diff --git a/src/main/kotlin/org/briarproject/briar/desktop/login/LoginScreen.kt b/src/main/kotlin/org/briarproject/briar/desktop/login/LoginScreen.kt index c3f072c1fdcef4968e7b86108a9cfd77136635b4..3beb11fbd0af019842b8f2c0c14aaf7f9984087e 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/login/LoginScreen.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/login/LoginScreen.kt @@ -34,6 +34,8 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp +import org.briarproject.briar.desktop.login.LoginViewModel.LoginState.SIGNED_OUT +import org.briarproject.briar.desktop.ui.Loader import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n import org.briarproject.briar.desktop.viewmodel.viewModel @@ -48,6 +50,12 @@ fun LoginScreen( viewModel.signIn(onSignedIn) } + if (viewModel.state.value != SIGNED_OUT) { + // todo: handle states individually + Loader() + return + } + val initialFocusRequester = remember { FocusRequester() } Surface { Column( diff --git a/src/main/kotlin/org/briarproject/briar/desktop/login/LoginViewModel.kt b/src/main/kotlin/org/briarproject/briar/desktop/login/LoginViewModel.kt index 85d939c109aba3be7e47078f0e626dbb3ea56605..39fbe88b64c83223c6181c6a7a74f62bbd8cde5d 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/login/LoginViewModel.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/login/LoginViewModel.kt @@ -4,35 +4,94 @@ import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import org.briarproject.bramble.api.account.AccountManager import org.briarproject.bramble.api.crypto.DecryptionException +import org.briarproject.bramble.api.db.TransactionManager +import org.briarproject.bramble.api.event.Event +import org.briarproject.bramble.api.event.EventBus +import org.briarproject.bramble.api.lifecycle.IoExecutor import org.briarproject.bramble.api.lifecycle.LifecycleManager -import org.briarproject.briar.desktop.viewmodel.ViewModel +import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState +import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent +import org.briarproject.briar.desktop.login.LoginViewModel.LoginState.COMPACTING +import org.briarproject.briar.desktop.login.LoginViewModel.LoginState.MIGRATING +import org.briarproject.briar.desktop.login.LoginViewModel.LoginState.SIGNED_OUT +import org.briarproject.briar.desktop.login.LoginViewModel.LoginState.SIGNING_IN +import org.briarproject.briar.desktop.login.LoginViewModel.LoginState.STARTED +import org.briarproject.briar.desktop.login.LoginViewModel.LoginState.STARTING +import org.briarproject.briar.desktop.viewmodel.BriarExecutors +import org.briarproject.briar.desktop.viewmodel.EventListenerDbViewModel +import org.briarproject.briar.desktop.viewmodel.UiExecutor import javax.inject.Inject class LoginViewModel @Inject constructor( private val accountManager: AccountManager, + private val briarExecutors: BriarExecutors, private val lifecycleManager: LifecycleManager, -) : ViewModel { + private val eventBus: EventBus, + db: TransactionManager, +) : EventListenerDbViewModel(briarExecutors, lifecycleManager, db, eventBus) { + enum class LoginState { + SIGNED_OUT, SIGNING_IN, SIGNED_IN, STARTING, MIGRATING, COMPACTING, STARTED + } + + private val _state = mutableStateOf(SIGNED_OUT) private val _password = mutableStateOf("") + val state: State<LoginState> = _state val password: State<String> = _password + override fun onInit() { + super.onInit() + updateState(lifecycleManager.lifecycleState) + } + + override fun eventOccurred(e: Event?) { + if (e is LifecycleEvent) { + updateState(e.lifecycleState) + } + } + + @UiExecutor + private fun updateState(s: LifecycleState) { + _state.value = + if (accountManager.hasDatabaseKey()) { + when { + s.isAfter(LifecycleState.STARTING_SERVICES) -> STARTED + s == LifecycleState.MIGRATING_DATABASE -> MIGRATING + s == LifecycleState.COMPACTING_DATABASE -> COMPACTING + else -> STARTING + } + } else { + SIGNED_OUT + } + } + fun setPassword(password: String) { _password.value = password } - fun signIn(success: () -> Unit) { - try { - accountManager.signIn(password.value) - signedIn() - success() - } catch (e: DecryptionException) { - // failure, try again + @UiExecutor + fun signIn(@UiExecutor success: () -> Unit) { + _state.value = SIGNING_IN + briarExecutors.onIoThread { + try { + accountManager.signIn(password.value) + signedIn() + + briarExecutors.onUiThread(success) + } catch (e: DecryptionException) { + // failure, try again + briarExecutors.onUiThread { + _state.value = SIGNED_OUT + _password.value = "" + } + } } } + @IoExecutor private fun signedIn() { val dbKey = accountManager.databaseKey ?: throw AssertionError() lifecycleManager.startServices(dbKey)