From 9c3aa5bfbfa9c4487094a32b217e9c281d44f5fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= Date: Tue, 4 Feb 2025 18:05:54 +0100 Subject: [PATCH] feat: handle 2fa code in new login flow [WPB-15853] --- .../wire/android/navigation/MainNavHost.kt | 11 ++ .../email/LoginEmailVerificationCodeScreen.kt | 3 + .../login/email/LoginEmailViewModel.kt | 3 +- .../verificationcode/ResendCodeText.kt | 6 - .../verificationcode/VerificationCode.kt | 39 +++-- .../code/NewLoginVerificationCodeScreen.kt | 157 ++++++++++++++++++ .../login/NewLoginContainer.kt | 27 ++- .../newauthentication/login/NewLoginScreen.kt | 2 +- .../login/password/NewLoginPasswordScreen.kt | 109 ++++++------ .../wire/android/util/CurrentScreenManager.kt | 2 + app/src/main/res/values/strings.xml | 1 + 11 files changed, 274 insertions(+), 86 deletions(-) create mode 100644 app/src/main/kotlin/com/wire/android/ui/newauthentication/code/NewLoginVerificationCodeScreen.kt diff --git a/app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt b/app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt index fbd1660dabd..44f23a196fd 100644 --- a/app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt +++ b/app/src/main/kotlin/com/wire/android/navigation/MainNavHost.kt @@ -36,7 +36,10 @@ import com.wire.android.feature.sketch.model.DrawingCanvasNavBackArgs import com.wire.android.navigation.style.DefaultNestedNavGraphAnimations import com.wire.android.navigation.style.DefaultRootNavGraphAnimations import com.wire.android.ui.NavGraphs +import com.wire.android.ui.authentication.login.email.LoginEmailViewModel import com.wire.android.ui.destinations.ConversationScreenDestination +import com.wire.android.ui.destinations.NewLoginPasswordScreenDestination +import com.wire.android.ui.destinations.NewLoginVerificationCodeScreenDestination import com.wire.android.ui.home.conversations.ConversationScreen import com.wire.android.ui.home.newconversation.NewConversationViewModel @@ -73,6 +76,14 @@ fun MainNavHost( } hiltViewModel(parentEntry) } + + // 👇 To reuse LoginEmailViewModel from NewLoginPasswordScreen on NewLoginVerificationCodeScreen + dependency(NewLoginVerificationCodeScreenDestination) { + val loginPasswordEntry = remember(navBackStackEntry) { + navController.getBackStackEntry(NewLoginPasswordScreenDestination.route) + } + hiltViewModel(loginPasswordEntry) + } }, manualComposableCallsBuilder = { /** diff --git a/app/src/main/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailVerificationCodeScreen.kt b/app/src/main/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailVerificationCodeScreen.kt index 80234d6be10..efd70767ecb 100644 --- a/app/src/main/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailVerificationCodeScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailVerificationCodeScreen.kt @@ -26,6 +26,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.input.TextFieldState +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -43,6 +44,7 @@ import com.wire.android.ui.common.scaffold.WireScaffold import com.wire.android.ui.common.topappbar.WireCenterAlignedTopAppBar import com.wire.android.ui.common.typography import com.wire.android.ui.theme.WireTheme +import com.wire.android.ui.theme.wireDimensions import com.wire.android.util.ui.PreviewMultipleThemes import com.wire.android.util.ui.UIText @@ -118,6 +120,7 @@ private fun MainContent( isLoading = isLoading, isCurrentCodeInvalid = codeState.isCurrentCodeInvalid, onResendCode = onResendCode, + modifier = Modifier.padding(vertical = MaterialTheme.wireDimensions.spacing24x), ) Spacer(modifier = Modifier .height(dimensions().spacing8x) diff --git a/app/src/main/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailViewModel.kt index e4c1e6251b3..27766966340 100644 --- a/app/src/main/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/authentication/login/email/LoginEmailViewModel.kt @@ -88,6 +88,7 @@ class LoginEmailViewModel @Inject constructor( val secondFactorVerificationCodeTextState: TextFieldState = TextFieldState() var secondFactorVerificationCodeState by mutableStateOf(VerificationCodeState()) + var autoLoginWhenFullCodeEntered: Boolean = false init { userIdentifierTextState.setTextAndPlaceCursorAtEnd( @@ -114,7 +115,7 @@ class LoginEmailViewModel @Inject constructor( viewModelScope.launch { secondFactorVerificationCodeTextState.textAsFlow().collectLatest { secondFactorVerificationCodeState = secondFactorVerificationCodeState.copy(isCurrentCodeInvalid = false) - if (it.length == VerificationCodeState.DEFAULT_VERIFICATION_CODE_LENGTH) { + if (it.length == VerificationCodeState.DEFAULT_VERIFICATION_CODE_LENGTH && autoLoginWhenFullCodeEntered) { login() } } diff --git a/app/src/main/kotlin/com/wire/android/ui/authentication/verificationcode/ResendCodeText.kt b/app/src/main/kotlin/com/wire/android/ui/authentication/verificationcode/ResendCodeText.kt index 9f09ab2e2b2..24fb442ab78 100644 --- a/app/src/main/kotlin/com/wire/android/ui/authentication/verificationcode/ResendCodeText.kt +++ b/app/src/main/kotlin/com/wire/android/ui/authentication/verificationcode/ResendCodeText.kt @@ -20,7 +20,6 @@ package com.wire.android.ui.authentication.verificationcode import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -30,7 +29,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import com.wire.android.R -import com.wire.android.ui.theme.wireDimensions import com.wire.android.ui.theme.wireTypography @Composable @@ -49,9 +47,5 @@ fun ResendCodeText(onResendCodePressed: () -> Unit, clickEnabled: Boolean, modif enabled = clickEnabled, onClick = onResendCodePressed ) - .padding( - horizontal = MaterialTheme.wireDimensions.spacing16x, - vertical = MaterialTheme.wireDimensions.spacing24x - ) ) } diff --git a/app/src/main/kotlin/com/wire/android/ui/authentication/verificationcode/VerificationCode.kt b/app/src/main/kotlin/com/wire/android/ui/authentication/verificationcode/VerificationCode.kt index a5f68f9bf8d..d0daacd0804 100644 --- a/app/src/main/kotlin/com/wire/android/ui/authentication/verificationcode/VerificationCode.kt +++ b/app/src/main/kotlin/com/wire/android/ui/authentication/verificationcode/VerificationCode.kt @@ -18,10 +18,13 @@ package com.wire.android.ui.authentication.verificationcode -import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.Crossfade +import androidx.compose.animation.animateContentSize import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable @@ -47,7 +50,8 @@ fun VerificationCode( isLoading: Boolean, isCurrentCodeInvalid: Boolean, onResendCode: () -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + showLoadingProgress: Boolean = true, ) { val focusRequester = remember { FocusRequester() } Column( @@ -67,18 +71,27 @@ fun VerificationCode( modifier = Modifier.focusRequester(focusRequester) ) - AnimatedVisibility(visible = isLoading) { - WireCircularProgressIndicator( - progressColor = MaterialTheme.wireColorScheme.primary, - size = MaterialTheme.wireDimensions.spacing24x, - modifier = Modifier.padding(vertical = MaterialTheme.wireDimensions.spacing16x) - ) - } + Crossfade( + targetState = isLoading to showLoadingProgress, + modifier = Modifier + .padding(top = MaterialTheme.wireDimensions.spacing24x) + .animateContentSize(), + ) { (isLoading, showLoadingProgress) -> + when { + !isLoading -> ResendCodeText( + onResendCodePressed = onResendCode, + clickEnabled = true, + modifier = Modifier + .defaultMinSize(minHeight = MaterialTheme.wireDimensions.spacing24x) + .wrapContentHeight(align = Alignment.CenterVertically), + ) - ResendCodeText( - onResendCodePressed = onResendCode, - clickEnabled = !isLoading - ) + isLoading && showLoadingProgress -> WireCircularProgressIndicator( + progressColor = MaterialTheme.wireColorScheme.primary, + size = MaterialTheme.wireDimensions.spacing24x, + ) + } + } } } diff --git a/app/src/main/kotlin/com/wire/android/ui/newauthentication/code/NewLoginVerificationCodeScreen.kt b/app/src/main/kotlin/com/wire/android/ui/newauthentication/code/NewLoginVerificationCodeScreen.kt new file mode 100644 index 00000000000..e93fd552fb3 --- /dev/null +++ b/app/src/main/kotlin/com/wire/android/ui/newauthentication/code/NewLoginVerificationCodeScreen.kt @@ -0,0 +1,157 @@ +/* + * Wire + * Copyright (C) 2025 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.android.ui.newauthentication.login.code + +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.input.TextFieldState +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import com.ramcosta.composedestinations.annotation.RootNavGraph +import com.wire.android.R +import com.wire.android.navigation.Navigator +import com.wire.android.navigation.WireDestination +import com.wire.android.navigation.style.AuthSlideNavigationAnimation +import com.wire.android.ui.authentication.login.LoginState +import com.wire.android.ui.authentication.login.WireAuthBackgroundLayout +import com.wire.android.ui.authentication.login.email.LoginButton +import com.wire.android.ui.authentication.login.email.LoginEmailViewModel +import com.wire.android.ui.authentication.verificationcode.VerificationCode +import com.wire.android.ui.authentication.verificationcode.VerificationCodeState +import com.wire.android.ui.common.dimensions +import com.wire.android.ui.common.preview.EdgeToEdgePreview +import com.wire.android.ui.common.textfield.clearAutofillTree +import com.wire.android.ui.newauthentication.login.NewLoginContainer +import com.wire.android.ui.newauthentication.login.NewLoginHeader +import com.wire.android.ui.newauthentication.login.NewLoginSubtitle +import com.wire.android.ui.newauthentication.login.NewLoginTitle +import com.wire.android.ui.newauthentication.login.password.LoginStateNavigationAndDialogs +import com.wire.android.ui.theme.WireTheme +import com.wire.android.ui.theme.wireDimensions +import com.wire.android.util.ui.PreviewMultipleThemes + +@RootNavGraph +@WireDestination( + style = AuthSlideNavigationAnimation::class, +) +@Composable +// has to be navigated to after NewLoginPasswordScreen, otherwise there will be illegal state because it needs to reuse view model from it +fun NewLoginVerificationCodeScreen( + navigator: Navigator, + loginEmailViewModel: LoginEmailViewModel, // provided in MainNavHost to reuse from NewLoginPasswordScreen, don't use hiltViewModel() +) { + clearAutofillTree() + LoginStateNavigationAndDialogs(loginEmailViewModel, navigator) + + LaunchedEffect(loginEmailViewModel) { + loginEmailViewModel.autoLoginWhenFullCodeEntered = false + } + + val navigateBack = { + loginEmailViewModel.onCodeVerificationBackPress() + navigator.navigateBack() + } + BackHandler { + navigateBack() + } + + LoginVerificationCodeContent( + codeTextState = loginEmailViewModel.secondFactorVerificationCodeTextState, + codeState = loginEmailViewModel.secondFactorVerificationCodeState, + isLoading = loginEmailViewModel.loginState.flowState is LoginState.Loading, + onResendCode = loginEmailViewModel::onCodeResend, + onLoginButtonClick = loginEmailViewModel::login, + canNavigateBack = navigator.navController.previousBackStackEntry != null, // if there is a previous screen to navigate back to + navigateBack = navigateBack, + ) +} + +@Composable +private fun LoginVerificationCodeContent( + codeTextState: TextFieldState, + codeState: VerificationCodeState, + isLoading: Boolean, + onResendCode: () -> Unit, + onLoginButtonClick: () -> Unit, + canNavigateBack: Boolean, + navigateBack: () -> Unit, +) { + NewLoginContainer( + header = { + NewLoginHeader( + title = { + NewLoginTitle( + title = stringResource(R.string.enterprise_login_verification_code_title), + modifier = Modifier.padding(bottom = dimensions().spacing24x) + ) + NewLoginSubtitle( + title = stringResource(R.string.second_factor_authentication_instructions_label, codeState.emailUsed), + ) + }, + canNavigateBack = canNavigateBack, + onNavigateBack = navigateBack + ) + } + ) { + VerificationCode( + codeLength = codeState.codeLength, + codeState = codeTextState, + isLoading = isLoading, + showLoadingProgress = false, // for new login we show progress on the "next" button + isCurrentCodeInvalid = codeState.isCurrentCodeInvalid, + onResendCode = onResendCode, + modifier = Modifier.padding(bottom = MaterialTheme.wireDimensions.spacing24x), + ) + LoginButton( + loading = isLoading, + enabled = codeTextState.text.length == codeState.codeLength, + text = stringResource(R.string.enterprise_login_next), + loadingText = stringResource(R.string.enterprise_login_next), + onClick = onLoginButtonClick, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = dimensions().spacing8x), + ) + } +} + +@PreviewMultipleThemes +@Composable +private fun PreviewNewLoginVerificationCodeScreen() = WireTheme { + EdgeToEdgePreview(useDarkIcons = false) { + WireAuthBackgroundLayout { + LoginVerificationCodeContent( + codeTextState = TextFieldState(), + codeState = VerificationCodeState( + codeLength = 6, + isCurrentCodeInvalid = false, + emailUsed = "" + ), + isLoading = false, + onResendCode = {}, + onLoginButtonClick = {}, + canNavigateBack = true, + navigateBack = {}, + ) + } + } +} diff --git a/app/src/main/kotlin/com/wire/android/ui/newauthentication/login/NewLoginContainer.kt b/app/src/main/kotlin/com/wire/android/ui/newauthentication/login/NewLoginContainer.kt index e2db8249ef5..5a7fa471e26 100644 --- a/app/src/main/kotlin/com/wire/android/ui/newauthentication/login/NewLoginContainer.kt +++ b/app/src/main/kotlin/com/wire/android/ui/newauthentication/login/NewLoginContainer.kt @@ -50,6 +50,7 @@ import com.wire.android.ui.common.rememberTopBarElevationState import com.wire.android.ui.common.scaffold.WireScaffold import com.wire.android.ui.common.topappbar.NavigationIconButton import com.wire.android.ui.common.topappbar.NavigationIconType +import com.wire.android.ui.common.typography import com.wire.android.ui.theme.WireTheme import com.wire.android.ui.theme.wireTypography import com.wire.android.util.ui.PreviewMultipleThemes @@ -130,6 +131,22 @@ fun NewLoginTitle( title: String, verticalPadding: Dp = dimensions().spacing2x, modifier: Modifier = Modifier +) { + Text( + text = title, + style = typography().title01, + color = colorsScheme().onSurface, + textAlign = TextAlign.Center, + modifier = modifier + .padding(vertical = verticalPadding) + ) +} + +@Composable +fun NewLoginSubtitle( + title: String, + verticalPadding: Dp = dimensions().spacing2x, + modifier: Modifier = Modifier ) { Text( text = title, @@ -158,7 +175,7 @@ private fun NavigationBarBackground() = Box( private fun PreviewNewLoginHeader() = WireTheme { NewLoginHeader( title = { - NewLoginTitle("Enter your password to log in") + NewLoginSubtitle("Enter your password to log in") }, canNavigateBack = true ) @@ -169,7 +186,7 @@ private fun PreviewNewLoginHeader() = WireTheme { private fun PreviewNewLoginHeaderNoNavigateBack() = WireTheme { NewLoginHeader( title = { - NewLoginTitle("Enter your password to log in") + NewLoginSubtitle("Enter your password to log in") }, canNavigateBack = false ) @@ -180,8 +197,8 @@ private fun PreviewNewLoginHeaderNoNavigateBack() = WireTheme { private fun PreviewNewLoginHeaderTwoLines() = WireTheme { NewLoginHeader( title = { - NewLoginTitle("Enter your password to log in") - NewLoginTitle("Enter your password to log in") + NewLoginSubtitle("Enter your password to log in") + NewLoginSubtitle("Enter your password to log in") }, canNavigateBack = true ) @@ -196,7 +213,7 @@ private fun PreviewNewLoginContent() = WireTheme { header = { NewLoginHeader( title = { - NewLoginTitle("Enter your password to log in") + NewLoginSubtitle("Enter your password to log in") }, canNavigateBack = true ) diff --git a/app/src/main/kotlin/com/wire/android/ui/newauthentication/login/NewLoginScreen.kt b/app/src/main/kotlin/com/wire/android/ui/newauthentication/login/NewLoginScreen.kt index 7408e33d088..702e9cfdb47 100644 --- a/app/src/main/kotlin/com/wire/android/ui/newauthentication/login/NewLoginScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/newauthentication/login/NewLoginScreen.kt @@ -107,7 +107,7 @@ private fun LoginContent( .padding(horizontal = dimensions().spacing32x) .size(dimensions().spacing120x) ) - NewLoginTitle( + NewLoginSubtitle( title = stringResource(R.string.enterprise_login_welcome), modifier = Modifier.padding(top = dimensions().spacing16x) ) diff --git a/app/src/main/kotlin/com/wire/android/ui/newauthentication/login/password/NewLoginPasswordScreen.kt b/app/src/main/kotlin/com/wire/android/ui/newauthentication/login/password/NewLoginPasswordScreen.kt index 5465be7fd33..be7627d8aba 100644 --- a/app/src/main/kotlin/com/wire/android/ui/newauthentication/login/password/NewLoginPasswordScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/newauthentication/login/password/NewLoginPasswordScreen.kt @@ -73,10 +73,11 @@ import com.wire.android.ui.destinations.CreatePersonalAccountOverviewScreenDesti import com.wire.android.ui.destinations.E2EIEnrollmentScreenDestination import com.wire.android.ui.destinations.HomeScreenDestination import com.wire.android.ui.destinations.InitialSyncScreenDestination +import com.wire.android.ui.destinations.NewLoginVerificationCodeScreenDestination import com.wire.android.ui.destinations.RemoveDeviceScreenDestination import com.wire.android.ui.newauthentication.login.NewLoginContainer import com.wire.android.ui.newauthentication.login.NewLoginHeader -import com.wire.android.ui.newauthentication.login.NewLoginTitle +import com.wire.android.ui.newauthentication.login.NewLoginSubtitle import com.wire.android.ui.theme.WireTheme import com.wire.android.util.ui.PreviewMultipleThemes import com.wire.kalium.logic.configuration.server.ServerConfig @@ -91,11 +92,15 @@ fun NewLoginPasswordScreen( navigator: Navigator, loginEmailViewModel: LoginEmailViewModel = hiltViewModel() ) { + clearAutofillTree() + LoginStateNavigationAndDialogs(loginEmailViewModel, navigator) + LaunchedEffect(loginEmailViewModel.secondFactorVerificationCodeState) { if (loginEmailViewModel.secondFactorVerificationCodeState.isCodeInputNecessary) { - // TODO: handle 2FA code by opening the verification code screen + navigator.navigate(NavigationCommand(NewLoginVerificationCodeScreenDestination())) } } + LoginPasswordContent( serverConfig = loginEmailViewModel.serverConfig, loginEmailState = loginEmailViewModel.loginState, @@ -103,21 +108,7 @@ fun NewLoginPasswordScreen( proxyIdentifierState = loginEmailViewModel.proxyIdentifierTextState, proxyPasswordState = loginEmailViewModel.proxyPasswordTextState, passwordTextState = loginEmailViewModel.passwordTextState, - onDialogDismiss = loginEmailViewModel::clearLoginErrors, - onSuccess = { initialSyncCompleted, isE2EIRequired -> - val destination = when { - isE2EIRequired -> E2EIEnrollmentScreenDestination - initialSyncCompleted -> HomeScreenDestination - else -> InitialSyncScreenDestination - } - navigator.navigate(NavigationCommand(destination, BackStackMode.CLEAR_WHOLE)) - }, - onRemoveDeviceOpen = { - loginEmailViewModel.clearLoginErrors() - navigator.navigate(NavigationCommand(RemoveDeviceScreenDestination, BackStackMode.CLEAR_WHOLE)) - }, onLoginButtonClick = loginEmailViewModel::login, - onUpdateApp = loginEmailViewModel::updateTheApp, onCreateAccount = { // TODO: Should it open CreatePersonalAccountScreen or CreateTeamAccountScreen? // Also, maybe open the second step directly - ...EmailScreen with e-mail already filled in instead of ...OverviewScreen @@ -137,50 +128,31 @@ internal fun LoginPasswordContent( proxyIdentifierState: TextFieldState, proxyPasswordState: TextFieldState, loginEmailState: LoginEmailState, - onSuccess: (initialSyncCompleted: Boolean, isE2EIRequired: Boolean) -> Unit, - onRemoveDeviceOpen: () -> Unit, - onDialogDismiss: () -> Unit, onLoginButtonClick: () -> Unit, - onUpdateApp: () -> Unit, onCreateAccount: () -> Unit, canNavigateBack: Boolean, navigateBack: () -> Unit, ) { - clearAutofillTree() - - LaunchedEffect(loginEmailState.flowState) { - if (loginEmailState.flowState is LoginState.Success) { - onSuccess(loginEmailState.flowState.initialSyncCompleted, loginEmailState.flowState.isE2EIRequired) - } else if (loginEmailState.flowState is LoginState.Error.TooManyDevicesError) { - onRemoveDeviceOpen() - } - } - if (loginEmailState.flowState is LoginState.Error.DialogError) { - LoginErrorDialog(loginEmailState.flowState, onDialogDismiss, onUpdateApp) - } - NewLoginContainer( header = { - Column { - NewLoginHeader( - title = { - if (serverConfig.isOnPremises) { - ServerTitle( - serverLinks = serverConfig, - style = typography().title01, - textColor = colorsScheme().onSurface, - titleResId = R.string.enterprise_login_on_prem_welcome_title, - modifier = Modifier.padding(bottom = dimensions().spacing24x), - ) - } - NewLoginTitle( - title = stringResource(id = R.string.enterprise_login_title), + NewLoginHeader( + title = { + if (serverConfig.isOnPremises) { + ServerTitle( + serverLinks = serverConfig, + style = typography().title01, + textColor = colorsScheme().onSurface, + titleResId = R.string.enterprise_login_on_prem_welcome_title, + modifier = Modifier.padding(bottom = dimensions().spacing24x), ) - }, - canNavigateBack = canNavigateBack, - onNavigateBack = navigateBack - ) - } + } + NewLoginSubtitle( + title = stringResource(id = R.string.enterprise_login_title), + ) + }, + canNavigateBack = canNavigateBack, + onNavigateBack = navigateBack + ) } ) { Column(modifier = Modifier.wrapContentHeight()) { @@ -328,6 +300,31 @@ private fun CreateAccountContent(onCreateAccountClicked: () -> Unit, modifier: M } } +@Composable +fun LoginStateNavigationAndDialogs(viewModel: LoginEmailViewModel, navigator: Navigator) { + val state = viewModel.loginState.flowState + LaunchedEffect(state) { + when (state) { + is LoginState.Success -> { + val destination = when { + state.isE2EIRequired -> E2EIEnrollmentScreenDestination + state.initialSyncCompleted -> HomeScreenDestination + else -> InitialSyncScreenDestination + } + navigator.navigate(NavigationCommand(destination, BackStackMode.CLEAR_WHOLE)) + } + is LoginState.Error.TooManyDevicesError -> { + viewModel.clearLoginErrors() + navigator.navigate(NavigationCommand(RemoveDeviceScreenDestination, BackStackMode.CLEAR_WHOLE)) + } + else -> { /* do nothing */ } + } + } + if (state is LoginState.Error.DialogError) { + LoginErrorDialog(state, viewModel::clearLoginErrors, viewModel::updateTheApp) + } +} + @PreviewMultipleThemes @Composable private fun PreviewNewLoginPasswordScreen() = WireTheme { @@ -340,11 +337,7 @@ private fun PreviewNewLoginPasswordScreen() = WireTheme { passwordTextState = TextFieldState(), proxyIdentifierState = TextFieldState(), proxyPasswordState = TextFieldState(), - onSuccess = { _, _ -> }, - onDialogDismiss = {}, - onRemoveDeviceOpen = {}, onLoginButtonClick = {}, - onUpdateApp = {}, onCreateAccount = {}, canNavigateBack = true, navigateBack = {}, @@ -368,11 +361,7 @@ private fun PreviewNewLoginPasswordWithProxyScreen() = WireTheme { passwordTextState = TextFieldState(), proxyIdentifierState = TextFieldState(), proxyPasswordState = TextFieldState(), - onSuccess = { _, _ -> }, - onDialogDismiss = {}, - onRemoveDeviceOpen = {}, onLoginButtonClick = {}, - onUpdateApp = {}, onCreateAccount = {}, canNavigateBack = false, navigateBack = {}, diff --git a/app/src/main/kotlin/com/wire/android/util/CurrentScreenManager.kt b/app/src/main/kotlin/com/wire/android/util/CurrentScreenManager.kt index cd5c6832b30..feaa1f1c3f5 100644 --- a/app/src/main/kotlin/com/wire/android/util/CurrentScreenManager.kt +++ b/app/src/main/kotlin/com/wire/android/util/CurrentScreenManager.kt @@ -45,6 +45,7 @@ import com.wire.android.ui.destinations.LoginScreenDestination import com.wire.android.ui.destinations.MigrationScreenDestination import com.wire.android.ui.destinations.NewLoginPasswordScreenDestination import com.wire.android.ui.destinations.NewLoginScreenDestination +import com.wire.android.ui.destinations.NewLoginVerificationCodeScreenDestination import com.wire.android.ui.destinations.NewWelcomeEmptyStartScreenDestination import com.wire.android.ui.destinations.OtherUserProfileScreenDestination import com.wire.android.ui.destinations.RegisterDeviceScreenDestination @@ -220,6 +221,7 @@ sealed class CurrentScreen { is LoginScreenDestination, is NewLoginScreenDestination, is NewLoginPasswordScreenDestination, + is NewLoginVerificationCodeScreenDestination, is CreatePersonalAccountOverviewScreenDestination, is CreateTeamAccountOverviewScreenDestination, is CreateAccountEmailScreenDestination, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 25c2eeed8aa..3b01b1e266f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -369,6 +369,7 @@ Don\'t have a Wire account? Create account Welcome to Wire Enterprise for %s! + You have mail Log in Forgot password?