PM-11192 update check email screen to new design (#3788)

This commit is contained in:
Dave Severns 2024-08-20 18:17:03 -04:00 committed by GitHub
parent 8d08b5f7c5
commit 86dabea39f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 275 additions and 154 deletions

View file

@ -80,9 +80,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

@ -9,9 +9,9 @@ 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
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
@ -23,7 +23,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.testTag
@ -31,23 +30,22 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
import com.x8bit.bitwarden.ui.platform.base.util.createAnnotatedString
import com.x8bit.bitwarden.ui.platform.base.util.standardHorizontalMargin
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.scaffold.BitwardenScaffold
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
/**
* Constant string to be used in string annotation tag field
*/
private const val TAG_URL = "URL"
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
/**
* Top level composable for the check email screen.
@ -57,7 +55,6 @@ private const val TAG_URL = "URL"
@Composable
fun CheckEmailScreen(
onNavigateBack: () -> Unit,
onNavigateBackToLanding: () -> Unit,
intentManager: IntentManager = LocalIntentManager.current,
viewModel: CheckEmailViewModel = hiltViewModel(),
) {
@ -71,10 +68,6 @@ fun CheckEmailScreen(
is CheckEmailEvent.NavigateToEmailApp -> {
intentManager.startDefaultEmailApplication()
}
is CheckEmailEvent.NavigateBackToLanding -> {
onNavigateBackToLanding.invoke()
}
}
}
@ -87,10 +80,10 @@ fun CheckEmailScreen(
BitwardenTopAppBar(
title = stringResource(id = R.string.create_account),
scrollBehavior = scrollBehavior,
navigationIcon = rememberVectorPainter(id = R.drawable.ic_close),
navigationIconContentDescription = stringResource(id = R.string.close),
navigationIcon = rememberVectorPainter(id = R.drawable.ic_back),
navigationIconContentDescription = stringResource(id = R.string.back),
onNavigationIconClick = remember(viewModel) {
{ viewModel.trySendAction(CheckEmailAction.CloseClick) }
{ viewModel.trySendAction(CheckEmailAction.BackClick) }
},
)
},
@ -102,105 +95,118 @@ fun CheckEmailScreen(
.fillMaxSize()
.verticalScroll(rememberScrollState()),
) {
Spacer(modifier = Modifier.height(32.dp))
Image(
painter = rememberVectorPainter(id = R.drawable.email_check),
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.primary),
contentDescription = null,
contentScale = ContentScale.FillHeight,
modifier = Modifier
.padding(horizontal = 16.dp)
.height(112.dp)
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(32.dp))
Text(
text = stringResource(id = R.string.check_your_email),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier
.padding(horizontal = 24.dp)
.wrapContentHeight()
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(16.dp))
@Suppress("MaxLineLength")
val descriptionAnnotatedString = createAnnotatedString(
mainString = stringResource(
id = R.string.follow_the_instructions_in_the_email_sent_to_x_to_continue_creating_your_account,
state.email,
),
highlights = listOf(state.email),
highlightStyle = SpanStyle(
color = MaterialTheme.colorScheme.onSurface,
fontSize = MaterialTheme.typography.bodyMedium.fontSize,
fontWeight = FontWeight.Bold,
),
tag = "EMAIL",
)
Text(
text = descriptionAnnotatedString,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(horizontal = 24.dp)
.fillMaxWidth()
.wrapContentHeight(),
)
Spacer(modifier = Modifier.height(32.dp))
BitwardenFilledButton(
label = stringResource(id = R.string.open_email_app),
onClick = remember(viewModel) {
{ viewModel.trySendAction(CheckEmailAction.OpenEmailClick) }
CheckEmailContent(
email = state.email,
onOpenEmailAppClick = remember(viewModel) {
{
viewModel.trySendAction(CheckEmailAction.OpenEmailClick)
}
},
modifier = Modifier
.testTag("OpenEmailApp")
.padding(horizontal = 16.dp)
.fillMaxWidth(),
onChangeEmailClick = remember(viewModel) {
{
viewModel.trySendAction(CheckEmailAction.ChangeEmailClick)
}
},
modifier = Modifier.standardHorizontalMargin(),
)
Spacer(modifier = Modifier.height(32.dp))
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
val goBackAnnotatedString = createAnnotatedString(
mainString = stringResource(
id = R.string.no_email_go_back_to_edit_your_email_address,
),
highlights = listOf(stringResource(id = R.string.go_back)),
tag = TAG_URL,
)
ClickableText(
text = goBackAnnotatedString,
onClick = {
goBackAnnotatedString
.getStringAnnotations(TAG_URL, it, it)
.firstOrNull()?.let {
viewModel.trySendAction(CheckEmailAction.CloseClick)
}
},
)
Spacer(modifier = Modifier.height(32.dp))
val logInAnnotatedString = createAnnotatedString(
mainString = stringResource(
id = R.string.or_log_in_you_may_already_have_an_account,
),
highlights = listOf(stringResource(id = R.string.log_in)),
tag = TAG_URL,
)
ClickableText(
text = logInAnnotatedString,
onClick = {
logInAnnotatedString
.getStringAnnotations(TAG_URL, it, it)
.firstOrNull()?.let {
viewModel.trySendAction(CheckEmailAction.LoginClick)
}
},
)
}
Spacer(modifier = Modifier.navigationBarsPadding())
}
}
}
@Suppress("LongMethod")
@Composable
private fun CheckEmailContent(
email: String,
onOpenEmailAppClick: () -> Unit,
onChangeEmailClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Spacer(modifier = Modifier.height(32.dp))
Image(
painter = rememberVectorPainter(id = R.drawable.open_email),
contentDescription = null,
contentScale = ContentScale.Fit,
modifier = Modifier
.size(100.dp),
)
Spacer(modifier = Modifier.height(32.dp))
Text(
text = stringResource(id = R.string.check_your_email),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier
.padding(horizontal = 8.dp)
.wrapContentHeight()
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(8.dp))
val descriptionAnnotatedString = createAnnotatedString(
mainString = stringResource(
id = R.string.we_sent_an_email_to,
email,
),
highlights = listOf(email),
highlightStyle = SpanStyle(
color = MaterialTheme.colorScheme.onSurface,
fontSize = MaterialTheme.typography.bodyMedium.fontSize,
fontWeight = FontWeight.Bold,
),
tag = "EMAIL",
)
Text(
text = descriptionAnnotatedString,
textAlign = TextAlign.Center,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier
.padding(horizontal = 8.dp)
.fillMaxWidth()
.wrapContentHeight(),
)
Spacer(modifier = Modifier.height(16.dp))
@Suppress("MaxLineLength")
Text(
text = stringResource(R.string.select_the_link_in_the_email_to_verify_your_email_address_and_continue_creating_your_account),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(horizontal = 8.dp)
.fillMaxWidth()
.wrapContentHeight(),
)
Spacer(modifier = Modifier.height(32.dp))
BitwardenFilledButton(
label = stringResource(id = R.string.open_email_app),
onClick = onOpenEmailAppClick,
modifier = Modifier
.testTag("OpenEmailApp")
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(12.dp))
BitwardenTextButton(
label = stringResource(R.string.change_email_address),
onClick = onChangeEmailClick,
)
}
}
@Preview(showBackground = true)
@Composable
private fun CheckEmailScreenPreview() {
BitwardenTheme {
CheckEmailContent(
email = "email@fake.com",
onOpenEmailAppClick = { },
onChangeEmailClick = { },
modifier = Modifier.standardHorizontalMargin(),
)
}
}

View file

@ -33,11 +33,17 @@ class CheckEmailViewModel @Inject constructor(
override fun handleAction(action: CheckEmailAction) {
when (action) {
CheckEmailAction.CloseClick -> sendEvent(CheckEmailEvent.NavigateBack)
CheckEmailAction.LoginClick -> sendEvent(CheckEmailEvent.NavigateBackToLanding)
CheckEmailAction.OpenEmailClick -> sendEvent(CheckEmailEvent.NavigateToEmailApp)
CheckEmailAction.BackClick -> handleBackClick()
CheckEmailAction.OpenEmailClick -> handleOpenEmailClick()
CheckEmailAction.ChangeEmailClick -> handleChangeEmailClick()
}
}
private fun handleOpenEmailClick() = sendEvent(CheckEmailEvent.NavigateToEmailApp)
private fun handleBackClick() = sendEvent(CheckEmailEvent.NavigateBack)
private fun handleChangeEmailClick() = sendEvent(CheckEmailEvent.NavigateBack)
}
/**
@ -62,11 +68,6 @@ sealed class CheckEmailEvent {
* Navigate to email app.
*/
data object NavigateToEmailApp : CheckEmailEvent()
/**
* Navigate to landing screen.
*/
data object NavigateBackToLanding : CheckEmailEvent()
}
/**
@ -76,12 +77,12 @@ sealed class CheckEmailAction {
/**
* User clicked close.
*/
data object CloseClick : CheckEmailAction()
data object BackClick : CheckEmailAction()
/**
* User clicked log in.
* User clicked change email.
*/
data object LoginClick : CheckEmailAction()
data object ChangeEmailClick : CheckEmailAction()
/**
* User clicked open email.

View file

@ -0,0 +1,54 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="197dp"
android:height="164dp"
android:viewportWidth="197"
android:viewportHeight="164">
<path
android:pathData="M89.79,9.59C85.92,6.59 80.54,6.55 76.62,9.48L64.3,18.71C63.41,19.37 62.16,19.19 61.5,18.31C60.84,17.42 61.02,16.17 61.9,15.51L74.23,6.28C79.58,2.27 86.95,2.33 92.24,6.42L94.8,8.41C95.67,9.08 95.83,10.34 95.15,11.21C94.48,12.09 93.22,12.25 92.35,11.57L89.79,9.59ZM21.6,48.19C22.26,49.08 22.08,50.33 21.2,50.99L8.35,60.62C5.61,62.67 4,65.89 4,69.31V148.26C4,154.26 8.86,159.12 14.86,159.12H152.88C158.88,159.12 163.75,154.26 163.75,148.26V103.35C163.75,102.24 164.64,101.35 165.75,101.35C166.85,101.35 167.75,102.24 167.75,103.35V148.26C167.75,156.46 161.09,163.12 152.88,163.12H14.86C6.65,163.12 0,156.46 0,148.26V69.31C0,64.63 2.21,60.22 5.95,57.41L18.8,47.79C19.69,47.13 20.94,47.31 21.6,48.19ZM165.75,60.87C166.85,60.87 167.75,61.77 167.75,62.87V84.94C167.75,86.05 166.85,86.94 165.75,86.94C164.64,86.94 163.75,86.05 163.75,84.94V62.87C163.75,61.77 164.64,60.87 165.75,60.87Z"
android:fillColor="#E2E3E4"
android:fillType="evenOdd"/>
<path
android:pathData="M25.44,19.61C24.18,19.61 23.16,20.63 23.16,21.89V78.03C23.16,79.13 22.26,80.03 21.16,80.03C20.05,80.03 19.16,79.13 19.16,78.03V21.89C19.16,18.42 21.97,15.61 25.44,15.61H84.36C85.47,15.61 86.36,16.5 86.36,17.61C86.36,18.71 85.47,19.61 84.36,19.61H25.44Z"
android:fillColor="#6FD9E2"
android:fillType="evenOdd"/>
<path
android:pathData="M34.33,36.2C34.33,35.1 35.23,34.2 36.33,34.2H64.99C66.1,34.2 66.99,35.1 66.99,36.2C66.99,37.31 66.1,38.2 64.99,38.2H36.33C35.23,38.2 34.33,37.31 34.33,36.2Z"
android:fillColor="#6FD9E2"
android:fillType="evenOdd"/>
<path
android:pathData="M34.33,53.32C34.33,52.22 35.23,51.32 36.33,51.32H64.16C65.26,51.32 66.16,52.22 66.16,53.32C66.16,54.42 65.26,55.32 64.16,55.32H36.33C35.23,55.32 34.33,54.42 34.33,53.32Z"
android:fillColor="#6FD9E2"
android:fillType="evenOdd"/>
<path
android:pathData="M34.33,70.44C34.33,69.33 35.23,68.44 36.33,68.44H68.75C69.85,68.44 70.75,69.33 70.75,70.44C70.75,71.54 69.85,72.44 68.75,72.44H36.33C35.23,72.44 34.33,71.54 34.33,70.44Z"
android:fillColor="#6FD9E2"
android:fillType="evenOdd"/>
<path
android:pathData="M34.33,87.56C34.33,86.46 35.23,85.56 36.33,85.56H78.76C79.87,85.56 80.76,86.46 80.76,87.56C80.76,88.67 79.87,89.56 78.76,89.56H36.33C35.23,89.56 34.33,88.67 34.33,87.56Z"
android:fillColor="#6FD9E2"
android:fillType="evenOdd"/>
<path
android:pathData="M53.59,108.05C57.97,103.8 63.83,101.42 69.93,101.42H95.35C101.26,101.42 106.95,103.65 111.28,107.66L163.62,156.15L160.9,159.09L108.56,110.6C104.97,107.27 100.25,105.42 95.35,105.42H69.93C64.87,105.42 60.01,107.39 56.38,110.92L6.87,159.06L4.08,156.19L53.59,108.05Z"
android:fillColor="#E2E3E4"
android:fillType="evenOdd"/>
<path
android:pathData="M123.04,93.78C123.59,94.74 123.26,95.96 122.3,96.51L106.02,105.89C105.06,106.44 103.84,106.11 103.29,105.15C102.75,104.19 103.08,102.96 104.04,102.41L120.32,93.04C121.27,92.49 122.49,92.82 123.04,93.78Z"
android:fillColor="#E2E3E4"
android:fillType="evenOdd"/>
<path
android:pathData="M1.85,67.55C1.29,68.5 1.6,69.73 2.55,70.29L61.83,105.83C62.77,106.4 64,106.09 64.56,105.14C65.13,104.19 64.82,102.96 63.87,102.39L4.59,66.86C3.64,66.29 2.42,66.6 1.85,67.55Z"
android:fillColor="#E2E3E4"
android:fillType="evenOdd"/>
<path
android:pathData="M75.87,48.27C75.87,23.81 95.62,4 119.97,4C144.31,4 164.06,23.81 164.06,48.27C164.06,72.72 144.31,92.53 119.97,92.53C95.62,92.53 75.87,72.72 75.87,48.27ZM119.97,-0C93.4,-0 71.87,21.62 71.87,48.27C71.87,74.92 93.4,96.53 119.97,96.53C146.54,96.53 168.06,74.92 168.06,48.27C168.06,21.62 146.54,-0 119.97,-0Z"
android:fillColor="#E2E3E4"
android:fillType="evenOdd"/>
<path
android:pathData="M118.72,88.06C118.72,88.65 119.2,89.13 119.79,89.13C142.52,89.13 160.96,70.84 160.96,48.27C160.96,47.68 160.48,47.2 159.89,47.2C159.3,47.2 158.82,47.68 158.82,48.27C158.82,69.64 141.35,86.99 119.79,86.99C119.2,86.99 118.72,87.47 118.72,88.06ZM79.69,49.34C80.28,49.34 80.76,48.86 80.76,48.27C80.76,26.89 98.23,9.55 119.79,9.55C120.38,9.55 120.86,9.07 120.86,8.48C120.86,7.89 120.38,7.41 119.79,7.41C97.06,7.41 78.62,25.69 78.62,48.27C78.62,48.86 79.1,49.34 79.69,49.34Z"
android:fillColor="#E2E3E4"
android:fillType="evenOdd"/>
<path
android:pathData="M188.81,111.53C190.12,112.85 190.12,114.98 188.81,116.29L187.81,117.29C186.5,118.61 184.38,118.61 183.07,117.29L149.62,83.71C148.84,82.93 147.57,82.93 146.79,83.71C146.01,84.5 146.01,85.77 146.79,86.55L180.25,120.13C183.11,123.01 187.76,123.01 190.63,120.13L191.63,119.13C194.5,116.25 194.5,111.58 191.63,108.7L158.18,75.12C157.4,74.34 156.13,74.34 155.35,75.12C154.57,75.9 154.57,77.17 155.35,77.96L188.81,111.53Z"
android:fillColor="#E2E3E4"
android:fillType="evenOdd"/>
</vector>

View file

@ -0,0 +1,54 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="197dp"
android:height="164dp"
android:viewportWidth="197"
android:viewportHeight="164">
<path
android:pathData="M89.79,9.59C85.92,6.59 80.54,6.55 76.62,9.48L64.3,18.71C63.41,19.37 62.16,19.19 61.5,18.31C60.84,17.42 61.02,16.17 61.9,15.51L74.23,6.28C79.58,2.27 86.95,2.33 92.24,6.42L94.8,8.41C95.67,9.08 95.83,10.34 95.15,11.21C94.48,12.09 93.22,12.25 92.35,11.57L89.79,9.59ZM21.6,48.19C22.26,49.08 22.08,50.33 21.2,50.99L8.35,60.62C5.61,62.67 4,65.89 4,69.31V148.26C4,154.26 8.86,159.12 14.86,159.12H152.88C158.88,159.12 163.75,154.26 163.75,148.26V103.35C163.75,102.24 164.64,101.35 165.75,101.35C166.85,101.35 167.75,102.24 167.75,103.35V148.26C167.75,156.46 161.09,163.12 152.88,163.12H14.86C6.65,163.12 0,156.46 0,148.26V69.31C0,64.63 2.21,60.22 5.95,57.41L18.8,47.79C19.69,47.13 20.94,47.31 21.6,48.19ZM165.75,60.87C166.85,60.87 167.75,61.77 167.75,62.87V84.94C167.75,86.05 166.85,86.94 165.75,86.94C164.64,86.94 163.75,86.05 163.75,84.94V62.87C163.75,61.77 164.64,60.87 165.75,60.87Z"
android:fillColor="#020F66"
android:fillType="evenOdd"/>
<path
android:pathData="M25.44,19.61C24.18,19.61 23.16,20.63 23.16,21.89V78.03C23.16,79.13 22.26,80.03 21.16,80.03C20.05,80.03 19.16,79.13 19.16,78.03V21.89C19.16,18.42 21.97,15.61 25.44,15.61H84.36C85.47,15.61 86.36,16.5 86.36,17.61C86.36,18.71 85.47,19.61 84.36,19.61H25.44Z"
android:fillColor="#10949D"
android:fillType="evenOdd"/>
<path
android:pathData="M34.33,36.2C34.33,35.1 35.23,34.2 36.33,34.2H64.99C66.1,34.2 66.99,35.1 66.99,36.2C66.99,37.31 66.1,38.2 64.99,38.2H36.33C35.23,38.2 34.33,37.31 34.33,36.2Z"
android:fillColor="#10949D"
android:fillType="evenOdd"/>
<path
android:pathData="M34.33,53.32C34.33,52.22 35.23,51.32 36.33,51.32H64.16C65.26,51.32 66.16,52.22 66.16,53.32C66.16,54.43 65.26,55.32 64.16,55.32H36.33C35.23,55.32 34.33,54.43 34.33,53.32Z"
android:fillColor="#10949D"
android:fillType="evenOdd"/>
<path
android:pathData="M34.33,70.44C34.33,69.33 35.23,68.44 36.33,68.44H68.75C69.85,68.44 70.75,69.33 70.75,70.44C70.75,71.54 69.85,72.44 68.75,72.44H36.33C35.23,72.44 34.33,71.54 34.33,70.44Z"
android:fillColor="#10949D"
android:fillType="evenOdd"/>
<path
android:pathData="M34.33,87.56C34.33,86.46 35.23,85.56 36.33,85.56H78.76C79.87,85.56 80.76,86.46 80.76,87.56C80.76,88.67 79.87,89.56 78.76,89.56H36.33C35.23,89.56 34.33,88.67 34.33,87.56Z"
android:fillColor="#10949D"
android:fillType="evenOdd"/>
<path
android:pathData="M53.59,108.05C57.97,103.8 63.83,101.42 69.93,101.42H95.35C101.26,101.42 106.95,103.65 111.28,107.66L163.62,156.15L160.9,159.09L108.56,110.6C104.97,107.27 100.25,105.42 95.35,105.42H69.93C64.87,105.42 60.01,107.39 56.38,110.92L6.87,159.05L4.08,156.19L53.59,108.05Z"
android:fillColor="#020F66"
android:fillType="evenOdd"/>
<path
android:pathData="M123.04,93.78C123.59,94.74 123.26,95.96 122.3,96.51L106.02,105.89C105.06,106.44 103.84,106.11 103.29,105.15C102.75,104.19 103.08,102.96 104.04,102.41L120.32,93.04C121.27,92.49 122.49,92.82 123.04,93.78Z"
android:fillColor="#020F66"
android:fillType="evenOdd"/>
<path
android:pathData="M1.85,67.55C1.29,68.5 1.6,69.73 2.55,70.29L61.83,105.83C62.77,106.4 64,106.09 64.56,105.14C65.13,104.19 64.82,102.96 63.87,102.39L4.59,66.86C3.64,66.29 2.42,66.6 1.85,67.55Z"
android:fillColor="#020F66"
android:fillType="evenOdd"/>
<path
android:pathData="M75.87,48.27C75.87,23.81 95.62,4 119.97,4C144.31,4 164.06,23.81 164.06,48.27C164.06,72.72 144.31,92.53 119.97,92.53C95.62,92.53 75.87,72.72 75.87,48.27ZM119.97,-0C93.4,-0 71.87,21.62 71.87,48.27C71.87,74.92 93.4,96.53 119.97,96.53C146.54,96.53 168.06,74.92 168.06,48.27C168.06,21.62 146.54,-0 119.97,-0Z"
android:fillColor="#020F66"
android:fillType="evenOdd"/>
<path
android:pathData="M118.72,88.06C118.72,88.65 119.2,89.13 119.79,89.13C142.52,89.13 160.96,70.84 160.96,48.27C160.96,47.68 160.48,47.2 159.89,47.2C159.3,47.2 158.82,47.68 158.82,48.27C158.82,69.64 141.35,86.99 119.79,86.99C119.2,86.99 118.72,87.47 118.72,88.06ZM79.69,49.34C80.28,49.34 80.76,48.86 80.76,48.27C80.76,26.89 98.23,9.55 119.79,9.55C120.38,9.55 120.86,9.07 120.86,8.48C120.86,7.89 120.38,7.41 119.79,7.41C97.06,7.41 78.62,25.69 78.62,48.27C78.62,48.86 79.1,49.34 79.69,49.34Z"
android:fillColor="#020F66"
android:fillType="evenOdd"/>
<path
android:pathData="M188.81,111.53C190.12,112.85 190.12,114.98 188.81,116.29L187.81,117.29C186.5,118.61 184.38,118.61 183.07,117.29L149.62,83.71C148.84,82.93 147.57,82.93 146.79,83.71C146.01,84.5 146.01,85.77 146.79,86.55L180.25,120.13C183.11,123.01 187.76,123.01 190.63,120.13L191.63,119.13C194.5,116.25 194.5,111.58 191.63,108.7L158.18,75.12C157.4,74.34 156.13,74.34 155.35,75.12C154.57,75.9 154.57,77.17 155.35,77.96L188.81,111.53Z"
android:fillColor="#020F66"
android:fillType="evenOdd"/>
</vector>

View file

@ -930,6 +930,7 @@ Do you want to switch to this account?</string>
<string name="user_verification_direction">User verification</string>
<string name="creating_on">Creating 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="we_sent_an_email_to">We sent an email to %1$s.</string>
<string name="by_continuing_you_agree_to_the_terms_of_service_and_privacy_policy">By continuing, you agree to the Terms of Service and Privacy Policy</string>
<string name="set_password">Set password</string>
<string name="unsubscribe">Unsubscribe</string>
@ -979,4 +980,6 @@ Do you want to switch to this account?</string>
<string name="learn_about_other_ways_to_prevent_account_lockout">Learn about other ways to prevent account lockout</string>
<string name="help_with_server_geolocations">Help with server geolocations.</string>
<string name="email_address_required">Email address (required)</string>
<string name="select_the_link_in_the_email_to_verify_your_email_address_and_continue_creating_your_account">"Select the link in the email to verify your email address and continue creating your account. "</string>
<string name="change_email_address">Change email address</string>
</resources>

View file

@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.auth.feature.checkemail
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
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
@ -21,8 +22,6 @@ class CheckEmailScreenTest : BaseComposeTest() {
every { startDefaultEmailApplication() } just runs
}
private var onNavigateBackCalled = false
private var onNavigateBackToLandingCalled = false
private var onNavigateToEmailAppCalled = false
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
private val mutableEventFlow = bufferedMutableSharedFlow<CheckEmailEvent>()
@ -36,7 +35,6 @@ class CheckEmailScreenTest : BaseComposeTest() {
composeTestRule.setContent {
CheckEmailScreen(
onNavigateBack = { onNavigateBackCalled = true },
onNavigateBackToLanding = { onNavigateBackToLandingCalled = true },
viewModel = viewModel,
intentManager = intentManager,
)
@ -44,27 +42,27 @@ class CheckEmailScreenTest : BaseComposeTest() {
}
@Test
fun `close button click should send CloseTap action`() {
composeTestRule.onNodeWithContentDescription("Close").performClick()
fun `close button click should send BackClick action`() {
composeTestRule
.onNodeWithContentDescription("Back")
.performClick()
verify {
viewModel.trySendAction(CheckEmailAction.CloseClick)
viewModel.trySendAction(CheckEmailAction.BackClick)
}
}
@Test
fun `open email app button click should send OpenEmailTap action`() {
composeTestRule.onNodeWithText("Open email app").performClick()
fun `open email app button click should send OpenEmailClcik action`() {
composeTestRule
.onNodeWithText("Open email app")
.performScrollTo()
.performClick()
verify {
viewModel.trySendAction(CheckEmailAction.OpenEmailClick)
}
}
@Test
fun `login button click should send LoginTap action`() {
mutableEventFlow.tryEmit(CheckEmailEvent.NavigateBackToLanding)
TestCase.assertTrue(onNavigateBackToLandingCalled)
}
@Test
fun `NavigateBack should call onNavigateBack`() {
mutableEventFlow.tryEmit(CheckEmailEvent.NavigateBack)
@ -79,6 +77,16 @@ class CheckEmailScreenTest : BaseComposeTest() {
}
}
@Test
fun `change email button click should send ChangeEmailClick action`() {
composeTestRule
.onNodeWithText("Change email address")
.performScrollTo()
.performClick()
verify { viewModel.trySendAction(CheckEmailAction.ChangeEmailClick) }
}
companion object {
private const val EMAIL = "test@gmail.com"
private val DEFAULT_STATE = CheckEmailState(

View file

@ -31,7 +31,7 @@ class CheckEmailViewModelTest : BaseViewModelTest() {
fun `CloseTap should emit NavigateBack`() = runTest {
val viewModel = createViewModel()
viewModel.eventFlow.test {
viewModel.trySendAction(CheckEmailAction.CloseClick)
viewModel.trySendAction(CheckEmailAction.BackClick)
assertEquals(
CheckEmailEvent.NavigateBack,
awaitItem(),
@ -39,18 +39,6 @@ class CheckEmailViewModelTest : BaseViewModelTest() {
}
}
@Test
fun `LoginTap should emit NavigateBackToLanding`() = runTest {
val viewModel = createViewModel()
viewModel.eventFlow.test {
viewModel.trySendAction(CheckEmailAction.LoginClick)
assertEquals(
CheckEmailEvent.NavigateBackToLanding,
awaitItem(),
)
}
}
@Test
fun `OpenEmailTap should emit NavigateToEmailApp`() = runTest {
val viewModel = createViewModel()
@ -63,6 +51,18 @@ class CheckEmailViewModelTest : BaseViewModelTest() {
}
}
@Test
fun `ChangeEmailTap should emit NavigateBack`() = runTest {
val viewModel = createViewModel()
viewModel.eventFlow.test {
viewModel.trySendAction(CheckEmailAction.ChangeEmailClick)
assertEquals(
CheckEmailEvent.NavigateBack,
awaitItem(),
)
}
}
private fun createViewModel(state: CheckEmailState? = null): CheckEmailViewModel =
CheckEmailViewModel(
savedStateHandle = SavedStateHandle().also {