mirror of
https://github.com/bitwarden/android.git
synced 2024-11-27 20:10:33 +03:00
[PM-11270] Hide all new UI behind onboarding flow flag. (#3810)
This commit is contained in:
parent
b56a21b6e5
commit
82d3b44712
11 changed files with 476 additions and 51 deletions
|
@ -81,6 +81,9 @@ fun NavGraphBuilder.authGraph(
|
|||
)
|
||||
checkEmailDestination(
|
||||
onNavigateBack = { navController.popBackStack() },
|
||||
onNavigateBackToLanding = {
|
||||
navController.popBackStack(route = LANDING_ROUTE, inclusive = false)
|
||||
},
|
||||
)
|
||||
completeRegistrationDestination(
|
||||
onNavigateBack = { navController.popBackStack() },
|
||||
|
|
|
@ -36,6 +36,7 @@ data class CheckEmailArgs(
|
|||
*/
|
||||
fun NavGraphBuilder.checkEmailDestination(
|
||||
onNavigateBack: () -> Unit,
|
||||
onNavigateBackToLanding: () -> Unit,
|
||||
) {
|
||||
composableWithSlideTransitions(
|
||||
route = CHECK_EMAIL_ROUTE,
|
||||
|
@ -45,6 +46,7 @@ fun NavGraphBuilder.checkEmailDestination(
|
|||
) {
|
||||
CheckEmailScreen(
|
||||
onNavigateBack = onNavigateBack,
|
||||
onNavigateBackToLanding = onNavigateBackToLanding,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ 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
|
||||
|
@ -20,13 +21,17 @@ import androidx.compose.material3.TopAppBarDefaults
|
|||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
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
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.semantics.onClick
|
||||
import androidx.compose.ui.semantics.role
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
|
@ -35,6 +40,7 @@ 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.auth.feature.checkemail.handlers.rememberCheckEmailHandler
|
||||
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
|
||||
|
@ -47,6 +53,8 @@ import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
|
|||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
|
||||
private const val TAG_URL = "URL"
|
||||
|
||||
/**
|
||||
* Top level composable for the check email screen.
|
||||
*/
|
||||
|
@ -55,19 +63,23 @@ import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
|||
@Composable
|
||||
fun CheckEmailScreen(
|
||||
onNavigateBack: () -> Unit,
|
||||
onNavigateBackToLanding: () -> Unit,
|
||||
intentManager: IntentManager = LocalIntentManager.current,
|
||||
viewModel: CheckEmailViewModel = hiltViewModel(),
|
||||
) {
|
||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
val handler = rememberCheckEmailHandler(viewModel = viewModel)
|
||||
EventsEffect(viewModel) { event ->
|
||||
when (event) {
|
||||
is CheckEmailEvent.NavigateBack -> {
|
||||
onNavigateBack.invoke()
|
||||
onNavigateBack()
|
||||
}
|
||||
|
||||
is CheckEmailEvent.NavigateToEmailApp -> {
|
||||
intentManager.startDefaultEmailApplication()
|
||||
}
|
||||
|
||||
CheckEmailEvent.NavigateBackToLanding -> onNavigateBackToLanding()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,9 +94,7 @@ fun CheckEmailScreen(
|
|||
scrollBehavior = scrollBehavior,
|
||||
navigationIcon = rememberVectorPainter(id = R.drawable.ic_back),
|
||||
navigationIconContentDescription = stringResource(id = R.string.back),
|
||||
onNavigationIconClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(CheckEmailAction.BackClick) }
|
||||
},
|
||||
onNavigationIconClick = handler.onBackClick,
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
|
@ -95,20 +105,21 @@ fun CheckEmailScreen(
|
|||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
if (state.showNewOnboardingUi) {
|
||||
CheckEmailContent(
|
||||
email = state.email,
|
||||
onOpenEmailAppClick = remember(viewModel) {
|
||||
{
|
||||
viewModel.trySendAction(CheckEmailAction.OpenEmailClick)
|
||||
}
|
||||
},
|
||||
onChangeEmailClick = remember(viewModel) {
|
||||
{
|
||||
viewModel.trySendAction(CheckEmailAction.ChangeEmailClick)
|
||||
}
|
||||
},
|
||||
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.navigationBarsPadding())
|
||||
}
|
||||
}
|
||||
|
@ -198,9 +209,136 @@ private fun CheckEmailContent(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun CheckEmailLegacyContent(
|
||||
email: String,
|
||||
onOpenEmailAppClick: () -> Unit,
|
||||
onChangeEmailClick: () -> Unit,
|
||||
onLoginClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
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,
|
||||
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,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 24.dp)
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
BitwardenFilledButton(
|
||||
label = stringResource(id = R.string.open_email_app),
|
||||
onClick = onOpenEmailAppClick,
|
||||
modifier = Modifier
|
||||
.testTag("OpenEmailApp")
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
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 {
|
||||
onChangeEmailClick()
|
||||
}
|
||||
},
|
||||
modifier = Modifier.semantics {
|
||||
role = Role.Button
|
||||
onClick {
|
||||
onChangeEmailClick()
|
||||
true
|
||||
}
|
||||
},
|
||||
)
|
||||
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 {
|
||||
onLoginClick()
|
||||
}
|
||||
},
|
||||
modifier = Modifier.semantics {
|
||||
role = Role.Button
|
||||
onClick {
|
||||
onLoginClick()
|
||||
true
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun CheckEmailScreenPreview() {
|
||||
private fun CheckEmailScreenNewUi_preview() {
|
||||
BitwardenTheme {
|
||||
CheckEmailContent(
|
||||
email = "email@fake.com",
|
||||
|
@ -210,3 +348,16 @@ private fun CheckEmailScreenPreview() {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun CheckEmailScreenLegacy_preview() {
|
||||
BitwardenTheme {
|
||||
CheckEmailLegacyContent(
|
||||
email = "email@fake.com",
|
||||
onOpenEmailAppClick = { },
|
||||
onChangeEmailClick = { },
|
||||
onLoginClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,14 @@ package com.x8bit.bitwarden.ui.auth.feature.checkemail
|
|||
import android.os.Parcelable
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
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.parcelize.Parcelize
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -17,11 +21,13 @@ private const val KEY_STATE = "state"
|
|||
*/
|
||||
@HiltViewModel
|
||||
class CheckEmailViewModel @Inject constructor(
|
||||
featureFlagManager: FeatureFlagManager,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : BaseViewModel<CheckEmailState, CheckEmailEvent, CheckEmailAction>(
|
||||
initialState = savedStateHandle[KEY_STATE]
|
||||
?: CheckEmailState(
|
||||
email = CheckEmailArgs(savedStateHandle).emailAddress,
|
||||
showNewOnboardingUi = featureFlagManager.getFeatureFlag(FlagKey.OnboardingFlow),
|
||||
),
|
||||
) {
|
||||
init {
|
||||
|
@ -29,6 +35,14 @@ class CheckEmailViewModel @Inject constructor(
|
|||
stateFlow
|
||||
.onEach { savedStateHandle[KEY_STATE] = it }
|
||||
.launchIn(viewModelScope)
|
||||
// Listen for changes on the onboarding feature flag.
|
||||
featureFlagManager
|
||||
.getFeatureFlagFlow(FlagKey.OnboardingFlow)
|
||||
.map {
|
||||
CheckEmailAction.Internal.OnboardingFeatureFlagUpdated(it)
|
||||
}
|
||||
.onEach(::sendAction)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
override fun handleAction(action: CheckEmailAction) {
|
||||
|
@ -36,6 +50,23 @@ class CheckEmailViewModel @Inject constructor(
|
|||
CheckEmailAction.BackClick -> handleBackClick()
|
||||
CheckEmailAction.OpenEmailClick -> handleOpenEmailClick()
|
||||
CheckEmailAction.ChangeEmailClick -> handleChangeEmailClick()
|
||||
is CheckEmailAction.Internal.OnboardingFeatureFlagUpdated -> {
|
||||
handleOnboardingFeatureFlagUpdated(action)
|
||||
}
|
||||
|
||||
CheckEmailAction.LoginClick -> handleLoginClick()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleLoginClick() {
|
||||
sendEvent(CheckEmailEvent.NavigateBackToLanding)
|
||||
}
|
||||
|
||||
private fun handleOnboardingFeatureFlagUpdated(
|
||||
action: CheckEmailAction.Internal.OnboardingFeatureFlagUpdated,
|
||||
) {
|
||||
mutableStateFlow.update {
|
||||
it.copy(showNewOnboardingUi = action.newValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,6 +83,7 @@ class CheckEmailViewModel @Inject constructor(
|
|||
@Parcelize
|
||||
data class CheckEmailState(
|
||||
val email: String,
|
||||
val showNewOnboardingUi: Boolean,
|
||||
) : Parcelable
|
||||
|
||||
/**
|
||||
|
@ -68,6 +100,11 @@ sealed class CheckEmailEvent {
|
|||
* Navigate to email app.
|
||||
*/
|
||||
data object NavigateToEmailApp : CheckEmailEvent()
|
||||
|
||||
/**
|
||||
* Navigate back to Landing
|
||||
*/
|
||||
data object NavigateBackToLanding : CheckEmailEvent()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,4 +125,19 @@ sealed class CheckEmailAction {
|
|||
* User clicked open email.
|
||||
*/
|
||||
data object OpenEmailClick : CheckEmailAction()
|
||||
|
||||
/**
|
||||
* User clicked log in.
|
||||
*/
|
||||
data object LoginClick : CheckEmailAction()
|
||||
|
||||
/**
|
||||
* Denotes an internal action.
|
||||
*/
|
||||
sealed class Internal : CheckEmailAction() {
|
||||
/**
|
||||
* Indicates updated value for onboarding feature flag.
|
||||
*/
|
||||
data class OnboardingFeatureFlagUpdated(val newValue: Boolean) : Internal()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package com.x8bit.bitwarden.ui.auth.feature.checkemail.handlers
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import com.x8bit.bitwarden.ui.auth.feature.checkemail.CheckEmailAction
|
||||
import com.x8bit.bitwarden.ui.auth.feature.checkemail.CheckEmailViewModel
|
||||
|
||||
/**
|
||||
* Handler for [CheckEmailScreen] actions.
|
||||
*/
|
||||
class CheckEmailHandler(
|
||||
val onOpenEmailAppClick: () -> Unit,
|
||||
val onChangeEmailClick: () -> Unit,
|
||||
val onBackClick: () -> Unit,
|
||||
val onLoginClick: () -> Unit,
|
||||
) {
|
||||
companion object {
|
||||
/**
|
||||
* Create [CheckEmailHandler] with the given [viewModel] to send actions to.
|
||||
*/
|
||||
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) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remember [CheckEmailHandler] with the given [viewModel] within a [Composable] scope.
|
||||
*/
|
||||
@Composable
|
||||
fun rememberCheckEmailHandler(viewModel: CheckEmailViewModel) =
|
||||
remember(viewModel) {
|
||||
CheckEmailHandler.create(viewModel)
|
||||
}
|
|
@ -194,6 +194,7 @@ fun StartRegistrationScreen(
|
|||
nameInput = state.nameInput,
|
||||
isReceiveMarketingEmailsToggled = state.isReceiveMarketingEmailsToggled,
|
||||
isContinueButtonEnabled = state.isContinueButtonEnabled,
|
||||
isNewOnboardingUiEnabled = state.showNewOnboardingUi,
|
||||
handler = handler,
|
||||
)
|
||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||
|
@ -210,10 +211,12 @@ private fun StartRegistrationContent(
|
|||
isReceiveMarketingEmailsToggled: Boolean,
|
||||
isContinueButtonEnabled: Boolean,
|
||||
handler: StartRegistrationHandler,
|
||||
isNewOnboardingUiEnabled: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
if (isNewOnboardingUiEnabled) {
|
||||
Image(
|
||||
painter = rememberVectorPainter(id = R.drawable.vault),
|
||||
contentDescription = null,
|
||||
|
@ -222,6 +225,7 @@ private fun StartRegistrationContent(
|
|||
.align(Alignment.CenterHorizontally),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(48.dp))
|
||||
}
|
||||
BitwardenTextField(
|
||||
label = stringResource(id = R.string.name),
|
||||
value = nameInput,
|
||||
|
@ -233,13 +237,9 @@ private fun StartRegistrationContent(
|
|||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenTextField(
|
||||
label = if (emailInput.isEmpty()) {
|
||||
stringResource(R.string.email_address_required)
|
||||
} else {
|
||||
stringResource(
|
||||
label = stringResource(
|
||||
id = R.string.email_address,
|
||||
)
|
||||
},
|
||||
),
|
||||
placeholder = stringResource(R.string.email_address_required),
|
||||
value = emailInput,
|
||||
onValueChange = handler.onEmailInputChange,
|
||||
|
@ -263,6 +263,7 @@ private fun StartRegistrationContent(
|
|||
modifier = Modifier
|
||||
.testTag("RegionSelectorDropdown"),
|
||||
)
|
||||
if (isNewOnboardingUiEnabled) {
|
||||
IconButton(
|
||||
onClick = handler.onServerGeologyHelpClick,
|
||||
// Align with design but keep accessible touch target of IconButton.
|
||||
|
@ -276,6 +277,7 @@ private fun StartRegistrationContent(
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
if (selectedEnvironmentType != Environment.Type.SELF_HOSTED) {
|
||||
|
@ -474,7 +476,7 @@ private fun ReceiveMarketingEmailsSwitch(
|
|||
|
||||
@PreviewScreenSizes
|
||||
@Composable
|
||||
private fun StartRegistrationContentPreview_filledout() {
|
||||
private fun StartRegistrationContentFilledOut_preview() {
|
||||
BitwardenTheme {
|
||||
StartRegistrationContent(
|
||||
emailInput = "e@mail.com",
|
||||
|
@ -482,6 +484,7 @@ private fun StartRegistrationContentPreview_filledout() {
|
|||
nameInput = "Test User",
|
||||
isReceiveMarketingEmailsToggled = true,
|
||||
isContinueButtonEnabled = true,
|
||||
isNewOnboardingUiEnabled = false,
|
||||
handler = StartRegistrationHandler(
|
||||
onEmailInputChange = {},
|
||||
onNameInputChange = {},
|
||||
|
@ -500,7 +503,7 @@ private fun StartRegistrationContentPreview_filledout() {
|
|||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun StartRegistrationContentPreview_empty() {
|
||||
private fun StartRegistrationContentEmpty_preview() {
|
||||
BitwardenTheme {
|
||||
StartRegistrationContent(
|
||||
emailInput = "",
|
||||
|
@ -508,6 +511,34 @@ private fun StartRegistrationContentPreview_empty() {
|
|||
nameInput = "",
|
||||
isReceiveMarketingEmailsToggled = false,
|
||||
isContinueButtonEnabled = false,
|
||||
isNewOnboardingUiEnabled = false,
|
||||
handler = StartRegistrationHandler(
|
||||
onEmailInputChange = {},
|
||||
onNameInputChange = {},
|
||||
onEnvironmentTypeSelect = {},
|
||||
onContinueClick = {},
|
||||
onTermsClick = {},
|
||||
onPrivacyPolicyClick = {},
|
||||
onReceiveMarketingEmailsToggle = {},
|
||||
onUnsubscribeMarketingEmailsClick = {},
|
||||
onServerGeologyHelpClick = {},
|
||||
onBackClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun StartRegistrationContentNewOnboardingUi_preview() {
|
||||
BitwardenTheme {
|
||||
StartRegistrationContent(
|
||||
emailInput = "",
|
||||
selectedEnvironmentType = Environment.Type.US,
|
||||
nameInput = "",
|
||||
isReceiveMarketingEmailsToggled = false,
|
||||
isContinueButtonEnabled = false,
|
||||
isNewOnboardingUiEnabled = true,
|
||||
handler = StartRegistrationHandler(
|
||||
onEmailInputChange = {},
|
||||
onNameInputChange = {},
|
||||
|
|
|
@ -7,6 +7,8 @@ import com.x8bit.bitwarden.R
|
|||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.RegisterResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.SendVerificationEmailResult
|
||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment.Type
|
||||
|
@ -15,6 +17,7 @@ import com.x8bit.bitwarden.ui.auth.feature.startregistration.StartRegistrationAc
|
|||
import com.x8bit.bitwarden.ui.auth.feature.startregistration.StartRegistrationAction.EmailInputChange
|
||||
import com.x8bit.bitwarden.ui.auth.feature.startregistration.StartRegistrationAction.EnvironmentTypeSelect
|
||||
import com.x8bit.bitwarden.ui.auth.feature.startregistration.StartRegistrationAction.ErrorDialogDismiss
|
||||
import com.x8bit.bitwarden.ui.auth.feature.startregistration.StartRegistrationAction.Internal.OnboardingFeatureFlagUpdated
|
||||
import com.x8bit.bitwarden.ui.auth.feature.startregistration.StartRegistrationAction.Internal.ReceiveSendVerificationEmailResult
|
||||
import com.x8bit.bitwarden.ui.auth.feature.startregistration.StartRegistrationAction.Internal.UpdatedEnvironmentReceive
|
||||
import com.x8bit.bitwarden.ui.auth.feature.startregistration.StartRegistrationAction.NameInputChange
|
||||
|
@ -29,6 +32,7 @@ import com.x8bit.bitwarden.ui.platform.base.util.isValidEmail
|
|||
import com.x8bit.bitwarden.ui.platform.components.dialog.BasicDialogState
|
||||
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
|
||||
|
@ -44,6 +48,7 @@ private const val KEY_STATE = "state"
|
|||
@HiltViewModel
|
||||
class StartRegistrationViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
featureFlagManager: FeatureFlagManager,
|
||||
private val authRepository: AuthRepository,
|
||||
private val environmentRepository: EnvironmentRepository,
|
||||
) : BaseViewModel<StartRegistrationState, StartRegistrationEvent, StartRegistrationAction>(
|
||||
|
@ -55,6 +60,7 @@ class StartRegistrationViewModel @Inject constructor(
|
|||
isContinueButtonEnabled = false,
|
||||
selectedEnvironmentType = environmentRepository.environment.type,
|
||||
dialog = null,
|
||||
showNewOnboardingUi = featureFlagManager.getFeatureFlag(FlagKey.OnboardingFlow),
|
||||
),
|
||||
) {
|
||||
|
||||
|
@ -73,6 +79,14 @@ class StartRegistrationViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
// Listen for changes on the onboarding feature flag.
|
||||
featureFlagManager
|
||||
.getFeatureFlagFlow(FlagKey.OnboardingFlow)
|
||||
.map {
|
||||
OnboardingFeatureFlagUpdated(it)
|
||||
}
|
||||
.onEach(::sendAction)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
override fun handleAction(action: StartRegistrationAction) {
|
||||
|
@ -99,6 +113,13 @@ class StartRegistrationViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
ServerGeologyHelpClick -> handleServerGeologyHelpClick()
|
||||
is OnboardingFeatureFlagUpdated -> handleOnboardingFeatureFlagUpdated(action)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleOnboardingFeatureFlagUpdated(action: OnboardingFeatureFlagUpdated) {
|
||||
mutableStateFlow.update {
|
||||
it.copy(showNewOnboardingUi = action.newValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,6 +290,7 @@ data class StartRegistrationState(
|
|||
val isContinueButtonEnabled: Boolean,
|
||||
val selectedEnvironmentType: Type,
|
||||
val dialog: StartRegistrationDialog?,
|
||||
val showNewOnboardingUi: Boolean,
|
||||
) : Parcelable
|
||||
|
||||
/**
|
||||
|
@ -422,5 +444,10 @@ sealed class StartRegistrationAction {
|
|||
data class UpdatedEnvironmentReceive(
|
||||
val environment: Environment,
|
||||
) : Internal()
|
||||
|
||||
/**
|
||||
* Indicates updated value for onboarding feature flag.
|
||||
*/
|
||||
data class OnboardingFeatureFlagUpdated(val newValue: Boolean) : Internal()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package com.x8bit.bitwarden.ui.auth.feature.checkemail
|
||||
|
||||
import androidx.compose.ui.semantics.SemanticsActions
|
||||
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 androidx.compose.ui.test.performSemanticsAction
|
||||
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
|
||||
|
@ -12,8 +14,8 @@ import io.mockk.just
|
|||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import io.mockk.verify
|
||||
import junit.framework.TestCase
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
|
@ -22,6 +24,7 @@ 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>()
|
||||
|
@ -35,6 +38,7 @@ class CheckEmailScreenTest : BaseComposeTest() {
|
|||
composeTestRule.setContent {
|
||||
CheckEmailScreen(
|
||||
onNavigateBack = { onNavigateBackCalled = true },
|
||||
onNavigateBackToLanding = { onNavigateToLandingCalled = true },
|
||||
viewModel = viewModel,
|
||||
intentManager = intentManager,
|
||||
)
|
||||
|
@ -63,10 +67,16 @@ 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)
|
||||
TestCase.assertTrue(onNavigateBackCalled)
|
||||
assertTrue(onNavigateBackCalled)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -77,8 +87,31 @@ class CheckEmailScreenTest : BaseComposeTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `go back and update email text click should send ChangeEmailClick action`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(showNewOnboardingUi = false)
|
||||
composeTestRule
|
||||
.onNodeWithText("No email? Go back to edit your email address.")
|
||||
.performScrollTo()
|
||||
.performSemanticsAction(SemanticsActions.OnClick)
|
||||
|
||||
verify { viewModel.trySendAction(CheckEmailAction.ChangeEmailClick) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `already have account text click should send ChangeEmailClick action`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(showNewOnboardingUi = false)
|
||||
composeTestRule
|
||||
.onNodeWithText("Or log in, you may already have an account.")
|
||||
.performScrollTo()
|
||||
.performSemanticsAction(SemanticsActions.OnClick)
|
||||
|
||||
verify { viewModel.trySendAction(CheckEmailAction.LoginClick) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `change email button click should send ChangeEmailClick action`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(showNewOnboardingUi = true)
|
||||
composeTestRule
|
||||
.onNodeWithText("Change email address")
|
||||
.performScrollTo()
|
||||
|
@ -91,6 +124,7 @@ class CheckEmailScreenTest : BaseComposeTest() {
|
|||
private const val EMAIL = "test@gmail.com"
|
||||
private val DEFAULT_STATE = CheckEmailState(
|
||||
email = EMAIL,
|
||||
showNewOnboardingUi = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,23 @@ package com.x8bit.bitwarden.ui.auth.feature.checkemail
|
|||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class CheckEmailViewModelTest : BaseViewModelTest() {
|
||||
private val mutableFeatureFlagFlow = MutableStateFlow(false)
|
||||
private val featureFlagManager = mockk<FeatureFlagManager>(relaxed = true) {
|
||||
every { getFeatureFlag(FlagKey.OnboardingFlow) } returns false
|
||||
every { getFeatureFlagFlow(FlagKey.OnboardingFlow) } returns mutableFeatureFlagFlow
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `initial state should be correct`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
|
@ -63,8 +74,31 @@ class CheckEmailViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OnboardingFeatureFlagUpdated should update showNewOnboardingUi in state`() {
|
||||
val viewModel = createViewModel()
|
||||
mutableFeatureFlagFlow.value = true
|
||||
val expectedState = DEFAULT_STATE.copy(
|
||||
showNewOnboardingUi = true,
|
||||
)
|
||||
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,
|
||||
savedStateHandle = SavedStateHandle().also {
|
||||
it["email"] = EMAIL
|
||||
it["state"] = state
|
||||
|
@ -75,6 +109,7 @@ class CheckEmailViewModelTest : BaseViewModelTest() {
|
|||
private const val EMAIL = "test@gmail.com"
|
||||
private val DEFAULT_STATE = CheckEmailState(
|
||||
email = EMAIL,
|
||||
showNewOnboardingUi = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ class StartRegistrationScreenTest : BaseComposeTest() {
|
|||
|
||||
@Test
|
||||
fun `email input change should send EmailInputChange action`() {
|
||||
composeTestRule.onNodeWithText("Email address (required)").performTextInput(TEST_INPUT)
|
||||
composeTestRule.onNodeWithText("Email address").performTextInput(TEST_INPUT)
|
||||
verify { viewModel.trySendAction(EmailInputChange(TEST_INPUT)) }
|
||||
}
|
||||
|
||||
|
@ -180,6 +180,7 @@ class StartRegistrationScreenTest : BaseComposeTest() {
|
|||
|
||||
@Test
|
||||
fun `clicking the server tool tip should send ServerGeologyHelpClickAction`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(showNewOnboardingUi = true)
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("Help with server geolocations.")
|
||||
.performScrollTo()
|
||||
|
@ -188,6 +189,14 @@ class StartRegistrationScreenTest : BaseComposeTest() {
|
|||
verify { viewModel.trySendAction(StartRegistrationAction.ServerGeologyHelpClick) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `server tool tip should not exist if not in new onboarding ui`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(showNewOnboardingUi = false)
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("Help with server geolocations.")
|
||||
.assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when NavigateToServerSelectionInfo is observed event should invoke intent manager`() {
|
||||
mutableEventFlow.tryEmit(StartRegistrationEvent.NavigateToServerSelectionInfo)
|
||||
|
@ -279,6 +288,7 @@ class StartRegistrationScreenTest : BaseComposeTest() {
|
|||
isContinueButtonEnabled = false,
|
||||
selectedEnvironmentType = Environment.Type.US,
|
||||
dialog = null,
|
||||
showNewOnboardingUi = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import com.x8bit.bitwarden.R
|
|||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.SendVerificationEmailResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.util.generateUriForCaptcha
|
||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
|
||||
import com.x8bit.bitwarden.ui.auth.feature.startregistration.StartRegistrationAction.BackClick
|
||||
|
@ -33,6 +35,7 @@ import io.mockk.every
|
|||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.unmockkStatic
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
|
@ -42,7 +45,11 @@ import org.junit.jupiter.api.Test
|
|||
|
||||
@Suppress("LargeClass")
|
||||
class StartRegistrationViewModelTest : BaseViewModelTest() {
|
||||
|
||||
private val mutableFeatureFlagFlow = MutableStateFlow(false)
|
||||
private val featureFlagManager = mockk<FeatureFlagManager>(relaxed = true) {
|
||||
every { getFeatureFlag(FlagKey.OnboardingFlow) } returns false
|
||||
every { getFeatureFlagFlow(FlagKey.OnboardingFlow) } returns mutableFeatureFlagFlow
|
||||
}
|
||||
/**
|
||||
* Saved state handle that has valid inputs. Useful for tests that want to test things
|
||||
* after the user has entered all valid inputs.
|
||||
|
@ -71,6 +78,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
assertEquals(DEFAULT_STATE, viewModel.stateFlow.value)
|
||||
}
|
||||
|
@ -84,12 +92,14 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
isContinueButtonEnabled = false,
|
||||
selectedEnvironmentType = Environment.Type.US,
|
||||
dialog = null,
|
||||
showNewOnboardingUi = false,
|
||||
)
|
||||
val handle = SavedStateHandle(mapOf("state" to savedState))
|
||||
val viewModel = StartRegistrationViewModel(
|
||||
savedStateHandle = handle,
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
assertEquals(savedState, viewModel.stateFlow.value)
|
||||
}
|
||||
|
@ -100,6 +110,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
val input = "a"
|
||||
viewModel.trySendAction(EmailInputChange(input))
|
||||
|
@ -125,6 +136,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
val input = " "
|
||||
viewModel.trySendAction(EmailInputChange(input))
|
||||
|
@ -162,6 +174,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = validInputHandle,
|
||||
authRepository = repo,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
turbineScope {
|
||||
val stateFlow = viewModel.stateFlow.testIn(backgroundScope)
|
||||
|
@ -197,6 +210,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = validInputHandle,
|
||||
authRepository = repo,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
viewModel.stateFlow.test {
|
||||
assertEquals(VALID_INPUT_STATE, awaitItem())
|
||||
|
@ -243,6 +257,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = validInputHandle,
|
||||
authRepository = repo,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(ContinueClick)
|
||||
|
@ -280,6 +295,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = validInputHandle,
|
||||
authRepository = repo,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(ContinueClick)
|
||||
|
@ -298,6 +314,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(BackClick)
|
||||
|
@ -311,6 +328,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(PrivacyPolicyClick)
|
||||
|
@ -324,6 +342,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(TermsClick)
|
||||
|
@ -337,6 +356,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(UnsubscribeMarketingEmailsClick)
|
||||
|
@ -351,6 +371,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
viewModel.stateFlow.test {
|
||||
awaitItem()
|
||||
|
@ -373,6 +394,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(
|
||||
|
@ -393,6 +415,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
viewModel.trySendAction(EmailInputChange("input"))
|
||||
viewModel.stateFlow.test {
|
||||
|
@ -412,6 +435,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
viewModel.trySendAction(NameInputChange("input"))
|
||||
viewModel.stateFlow.test {
|
||||
|
@ -425,6 +449,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
viewModel.trySendAction(ReceiveMarketingEmailsToggle(false))
|
||||
viewModel.stateFlow.test {
|
||||
|
@ -438,6 +463,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
|
@ -446,6 +472,21 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OnboardingFeatureFlagUpdated should update showNewOnboardingUi in state`() {
|
||||
val viewModel = StartRegistrationViewModel(
|
||||
savedStateHandle = SavedStateHandle(),
|
||||
authRepository = mockAuthRepository,
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
featureFlagManager = featureFlagManager,
|
||||
)
|
||||
mutableFeatureFlagFlow.value = true
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(showNewOnboardingUi = true),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val EMAIL = "test@test.com"
|
||||
private const val NAME = "name"
|
||||
|
@ -456,6 +497,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
isContinueButtonEnabled = false,
|
||||
selectedEnvironmentType = Environment.Type.US,
|
||||
dialog = null,
|
||||
showNewOnboardingUi = false,
|
||||
)
|
||||
private val VALID_INPUT_STATE = StartRegistrationState(
|
||||
emailInput = EMAIL,
|
||||
|
@ -464,6 +506,7 @@ class StartRegistrationViewModelTest : BaseViewModelTest() {
|
|||
isContinueButtonEnabled = true,
|
||||
selectedEnvironmentType = Environment.Type.US,
|
||||
dialog = null,
|
||||
showNewOnboardingUi = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue