mirror of
https://github.com/bitwarden/android.git
synced 2024-11-22 01:16:02 +03:00
PM-13068 Navigate from settings to setup autofill screen. (#4034)
This commit is contained in:
parent
bc057932a0
commit
641a48fe44
18 changed files with 301 additions and 44 deletions
|
@ -1,29 +1,79 @@
|
||||||
package com.x8bit.bitwarden.ui.auth.feature.accountsetup
|
package com.x8bit.bitwarden.ui.auth.feature.accountsetup
|
||||||
|
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.NavOptions
|
import androidx.navigation.NavOptions
|
||||||
|
import androidx.navigation.NavType
|
||||||
|
import androidx.navigation.navArgument
|
||||||
|
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.composableWithPushTransitions
|
import com.x8bit.bitwarden.ui.platform.base.util.composableWithPushTransitions
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.composableWithSlideTransitions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Route name for [SetupAutoFillScreen].
|
* Route constant for navigating to the [SetupAutoFillScreen].
|
||||||
*/
|
*/
|
||||||
const val SETUP_AUTO_FILL_ROUTE = "setup_auto_fill"
|
private const val SETUP_AUTO_FILL_PREFIX = "setup_auto_fill"
|
||||||
|
private const val SETUP_AUTO_FILL_AS_ROOT_PREFIX = "${SETUP_AUTO_FILL_PREFIX}_as_root"
|
||||||
|
private const val SETUP_AUTO_FILL_NAV_ARG = "isInitialSetup"
|
||||||
|
private const val SETUP_AUTO_FILL_ROUTE = "$SETUP_AUTO_FILL_PREFIX/{$SETUP_AUTO_FILL_NAV_ARG}"
|
||||||
|
const val SETUP_AUTO_FILL_AS_ROOT_ROUTE =
|
||||||
|
"$SETUP_AUTO_FILL_AS_ROOT_PREFIX/{$SETUP_AUTO_FILL_NAV_ARG}"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arguments for the [SetupAutoFillScreen] using [SavedStateHandle].
|
||||||
|
*/
|
||||||
|
@OmitFromCoverage
|
||||||
|
data class SetupAutoFillScreenArgs(val isInitialSetup: Boolean) {
|
||||||
|
constructor(savedStateHandle: SavedStateHandle) : this(
|
||||||
|
isInitialSetup = requireNotNull(savedStateHandle[SETUP_AUTO_FILL_NAV_ARG]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigate to the setup auto-fill screen.
|
* Navigate to the setup auto-fill screen.
|
||||||
*/
|
*/
|
||||||
fun NavController.navigateToSetupAutoFillScreen(navOptions: NavOptions? = null) {
|
fun NavController.navigateToSetupAutoFillScreen(navOptions: NavOptions? = null) {
|
||||||
this.navigate(SETUP_AUTO_FILL_ROUTE, navOptions)
|
this.navigate("$SETUP_AUTO_FILL_PREFIX/false", navOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the setup auto-fill screen as the root.
|
||||||
|
*/
|
||||||
|
fun NavController.navigateToSetupAutoFillAsRootScreen(navOptions: NavOptions? = null) {
|
||||||
|
this.navigate("$SETUP_AUTO_FILL_AS_ROOT_PREFIX/true", navOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the setup auto-fil screen to the nav graph.
|
* Add the setup auto-fil screen to the nav graph.
|
||||||
*/
|
*/
|
||||||
fun NavGraphBuilder.setupAutoFillDestination() {
|
fun NavGraphBuilder.setupAutoFillDestination(onNavigateBack: () -> Unit) {
|
||||||
composableWithPushTransitions(
|
composableWithSlideTransitions(
|
||||||
route = SETUP_AUTO_FILL_ROUTE,
|
route = SETUP_AUTO_FILL_ROUTE,
|
||||||
|
arguments = setupAutofillNavArgs,
|
||||||
) {
|
) {
|
||||||
SetupAutoFillScreen()
|
SetupAutoFillScreen(onNavigateBack = onNavigateBack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the setup autofil screen to the root nav graph.
|
||||||
|
*/
|
||||||
|
fun NavGraphBuilder.setupAutoFillDestinationAsRoot() {
|
||||||
|
composableWithPushTransitions(
|
||||||
|
route = SETUP_AUTO_FILL_AS_ROOT_ROUTE,
|
||||||
|
arguments = setupAutofillNavArgs,
|
||||||
|
) {
|
||||||
|
SetupAutoFillScreen(
|
||||||
|
onNavigateBack = {
|
||||||
|
// No-Op
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val setupAutofillNavArgs = listOf(
|
||||||
|
navArgument(SETUP_AUTO_FILL_NAV_ARG) {
|
||||||
|
type = NavType.BoolType
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.x8bit.bitwarden.ui.auth.feature.accountsetup
|
package com.x8bit.bitwarden.ui.auth.feature.accountsetup
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus
|
import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus
|
||||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||||
|
@ -10,20 +12,31 @@ import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val KEY_STATE = "state"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View model for the Auto-fill setup screen.
|
* View model for the Auto-fill setup screen.
|
||||||
*/
|
*/
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class SetupAutoFillViewModel @Inject constructor(
|
class SetupAutoFillViewModel @Inject constructor(
|
||||||
|
savedStateHandle: SavedStateHandle,
|
||||||
private val settingsRepository: SettingsRepository,
|
private val settingsRepository: SettingsRepository,
|
||||||
private val authRepository: AuthRepository,
|
private val authRepository: AuthRepository,
|
||||||
) :
|
) :
|
||||||
BaseViewModel<SetupAutoFillState, SetupAutoFillEvent, SetupAutoFillAction>(
|
BaseViewModel<SetupAutoFillState, SetupAutoFillEvent, SetupAutoFillAction>(
|
||||||
initialState = run {
|
// We load the state from the savedStateHandle for testing purposes.
|
||||||
|
initialState = savedStateHandle[KEY_STATE] ?: run {
|
||||||
val userId = requireNotNull(authRepository.userStateFlow.value).activeUserId
|
val userId = requireNotNull(authRepository.userStateFlow.value).activeUserId
|
||||||
SetupAutoFillState(userId = userId, dialogState = null, autofillEnabled = false)
|
val isInitialSetup = SetupAutoFillScreenArgs(savedStateHandle).isInitialSetup
|
||||||
|
SetupAutoFillState(
|
||||||
|
userId = userId,
|
||||||
|
dialogState = null,
|
||||||
|
autofillEnabled = false,
|
||||||
|
isInitialSetup = isInitialSetup,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -48,9 +61,15 @@ class SetupAutoFillViewModel @Inject constructor(
|
||||||
is SetupAutoFillAction.Internal.AutofillEnabledUpdateReceive -> {
|
is SetupAutoFillAction.Internal.AutofillEnabledUpdateReceive -> {
|
||||||
handleAutofillEnabledUpdateReceive(action)
|
handleAutofillEnabledUpdateReceive(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetupAutoFillAction.CloseClick -> handleCloseClick()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleCloseClick() {
|
||||||
|
sendEvent(SetupAutoFillEvent.NavigateBack)
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleAutofillEnabledUpdateReceive(
|
private fun handleAutofillEnabledUpdateReceive(
|
||||||
action: SetupAutoFillAction.Internal.AutofillEnabledUpdateReceive,
|
action: SetupAutoFillAction.Internal.AutofillEnabledUpdateReceive,
|
||||||
) {
|
) {
|
||||||
|
@ -83,7 +102,11 @@ class SetupAutoFillViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleContinueClick() {
|
private fun handleContinueClick() {
|
||||||
|
if (state.isInitialSetup) {
|
||||||
updateOnboardingStatusToNextStep()
|
updateOnboardingStatusToNextStep()
|
||||||
|
} else {
|
||||||
|
sendEvent(SetupAutoFillEvent.NavigateBack)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleAutofillServiceChanged(action: SetupAutoFillAction.AutofillServiceChanged) {
|
private fun handleAutofillServiceChanged(action: SetupAutoFillAction.AutofillServiceChanged) {
|
||||||
|
@ -105,24 +128,28 @@ class SetupAutoFillViewModel @Inject constructor(
|
||||||
/**
|
/**
|
||||||
* UI State for the Auto-fill setup screen.
|
* UI State for the Auto-fill setup screen.
|
||||||
*/
|
*/
|
||||||
|
@Parcelize
|
||||||
data class SetupAutoFillState(
|
data class SetupAutoFillState(
|
||||||
val userId: String,
|
val userId: String,
|
||||||
val dialogState: SetupAutoFillDialogState?,
|
val dialogState: SetupAutoFillDialogState?,
|
||||||
val autofillEnabled: Boolean,
|
val autofillEnabled: Boolean,
|
||||||
)
|
val isInitialSetup: Boolean,
|
||||||
|
) : Parcelable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog states for the Auto-fill setup screen.
|
* Dialog states for the Auto-fill setup screen.
|
||||||
*/
|
*/
|
||||||
sealed class SetupAutoFillDialogState {
|
sealed class SetupAutoFillDialogState : Parcelable {
|
||||||
/**
|
/**
|
||||||
* Represents the turn on later dialog.
|
* Represents the turn on later dialog.
|
||||||
*/
|
*/
|
||||||
|
@Parcelize
|
||||||
data object TurnOnLaterDialog : SetupAutoFillDialogState()
|
data object TurnOnLaterDialog : SetupAutoFillDialogState()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the autofill fallback dialog.
|
* Represents the autofill fallback dialog.
|
||||||
*/
|
*/
|
||||||
|
@Parcelize
|
||||||
data object AutoFillFallbackDialog : SetupAutoFillDialogState()
|
data object AutoFillFallbackDialog : SetupAutoFillDialogState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +162,11 @@ sealed class SetupAutoFillEvent {
|
||||||
* Navigate to the autofill settings screen.
|
* Navigate to the autofill settings screen.
|
||||||
*/
|
*/
|
||||||
data object NavigateToAutofillSettings : SetupAutoFillEvent()
|
data object NavigateToAutofillSettings : SetupAutoFillEvent()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate back.
|
||||||
|
*/
|
||||||
|
data object NavigateBack : SetupAutoFillEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,6 +205,11 @@ sealed class SetupAutoFillAction {
|
||||||
*/
|
*/
|
||||||
data object AutoFillServiceFallback : SetupAutoFillAction()
|
data object AutoFillServiceFallback : SetupAutoFillAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user has clicked the close button.
|
||||||
|
*/
|
||||||
|
data object CloseClick : SetupAutoFillAction()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal actions not send through UI.
|
* Internal actions not send through UI.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -19,6 +19,7 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
@ -37,6 +38,7 @@ import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.standardHorizontalMargin
|
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.appbar.BitwardenTopAppBar
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.appbar.NavigationIcon
|
||||||
import com.x8bit.bitwarden.ui.platform.components.button.BitwardenFilledButton
|
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.BitwardenTextButton
|
||||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BasicDialogState
|
import com.x8bit.bitwarden.ui.platform.components.dialog.BasicDialogState
|
||||||
|
@ -45,6 +47,7 @@ import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialo
|
||||||
import com.x8bit.bitwarden.ui.platform.components.image.BitwardenGifImage
|
import com.x8bit.bitwarden.ui.platform.components.image.BitwardenGifImage
|
||||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||||
import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenWideSwitch
|
import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenWideSwitch
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||||
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
|
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
|
||||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||||
|
@ -57,6 +60,7 @@ import com.x8bit.bitwarden.ui.platform.util.isPortrait
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun SetupAutoFillScreen(
|
fun SetupAutoFillScreen(
|
||||||
|
onNavigateBack: () -> Unit,
|
||||||
intentManager: IntentManager = LocalIntentManager.current,
|
intentManager: IntentManager = LocalIntentManager.current,
|
||||||
viewModel: SetupAutoFillViewModel = hiltViewModel(),
|
viewModel: SetupAutoFillViewModel = hiltViewModel(),
|
||||||
) {
|
) {
|
||||||
|
@ -70,6 +74,8 @@ fun SetupAutoFillScreen(
|
||||||
handler.sendAutoFillServiceFallback.invoke()
|
handler.sendAutoFillServiceFallback.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetupAutoFillEvent.NavigateBack -> onNavigateBack()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
when (state.dialogState) {
|
when (state.dialogState) {
|
||||||
|
@ -105,14 +111,32 @@ fun SetupAutoFillScreen(
|
||||||
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
topBar = {
|
topBar = {
|
||||||
BitwardenTopAppBar(
|
BitwardenTopAppBar(
|
||||||
title = stringResource(id = R.string.account_setup),
|
title = stringResource(
|
||||||
|
id = if (state.isInitialSetup) {
|
||||||
|
R.string.account_setup
|
||||||
|
} else {
|
||||||
|
R.string.turn_on_autofill
|
||||||
|
},
|
||||||
|
),
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
navigationIcon = null,
|
navigationIcon = if (state.isInitialSetup) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
NavigationIcon(
|
||||||
|
navigationIcon = rememberVectorPainter(id = R.drawable.ic_close),
|
||||||
|
navigationIconContentDescription = stringResource(id = R.string.close),
|
||||||
|
onNavigationIconClick = remember(viewModel) {
|
||||||
|
{
|
||||||
|
viewModel.trySendAction(SetupAutoFillAction.CloseClick)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
SetupAutoFillContent(
|
SetupAutoFillContent(
|
||||||
autofillEnabled = state.autofillEnabled,
|
state = state,
|
||||||
onAutofillServiceChanged = { handler.onAutofillServiceChanged(it) },
|
onAutofillServiceChanged = { handler.onAutofillServiceChanged(it) },
|
||||||
onContinueClick = handler.onContinueClick,
|
onContinueClick = handler.onContinueClick,
|
||||||
onTurnOnLaterClick = handler.onTurnOnLaterClick,
|
onTurnOnLaterClick = handler.onTurnOnLaterClick,
|
||||||
|
@ -127,7 +151,7 @@ fun SetupAutoFillScreen(
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod")
|
||||||
@Composable
|
@Composable
|
||||||
private fun SetupAutoFillContent(
|
private fun SetupAutoFillContent(
|
||||||
autofillEnabled: Boolean,
|
state: SetupAutoFillState,
|
||||||
onAutofillServiceChanged: (Boolean) -> Unit,
|
onAutofillServiceChanged: (Boolean) -> Unit,
|
||||||
onContinueClick: () -> Unit,
|
onContinueClick: () -> Unit,
|
||||||
onTurnOnLaterClick: () -> Unit,
|
onTurnOnLaterClick: () -> Unit,
|
||||||
|
@ -147,7 +171,7 @@ private fun SetupAutoFillContent(
|
||||||
label = stringResource(
|
label = stringResource(
|
||||||
R.string.autofill_services,
|
R.string.autofill_services,
|
||||||
),
|
),
|
||||||
isChecked = autofillEnabled,
|
isChecked = state.autofillEnabled,
|
||||||
onCheckedChange = onAutofillServiceChanged,
|
onCheckedChange = onAutofillServiceChanged,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
@ -162,6 +186,7 @@ private fun SetupAutoFillContent(
|
||||||
.standardHorizontalMargin(),
|
.standardHorizontalMargin(),
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
if (state.isInitialSetup) {
|
||||||
BitwardenTextButton(
|
BitwardenTextButton(
|
||||||
label = stringResource(R.string.turn_on_later),
|
label = stringResource(R.string.turn_on_later),
|
||||||
onClick = onTurnOnLaterClick,
|
onClick = onTurnOnLaterClick,
|
||||||
|
@ -169,6 +194,7 @@ private fun SetupAutoFillContent(
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.standardHorizontalMargin(),
|
.standardHorizontalMargin(),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
Spacer(modifier = Modifier.navigationBarsPadding())
|
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,7 +266,12 @@ private fun OrderedHeaderContent() {
|
||||||
private fun SetupAutoFillContentDisabled_preview() {
|
private fun SetupAutoFillContentDisabled_preview() {
|
||||||
BitwardenTheme {
|
BitwardenTheme {
|
||||||
SetupAutoFillContent(
|
SetupAutoFillContent(
|
||||||
|
state = SetupAutoFillState(
|
||||||
|
userId = "disputationi",
|
||||||
|
dialogState = null,
|
||||||
autofillEnabled = false,
|
autofillEnabled = false,
|
||||||
|
isInitialSetup = true,
|
||||||
|
),
|
||||||
onAutofillServiceChanged = {},
|
onAutofillServiceChanged = {},
|
||||||
onContinueClick = {},
|
onContinueClick = {},
|
||||||
onTurnOnLaterClick = {},
|
onTurnOnLaterClick = {},
|
||||||
|
@ -253,7 +284,12 @@ private fun SetupAutoFillContentDisabled_preview() {
|
||||||
private fun SetupAutoFillContentEnabled_preview() {
|
private fun SetupAutoFillContentEnabled_preview() {
|
||||||
BitwardenTheme {
|
BitwardenTheme {
|
||||||
SetupAutoFillContent(
|
SetupAutoFillContent(
|
||||||
|
state = SetupAutoFillState(
|
||||||
|
userId = "disputationi",
|
||||||
|
dialogState = null,
|
||||||
autofillEnabled = true,
|
autofillEnabled = true,
|
||||||
|
isInitialSetup = true,
|
||||||
|
),
|
||||||
onAutofillServiceChanged = {},
|
onAutofillServiceChanged = {},
|
||||||
onContinueClick = {},
|
onContinueClick = {},
|
||||||
onTurnOnLaterClick = {},
|
onTurnOnLaterClick = {},
|
||||||
|
|
|
@ -33,6 +33,7 @@ class SetupUnlockViewModel @Inject constructor(
|
||||||
private val settingsRepository: SettingsRepository,
|
private val settingsRepository: SettingsRepository,
|
||||||
private val biometricsEncryptionManager: BiometricsEncryptionManager,
|
private val biometricsEncryptionManager: BiometricsEncryptionManager,
|
||||||
) : BaseViewModel<SetupUnlockState, SetupUnlockEvent, SetupUnlockAction>(
|
) : BaseViewModel<SetupUnlockState, SetupUnlockEvent, SetupUnlockAction>(
|
||||||
|
// We load the state from the savedStateHandle for testing purposes.
|
||||||
initialState = savedStateHandle[KEY_STATE] ?: run {
|
initialState = savedStateHandle[KEY_STATE] ?: run {
|
||||||
val userId = requireNotNull(authRepository.userStateFlow.value).activeUserId
|
val userId = requireNotNull(authRepository.userStateFlow.value).activeUserId
|
||||||
val isBiometricsValid = biometricsEncryptionManager.isBiometricIntegrityValid(
|
val isBiometricsValid = biometricsEncryptionManager.isBiometricIntegrityValid(
|
||||||
|
|
|
@ -15,13 +15,13 @@ import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import androidx.navigation.navOptions
|
import androidx.navigation.navOptions
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.SETUP_AUTO_FILL_ROUTE
|
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.SETUP_AUTO_FILL_AS_ROOT_ROUTE
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.SETUP_COMPLETE_ROUTE
|
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.SETUP_COMPLETE_ROUTE
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.SETUP_UNLOCK_AS_ROOT_ROUTE
|
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.SETUP_UNLOCK_AS_ROOT_ROUTE
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.navigateToSetupAutoFillScreen
|
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.navigateToSetupAutoFillAsRootScreen
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.navigateToSetupCompleteScreen
|
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.navigateToSetupCompleteScreen
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.navigateToSetupUnlockScreenAsRoot
|
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.navigateToSetupUnlockScreenAsRoot
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.setupAutoFillDestination
|
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.setupAutoFillDestinationAsRoot
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.setupCompleteDestination
|
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.setupCompleteDestination
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.setupUnlockDestinationAsRoot
|
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.setupUnlockDestinationAsRoot
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.auth.AUTH_GRAPH_ROUTE
|
import com.x8bit.bitwarden.ui.auth.feature.auth.AUTH_GRAPH_ROUTE
|
||||||
|
@ -100,7 +100,7 @@ fun RootNavScreen(
|
||||||
vaultUnlockedGraph(navController)
|
vaultUnlockedGraph(navController)
|
||||||
setupDebugMenuDestination(onNavigateBack = { navController.popBackStack() })
|
setupDebugMenuDestination(onNavigateBack = { navController.popBackStack() })
|
||||||
setupUnlockDestinationAsRoot()
|
setupUnlockDestinationAsRoot()
|
||||||
setupAutoFillDestination()
|
setupAutoFillDestinationAsRoot()
|
||||||
setupCompleteDestination()
|
setupCompleteDestination()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ fun RootNavScreen(
|
||||||
-> VAULT_UNLOCKED_GRAPH_ROUTE
|
-> VAULT_UNLOCKED_GRAPH_ROUTE
|
||||||
|
|
||||||
RootNavState.OnboardingAccountLockSetup -> SETUP_UNLOCK_AS_ROOT_ROUTE
|
RootNavState.OnboardingAccountLockSetup -> SETUP_UNLOCK_AS_ROOT_ROUTE
|
||||||
RootNavState.OnboardingAutoFillSetup -> SETUP_AUTO_FILL_ROUTE
|
RootNavState.OnboardingAutoFillSetup -> SETUP_AUTO_FILL_AS_ROOT_ROUTE
|
||||||
RootNavState.OnboardingStepsComplete -> SETUP_COMPLETE_ROUTE
|
RootNavState.OnboardingStepsComplete -> SETUP_COMPLETE_ROUTE
|
||||||
}
|
}
|
||||||
val currentRoute = navController.currentDestination?.rootLevelRoute()
|
val currentRoute = navController.currentDestination?.rootLevelRoute()
|
||||||
|
@ -248,7 +248,7 @@ fun RootNavScreen(
|
||||||
}
|
}
|
||||||
|
|
||||||
RootNavState.OnboardingAutoFillSetup -> {
|
RootNavState.OnboardingAutoFillSetup -> {
|
||||||
navController.navigateToSetupAutoFillScreen(rootNavOptions)
|
navController.navigateToSetupAutoFillAsRootScreen(rootNavOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
RootNavState.OnboardingStepsComplete -> {
|
RootNavState.OnboardingStepsComplete -> {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.NavOptions
|
import androidx.navigation.NavOptions
|
||||||
import androidx.navigation.navigation
|
import androidx.navigation.navigation
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.navigateToSetupUnlockScreen
|
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.composableWithRootPushTransitions
|
import com.x8bit.bitwarden.ui.platform.base.util.composableWithRootPushTransitions
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.about.aboutDestination
|
import com.x8bit.bitwarden.ui.platform.feature.settings.about.aboutDestination
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.about.navigateToAbout
|
import com.x8bit.bitwarden.ui.platform.feature.settings.about.navigateToAbout
|
||||||
|
@ -34,6 +33,8 @@ fun NavGraphBuilder.settingsGraph(
|
||||||
onNavigateToExportVault: () -> Unit,
|
onNavigateToExportVault: () -> Unit,
|
||||||
onNavigateToFolders: () -> Unit,
|
onNavigateToFolders: () -> Unit,
|
||||||
onNavigateToPendingRequests: () -> Unit,
|
onNavigateToPendingRequests: () -> Unit,
|
||||||
|
onNavigateToSetupUnlockScreen: () -> Unit,
|
||||||
|
onNavigateToSetupAutoFillScreen: () -> Unit,
|
||||||
) {
|
) {
|
||||||
navigation(
|
navigation(
|
||||||
startDestination = SETTINGS_ROUTE,
|
startDestination = SETTINGS_ROUTE,
|
||||||
|
@ -56,12 +57,13 @@ fun NavGraphBuilder.settingsGraph(
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.popBackStack() },
|
||||||
onNavigateToDeleteAccount = onNavigateToDeleteAccount,
|
onNavigateToDeleteAccount = onNavigateToDeleteAccount,
|
||||||
onNavigateToPendingRequests = onNavigateToPendingRequests,
|
onNavigateToPendingRequests = onNavigateToPendingRequests,
|
||||||
onNavigateToSetupUnlockScreen = { navController.navigateToSetupUnlockScreen() },
|
onNavigateToSetupUnlockScreen = onNavigateToSetupUnlockScreen,
|
||||||
)
|
)
|
||||||
appearanceDestination(onNavigateBack = { navController.popBackStack() })
|
appearanceDestination(onNavigateBack = { navController.popBackStack() })
|
||||||
autoFillDestination(
|
autoFillDestination(
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.popBackStack() },
|
||||||
onNavigateToBlockAutoFillScreen = { navController.navigateToBlockAutoFillScreen() },
|
onNavigateToBlockAutoFillScreen = { navController.navigateToBlockAutoFillScreen() },
|
||||||
|
onNavigateToSetupAutofill = onNavigateToSetupAutoFillScreen,
|
||||||
)
|
)
|
||||||
otherDestination(onNavigateBack = { navController.popBackStack() })
|
otherDestination(onNavigateBack = { navController.popBackStack() })
|
||||||
vaultSettingsDestination(
|
vaultSettingsDestination(
|
||||||
|
|
|
@ -13,6 +13,7 @@ private const val AUTO_FILL_ROUTE = "settings_auto_fill"
|
||||||
fun NavGraphBuilder.autoFillDestination(
|
fun NavGraphBuilder.autoFillDestination(
|
||||||
onNavigateBack: () -> Unit,
|
onNavigateBack: () -> Unit,
|
||||||
onNavigateToBlockAutoFillScreen: () -> Unit,
|
onNavigateToBlockAutoFillScreen: () -> Unit,
|
||||||
|
onNavigateToSetupAutofill: () -> Unit,
|
||||||
) {
|
) {
|
||||||
composableWithPushTransitions(
|
composableWithPushTransitions(
|
||||||
route = AUTO_FILL_ROUTE,
|
route = AUTO_FILL_ROUTE,
|
||||||
|
@ -20,6 +21,7 @@ fun NavGraphBuilder.autoFillDestination(
|
||||||
AutoFillScreen(
|
AutoFillScreen(
|
||||||
onNavigateBack = onNavigateBack,
|
onNavigateBack = onNavigateBack,
|
||||||
onNavigateToBlockAutoFillScreen = onNavigateToBlockAutoFillScreen,
|
onNavigateToBlockAutoFillScreen = onNavigateToBlockAutoFillScreen,
|
||||||
|
onNavigateToSetupAutofill = onNavigateToSetupAutofill,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ fun AutoFillScreen(
|
||||||
viewModel: AutoFillViewModel = hiltViewModel(),
|
viewModel: AutoFillViewModel = hiltViewModel(),
|
||||||
intentManager: IntentManager = LocalIntentManager.current,
|
intentManager: IntentManager = LocalIntentManager.current,
|
||||||
onNavigateToBlockAutoFillScreen: () -> Unit,
|
onNavigateToBlockAutoFillScreen: () -> Unit,
|
||||||
|
onNavigateToSetupAutofill: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
@ -94,6 +95,8 @@ fun AutoFillScreen(
|
||||||
AutoFillEvent.NavigateToSettings -> {
|
AutoFillEvent.NavigateToSettings -> {
|
||||||
intentManager.startCredentialManagerSettings(context)
|
intentManager.startCredentialManagerSettings(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AutoFillEvent.NavigateToSetupAutofill -> onNavigateToSetupAutofill()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ class AutoFillViewModel @Inject constructor(
|
||||||
|
|
||||||
private fun handleAutoFillActionCardCtClick() {
|
private fun handleAutoFillActionCardCtClick() {
|
||||||
dismissShowAutofillActionCard()
|
dismissShowAutofillActionCard()
|
||||||
// TODO PM-13068 navigate to auto fill setup screen
|
sendEvent(AutoFillEvent.NavigateToSetupAutofill)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleUpdateShowAutofillActionCard(
|
private fun handleUpdateShowAutofillActionCard(
|
||||||
|
@ -261,6 +261,11 @@ sealed class AutoFillEvent {
|
||||||
data class ShowToast(
|
data class ShowToast(
|
||||||
val text: Text,
|
val text: Text,
|
||||||
) : AutoFillEvent()
|
) : AutoFillEvent()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigates to the setup autofill screen.
|
||||||
|
*/
|
||||||
|
data object NavigateToSetupAutofill : AutoFillEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,6 +4,10 @@ import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.NavOptions
|
import androidx.navigation.NavOptions
|
||||||
import androidx.navigation.navigation
|
import androidx.navigation.navigation
|
||||||
|
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.navigateToSetupAutoFillScreen
|
||||||
|
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.navigateToSetupUnlockScreen
|
||||||
|
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.setupAutoFillDestination
|
||||||
|
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.setupUnlockDestination
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.search.navigateToSearch
|
import com.x8bit.bitwarden.ui.platform.feature.search.navigateToSearch
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.search.searchDestination
|
import com.x8bit.bitwarden.ui.platform.feature.search.searchDestination
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.deleteaccount.deleteAccountDestination
|
import com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.deleteaccount.deleteAccountDestination
|
||||||
|
@ -98,6 +102,8 @@ fun NavGraphBuilder.vaultUnlockedGraph(
|
||||||
passwordHistoryMode = GeneratorPasswordHistoryMode.Default,
|
passwordHistoryMode = GeneratorPasswordHistoryMode.Default,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
onNavigateToSetupUnlockScreen = { navController.navigateToSetupUnlockScreen() },
|
||||||
|
onNavigateToSetupAutoFillScreen = { navController.navigateToSetupAutoFillScreen() },
|
||||||
)
|
)
|
||||||
deleteAccountDestination(
|
deleteAccountDestination(
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.popBackStack() },
|
||||||
|
@ -200,5 +206,15 @@ fun NavGraphBuilder.vaultUnlockedGraph(
|
||||||
attachmentDestination(
|
attachmentDestination(
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.popBackStack() },
|
||||||
)
|
)
|
||||||
|
setupUnlockDestination(
|
||||||
|
onNavigateBack = {
|
||||||
|
navController.popBackStack()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
setupAutoFillDestination(
|
||||||
|
onNavigateBack = {
|
||||||
|
navController.popBackStack()
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,8 @@ fun NavGraphBuilder.vaultUnlockedNavBarDestination(
|
||||||
onNavigateToFolders: () -> Unit,
|
onNavigateToFolders: () -> Unit,
|
||||||
onNavigateToPendingRequests: () -> Unit,
|
onNavigateToPendingRequests: () -> Unit,
|
||||||
onNavigateToPasswordHistory: () -> Unit,
|
onNavigateToPasswordHistory: () -> Unit,
|
||||||
|
onNavigateToSetupUnlockScreen: () -> Unit,
|
||||||
|
onNavigateToSetupAutoFillScreen: () -> Unit,
|
||||||
) {
|
) {
|
||||||
composableWithStayTransitions(
|
composableWithStayTransitions(
|
||||||
route = VAULT_UNLOCKED_NAV_BAR_ROUTE,
|
route = VAULT_UNLOCKED_NAV_BAR_ROUTE,
|
||||||
|
@ -53,6 +55,8 @@ fun NavGraphBuilder.vaultUnlockedNavBarDestination(
|
||||||
onNavigateToFolders = onNavigateToFolders,
|
onNavigateToFolders = onNavigateToFolders,
|
||||||
onNavigateToPendingRequests = onNavigateToPendingRequests,
|
onNavigateToPendingRequests = onNavigateToPendingRequests,
|
||||||
onNavigateToPasswordHistory = onNavigateToPasswordHistory,
|
onNavigateToPasswordHistory = onNavigateToPasswordHistory,
|
||||||
|
onNavigateToSetupUnlockScreen = onNavigateToSetupUnlockScreen,
|
||||||
|
onNavigateToSetupAutoFillScreen = onNavigateToSetupAutoFillScreen,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import androidx.navigation.navOptions
|
import androidx.navigation.navOptions
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.accountsetup.setupUnlockDestination
|
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.max
|
import com.x8bit.bitwarden.ui.platform.base.util.max
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.toDp
|
import com.x8bit.bitwarden.ui.platform.base.util.toDp
|
||||||
|
@ -76,6 +75,8 @@ fun VaultUnlockedNavBarScreen(
|
||||||
onNavigateToFolders: () -> Unit,
|
onNavigateToFolders: () -> Unit,
|
||||||
onNavigateToPendingRequests: () -> Unit,
|
onNavigateToPendingRequests: () -> Unit,
|
||||||
onNavigateToPasswordHistory: () -> Unit,
|
onNavigateToPasswordHistory: () -> Unit,
|
||||||
|
onNavigateToSetupUnlockScreen: () -> Unit,
|
||||||
|
onNavigateToSetupAutoFillScreen: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
|
@ -133,6 +134,8 @@ fun VaultUnlockedNavBarScreen(
|
||||||
settingsTabClickedAction = remember(viewModel) {
|
settingsTabClickedAction = remember(viewModel) {
|
||||||
{ viewModel.trySendAction(VaultUnlockedNavBarAction.SettingsTabClick) }
|
{ viewModel.trySendAction(VaultUnlockedNavBarAction.SettingsTabClick) }
|
||||||
},
|
},
|
||||||
|
onNavigateToSetupUnlockScreen = onNavigateToSetupUnlockScreen,
|
||||||
|
onNavigateToSetupAutoFillScreen = onNavigateToSetupAutoFillScreen,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +163,8 @@ private fun VaultUnlockedNavBarScaffold(
|
||||||
navigateToFolders: () -> Unit,
|
navigateToFolders: () -> Unit,
|
||||||
navigateToPendingRequests: () -> Unit,
|
navigateToPendingRequests: () -> Unit,
|
||||||
navigateToPasswordHistory: () -> Unit,
|
navigateToPasswordHistory: () -> Unit,
|
||||||
|
onNavigateToSetupUnlockScreen: () -> Unit,
|
||||||
|
onNavigateToSetupAutoFillScreen: () -> Unit,
|
||||||
) {
|
) {
|
||||||
var shouldDimNavBar by remember { mutableStateOf(false) }
|
var shouldDimNavBar by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
@ -235,11 +240,8 @@ private fun VaultUnlockedNavBarScaffold(
|
||||||
onNavigateToExportVault = navigateToExportVault,
|
onNavigateToExportVault = navigateToExportVault,
|
||||||
onNavigateToFolders = navigateToFolders,
|
onNavigateToFolders = navigateToFolders,
|
||||||
onNavigateToPendingRequests = navigateToPendingRequests,
|
onNavigateToPendingRequests = navigateToPendingRequests,
|
||||||
)
|
onNavigateToSetupUnlockScreen = onNavigateToSetupUnlockScreen,
|
||||||
setupUnlockDestination(
|
onNavigateToSetupAutoFillScreen = onNavigateToSetupAutoFillScreen,
|
||||||
onNavigateBack = {
|
|
||||||
navController.popBackStack()
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.x8bit.bitwarden.ui.auth.feature.accountsetup
|
package com.x8bit.bitwarden.ui.auth.feature.accountsetup
|
||||||
|
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus
|
import com.x8bit.bitwarden.data.auth.datasource.disk.model.OnboardingStatus
|
||||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||||
|
@ -128,6 +129,25 @@ class SetupAutoFillViewModelTest : BaseViewModelTest() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `handleContinueClick send NavigateBack event when not initial setup`() = runTest {
|
||||||
|
val viewModel = createViewModel(initialState = DEFAULT_STATE.copy(isInitialSetup = false))
|
||||||
|
viewModel.eventFlow.test {
|
||||||
|
viewModel.trySendAction(SetupAutoFillAction.ContinueClick)
|
||||||
|
assertEquals(
|
||||||
|
SetupAutoFillEvent.NavigateBack,
|
||||||
|
awaitItem(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
verify(exactly = 0) {
|
||||||
|
authRepository.setOnboardingStatus(
|
||||||
|
DEFAULT_USER_ID,
|
||||||
|
OnboardingStatus.FINAL_STEP,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `handleTurnOnLaterConfirmClick sets showAutoFillSettingBadge to true`() {
|
fun `handleTurnOnLaterConfirmClick sets showAutoFillSettingBadge to true`() {
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
|
@ -140,10 +160,34 @@ class SetupAutoFillViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createViewModel() = SetupAutoFillViewModel(
|
@Test
|
||||||
|
fun `handleClose click sends NavigateBack event`() = runTest {
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
viewModel.eventFlow.test {
|
||||||
|
viewModel.trySendAction(SetupAutoFillAction.CloseClick)
|
||||||
|
assertEquals(SetupAutoFillEvent.NavigateBack, awaitItem())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createViewModel(
|
||||||
|
initialState: SetupAutoFillState? = null,
|
||||||
|
) = SetupAutoFillViewModel(
|
||||||
|
savedStateHandle = SavedStateHandle(
|
||||||
|
mapOf(
|
||||||
|
"state" to initialState,
|
||||||
|
"isInitialSetup" to true,
|
||||||
|
),
|
||||||
|
),
|
||||||
settingsRepository = settingsRepository,
|
settingsRepository = settingsRepository,
|
||||||
authRepository = authRepository,
|
authRepository = authRepository,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val DEFAULT_USER_ID = "userId"
|
private const val DEFAULT_USER_ID = "userId"
|
||||||
|
|
||||||
|
private val DEFAULT_STATE = SetupAutoFillState(
|
||||||
|
userId = DEFAULT_USER_ID,
|
||||||
|
dialogState = null,
|
||||||
|
autofillEnabled = false,
|
||||||
|
isInitialSetup = true,
|
||||||
|
)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import androidx.compose.ui.test.filterToOne
|
||||||
import androidx.compose.ui.test.hasAnyAncestor
|
import androidx.compose.ui.test.hasAnyAncestor
|
||||||
import androidx.compose.ui.test.isDialog
|
import androidx.compose.ui.test.isDialog
|
||||||
import androidx.compose.ui.test.onAllNodesWithText
|
import androidx.compose.ui.test.onAllNodesWithText
|
||||||
|
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||||
import androidx.compose.ui.test.onNodeWithText
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
import androidx.compose.ui.test.performScrollTo
|
import androidx.compose.ui.test.performScrollTo
|
||||||
|
@ -15,12 +16,14 @@ import com.x8bit.bitwarden.ui.util.assertNoDialogExists
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
|
import junit.framework.TestCase.assertTrue
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class SetupAutofillScreenTest : BaseComposeTest() {
|
class SetupAutofillScreenTest : BaseComposeTest() {
|
||||||
|
private var onNavigateBackCalled = false
|
||||||
|
|
||||||
private val mutableEventFlow = bufferedMutableSharedFlow<SetupAutoFillEvent>()
|
private val mutableEventFlow = bufferedMutableSharedFlow<SetupAutoFillEvent>()
|
||||||
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
|
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
|
||||||
|
@ -38,6 +41,7 @@ class SetupAutofillScreenTest : BaseComposeTest() {
|
||||||
SetupAutoFillScreen(
|
SetupAutoFillScreen(
|
||||||
intentManager = intentManager,
|
intentManager = intentManager,
|
||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
|
onNavigateBack = { onNavigateBackCalled = true },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,6 +94,15 @@ class SetupAutofillScreenTest : BaseComposeTest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Turn on later component should not be displayed when not in initial setup`() {
|
||||||
|
mutableStateFlow.update { it.copy(isInitialSetup = false) }
|
||||||
|
composeTestRule.assertNoDialogExists()
|
||||||
|
composeTestRule
|
||||||
|
.onNodeWithText(text = "Turn on later")
|
||||||
|
.assertDoesNotExist()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `NavigateToAutoFillSettings should start system autofill settings activity`() {
|
fun `NavigateToAutoFillSettings should start system autofill settings activity`() {
|
||||||
every { intentManager.startSystemAutofillSettingsActivity() } returns true
|
every { intentManager.startSystemAutofillSettingsActivity() } returns true
|
||||||
|
@ -207,10 +220,35 @@ class SetupAutofillScreenTest : BaseComposeTest() {
|
||||||
}
|
}
|
||||||
composeTestRule.assertNoDialogExists()
|
composeTestRule.assertNoDialogExists()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `on NavigateBack event should invoke onNavigateBack`() {
|
||||||
|
mutableEventFlow.tryEmit(SetupAutoFillEvent.NavigateBack)
|
||||||
|
assertTrue(onNavigateBackCalled)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `close icon should not show when in initial setup`() {
|
||||||
|
composeTestRule
|
||||||
|
.onNodeWithContentDescription(label = "Close")
|
||||||
|
.assertDoesNotExist()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `close icon should show when not initial setup and send action when clicked`() {
|
||||||
|
mutableStateFlow.update { it.copy(isInitialSetup = false) }
|
||||||
|
composeTestRule
|
||||||
|
.onNodeWithContentDescription(label = "Close")
|
||||||
|
.assertIsDisplayed()
|
||||||
|
.performClick()
|
||||||
|
|
||||||
|
verify { viewModel.trySendAction(SetupAutoFillAction.CloseClick) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val DEFAULT_STATE = SetupAutoFillState(
|
private val DEFAULT_STATE = SetupAutoFillState(
|
||||||
userId = "userId",
|
userId = "userId",
|
||||||
dialogState = null,
|
dialogState = null,
|
||||||
autofillEnabled = false,
|
autofillEnabled = false,
|
||||||
|
isInitialSetup = true,
|
||||||
)
|
)
|
||||||
|
|
|
@ -250,7 +250,7 @@ class RootNavScreenTest : BaseComposeTest() {
|
||||||
RootNavState.OnboardingAutoFillSetup
|
RootNavState.OnboardingAutoFillSetup
|
||||||
composeTestRule.runOnIdle {
|
composeTestRule.runOnIdle {
|
||||||
fakeNavHostController.assertLastNavigation(
|
fakeNavHostController.assertLastNavigation(
|
||||||
route = "setup_auto_fill",
|
route = "setup_auto_fill_as_root/true",
|
||||||
navOptions = expectedNavOptions,
|
navOptions = expectedNavOptions,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ class AutoFillScreenTest : BaseComposeTest() {
|
||||||
private var isSystemSettingsRequestSuccess = false
|
private var isSystemSettingsRequestSuccess = false
|
||||||
private var onNavigateBackCalled = false
|
private var onNavigateBackCalled = false
|
||||||
private var onNavigateToBlockAutoFillScreenCalled = false
|
private var onNavigateToBlockAutoFillScreenCalled = false
|
||||||
|
private var onNavigateToSetupAutoFillScreenCalled = false
|
||||||
|
|
||||||
private val mutableEventFlow = bufferedMutableSharedFlow<AutoFillEvent>()
|
private val mutableEventFlow = bufferedMutableSharedFlow<AutoFillEvent>()
|
||||||
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
|
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
|
||||||
|
@ -56,6 +57,7 @@ class AutoFillScreenTest : BaseComposeTest() {
|
||||||
onNavigateToBlockAutoFillScreen = { onNavigateToBlockAutoFillScreenCalled = true },
|
onNavigateToBlockAutoFillScreen = { onNavigateToBlockAutoFillScreenCalled = true },
|
||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
intentManager = intentManager,
|
intentManager = intentManager,
|
||||||
|
onNavigateToSetupAutofill = { onNavigateToSetupAutoFillScreenCalled = true },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -498,6 +500,12 @@ class AutoFillScreenTest : BaseComposeTest() {
|
||||||
.performClick()
|
.performClick()
|
||||||
verify { viewModel.trySendAction(AutoFillAction.DismissShowAutofillActionCard) }
|
verify { viewModel.trySendAction(AutoFillAction.DismissShowAutofillActionCard) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when NavigateToSetupAutofill event is sent should call onNavigateToSetupAutofill`() {
|
||||||
|
mutableEventFlow.tryEmit(AutoFillEvent.NavigateToSetupAutofill)
|
||||||
|
assertTrue(onNavigateToSetupAutoFillScreenCalled)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val DEFAULT_STATE: AutoFillState = AutoFillState(
|
private val DEFAULT_STATE: AutoFillState = AutoFillState(
|
||||||
|
|
|
@ -321,10 +321,17 @@ class AutoFillViewModelTest : BaseViewModelTest() {
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `when AutoFillActionCardCtaClick action is sent should update show autofill in repository`() {
|
fun `when AutoFillActionCardCtaClick action is sent should update show autofill in repository and send NavigateToSetupAutofill event`() =
|
||||||
|
runTest {
|
||||||
mutableShowAutofillActionCardFlow.update { true }
|
mutableShowAutofillActionCardFlow.update { true }
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
|
viewModel.eventFlow.test {
|
||||||
viewModel.trySendAction(AutoFillAction.AutoFillActionCardCtaClick)
|
viewModel.trySendAction(AutoFillAction.AutoFillActionCardCtaClick)
|
||||||
|
assertEquals(
|
||||||
|
AutoFillEvent.NavigateToSetupAutofill,
|
||||||
|
awaitItem(),
|
||||||
|
)
|
||||||
|
}
|
||||||
verify {
|
verify {
|
||||||
settingsRepository.storeShowAutoFillSettingBadge(
|
settingsRepository.storeShowAutoFillSettingBadge(
|
||||||
DEFAULT_STATE.activeUserId,
|
DEFAULT_STATE.activeUserId,
|
||||||
|
|
|
@ -53,6 +53,8 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() {
|
||||||
onNavigateToPendingRequests = {},
|
onNavigateToPendingRequests = {},
|
||||||
onNavigateToSearchVault = {},
|
onNavigateToSearchVault = {},
|
||||||
onNavigateToSearchSend = {},
|
onNavigateToSearchSend = {},
|
||||||
|
onNavigateToSetupAutoFillScreen = {},
|
||||||
|
onNavigateToSetupUnlockScreen = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue