190 lines
7.3 KiB
Java
190 lines
7.3 KiB
Java
package org.mercury_im.messenger.core.viewmodel.account;
|
|
|
|
import org.jivesoftware.smack.util.StringUtils;
|
|
import org.jxmpp.jid.EntityBareJid;
|
|
import org.jxmpp.jid.impl.JidCreate;
|
|
import org.jxmpp.stringprep.XmppStringprepException;
|
|
import org.mercury_im.messenger.core.SchedulersFacade;
|
|
import org.mercury_im.messenger.core.account.error.PasswordError;
|
|
import org.mercury_im.messenger.core.account.error.UsernameError;
|
|
import org.mercury_im.messenger.core.connection.MercuryConnectionManager;
|
|
import org.mercury_im.messenger.core.connection.exception.InvalidCredentialsException;
|
|
import org.mercury_im.messenger.core.connection.exception.ServerUnreachableException;
|
|
import org.mercury_im.messenger.core.connection.state.ConnectionState;
|
|
import org.mercury_im.messenger.core.connection.state.ConnectivityState;
|
|
import org.mercury_im.messenger.core.data.repository.AccountRepository;
|
|
import org.mercury_im.messenger.core.util.Optional;
|
|
import org.mercury_im.messenger.core.viewmodel.MercuryViewModel;
|
|
import org.mercury_im.messenger.entity.Account;
|
|
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
|
|
import javax.inject.Inject;
|
|
|
|
import io.reactivex.Observable;
|
|
import io.reactivex.subjects.BehaviorSubject;
|
|
|
|
public class LoginViewModel implements MercuryViewModel {
|
|
|
|
private static final Logger LOGGER = Logger.getLogger(LoginViewModel.class.getName());
|
|
|
|
private final MercuryConnectionManager connectionManager;
|
|
private final AccountRepository accountRepository;
|
|
|
|
private final SchedulersFacade schedulers;
|
|
|
|
private BehaviorSubject<Optional<UsernameError>> loginUsernameError;
|
|
private BehaviorSubject<Optional<PasswordError>> loginPasswordError;
|
|
private BehaviorSubject<Boolean> isLoginPossible;
|
|
private BehaviorSubject<Optional<Account>> isLoginSuccessful;
|
|
private BehaviorSubject<Boolean> displayProgressBar;
|
|
|
|
private EntityBareJid loginUsernameValue;
|
|
private String loginPasswordValue;
|
|
private Account account;
|
|
|
|
@Inject
|
|
public LoginViewModel(MercuryConnectionManager connectionManager,
|
|
AccountRepository accountRepository,
|
|
SchedulersFacade schedulers) {
|
|
this.connectionManager = connectionManager;
|
|
this.accountRepository = accountRepository;
|
|
this.schedulers = schedulers;
|
|
|
|
reset();
|
|
}
|
|
|
|
public void reset() {
|
|
loginUsernameError = BehaviorSubject.createDefault(new Optional<>());
|
|
loginPasswordError = BehaviorSubject.createDefault(new Optional<>());
|
|
isLoginPossible = BehaviorSubject.createDefault(false);
|
|
isLoginSuccessful = BehaviorSubject.createDefault(new Optional<>());
|
|
displayProgressBar = BehaviorSubject.createDefault(false);
|
|
|
|
loginUsernameValue = null;
|
|
loginPasswordValue = null;
|
|
}
|
|
|
|
public Observable<Optional<UsernameError>> getLoginUsernameError() {
|
|
return loginUsernameError;
|
|
}
|
|
|
|
public Observable<Optional<PasswordError>> getLoginPasswordError() {
|
|
return loginPasswordError;
|
|
}
|
|
|
|
public Observable<Boolean> isLoginPossible() {
|
|
return isLoginPossible;
|
|
}
|
|
|
|
public Observable<Optional<Account>> isLoginSuccessful() {
|
|
return isLoginSuccessful;
|
|
}
|
|
|
|
public synchronized void onLoginUsernameChanged(String username) {
|
|
if (StringUtils.isNullOrEmpty(username)) {
|
|
loginUsernameValue = null;
|
|
loginUsernameError.onNext(new Optional<>(UsernameError.emptyUsername));
|
|
} else {
|
|
try {
|
|
loginUsernameValue = JidCreate.entityBareFrom(username);
|
|
loginUsernameError.onNext(new Optional<>());
|
|
} catch (XmppStringprepException e) {
|
|
loginUsernameValue = null;
|
|
loginUsernameError.onNext(new Optional<>(UsernameError.invalidUsername));
|
|
}
|
|
}
|
|
updateLoginPossible();
|
|
}
|
|
|
|
public synchronized void onLoginPasswordChanged(String password) {
|
|
if (StringUtils.isNullOrEmpty(password)) {
|
|
loginPasswordValue = null;
|
|
loginPasswordError.onNext(new Optional<>(PasswordError.emptyPassword));
|
|
} else {
|
|
loginPasswordValue = password;
|
|
loginPasswordError.onNext(new Optional<>());
|
|
}
|
|
updateLoginPossible();
|
|
}
|
|
|
|
private synchronized void updateLoginPossible() {
|
|
isLoginPossible.onNext(loginUsernameValue != null && loginPasswordValue != null);
|
|
}
|
|
|
|
public synchronized Account login() {
|
|
displayProgressBar.onNext(true);
|
|
if (!isLoginPossible.getValue()) {
|
|
// Prevent race condition where account would be logged in twice
|
|
return account;
|
|
}
|
|
isLoginPossible.onNext(false);
|
|
|
|
account = createAccountEntity();
|
|
|
|
//MercuryConnection connection = connectionManager.createConnection(account);
|
|
addDisposable(accountRepository.upsertAccount(account)
|
|
//.andThen(connection.connect())
|
|
//.andThen(connection.login())
|
|
//.andThen(connectionManager.registerConnection(connection))
|
|
.subscribeOn(schedulers.getNewThread())
|
|
.observeOn(schedulers.getUiScheduler())
|
|
.subscribe(
|
|
a -> LOGGER.log(Level.INFO, "Account " + a + " successfully inserted."),
|
|
this::onLoginFailed
|
|
));
|
|
|
|
addDisposable(connectionManager.observeConnectionPool()
|
|
.map(cp -> {
|
|
ConnectionState state = cp.getConnectionStates().get(account.getId());
|
|
if (state == null) {
|
|
return ConnectivityState.disconnected;
|
|
} else {
|
|
return state.getConnectivity();
|
|
}
|
|
})
|
|
.filter(s -> s == ConnectivityState.disconnectedOnError || s == ConnectivityState.authenticated)
|
|
.firstOrError()
|
|
.compose(schedulers.executeUiSafeSingle())
|
|
.subscribe(connectivityState -> {
|
|
displayProgressBar.onNext(false);
|
|
if (connectivityState == ConnectivityState.disconnectedOnError) {
|
|
onLoginFailed(new Exception());
|
|
} else {
|
|
onLoginSuccessful(account);
|
|
}
|
|
}));
|
|
|
|
return account;
|
|
}
|
|
|
|
private Account createAccountEntity() {
|
|
Account account = new Account();
|
|
account.setAddress(loginUsernameValue.asEntityBareJidString());
|
|
account.setPassword(loginPasswordValue);
|
|
account.setEnabled(true);
|
|
|
|
return account;
|
|
}
|
|
|
|
private void onLoginSuccessful(Account account) {
|
|
LOGGER.log(Level.INFO, "Login successful.");
|
|
isLoginSuccessful.onNext(new Optional<>(account));
|
|
}
|
|
|
|
private void onLoginFailed(Throwable error) {
|
|
LOGGER.log(Level.INFO, "Login failed!");
|
|
isLoginPossible.onNext(true);
|
|
if (error instanceof InvalidCredentialsException) {
|
|
loginPasswordError.onNext(new Optional<>(PasswordError.incorrectPassword));
|
|
} else if (error instanceof ServerUnreachableException) {
|
|
loginUsernameError.onNext(new Optional<>(UsernameError.unreachableServer));
|
|
}
|
|
}
|
|
|
|
public Observable<Boolean> isDisplayProgressBar() {
|
|
return displayProgressBar;
|
|
}
|
|
}
|