Clean up the generator screen and handlers (#4270)

This commit is contained in:
David Perez 2024-11-11 10:07:16 -06:00 committed by GitHub
parent 6dd783051f
commit 16cc70f344
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 535 additions and 484 deletions

View file

@ -67,6 +67,20 @@ import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Pa
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.ServiceTypeOption
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.CatchAllEmailHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.ForwardedEmailAliasHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.PassphraseHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.PasswordHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.PlusAddressedEmailHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.RandomWordHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.UsernameTypeHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.rememberCatchAllEmailHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.rememberForwardedEmailAliasHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.rememberPassphraseHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.rememberPasswordHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.rememberPlusAddressedEmailHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.rememberRandomWordHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.handlers.rememberUsernameTypeHandlers
import com.x8bit.bitwarden.ui.tools.feature.generator.model.GeneratorMode
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@ -135,47 +149,26 @@ fun GeneratorScreen(
remember(viewModel) {
{
viewModel.trySendAction(
GeneratorAction.MainType.Username.UsernameTypeOptionSelect(
it,
),
GeneratorAction.MainType.Username.UsernameTypeOptionSelect(it),
)
}
}
val passwordHandlers = remember(viewModel) {
PasswordHandlers.create(viewModel = viewModel)
}
val passphraseHandlers = remember(viewModel) {
PassphraseHandlers.create(viewModel = viewModel)
}
val usernameTypeHandlers = remember(viewModel) {
UsernameTypeHandlers.create(viewModel = viewModel)
}
val forwardedEmailAliasHandlers = remember(viewModel) {
ForwardedEmailAliasHandlers.create(viewModel = viewModel)
}
val plusAddressedEmailHandlers = remember(viewModel) {
PlusAddressedEmailHandlers.create(viewModel = viewModel)
}
val catchAllEmailHandlers = remember(viewModel) {
CatchAllEmailHandlers.create(viewModel = viewModel)
}
val randomWordHandlers = remember(viewModel) {
RandomWordHandlers.create(viewModel = viewModel)
}
val passwordHandlers = rememberPasswordHandlers(viewModel)
val passphraseHandlers = rememberPassphraseHandlers(viewModel)
val usernameTypeHandlers = rememberUsernameTypeHandlers(viewModel)
val forwardedEmailAliasHandlers = rememberForwardedEmailAliasHandlers(viewModel)
val plusAddressedEmailHandlers = rememberPlusAddressedEmailHandlers(viewModel)
val catchAllEmailHandlers = rememberCatchAllEmailHandlers(viewModel)
val randomWordHandlers = rememberRandomWordHandlers(viewModel)
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
BitwardenScaffold(
topBar = {
when (state.generatorMode) {
when (val generatorMode = state.generatorMode) {
is GeneratorMode.Modal -> {
ModalAppBar(
generatorMode = generatorMode,
scrollBehavior = scrollBehavior,
onCloseClick = remember(viewModel) {
{ viewModel.trySendAction(GeneratorAction.CloseClick) }
@ -234,6 +227,7 @@ fun GeneratorScreen(
private fun DefaultAppBar(
scrollBehavior: TopAppBarScrollBehavior,
onPasswordHistoryClick: () -> Unit,
modifier: Modifier = Modifier,
) {
BitwardenMediumTopAppBar(
title = stringResource(id = R.string.generator),
@ -249,15 +243,18 @@ private fun DefaultAppBar(
),
)
},
modifier = modifier,
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ModalAppBar(
generatorMode: GeneratorMode.Modal,
scrollBehavior: TopAppBarScrollBehavior,
onCloseClick: () -> Unit,
onSelectClick: () -> Unit,
modifier: Modifier = Modifier,
) {
BitwardenTopAppBar(
title = stringResource(id = R.string.generator),
@ -265,6 +262,10 @@ private fun ModalAppBar(
navigationIconContentDescription = stringResource(id = R.string.close),
onNavigationIconClick = onCloseClick,
scrollBehavior = scrollBehavior,
dividerStyle = when (generatorMode) {
GeneratorMode.Modal.Password -> TopAppBarDividerStyle.NONE
is GeneratorMode.Modal.Username -> TopAppBarDividerStyle.ON_SCROLL
},
actions = {
BitwardenTextButton(
label = stringResource(id = R.string.select),
@ -272,6 +273,7 @@ private fun ModalAppBar(
modifier = Modifier.testTag("SelectButton"),
)
},
modifier = modifier,
)
}
@ -365,6 +367,7 @@ private fun GeneratedStringItem(
generatedText: String,
onCopyClick: () -> Unit,
onRegenerateClick: () -> Unit,
modifier: Modifier = Modifier,
) {
BitwardenTextFieldWithActions(
label = "",
@ -390,7 +393,7 @@ private fun GeneratedStringItem(
textStyle = BitwardenTheme.typography.sensitiveInfoSmall,
shouldAddCustomLineBreaks = true,
visualTransformation = nonLetterColorVisualTransformation(),
modifier = Modifier.padding(horizontal = 16.dp),
modifier = modifier.padding(horizontal = 16.dp),
)
}
@ -469,26 +472,25 @@ private fun ColumnScope.PasswordTypeContent(
PasswordCapitalLettersToggleItem(
useCapitals = passwordTypeState.useCapitals,
onPasswordToggleCapitalLettersChange =
passwordHandlers.onPasswordToggleCapitalLettersChange,
onPasswordToggleCapitalLettersChange = passwordHandlers
.onPasswordToggleCapitalLettersChange,
enabled = passwordTypeState.capitalsEnabled,
)
PasswordLowercaseLettersToggleItem(
useLowercase = passwordTypeState.useLowercase,
onPasswordToggleLowercaseLettersChange =
passwordHandlers.onPasswordToggleLowercaseLettersChange,
onPasswordToggleLowercaseLettersChange = passwordHandlers
.onPasswordToggleLowercaseLettersChange,
enabled = passwordTypeState.lowercaseEnabled,
)
PasswordNumbersToggleItem(
useNumbers = passwordTypeState.useNumbers,
onPasswordToggleNumbersChange =
passwordHandlers.onPasswordToggleNumbersChange,
onPasswordToggleNumbersChange = passwordHandlers.onPasswordToggleNumbersChange,
enabled = passwordTypeState.numbersEnabled,
)
PasswordSpecialCharactersToggleItem(
useSpecialChars = passwordTypeState.useSpecialChars,
onPasswordToggleSpecialCharactersChange =
passwordHandlers.onPasswordToggleSpecialCharactersChange,
onPasswordToggleSpecialCharactersChange = passwordHandlers
.onPasswordToggleSpecialCharactersChange,
enabled = passwordTypeState.specialCharsEnabled,
)
}
@ -497,8 +499,7 @@ private fun ColumnScope.PasswordTypeContent(
PasswordMinNumbersCounterItem(
minNumbers = passwordTypeState.minNumbers,
onPasswordMinNumbersCounterChange =
passwordHandlers.onPasswordMinNumbersCounterChange,
onPasswordMinNumbersCounterChange = passwordHandlers.onPasswordMinNumbersCounterChange,
maxValue = max(passwordTypeState.maxNumbersAllowed, passwordTypeState.minNumbersAllowed),
minValue = passwordTypeState.minNumbersAllowed,
)
@ -507,8 +508,8 @@ private fun ColumnScope.PasswordTypeContent(
PasswordMinSpecialCharactersCounterItem(
minSpecial = passwordTypeState.minSpecial,
onPasswordMinSpecialCharactersChange =
passwordHandlers.onPasswordMinSpecialCharactersChange,
onPasswordMinSpecialCharactersChange = passwordHandlers
.onPasswordMinSpecialCharactersChange,
maxValue = max(passwordTypeState.maxSpecialAllowed, passwordTypeState.minSpecialAllowed),
minValue = passwordTypeState.minSpecialAllowed,
)
@ -517,8 +518,8 @@ private fun ColumnScope.PasswordTypeContent(
PasswordAvoidAmbiguousCharsToggleItem(
avoidAmbiguousChars = passwordTypeState.avoidAmbiguousChars,
onPasswordToggleAvoidAmbiguousCharsChange =
passwordHandlers.onPasswordToggleAvoidAmbiguousCharsChange,
onPasswordToggleAvoidAmbiguousCharsChange = passwordHandlers
.onPasswordToggleAvoidAmbiguousCharsChange,
enabled = passwordTypeState.ambiguousCharsEnabled,
)
}
@ -527,18 +528,19 @@ private fun ColumnScope.PasswordTypeContent(
private fun PasswordCapitalLettersToggleItem(
useCapitals: Boolean,
onPasswordToggleCapitalLettersChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
) {
BitwardenSwitch(
label = "A—Z",
contentDescription = stringResource(id = R.string.uppercase_ato_z),
isChecked = useCapitals,
onCheckedChange = onPasswordToggleCapitalLettersChange,
enabled = enabled,
modifier = Modifier
modifier = modifier
.fillMaxWidth()
.testTag("UppercaseAtoZToggle")
.padding(horizontal = 16.dp),
contentDescription = stringResource(id = R.string.uppercase_ato_z),
)
}
@ -546,18 +548,19 @@ private fun PasswordCapitalLettersToggleItem(
private fun PasswordLowercaseLettersToggleItem(
useLowercase: Boolean,
onPasswordToggleLowercaseLettersChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
) {
BitwardenSwitch(
label = "a—z",
contentDescription = stringResource(id = R.string.lowercase_ato_z),
isChecked = useLowercase,
onCheckedChange = onPasswordToggleLowercaseLettersChange,
enabled = enabled,
modifier = Modifier
modifier = modifier
.fillMaxWidth()
.testTag("LowercaseAtoZToggle")
.padding(horizontal = 16.dp),
contentDescription = stringResource(id = R.string.lowercase_ato_z),
)
}
@ -565,18 +568,19 @@ private fun PasswordLowercaseLettersToggleItem(
private fun PasswordNumbersToggleItem(
useNumbers: Boolean,
onPasswordToggleNumbersChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
) {
BitwardenSwitch(
label = "0-9",
contentDescription = stringResource(id = R.string.numbers_zero_to_nine),
isChecked = useNumbers,
onCheckedChange = onPasswordToggleNumbersChange,
enabled = enabled,
modifier = Modifier
modifier = modifier
.fillMaxWidth()
.testTag("NumbersZeroToNineToggle")
.padding(horizontal = 16.dp),
contentDescription = stringResource(id = R.string.numbers_zero_to_nine),
)
}
@ -584,18 +588,19 @@ private fun PasswordNumbersToggleItem(
private fun PasswordSpecialCharactersToggleItem(
useSpecialChars: Boolean,
onPasswordToggleSpecialCharactersChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
) {
BitwardenSwitch(
label = "!@#$%^&*",
contentDescription = stringResource(id = R.string.special_characters),
isChecked = useSpecialChars,
onCheckedChange = onPasswordToggleSpecialCharactersChange,
enabled = enabled,
modifier = Modifier
modifier = modifier
.fillMaxWidth()
.testTag("SpecialCharactersToggle")
.padding(horizontal = 16.dp),
contentDescription = stringResource(id = R.string.special_characters),
)
}
@ -605,13 +610,14 @@ private fun PasswordMinNumbersCounterItem(
onPasswordMinNumbersCounterChange: (Int) -> Unit,
minValue: Int,
maxValue: Int,
modifier: Modifier = Modifier,
) {
BitwardenStepper(
label = stringResource(id = R.string.min_numbers),
value = minNumbers.coerceIn(minValue, maxValue),
range = minValue..maxValue,
onValueChange = onPasswordMinNumbersCounterChange,
modifier = Modifier
modifier = modifier
.testTag("MinNumberValueLabel")
.padding(horizontal = 16.dp),
)
@ -623,13 +629,14 @@ private fun PasswordMinSpecialCharactersCounterItem(
onPasswordMinSpecialCharactersChange: (Int) -> Unit,
minValue: Int,
maxValue: Int,
modifier: Modifier = Modifier,
) {
BitwardenStepper(
label = stringResource(id = R.string.min_special),
value = minSpecial.coerceIn(minValue, maxValue),
range = minValue..maxValue,
onValueChange = onPasswordMinSpecialCharactersChange,
modifier = Modifier
modifier = modifier
.testTag("MinSpecialValueLabel")
.padding(horizontal = 16.dp),
)
@ -639,6 +646,7 @@ private fun PasswordMinSpecialCharactersCounterItem(
private fun PasswordAvoidAmbiguousCharsToggleItem(
avoidAmbiguousChars: Boolean,
onPasswordToggleAvoidAmbiguousCharsChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
) {
BitwardenSwitch(
@ -646,7 +654,7 @@ private fun PasswordAvoidAmbiguousCharsToggleItem(
isChecked = avoidAmbiguousChars,
enabled = enabled,
onCheckedChange = onPasswordToggleAvoidAmbiguousCharsChange,
modifier = Modifier
modifier = modifier
.fillMaxWidth()
.testTag("AvoidAmbiguousCharsToggle")
.padding(horizontal = 16.dp),
@ -666,8 +674,7 @@ private fun ColumnScope.PassphraseTypeContent(
PassphraseNumWordsCounterItem(
numWords = passphraseTypeState.numWords,
onPassphraseNumWordsCounterChange =
passphraseHandlers.onPassphraseNumWordsCounterChange,
onPassphraseNumWordsCounterChange = passphraseHandlers.onPassphraseNumWordsCounterChange,
minValue = passphraseTypeState.minNumWords,
maxValue = passphraseTypeState.maxNumWords,
)
@ -686,14 +693,14 @@ private fun ColumnScope.PassphraseTypeContent(
) {
PassphraseCapitalizeToggleItem(
capitalize = passphraseTypeState.capitalize,
onPassphraseCapitalizeToggleChange =
passphraseHandlers.onPassphraseCapitalizeToggleChange,
onPassphraseCapitalizeToggleChange = passphraseHandlers
.onPassphraseCapitalizeToggleChange,
enabled = passphraseTypeState.capitalizeEnabled,
)
PassphraseIncludeNumberToggleItem(
includeNumber = passphraseTypeState.includeNumber,
onPassphraseIncludeNumberToggleChange =
passphraseHandlers.onPassphraseIncludeNumberToggleChange,
onPassphraseIncludeNumberToggleChange = passphraseHandlers
.onPassphraseIncludeNumberToggleChange,
enabled = passphraseTypeState.includeNumberEnabled,
)
}
@ -703,6 +710,7 @@ private fun ColumnScope.PassphraseTypeContent(
private fun PassphraseNumWordsCounterItem(
numWords: Int,
onPassphraseNumWordsCounterChange: (Int) -> Unit,
modifier: Modifier = Modifier,
minValue: Int = PASSPHRASE_MIN_NUMBER_OF_WORDS,
maxValue: Int = PASSPHRASE_MAX_NUMBER_OF_WORDS,
) {
@ -714,7 +722,7 @@ private fun PassphraseNumWordsCounterItem(
range = minValue..maxValue,
onValueChange = onPassphraseNumWordsCounterChange,
stepperActionsTestTag = "NumberOfWordsStepper",
modifier = Modifier
modifier = modifier
.testTag("NumberOfWordsLabel")
.padding(horizontal = 16.dp),
)
@ -724,6 +732,7 @@ private fun PassphraseNumWordsCounterItem(
private fun PassphraseWordSeparatorInputItem(
wordSeparator: Char?,
onPassphraseWordSeparatorChange: (wordSeparator: Char?) -> Unit,
modifier: Modifier = Modifier,
) {
BitwardenTextField(
label = stringResource(id = R.string.word_separator),
@ -737,7 +746,7 @@ private fun PassphraseWordSeparatorInputItem(
onPassphraseWordSeparatorChange(char)
}
},
modifier = Modifier
modifier = modifier
.testTag("WordSeparatorEntry")
.fillMaxWidth()
.padding(horizontal = 16.dp),
@ -748,6 +757,7 @@ private fun PassphraseWordSeparatorInputItem(
private fun PassphraseCapitalizeToggleItem(
capitalize: Boolean,
onPassphraseCapitalizeToggleChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
) {
BitwardenSwitch(
@ -755,7 +765,7 @@ private fun PassphraseCapitalizeToggleItem(
isChecked = capitalize,
onCheckedChange = onPassphraseCapitalizeToggleChange,
enabled = enabled,
modifier = Modifier
modifier = modifier
.testTag("CapitalizePassphraseToggle")
.fillMaxWidth()
.padding(horizontal = 16.dp),
@ -767,13 +777,14 @@ private fun PassphraseIncludeNumberToggleItem(
includeNumber: Boolean,
onPassphraseIncludeNumberToggleChange: (Boolean) -> Unit,
enabled: Boolean,
modifier: Modifier = Modifier,
) {
BitwardenSwitch(
label = stringResource(id = R.string.include_number),
isChecked = includeNumber,
enabled = enabled,
onCheckedChange = onPassphraseIncludeNumberToggleChange,
modifier = Modifier
modifier = modifier
.testTag("IncludeNumbersToggle")
.fillMaxWidth()
.padding(horizontal = 16.dp),
@ -832,6 +843,7 @@ private fun UsernameOptionsItem(
currentSubState: GeneratorState.MainType.Username,
onSubStateOptionClicked: (GeneratorState.MainType.Username.UsernameTypeOption) -> Unit,
usernameTypeHandlers: UsernameTypeHandlers,
modifier: Modifier = Modifier,
) {
val possibleSubStates = GeneratorState.MainType.Username.UsernameTypeOption.entries
val optionsWithStrings = possibleSubStates.associateWith { stringResource(id = it.labelRes) }
@ -845,10 +857,6 @@ private fun UsernameOptionsItem(
optionsWithStrings.entries.first { it.value == selectedOption }.key
onSubStateOptionClicked(selectedOptionId)
},
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth()
.testTag("UsernameTypePicker"),
supportingText = currentSubState.selectedType.supportingStringResId?.let {
stringResource(id = it)
},
@ -856,6 +864,10 @@ private fun UsernameOptionsItem(
onClick = usernameTypeHandlers.onUsernameTooltipClicked,
contentDescription = stringResource(id = R.string.learn_more),
),
modifier = modifier
.padding(horizontal = 16.dp)
.fillMaxWidth()
.testTag("UsernameTypePicker"),
)
}
@ -1002,6 +1014,7 @@ private fun ColumnScope.ForwardedEmailAliasTypeContent(
private fun ServiceTypeOptionsItem(
currentSubState: GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias,
onSubStateOptionClicked: (ServiceTypeOption) -> Unit,
modifier: Modifier = Modifier,
) {
val possibleSubStates = ServiceTypeOption.entries
val optionsWithStrings = possibleSubStates.associateWith { stringResource(id = it.labelRes) }
@ -1017,7 +1030,7 @@ private fun ServiceTypeOptionsItem(
optionsWithStrings.entries.first { it.value == selectedOption }.key
onSubStateOptionClicked(selectedOptionId)
},
modifier = Modifier
modifier = modifier
.padding(horizontal = 16.dp)
.testTag("ServiceTypePicker")
.fillMaxWidth(),
@ -1043,14 +1056,13 @@ private fun ColumnScope.PlusAddressedEmailTypeContent(
private fun PlusAddressedEmailTextInputItem(
email: String,
onPlusAddressedEmailTextChange: (email: String) -> Unit,
modifier: Modifier = Modifier,
) {
BitwardenTextField(
label = stringResource(id = R.string.email_required_parenthesis),
value = email,
onValueChange = {
onPlusAddressedEmailTextChange(it)
},
modifier = Modifier
onValueChange = onPlusAddressedEmailTextChange,
modifier = modifier
.fillMaxWidth()
.testTag("PlusAddressedEmailEntry")
.padding(horizontal = 16.dp),
@ -1078,14 +1090,13 @@ private fun ColumnScope.CatchAllEmailTypeContent(
private fun CatchAllEmailTextInputItem(
domain: String,
onDomainTextChange: (domain: String) -> Unit,
modifier: Modifier = Modifier,
) {
BitwardenTextField(
label = stringResource(id = R.string.domain_name_required_parenthesis),
value = domain,
onValueChange = {
onDomainTextChange(it)
},
modifier = Modifier
onValueChange = onDomainTextChange,
modifier = modifier
.fillMaxWidth()
.testTag("CatchAllEmailDomainEntry")
.padding(horizontal = 16.dp),
@ -1118,12 +1129,13 @@ private fun ColumnScope.RandomWordTypeContent(
private fun RandomWordCapitalizeToggleItem(
capitalize: Boolean,
onRandomWordCapitalizeToggleChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
) {
BitwardenSwitch(
label = stringResource(id = R.string.capitalize),
isChecked = capitalize,
onCheckedChange = onRandomWordCapitalizeToggleChange,
modifier = Modifier
modifier = modifier
.fillMaxWidth()
.testTag("CapitalizeRandomWordUsernameToggle")
.padding(horizontal = 16.dp),
@ -1134,12 +1146,13 @@ private fun RandomWordCapitalizeToggleItem(
private fun RandomWordIncludeNumberToggleItem(
includeNumber: Boolean,
onRandomWordIncludeNumberToggleChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
) {
BitwardenSwitch(
label = stringResource(id = R.string.include_number),
isChecked = includeNumber,
onCheckedChange = onRandomWordIncludeNumberToggleChange,
modifier = Modifier
modifier = modifier
.fillMaxWidth()
.testTag("IncludeNumberRandomWordUsernameToggle")
.padding(horizontal = 16.dp),
@ -1150,7 +1163,7 @@ private fun RandomWordIncludeNumberToggleItem(
@Preview(showBackground = true)
@Composable
private fun GeneratorPreview() {
private fun Generator_preview() {
BitwardenTheme {
GeneratorScreen(
onNavigateToPasswordHistory = {},
@ -1158,404 +1171,3 @@ private fun GeneratorPreview() {
)
}
}
/**
* A class dedicated to handling user interactions related to password configuration.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
@Suppress("LongParameterList")
private data class PasswordHandlers(
val onPasswordSliderLengthChange: (Int, Boolean) -> Unit,
val onPasswordToggleCapitalLettersChange: (Boolean) -> Unit,
val onPasswordToggleLowercaseLettersChange: (Boolean) -> Unit,
val onPasswordToggleNumbersChange: (Boolean) -> Unit,
val onPasswordToggleSpecialCharactersChange: (Boolean) -> Unit,
val onPasswordMinNumbersCounterChange: (Int) -> Unit,
val onPasswordMinSpecialCharactersChange: (Int) -> Unit,
val onPasswordToggleAvoidAmbiguousCharsChange: (Boolean) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
@Suppress("LongMethod")
fun create(viewModel: GeneratorViewModel): PasswordHandlers {
return PasswordHandlers(
onPasswordSliderLengthChange = { newLength, isUserInteracting ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.SliderLengthChange(
length = newLength,
isUserInteracting = isUserInteracting,
),
)
},
onPasswordToggleCapitalLettersChange = { shouldUseCapitals ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.ToggleCapitalLettersChange(
useCapitals = shouldUseCapitals,
),
)
},
onPasswordToggleLowercaseLettersChange = { shouldUseLowercase ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.ToggleLowercaseLettersChange(
useLowercase = shouldUseLowercase,
),
)
},
onPasswordToggleNumbersChange = { shouldUseNumbers ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.ToggleNumbersChange(
useNumbers = shouldUseNumbers,
),
)
},
onPasswordToggleSpecialCharactersChange = { shouldUseSpecialChars ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.ToggleSpecialCharactersChange(
useSpecialChars = shouldUseSpecialChars,
),
)
},
onPasswordMinNumbersCounterChange = { newMinNumbers ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.MinNumbersCounterChange(
minNumbers = newMinNumbers,
),
)
},
onPasswordMinSpecialCharactersChange = { newMinSpecial ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.MinSpecialCharactersChange(
minSpecial = newMinSpecial,
),
)
},
onPasswordToggleAvoidAmbiguousCharsChange = { shouldAvoidAmbiguousChars ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.ToggleAvoidAmbigousCharactersChange(
avoidAmbiguousChars = shouldAvoidAmbiguousChars,
),
)
},
)
}
}
}
/**
* A class dedicated to handling user interactions related to passphrase configuration.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
private data class PassphraseHandlers(
val onPassphraseNumWordsCounterChange: (Int) -> Unit,
val onPassphraseWordSeparatorChange: (Char?) -> Unit,
val onPassphraseCapitalizeToggleChange: (Boolean) -> Unit,
val onPassphraseIncludeNumberToggleChange: (Boolean) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
fun create(viewModel: GeneratorViewModel): PassphraseHandlers {
return PassphraseHandlers(
onPassphraseNumWordsCounterChange = { changeInCounter ->
viewModel.trySendAction(
GeneratorAction.MainType.Passphrase.NumWordsCounterChange(
numWords = changeInCounter,
),
)
},
onPassphraseWordSeparatorChange = { newSeparator ->
viewModel.trySendAction(
GeneratorAction.MainType.Passphrase.WordSeparatorTextChange(
wordSeparator = newSeparator,
),
)
},
onPassphraseCapitalizeToggleChange = { shouldCapitalize ->
viewModel.trySendAction(
GeneratorAction.MainType.Passphrase.ToggleCapitalizeChange(
capitalize = shouldCapitalize,
),
)
},
onPassphraseIncludeNumberToggleChange = { shouldIncludeNumber ->
viewModel.trySendAction(
GeneratorAction.MainType.Passphrase.ToggleIncludeNumberChange(
includeNumber = shouldIncludeNumber,
),
)
},
)
}
}
}
/**
* A class dedicated to handling user interactions related to all username configurations.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
@Suppress("LongParameterList")
private data class UsernameTypeHandlers(
val onUsernameTooltipClicked: () -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
fun create(viewModel: GeneratorViewModel): UsernameTypeHandlers {
return UsernameTypeHandlers(
onUsernameTooltipClicked = {
viewModel.trySendAction(
GeneratorAction.MainType.Username.UsernameType.TooltipClick,
)
},
)
}
}
}
/**
* A class dedicated to handling user interactions related to forwarded email alias
* configuration.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
@Suppress("LongParameterList")
private data class ForwardedEmailAliasHandlers(
val onServiceChange: (ServiceTypeOption) -> Unit,
val onAddyIoAccessTokenTextChange: (String) -> Unit,
val onAddyIoDomainNameTextChange: (String) -> Unit,
val onDuckDuckGoApiKeyTextChange: (String) -> Unit,
val onFastMailApiKeyTextChange: (String) -> Unit,
val onFirefoxRelayAccessTokenTextChange: (String) -> Unit,
val onForwardEmailApiKeyTextChange: (String) -> Unit,
val onForwardEmailDomainNameTextChange: (String) -> Unit,
val onSimpleLoginApiKeyTextChange: (String) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
@Suppress("LongMethod")
fun create(viewModel: GeneratorViewModel): ForwardedEmailAliasHandlers {
return ForwardedEmailAliasHandlers(
onServiceChange = { newServiceTypeOption ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.ServiceTypeOptionSelect(
serviceTypeOption = newServiceTypeOption,
),
)
},
onAddyIoAccessTokenTextChange = { newAccessToken ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.AddyIo
.AccessTokenTextChange(
accessToken = newAccessToken,
),
)
},
onAddyIoDomainNameTextChange = { newDomainName ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.AddyIo
.DomainTextChange(
domain = newDomainName,
),
)
},
onDuckDuckGoApiKeyTextChange = { newApiKey ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.DuckDuckGo
.ApiKeyTextChange(
apiKey = newApiKey,
),
)
},
onFastMailApiKeyTextChange = { newApiKey ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.FastMail
.ApiKeyTextChange(
apiKey = newApiKey,
),
)
},
onFirefoxRelayAccessTokenTextChange = { newAccessToken ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.FirefoxRelay
.AccessTokenTextChange(
accessToken = newAccessToken,
),
)
},
onForwardEmailApiKeyTextChange = { newApiKey ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.ForwardEmail
.ApiKeyTextChange(
apiKey = newApiKey,
),
)
},
onForwardEmailDomainNameTextChange = { newDomainName ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.ForwardEmail
.DomainNameTextChange(
domainName = newDomainName,
),
)
},
onSimpleLoginApiKeyTextChange = { newApiKey ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.ForwardedEmailAlias
.SimpleLogin
.ApiKeyTextChange(
apiKey = newApiKey,
),
)
},
)
}
}
}
/**
* A class dedicated to handling user interactions related to plus addressed email
* configuration.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
private data class PlusAddressedEmailHandlers(
val onEmailChange: (String) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
fun create(viewModel: GeneratorViewModel): PlusAddressedEmailHandlers {
return PlusAddressedEmailHandlers(
onEmailChange = { newEmail ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.PlusAddressedEmail
.EmailTextChange(
email = newEmail,
),
)
},
)
}
}
}
/**
* A class dedicated to handling user interactions related to plus addressed email
* configuration.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
private data class CatchAllEmailHandlers(
val onDomainChange: (String) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
fun create(viewModel: GeneratorViewModel): CatchAllEmailHandlers {
return CatchAllEmailHandlers(
onDomainChange = { newDomain ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.CatchAllEmail
.DomainTextChange(
domain = newDomain,
),
)
},
)
}
}
}
/**
* A class dedicated to handling user interactions related to Random Word
* configuration.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
private data class RandomWordHandlers(
val onCapitalizeChange: (Boolean) -> Unit,
val onIncludeNumberChange: (Boolean) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
fun create(viewModel: GeneratorViewModel): RandomWordHandlers {
return RandomWordHandlers(
onCapitalizeChange = { shouldCapitalize ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.RandomWord
.ToggleCapitalizeChange(
capitalize = shouldCapitalize,
),
)
},
onIncludeNumberChange = { shouldIncludeNumber ->
viewModel.trySendAction(
GeneratorAction
.MainType
.Username
.UsernameType
.RandomWord
.ToggleIncludeNumberChange(
includeNumber = shouldIncludeNumber,
),
)
},
)
}
}
}

View file

@ -0,0 +1,40 @@
package com.x8bit.bitwarden.ui.tools.feature.generator.handlers
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorViewModel
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorAction.MainType.Username.UsernameType.CatchAllEmail as CatchAllEmailAction
/**
* A class dedicated to handling user interactions related to plus addressed email
* configuration.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
data class CatchAllEmailHandlers(
val onDomainChange: (String) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
/**
* Creates an instance of [CatchAllEmailHandlers] by binding actions to the provided
* [GeneratorViewModel].
*/
fun create(
viewModel: GeneratorViewModel,
): CatchAllEmailHandlers = CatchAllEmailHandlers(
onDomainChange = { newDomain ->
viewModel.trySendAction(CatchAllEmailAction.DomainTextChange(domain = newDomain))
},
)
}
}
/**
* Helper function to remember a [CatchAllEmailHandlers] instance in a [Composable] scope.
*/
@Composable
fun rememberCatchAllEmailHandlers(viewModel: GeneratorViewModel): CatchAllEmailHandlers =
remember(viewModel) {
CatchAllEmailHandlers.create(viewModel = viewModel)
}

View file

@ -0,0 +1,102 @@
package com.x8bit.bitwarden.ui.tools.feature.generator.handlers
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorViewModel
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorAction.MainType.Username.UsernameType.ForwardedEmailAlias as ForwardedEmailAliasAction
/**
* A class dedicated to handling user interactions related to forwarded email alias
* configuration.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
@Suppress("LongParameterList")
data class ForwardedEmailAliasHandlers(
val onServiceChange: (ForwardedEmailAlias.ServiceTypeOption) -> Unit,
val onAddyIoAccessTokenTextChange: (String) -> Unit,
val onAddyIoDomainNameTextChange: (String) -> Unit,
val onDuckDuckGoApiKeyTextChange: (String) -> Unit,
val onFastMailApiKeyTextChange: (String) -> Unit,
val onFirefoxRelayAccessTokenTextChange: (String) -> Unit,
val onForwardEmailApiKeyTextChange: (String) -> Unit,
val onForwardEmailDomainNameTextChange: (String) -> Unit,
val onSimpleLoginApiKeyTextChange: (String) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
/**
* Creates an instance of [ForwardedEmailAliasHandlers] by binding actions to the provided
* [GeneratorViewModel].
*/
fun create(
viewModel: GeneratorViewModel,
): ForwardedEmailAliasHandlers = ForwardedEmailAliasHandlers(
onServiceChange = { newServiceTypeOption ->
viewModel.trySendAction(
ForwardedEmailAliasAction.ServiceTypeOptionSelect(
serviceTypeOption = newServiceTypeOption,
),
)
},
onAddyIoAccessTokenTextChange = { newAccessToken ->
viewModel.trySendAction(
ForwardedEmailAliasAction.AddyIo.AccessTokenTextChange(
accessToken = newAccessToken,
),
)
},
onAddyIoDomainNameTextChange = { newDomainName ->
viewModel.trySendAction(
ForwardedEmailAliasAction.AddyIo.DomainTextChange(domain = newDomainName),
)
},
onDuckDuckGoApiKeyTextChange = { newApiKey ->
viewModel.trySendAction(
ForwardedEmailAliasAction.DuckDuckGo.ApiKeyTextChange(apiKey = newApiKey),
)
},
onFastMailApiKeyTextChange = { newApiKey ->
viewModel.trySendAction(
ForwardedEmailAliasAction.FastMail.ApiKeyTextChange(apiKey = newApiKey),
)
},
onFirefoxRelayAccessTokenTextChange = { newAccessToken ->
viewModel.trySendAction(
ForwardedEmailAliasAction.FirefoxRelay.AccessTokenTextChange(
accessToken = newAccessToken,
),
)
},
onForwardEmailApiKeyTextChange = { newApiKey ->
viewModel.trySendAction(
ForwardedEmailAliasAction.ForwardEmail.ApiKeyTextChange(apiKey = newApiKey),
)
},
onForwardEmailDomainNameTextChange = { newDomainName ->
viewModel.trySendAction(
ForwardedEmailAliasAction.ForwardEmail.DomainNameTextChange(
domainName = newDomainName,
),
)
},
onSimpleLoginApiKeyTextChange = { newApiKey ->
viewModel.trySendAction(
ForwardedEmailAliasAction.SimpleLogin.ApiKeyTextChange(apiKey = newApiKey),
)
},
)
}
}
/**
* Helper function to remember a [ForwardedEmailAliasHandlers] instance in a [Composable] scope.
*/
@Composable
fun rememberForwardedEmailAliasHandlers(
viewModel: GeneratorViewModel,
): ForwardedEmailAliasHandlers =
remember(viewModel) {
ForwardedEmailAliasHandlers.create(viewModel = viewModel)
}

View file

@ -0,0 +1,67 @@
package com.x8bit.bitwarden.ui.tools.feature.generator.handlers
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorAction
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorViewModel
/**
* A class dedicated to handling user interactions related to passphrase configuration.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
data class PassphraseHandlers(
val onPassphraseNumWordsCounterChange: (Int) -> Unit,
val onPassphraseWordSeparatorChange: (Char?) -> Unit,
val onPassphraseCapitalizeToggleChange: (Boolean) -> Unit,
val onPassphraseIncludeNumberToggleChange: (Boolean) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
/**
* Creates an instance of [PassphraseHandlers] by binding actions to the provided
* [GeneratorViewModel].
*/
fun create(
viewModel: GeneratorViewModel,
): PassphraseHandlers = PassphraseHandlers(
onPassphraseNumWordsCounterChange = { changeInCounter ->
viewModel.trySendAction(
GeneratorAction.MainType.Passphrase.NumWordsCounterChange(
numWords = changeInCounter,
),
)
},
onPassphraseWordSeparatorChange = { newSeparator ->
viewModel.trySendAction(
GeneratorAction.MainType.Passphrase.WordSeparatorTextChange(
wordSeparator = newSeparator,
),
)
},
onPassphraseCapitalizeToggleChange = { shouldCapitalize ->
viewModel.trySendAction(
GeneratorAction.MainType.Passphrase.ToggleCapitalizeChange(
capitalize = shouldCapitalize,
),
)
},
onPassphraseIncludeNumberToggleChange = { shouldIncludeNumber ->
viewModel.trySendAction(
GeneratorAction.MainType.Passphrase.ToggleIncludeNumberChange(
includeNumber = shouldIncludeNumber,
),
)
},
)
}
}
/**
* Helper function to remember a [PassphraseHandlers] instance in a [Composable] scope.
*/
@Composable
fun rememberPassphraseHandlers(viewModel: GeneratorViewModel): PassphraseHandlers =
remember(viewModel) {
PassphraseHandlers.create(viewModel = viewModel)
}

View file

@ -0,0 +1,101 @@
package com.x8bit.bitwarden.ui.tools.feature.generator.handlers
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorAction
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorViewModel
/**
* A class dedicated to handling user interactions related to password configuration.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
@Suppress("LongParameterList")
data class PasswordHandlers(
val onPasswordSliderLengthChange: (Int, Boolean) -> Unit,
val onPasswordToggleCapitalLettersChange: (Boolean) -> Unit,
val onPasswordToggleLowercaseLettersChange: (Boolean) -> Unit,
val onPasswordToggleNumbersChange: (Boolean) -> Unit,
val onPasswordToggleSpecialCharactersChange: (Boolean) -> Unit,
val onPasswordMinNumbersCounterChange: (Int) -> Unit,
val onPasswordMinSpecialCharactersChange: (Int) -> Unit,
val onPasswordToggleAvoidAmbiguousCharsChange: (Boolean) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
/**
* Creates an instance of [PasswordHandlers] by binding actions to the provided
* [GeneratorViewModel].
*/
fun create(
viewModel: GeneratorViewModel,
): PasswordHandlers = PasswordHandlers(
onPasswordSliderLengthChange = { newLength, isUserInteracting ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.SliderLengthChange(
length = newLength,
isUserInteracting = isUserInteracting,
),
)
},
onPasswordToggleCapitalLettersChange = { shouldUseCapitals ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.ToggleCapitalLettersChange(
useCapitals = shouldUseCapitals,
),
)
},
onPasswordToggleLowercaseLettersChange = { shouldUseLowercase ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.ToggleLowercaseLettersChange(
useLowercase = shouldUseLowercase,
),
)
},
onPasswordToggleNumbersChange = { shouldUseNumbers ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.ToggleNumbersChange(
useNumbers = shouldUseNumbers,
),
)
},
onPasswordToggleSpecialCharactersChange = { shouldUseSpecialChars ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.ToggleSpecialCharactersChange(
useSpecialChars = shouldUseSpecialChars,
),
)
},
onPasswordMinNumbersCounterChange = { newMinNumbers ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.MinNumbersCounterChange(
minNumbers = newMinNumbers,
),
)
},
onPasswordMinSpecialCharactersChange = { newMinSpecial ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.MinSpecialCharactersChange(
minSpecial = newMinSpecial,
),
)
},
onPasswordToggleAvoidAmbiguousCharsChange = { shouldAvoidAmbiguousChars ->
viewModel.trySendAction(
GeneratorAction.MainType.Password.ToggleAvoidAmbigousCharactersChange(
avoidAmbiguousChars = shouldAvoidAmbiguousChars,
),
)
},
)
}
}
/**
* Helper function to remember a [PasswordHandlers] instance in a [Composable] scope.
*/
@Composable
fun rememberPasswordHandlers(viewModel: GeneratorViewModel): PasswordHandlers =
remember(viewModel) {
PasswordHandlers.create(viewModel = viewModel)
}

View file

@ -0,0 +1,41 @@
package com.x8bit.bitwarden.ui.tools.feature.generator.handlers
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorViewModel
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorAction.MainType.Username.UsernameType.PlusAddressedEmail as PlusAddressedEmailAction
/**
* A class dedicated to handling user interactions related to plus addressed email
* configuration.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
data class PlusAddressedEmailHandlers(
val onEmailChange: (String) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
/**
* Creates an instance of [PlusAddressedEmailHandlers] by binding actions to the provided
* [GeneratorViewModel].
*/
fun create(viewModel: GeneratorViewModel): PlusAddressedEmailHandlers =
PlusAddressedEmailHandlers(
onEmailChange = { newEmail ->
viewModel.trySendAction(
PlusAddressedEmailAction.EmailTextChange(email = newEmail),
)
},
)
}
}
/**
* Helper function to remember a [PlusAddressedEmailHandlers] instance in a [Composable] scope.
*/
@Composable
fun rememberPlusAddressedEmailHandlers(viewModel: GeneratorViewModel): PlusAddressedEmailHandlers =
remember(viewModel) {
PlusAddressedEmailHandlers.create(viewModel = viewModel)
}

View file

@ -0,0 +1,48 @@
package com.x8bit.bitwarden.ui.tools.feature.generator.handlers
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorViewModel
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorAction.MainType.Username.UsernameType.RandomWord as RandomWordAction
/**
* A class dedicated to handling user interactions related to Random Word
* configuration.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
data class RandomWordHandlers(
val onCapitalizeChange: (Boolean) -> Unit,
val onIncludeNumberChange: (Boolean) -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
/**
* Creates an instance of [RandomWordHandlers] by binding actions to the provided
* [GeneratorViewModel].
*/
fun create(
viewModel: GeneratorViewModel,
): RandomWordHandlers = RandomWordHandlers(
onCapitalizeChange = { shouldCapitalize ->
viewModel.trySendAction(
RandomWordAction.ToggleCapitalizeChange(capitalize = shouldCapitalize),
)
},
onIncludeNumberChange = { shouldIncludeNumber ->
viewModel.trySendAction(
RandomWordAction.ToggleIncludeNumberChange(includeNumber = shouldIncludeNumber),
)
},
)
}
}
/**
* Helper function to remember a [RandomWordHandlers] instance in a [Composable] scope.
*/
@Composable
fun rememberRandomWordHandlers(viewModel: GeneratorViewModel): RandomWordHandlers =
remember(viewModel) {
RandomWordHandlers.create(viewModel = viewModel)
}

View file

@ -0,0 +1,40 @@
package com.x8bit.bitwarden.ui.tools.feature.generator.handlers
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorAction
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorViewModel
/**
* A class dedicated to handling user interactions related to all username configurations.
* Each lambda corresponds to a specific user action, allowing for easy delegation of
* logic when user input is detected.
*/
@Suppress("LongParameterList")
data class UsernameTypeHandlers(
val onUsernameTooltipClicked: () -> Unit,
) {
@Suppress("UndocumentedPublicClass")
companion object {
/**
* Creates an instance of [UsernameTypeHandlers] by binding actions to the provided
* [GeneratorViewModel].
*/
fun create(
viewModel: GeneratorViewModel,
): UsernameTypeHandlers = UsernameTypeHandlers(
onUsernameTooltipClicked = {
viewModel.trySendAction(GeneratorAction.MainType.Username.UsernameType.TooltipClick)
},
)
}
}
/**
* Helper function to remember a [UsernameTypeHandlers] instance in a [Composable] scope.
*/
@Composable
fun rememberUsernameTypeHandlers(viewModel: GeneratorViewModel): UsernameTypeHandlers =
remember(viewModel) {
UsernameTypeHandlers.create(viewModel = viewModel)
}