Move Vault Listing Dialog clicks to VaultItemListingHandlers (#6375)

This commit is contained in:
David Perez 2026-01-16 13:50:26 -06:00 committed by GitHub
parent 3e470ebc25
commit 27a0f5172c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 145 additions and 162 deletions

View File

@ -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)
}
},
)

View File

@ -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(),
)
}

View File

@ -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),
)
},
)
}
}