PM-17388 Update existing and v3 email verification screen to match design audit (#4645)

This commit is contained in:
Dave Severns
2025-01-29 15:41:44 -05:00
committed by GitHub
parent 6a1f37b243
commit 76c7f8c41d
8 changed files with 33 additions and 110 deletions

View File

@@ -83,9 +83,6 @@ fun NavGraphBuilder.authGraph(
)
checkEmailDestination(
onNavigateBack = { navController.popBackStack() },
onNavigateBackToLanding = {
navController.popBackStack(route = LANDING_ROUTE, inclusive = false)
},
)
completeRegistrationDestination(
onNavigateBack = { navController.popBackStack() },

View File

@@ -36,7 +36,6 @@ data class CheckEmailArgs(
*/
fun NavGraphBuilder.checkEmailDestination(
onNavigateBack: () -> Unit,
onNavigateBackToLanding: () -> Unit,
) {
composableWithSlideTransitions(
route = CHECK_EMAIL_ROUTE,
@@ -46,7 +45,6 @@ fun NavGraphBuilder.checkEmailDestination(
) {
CheckEmailScreen(
onNavigateBack = onNavigateBack,
onNavigateBackToLanding = onNavigateBackToLanding,
)
}
}

View File

@@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
@@ -40,7 +39,7 @@ import com.x8bit.bitwarden.ui.platform.base.util.standardHorizontalMargin
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenFilledButton
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenTextButton
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenOutlinedButton
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
@@ -55,7 +54,6 @@ import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
@Composable
fun CheckEmailScreen(
onNavigateBack: () -> Unit,
onNavigateBackToLanding: () -> Unit,
intentManager: IntentManager = LocalIntentManager.current,
viewModel: CheckEmailViewModel = hiltViewModel(),
) {
@@ -70,8 +68,6 @@ fun CheckEmailScreen(
is CheckEmailEvent.NavigateToEmailApp -> {
intentManager.startDefaultEmailApplication()
}
CheckEmailEvent.NavigateBackToLanding -> onNavigateBackToLanding()
}
}
@@ -101,16 +97,15 @@ fun CheckEmailScreen(
email = state.email,
onOpenEmailAppClick = handler.onOpenEmailAppClick,
onChangeEmailClick = handler.onChangeEmailClick,
modifier = Modifier.standardHorizontalMargin(),
)
} else {
CheckEmailLegacyContent(
email = state.email,
onOpenEmailAppClick = handler.onOpenEmailAppClick,
onChangeEmailClick = handler.onChangeEmailClick,
onLoginClick = handler.onLoginClick,
)
}
Spacer(modifier = Modifier.height(12.dp))
Spacer(modifier = Modifier.navigationBarsPadding())
}
}
@@ -133,9 +128,11 @@ private fun CheckEmailContent(
Image(
painter = rememberVectorPainter(id = R.drawable.open_email),
contentDescription = null,
contentScale = ContentScale.Fit,
contentScale = ContentScale.FillHeight,
modifier = Modifier
.size(100.dp),
.standardHorizontalMargin()
.size(100.dp)
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(32.dp))
Text(
@@ -144,9 +141,9 @@ private fun CheckEmailContent(
style = BitwardenTheme.typography.titleMedium,
color = BitwardenTheme.colorScheme.text.primary,
modifier = Modifier
.padding(horizontal = 8.dp)
.wrapContentHeight()
.fillMaxWidth(),
.fillMaxWidth()
.standardHorizontalMargin(),
)
Spacer(modifier = Modifier.height(8.dp))
@@ -163,9 +160,9 @@ private fun CheckEmailContent(
textAlign = TextAlign.Center,
style = BitwardenTheme.typography.bodyMedium,
modifier = Modifier
.padding(horizontal = 8.dp)
.fillMaxWidth()
.wrapContentHeight(),
.wrapContentHeight()
.standardHorizontalMargin(),
)
Spacer(modifier = Modifier.height(16.dp))
@Suppress("MaxLineLength")
@@ -175,9 +172,9 @@ private fun CheckEmailContent(
color = BitwardenTheme.colorScheme.text.primary,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(horizontal = 8.dp)
.fillMaxWidth()
.wrapContentHeight(),
.wrapContentHeight()
.standardHorizontalMargin(),
)
Spacer(modifier = Modifier.height(32.dp))
BitwardenFilledButton(
@@ -185,12 +182,16 @@ private fun CheckEmailContent(
onClick = onOpenEmailAppClick,
modifier = Modifier
.testTag("OpenEmailApp")
.fillMaxWidth(),
.fillMaxWidth()
.standardHorizontalMargin(),
)
Spacer(modifier = Modifier.height(12.dp))
BitwardenTextButton(
BitwardenOutlinedButton(
label = stringResource(R.string.change_email_address),
onClick = onChangeEmailClick,
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin(),
)
}
}
@@ -201,7 +202,6 @@ private fun CheckEmailLegacyContent(
email: String,
onOpenEmailAppClick: () -> Unit,
onChangeEmailClick: () -> Unit,
onLoginClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
@@ -216,7 +216,7 @@ private fun CheckEmailLegacyContent(
contentDescription = null,
contentScale = ContentScale.FillHeight,
modifier = Modifier
.padding(horizontal = 16.dp)
.standardHorizontalMargin()
.height(112.dp)
.fillMaxWidth(),
)
@@ -227,7 +227,7 @@ private fun CheckEmailLegacyContent(
style = BitwardenTheme.typography.headlineSmall,
color = BitwardenTheme.colorScheme.text.primary,
modifier = Modifier
.padding(horizontal = 24.dp)
.standardHorizontalMargin()
.wrapContentHeight()
.fillMaxWidth(),
)
@@ -236,7 +236,7 @@ private fun CheckEmailLegacyContent(
@Suppress("MaxLineLength")
val descriptionAnnotatedString =
R.string.follow_the_instructions_in_the_email_sent_to_x_to_continue_creating_your_account.toAnnotatedString(
email,
args = arrayOf(email),
emphasisHighlightStyle = SpanStyle(
color = BitwardenTheme.colorScheme.text.primary,
fontSize = BitwardenTheme.typography.bodyMedium.fontSize,
@@ -247,8 +247,8 @@ private fun CheckEmailLegacyContent(
text = descriptionAnnotatedString,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(horizontal = 24.dp)
.fillMaxWidth()
.standardHorizontalMargin()
.wrapContentHeight(),
)
Spacer(modifier = Modifier.height(32.dp))
@@ -257,27 +257,18 @@ private fun CheckEmailLegacyContent(
onClick = onOpenEmailAppClick,
modifier = Modifier
.testTag("OpenEmailApp")
.padding(horizontal = 16.dp)
.standardHorizontalMargin()
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(32.dp))
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = R.string.no_email_go_back_to_edit_your_email_address.toAnnotatedString {
onChangeEmailClick()
},
)
Spacer(modifier = Modifier.height(32.dp))
Text(
text = R.string.or_log_in_you_may_already_have_an_account
.toAnnotatedString {
onLoginClick()
},
)
}
Spacer(modifier = Modifier.height(12.dp))
BitwardenOutlinedButton(
label = stringResource(R.string.change_email_address),
onClick = onChangeEmailClick,
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin(),
)
}
}
@@ -289,7 +280,6 @@ private fun CheckEmailScreenNewUi_preview() {
email = "email@fake.com",
onOpenEmailAppClick = { },
onChangeEmailClick = { },
modifier = Modifier.standardHorizontalMargin(),
)
}
}
@@ -302,7 +292,6 @@ private fun CheckEmailScreenLegacy_preview() {
email = "email@fake.com",
onOpenEmailAppClick = { },
onChangeEmailClick = { },
onLoginClick = {},
)
}
}

View File

@@ -53,15 +53,9 @@ class CheckEmailViewModel @Inject constructor(
is CheckEmailAction.Internal.OnboardingFeatureFlagUpdated -> {
handleOnboardingFeatureFlagUpdated(action)
}
CheckEmailAction.LoginClick -> handleLoginClick()
}
}
private fun handleLoginClick() {
sendEvent(CheckEmailEvent.NavigateBackToLanding)
}
private fun handleOnboardingFeatureFlagUpdated(
action: CheckEmailAction.Internal.OnboardingFeatureFlagUpdated,
) {
@@ -100,11 +94,6 @@ sealed class CheckEmailEvent {
* Navigate to email app.
*/
data object NavigateToEmailApp : CheckEmailEvent()
/**
* Navigate back to Landing
*/
data object NavigateBackToLanding : CheckEmailEvent()
}
/**
@@ -126,11 +115,6 @@ sealed class CheckEmailAction {
*/
data object OpenEmailClick : CheckEmailAction()
/**
* User clicked log in.
*/
data object LoginClick : CheckEmailAction()
/**
* Denotes an internal action.
*/

View File

@@ -12,7 +12,6 @@ class CheckEmailHandler(
val onOpenEmailAppClick: () -> Unit,
val onChangeEmailClick: () -> Unit,
val onBackClick: () -> Unit,
val onLoginClick: () -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
@@ -22,7 +21,6 @@ class CheckEmailHandler(
fun create(viewModel: CheckEmailViewModel) = CheckEmailHandler(
onChangeEmailClick = { viewModel.trySendAction(CheckEmailAction.ChangeEmailClick) },
onOpenEmailAppClick = { viewModel.trySendAction(CheckEmailAction.OpenEmailClick) },
onLoginClick = { viewModel.trySendAction(CheckEmailAction.LoginClick) },
onBackClick = { viewModel.trySendAction(CheckEmailAction.BackClick) },
)
}

View File

@@ -940,7 +940,7 @@ Do you want to switch to this account?</string>
<string name="user_verification_direction">User verification</string>
<string name="create_account_on">Create account on</string>
<string name="create_account_on_with_colon">Create account on:</string>
<string name="follow_the_instructions_in_the_email_sent_to_x_to_continue_creating_your_account">Follow the instructions in the email sent to %1$s to continue creating your account.</string>
<string name="follow_the_instructions_in_the_email_sent_to_x_to_continue_creating_your_account">Follow the instructions in the email sent to <annotation emphasis="bold"><annotation arg="0">%1$s</annotation></annotation> to continue creating your account.</string>
<string name="we_sent_an_email_to">We sent an email to <annotation emphasis="bold"><annotation arg="0">%1$s</annotation></annotation>.</string>
<string name="by_continuing_you_agree_to_the_terms_of_service_and_privacy_policy">By continuing, you agree to the <annotation link="termsOfService">Terms of Service</annotation> and <annotation link="privacyPolicy">Privacy Policy</annotation></string>
<string name="set_password">Set password</string>

View File

@@ -7,7 +7,6 @@ import androidx.compose.ui.test.performScrollTo
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
import com.x8bit.bitwarden.ui.util.assertLinkAnnotationIsAppliedAndInvokeClickAction
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
@@ -23,7 +22,6 @@ class CheckEmailScreenTest : BaseComposeTest() {
every { startDefaultEmailApplication() } just runs
}
private var onNavigateBackCalled = false
private var onNavigateToLandingCalled = false
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
private val mutableEventFlow = bufferedMutableSharedFlow<CheckEmailEvent>()
@@ -37,7 +35,6 @@ class CheckEmailScreenTest : BaseComposeTest() {
composeTestRule.setContent {
CheckEmailScreen(
onNavigateBack = { onNavigateBackCalled = true },
onNavigateBackToLanding = { onNavigateToLandingCalled = true },
viewModel = viewModel,
intentManager = intentManager,
)
@@ -66,12 +63,6 @@ class CheckEmailScreenTest : BaseComposeTest() {
}
}
@Test
fun `login button click should send LoginTap action`() {
mutableEventFlow.tryEmit(CheckEmailEvent.NavigateBackToLanding)
assertTrue(onNavigateToLandingCalled)
}
@Test
fun `NavigateBack should call onNavigateBack`() {
mutableEventFlow.tryEmit(CheckEmailEvent.NavigateBack)
@@ -86,28 +77,6 @@ class CheckEmailScreenTest : BaseComposeTest() {
}
}
@Test
fun `go back and update email text click should send ChangeEmailClick action`() {
mutableStateFlow.value = DEFAULT_STATE.copy(showNewOnboardingUi = false)
val mainString = "No email? Go back to edit your email address."
composeTestRule.assertLinkAnnotationIsAppliedAndInvokeClickAction(
mainString = mainString,
)
verify { viewModel.trySendAction(CheckEmailAction.ChangeEmailClick) }
}
@Test
fun `already have account text click should send ChangeEmailClick action`() {
mutableStateFlow.value = DEFAULT_STATE.copy(showNewOnboardingUi = false)
val mainString = "Or log in, you may already have an account."
composeTestRule.assertLinkAnnotationIsAppliedAndInvokeClickAction(
mainString = mainString,
)
verify { viewModel.trySendAction(CheckEmailAction.LoginClick) }
}
@Test
fun `change email button click should send ChangeEmailClick action`() {
mutableStateFlow.value = DEFAULT_STATE.copy(showNewOnboardingUi = true)

View File

@@ -84,18 +84,6 @@ class CheckEmailViewModelTest : BaseViewModelTest() {
assertEquals(expectedState, viewModel.stateFlow.value)
}
@Test
fun `OnLoginClick action should send NavigateToLanding event`() = runTest {
val viewModel = createViewModel()
viewModel.eventFlow.test {
viewModel.trySendAction(CheckEmailAction.LoginClick)
assertEquals(
CheckEmailEvent.NavigateBackToLanding,
awaitItem(),
)
}
}
private fun createViewModel(state: CheckEmailState? = null): CheckEmailViewModel =
CheckEmailViewModel(
featureFlagManager = featureFlagManager,