Mercury-IM/domain/src/main/java/org/mercury_im/messenger/core/viewmodel/accounts/LoginViewModel.java

157 lines
5.7 KiB
Java

package org.mercury_im.messenger.core.viewmodel.accounts;
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.data.repository.AccountRepository;
import org.mercury_im.messenger.core.util.Optional;
import org.mercury_im.messenger.core.viewmodel.MercuryViewModel;
import org.mercury_im.messenger.core.xmpp.MercuryConnection;
import org.mercury_im.messenger.core.xmpp.MercuryConnectionManager;
import org.mercury_im.messenger.core.xmpp.exception.InvalidCredentialsException;
import org.mercury_im.messenger.core.xmpp.exception.ServerUnreachableException;
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<Boolean> isLoginSuccessful;
private EntityBareJid loginUsernameValue;
private String loginPasswordValue;
@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(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<Boolean> 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 void login() {
if (!isLoginPossible.getValue()) {
// Prevent race condition where account would be logged in twice
return;
}
isLoginPossible.onNext(false);
Account account = createAccountEntity();
MercuryConnection connection = connectionManager.createConnection(account);
addDisposable(connection.connect()
.andThen(connection.login())
.andThen(connectionManager.registerConnection(connection))
.andThen(accountRepository.insertAccount(account))
.subscribeOn(schedulers.getNewThread())
.observeOn(schedulers.getUiScheduler())
.subscribe(
this::onLoginSuccessful,
this::onLoginFailed
));
}
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.FINER, "Successfully added new account " + account);
isLoginSuccessful.onNext(true);
}
private void onLoginFailed(Throwable error) {
isLoginPossible.onNext(true);
if (error instanceof InvalidCredentialsException) {
loginPasswordError.onNext(new Optional<>(PasswordError.incorrectPassword));
} else if (error instanceof ServerUnreachableException) {
loginUsernameError.onNext(new Optional<>(UsernameError.unreachableServer));
}
}
}