From 27a0f5172c6ce75baa230e751fac70bd7b451fda Mon Sep 17 00:00:00 2001 From: David Perez Date: Fri, 16 Jan 2026 13:50:26 -0600 Subject: [PATCH] Move Vault Listing Dialog clicks to VaultItemListingHandlers (#6375) --- .../itemlisting/VaultItemListingContent.kt | 21 +- .../itemlisting/VaultItemListingScreen.kt | 199 +++++------------- .../handlers/VaultItemListingHandlers.kt | 87 ++++++++ 3 files changed, 145 insertions(+), 162 deletions(-) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingContent.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingContent.kt index d34909c051..fad6b70d55 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingContent.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingContent.kt @@ -28,6 +28,7 @@ import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenMasterPassword import com.x8bit.bitwarden.ui.platform.components.listitem.BitwardenGroupItem import com.x8bit.bitwarden.ui.platform.components.listitem.BitwardenListItem import com.x8bit.bitwarden.ui.platform.components.listitem.SelectionItemData +import com.x8bit.bitwarden.ui.vault.feature.itemlisting.handlers.VaultItemListingHandlers import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction import kotlinx.collections.immutable.toPersistentList @@ -40,11 +41,7 @@ fun VaultItemListingContent( state: VaultItemListingState.ViewState.Content, policyDisablesSend: Boolean, showAddTotpBanner: Boolean, - collectionClick: (id: String) -> Unit, - folderClick: (id: String) -> Unit, - vaultItemClick: (id: String, type: VaultItemListingState.DisplayItem.ItemType) -> Unit, - masterPasswordRepromptSubmit: (password: String, data: MasterPasswordRepromptData) -> Unit, - onOverflowItemClick: (action: ListingItemOverflowAction) -> Unit, + vaultItemListingHandlers: VaultItemListingHandlers, modifier: Modifier = Modifier, ) { var showConfirmationDialog: ListingItemOverflowAction? by rememberSaveable { @@ -59,7 +56,7 @@ fun VaultItemListingContent( dismissButtonText = stringResource(id = BitwardenString.cancel), onConfirmClick = { showConfirmationDialog = null - onOverflowItemClick(option) + vaultItemListingHandlers.overflowItemClick(option) }, onDismissClick = { showConfirmationDialog = null }, onDismissRequest = { showConfirmationDialog = null }, @@ -89,7 +86,7 @@ fun VaultItemListingContent( BitwardenMasterPasswordDialog( onConfirmClick = { password -> masterPasswordRepromptData = null - masterPasswordRepromptSubmit(password, data) + vaultItemListingHandlers.masterPasswordRepromptSubmit(password, data) }, onDismissRequest = { masterPasswordRepromptData = null @@ -145,7 +142,7 @@ fun VaultItemListingContent( startIcon = IconData.Local(iconRes = BitwardenDrawable.ic_collections), label = collection.name, supportingLabel = collection.count.toString(), - onClick = { collectionClick(collection.id) }, + onClick = { vaultItemListingHandlers.collectionClick(collection.id) }, cardStyle = state .displayCollectionList .toListItemCardStyle(index = index, dividerPadding = 56.dp), @@ -175,7 +172,7 @@ fun VaultItemListingContent( startIcon = IconData.Local(iconRes = BitwardenDrawable.ic_folder), label = folder.name, supportingLabel = folder.count.toString(), - onClick = { folderClick(folder.id) }, + onClick = { vaultItemListingHandlers.folderClick(folder.id) }, cardStyle = state .displayFolderList .toListItemCardStyle(index = index, dividerPadding = 56.dp), @@ -221,7 +218,7 @@ fun VaultItemListingContent( itemType = it.itemType, ) } else { - vaultItemClick(it.id, it.itemType) + vaultItemListingHandlers.itemClick(it.id, it.itemType) } }, trailingLabelIcons = it.extraIconList, @@ -245,11 +242,11 @@ fun VaultItemListingContent( action = option, ) } else { - onOverflowItemClick(option) + vaultItemListingHandlers.overflowItemClick(option) } } - else -> onOverflowItemClick(option) + else -> vaultItemListingHandlers.overflowItemClick(option) } }, ) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt index 8e7938efad..1efd89c737 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt @@ -46,7 +46,6 @@ import com.bitwarden.ui.platform.manager.IntentManager import com.bitwarden.ui.platform.manager.exit.ExitManager import com.bitwarden.ui.platform.resource.BitwardenDrawable import com.bitwarden.ui.platform.resource.BitwardenString -import com.bitwarden.ui.util.Text import com.bitwarden.ui.util.asText import com.x8bit.bitwarden.ui.credentials.manager.CredentialProviderCompletionManager import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenMasterPasswordDialog @@ -61,7 +60,6 @@ import com.x8bit.bitwarden.ui.tools.feature.send.addedit.AddEditSendRoute import com.x8bit.bitwarden.ui.tools.feature.send.addedit.ModeType import com.x8bit.bitwarden.ui.tools.feature.send.viewsend.ViewSendRoute import com.x8bit.bitwarden.ui.vault.components.VaultItemSelectionDialog -import com.x8bit.bitwarden.ui.vault.components.model.CreateVaultItemType import com.x8bit.bitwarden.ui.vault.feature.addedit.VaultAddEditArgs import com.x8bit.bitwarden.ui.vault.feature.item.VaultItemArgs import com.x8bit.bitwarden.ui.vault.feature.itemlisting.handlers.VaultItemListingHandlers @@ -223,114 +221,13 @@ fun VaultItemListingScreen( } } - VaultItemListingDialogs( - dialogState = state.dialogState, - onDismissRequest = remember(viewModel) { - { viewModel.trySendAction(VaultItemListingsAction.DismissDialogClick) } - }, - onDismissCredentialManagerErrorDialog = remember(viewModel) { - { errorMessage -> - viewModel.trySendAction( - VaultItemListingsAction - .DismissCredentialManagerErrorDialogClick( - message = errorMessage, - ), - ) - } - }, - onConfirmOverwriteExistingPasskey = remember(viewModel) { - { cipherId -> - viewModel.trySendAction( - VaultItemListingsAction.ConfirmOverwriteExistingPasskeyClick( - cipherViewId = cipherId, - ), - ) - } - }, - onSubmitMasterPasswordCredentialVerification = remember(viewModel) { - { password, cipherId -> - viewModel.trySendAction( - VaultItemListingsAction.MasterPasswordUserVerificationSubmit( - password = password, - selectedCipherId = cipherId, - ), - ) - } - }, - onRetryGetCredentialPasswordVerification = remember(viewModel) { - { - viewModel.trySendAction( - VaultItemListingsAction.RetryUserVerificationPasswordVerificationClick(it), - ) - } - }, - onSubmitPinCredentialVerification = remember(viewModel) { - { pin, cipherId -> - viewModel.trySendAction( - VaultItemListingsAction.PinUserVerificationSubmit( - pin = pin, - selectedCipherId = cipherId, - ), - ) - } - }, - onRetryPinCredentialVerification = remember(viewModel) { - { - viewModel.trySendAction( - VaultItemListingsAction.RetryUserVerificationPinVerificationClick(it), - ) - } - }, - onSubmitPinSetUpCredentialVerification = remember(viewModel) { - { pin, cipherId -> - viewModel.trySendAction( - VaultItemListingsAction.UserVerificationPinSetUpSubmit( - pin = pin, - selectedCipherId = cipherId, - ), - ) - } - }, - onRetryPinSetUpCredentialVerification = remember(viewModel) { - { - viewModel.trySendAction( - VaultItemListingsAction.UserVerificationPinSetUpRetryClick(it), - ) - } - }, - onDismissUserVerification = remember(viewModel) { - { - viewModel.trySendAction( - VaultItemListingsAction.DismissUserVerificationDialogClick, - ) - } - }, - onVaultItemTypeSelected = remember(viewModel) { - { - viewModel.trySendAction( - VaultItemListingsAction.ItemTypeToAddSelected(itemType = it), - ) - } - }, - onTrustPrivilegedAppClick = remember(viewModel) { - { - viewModel.trySendAction( - VaultItemListingsAction.TrustPrivilegedAppClick(it), - ) - } - }, - onShareCipherDecryptionErrorClick = remember(viewModel) { - { - viewModel.trySendAction( - VaultItemListingsAction.ShareCipherDecryptionErrorClick(it), - ) - } - }, - ) - val vaultItemListingHandlers = remember(viewModel) { VaultItemListingHandlers.create(viewModel) } + VaultItemListingDialogs( + dialogState = state.dialogState, + vaultItemListingHandlers = vaultItemListingHandlers, + ) BackHandler(onBack = vaultItemListingHandlers.backClick) VaultItemListingScaffold( @@ -345,25 +242,13 @@ fun VaultItemListingScreen( @Composable private fun VaultItemListingDialogs( dialogState: VaultItemListingState.DialogState?, - onDismissRequest: () -> Unit, - onDismissCredentialManagerErrorDialog: (Text) -> Unit, - onConfirmOverwriteExistingPasskey: (cipherViewId: String) -> Unit, - onSubmitMasterPasswordCredentialVerification: (password: String, cipherId: String) -> Unit, - onRetryGetCredentialPasswordVerification: (cipherId: String) -> Unit, - onSubmitPinCredentialVerification: (pin: String, cipherId: String) -> Unit, - onRetryPinCredentialVerification: (cipherViewId: String) -> Unit, - onSubmitPinSetUpCredentialVerification: (pin: String, cipherId: String) -> Unit, - onRetryPinSetUpCredentialVerification: (cipherId: String) -> Unit, - onDismissUserVerification: () -> Unit, - onVaultItemTypeSelected: (CreateVaultItemType) -> Unit, - onTrustPrivilegedAppClick: (selectedCipherId: String?) -> Unit, - onShareCipherDecryptionErrorClick: (selectedCipherId: String) -> Unit, + vaultItemListingHandlers: VaultItemListingHandlers, ) { when (dialogState) { is VaultItemListingState.DialogState.Error -> BitwardenBasicDialog( title = dialogState.title?.invoke(), message = dialogState.message(), - onDismissRequest = onDismissRequest, + onDismissRequest = vaultItemListingHandlers.dismissDialogRequest, throwable = dialogState.throwable, ) @@ -378,17 +263,21 @@ private fun VaultItemListingDialogs( confirmButtonText = stringResource(BitwardenString.copy_error_report), dismissButtonText = stringResource(BitwardenString.close), onConfirmClick = { - onShareCipherDecryptionErrorClick(dialogState.selectedCipherId) + vaultItemListingHandlers.shareCipherDecryptionErrorClick( + dialogState.selectedCipherId, + ) }, - onDismissClick = onDismissRequest, - onDismissRequest = onDismissRequest, + onDismissClick = vaultItemListingHandlers.dismissDialogRequest, + onDismissRequest = vaultItemListingHandlers.dismissDialogRequest, ) } is VaultItemListingState.DialogState.CredentialManagerOperationFail -> BitwardenBasicDialog( title = dialogState.title(), message = dialogState.message(), - onDismissRequest = { onDismissCredentialManagerErrorDialog(dialogState.message) }, + onDismissRequest = { + vaultItemListingHandlers.dismissCredentialManagerErrorDialog(dialogState.message) + }, ) is VaultItemListingState.DialogState.OverwritePasskeyConfirmationPrompt -> { @@ -399,20 +288,24 @@ private fun VaultItemListingDialogs( id = BitwardenString .this_item_already_contains_a_passkey_are_you_sure_you_want_to_overwrite_the_current_passkey, ), - onConfirmClick = { onConfirmOverwriteExistingPasskey(dialogState.cipherViewId) }, - onDismissRequest = onDismissRequest, + onConfirmClick = { + vaultItemListingHandlers.confirmOverwriteExistingPasskey( + dialogState.cipherViewId, + ) + }, + onDismissRequest = vaultItemListingHandlers.dismissDialogRequest, ) } is VaultItemListingState.DialogState.UserVerificationMasterPasswordPrompt -> { BitwardenMasterPasswordDialog( onConfirmClick = { password -> - onSubmitMasterPasswordCredentialVerification( + vaultItemListingHandlers.submitMasterPasswordCredentialVerification( password, dialogState.selectedCipherId, ) }, - onDismissRequest = onDismissUserVerification, + onDismissRequest = vaultItemListingHandlers.dismissUserVerification, ) } @@ -421,7 +314,9 @@ private fun VaultItemListingDialogs( title = dialogState.title?.invoke(), message = dialogState.message(), onDismissRequest = { - onRetryGetCredentialPasswordVerification(dialogState.selectedCipherId) + vaultItemListingHandlers.retryGetCredentialPasswordVerification( + dialogState.selectedCipherId, + ) }, ) } @@ -429,12 +324,12 @@ private fun VaultItemListingDialogs( is VaultItemListingState.DialogState.UserVerificationPinPrompt -> { BitwardenPinDialog( onConfirmClick = { pin -> - onSubmitPinCredentialVerification( + vaultItemListingHandlers.submitPinCredentialVerification( pin, dialogState.selectedCipherId, ) }, - onDismissRequest = onDismissUserVerification, + onDismissRequest = vaultItemListingHandlers.dismissUserVerification, ) } @@ -443,18 +338,23 @@ private fun VaultItemListingDialogs( title = dialogState.title?.invoke(), message = dialogState.message(), onDismissRequest = { - onRetryPinCredentialVerification(dialogState.selectedCipherId) + vaultItemListingHandlers.retryPinCredentialVerification( + dialogState.selectedCipherId, + ) }, ) } is VaultItemListingState.DialogState.UserVerificationPinSetUpPrompt -> { PinInputDialog( - onCancelClick = onDismissUserVerification, + onCancelClick = vaultItemListingHandlers.dismissUserVerification, onSubmitClick = { pin -> - onSubmitPinSetUpCredentialVerification(pin, dialogState.selectedCipherId) + vaultItemListingHandlers.submitPinSetUpCredentialVerification( + pin, + dialogState.selectedCipherId, + ) }, - onDismissRequest = onDismissUserVerification, + onDismissRequest = vaultItemListingHandlers.dismissUserVerification, ) } @@ -463,15 +363,17 @@ private fun VaultItemListingDialogs( title = dialogState.title?.invoke(), message = dialogState.message(), onDismissRequest = { - onRetryPinSetUpCredentialVerification(dialogState.selectedCipherId) + vaultItemListingHandlers.retryPinSetUpCredentialVerification( + dialogState.selectedCipherId, + ) }, ) } is VaultItemListingState.DialogState.VaultItemTypeSelection -> { VaultItemSelectionDialog( - onDismissRequest = onDismissRequest, - onOptionSelected = onVaultItemTypeSelected, + onDismissRequest = vaultItemListingHandlers.dismissDialogRequest, + onOptionSelected = vaultItemListingHandlers.vaultItemTypeSelected, excludedOptions = dialogState.excludedOptions, ) } @@ -483,17 +385,19 @@ private fun VaultItemListingDialogs( confirmButtonText = stringResource(BitwardenString.trust), dismissButtonText = stringResource(BitwardenString.cancel), onConfirmClick = { - onTrustPrivilegedAppClick(dialogState.selectedCipherId) + vaultItemListingHandlers.trustPrivilegedAppClick(dialogState.selectedCipherId) }, onDismissClick = { - onDismissCredentialManagerErrorDialog( - BitwardenString.passkey_operation_failed_because_the_browser_is_not_trusted + vaultItemListingHandlers.dismissCredentialManagerErrorDialog( + BitwardenString + .passkey_operation_failed_because_the_browser_is_not_trusted .asText(), ) }, onDismissRequest = { - onDismissCredentialManagerErrorDialog( - BitwardenString.passkey_operation_failed_because_the_browser_is_not_trusted + vaultItemListingHandlers.dismissCredentialManagerErrorDialog( + BitwardenString + .passkey_operation_failed_because_the_browser_is_not_trusted .asText(), ) }, @@ -595,12 +499,7 @@ private fun VaultItemListingScaffold( showAddTotpBanner = state.isTotp, policyDisablesSend = state.policyDisablesSend && state.itemListingType is VaultItemListingState.ItemListingType.Send, - vaultItemClick = vaultItemListingHandlers.itemClick, - collectionClick = vaultItemListingHandlers.collectionClick, - folderClick = vaultItemListingHandlers.folderClick, - masterPasswordRepromptSubmit = vaultItemListingHandlers - .masterPasswordRepromptSubmit, - onOverflowItemClick = vaultItemListingHandlers.overflowItemClick, + vaultItemListingHandlers = vaultItemListingHandlers, modifier = Modifier.fillMaxSize(), ) } diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/handlers/VaultItemListingHandlers.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/handlers/VaultItemListingHandlers.kt index cda27901c5..6e1e69589b 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/handlers/VaultItemListingHandlers.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/itemlisting/handlers/VaultItemListingHandlers.kt @@ -1,6 +1,8 @@ package com.x8bit.bitwarden.ui.vault.feature.itemlisting.handlers import com.bitwarden.ui.platform.components.account.model.AccountSummary +import com.bitwarden.ui.util.Text +import com.x8bit.bitwarden.ui.vault.components.model.CreateVaultItemType import com.x8bit.bitwarden.ui.vault.feature.itemlisting.MasterPasswordRepromptData import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingState import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingViewModel @@ -26,6 +28,19 @@ data class VaultItemListingHandlers( val syncClick: () -> Unit, val lockClick: () -> Unit, val overflowItemClick: (action: ListingItemOverflowAction) -> Unit, + val dismissDialogRequest: () -> Unit, + val dismissCredentialManagerErrorDialog: (Text) -> Unit, + val confirmOverwriteExistingPasskey: (cipherViewId: String) -> Unit, + val submitMasterPasswordCredentialVerification: (password: String, cipherId: String) -> Unit, + val retryGetCredentialPasswordVerification: (cipherId: String) -> Unit, + val submitPinCredentialVerification: (pin: String, cipherId: String) -> Unit, + val retryPinCredentialVerification: (cipherViewId: String) -> Unit, + val submitPinSetUpCredentialVerification: (pin: String, cipherId: String) -> Unit, + val retryPinSetUpCredentialVerification: (cipherId: String) -> Unit, + val dismissUserVerification: () -> Unit, + val vaultItemTypeSelected: (CreateVaultItemType) -> Unit, + val trustPrivilegedAppClick: (selectedCipherId: String?) -> Unit, + val shareCipherDecryptionErrorClick: (selectedCipherId: String) -> Unit, ) { @Suppress("UndocumentedPublicClass") companion object { @@ -33,6 +48,7 @@ data class VaultItemListingHandlers( * Creates an instance of [VaultItemListingHandlers] by binding actions to the provided * [VaultItemListingViewModel]. */ + @Suppress("LongMethod") fun create( viewModel: VaultItemListingViewModel, ): VaultItemListingHandlers = @@ -76,6 +92,77 @@ data class VaultItemListingHandlers( overflowItemClick = { viewModel.trySendAction(VaultItemListingsAction.OverflowOptionClick(it)) }, + + dismissDialogRequest = { + viewModel.trySendAction(VaultItemListingsAction.DismissDialogClick) + }, + dismissCredentialManagerErrorDialog = { errorMessage -> + viewModel.trySendAction( + VaultItemListingsAction.DismissCredentialManagerErrorDialogClick( + message = errorMessage, + ), + ) + }, + confirmOverwriteExistingPasskey = { cipherId -> + viewModel.trySendAction( + VaultItemListingsAction.ConfirmOverwriteExistingPasskeyClick(cipherId), + ) + }, + submitMasterPasswordCredentialVerification = { password, cipherId -> + viewModel.trySendAction( + VaultItemListingsAction.MasterPasswordUserVerificationSubmit( + password = password, + selectedCipherId = cipherId, + ), + ) + }, + retryGetCredentialPasswordVerification = { + viewModel.trySendAction( + VaultItemListingsAction.RetryUserVerificationPasswordVerificationClick(it), + ) + }, + submitPinCredentialVerification = { pin, cipherId -> + viewModel.trySendAction( + VaultItemListingsAction.PinUserVerificationSubmit( + pin = pin, + selectedCipherId = cipherId, + ), + ) + }, + retryPinCredentialVerification = { + viewModel.trySendAction( + VaultItemListingsAction.RetryUserVerificationPinVerificationClick(it), + ) + }, + submitPinSetUpCredentialVerification = { pin, cipherId -> + viewModel.trySendAction( + VaultItemListingsAction.UserVerificationPinSetUpSubmit( + pin = pin, + selectedCipherId = cipherId, + ), + ) + }, + retryPinSetUpCredentialVerification = { + viewModel.trySendAction( + VaultItemListingsAction.UserVerificationPinSetUpRetryClick(it), + ) + }, + dismissUserVerification = { + viewModel.trySendAction( + VaultItemListingsAction.DismissUserVerificationDialogClick, + ) + }, + vaultItemTypeSelected = { + viewModel.trySendAction(VaultItemListingsAction.ItemTypeToAddSelected(it)) + }, + trustPrivilegedAppClick = { + viewModel.trySendAction(VaultItemListingsAction.TrustPrivilegedAppClick(it)) + }, + shareCipherDecryptionErrorClick = { + viewModel.trySendAction( + VaultItemListingsAction.ShareCipherDecryptionErrorClick(it), + ) + }, ) } }