Minor clean up of the TwoFactorLoginScreen (#1022)

This commit is contained in:
David Perez 2024-02-15 13:56:07 -06:00 committed by Álison Fernandes
parent 6ac7e0430f
commit b74427dd88
4 changed files with 67 additions and 53 deletions

View file

@ -43,9 +43,9 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledTonalButton
import com.x8bit.bitwarden.ui.platform.components.BitwardenLoadingDialog
import com.x8bit.bitwarden.ui.platform.components.BitwardenOverflowActionItem
import com.x8bit.bitwarden.ui.platform.components.BitwardenScaffold
import com.x8bit.bitwarden.ui.platform.components.BitwardenSwitch
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextField
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
import com.x8bit.bitwarden.ui.platform.components.BitwardenWideSwitch
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
import com.x8bit.bitwarden.ui.platform.components.OverflowMenuItemData
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
@ -83,29 +83,12 @@ fun TwoFactorLoginScreen(
}
}
when (val dialog = state.dialogState) {
is TwoFactorLoginState.DialogState.Error -> {
BitwardenBasicDialog(
visibilityState = BasicDialogState.Shown(
title = dialog.title ?: R.string.an_error_has_occurred.asText(),
message = dialog.message,
),
onDismissRequest = remember(viewModel) {
{ viewModel.trySendAction(TwoFactorLoginAction.DialogDismiss) }
},
)
}
is TwoFactorLoginState.DialogState.Loading -> {
BitwardenLoadingDialog(
visibilityState = LoadingDialogState.Shown(
text = dialog.message,
),
)
}
null -> Unit
}
TwoFactorLoginDialogs(
dialogState = state.dialogState,
onDismissRequest = remember(viewModel) {
{ viewModel.trySendAction(TwoFactorLoginAction.DialogDismiss) }
},
)
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
BitwardenScaffold(
@ -164,7 +147,28 @@ fun TwoFactorLoginScreen(
}
@Composable
@Suppress("LongMethod")
private fun TwoFactorLoginDialogs(
dialogState: TwoFactorLoginState.DialogState?,
onDismissRequest: () -> Unit,
) {
when (dialogState) {
is TwoFactorLoginState.DialogState.Error -> BitwardenBasicDialog(
visibilityState = BasicDialogState.Shown(
title = dialogState.title ?: R.string.an_error_has_occurred.asText(),
message = dialogState.message,
),
onDismissRequest = onDismissRequest,
)
is TwoFactorLoginState.DialogState.Loading -> BitwardenLoadingDialog(
visibilityState = LoadingDialogState.Shown(text = dialogState.message),
)
null -> Unit
}
}
@Composable
private fun TwoFactorLoginScreenContent(
state: TwoFactorLoginState,
onCodeInputChange: (String) -> Unit,
@ -203,7 +207,7 @@ private fun TwoFactorLoginScreenContent(
Spacer(modifier = Modifier.height(12.dp))
BitwardenSwitch(
BitwardenWideSwitch(
label = stringResource(id = R.string.remember_me),
isChecked = state.isRememberMeEnabled,
onCheckedChange = onRememberMeToggle,

View file

@ -20,6 +20,7 @@ import com.x8bit.bitwarden.ui.platform.base.util.Text
import com.x8bit.bitwarden.ui.platform.base.util.asText
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
@ -60,13 +61,8 @@ class TwoFactorLoginViewModel @Inject constructor(
// Automatically attempt to login again if a captcha token is received.
authRepository
.captchaTokenResultFlow
.onEach {
sendAction(
TwoFactorLoginAction.Internal.ReceiveCaptchaToken(
tokenResult = it,
),
)
}
.map { TwoFactorLoginAction.Internal.ReceiveCaptchaToken(tokenResult = it) }
.onEach(::sendAction)
.launchIn(viewModelScope)
}
@ -79,20 +75,27 @@ class TwoFactorLoginViewModel @Inject constructor(
is TwoFactorLoginAction.RememberMeToggle -> handleRememberMeToggle(action)
TwoFactorLoginAction.ResendEmailClick -> handleResendEmailClick()
is TwoFactorLoginAction.SelectAuthMethod -> handleSelectAuthMethod(action)
is TwoFactorLoginAction.Internal -> handleInternalAction(action)
}
}
private fun handleInternalAction(action: TwoFactorLoginAction.Internal) {
when (action) {
is TwoFactorLoginAction.Internal.ReceiveLoginResult -> handleReceiveLoginResult(action)
is TwoFactorLoginAction.Internal.ReceiveCaptchaToken -> {
handleCaptchaTokenReceived(action.tokenResult)
handleCaptchaTokenReceived(action)
}
is TwoFactorLoginAction.Internal.ReceiveLoginResult -> handleReceiveLoginResult(action)
is TwoFactorLoginAction.Internal.ReceiveResendEmailResult -> {
handleReceiveResendEmailResult(action)
}
}
}
private fun handleCaptchaTokenReceived(tokenResult: CaptchaCallbackTokenResult) {
when (tokenResult) {
private fun handleCaptchaTokenReceived(
action: TwoFactorLoginAction.Internal.ReceiveCaptchaToken,
) {
when (val tokenResult = action.tokenResult) {
CaptchaCallbackTokenResult.MissingToken -> {
mutableStateFlow.update {
it.copy(
@ -138,26 +141,31 @@ class TwoFactorLoginViewModel @Inject constructor(
}
// If the user is manually entering a code, remove any white spaces, just in case.
val code = mutableStateFlow.value.codeInput.let { rawCode ->
if (mutableStateFlow.value.authMethod == TwoFactorAuthMethod.AUTHENTICATOR_APP ||
mutableStateFlow.value.authMethod == TwoFactorAuthMethod.EMAIL
) {
rawCode.replace(" ", "")
} else {
rawCode
}
val code = when (state.authMethod) {
TwoFactorAuthMethod.AUTHENTICATOR_APP,
TwoFactorAuthMethod.EMAIL,
-> state.codeInput.replace(" ", "")
TwoFactorAuthMethod.YUBI_KEY,
TwoFactorAuthMethod.DUO,
TwoFactorAuthMethod.U2F,
TwoFactorAuthMethod.REMEMBER,
TwoFactorAuthMethod.DUO_ORGANIZATION,
TwoFactorAuthMethod.FIDO_2_WEB_APP,
TwoFactorAuthMethod.RECOVERY_CODE,
-> state.codeInput
}
viewModelScope.launch {
val result = authRepository.login(
email = mutableStateFlow.value.email,
password = mutableStateFlow.value.password,
email = state.email,
password = state.password,
twoFactorData = TwoFactorDataModel(
code = code,
method = mutableStateFlow.value.authMethod.value.toString(),
remember = mutableStateFlow.value.isRememberMeEnabled,
method = state.authMethod.value.toString(),
remember = state.isRememberMeEnabled,
),
captchaToken = mutableStateFlow.value.captchaToken,
captchaToken = state.captchaToken,
)
sendAction(
TwoFactorLoginAction.Internal.ReceiveLoginResult(
@ -267,7 +275,7 @@ class TwoFactorLoginViewModel @Inject constructor(
*/
private fun handleResendEmailClick() {
// Ensure that the user is in fact verifying with email.
if (mutableStateFlow.value.authMethod != TwoFactorAuthMethod.EMAIL) {
if (state.authMethod != TwoFactorAuthMethod.EMAIL) {
return
}

View file

@ -13,6 +13,7 @@ val TwoFactorAuthMethod.title: Text
TwoFactorAuthMethod.AUTHENTICATOR_APP -> R.string.authenticator_app_title.asText()
TwoFactorAuthMethod.EMAIL -> R.string.email.asText()
TwoFactorAuthMethod.RECOVERY_CODE -> R.string.recovery_code_title.asText()
TwoFactorAuthMethod.YUBI_KEY -> R.string.yubi_key_title.asText()
else -> "".asText()
}
@ -22,5 +23,6 @@ val TwoFactorAuthMethod.title: Text
fun TwoFactorAuthMethod.description(email: String): Text = when (this) {
TwoFactorAuthMethod.AUTHENTICATOR_APP -> R.string.enter_verification_code_app.asText()
TwoFactorAuthMethod.EMAIL -> R.string.enter_verification_code_email.asText(email)
TwoFactorAuthMethod.YUBI_KEY -> R.string.yubi_key_instruction.asText()
else -> "".asText()
}

View file

@ -13,7 +13,7 @@ class TwoFactorAuthMethodExtensionTest {
TwoFactorAuthMethod.AUTHENTICATOR_APP to R.string.authenticator_app_title.asText(),
TwoFactorAuthMethod.EMAIL to R.string.email.asText(),
TwoFactorAuthMethod.DUO to "".asText(),
TwoFactorAuthMethod.YUBI_KEY to "".asText(),
TwoFactorAuthMethod.YUBI_KEY to R.string.yubi_key_title.asText(),
TwoFactorAuthMethod.U2F to "".asText(),
TwoFactorAuthMethod.REMEMBER to "".asText(),
TwoFactorAuthMethod.DUO_ORGANIZATION to "".asText(),
@ -36,7 +36,7 @@ class TwoFactorAuthMethodExtensionTest {
TwoFactorAuthMethod.EMAIL to
R.string.enter_verification_code_email.asText("ex***@email.com"),
TwoFactorAuthMethod.DUO to "".asText(),
TwoFactorAuthMethod.YUBI_KEY to "".asText(),
TwoFactorAuthMethod.YUBI_KEY to R.string.yubi_key_instruction.asText(),
TwoFactorAuthMethod.U2F to "".asText(),
TwoFactorAuthMethod.REMEMBER to "".asText(),
TwoFactorAuthMethod.DUO_ORGANIZATION to "".asText(),