@@ -46,6 +46,7 @@ import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Us
4646import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.PlusAddressedEmail
4747import com.x8bit.bitwarden.ui.tools.feature.generator.GeneratorState.MainType.Username.UsernameType.RandomWord
4848import com.x8bit.bitwarden.ui.tools.feature.generator.model.GeneratorMode
49+ import com.x8bit.bitwarden.ui.tools.feature.generator.util.GeneratorRequestResult
4950import com.x8bit.bitwarden.ui.tools.feature.generator.util.toServiceType
5051import com.x8bit.bitwarden.ui.tools.feature.generator.util.toStrictestPolicy
5152import com.x8bit.bitwarden.ui.tools.feature.generator.util.toUsernameGeneratorRequest
@@ -170,7 +171,7 @@ class GeneratorViewModel @Inject constructor(
170171 is GeneratorAction .PasswordHistoryClick -> handlePasswordHistoryClick()
171172 is GeneratorAction .CloseClick -> handleCloseClick()
172173 is GeneratorAction .SaveClick -> handleSaveClick()
173- is GeneratorAction .RegenerateClick -> handleRegenerationClick ()
174+ is GeneratorAction .RegenerateClick -> handleRegenerateClick ()
174175 is GeneratorAction .CopyClick -> handleCopyClick()
175176 is GeneratorAction .MainTypeOptionSelect -> handleMainTypeOptionSelect(action)
176177 is GeneratorAction .MainType -> handleMainTypeAction(action)
@@ -711,10 +712,13 @@ class GeneratorViewModel @Inject constructor(
711712
712713 // region Generated Field Handlers
713714
714- private fun handleRegenerationClick () {
715+ private fun handleRegenerateClick () {
715716 // Go through the update process with the current state to trigger a
716717 // regeneration of the generated text for the same state.
717- updateGeneratorMainType(forceRegeneration = true ) { state.selectedType }
718+ updateGeneratorMainType(
719+ allowErrorsWhenMissingValues = true ,
720+ forceRegeneration = true ,
721+ ) { state.selectedType }
718722 }
719723
720724 private fun handleCopyClick () {
@@ -1511,7 +1515,9 @@ class GeneratorViewModel @Inject constructor(
15111515
15121516 // region Utility Functions
15131517
1518+ @Suppress(" LongMethod" )
15141519 private inline fun updateGeneratorMainType (
1520+ allowErrorsWhenMissingValues : Boolean = false,
15151521 forceRegeneration : Boolean = false,
15161522 crossinline block : (GeneratorState .MainType ) -> GeneratorState .MainType ? ,
15171523 ) {
@@ -1523,21 +1529,26 @@ class GeneratorViewModel @Inject constructor(
15231529 generateTextJob = viewModelScope.launch {
15241530 when (updatedMainType) {
15251531 is GeneratorState .MainType .Passphrase -> {
1526- savePassphraseOptionsToDisk(updatedMainType)
1527- generatePassphrase(updatedMainType)
1532+ savePassphraseOptionsToDisk(passphrase = updatedMainType)
1533+ generatePassphrase(passphrase = updatedMainType)
15281534 }
15291535
15301536 is GeneratorState .MainType .Password -> {
1531- savePasswordOptionsToDisk(updatedMainType)
1532- generatePassword(updatedMainType)
1537+ savePasswordOptionsToDisk(password = updatedMainType)
1538+ generatePassword(password = updatedMainType)
15331539 }
15341540
15351541 is GeneratorState .MainType .Username -> {
15361542 when (val selectedType = updatedMainType.selectedType) {
15371543 is ForwardedEmailAlias -> {
1538- saveForwardedEmailAliasServiceTypeToDisk(selectedType)
1544+ saveForwardedEmailAliasServiceTypeToDisk(
1545+ forwardedEmailAlias = selectedType,
1546+ )
15391547 if (forceRegeneration) {
1540- generateForwardedEmailAlias(selectedType)
1548+ generateForwardedEmailAlias(
1549+ allowErrorsWhenMissingValues = allowErrorsWhenMissingValues,
1550+ alias = selectedType,
1551+ )
15411552 } else {
15421553 mutableStateFlow.update {
15431554 it.copy(generatedText = NO_GENERATED_TEXT )
@@ -1546,9 +1557,12 @@ class GeneratorViewModel @Inject constructor(
15461557 }
15471558
15481559 is CatchAllEmail -> {
1549- saveCatchAllEmailOptionsToDisk(selectedType)
1560+ saveCatchAllEmailOptionsToDisk(catchAllEmail = selectedType)
15501561 if (forceRegeneration) {
1551- generateCatchAllEmail(selectedType)
1562+ generateCatchAllEmail(
1563+ catchAllEmail = selectedType,
1564+ allowErrorsWhenMissingValues = allowErrorsWhenMissingValues,
1565+ )
15521566 } else {
15531567 mutableStateFlow.update {
15541568 it.copy(generatedText = NO_GENERATED_TEXT )
@@ -1557,9 +1571,9 @@ class GeneratorViewModel @Inject constructor(
15571571 }
15581572
15591573 is PlusAddressedEmail -> {
1560- savePlusAddressedEmailOptionsToDisk(selectedType)
1574+ savePlusAddressedEmailOptionsToDisk(plusAddressedEmail = selectedType)
15611575 if (forceRegeneration) {
1562- generatePlusAddressedEmail(selectedType)
1576+ generatePlusAddressedEmail(plusAddressedEmail = selectedType)
15631577 } else {
15641578 mutableStateFlow.update {
15651579 it.copy(generatedText = NO_GENERATED_TEXT )
@@ -1568,16 +1582,19 @@ class GeneratorViewModel @Inject constructor(
15681582 }
15691583
15701584 is RandomWord -> {
1571- saveRandomWordOptionsToDisk(selectedType)
1572- generateRandomWordUsername(selectedType)
1585+ saveRandomWordOptionsToDisk(randomWord = selectedType)
1586+ generateRandomWordUsername(randomWord = selectedType)
15731587 }
15741588 }
15751589 }
15761590 }
15771591 }
15781592 }
15791593
1580- private suspend fun generateForwardedEmailAlias (alias : ForwardedEmailAlias ) {
1594+ private suspend fun generateForwardedEmailAlias (
1595+ alias : ForwardedEmailAlias ,
1596+ allowErrorsWhenMissingValues : Boolean ,
1597+ ) {
15811598 val request = alias
15821599 .selectedServiceType
15831600 ?.toUsernameGeneratorRequest(
@@ -1589,8 +1606,27 @@ class GeneratorViewModel @Inject constructor(
15891606 mutableStateFlow.update { it.copy(generatedText = NO_GENERATED_TEXT ) }
15901607 return
15911608 }
1592- val result = generatorRepository.generateForwardedServiceUsername(request)
1593- sendAction(GeneratorAction .Internal .UpdateGeneratedForwardedServiceUsernameResult (result))
1609+ when (request) {
1610+ is GeneratorRequestResult .MissingField -> {
1611+ mutableStateFlow.update { it.copy(generatedText = NO_GENERATED_TEXT ) }
1612+ if (allowErrorsWhenMissingValues) {
1613+ sendEvent(
1614+ event = GeneratorEvent .ShowSnackbar (
1615+ message = R .string.validation_field_required.asText(request.fieldName),
1616+ ),
1617+ )
1618+ }
1619+ }
1620+
1621+ is GeneratorRequestResult .Success -> {
1622+ val result = generatorRepository.generateForwardedServiceUsername(request.result)
1623+ sendAction(
1624+ action = GeneratorAction .Internal .UpdateGeneratedForwardedServiceUsernameResult (
1625+ result = result,
1626+ ),
1627+ )
1628+ }
1629+ }
15941630 }
15951631
15961632 private suspend fun generatePlusAddressedEmail (plusAddressedEmail : PlusAddressedEmail ) {
@@ -1603,9 +1639,21 @@ class GeneratorViewModel @Inject constructor(
16031639 sendAction(GeneratorAction .Internal .UpdateGeneratedPlusAddressedUsernameResult (result))
16041640 }
16051641
1606- private suspend fun generateCatchAllEmail (catchAllEmail : CatchAllEmail ) {
1642+ private suspend fun generateCatchAllEmail (
1643+ catchAllEmail : CatchAllEmail ,
1644+ allowErrorsWhenMissingValues : Boolean ,
1645+ ) {
16071646 val domainName = catchAllEmail.domainName.orNullIfBlank() ? : run {
16081647 mutableStateFlow.update { it.copy(generatedText = NO_GENERATED_TEXT ) }
1648+ if (allowErrorsWhenMissingValues) {
1649+ sendEvent(
1650+ event = GeneratorEvent .ShowSnackbar (
1651+ message = R .string.validation_field_required.asText(
1652+ R .string.domain_name.asText(),
1653+ ),
1654+ ),
1655+ )
1656+ }
16091657 return
16101658 }
16111659 val result = generatorRepository.generateCatchAllEmail(
0 commit comments