mirror of
https://github.com/bitwarden/android.git
synced 2024-11-21 17:05:44 +03:00
Clean up the generator screen and handlers (#4270)
This commit is contained in:
parent
6dd783051f
commit
16cc70f344
8 changed files with 535 additions and 484 deletions
|
@ -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.Passphrase.Companion.PASSPHRASE_MIN_NUMBER_OF_WORDS
|
||||||
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias.ServiceType
|
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias.ServiceType
|
||||||
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias.ServiceTypeOption
|
import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias.ServiceTypeOption
|
||||||
|
import com.x8bit.bitwarden.ui.tools.feature.generator.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 com.x8bit.bitwarden.ui.tools.feature.generator.model.GeneratorMode
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
@ -135,47 +149,26 @@ fun GeneratorScreen(
|
||||||
remember(viewModel) {
|
remember(viewModel) {
|
||||||
{
|
{
|
||||||
viewModel.trySendAction(
|
viewModel.trySendAction(
|
||||||
GeneratorAction.MainType.Username.UsernameTypeOptionSelect(
|
GeneratorAction.MainType.Username.UsernameTypeOptionSelect(it),
|
||||||
it,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val passwordHandlers = remember(viewModel) {
|
val passwordHandlers = rememberPasswordHandlers(viewModel)
|
||||||
PasswordHandlers.create(viewModel = viewModel)
|
val passphraseHandlers = rememberPassphraseHandlers(viewModel)
|
||||||
}
|
val usernameTypeHandlers = rememberUsernameTypeHandlers(viewModel)
|
||||||
|
val forwardedEmailAliasHandlers = rememberForwardedEmailAliasHandlers(viewModel)
|
||||||
val passphraseHandlers = remember(viewModel) {
|
val plusAddressedEmailHandlers = rememberPlusAddressedEmailHandlers(viewModel)
|
||||||
PassphraseHandlers.create(viewModel = viewModel)
|
val catchAllEmailHandlers = rememberCatchAllEmailHandlers(viewModel)
|
||||||
}
|
val randomWordHandlers = rememberRandomWordHandlers(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 scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||||
BitwardenScaffold(
|
BitwardenScaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
when (state.generatorMode) {
|
when (val generatorMode = state.generatorMode) {
|
||||||
is GeneratorMode.Modal -> {
|
is GeneratorMode.Modal -> {
|
||||||
ModalAppBar(
|
ModalAppBar(
|
||||||
|
generatorMode = generatorMode,
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
onCloseClick = remember(viewModel) {
|
onCloseClick = remember(viewModel) {
|
||||||
{ viewModel.trySendAction(GeneratorAction.CloseClick) }
|
{ viewModel.trySendAction(GeneratorAction.CloseClick) }
|
||||||
|
@ -234,6 +227,7 @@ fun GeneratorScreen(
|
||||||
private fun DefaultAppBar(
|
private fun DefaultAppBar(
|
||||||
scrollBehavior: TopAppBarScrollBehavior,
|
scrollBehavior: TopAppBarScrollBehavior,
|
||||||
onPasswordHistoryClick: () -> Unit,
|
onPasswordHistoryClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
BitwardenMediumTopAppBar(
|
BitwardenMediumTopAppBar(
|
||||||
title = stringResource(id = R.string.generator),
|
title = stringResource(id = R.string.generator),
|
||||||
|
@ -249,15 +243,18 @@ private fun DefaultAppBar(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun ModalAppBar(
|
private fun ModalAppBar(
|
||||||
|
generatorMode: GeneratorMode.Modal,
|
||||||
scrollBehavior: TopAppBarScrollBehavior,
|
scrollBehavior: TopAppBarScrollBehavior,
|
||||||
onCloseClick: () -> Unit,
|
onCloseClick: () -> Unit,
|
||||||
onSelectClick: () -> Unit,
|
onSelectClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
BitwardenTopAppBar(
|
BitwardenTopAppBar(
|
||||||
title = stringResource(id = R.string.generator),
|
title = stringResource(id = R.string.generator),
|
||||||
|
@ -265,6 +262,10 @@ private fun ModalAppBar(
|
||||||
navigationIconContentDescription = stringResource(id = R.string.close),
|
navigationIconContentDescription = stringResource(id = R.string.close),
|
||||||
onNavigationIconClick = onCloseClick,
|
onNavigationIconClick = onCloseClick,
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
|
dividerStyle = when (generatorMode) {
|
||||||
|
GeneratorMode.Modal.Password -> TopAppBarDividerStyle.NONE
|
||||||
|
is GeneratorMode.Modal.Username -> TopAppBarDividerStyle.ON_SCROLL
|
||||||
|
},
|
||||||
actions = {
|
actions = {
|
||||||
BitwardenTextButton(
|
BitwardenTextButton(
|
||||||
label = stringResource(id = R.string.select),
|
label = stringResource(id = R.string.select),
|
||||||
|
@ -272,6 +273,7 @@ private fun ModalAppBar(
|
||||||
modifier = Modifier.testTag("SelectButton"),
|
modifier = Modifier.testTag("SelectButton"),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,6 +367,7 @@ private fun GeneratedStringItem(
|
||||||
generatedText: String,
|
generatedText: String,
|
||||||
onCopyClick: () -> Unit,
|
onCopyClick: () -> Unit,
|
||||||
onRegenerateClick: () -> Unit,
|
onRegenerateClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
BitwardenTextFieldWithActions(
|
BitwardenTextFieldWithActions(
|
||||||
label = "",
|
label = "",
|
||||||
|
@ -390,7 +393,7 @@ private fun GeneratedStringItem(
|
||||||
textStyle = BitwardenTheme.typography.sensitiveInfoSmall,
|
textStyle = BitwardenTheme.typography.sensitiveInfoSmall,
|
||||||
shouldAddCustomLineBreaks = true,
|
shouldAddCustomLineBreaks = true,
|
||||||
visualTransformation = nonLetterColorVisualTransformation(),
|
visualTransformation = nonLetterColorVisualTransformation(),
|
||||||
modifier = Modifier.padding(horizontal = 16.dp),
|
modifier = modifier.padding(horizontal = 16.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,26 +472,25 @@ private fun ColumnScope.PasswordTypeContent(
|
||||||
|
|
||||||
PasswordCapitalLettersToggleItem(
|
PasswordCapitalLettersToggleItem(
|
||||||
useCapitals = passwordTypeState.useCapitals,
|
useCapitals = passwordTypeState.useCapitals,
|
||||||
onPasswordToggleCapitalLettersChange =
|
onPasswordToggleCapitalLettersChange = passwordHandlers
|
||||||
passwordHandlers.onPasswordToggleCapitalLettersChange,
|
.onPasswordToggleCapitalLettersChange,
|
||||||
enabled = passwordTypeState.capitalsEnabled,
|
enabled = passwordTypeState.capitalsEnabled,
|
||||||
)
|
)
|
||||||
PasswordLowercaseLettersToggleItem(
|
PasswordLowercaseLettersToggleItem(
|
||||||
useLowercase = passwordTypeState.useLowercase,
|
useLowercase = passwordTypeState.useLowercase,
|
||||||
onPasswordToggleLowercaseLettersChange =
|
onPasswordToggleLowercaseLettersChange = passwordHandlers
|
||||||
passwordHandlers.onPasswordToggleLowercaseLettersChange,
|
.onPasswordToggleLowercaseLettersChange,
|
||||||
enabled = passwordTypeState.lowercaseEnabled,
|
enabled = passwordTypeState.lowercaseEnabled,
|
||||||
)
|
)
|
||||||
PasswordNumbersToggleItem(
|
PasswordNumbersToggleItem(
|
||||||
useNumbers = passwordTypeState.useNumbers,
|
useNumbers = passwordTypeState.useNumbers,
|
||||||
onPasswordToggleNumbersChange =
|
onPasswordToggleNumbersChange = passwordHandlers.onPasswordToggleNumbersChange,
|
||||||
passwordHandlers.onPasswordToggleNumbersChange,
|
|
||||||
enabled = passwordTypeState.numbersEnabled,
|
enabled = passwordTypeState.numbersEnabled,
|
||||||
)
|
)
|
||||||
PasswordSpecialCharactersToggleItem(
|
PasswordSpecialCharactersToggleItem(
|
||||||
useSpecialChars = passwordTypeState.useSpecialChars,
|
useSpecialChars = passwordTypeState.useSpecialChars,
|
||||||
onPasswordToggleSpecialCharactersChange =
|
onPasswordToggleSpecialCharactersChange = passwordHandlers
|
||||||
passwordHandlers.onPasswordToggleSpecialCharactersChange,
|
.onPasswordToggleSpecialCharactersChange,
|
||||||
enabled = passwordTypeState.specialCharsEnabled,
|
enabled = passwordTypeState.specialCharsEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -497,8 +499,7 @@ private fun ColumnScope.PasswordTypeContent(
|
||||||
|
|
||||||
PasswordMinNumbersCounterItem(
|
PasswordMinNumbersCounterItem(
|
||||||
minNumbers = passwordTypeState.minNumbers,
|
minNumbers = passwordTypeState.minNumbers,
|
||||||
onPasswordMinNumbersCounterChange =
|
onPasswordMinNumbersCounterChange = passwordHandlers.onPasswordMinNumbersCounterChange,
|
||||||
passwordHandlers.onPasswordMinNumbersCounterChange,
|
|
||||||
maxValue = max(passwordTypeState.maxNumbersAllowed, passwordTypeState.minNumbersAllowed),
|
maxValue = max(passwordTypeState.maxNumbersAllowed, passwordTypeState.minNumbersAllowed),
|
||||||
minValue = passwordTypeState.minNumbersAllowed,
|
minValue = passwordTypeState.minNumbersAllowed,
|
||||||
)
|
)
|
||||||
|
@ -507,8 +508,8 @@ private fun ColumnScope.PasswordTypeContent(
|
||||||
|
|
||||||
PasswordMinSpecialCharactersCounterItem(
|
PasswordMinSpecialCharactersCounterItem(
|
||||||
minSpecial = passwordTypeState.minSpecial,
|
minSpecial = passwordTypeState.minSpecial,
|
||||||
onPasswordMinSpecialCharactersChange =
|
onPasswordMinSpecialCharactersChange = passwordHandlers
|
||||||
passwordHandlers.onPasswordMinSpecialCharactersChange,
|
.onPasswordMinSpecialCharactersChange,
|
||||||
maxValue = max(passwordTypeState.maxSpecialAllowed, passwordTypeState.minSpecialAllowed),
|
maxValue = max(passwordTypeState.maxSpecialAllowed, passwordTypeState.minSpecialAllowed),
|
||||||
minValue = passwordTypeState.minSpecialAllowed,
|
minValue = passwordTypeState.minSpecialAllowed,
|
||||||
)
|
)
|
||||||
|
@ -517,8 +518,8 @@ private fun ColumnScope.PasswordTypeContent(
|
||||||
|
|
||||||
PasswordAvoidAmbiguousCharsToggleItem(
|
PasswordAvoidAmbiguousCharsToggleItem(
|
||||||
avoidAmbiguousChars = passwordTypeState.avoidAmbiguousChars,
|
avoidAmbiguousChars = passwordTypeState.avoidAmbiguousChars,
|
||||||
onPasswordToggleAvoidAmbiguousCharsChange =
|
onPasswordToggleAvoidAmbiguousCharsChange = passwordHandlers
|
||||||
passwordHandlers.onPasswordToggleAvoidAmbiguousCharsChange,
|
.onPasswordToggleAvoidAmbiguousCharsChange,
|
||||||
enabled = passwordTypeState.ambiguousCharsEnabled,
|
enabled = passwordTypeState.ambiguousCharsEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -527,18 +528,19 @@ private fun ColumnScope.PasswordTypeContent(
|
||||||
private fun PasswordCapitalLettersToggleItem(
|
private fun PasswordCapitalLettersToggleItem(
|
||||||
useCapitals: Boolean,
|
useCapitals: Boolean,
|
||||||
onPasswordToggleCapitalLettersChange: (Boolean) -> Unit,
|
onPasswordToggleCapitalLettersChange: (Boolean) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
) {
|
) {
|
||||||
BitwardenSwitch(
|
BitwardenSwitch(
|
||||||
label = "A—Z",
|
label = "A—Z",
|
||||||
|
contentDescription = stringResource(id = R.string.uppercase_ato_z),
|
||||||
isChecked = useCapitals,
|
isChecked = useCapitals,
|
||||||
onCheckedChange = onPasswordToggleCapitalLettersChange,
|
onCheckedChange = onPasswordToggleCapitalLettersChange,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.testTag("UppercaseAtoZToggle")
|
.testTag("UppercaseAtoZToggle")
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
contentDescription = stringResource(id = R.string.uppercase_ato_z),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,18 +548,19 @@ private fun PasswordCapitalLettersToggleItem(
|
||||||
private fun PasswordLowercaseLettersToggleItem(
|
private fun PasswordLowercaseLettersToggleItem(
|
||||||
useLowercase: Boolean,
|
useLowercase: Boolean,
|
||||||
onPasswordToggleLowercaseLettersChange: (Boolean) -> Unit,
|
onPasswordToggleLowercaseLettersChange: (Boolean) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
) {
|
) {
|
||||||
BitwardenSwitch(
|
BitwardenSwitch(
|
||||||
label = "a—z",
|
label = "a—z",
|
||||||
|
contentDescription = stringResource(id = R.string.lowercase_ato_z),
|
||||||
isChecked = useLowercase,
|
isChecked = useLowercase,
|
||||||
onCheckedChange = onPasswordToggleLowercaseLettersChange,
|
onCheckedChange = onPasswordToggleLowercaseLettersChange,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.testTag("LowercaseAtoZToggle")
|
.testTag("LowercaseAtoZToggle")
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
contentDescription = stringResource(id = R.string.lowercase_ato_z),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,18 +568,19 @@ private fun PasswordLowercaseLettersToggleItem(
|
||||||
private fun PasswordNumbersToggleItem(
|
private fun PasswordNumbersToggleItem(
|
||||||
useNumbers: Boolean,
|
useNumbers: Boolean,
|
||||||
onPasswordToggleNumbersChange: (Boolean) -> Unit,
|
onPasswordToggleNumbersChange: (Boolean) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
) {
|
) {
|
||||||
BitwardenSwitch(
|
BitwardenSwitch(
|
||||||
label = "0-9",
|
label = "0-9",
|
||||||
|
contentDescription = stringResource(id = R.string.numbers_zero_to_nine),
|
||||||
isChecked = useNumbers,
|
isChecked = useNumbers,
|
||||||
onCheckedChange = onPasswordToggleNumbersChange,
|
onCheckedChange = onPasswordToggleNumbersChange,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.testTag("NumbersZeroToNineToggle")
|
.testTag("NumbersZeroToNineToggle")
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
contentDescription = stringResource(id = R.string.numbers_zero_to_nine),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,18 +588,19 @@ private fun PasswordNumbersToggleItem(
|
||||||
private fun PasswordSpecialCharactersToggleItem(
|
private fun PasswordSpecialCharactersToggleItem(
|
||||||
useSpecialChars: Boolean,
|
useSpecialChars: Boolean,
|
||||||
onPasswordToggleSpecialCharactersChange: (Boolean) -> Unit,
|
onPasswordToggleSpecialCharactersChange: (Boolean) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
) {
|
) {
|
||||||
BitwardenSwitch(
|
BitwardenSwitch(
|
||||||
label = "!@#$%^&*",
|
label = "!@#$%^&*",
|
||||||
|
contentDescription = stringResource(id = R.string.special_characters),
|
||||||
isChecked = useSpecialChars,
|
isChecked = useSpecialChars,
|
||||||
onCheckedChange = onPasswordToggleSpecialCharactersChange,
|
onCheckedChange = onPasswordToggleSpecialCharactersChange,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.testTag("SpecialCharactersToggle")
|
.testTag("SpecialCharactersToggle")
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
contentDescription = stringResource(id = R.string.special_characters),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,13 +610,14 @@ private fun PasswordMinNumbersCounterItem(
|
||||||
onPasswordMinNumbersCounterChange: (Int) -> Unit,
|
onPasswordMinNumbersCounterChange: (Int) -> Unit,
|
||||||
minValue: Int,
|
minValue: Int,
|
||||||
maxValue: Int,
|
maxValue: Int,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
BitwardenStepper(
|
BitwardenStepper(
|
||||||
label = stringResource(id = R.string.min_numbers),
|
label = stringResource(id = R.string.min_numbers),
|
||||||
value = minNumbers.coerceIn(minValue, maxValue),
|
value = minNumbers.coerceIn(minValue, maxValue),
|
||||||
range = minValue..maxValue,
|
range = minValue..maxValue,
|
||||||
onValueChange = onPasswordMinNumbersCounterChange,
|
onValueChange = onPasswordMinNumbersCounterChange,
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.testTag("MinNumberValueLabel")
|
.testTag("MinNumberValueLabel")
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
)
|
)
|
||||||
|
@ -623,13 +629,14 @@ private fun PasswordMinSpecialCharactersCounterItem(
|
||||||
onPasswordMinSpecialCharactersChange: (Int) -> Unit,
|
onPasswordMinSpecialCharactersChange: (Int) -> Unit,
|
||||||
minValue: Int,
|
minValue: Int,
|
||||||
maxValue: Int,
|
maxValue: Int,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
BitwardenStepper(
|
BitwardenStepper(
|
||||||
label = stringResource(id = R.string.min_special),
|
label = stringResource(id = R.string.min_special),
|
||||||
value = minSpecial.coerceIn(minValue, maxValue),
|
value = minSpecial.coerceIn(minValue, maxValue),
|
||||||
range = minValue..maxValue,
|
range = minValue..maxValue,
|
||||||
onValueChange = onPasswordMinSpecialCharactersChange,
|
onValueChange = onPasswordMinSpecialCharactersChange,
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.testTag("MinSpecialValueLabel")
|
.testTag("MinSpecialValueLabel")
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
)
|
)
|
||||||
|
@ -639,6 +646,7 @@ private fun PasswordMinSpecialCharactersCounterItem(
|
||||||
private fun PasswordAvoidAmbiguousCharsToggleItem(
|
private fun PasswordAvoidAmbiguousCharsToggleItem(
|
||||||
avoidAmbiguousChars: Boolean,
|
avoidAmbiguousChars: Boolean,
|
||||||
onPasswordToggleAvoidAmbiguousCharsChange: (Boolean) -> Unit,
|
onPasswordToggleAvoidAmbiguousCharsChange: (Boolean) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
) {
|
) {
|
||||||
BitwardenSwitch(
|
BitwardenSwitch(
|
||||||
|
@ -646,7 +654,7 @@ private fun PasswordAvoidAmbiguousCharsToggleItem(
|
||||||
isChecked = avoidAmbiguousChars,
|
isChecked = avoidAmbiguousChars,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
onCheckedChange = onPasswordToggleAvoidAmbiguousCharsChange,
|
onCheckedChange = onPasswordToggleAvoidAmbiguousCharsChange,
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.testTag("AvoidAmbiguousCharsToggle")
|
.testTag("AvoidAmbiguousCharsToggle")
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
|
@ -666,8 +674,7 @@ private fun ColumnScope.PassphraseTypeContent(
|
||||||
|
|
||||||
PassphraseNumWordsCounterItem(
|
PassphraseNumWordsCounterItem(
|
||||||
numWords = passphraseTypeState.numWords,
|
numWords = passphraseTypeState.numWords,
|
||||||
onPassphraseNumWordsCounterChange =
|
onPassphraseNumWordsCounterChange = passphraseHandlers.onPassphraseNumWordsCounterChange,
|
||||||
passphraseHandlers.onPassphraseNumWordsCounterChange,
|
|
||||||
minValue = passphraseTypeState.minNumWords,
|
minValue = passphraseTypeState.minNumWords,
|
||||||
maxValue = passphraseTypeState.maxNumWords,
|
maxValue = passphraseTypeState.maxNumWords,
|
||||||
)
|
)
|
||||||
|
@ -686,14 +693,14 @@ private fun ColumnScope.PassphraseTypeContent(
|
||||||
) {
|
) {
|
||||||
PassphraseCapitalizeToggleItem(
|
PassphraseCapitalizeToggleItem(
|
||||||
capitalize = passphraseTypeState.capitalize,
|
capitalize = passphraseTypeState.capitalize,
|
||||||
onPassphraseCapitalizeToggleChange =
|
onPassphraseCapitalizeToggleChange = passphraseHandlers
|
||||||
passphraseHandlers.onPassphraseCapitalizeToggleChange,
|
.onPassphraseCapitalizeToggleChange,
|
||||||
enabled = passphraseTypeState.capitalizeEnabled,
|
enabled = passphraseTypeState.capitalizeEnabled,
|
||||||
)
|
)
|
||||||
PassphraseIncludeNumberToggleItem(
|
PassphraseIncludeNumberToggleItem(
|
||||||
includeNumber = passphraseTypeState.includeNumber,
|
includeNumber = passphraseTypeState.includeNumber,
|
||||||
onPassphraseIncludeNumberToggleChange =
|
onPassphraseIncludeNumberToggleChange = passphraseHandlers
|
||||||
passphraseHandlers.onPassphraseIncludeNumberToggleChange,
|
.onPassphraseIncludeNumberToggleChange,
|
||||||
enabled = passphraseTypeState.includeNumberEnabled,
|
enabled = passphraseTypeState.includeNumberEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -703,6 +710,7 @@ private fun ColumnScope.PassphraseTypeContent(
|
||||||
private fun PassphraseNumWordsCounterItem(
|
private fun PassphraseNumWordsCounterItem(
|
||||||
numWords: Int,
|
numWords: Int,
|
||||||
onPassphraseNumWordsCounterChange: (Int) -> Unit,
|
onPassphraseNumWordsCounterChange: (Int) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
minValue: Int = PASSPHRASE_MIN_NUMBER_OF_WORDS,
|
minValue: Int = PASSPHRASE_MIN_NUMBER_OF_WORDS,
|
||||||
maxValue: Int = PASSPHRASE_MAX_NUMBER_OF_WORDS,
|
maxValue: Int = PASSPHRASE_MAX_NUMBER_OF_WORDS,
|
||||||
) {
|
) {
|
||||||
|
@ -714,7 +722,7 @@ private fun PassphraseNumWordsCounterItem(
|
||||||
range = minValue..maxValue,
|
range = minValue..maxValue,
|
||||||
onValueChange = onPassphraseNumWordsCounterChange,
|
onValueChange = onPassphraseNumWordsCounterChange,
|
||||||
stepperActionsTestTag = "NumberOfWordsStepper",
|
stepperActionsTestTag = "NumberOfWordsStepper",
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.testTag("NumberOfWordsLabel")
|
.testTag("NumberOfWordsLabel")
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
)
|
)
|
||||||
|
@ -724,6 +732,7 @@ private fun PassphraseNumWordsCounterItem(
|
||||||
private fun PassphraseWordSeparatorInputItem(
|
private fun PassphraseWordSeparatorInputItem(
|
||||||
wordSeparator: Char?,
|
wordSeparator: Char?,
|
||||||
onPassphraseWordSeparatorChange: (wordSeparator: Char?) -> Unit,
|
onPassphraseWordSeparatorChange: (wordSeparator: Char?) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
BitwardenTextField(
|
BitwardenTextField(
|
||||||
label = stringResource(id = R.string.word_separator),
|
label = stringResource(id = R.string.word_separator),
|
||||||
|
@ -737,7 +746,7 @@ private fun PassphraseWordSeparatorInputItem(
|
||||||
onPassphraseWordSeparatorChange(char)
|
onPassphraseWordSeparatorChange(char)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.testTag("WordSeparatorEntry")
|
.testTag("WordSeparatorEntry")
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
|
@ -748,6 +757,7 @@ private fun PassphraseWordSeparatorInputItem(
|
||||||
private fun PassphraseCapitalizeToggleItem(
|
private fun PassphraseCapitalizeToggleItem(
|
||||||
capitalize: Boolean,
|
capitalize: Boolean,
|
||||||
onPassphraseCapitalizeToggleChange: (Boolean) -> Unit,
|
onPassphraseCapitalizeToggleChange: (Boolean) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
) {
|
) {
|
||||||
BitwardenSwitch(
|
BitwardenSwitch(
|
||||||
|
@ -755,7 +765,7 @@ private fun PassphraseCapitalizeToggleItem(
|
||||||
isChecked = capitalize,
|
isChecked = capitalize,
|
||||||
onCheckedChange = onPassphraseCapitalizeToggleChange,
|
onCheckedChange = onPassphraseCapitalizeToggleChange,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.testTag("CapitalizePassphraseToggle")
|
.testTag("CapitalizePassphraseToggle")
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
|
@ -767,13 +777,14 @@ private fun PassphraseIncludeNumberToggleItem(
|
||||||
includeNumber: Boolean,
|
includeNumber: Boolean,
|
||||||
onPassphraseIncludeNumberToggleChange: (Boolean) -> Unit,
|
onPassphraseIncludeNumberToggleChange: (Boolean) -> Unit,
|
||||||
enabled: Boolean,
|
enabled: Boolean,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
BitwardenSwitch(
|
BitwardenSwitch(
|
||||||
label = stringResource(id = R.string.include_number),
|
label = stringResource(id = R.string.include_number),
|
||||||
isChecked = includeNumber,
|
isChecked = includeNumber,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
onCheckedChange = onPassphraseIncludeNumberToggleChange,
|
onCheckedChange = onPassphraseIncludeNumberToggleChange,
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.testTag("IncludeNumbersToggle")
|
.testTag("IncludeNumbersToggle")
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
|
@ -832,6 +843,7 @@ private fun UsernameOptionsItem(
|
||||||
currentSubState: GeneratorState.MainType.Username,
|
currentSubState: GeneratorState.MainType.Username,
|
||||||
onSubStateOptionClicked: (GeneratorState.MainType.Username.UsernameTypeOption) -> Unit,
|
onSubStateOptionClicked: (GeneratorState.MainType.Username.UsernameTypeOption) -> Unit,
|
||||||
usernameTypeHandlers: UsernameTypeHandlers,
|
usernameTypeHandlers: UsernameTypeHandlers,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val possibleSubStates = GeneratorState.MainType.Username.UsernameTypeOption.entries
|
val possibleSubStates = GeneratorState.MainType.Username.UsernameTypeOption.entries
|
||||||
val optionsWithStrings = possibleSubStates.associateWith { stringResource(id = it.labelRes) }
|
val optionsWithStrings = possibleSubStates.associateWith { stringResource(id = it.labelRes) }
|
||||||
|
@ -845,10 +857,6 @@ private fun UsernameOptionsItem(
|
||||||
optionsWithStrings.entries.first { it.value == selectedOption }.key
|
optionsWithStrings.entries.first { it.value == selectedOption }.key
|
||||||
onSubStateOptionClicked(selectedOptionId)
|
onSubStateOptionClicked(selectedOptionId)
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
|
||||||
.padding(horizontal = 16.dp)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.testTag("UsernameTypePicker"),
|
|
||||||
supportingText = currentSubState.selectedType.supportingStringResId?.let {
|
supportingText = currentSubState.selectedType.supportingStringResId?.let {
|
||||||
stringResource(id = it)
|
stringResource(id = it)
|
||||||
},
|
},
|
||||||
|
@ -856,6 +864,10 @@ private fun UsernameOptionsItem(
|
||||||
onClick = usernameTypeHandlers.onUsernameTooltipClicked,
|
onClick = usernameTypeHandlers.onUsernameTooltipClicked,
|
||||||
contentDescription = stringResource(id = R.string.learn_more),
|
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(
|
private fun ServiceTypeOptionsItem(
|
||||||
currentSubState: GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias,
|
currentSubState: GeneratorState.MainType.Username.UsernameType.ForwardedEmailAlias,
|
||||||
onSubStateOptionClicked: (ServiceTypeOption) -> Unit,
|
onSubStateOptionClicked: (ServiceTypeOption) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val possibleSubStates = ServiceTypeOption.entries
|
val possibleSubStates = ServiceTypeOption.entries
|
||||||
val optionsWithStrings = possibleSubStates.associateWith { stringResource(id = it.labelRes) }
|
val optionsWithStrings = possibleSubStates.associateWith { stringResource(id = it.labelRes) }
|
||||||
|
@ -1017,7 +1030,7 @@ private fun ServiceTypeOptionsItem(
|
||||||
optionsWithStrings.entries.first { it.value == selectedOption }.key
|
optionsWithStrings.entries.first { it.value == selectedOption }.key
|
||||||
onSubStateOptionClicked(selectedOptionId)
|
onSubStateOptionClicked(selectedOptionId)
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
.testTag("ServiceTypePicker")
|
.testTag("ServiceTypePicker")
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
|
@ -1043,14 +1056,13 @@ private fun ColumnScope.PlusAddressedEmailTypeContent(
|
||||||
private fun PlusAddressedEmailTextInputItem(
|
private fun PlusAddressedEmailTextInputItem(
|
||||||
email: String,
|
email: String,
|
||||||
onPlusAddressedEmailTextChange: (email: String) -> Unit,
|
onPlusAddressedEmailTextChange: (email: String) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
BitwardenTextField(
|
BitwardenTextField(
|
||||||
label = stringResource(id = R.string.email_required_parenthesis),
|
label = stringResource(id = R.string.email_required_parenthesis),
|
||||||
value = email,
|
value = email,
|
||||||
onValueChange = {
|
onValueChange = onPlusAddressedEmailTextChange,
|
||||||
onPlusAddressedEmailTextChange(it)
|
modifier = modifier
|
||||||
},
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.testTag("PlusAddressedEmailEntry")
|
.testTag("PlusAddressedEmailEntry")
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
|
@ -1078,14 +1090,13 @@ private fun ColumnScope.CatchAllEmailTypeContent(
|
||||||
private fun CatchAllEmailTextInputItem(
|
private fun CatchAllEmailTextInputItem(
|
||||||
domain: String,
|
domain: String,
|
||||||
onDomainTextChange: (domain: String) -> Unit,
|
onDomainTextChange: (domain: String) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
BitwardenTextField(
|
BitwardenTextField(
|
||||||
label = stringResource(id = R.string.domain_name_required_parenthesis),
|
label = stringResource(id = R.string.domain_name_required_parenthesis),
|
||||||
value = domain,
|
value = domain,
|
||||||
onValueChange = {
|
onValueChange = onDomainTextChange,
|
||||||
onDomainTextChange(it)
|
modifier = modifier
|
||||||
},
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.testTag("CatchAllEmailDomainEntry")
|
.testTag("CatchAllEmailDomainEntry")
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
|
@ -1118,12 +1129,13 @@ private fun ColumnScope.RandomWordTypeContent(
|
||||||
private fun RandomWordCapitalizeToggleItem(
|
private fun RandomWordCapitalizeToggleItem(
|
||||||
capitalize: Boolean,
|
capitalize: Boolean,
|
||||||
onRandomWordCapitalizeToggleChange: (Boolean) -> Unit,
|
onRandomWordCapitalizeToggleChange: (Boolean) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
BitwardenSwitch(
|
BitwardenSwitch(
|
||||||
label = stringResource(id = R.string.capitalize),
|
label = stringResource(id = R.string.capitalize),
|
||||||
isChecked = capitalize,
|
isChecked = capitalize,
|
||||||
onCheckedChange = onRandomWordCapitalizeToggleChange,
|
onCheckedChange = onRandomWordCapitalizeToggleChange,
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.testTag("CapitalizeRandomWordUsernameToggle")
|
.testTag("CapitalizeRandomWordUsernameToggle")
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
|
@ -1134,12 +1146,13 @@ private fun RandomWordCapitalizeToggleItem(
|
||||||
private fun RandomWordIncludeNumberToggleItem(
|
private fun RandomWordIncludeNumberToggleItem(
|
||||||
includeNumber: Boolean,
|
includeNumber: Boolean,
|
||||||
onRandomWordIncludeNumberToggleChange: (Boolean) -> Unit,
|
onRandomWordIncludeNumberToggleChange: (Boolean) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
BitwardenSwitch(
|
BitwardenSwitch(
|
||||||
label = stringResource(id = R.string.include_number),
|
label = stringResource(id = R.string.include_number),
|
||||||
isChecked = includeNumber,
|
isChecked = includeNumber,
|
||||||
onCheckedChange = onRandomWordIncludeNumberToggleChange,
|
onCheckedChange = onRandomWordIncludeNumberToggleChange,
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.testTag("IncludeNumberRandomWordUsernameToggle")
|
.testTag("IncludeNumberRandomWordUsernameToggle")
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
|
@ -1150,7 +1163,7 @@ private fun RandomWordIncludeNumberToggleItem(
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
private fun GeneratorPreview() {
|
private fun Generator_preview() {
|
||||||
BitwardenTheme {
|
BitwardenTheme {
|
||||||
GeneratorScreen(
|
GeneratorScreen(
|
||||||
onNavigateToPasswordHistory = {},
|
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,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
Loading…
Reference in a new issue