diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorScreen.kt index 6166f50a9..84c1ea694 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/GeneratorScreen.kt @@ -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, - ), - ) - }, - ) - } - } -} diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/CatchAllEmailHandlers.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/CatchAllEmailHandlers.kt new file mode 100644 index 000000000..cc99b75e0 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/CatchAllEmailHandlers.kt @@ -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) + } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/ForwardedEmailAliasHandlers.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/ForwardedEmailAliasHandlers.kt new file mode 100644 index 000000000..916b467d5 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/ForwardedEmailAliasHandlers.kt @@ -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) + } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/PassphraseHandlers.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/PassphraseHandlers.kt new file mode 100644 index 000000000..90a99bf28 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/PassphraseHandlers.kt @@ -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) + } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/PasswordHandlers.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/PasswordHandlers.kt new file mode 100644 index 000000000..83c761f8f --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/PasswordHandlers.kt @@ -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) + } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/PlusAddressedEmailHandlers.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/PlusAddressedEmailHandlers.kt new file mode 100644 index 000000000..009928082 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/PlusAddressedEmailHandlers.kt @@ -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) + } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/RandomWordHandlers.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/RandomWordHandlers.kt new file mode 100644 index 000000000..a90ff6925 --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/RandomWordHandlers.kt @@ -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) + } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/UsernameTypeHandlers.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/UsernameTypeHandlers.kt new file mode 100644 index 000000000..485937e4d --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/generator/handlers/UsernameTypeHandlers.kt @@ -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) + }