package org.mercury_im.messenger.ui.account; import android.app.Application; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import org.jivesoftware.smack.sasl.SASLErrorException; import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.stringprep.XmppStringprepException; import org.mercury_im.messenger.MercuryImApplication; import org.mercury_im.messenger.Messenger; import org.mercury_im.messenger.R; import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.IAccount; import java.util.logging.Level; import java.util.logging.Logger; import javax.inject.Inject; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; public class LoginViewModel extends AndroidViewModel { private MutableLiveData usernameError = new MutableLiveData<>(new Error()); private MutableLiveData passwordError = new MutableLiveData<>(new Error()); private MutableLiveData loginButtonEnabled = new MutableLiveData<>(false); private MutableLiveData loginCompleted = new MutableLiveData<>(false); private final CompositeDisposable disposable = new CompositeDisposable(); private EntityBareJid username; private String password; @Inject Messenger messenger; public LoginViewModel(@NonNull Application application) { super(application); ((MercuryImApplication) application).getAppComponent().inject(this); } public void setUsername(String username) { if (username == null || username.isEmpty()) { this.username = null; usernameError.setValue(new Error(getApplication().getResources().getString(R.string.error_field_required))); } else { try { this.username = JidCreate.entityBareFrom(username); } catch (XmppStringprepException e) { this.username = null; usernameError.setValue(new Error(getApplication().getResources().getString(R.string.error_invalid_username))); } } updateLoginButtonState(); } public void setPassword(String password) { if (password == null || password.isEmpty()) { this.password = null; passwordError.setValue(new Error(getApplication().getResources().getString(R.string.error_field_required))); } else { this.password = password; } updateLoginButtonState(); } private void updateLoginButtonState() { loginButtonEnabled.setValue(username != null && !(password == null || password.isEmpty())); } public synchronized void login() { Boolean loginEnabled = loginButtonEnabled.getValue(); if (loginEnabled != null && !loginEnabled) { // Prevent race condition where account would be logged in twice return; } loginButtonEnabled.setValue(false); Account account = new IAccount(); account.setAddress(username.asUnescapedString()); account.setPassword(password); disposable.add(messenger.addAccount() .execute(account) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .doOnComplete(this::signalLoginSuccessful) .doOnError(this::signalLoginError) .subscribe()); } private void signalLoginSuccessful() { Logger.getAnonymousLogger().log(Level.INFO, "Signal Login Successful"); loginCompleted.setValue(true); } private void signalLoginError(Throwable error) { if (error instanceof SASLErrorException) { passwordError.setValue(new Error(getApplication().getResources().getString(R.string.error_incorrect_password))); loginButtonEnabled.setValue(true); } else { Toast.makeText(getApplication(), "A connection error occurred", Toast.LENGTH_LONG).show(); loginButtonEnabled.setValue(true); } } public LiveData getPasswordError() { return passwordError; } public LiveData getUsernameError() { return usernameError; } public LiveData isLoginSuccessful() { return loginCompleted; } public LiveData isLoginEnabled() { return loginButtonEnabled; } @Override protected void onCleared() { super.onCleared(); disposable.clear(); } public static class Error { private String message; public Error() { } public Error(String errorMessage) { this.message = errorMessage; } public boolean isError() { return message != null; } public String getErrorMessage() { return message; } } }