PM-11176: Update generator to use segmented control (#4075)

This commit is contained in:
David Perez 2024-10-14 15:43:17 -05:00 committed by GitHub
parent 2b87cdac9e
commit efbf84238d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 958 additions and 1505 deletions

View file

@ -46,6 +46,7 @@ fun BitwardenSegmentedButton(
) { ) {
options.forEachIndexed { index, option -> options.forEachIndexed { index, option ->
SegmentedButton( SegmentedButton(
enabled = option.isEnabled,
selected = option.isChecked, selected = option.isChecked,
onClick = option.onClick, onClick = option.onClick,
colors = bitwardenSegmentedButtonColors(), colors = bitwardenSegmentedButtonColors(),
@ -74,5 +75,6 @@ data class SegmentedButtonState(
val text: String, val text: String,
val onClick: () -> Unit, val onClick: () -> Unit,
val isChecked: Boolean, val isChecked: Boolean,
val isEnabled: Boolean = true,
val testTag: String? = null, val testTag: String? = null,
) )

View file

@ -20,6 +20,6 @@ fun bitwardenSegmentedButtonColors(): SegmentedButtonColors = SegmentedButtonCol
disabledActiveContentColor = BitwardenTheme.colorScheme.filledButton.foregroundDisabled, disabledActiveContentColor = BitwardenTheme.colorScheme.filledButton.foregroundDisabled,
disabledActiveBorderColor = Color.Transparent, disabledActiveBorderColor = Color.Transparent,
disabledInactiveContainerColor = BitwardenTheme.colorScheme.background.primary, disabledInactiveContainerColor = BitwardenTheme.colorScheme.background.primary,
disabledInactiveContentColor = BitwardenTheme.colorScheme.filledButton.foregroundDisabled, disabledInactiveContentColor = BitwardenTheme.colorScheme.stroke.divider,
disabledInactiveBorderColor = Color.Transparent, disabledInactiveBorderColor = Color.Transparent,
) )

View file

@ -36,6 +36,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.x8bit.bitwarden.R import com.x8bit.bitwarden.R
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.LivecycleEventEffect import com.x8bit.bitwarden.ui.platform.base.util.LivecycleEventEffect
import com.x8bit.bitwarden.ui.platform.base.util.scrolledContainerBottomDivider
import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenMediumTopAppBar import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenMediumTopAppBar
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.action.BitwardenOverflowActionItem import com.x8bit.bitwarden.ui.platform.components.appbar.action.BitwardenOverflowActionItem
@ -49,7 +50,10 @@ import com.x8bit.bitwarden.ui.platform.components.field.BitwardenTextField
import com.x8bit.bitwarden.ui.platform.components.field.BitwardenTextFieldWithActions import com.x8bit.bitwarden.ui.platform.components.field.BitwardenTextFieldWithActions
import com.x8bit.bitwarden.ui.platform.components.header.BitwardenListHeaderText import com.x8bit.bitwarden.ui.platform.components.header.BitwardenListHeaderText
import com.x8bit.bitwarden.ui.platform.components.model.TooltipData import com.x8bit.bitwarden.ui.platform.components.model.TooltipData
import com.x8bit.bitwarden.ui.platform.components.model.TopAppBarDividerStyle
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.segment.BitwardenSegmentedButton
import com.x8bit.bitwarden.ui.platform.components.segment.SegmentedButtonState
import com.x8bit.bitwarden.ui.platform.components.slider.BitwardenSlider import com.x8bit.bitwarden.ui.platform.components.slider.BitwardenSlider
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarHost import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarHost
import com.x8bit.bitwarden.ui.platform.components.stepper.BitwardenStepper import com.x8bit.bitwarden.ui.platform.components.stepper.BitwardenStepper
@ -59,8 +63,8 @@ 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
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Passcode.PasscodeType.Passphrase.Companion.PASSPHRASE_MAX_NUMBER_OF_WORDS import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Passphrase.Companion.PASSPHRASE_MAX_NUMBER_OF_WORDS
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Passcode.PasscodeType.Passphrase.Companion.PASSPHRASE_MIN_NUMBER_OF_WORDS import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Passphrase.Companion.PASSPHRASE_MIN_NUMBER_OF_WORDS
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias.ServiceType import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias.ServiceType
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias.ServiceTypeOption import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias.ServiceTypeOption
import com.x8bit.bitwarden.ui.tools.feature.generator.model.GeneratorMode import com.x8bit.bitwarden.ui.tools.feature.generator.model.GeneratorMode
@ -129,17 +133,6 @@ fun GeneratorScreen(
{ viewModel.trySendAction(GeneratorAction.MainTypeOptionSelect(it)) } { viewModel.trySendAction(GeneratorAction.MainTypeOptionSelect(it)) }
} }
val onPasscodeOptionClicked: (GeneratorState.MainType.Passcode.PasscodeTypeOption) -> Unit =
remember(viewModel) {
{
viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeTypeOptionSelect(
it,
),
)
}
}
val onUsernameOptionClicked: (GeneratorState.MainType.Username.UsernameTypeOption) -> Unit = val onUsernameOptionClicked: (GeneratorState.MainType.Username.UsernameTypeOption) -> Unit =
remember(viewModel) { remember(viewModel) {
{ {
@ -183,9 +176,7 @@ fun GeneratorScreen(
BitwardenScaffold( BitwardenScaffold(
topBar = { topBar = {
when (state.generatorMode) { when (state.generatorMode) {
is GeneratorMode.Modal.Username, is GeneratorMode.Modal -> {
GeneratorMode.Modal.Password,
-> {
ModalAppBar( ModalAppBar(
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
onCloseClick = remember(viewModel) { onCloseClick = remember(viewModel) {
@ -212,22 +203,31 @@ fun GeneratorScreen(
}, },
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
) { innerPadding -> ) { innerPadding ->
ScrollContent( Column(modifier = Modifier.padding(innerPadding)) {
state = state, if (state.generatorMode == GeneratorMode.Default) {
onRegenerateClick = onRegenerateClick, MainStateOptionsItem(
onCopyClick = onCopyClick, selectedType = state.selectedType,
onMainStateOptionClicked = onMainStateOptionClicked, passcodePolicyOverride = state.passcodePolicyOverride,
onPasscodeSubStateOptionClicked = onPasscodeOptionClicked, possibleMainStates = state.typeOptions.toImmutableList(),
onUsernameSubStateOptionClicked = onUsernameOptionClicked, onMainStateOptionClicked = onMainStateOptionClicked,
passwordHandlers = passwordHandlers, modifier = Modifier
passphraseHandlers = passphraseHandlers, .scrolledContainerBottomDivider(topAppBarScrollBehavior = scrollBehavior),
usernameTypeHandlers = usernameTypeHandlers, )
forwardedEmailAliasHandlers = forwardedEmailAliasHandlers, }
plusAddressedEmailHandlers = plusAddressedEmailHandlers, ScrollContent(
catchAllEmailHandlers = catchAllEmailHandlers, state = state,
randomWordHandlers = randomWordHandlers, onRegenerateClick = onRegenerateClick,
modifier = Modifier.padding(innerPadding), onCopyClick = onCopyClick,
) onUsernameSubStateOptionClicked = onUsernameOptionClicked,
passwordHandlers = passwordHandlers,
passphraseHandlers = passphraseHandlers,
usernameTypeHandlers = usernameTypeHandlers,
forwardedEmailAliasHandlers = forwardedEmailAliasHandlers,
plusAddressedEmailHandlers = plusAddressedEmailHandlers,
catchAllEmailHandlers = catchAllEmailHandlers,
randomWordHandlers = randomWordHandlers,
)
}
} }
} }
@ -242,6 +242,7 @@ private fun DefaultAppBar(
BitwardenMediumTopAppBar( BitwardenMediumTopAppBar(
title = stringResource(id = R.string.generator), title = stringResource(id = R.string.generator),
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
dividerStyle = TopAppBarDividerStyle.NONE,
actions = { actions = {
BitwardenOverflowActionItem( BitwardenOverflowActionItem(
menuItemDataList = persistentListOf( menuItemDataList = persistentListOf(
@ -288,8 +289,6 @@ private fun ScrollContent(
state: GeneratorState, state: GeneratorState,
onRegenerateClick: () -> Unit, onRegenerateClick: () -> Unit,
onCopyClick: () -> Unit, onCopyClick: () -> Unit,
onMainStateOptionClicked: (GeneratorState.MainTypeOption) -> Unit,
onPasscodeSubStateOptionClicked: (GeneratorState.MainType.Passcode.PasscodeTypeOption) -> Unit,
onUsernameSubStateOptionClicked: (GeneratorState.MainType.Username.UsernameTypeOption) -> Unit, onUsernameSubStateOptionClicked: (GeneratorState.MainType.Username.UsernameTypeOption) -> Unit,
passwordHandlers: PasswordHandlers, passwordHandlers: PasswordHandlers,
passphraseHandlers: PassphraseHandlers, passphraseHandlers: PassphraseHandlers,
@ -305,8 +304,8 @@ private fun ScrollContent(
.fillMaxHeight() .fillMaxHeight()
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState()),
) { ) {
if (state.isUnderPolicy) { if (state.isUnderPolicy) {
Spacer(modifier = Modifier.height(8.dp))
BitwardenInfoCalloutCard( BitwardenInfoCalloutCard(
text = stringResource(id = R.string.password_generator_policy_in_effect), text = stringResource(id = R.string.password_generator_policy_in_effect),
modifier = Modifier modifier = Modifier
@ -324,15 +323,6 @@ private fun ScrollContent(
onRegenerateClick = onRegenerateClick, onRegenerateClick = onRegenerateClick,
) )
if (state.generatorMode == GeneratorMode.Default) {
Spacer(modifier = Modifier.height(8.dp))
MainStateOptionsItem(
selectedType = state.selectedType,
possibleMainStates = state.typeOptions.toImmutableList(),
onMainStateOptionClicked = onMainStateOptionClicked,
)
}
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
BitwardenListHeaderText( BitwardenListHeaderText(
@ -345,13 +335,17 @@ private fun ScrollContent(
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
when (val selectedType = state.selectedType) { when (val selectedType = state.selectedType) {
is GeneratorState.MainType.Passcode -> { is GeneratorState.MainType.Passphrase -> {
PasscodeTypeItems( PassphraseTypeContent(
passcodeState = selectedType, passphraseTypeState = selectedType,
onSubStateOptionClicked = onPasscodeSubStateOptionClicked,
passwordHandlers = passwordHandlers,
passphraseHandlers = passphraseHandlers, passphraseHandlers = passphraseHandlers,
overridePasswordPolicyRestriction = state.overridePassword, )
}
is GeneratorState.MainType.Password -> {
PasswordTypeContent(
passwordTypeState = selectedType,
passwordHandlers = passwordHandlers,
) )
} }
@ -407,92 +401,55 @@ private fun GeneratedStringItem(
@Composable @Composable
private fun MainStateOptionsItem( private fun MainStateOptionsItem(
selectedType: GeneratorState.MainType, selectedType: GeneratorState.MainType,
passcodePolicyOverride: GeneratorState.PasscodePolicyOverride?,
possibleMainStates: ImmutableList<GeneratorState.MainTypeOption>, possibleMainStates: ImmutableList<GeneratorState.MainTypeOption>,
onMainStateOptionClicked: (GeneratorState.MainTypeOption) -> Unit, onMainStateOptionClicked: (GeneratorState.MainTypeOption) -> Unit,
modifier: Modifier = Modifier,
) { ) {
val optionsWithStrings = possibleMainStates.associateWith { stringResource(id = it.labelRes) } BitwardenSegmentedButton(
options = possibleMainStates
.map { mainOptionType ->
SegmentedButtonState(
text = stringResource(id = mainOptionType.labelRes),
onClick = { onMainStateOptionClicked(mainOptionType) },
isChecked = selectedType.mainTypeOption == mainOptionType,
isEnabled = when (mainOptionType) {
GeneratorState.MainTypeOption.PASSWORD -> {
when (passcodePolicyOverride) {
GeneratorState.PasscodePolicyOverride.PASSWORD -> true
GeneratorState.PasscodePolicyOverride.PASSPHRASE -> false
null -> true
}
}
BitwardenMultiSelectButton( GeneratorState.MainTypeOption.PASSPHRASE -> {
label = stringResource(id = R.string.what_would_you_like_to_generate), when (passcodePolicyOverride) {
options = optionsWithStrings.values.toImmutableList(), GeneratorState.PasscodePolicyOverride.PASSWORD -> false
selectedOption = stringResource(id = selectedType.displayStringResId), GeneratorState.PasscodePolicyOverride.PASSPHRASE -> true
onOptionSelected = { selectedOption -> null -> true
val selectedOptionId = }
optionsWithStrings.entries.first { it.value == selectedOption }.key }
onMainStateOptionClicked(selectedOptionId)
}, GeneratorState.MainTypeOption.USERNAME -> true
modifier = Modifier },
.padding(horizontal = 16.dp) testTag = mainOptionType.testTag,
)
}
.toImmutableList(),
modifier = modifier
.fillMaxWidth() .fillMaxWidth()
.testTag("GeneratorTypePicker"), .testTag(tag = "GeneratorTypePicker"),
) )
} }
//endregion ScrollContent and Static Items //endregion ScrollContent and Static Items
//region PasscodeType Composables
@Composable
private fun ColumnScope.PasscodeTypeItems(
passcodeState: GeneratorState.MainType.Passcode,
onSubStateOptionClicked: (GeneratorState.MainType.Passcode.PasscodeTypeOption) -> Unit,
passwordHandlers: PasswordHandlers,
passphraseHandlers: PassphraseHandlers,
overridePasswordPolicyRestriction: Boolean,
) {
PasscodeOptionsItem(passcodeState, onSubStateOptionClicked, overridePasswordPolicyRestriction)
when (val selectedType = passcodeState.selectedType) {
is GeneratorState.MainType.Passcode.PasscodeType.Password -> {
PasswordTypeContent(
passwordTypeState = selectedType,
passwordHandlers = passwordHandlers,
)
}
is GeneratorState.MainType.Passcode.PasscodeType.Passphrase -> {
PassphraseTypeContent(
passphraseTypeState = selectedType,
passphraseHandlers = passphraseHandlers,
)
}
}
}
@Composable
private fun PasscodeOptionsItem(
currentSubState: GeneratorState.MainType.Passcode,
onSubStateOptionClicked: (GeneratorState.MainType.Passcode.PasscodeTypeOption) -> Unit,
overridePasswordPolicyRestriction: Boolean,
) {
val possibleSubStates = GeneratorState.MainType.Passcode.PasscodeTypeOption.entries
val optionsWithStrings = possibleSubStates.associateWith { stringResource(id = it.labelRes) }
BitwardenMultiSelectButton(
label = stringResource(id = R.string.password_type),
options = optionsWithStrings.values.toImmutableList(),
selectedOption = stringResource(id = currentSubState.selectedType.displayStringResId),
onOptionSelected = { selectedOption ->
val selectedOptionId =
optionsWithStrings.entries.first { it.value == selectedOption }.key
onSubStateOptionClicked(selectedOptionId)
},
isEnabled = !overridePasswordPolicyRestriction,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth()
.testTag("PasswordTypePicker"),
)
}
//endregion PasscodeType Composables
//region PasswordType Composables //region PasswordType Composables
@Suppress("LongMethod") @Suppress("LongMethod")
@Composable @Composable
private fun ColumnScope.PasswordTypeContent( private fun ColumnScope.PasswordTypeContent(
passwordTypeState: GeneratorState.MainType.Passcode.PasscodeType.Password, passwordTypeState: GeneratorState.MainType.Password,
passwordHandlers: PasswordHandlers, passwordHandlers: PasswordHandlers,
) { ) {
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
@ -707,7 +664,7 @@ private fun PasswordAvoidAmbiguousCharsToggleItem(
@Composable @Composable
private fun ColumnScope.PassphraseTypeContent( private fun ColumnScope.PassphraseTypeContent(
passphraseTypeState: GeneratorState.MainType.Passcode.PasscodeType.Passphrase, passphraseTypeState: GeneratorState.MainType.Passphrase,
passphraseHandlers: PassphraseHandlers, passphraseHandlers: PassphraseHandlers,
) { ) {
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
@ -1232,67 +1189,59 @@ private data class PasswordHandlers(
return PasswordHandlers( return PasswordHandlers(
onPasswordSliderLengthChange = { newLength, isUserInteracting -> onPasswordSliderLengthChange = { newLength, isUserInteracting ->
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password GeneratorAction.MainType.Password.SliderLengthChange(
.SliderLengthChange( length = newLength,
length = newLength, isUserInteracting = isUserInteracting,
isUserInteracting = isUserInteracting, ),
),
) )
}, },
onPasswordToggleCapitalLettersChange = { shouldUseCapitals -> onPasswordToggleCapitalLettersChange = { shouldUseCapitals ->
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password GeneratorAction.MainType.Password.ToggleCapitalLettersChange(
.ToggleCapitalLettersChange( useCapitals = shouldUseCapitals,
useCapitals = shouldUseCapitals, ),
),
) )
}, },
onPasswordToggleLowercaseLettersChange = { shouldUseLowercase -> onPasswordToggleLowercaseLettersChange = { shouldUseLowercase ->
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password GeneratorAction.MainType.Password.ToggleLowercaseLettersChange(
.ToggleLowercaseLettersChange( useLowercase = shouldUseLowercase,
useLowercase = shouldUseLowercase, ),
),
) )
}, },
onPasswordToggleNumbersChange = { shouldUseNumbers -> onPasswordToggleNumbersChange = { shouldUseNumbers ->
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password GeneratorAction.MainType.Password.ToggleNumbersChange(
.ToggleNumbersChange( useNumbers = shouldUseNumbers,
useNumbers = shouldUseNumbers, ),
),
) )
}, },
onPasswordToggleSpecialCharactersChange = { shouldUseSpecialChars -> onPasswordToggleSpecialCharactersChange = { shouldUseSpecialChars ->
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password GeneratorAction.MainType.Password.ToggleSpecialCharactersChange(
.ToggleSpecialCharactersChange( useSpecialChars = shouldUseSpecialChars,
useSpecialChars = shouldUseSpecialChars, ),
),
) )
}, },
onPasswordMinNumbersCounterChange = { newMinNumbers -> onPasswordMinNumbersCounterChange = { newMinNumbers ->
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password GeneratorAction.MainType.Password.MinNumbersCounterChange(
.MinNumbersCounterChange( minNumbers = newMinNumbers,
minNumbers = newMinNumbers, ),
),
) )
}, },
onPasswordMinSpecialCharactersChange = { newMinSpecial -> onPasswordMinSpecialCharactersChange = { newMinSpecial ->
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password GeneratorAction.MainType.Password.MinSpecialCharactersChange(
.MinSpecialCharactersChange( minSpecial = newMinSpecial,
minSpecial = newMinSpecial, ),
),
) )
}, },
onPasswordToggleAvoidAmbiguousCharsChange = { shouldAvoidAmbiguousChars -> onPasswordToggleAvoidAmbiguousCharsChange = { shouldAvoidAmbiguousChars ->
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password GeneratorAction.MainType.Password.ToggleAvoidAmbigousCharactersChange(
.ToggleAvoidAmbigousCharactersChange( avoidAmbiguousChars = shouldAvoidAmbiguousChars,
avoidAmbiguousChars = shouldAvoidAmbiguousChars, ),
),
) )
}, },
) )
@ -1317,34 +1266,30 @@ private data class PassphraseHandlers(
return PassphraseHandlers( return PassphraseHandlers(
onPassphraseNumWordsCounterChange = { changeInCounter -> onPassphraseNumWordsCounterChange = { changeInCounter ->
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Passphrase GeneratorAction.MainType.Passphrase.NumWordsCounterChange(
.NumWordsCounterChange( numWords = changeInCounter,
numWords = changeInCounter, ),
),
) )
}, },
onPassphraseWordSeparatorChange = { newSeparator -> onPassphraseWordSeparatorChange = { newSeparator ->
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Passphrase GeneratorAction.MainType.Passphrase.WordSeparatorTextChange(
.WordSeparatorTextChange( wordSeparator = newSeparator,
wordSeparator = newSeparator, ),
),
) )
}, },
onPassphraseCapitalizeToggleChange = { shouldCapitalize -> onPassphraseCapitalizeToggleChange = { shouldCapitalize ->
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Passphrase GeneratorAction.MainType.Passphrase.ToggleCapitalizeChange(
.ToggleCapitalizeChange( capitalize = shouldCapitalize,
capitalize = shouldCapitalize, ),
),
) )
}, },
onPassphraseIncludeNumberToggleChange = { shouldIncludeNumber -> onPassphraseIncludeNumberToggleChange = { shouldIncludeNumber ->
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Passphrase GeneratorAction.MainType.Passphrase.ToggleIncludeNumberChange(
.ToggleIncludeNumberChange( includeNumber = shouldIncludeNumber,
includeNumber = shouldIncludeNumber, ),
),
) )
}, },
) )

View file

@ -205,15 +205,7 @@ class GeneratorScreenTest : BaseComposeTest() {
fun `clicking a MainStateOption should send MainTypeOptionSelect action`() { fun `clicking a MainStateOption should send MainTypeOptionSelect action`() {
// Opens the menu // Opens the menu
composeTestRule composeTestRule
.onNodeWithContentDescription(label = "Password. What would you like to generate?") .onNodeWithText(text = "Password")
.performClick()
// Choose the option from the menu
composeTestRule
.onAllNodesWithText(text = "Password")
.onLast()
.performScrollTo()
.assert(hasAnyAncestor(isDialog()))
.performClick() .performClick()
verify { verify {
@ -228,45 +220,13 @@ class GeneratorScreenTest : BaseComposeTest() {
.assertDoesNotExist() .assertDoesNotExist()
} }
@Test
fun `clicking a PasscodeOption should send PasscodeTypeOption action`() {
// Opens the menu
composeTestRule
.onNodeWithContentDescription(label = "Password. Password type")
.performClick()
// Choose the option from the menu
composeTestRule
.onAllNodesWithText(text = "Passphrase")
.onLast()
.assert(hasAnyAncestor(isDialog()))
.performClick()
verify {
viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeTypeOptionSelect(
GeneratorState.MainType.Passcode.PasscodeTypeOption.PASSPHRASE,
),
)
}
// Make sure dialog is hidden:
composeTestRule
.onNode(isDialog())
.assertDoesNotExist()
}
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `clicking a UsernameOption should send UsernameTypeOption action`() { fun `clicking a UsernameOption should send UsernameTypeOption action`() {
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Username( selectedType = GeneratorState.MainType.Username(
GeneratorState GeneratorState.MainType.Username.UsernameType.PlusAddressedEmail(),
.MainType
.Username
.UsernameType
.PlusAddressedEmail(),
), ),
), ),
) )
@ -302,15 +262,7 @@ class GeneratorScreenTest : BaseComposeTest() {
//region Passcode Password Tests //region Passcode Password Tests
@Test @Test
fun `in Passcode_Password state, the ViewModel state should update the UI correctly`() { fun `in Password state, the ViewModel state should update the UI correctly`() {
composeTestRule
.onNodeWithContentDescription(label = "Password. What would you like to generate?")
.assertIsDisplayed()
composeTestRule
.onNodeWithContentDescription(label = "Password. Password type")
.assertIsDisplayed()
composeTestRule composeTestRule
.onNode( .onNode(
expectValue( expectValue(
@ -363,7 +315,7 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, adjusting the slider should send SliderLengthChange action with length not equal to default`() { fun `in Password state, adjusting the slider should send SliderLengthChange action with length not equal to default`() {
composeTestRule composeTestRule
.onNodeWithText("Length") .onNodeWithText("Length")
.onSiblings() .onSiblings()
@ -383,7 +335,7 @@ class GeneratorScreenTest : BaseComposeTest() {
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password.SliderLengthChange( GeneratorAction.MainType.Password.SliderLengthChange(
length = 128, length = 128,
isUserInteracting = true, isUserInteracting = true,
), ),
@ -396,7 +348,7 @@ class GeneratorScreenTest : BaseComposeTest() {
// actually get updated from its original value, and thus will be its original value of 14. // actually get updated from its original value, and thus will be its original value of 14.
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password.SliderLengthChange( GeneratorAction.MainType.Password.SliderLengthChange(
length = 14, length = 14,
isUserInteracting = false, isUserInteracting = false,
), ),
@ -406,14 +358,14 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, toggling the capital letters toggle should send ToggleCapitalLettersChange action`() { fun `in Password state, toggling the capital letters toggle should send ToggleCapitalLettersChange action`() {
composeTestRule.onNodeWithText("A—Z") composeTestRule.onNodeWithText("A—Z")
.performScrollTo() .performScrollTo()
.performClick() .performClick()
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password.ToggleCapitalLettersChange( GeneratorAction.MainType.Password.ToggleCapitalLettersChange(
useCapitals = false, useCapitals = false,
), ),
) )
@ -422,36 +374,15 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, toggling the use lowercase toggle should send ToggleLowercaseLettersChange action`() { fun `in Password state, toggling the use lowercase toggle should send ToggleLowercaseLettersChange action`() {
composeTestRule.onNodeWithText("a—z") composeTestRule.onNodeWithText("a—z")
.performScrollTo() .performScrollTo()
.performClick() .performClick()
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction GeneratorAction.MainType.Password.ToggleLowercaseLettersChange(
.MainType useLowercase = false,
.Passcode
.PasscodeType
.Password
.ToggleLowercaseLettersChange(
useLowercase = false,
),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `in Passcode_Password state, toggling the use numbers toggle should send ToggleNumbersChange action`() {
composeTestRule.onNodeWithText("0-9")
.performScrollTo()
.performClick()
verify {
viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password.ToggleNumbersChange(
useNumbers = false,
), ),
) )
} }
@ -459,28 +390,37 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, toggling the use special characters toggle should send ToggleSpecialCharactersChange action`() { fun `in Password state, toggling the use numbers toggle should send ToggleNumbersChange action`() {
composeTestRule.onNodeWithText("!@#$%^&*") composeTestRule.onNodeWithText("0-9")
.performScrollTo() .performScrollTo()
.performClick() .performClick()
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction GeneratorAction.MainType.Password.ToggleNumbersChange(useNumbers = false),
.MainType
.Passcode
.PasscodeType
.Password
.ToggleSpecialCharactersChange(
useSpecialChars = true,
),
) )
} }
} }
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, decrementing the minimum numbers counter should send MinNumbersCounterChange action`() { fun `in Password state, toggling the use special characters toggle should send ToggleSpecialCharactersChange action`() {
composeTestRule.onNodeWithText("!@#$%^&*")
.performScrollTo()
.performClick()
verify {
viewModel.trySendAction(
GeneratorAction.MainType.Password.ToggleSpecialCharactersChange(
useSpecialChars = true,
),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `in Password state, decrementing the minimum numbers counter should send MinNumbersCounterChange action`() {
val initialMinNumbers = 1 val initialMinNumbers = 1
composeTestRule.onNodeWithText("Minimum numbers") composeTestRule.onNodeWithText("Minimum numbers")
@ -492,7 +432,7 @@ class GeneratorScreenTest : BaseComposeTest() {
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password.MinNumbersCounterChange( GeneratorAction.MainType.Password.MinNumbersCounterChange(
minNumbers = initialMinNumbers - 1, minNumbers = initialMinNumbers - 1,
), ),
) )
@ -501,7 +441,7 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, incrementing the minimum numbers counter should send MinNumbersCounterChange action`() { fun `in Password state, incrementing the minimum numbers counter should send MinNumbersCounterChange action`() {
val initialMinNumbers = 1 val initialMinNumbers = 1
composeTestRule.onNodeWithText("Minimum numbers") composeTestRule.onNodeWithText("Minimum numbers")
@ -513,28 +453,19 @@ class GeneratorScreenTest : BaseComposeTest() {
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password.MinNumbersCounterChange( GeneratorAction.MainType.Password.MinNumbersCounterChange(
minNumbers = initialMinNumbers + 1, minNumbers = initialMinNumbers + 1,
), ),
) )
} }
} }
@Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, decrementing the minimum numbers counter below 0 should do nothing`() { fun `in Password state, decrementing the minimum numbers counter below 0 should do nothing`() {
val initialMinNumbers = 0 val initialMinNumbers = 0
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Password(minNumbers = initialMinNumbers),
GeneratorState
.MainType
.Passcode
.PasscodeType
.Password(
minNumbers = initialMinNumbers,
),
),
), ),
) )
@ -549,21 +480,12 @@ class GeneratorScreenTest : BaseComposeTest() {
verify(exactly = 1) { viewModel.trySendAction(any()) } verify(exactly = 1) { viewModel.trySendAction(any()) }
} }
@Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, incrementing the minimum numbers counter above 9 should do nothing`() { fun `in Password state, incrementing the minimum numbers counter above 9 should do nothing`() {
val initialMinNumbers = 9 val initialMinNumbers = 9
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Password(minNumbers = initialMinNumbers),
GeneratorState
.MainType
.Passcode
.PasscodeType
.Password(
minNumbers = initialMinNumbers,
),
),
), ),
) )
@ -580,7 +502,7 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, decrementing the minimum special characters counter should send MinSpecialCharactersChange action`() { fun `in Password state, decrementing the minimum special characters counter should send MinSpecialCharactersChange action`() {
val initialSpecialChars = 1 val initialSpecialChars = 1
composeTestRule.onNodeWithText("Minimum special") composeTestRule.onNodeWithText("Minimum special")
@ -592,7 +514,7 @@ class GeneratorScreenTest : BaseComposeTest() {
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password.MinSpecialCharactersChange( GeneratorAction.MainType.Password.MinSpecialCharactersChange(
minSpecial = initialSpecialChars - 1, minSpecial = initialSpecialChars - 1,
), ),
) )
@ -601,7 +523,7 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, incrementing the minimum special characters counter should send MinSpecialCharactersChange action`() { fun `in Password state, incrementing the minimum special characters counter should send MinSpecialCharactersChange action`() {
val initialSpecialChars = 1 val initialSpecialChars = 1
composeTestRule.onNodeWithText("Minimum special") composeTestRule.onNodeWithText("Minimum special")
@ -613,7 +535,7 @@ class GeneratorScreenTest : BaseComposeTest() {
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password.MinSpecialCharactersChange( GeneratorAction.MainType.Password.MinSpecialCharactersChange(
minSpecial = initialSpecialChars + 1, minSpecial = initialSpecialChars + 1,
), ),
) )
@ -622,19 +544,11 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, decrementing the minimum special characters below 0 should do nothing`() { fun `in Password state, decrementing the minimum special characters below 0 should do nothing`() {
val initialSpecialChars = 0 val initialSpecialChars = 0
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Password(minSpecial = initialSpecialChars),
GeneratorState
.MainType
.Passcode
.PasscodeType
.Password(
minSpecial = initialSpecialChars,
),
),
), ),
) )
@ -650,19 +564,11 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, decrementing the minimum special characters above 9 should do nothing`() { fun `in Password state, decrementing the minimum special characters above 9 should do nothing`() {
val initialSpecialChars = 9 val initialSpecialChars = 9
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Password(minSpecial = initialSpecialChars),
GeneratorState
.MainType
.Passcode
.PasscodeType
.Password(
minSpecial = initialSpecialChars,
),
),
), ),
) )
@ -678,41 +584,30 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, toggling the use avoid ambiguous characters toggle should send ToggleSpecialCharactersChange action`() { fun `in Password state, toggling the use avoid ambiguous characters toggle should send ToggleSpecialCharactersChange action`() {
composeTestRule.onNodeWithText("Avoid ambiguous characters") composeTestRule.onNodeWithText("Avoid ambiguous characters")
.performScrollTo() .performScrollTo()
.performClick() .performClick()
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction GeneratorAction.MainType.Password.ToggleAvoidAmbigousCharactersChange(
.MainType avoidAmbiguousChars = true,
.Passcode ),
.PasscodeType
.Password
.ToggleAvoidAmbigousCharactersChange(
avoidAmbiguousChars = true,
),
) )
} }
} }
@Test @Test
fun `in Passcode_Password state, disabled elements should not send events`() { fun `in Password state, disabled elements should not send events`() {
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Password(
GeneratorState capitalsEnabled = false,
.MainType lowercaseEnabled = false,
.Passcode numbersEnabled = false,
.PasscodeType specialCharsEnabled = false,
.Password( ambiguousCharsEnabled = false,
capitalsEnabled = false,
lowercaseEnabled = false,
numbersEnabled = false,
specialCharsEnabled = false,
ambiguousCharsEnabled = false,
),
), ),
), ),
) )
@ -735,72 +630,37 @@ class GeneratorScreenTest : BaseComposeTest() {
verify(exactly = 0) { verify(exactly = 0) {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction GeneratorAction.MainType.Password.ToggleCapitalLettersChange(useCapitals = false),
.MainType
.Passcode
.PasscodeType
.Password
.ToggleCapitalLettersChange(
useCapitals = false,
),
) )
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction GeneratorAction.MainType.Password.ToggleLowercaseLettersChange(
.MainType useLowercase = false,
.Passcode ),
.PasscodeType
.Password
.ToggleLowercaseLettersChange(
useLowercase = false,
),
) )
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction GeneratorAction.MainType.Password.ToggleNumbersChange(useNumbers = false),
.MainType
.Passcode
.PasscodeType
.Password
.ToggleNumbersChange(
useNumbers = false,
),
) )
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction GeneratorAction.MainType.Password.ToggleSpecialCharactersChange(
.MainType useSpecialChars = true,
.Passcode ),
.PasscodeType
.Password
.ToggleSpecialCharactersChange(
useSpecialChars = true,
),
) )
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction GeneratorAction.MainType.Password.ToggleAvoidAmbigousCharactersChange(
.MainType avoidAmbiguousChars = true,
.Passcode ),
.PasscodeType
.Password
.ToggleAvoidAmbigousCharactersChange(
avoidAmbiguousChars = true,
),
) )
} }
} }
@Test @Test
fun `in Passcode_Password state, minimum numbers cannot go below minimum threshold`() { fun `in Password state, minimum numbers cannot go below minimum threshold`() {
val initialMinNumbers = 5 val initialMinNumbers = 5
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Password(
GeneratorState minNumbersAllowed = initialMinNumbers,
.MainType
.Passcode
.PasscodeType
.Password(
minNumbersAllowed = initialMinNumbers,
),
), ),
), ),
) )
@ -814,7 +674,7 @@ class GeneratorScreenTest : BaseComposeTest() {
verify(exactly = 0) { verify(exactly = 0) {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password.MinNumbersCounterChange( GeneratorAction.MainType.Password.MinNumbersCounterChange(
minNumbers = 4, minNumbers = 4,
), ),
) )
@ -822,21 +682,15 @@ class GeneratorScreenTest : BaseComposeTest() {
} }
@Test @Test
fun `in Passcode_Password state, maximum numbers should match minimum if lower`() { fun `in Password state, maximum numbers should match minimum if lower`() {
val initialMinNumbers = 7 val initialMinNumbers = 7
val initialMaxNumbers = 5 val initialMaxNumbers = 5
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Password(
GeneratorState minNumbersAllowed = initialMinNumbers,
.MainType maxNumbersAllowed = initialMaxNumbers,
.Passcode
.PasscodeType
.Password(
minNumbersAllowed = initialMinNumbers,
maxNumbersAllowed = initialMaxNumbers,
),
), ),
), ),
) )
@ -850,21 +704,14 @@ class GeneratorScreenTest : BaseComposeTest() {
.assertIsDisplayed() .assertIsDisplayed()
} }
@Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Password state, minimum special characters cannot go below minimum threshold`() { fun `in Password state, minimum special characters cannot go below minimum threshold`() {
val initialMinSpecials = 5 val initialMinSpecials = 5
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Password(
GeneratorState minSpecialAllowed = initialMinSpecials,
.MainType
.Passcode
.PasscodeType
.Password(
minSpecialAllowed = initialMinSpecials,
),
), ),
), ),
) )
@ -878,7 +725,7 @@ class GeneratorScreenTest : BaseComposeTest() {
verify(exactly = 0) { verify(exactly = 0) {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Password.MinSpecialCharactersChange( GeneratorAction.MainType.Password.MinSpecialCharactersChange(
minSpecial = 4, minSpecial = 4,
), ),
) )
@ -886,21 +733,15 @@ class GeneratorScreenTest : BaseComposeTest() {
} }
@Test @Test
fun `in Passcode_Password state, maximum special should match minimum if lower `() { fun `in Password state, maximum special should match minimum if lower `() {
val initialMinSpecials = 7 val initialMinSpecials = 7
val initialMaxSpecials = 5 val initialMaxSpecials = 5
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Password(
GeneratorState minSpecialAllowed = initialMinSpecials,
.MainType maxSpecialAllowed = initialMaxSpecials,
.Passcode
.PasscodeType
.Password(
minSpecialAllowed = initialMinSpecials,
maxSpecialAllowed = initialMaxSpecials,
),
), ),
), ),
) )
@ -914,18 +755,12 @@ class GeneratorScreenTest : BaseComposeTest() {
} }
@Test @Test
fun `in Passcode_Passphrase state, disabled elements should not send events`() { fun `in Passphrase state, disabled elements should not send events`() {
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Passphrase(
GeneratorState capitalizeEnabled = false,
.MainType includeNumberEnabled = false,
.Passcode
.PasscodeType
.Passphrase(
capitalizeEnabled = false,
includeNumberEnabled = false,
),
), ),
), ),
) )
@ -939,44 +774,25 @@ class GeneratorScreenTest : BaseComposeTest() {
verify(exactly = 0) { verify(exactly = 0) {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction GeneratorAction.MainType.Passphrase.ToggleCapitalizeChange(
.MainType capitalize = true,
.Passcode ),
.PasscodeType
.Passphrase
.ToggleCapitalizeChange(
capitalize = true,
),
) )
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction GeneratorAction.MainType.Passphrase.ToggleIncludeNumberChange(
.MainType includeNumber = true,
.Passcode ),
.PasscodeType
.Passphrase
.ToggleIncludeNumberChange(
includeNumber = true,
),
) )
} }
} }
@Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_passphrase state, minimum number of words cannot go below minimum threshold`() { fun `in Passphrase state, minimum number of words cannot go below minimum threshold`() {
val initialMinWords = 5 val initialMinWords = 5
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Passphrase(minNumWords = initialMinWords),
GeneratorState
.MainType
.Passcode
.PasscodeType
.Passphrase(
minNumWords = initialMinWords,
),
),
), ),
) )
@ -989,9 +805,7 @@ class GeneratorScreenTest : BaseComposeTest() {
verify(exactly = 0) { verify(exactly = 0) {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Passphrase.NumWordsCounterChange( GeneratorAction.MainType.Passphrase.NumWordsCounterChange(numWords = 4),
numWords = 4,
),
) )
} }
} }
@ -1002,19 +816,11 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Passphrase state, decrementing number of words should send NumWordsCounterChange action with decremented value`() { fun `in Passphrase state, decrementing number of words should send NumWordsCounterChange action with decremented value`() {
val initialNumWords = 4 val initialNumWords = 4
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Passphrase(numWords = initialNumWords),
GeneratorState
.MainType
.Passcode
.PasscodeType
.Passphrase(
numWords = initialNumWords,
),
),
), ),
) )
@ -1029,7 +835,7 @@ class GeneratorScreenTest : BaseComposeTest() {
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Passphrase.NumWordsCounterChange( GeneratorAction.MainType.Passphrase.NumWordsCounterChange(
numWords = initialNumWords - 1, numWords = initialNumWords - 1,
), ),
) )
@ -1037,19 +843,11 @@ class GeneratorScreenTest : BaseComposeTest() {
} }
@Test @Test
fun `in Passcode_Passphrase state, decrementing number of words under 3 should do nothing`() { fun `in Passphrase state, decrementing number of words under 3 should do nothing`() {
val initialNumWords = 3 val initialNumWords = 3
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Passphrase(numWords = initialNumWords),
GeneratorState
.MainType
.Passcode
.PasscodeType
.Passphrase(
numWords = initialNumWords,
),
),
), ),
) )
@ -1066,19 +864,11 @@ class GeneratorScreenTest : BaseComposeTest() {
} }
@Test @Test
fun `in Passcode_Passphrase state, incrementing number of words over 20 should do nothing`() { fun `in Passphrase state, incrementing number of words over 20 should do nothing`() {
val initialNumWords = 20 val initialNumWords = 20
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Passphrase(numWords = initialNumWords),
GeneratorState
.MainType
.Passcode
.PasscodeType
.Passphrase(
numWords = initialNumWords,
),
),
), ),
) )
@ -1096,17 +886,11 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Passphrase state, incrementing number of words should send NumWordsCounterChange action with incremented value`() { fun `in Passphrase state, incrementing number of words should send NumWordsCounterChange action with incremented value`() {
val initialNumWords = 3 val initialNumWords = 3
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Passphrase(),
GeneratorState
.MainType
.Passcode
.PasscodeType
.Passphrase(),
),
), ),
) )
@ -1120,25 +904,18 @@ class GeneratorScreenTest : BaseComposeTest() {
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Passphrase.NumWordsCounterChange( GeneratorAction.MainType.Passphrase.NumWordsCounterChange(
numWords = initialNumWords + 1, numWords = initialNumWords + 1,
), ),
) )
} }
} }
@Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Passphrase state, toggling capitalize should send ToggleCapitalizeChange action`() { fun `in Passphrase state, toggling capitalize should send ToggleCapitalizeChange action`() {
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Passphrase(),
GeneratorState
.MainType
.Passcode
.PasscodeType
.Passphrase(),
),
), ),
) )
@ -1149,7 +926,7 @@ class GeneratorScreenTest : BaseComposeTest() {
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Passphrase.ToggleCapitalizeChange( GeneratorAction.MainType.Passphrase.ToggleCapitalizeChange(
capitalize = true, capitalize = true,
), ),
) )
@ -1158,16 +935,10 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Passphrase state, toggling the include number toggle should send ToggleIncludeNumberChange action`() { fun `in Passphrase state, toggling the include number toggle should send ToggleIncludeNumberChange action`() {
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Passphrase(),
GeneratorState
.MainType
.Passcode
.PasscodeType
.Passphrase(),
),
), ),
) )
@ -1177,7 +948,7 @@ class GeneratorScreenTest : BaseComposeTest() {
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Passphrase.ToggleIncludeNumberChange( GeneratorAction.MainType.Passphrase.ToggleIncludeNumberChange(
includeNumber = true, includeNumber = true,
), ),
) )
@ -1186,16 +957,10 @@ class GeneratorScreenTest : BaseComposeTest() {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `in Passcode_Passphrase state, updating text in word separator should send WordSeparatorTextChange action`() { fun `in Passphrase state, updating text in word separator should send WordSeparatorTextChange action`() {
updateState( updateState(
DEFAULT_STATE.copy( DEFAULT_STATE.copy(
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Passphrase(),
GeneratorState
.MainType
.Passcode
.PasscodeType
.Passphrase(),
),
), ),
) )
@ -1206,7 +971,7 @@ class GeneratorScreenTest : BaseComposeTest() {
verify { verify {
viewModel.trySendAction( viewModel.trySendAction(
GeneratorAction.MainType.Passcode.PasscodeType.Passphrase.WordSeparatorTextChange( GeneratorAction.MainType.Passphrase.WordSeparatorTextChange(
wordSeparator = 'a', wordSeparator = 'a',
), ),
) )
@ -1765,8 +1530,6 @@ class GeneratorScreenTest : BaseComposeTest() {
private val DEFAULT_STATE = GeneratorState( private val DEFAULT_STATE = GeneratorState(
generatedText = "", generatedText = "",
selectedType = GeneratorState.MainType.Passcode( selectedType = GeneratorState.MainType.Password(),
GeneratorState.MainType.Passcode.PasscodeType.Password(),
),
currentEmailAddress = "currentEmail", currentEmailAddress = "currentEmail",
) )