mirror of
https://github.com/bitwarden/android.git
synced 2025-02-16 11:59:57 +03:00
PM-10621: Create common biometrics and pin unlock UI elements (#3696)
This commit is contained in:
parent
be534f940b
commit
e598fe5714
6 changed files with 268 additions and 208 deletions
|
@ -0,0 +1,39 @@
|
|||
package com.x8bit.bitwarden.ui.platform.components.toggle
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.x8bit.bitwarden.R
|
||||
|
||||
/**
|
||||
* Displays a switch for enabling or disabling unlock with biometrics functionality.
|
||||
*
|
||||
* @param isChecked Indicates that the switch should be checked or not.
|
||||
* @param isBiometricsSupported Indicates if biometrics is supported and we should display the
|
||||
* switch.
|
||||
* @param onDisableBiometrics Callback invoked when the toggle has be turned off.
|
||||
* @param onEnableBiometrics Callback invoked when the toggle has be turned on.
|
||||
* @param modifier The [Modifier] to be applied to the switch.
|
||||
*/
|
||||
@Composable
|
||||
fun BitwardenUnlockWithBiometricsSwitch(
|
||||
isBiometricsSupported: Boolean,
|
||||
isChecked: Boolean,
|
||||
onDisableBiometrics: () -> Unit,
|
||||
onEnableBiometrics: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (!isBiometricsSupported) return
|
||||
BitwardenWideSwitch(
|
||||
modifier = modifier,
|
||||
label = stringResource(id = R.string.unlock_with, stringResource(id = R.string.biometrics)),
|
||||
isChecked = isChecked,
|
||||
onCheckedChange = { toggled ->
|
||||
if (toggled) {
|
||||
onEnableBiometrics()
|
||||
} else {
|
||||
onDisableBiometrics()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
package com.x8bit.bitwarden.ui.platform.components.toggle
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.PinInputDialog
|
||||
|
||||
/**
|
||||
* Displays a switch for enabling or disabling unlock with pin functionality.
|
||||
*
|
||||
* @param isUnlockWithPasswordEnabled Indicates whether or not the password unlocking is enabled.
|
||||
* @param isUnlockWithPinEnabled Indicates whether or not the pin unlocking is enabled.
|
||||
* @param onUnlockWithPinToggleAction Callback that is invoked when the current state of the switch
|
||||
* changes.
|
||||
* @param modifier The [Modifier] to be applied to the switch.
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun BitwardenUnlockWithPinSwitch(
|
||||
isUnlockWithPasswordEnabled: Boolean,
|
||||
isUnlockWithPinEnabled: Boolean,
|
||||
onUnlockWithPinToggleAction: (UnlockWithPinState) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var shouldShowPinInputDialog by rememberSaveable { mutableStateOf(value = false) }
|
||||
var shouldShowPinConfirmationDialog by rememberSaveable { mutableStateOf(value = false) }
|
||||
var pin by remember { mutableStateOf(value = "") }
|
||||
BitwardenWideSwitch(
|
||||
label = stringResource(id = R.string.unlock_with_pin),
|
||||
isChecked = isUnlockWithPinEnabled,
|
||||
onCheckedChange = { isChecked ->
|
||||
if (isChecked) {
|
||||
onUnlockWithPinToggleAction(UnlockWithPinState.PendingEnabled)
|
||||
shouldShowPinInputDialog = true
|
||||
} else {
|
||||
onUnlockWithPinToggleAction(UnlockWithPinState.Disabled)
|
||||
}
|
||||
},
|
||||
modifier = modifier,
|
||||
)
|
||||
|
||||
when {
|
||||
shouldShowPinInputDialog -> {
|
||||
PinInputDialog(
|
||||
onCancelClick = {
|
||||
shouldShowPinInputDialog = false
|
||||
onUnlockWithPinToggleAction(UnlockWithPinState.Disabled)
|
||||
pin = ""
|
||||
},
|
||||
onSubmitClick = {
|
||||
pin = it
|
||||
if (pin.isNotEmpty()) {
|
||||
shouldShowPinInputDialog = false
|
||||
if (isUnlockWithPasswordEnabled) {
|
||||
shouldShowPinConfirmationDialog = true
|
||||
onUnlockWithPinToggleAction(UnlockWithPinState.PendingEnabled)
|
||||
} else {
|
||||
onUnlockWithPinToggleAction(
|
||||
UnlockWithPinState.Enabled(
|
||||
pin = pin,
|
||||
shouldRequireMasterPasswordOnRestart = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
shouldShowPinInputDialog = false
|
||||
onUnlockWithPinToggleAction(UnlockWithPinState.Disabled)
|
||||
}
|
||||
},
|
||||
onDismissRequest = {
|
||||
shouldShowPinInputDialog = false
|
||||
onUnlockWithPinToggleAction(UnlockWithPinState.Disabled)
|
||||
pin = ""
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
shouldShowPinConfirmationDialog -> {
|
||||
BitwardenTwoButtonDialog(
|
||||
title = stringResource(id = R.string.unlock_with_pin),
|
||||
message = stringResource(id = R.string.pin_require_master_password_restart),
|
||||
confirmButtonText = stringResource(id = R.string.yes),
|
||||
dismissButtonText = stringResource(id = R.string.no),
|
||||
onConfirmClick = {
|
||||
shouldShowPinConfirmationDialog = false
|
||||
onUnlockWithPinToggleAction(
|
||||
UnlockWithPinState.Enabled(
|
||||
pin = pin,
|
||||
shouldRequireMasterPasswordOnRestart = true,
|
||||
),
|
||||
)
|
||||
pin = ""
|
||||
},
|
||||
onDismissClick = {
|
||||
shouldShowPinConfirmationDialog = false
|
||||
onUnlockWithPinToggleAction(
|
||||
UnlockWithPinState.Enabled(
|
||||
pin = pin,
|
||||
shouldRequireMasterPasswordOnRestart = false,
|
||||
),
|
||||
)
|
||||
pin = ""
|
||||
},
|
||||
onDismissRequest = {
|
||||
// Dismissing the dialog is the same as requiring a master password
|
||||
// confirmation.
|
||||
shouldShowPinConfirmationDialog = false
|
||||
onUnlockWithPinToggleAction(
|
||||
UnlockWithPinState.Enabled(
|
||||
pin = pin,
|
||||
shouldRequireMasterPasswordOnRestart = true,
|
||||
),
|
||||
)
|
||||
pin = ""
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User toggled the unlock with pin switch.
|
||||
*/
|
||||
sealed class UnlockWithPinState {
|
||||
/**
|
||||
* Whether or not the action represents PIN unlocking being enabled.
|
||||
*/
|
||||
abstract val isUnlockWithPinEnabled: Boolean
|
||||
|
||||
/**
|
||||
* The toggle was disabled.
|
||||
*/
|
||||
data object Disabled : UnlockWithPinState() {
|
||||
override val isUnlockWithPinEnabled: Boolean get() = false
|
||||
}
|
||||
|
||||
/**
|
||||
* The toggle was enabled but the behavior is pending confirmation.
|
||||
*/
|
||||
data object PendingEnabled : UnlockWithPinState() {
|
||||
override val isUnlockWithPinEnabled: Boolean get() = true
|
||||
}
|
||||
|
||||
/**
|
||||
* The toggle was enabled and the user's [pin] and [shouldRequireMasterPasswordOnRestart]
|
||||
* preference were confirmed.
|
||||
*/
|
||||
data class Enabled(
|
||||
val pin: String,
|
||||
val shouldRequireMasterPasswordOnRestart: Boolean,
|
||||
) : UnlockWithPinState() {
|
||||
override val isUnlockWithPinEnabled: Boolean get() = true
|
||||
}
|
||||
}
|
|
@ -52,7 +52,8 @@ import com.x8bit.bitwarden.ui.platform.components.row.BitwardenExternalLinkRow
|
|||
import com.x8bit.bitwarden.ui.platform.components.row.BitwardenTextRow
|
||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.text.BitwardenPolicyWarningText
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenWideSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenUnlockWithBiometricsSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenUnlockWithPinSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalBiometricsManager
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
|
||||
|
@ -196,9 +197,9 @@ fun AccountSecurityScreen(
|
|||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
UnlockWithBiometricsRow(
|
||||
isChecked = state.isUnlockWithBiometricsEnabled,
|
||||
showBiometricsPrompt = showBiometricsPrompt,
|
||||
BitwardenUnlockWithBiometricsSwitch(
|
||||
isBiometricsSupported = biometricsManager.isBiometricsSupported,
|
||||
isChecked = state.isUnlockWithBiometricsEnabled || showBiometricsPrompt,
|
||||
onDisableBiometrics = remember(viewModel) {
|
||||
{
|
||||
viewModel.trySendAction(
|
||||
|
@ -211,17 +212,16 @@ fun AccountSecurityScreen(
|
|||
onEnableBiometrics = remember(viewModel) {
|
||||
{ viewModel.trySendAction(AccountSecurityAction.EnableBiometricsClick) }
|
||||
},
|
||||
biometricsManager = biometricsManager,
|
||||
modifier = Modifier
|
||||
.testTag("UnlockWithBiometricsSwitch")
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
UnlockWithPinRow(
|
||||
BitwardenUnlockWithPinSwitch(
|
||||
isUnlockWithPasswordEnabled = state.isUnlockWithPasswordEnabled,
|
||||
isUnlockWithPinEnabled = state.isUnlockWithPinEnabled,
|
||||
onUnlockWithPinToggleAction = remember(viewModel) {
|
||||
{ viewModel.trySendAction(it) }
|
||||
{ viewModel.trySendAction(AccountSecurityAction.UnlockWithPinToggle(it)) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.testTag("UnlockWithPinSwitch")
|
||||
|
@ -380,149 +380,6 @@ private fun AccountSecurityDialogs(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UnlockWithBiometricsRow(
|
||||
isChecked: Boolean,
|
||||
showBiometricsPrompt: Boolean,
|
||||
onDisableBiometrics: () -> Unit,
|
||||
onEnableBiometrics: () -> Unit,
|
||||
biometricsManager: BiometricsManager,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (!biometricsManager.isBiometricsSupported) return
|
||||
BitwardenWideSwitch(
|
||||
modifier = modifier,
|
||||
label = stringResource(
|
||||
id = R.string.unlock_with,
|
||||
stringResource(id = R.string.biometrics),
|
||||
),
|
||||
isChecked = isChecked || showBiometricsPrompt,
|
||||
onCheckedChange = { toggled ->
|
||||
if (toggled) {
|
||||
onEnableBiometrics()
|
||||
} else {
|
||||
onDisableBiometrics()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun UnlockWithPinRow(
|
||||
isUnlockWithPasswordEnabled: Boolean,
|
||||
isUnlockWithPinEnabled: Boolean,
|
||||
onUnlockWithPinToggleAction: (AccountSecurityAction.UnlockWithPinToggle) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var shouldShowPinInputDialog by rememberSaveable { mutableStateOf(false) }
|
||||
var shouldShowPinConfirmationDialog by rememberSaveable { mutableStateOf(false) }
|
||||
var pin by remember { mutableStateOf("") }
|
||||
BitwardenWideSwitch(
|
||||
label = stringResource(id = R.string.unlock_with_pin),
|
||||
isChecked = isUnlockWithPinEnabled,
|
||||
onCheckedChange = { isChecked ->
|
||||
if (isChecked) {
|
||||
onUnlockWithPinToggleAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.PendingEnabled,
|
||||
)
|
||||
shouldShowPinInputDialog = true
|
||||
} else {
|
||||
onUnlockWithPinToggleAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Disabled,
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = modifier,
|
||||
)
|
||||
|
||||
when {
|
||||
shouldShowPinInputDialog -> {
|
||||
PinInputDialog(
|
||||
onCancelClick = {
|
||||
shouldShowPinInputDialog = false
|
||||
onUnlockWithPinToggleAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Disabled,
|
||||
)
|
||||
pin = ""
|
||||
},
|
||||
onSubmitClick = {
|
||||
pin = it
|
||||
if (pin.isNotEmpty()) {
|
||||
shouldShowPinInputDialog = false
|
||||
if (isUnlockWithPasswordEnabled) {
|
||||
shouldShowPinConfirmationDialog = true
|
||||
onUnlockWithPinToggleAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.PendingEnabled,
|
||||
)
|
||||
} else {
|
||||
onUnlockWithPinToggleAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Enabled(
|
||||
pin = pin,
|
||||
shouldRequireMasterPasswordOnRestart = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
shouldShowPinInputDialog = false
|
||||
onUnlockWithPinToggleAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Disabled,
|
||||
)
|
||||
}
|
||||
},
|
||||
onDismissRequest = {
|
||||
shouldShowPinInputDialog = false
|
||||
onUnlockWithPinToggleAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Disabled,
|
||||
)
|
||||
pin = ""
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
shouldShowPinConfirmationDialog -> {
|
||||
BitwardenTwoButtonDialog(
|
||||
title = stringResource(id = R.string.unlock_with_pin),
|
||||
message = stringResource(id = R.string.pin_require_master_password_restart),
|
||||
confirmButtonText = stringResource(id = R.string.yes),
|
||||
dismissButtonText = stringResource(id = R.string.no),
|
||||
onConfirmClick = {
|
||||
shouldShowPinConfirmationDialog = false
|
||||
onUnlockWithPinToggleAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Enabled(
|
||||
pin = pin,
|
||||
shouldRequireMasterPasswordOnRestart = true,
|
||||
),
|
||||
)
|
||||
pin = ""
|
||||
},
|
||||
onDismissClick = {
|
||||
shouldShowPinConfirmationDialog = false
|
||||
onUnlockWithPinToggleAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Enabled(
|
||||
pin = pin,
|
||||
shouldRequireMasterPasswordOnRestart = false,
|
||||
),
|
||||
)
|
||||
pin = ""
|
||||
},
|
||||
onDismissRequest = {
|
||||
// Dismissing the dialog is the same as requiring a master password
|
||||
// confirmation.
|
||||
shouldShowPinConfirmationDialog = false
|
||||
onUnlockWithPinToggleAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Enabled(
|
||||
pin = pin,
|
||||
shouldRequireMasterPasswordOnRestart = true,
|
||||
),
|
||||
)
|
||||
pin = ""
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SessionTimeoutPolicyRow(
|
||||
vaultTimeoutPolicyMinutes: Int?,
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
|||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.UnlockWithPinState
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
@ -258,21 +259,21 @@ class AccountSecurityViewModel @Inject constructor(
|
|||
|
||||
private fun handleUnlockWithPinToggle(action: AccountSecurityAction.UnlockWithPinToggle) {
|
||||
mutableStateFlow.update {
|
||||
it.copy(isUnlockWithPinEnabled = action.isUnlockWithPinEnabled)
|
||||
it.copy(isUnlockWithPinEnabled = action.unlockWithPinState.isUnlockWithPinEnabled)
|
||||
}
|
||||
|
||||
when (action) {
|
||||
AccountSecurityAction.UnlockWithPinToggle.PendingEnabled -> Unit
|
||||
AccountSecurityAction.UnlockWithPinToggle.Disabled -> {
|
||||
when (val state = action.unlockWithPinState) {
|
||||
UnlockWithPinState.PendingEnabled -> Unit
|
||||
UnlockWithPinState.Disabled -> {
|
||||
settingsRepository.clearUnlockPin()
|
||||
validateVaultTimeoutAction()
|
||||
}
|
||||
|
||||
is AccountSecurityAction.UnlockWithPinToggle.Enabled -> {
|
||||
is UnlockWithPinState.Enabled -> {
|
||||
settingsRepository.storeUnlockPin(
|
||||
pin = action.pin,
|
||||
pin = state.pin,
|
||||
shouldRequireMasterPasswordOnRestart =
|
||||
action.shouldRequireMasterPasswordOnRestart,
|
||||
state.shouldRequireMasterPasswordOnRestart,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -563,37 +564,9 @@ sealed class AccountSecurityAction {
|
|||
/**
|
||||
* User toggled the unlock with pin switch.
|
||||
*/
|
||||
sealed class UnlockWithPinToggle : AccountSecurityAction() {
|
||||
/**
|
||||
* Whether or not the action represents PIN unlocking being enabled.
|
||||
*/
|
||||
abstract val isUnlockWithPinEnabled: Boolean
|
||||
|
||||
/**
|
||||
* The toggle was disabled.
|
||||
*/
|
||||
data object Disabled : UnlockWithPinToggle() {
|
||||
override val isUnlockWithPinEnabled: Boolean get() = false
|
||||
}
|
||||
|
||||
/**
|
||||
* The toggle was enabled but the behavior is pending confirmation.
|
||||
*/
|
||||
data object PendingEnabled : UnlockWithPinToggle() {
|
||||
override val isUnlockWithPinEnabled: Boolean get() = true
|
||||
}
|
||||
|
||||
/**
|
||||
* The toggle was enabled and the user's [pin] and [shouldRequireMasterPasswordOnRestart]
|
||||
* preference were confirmed.
|
||||
*/
|
||||
data class Enabled(
|
||||
val pin: String,
|
||||
val shouldRequireMasterPasswordOnRestart: Boolean,
|
||||
) : UnlockWithPinToggle() {
|
||||
override val isUnlockWithPinEnabled: Boolean get() = true
|
||||
}
|
||||
}
|
||||
data class UnlockWithPinToggle(
|
||||
val unlockWithPinState: UnlockWithPinState,
|
||||
) : AccountSecurityAction()
|
||||
|
||||
/**
|
||||
* Models actions that can be sent by the view model itself.
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.x8bit.bitwarden.data.platform.repository.model.VaultTimeoutAction
|
|||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.UnlockWithPinState
|
||||
import com.x8bit.bitwarden.ui.platform.manager.biometrics.BiometricsManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
import com.x8bit.bitwarden.ui.util.assertNoDialogExists
|
||||
|
@ -244,7 +245,11 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
|||
.performScrollTo()
|
||||
.performClick()
|
||||
|
||||
verify { viewModel.trySendAction(AccountSecurityAction.UnlockWithPinToggle.Disabled) }
|
||||
verify {
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle(UnlockWithPinState.Disabled),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
|
@ -285,7 +290,11 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
|||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
.assertIsDisplayed()
|
||||
|
||||
verify { viewModel.trySendAction(AccountSecurityAction.UnlockWithPinToggle.PendingEnabled) }
|
||||
verify {
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle(UnlockWithPinState.PendingEnabled),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
|
@ -304,7 +313,11 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
|||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
.performClick()
|
||||
|
||||
verify { viewModel.trySendAction(AccountSecurityAction.UnlockWithPinToggle.Disabled) }
|
||||
verify {
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle(UnlockWithPinState.Disabled),
|
||||
)
|
||||
}
|
||||
composeTestRule.assertNoDialogExists()
|
||||
}
|
||||
|
||||
|
@ -324,7 +337,11 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
|||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
.performClick()
|
||||
|
||||
verify { viewModel.trySendAction(AccountSecurityAction.UnlockWithPinToggle.Disabled) }
|
||||
verify {
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle(UnlockWithPinState.Disabled),
|
||||
)
|
||||
}
|
||||
composeTestRule.assertNoDialogExists()
|
||||
}
|
||||
|
||||
|
@ -368,7 +385,11 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
|||
.filterToOne(hasAnyAncestor(isDialog()))
|
||||
.assertIsDisplayed()
|
||||
|
||||
verify { viewModel.trySendAction(AccountSecurityAction.UnlockWithPinToggle.PendingEnabled) }
|
||||
verify {
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle(UnlockWithPinState.PendingEnabled),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
|
@ -398,9 +419,11 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
|||
|
||||
verify {
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Enabled(
|
||||
pin = "1234",
|
||||
shouldRequireMasterPasswordOnRestart = false,
|
||||
AccountSecurityAction.UnlockWithPinToggle(
|
||||
UnlockWithPinState.Enabled(
|
||||
pin = "1234",
|
||||
shouldRequireMasterPasswordOnRestart = false,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -432,9 +455,11 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
|||
|
||||
verify {
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Enabled(
|
||||
pin = "1234",
|
||||
shouldRequireMasterPasswordOnRestart = false,
|
||||
AccountSecurityAction.UnlockWithPinToggle(
|
||||
UnlockWithPinState.Enabled(
|
||||
pin = "1234",
|
||||
shouldRequireMasterPasswordOnRestart = false,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -467,9 +492,11 @@ class AccountSecurityScreenTest : BaseComposeTest() {
|
|||
|
||||
verify {
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Enabled(
|
||||
pin = "1234",
|
||||
shouldRequireMasterPasswordOnRestart = true,
|
||||
AccountSecurityAction.UnlockWithPinToggle(
|
||||
UnlockWithPinState.Enabled(
|
||||
pin = "1234",
|
||||
shouldRequireMasterPasswordOnRestart = true,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.x8bit.bitwarden.data.vault.datasource.network.model.createMockPolicy
|
|||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.toggle.UnlockWithPinState
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
|
@ -458,7 +459,7 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
|||
every { settingsRepository.clearUnlockPin() } just runs
|
||||
val viewModel = createViewModel(initialState = initialState)
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Disabled,
|
||||
AccountSecurityAction.UnlockWithPinToggle(UnlockWithPinState.Disabled),
|
||||
)
|
||||
assertEquals(
|
||||
initialState.copy(isUnlockWithPinEnabled = false),
|
||||
|
@ -478,7 +479,7 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
|||
every { settingsRepository.vaultTimeoutAction = VaultTimeoutAction.LOGOUT } just runs
|
||||
val viewModel = createViewModel(initialState = initialState)
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Disabled,
|
||||
AccountSecurityAction.UnlockWithPinToggle(UnlockWithPinState.Disabled),
|
||||
)
|
||||
assertEquals(
|
||||
initialState.copy(
|
||||
|
@ -500,7 +501,7 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
|||
)
|
||||
val viewModel = createViewModel(initialState = initialState)
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.PendingEnabled,
|
||||
AccountSecurityAction.UnlockWithPinToggle(UnlockWithPinState.PendingEnabled),
|
||||
)
|
||||
assertEquals(
|
||||
initialState.copy(isUnlockWithPinEnabled = true),
|
||||
|
@ -518,9 +519,11 @@ class AccountSecurityViewModelTest : BaseViewModelTest() {
|
|||
|
||||
val viewModel = createViewModel(initialState = initialState)
|
||||
viewModel.trySendAction(
|
||||
AccountSecurityAction.UnlockWithPinToggle.Enabled(
|
||||
pin = "1234",
|
||||
shouldRequireMasterPasswordOnRestart = true,
|
||||
AccountSecurityAction.UnlockWithPinToggle(
|
||||
UnlockWithPinState.Enabled(
|
||||
pin = "1234",
|
||||
shouldRequireMasterPasswordOnRestart = true,
|
||||
),
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
|
|
Loading…
Add table
Reference in a new issue