From 96a3aa9f746ab5ba9d99ee77e46280a0cdad70e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Wed, 6 Nov 2024 16:55:52 +0000 Subject: [PATCH 01/13] [PM-11303] Add button visible inside folders --- .../ui/vault/feature/itemlisting/VaultItemListingViewModel.kt | 2 +- .../feature/itemlisting/util/VaultItemListingStateExtensions.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt index e1e8084eff2..290c698c99a 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt @@ -2089,7 +2089,7 @@ data class VaultItemListingState( get() = folderId ?.let { folderName.asText() } ?: R.string.folder_none.asText() - override val hasFab: Boolean get() = false + override val hasFab: Boolean get() = true } /** diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingStateExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingStateExtensions.kt index 87814f0447c..02fe69bb846 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingStateExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingStateExtensions.kt @@ -40,8 +40,8 @@ fun VaultItemListingState.ItemListingType.Vault.toVaultItemCipherType(): VaultIt is VaultItemListingState.ItemListingType.Vault.SshKey -> VaultItemCipherType.SSH_KEY is VaultItemListingState.ItemListingType.Vault.Login -> VaultItemCipherType.LOGIN is VaultItemListingState.ItemListingType.Vault.Collection -> VaultItemCipherType.LOGIN + is VaultItemListingState.ItemListingType.Vault.Folder -> VaultItemCipherType.LOGIN is VaultItemListingState.ItemListingType.Vault.Trash, - is VaultItemListingState.ItemListingType.Vault.Folder, -> { throw IllegalStateException( "Cannot create vault item from this VaultItemListingState!", From ad055f3465071f04ef656d8b0de87c548f806024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Wed, 6 Nov 2024 22:00:13 +0000 Subject: [PATCH 02/13] [PM-11303] Add selected folder id navigation parameter to preselect add item folder --- .../vaultunlocked/VaultUnlockedNavigation.kt | 14 ++++++++++---- .../VaultUnlockedNavBarNavigation.kt | 2 +- .../VaultUnlockedNavBarScreen.kt | 4 ++-- .../feature/addedit/VaultAddEditNavigation.kt | 14 ++++++++++++-- .../feature/addedit/VaultAddEditViewModel.kt | 5 ++++- .../addedit/util/CipherViewExtensions.kt | 2 +- .../itemlisting/VaultItemListingNavigation.kt | 17 +++++++++++++---- .../itemlisting/VaultItemListingScreen.kt | 10 ++++++++-- .../itemlisting/VaultItemListingViewModel.kt | 8 ++++++++ .../vault/feature/vault/VaultGraphNavigation.kt | 7 +++++-- .../VaultUnlockedNavBarScreenTest.kt | 2 +- .../itemlisting/VaultItemListingScreenTest.kt | 4 +++- .../util/VaultItemListingStateExtensionsTest.kt | 11 ++--------- 13 files changed, 70 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlocked/VaultUnlockedNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlocked/VaultUnlockedNavigation.kt index d9264facaab..98fa14fca57 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlocked/VaultUnlockedNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlocked/VaultUnlockedNavigation.kt @@ -75,8 +75,11 @@ fun NavGraphBuilder.vaultUnlockedGraph( vaultItemListingDestinationAsRoot( onNavigateBack = { navController.popBackStack() }, onNavigateToVaultItemScreen = { navController.navigateToVaultItem(vaultItemId = it) }, - onNavigateToVaultAddItemScreen = { - navController.navigateToVaultAddEdit(VaultAddEditType.AddItem(it)) + onNavigateToVaultAddItemScreen = { cipherType, selectedFolderId -> + navController.navigateToVaultAddEdit( + VaultAddEditType.AddItem(cipherType), + selectedFolderId, + ) }, onNavigateToSearchVault = { navController.navigateToSearch(searchType = it) }, onNavigateToVaultEditItemScreen = { @@ -86,8 +89,11 @@ fun NavGraphBuilder.vaultUnlockedGraph( vaultUnlockedNavBarDestination( onNavigateToExportVault = { navController.navigateToExportVault() }, onNavigateToFolders = { navController.navigateToFolders() }, - onNavigateToVaultAddItem = { - navController.navigateToVaultAddEdit(VaultAddEditType.AddItem(it)) + onNavigateToVaultAddItem = { cipherType, selectedFolderId -> + navController.navigateToVaultAddEdit( + VaultAddEditType.AddItem(cipherType), + selectedFolderId, + ) }, onNavigateToVaultItem = { navController.navigateToVaultItem(it) }, onNavigateToVaultEditItem = { diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarNavigation.kt index af86915c2e0..5345f8873f3 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarNavigation.kt @@ -25,7 +25,7 @@ fun NavController.navigateToVaultUnlockedNavBar(navOptions: NavOptions? = null) */ @Suppress("LongParameterList") fun NavGraphBuilder.vaultUnlockedNavBarDestination( - onNavigateToVaultAddItem: (VaultItemCipherType) -> Unit, + onNavigateToVaultAddItem: (VaultItemCipherType, String?) -> Unit, onNavigateToVaultItem: (vaultItemId: String) -> Unit, onNavigateToVaultEditItem: (vaultItemId: String) -> Unit, onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreen.kt index 1a3b029cdac..b0c011c5ea7 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreen.kt @@ -64,7 +64,7 @@ import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType fun VaultUnlockedNavBarScreen( viewModel: VaultUnlockedNavBarViewModel = hiltViewModel(), navController: NavHostController = rememberNavController(), - onNavigateToVaultAddItem: (VaultItemCipherType) -> Unit, + onNavigateToVaultAddItem: (VaultItemCipherType, String?) -> Unit, onNavigateToVaultItem: (vaultItemId: String) -> Unit, onNavigateToVaultEditItem: (vaultItemId: String) -> Unit, onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit, @@ -158,7 +158,7 @@ private fun VaultUnlockedNavBarScaffold( sendTabClickedAction: () -> Unit, generatorTabClickedAction: () -> Unit, settingsTabClickedAction: () -> Unit, - navigateToVaultAddItem: (VaultItemCipherType) -> Unit, + navigateToVaultAddItem: (VaultItemCipherType, String?) -> Unit, onNavigateToVaultItem: (vaultItemId: String) -> Unit, onNavigateToVaultEditItem: (vaultItemId: String) -> Unit, onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditNavigation.kt index ea2ec0fa6b2..aa130f7f5fb 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditNavigation.kt @@ -26,12 +26,14 @@ private const val ADD_ITEM_TYPE: String = "vault_add_item_type" private const val ADD_EDIT_ITEM_PREFIX: String = "vault_add_edit_item" private const val ADD_EDIT_ITEM_TYPE: String = "vault_add_edit_type" +private const val ADD_SELECTED_FOLDER_ID: String = "vault_add_selected_folder_id" private const val ADD_EDIT_ITEM_ROUTE: String = ADD_EDIT_ITEM_PREFIX + "/{$ADD_EDIT_ITEM_TYPE}" + "?$EDIT_ITEM_ID={$EDIT_ITEM_ID}" + - "?$ADD_ITEM_TYPE={$ADD_ITEM_TYPE}" + "?$ADD_ITEM_TYPE={$ADD_ITEM_TYPE}" + + "?$ADD_SELECTED_FOLDER_ID={$ADD_SELECTED_FOLDER_ID}" /** * Class to retrieve vault add & edit arguments from the [SavedStateHandle]. @@ -39,6 +41,7 @@ private const val ADD_EDIT_ITEM_ROUTE: String = @OmitFromCoverage data class VaultAddEditArgs( val vaultAddEditType: VaultAddEditType, + val selectedFolderId: String? = null, ) { constructor(savedStateHandle: SavedStateHandle) : this( vaultAddEditType = when (requireNotNull(savedStateHandle[ADD_EDIT_ITEM_TYPE])) { @@ -53,6 +56,7 @@ data class VaultAddEditArgs( CLONE_TYPE -> VaultAddEditType.CloneItem(requireNotNull(savedStateHandle[EDIT_ITEM_ID])) else -> throw IllegalStateException("Unknown VaultAddEditType.") }, + selectedFolderId = savedStateHandle[ADD_SELECTED_FOLDER_ID], ) } @@ -72,6 +76,10 @@ fun NavGraphBuilder.vaultAddEditDestination( route = ADD_EDIT_ITEM_ROUTE, arguments = listOf( navArgument(ADD_EDIT_ITEM_TYPE) { type = NavType.StringType }, + navArgument(ADD_SELECTED_FOLDER_ID) { + type = NavType.StringType + nullable = true + }, ), ) { VaultAddEditScreen( @@ -90,12 +98,14 @@ fun NavGraphBuilder.vaultAddEditDestination( */ fun NavController.navigateToVaultAddEdit( vaultAddEditType: VaultAddEditType, + selectedFolderId: String? = null, navOptions: NavOptions? = null, ) { navigate( route = "$ADD_EDIT_ITEM_PREFIX/${vaultAddEditType.toTypeString()}" + "?$EDIT_ITEM_ID=${vaultAddEditType.toIdOrNull()}" + - "?$ADD_ITEM_TYPE=${vaultAddEditType.toVaultItemCipherTypeOrNull()}", + "?$ADD_ITEM_TYPE=${vaultAddEditType.toVaultItemCipherTypeOrNull()}" + + "?$ADD_SELECTED_FOLDER_ID=$selectedFolderId", navOptions = navOptions, ) } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt index fd7dfb4ae57..7d1bf8383d7 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt @@ -109,6 +109,7 @@ class VaultAddEditViewModel @Inject constructor( initialState = savedStateHandle[KEY_STATE] ?: run { val vaultAddEditType = VaultAddEditArgs(savedStateHandle).vaultAddEditType + val selectedFolderId = VaultAddEditArgs(savedStateHandle).selectedFolderId val isIndividualVaultDisabled = policyManager .getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP) .any() @@ -151,7 +152,9 @@ class VaultAddEditViewModel @Inject constructor( ) ?: totpData?.toDefaultAddTypeContent(isIndividualVaultDisabled) ?: VaultAddEditState.ViewState.Content( - common = VaultAddEditState.ViewState.Content.Common(), + common = VaultAddEditState.ViewState.Content.Common( + selectedFolderId = selectedFolderId, + ), isIndividualVaultDisabled = isIndividualVaultDisabled, type = vaultAddEditType.vaultItemCipherType.toItemType(), ) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt index a6883458829..5a568beb916 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt @@ -127,7 +127,7 @@ fun VaultAddEditState.ViewState.appendFolderAndOwnerData( common = currentContentState.common.copy( selectedFolderId = folderViewList.toSelectedFolderId( cipherView = currentContentState.common.originalCipher, - ), + ) ?: currentContentState.common.selectedFolderId, availableFolders = folderViewList.toAvailableFolders( resourceManager = resourceManager, ), diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt index b076c532aad..382fc77c42d 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt @@ -64,7 +64,10 @@ fun NavGraphBuilder.vaultItemListingDestination( onNavigateToVaultItemScreen: (id: String) -> Unit, onNavigateToVaultEditItemScreen: (cipherId: String) -> Unit, onNavigateToVaultItemListing: (vaultItemListingType: VaultItemListingType) -> Unit, - onNavigateToVaultAddItemScreen: (vaultItemCipherType: VaultItemCipherType) -> Unit, + onNavigateToVaultAddItemScreen: ( + cipherType: VaultItemCipherType, + selectedFolderId: String?, + ) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, ) { internalVaultItemListingDestination( @@ -87,7 +90,10 @@ fun NavGraphBuilder.vaultItemListingDestinationAsRoot( onNavigateBack: () -> Unit, onNavigateToVaultItemScreen: (id: String) -> Unit, onNavigateToVaultEditItemScreen: (cipherId: String) -> Unit, - onNavigateToVaultAddItemScreen: (VaultItemCipherType) -> Unit, + onNavigateToVaultAddItemScreen: ( + cipherType: VaultItemCipherType, + selectedFolderId: String?, + ) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, ) { composableWithStayTransitions( @@ -128,7 +134,7 @@ fun NavGraphBuilder.sendItemListingDestination( onNavigateBack = onNavigateBack, onNavigateToAddSendItem = onNavigateToAddSendItem, onNavigateToEditSendItem = onNavigateToEditSendItem, - onNavigateToVaultAddItemScreen = { }, + onNavigateToVaultAddItemScreen = { _, _ -> }, onNavigateToVaultItemScreen = { }, onNavigateToVaultEditItemScreen = { }, onNavigateToVaultItemListing = { }, @@ -146,7 +152,10 @@ private fun NavGraphBuilder.internalVaultItemListingDestination( onNavigateToVaultItemScreen: (id: String) -> Unit, onNavigateToVaultEditItemScreen: (cipherId: String) -> Unit, onNavigateToVaultItemListing: (vaultItemListingType: VaultItemListingType) -> Unit, - onNavigateToVaultAddItemScreen: (vaultItemCipherType: VaultItemCipherType) -> Unit, + onNavigateToVaultAddItemScreen: ( + cipherType: VaultItemCipherType, + selectedFolderId: String?, + ) -> Unit, onNavigateToAddSendItem: () -> Unit, onNavigateToEditSendItem: (sendId: String) -> Unit, onNavigateToSearch: (searchType: SearchType) -> Unit, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt index 3285eb877a2..7b86d7680cb 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt @@ -72,7 +72,10 @@ fun VaultItemListingScreen( onNavigateToVaultItem: (id: String) -> Unit, onNavigateToVaultEditItemScreen: (cipherVaultId: String) -> Unit, onNavigateToVaultItemListing: (vaultItemListingType: VaultItemListingType) -> Unit, - onNavigateToVaultAddItemScreen: (vaultItemCipherType: VaultItemCipherType) -> Unit, + onNavigateToVaultAddItemScreen: ( + vaultItemCipherType: VaultItemCipherType, + selectedFolderId: String?, + ) -> Unit, onNavigateToAddSendItem: () -> Unit, onNavigateToEditSendItem: (sendId: String) -> Unit, onNavigateToSearch: (searchType: SearchType) -> Unit, @@ -113,7 +116,10 @@ fun VaultItemListingScreen( } is VaultItemListingEvent.NavigateToAddVaultItem -> { - onNavigateToVaultAddItemScreen(event.vaultItemCipherType) + onNavigateToVaultAddItemScreen( + event.vaultItemCipherType, + event.selectedFolderId, + ) } is VaultItemListingEvent.NavigateToEditCipher -> { diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt index 290c698c99a..4af2169e741 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt @@ -534,6 +534,13 @@ class VaultItemListingViewModel @Inject constructor( private fun handleAddVaultItemClick() { val event = when (val itemListingType = state.itemListingType) { + is VaultItemListingState.ItemListingType.Vault.Folder -> { + VaultItemListingEvent.NavigateToAddVaultItem( + vaultItemCipherType = itemListingType.toVaultItemCipherType(), + selectedFolderId = itemListingType.folderId, + ) + } + is VaultItemListingState.ItemListingType.Vault -> { VaultItemListingEvent.NavigateToAddVaultItem( vaultItemCipherType = itemListingType.toVaultItemCipherType(), @@ -2150,6 +2157,7 @@ sealed class VaultItemListingEvent { */ data class NavigateToAddVaultItem( val vaultItemCipherType: VaultItemCipherType, + val selectedFolderId: String? = null, ) : VaultItemListingEvent() /** diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt index 8b4a052faf3..538b7a55c3e 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt @@ -20,7 +20,10 @@ const val VAULT_GRAPH_ROUTE: String = "vault_graph" @Suppress("LongParameterList") fun NavGraphBuilder.vaultGraph( navController: NavController, - onNavigateToVaultAddItemScreen: (vaultItemCipherType: VaultItemCipherType) -> Unit, + onNavigateToVaultAddItemScreen: ( + vaultItemCipherType: VaultItemCipherType, + selectedFolderId: String?, + ) -> Unit, onNavigateToVaultItemScreen: (vaultItemId: String) -> Unit, onNavigateToVaultEditItemScreen: (vaultItemId: String) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, @@ -33,7 +36,7 @@ fun NavGraphBuilder.vaultGraph( ) { vaultDestination( onNavigateToVaultAddItemScreen = { - onNavigateToVaultAddItemScreen(VaultItemCipherType.LOGIN) + onNavigateToVaultAddItemScreen(VaultItemCipherType.LOGIN, null) }, onNavigateToVaultItemScreen = onNavigateToVaultItemScreen, onNavigateToVaultEditItemScreen = onNavigateToVaultEditItemScreen, diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt index 0999c3b57e5..6311356eb28 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt @@ -41,7 +41,7 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { VaultUnlockedNavBarScreen( viewModel = viewModel, navController = fakeNavHostController, - onNavigateToVaultAddItem = {}, + onNavigateToVaultAddItem = { _, _ -> }, onNavigateToVaultItem = {}, onNavigateToVaultEditItem = {}, onNavigateToAddSend = {}, diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt index f84921b60d1..de75be94c64 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt @@ -117,7 +117,9 @@ class VaultItemListingScreenTest : BaseComposeTest() { biometricsManager = biometricsManager, onNavigateBack = { onNavigateBackCalled = true }, onNavigateToVaultItem = { onNavigateToVaultItemId = it }, - onNavigateToVaultAddItemScreen = { onNavigateToVaultAddItemScreenCalled = true }, + onNavigateToVaultAddItemScreen = { _, _ -> + onNavigateToVaultAddItemScreenCalled = true + }, onNavigateToAddSendItem = { onNavigateToAddSendScreenCalled = true }, onNavigateToEditSendItem = { onNavigateToEditSendItemId = it }, onNavigateToSearch = { onNavigateToSearchType = it }, diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingStateExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingStateExtensionsTest.kt index 211d6dc58c2..78ce301e325 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingStateExtensionsTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingStateExtensionsTest.kt @@ -149,15 +149,8 @@ class VaultItemListingStateExtensionsTest { @Test fun `toVaultItemCipherType should throw an exception for unsupported ItemListingTypes`() { - val itemListingTypes = listOf( - VaultItemListingState.ItemListingType.Vault.Trash, - VaultItemListingState.ItemListingType.Vault.Folder( - folderId = "mockId", - ), - ) - - itemListingTypes.forEach { - assertThrows { it.toVaultItemCipherType() } + assertThrows { + VaultItemListingState.ItemListingType.Vault.Trash.toVaultItemCipherType() } } } From a52588fe7ebb982917446bba2e8f7cf7379b0e69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Thu, 7 Nov 2024 11:34:42 +0000 Subject: [PATCH 03/13] [PM-11303] Add missing tests --- .../VaultItemListingViewModelTest.kt | 20 +++++++++++++++++++ .../VaultItemListingStateExtensionsTest.kt | 2 ++ 2 files changed, 22 insertions(+) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt index 591a0f1e4c5..1e21bc9cfb1 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt @@ -942,6 +942,26 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { } } + @Suppress("MaxLineLength") + @Test + fun `AddVaultItemClick inside a folder should emit NavigateToAddVaultItem with a selected folder id`() = runTest { + val viewModel = createVaultItemListingViewModel( + savedStateHandle = createSavedStateHandleWithVaultItemListingType( + vaultItemListingType = VaultItemListingType.Folder(folderId = "id"), + ), + ) + viewModel.eventFlow.test { + viewModel.trySendAction(VaultItemListingsAction.AddVaultItemClick) + assertEquals( + VaultItemListingEvent.NavigateToAddVaultItem( + VaultItemCipherType.LOGIN, + selectedFolderId = "id", + ), + awaitItem(), + ) + } + } + @Test fun `AddVaultItemClick for vault item should emit NavigateToAddVaultItem`() = runTest { val viewModel = createVaultItemListingViewModel() diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingStateExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingStateExtensionsTest.kt index 78ce301e325..0b2129f8738 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingStateExtensionsTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingStateExtensionsTest.kt @@ -130,6 +130,7 @@ class VaultItemListingStateExtensionsTest { VaultItemListingState.ItemListingType.Vault.Login, VaultItemListingState.ItemListingType.Vault.Collection(collectionId = "mockId"), VaultItemListingState.ItemListingType.Vault.SshKey, + VaultItemListingState.ItemListingType.Vault.Folder(folderId = "mockId"), ) val result = itemListingTypes.map { it.toVaultItemCipherType() } @@ -142,6 +143,7 @@ class VaultItemListingStateExtensionsTest { VaultItemCipherType.LOGIN, VaultItemCipherType.LOGIN, VaultItemCipherType.SSH_KEY, + VaultItemCipherType.LOGIN, ), result, ) From b185412fbab5416e36bc845dfacd2995c66a8e91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Thu, 7 Nov 2024 16:54:07 +0000 Subject: [PATCH 04/13] [PM-11304] Add collection Id to navigation params --- .../vaultunlocked/VaultUnlockedNavigation.kt | 6 ++++-- .../VaultUnlockedNavBarNavigation.kt | 2 +- .../VaultUnlockedNavBarScreen.kt | 4 ++-- .../feature/addedit/VaultAddEditNavigation.kt | 15 +++++++++++++-- .../itemlisting/VaultItemListingNavigation.kt | 5 ++++- .../feature/itemlisting/VaultItemListingScreen.kt | 2 ++ .../vault/feature/vault/VaultGraphNavigation.kt | 3 ++- .../VaultUnlockedNavBarScreenTest.kt | 2 +- .../itemlisting/VaultItemListingScreenTest.kt | 2 +- 9 files changed, 30 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlocked/VaultUnlockedNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlocked/VaultUnlockedNavigation.kt index 98fa14fca57..1c96b4a9487 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlocked/VaultUnlockedNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlocked/VaultUnlockedNavigation.kt @@ -75,10 +75,11 @@ fun NavGraphBuilder.vaultUnlockedGraph( vaultItemListingDestinationAsRoot( onNavigateBack = { navController.popBackStack() }, onNavigateToVaultItemScreen = { navController.navigateToVaultItem(vaultItemId = it) }, - onNavigateToVaultAddItemScreen = { cipherType, selectedFolderId -> + onNavigateToVaultAddItemScreen = { cipherType, selectedFolderId, collectionId -> navController.navigateToVaultAddEdit( VaultAddEditType.AddItem(cipherType), selectedFolderId, + collectionId, ) }, onNavigateToSearchVault = { navController.navigateToSearch(searchType = it) }, @@ -89,10 +90,11 @@ fun NavGraphBuilder.vaultUnlockedGraph( vaultUnlockedNavBarDestination( onNavigateToExportVault = { navController.navigateToExportVault() }, onNavigateToFolders = { navController.navigateToFolders() }, - onNavigateToVaultAddItem = { cipherType, selectedFolderId -> + onNavigateToVaultAddItem = { cipherType, selectedFolderId, collectionId -> navController.navigateToVaultAddEdit( VaultAddEditType.AddItem(cipherType), selectedFolderId, + collectionId, ) }, onNavigateToVaultItem = { navController.navigateToVaultItem(it) }, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarNavigation.kt index 5345f8873f3..a6a43bf3950 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarNavigation.kt @@ -25,7 +25,7 @@ fun NavController.navigateToVaultUnlockedNavBar(navOptions: NavOptions? = null) */ @Suppress("LongParameterList") fun NavGraphBuilder.vaultUnlockedNavBarDestination( - onNavigateToVaultAddItem: (VaultItemCipherType, String?) -> Unit, + onNavigateToVaultAddItem: (VaultItemCipherType, String?, String?) -> Unit, onNavigateToVaultItem: (vaultItemId: String) -> Unit, onNavigateToVaultEditItem: (vaultItemId: String) -> Unit, onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreen.kt index b0c011c5ea7..f95d7176f33 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreen.kt @@ -64,7 +64,7 @@ import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType fun VaultUnlockedNavBarScreen( viewModel: VaultUnlockedNavBarViewModel = hiltViewModel(), navController: NavHostController = rememberNavController(), - onNavigateToVaultAddItem: (VaultItemCipherType, String?) -> Unit, + onNavigateToVaultAddItem: (VaultItemCipherType, String?, String?) -> Unit, onNavigateToVaultItem: (vaultItemId: String) -> Unit, onNavigateToVaultEditItem: (vaultItemId: String) -> Unit, onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit, @@ -158,7 +158,7 @@ private fun VaultUnlockedNavBarScaffold( sendTabClickedAction: () -> Unit, generatorTabClickedAction: () -> Unit, settingsTabClickedAction: () -> Unit, - navigateToVaultAddItem: (VaultItemCipherType, String?) -> Unit, + navigateToVaultAddItem: (VaultItemCipherType, String?, String?) -> Unit, onNavigateToVaultItem: (vaultItemId: String) -> Unit, onNavigateToVaultEditItem: (vaultItemId: String) -> Unit, onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditNavigation.kt index aa130f7f5fb..f72448fe0a5 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditNavigation.kt @@ -27,13 +27,15 @@ private const val ADD_ITEM_TYPE: String = "vault_add_item_type" private const val ADD_EDIT_ITEM_PREFIX: String = "vault_add_edit_item" private const val ADD_EDIT_ITEM_TYPE: String = "vault_add_edit_type" private const val ADD_SELECTED_FOLDER_ID: String = "vault_add_selected_folder_id" +private const val ADD_SELECTED_COLLECTION_ID: String = "vault_add_selected_collection_id" private const val ADD_EDIT_ITEM_ROUTE: String = ADD_EDIT_ITEM_PREFIX + "/{$ADD_EDIT_ITEM_TYPE}" + "?$EDIT_ITEM_ID={$EDIT_ITEM_ID}" + "?$ADD_ITEM_TYPE={$ADD_ITEM_TYPE}" + - "?$ADD_SELECTED_FOLDER_ID={$ADD_SELECTED_FOLDER_ID}" + "?$ADD_SELECTED_FOLDER_ID={$ADD_SELECTED_FOLDER_ID}" + + "?$ADD_SELECTED_COLLECTION_ID={$ADD_SELECTED_COLLECTION_ID}" /** * Class to retrieve vault add & edit arguments from the [SavedStateHandle]. @@ -42,6 +44,8 @@ private const val ADD_EDIT_ITEM_ROUTE: String = data class VaultAddEditArgs( val vaultAddEditType: VaultAddEditType, val selectedFolderId: String? = null, + val selectedCollectionId: String? = null, + val ownerId: String? = null, ) { constructor(savedStateHandle: SavedStateHandle) : this( vaultAddEditType = when (requireNotNull(savedStateHandle[ADD_EDIT_ITEM_TYPE])) { @@ -57,6 +61,7 @@ data class VaultAddEditArgs( else -> throw IllegalStateException("Unknown VaultAddEditType.") }, selectedFolderId = savedStateHandle[ADD_SELECTED_FOLDER_ID], + selectedCollectionId = savedStateHandle[ADD_SELECTED_COLLECTION_ID], ) } @@ -80,6 +85,10 @@ fun NavGraphBuilder.vaultAddEditDestination( type = NavType.StringType nullable = true }, + navArgument(ADD_SELECTED_COLLECTION_ID) { + type = NavType.StringType + nullable = true + }, ), ) { VaultAddEditScreen( @@ -99,13 +108,15 @@ fun NavGraphBuilder.vaultAddEditDestination( fun NavController.navigateToVaultAddEdit( vaultAddEditType: VaultAddEditType, selectedFolderId: String? = null, + selectedCollectionId: String? = null, navOptions: NavOptions? = null, ) { navigate( route = "$ADD_EDIT_ITEM_PREFIX/${vaultAddEditType.toTypeString()}" + "?$EDIT_ITEM_ID=${vaultAddEditType.toIdOrNull()}" + "?$ADD_ITEM_TYPE=${vaultAddEditType.toVaultItemCipherTypeOrNull()}" + - "?$ADD_SELECTED_FOLDER_ID=$selectedFolderId", + "?$ADD_SELECTED_FOLDER_ID=$selectedFolderId" + + "?$ADD_SELECTED_COLLECTION_ID=$selectedCollectionId", navOptions = navOptions, ) } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt index 382fc77c42d..2bc0bac02f1 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt @@ -67,6 +67,7 @@ fun NavGraphBuilder.vaultItemListingDestination( onNavigateToVaultAddItemScreen: ( cipherType: VaultItemCipherType, selectedFolderId: String?, + selectedCollectionId: String?, ) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, ) { @@ -93,6 +94,7 @@ fun NavGraphBuilder.vaultItemListingDestinationAsRoot( onNavigateToVaultAddItemScreen: ( cipherType: VaultItemCipherType, selectedFolderId: String?, + selectedCollectionId: String?, ) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, ) { @@ -134,7 +136,7 @@ fun NavGraphBuilder.sendItemListingDestination( onNavigateBack = onNavigateBack, onNavigateToAddSendItem = onNavigateToAddSendItem, onNavigateToEditSendItem = onNavigateToEditSendItem, - onNavigateToVaultAddItemScreen = { _, _ -> }, + onNavigateToVaultAddItemScreen = { _, _, _ -> }, onNavigateToVaultItemScreen = { }, onNavigateToVaultEditItemScreen = { }, onNavigateToVaultItemListing = { }, @@ -155,6 +157,7 @@ private fun NavGraphBuilder.internalVaultItemListingDestination( onNavigateToVaultAddItemScreen: ( cipherType: VaultItemCipherType, selectedFolderId: String?, + selectedCollectionId: String?, ) -> Unit, onNavigateToAddSendItem: () -> Unit, onNavigateToEditSendItem: (sendId: String) -> Unit, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt index 7b86d7680cb..84e702e6a9e 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt @@ -75,6 +75,7 @@ fun VaultItemListingScreen( onNavigateToVaultAddItemScreen: ( vaultItemCipherType: VaultItemCipherType, selectedFolderId: String?, + selectedCollectionId: String?, ) -> Unit, onNavigateToAddSendItem: () -> Unit, onNavigateToEditSendItem: (sendId: String) -> Unit, @@ -119,6 +120,7 @@ fun VaultItemListingScreen( onNavigateToVaultAddItemScreen( event.vaultItemCipherType, event.selectedFolderId, + event.selectedCollectionId, ) } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt index 538b7a55c3e..bd57f4d2d98 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt @@ -23,6 +23,7 @@ fun NavGraphBuilder.vaultGraph( onNavigateToVaultAddItemScreen: ( vaultItemCipherType: VaultItemCipherType, selectedFolderId: String?, + selectedCollectionId: String?, ) -> Unit, onNavigateToVaultItemScreen: (vaultItemId: String) -> Unit, onNavigateToVaultEditItemScreen: (vaultItemId: String) -> Unit, @@ -36,7 +37,7 @@ fun NavGraphBuilder.vaultGraph( ) { vaultDestination( onNavigateToVaultAddItemScreen = { - onNavigateToVaultAddItemScreen(VaultItemCipherType.LOGIN, null) + onNavigateToVaultAddItemScreen(VaultItemCipherType.LOGIN, null, null) }, onNavigateToVaultItemScreen = onNavigateToVaultItemScreen, onNavigateToVaultEditItemScreen = onNavigateToVaultEditItemScreen, diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt index 6311356eb28..ca324e073f0 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt @@ -41,7 +41,7 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { VaultUnlockedNavBarScreen( viewModel = viewModel, navController = fakeNavHostController, - onNavigateToVaultAddItem = { _, _ -> }, + onNavigateToVaultAddItem = { _, _, _ -> }, onNavigateToVaultItem = {}, onNavigateToVaultEditItem = {}, onNavigateToAddSend = {}, diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt index de75be94c64..52642bffa36 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt @@ -117,7 +117,7 @@ class VaultItemListingScreenTest : BaseComposeTest() { biometricsManager = biometricsManager, onNavigateBack = { onNavigateBackCalled = true }, onNavigateToVaultItem = { onNavigateToVaultItemId = it }, - onNavigateToVaultAddItemScreen = { _, _ -> + onNavigateToVaultAddItemScreen = { _, _, _ -> onNavigateToVaultAddItemScreenCalled = true }, onNavigateToAddSendItem = { onNavigateToAddSendScreenCalled = true }, From 96f118e1e4cdcba48d3eaf751dbd7ca0abd6182c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Thu, 7 Nov 2024 16:56:13 +0000 Subject: [PATCH 05/13] [PM-11304] Enable fab for collection vault listings --- .../ui/vault/feature/itemlisting/VaultItemListingViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt index 4af2169e741..8aa633aa938 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt @@ -2111,7 +2111,7 @@ data class VaultItemListingState( val collectionName: String = "", ) : Vault() { override val titleText: Text get() = collectionName.asText() - override val hasFab: Boolean get() = false + override val hasFab: Boolean get() = true } } From 9213ad288252e4250c4755ad1d4f890e1c1b3d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Thu, 7 Nov 2024 16:57:35 +0000 Subject: [PATCH 06/13] [PM-11304] Select owner and collection if creating cipher from an org folder --- .../feature/addedit/VaultAddEditViewModel.kt | 3 +++ .../addedit/util/CipherViewExtensions.kt | 17 +++++++++++++---- .../itemlisting/VaultItemListingViewModel.kt | 8 ++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt index 7d1bf8383d7..bc35183f646 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt @@ -110,6 +110,7 @@ class VaultAddEditViewModel @Inject constructor( ?: run { val vaultAddEditType = VaultAddEditArgs(savedStateHandle).vaultAddEditType val selectedFolderId = VaultAddEditArgs(savedStateHandle).selectedFolderId + val selectedCollectionId = VaultAddEditArgs(savedStateHandle).selectedCollectionId val isIndividualVaultDisabled = policyManager .getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP) .any() @@ -154,6 +155,7 @@ class VaultAddEditViewModel @Inject constructor( ?: VaultAddEditState.ViewState.Content( common = VaultAddEditState.ViewState.Content.Common( selectedFolderId = selectedFolderId, + selectedCollectionId = selectedCollectionId, ), isIndividualVaultDisabled = isIndividualVaultDisabled, type = vaultAddEditType.vaultItemCipherType.toItemType(), @@ -2099,6 +2101,7 @@ data class VaultAddEditState( val favorite: Boolean = false, val customFieldData: List = emptyList(), val notes: String = "", + val selectedCollectionId: String? = null, val selectedFolderId: String? = null, val availableFolders: List = emptyList(), val selectedOwnerId: String? = null, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt index 5a568beb916..318cd8f9e3d 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt @@ -127,17 +127,23 @@ fun VaultAddEditState.ViewState.appendFolderAndOwnerData( common = currentContentState.common.copy( selectedFolderId = folderViewList.toSelectedFolderId( cipherView = currentContentState.common.originalCipher, - ) ?: currentContentState.common.selectedFolderId, + ) + ?: currentContentState.common.selectedFolderId, availableFolders = folderViewList.toAvailableFolders( resourceManager = resourceManager, ), selectedOwnerId = activeAccount.toSelectedOwnerId( cipherView = currentContentState.common.originalCipher, - ), + ) + ?: collectionViewList.firstOrNull { + it.id == currentContentState.common.selectedCollectionId + } + ?.organizationId, availableOwners = activeAccount.toAvailableOwners( collectionViewList = collectionViewList, cipherView = currentContentState.common.originalCipher, isIndividualVaultDisabled = isIndividualVaultDisabled, + selectedCollectionId = currentContentState.common.selectedCollectionId, ), isUnlockWithPasswordEnabled = activeAccount.hasMasterPassword, hasOrganizations = activeAccount.organizations.isNotEmpty(), @@ -192,6 +198,7 @@ private fun UserState.Account.toAvailableOwners( collectionViewList: List, cipherView: CipherView?, isIndividualVaultDisabled: Boolean, + selectedCollectionId: String? = null, ): List = listOfNotNull( VaultAddEditState.Owner( @@ -214,9 +221,11 @@ private fun UserState.Account.toAvailableOwners( VaultCollection( id = collection.id.orEmpty(), name = collection.name, - isSelected = cipherView + isSelected = (cipherView ?.collectionIds - ?.contains(collection.id) == true, + ?.contains(collection.id)) + ?: (selectedCollectionId != null && + collection.id == selectedCollectionId), ) }, ) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt index 8aa633aa938..35099e6027f 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt @@ -541,6 +541,13 @@ class VaultItemListingViewModel @Inject constructor( ) } + is VaultItemListingState.ItemListingType.Vault.Collection -> { + VaultItemListingEvent.NavigateToAddVaultItem( + vaultItemCipherType = itemListingType.toVaultItemCipherType(), + selectedCollectionId = itemListingType.collectionId, + ) + } + is VaultItemListingState.ItemListingType.Vault -> { VaultItemListingEvent.NavigateToAddVaultItem( vaultItemCipherType = itemListingType.toVaultItemCipherType(), @@ -2158,6 +2165,7 @@ sealed class VaultItemListingEvent { data class NavigateToAddVaultItem( val vaultItemCipherType: VaultItemCipherType, val selectedFolderId: String? = null, + val selectedCollectionId: String? = null, ) : VaultItemListingEvent() /** From 3dc76578d3205bd976409659e840a5b9b1311fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Thu, 7 Nov 2024 16:58:16 +0000 Subject: [PATCH 07/13] [PM-11304] Update show add cipher fab button logic --- .../ui/vault/feature/itemlisting/VaultItemListingScreen.kt | 2 +- .../vault/feature/itemlisting/VaultItemListingViewModel.kt | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt index 84e702e6a9e..06f0b8dc1b0 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt @@ -449,7 +449,7 @@ private fun VaultItemListingScaffold( ) }, floatingActionButton = { - if (state.itemListingType.hasFab) { + if (state.hasAddItemFabButton) { BitwardenFloatingActionButton( onClick = vaultItemListingHandlers.addVaultItemClick, painter = rememberVectorPainter(id = R.drawable.ic_plus_large), diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt index 35099e6027f..f1b3a804cad 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModel.kt @@ -1746,6 +1746,13 @@ data class VaultItemListingState( val isPremium: Boolean, val isRefreshing: Boolean, ) { + /** + * Whether or not the add FAB should be shown. + */ + val hasAddItemFabButton: Boolean + get() = itemListingType.hasFab && + !(viewState is ViewState.NoItems && viewState.shouldShowAddButton) + /** * Whether or not this represents a listing screen for autofill. */ From c70ff9be3661fd7a35345a5708d3661efa3c6aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Thu, 7 Nov 2024 18:49:57 +0000 Subject: [PATCH 08/13] [PM-11303] Code cleanup --- .../addedit/util/CipherViewExtensions.kt | 3 +- .../itemlisting/VaultItemListingNavigation.kt | 2 +- .../feature/vault/VaultGraphNavigation.kt | 2 +- .../VaultItemListingViewModelTest.kt | 29 ++++++++++--------- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt index 5a568beb916..a2ba67f4bdd 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt @@ -127,7 +127,8 @@ fun VaultAddEditState.ViewState.appendFolderAndOwnerData( common = currentContentState.common.copy( selectedFolderId = folderViewList.toSelectedFolderId( cipherView = currentContentState.common.originalCipher, - ) ?: currentContentState.common.selectedFolderId, + ) + ?: currentContentState.common.selectedFolderId, availableFolders = folderViewList.toAvailableFolders( resourceManager = resourceManager, ), diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt index 382fc77c42d..e9f424de7e3 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt @@ -93,7 +93,7 @@ fun NavGraphBuilder.vaultItemListingDestinationAsRoot( onNavigateToVaultAddItemScreen: ( cipherType: VaultItemCipherType, selectedFolderId: String?, - ) -> Unit, + ) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, ) { composableWithStayTransitions( diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt index 538b7a55c3e..c1a030d54ed 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt @@ -23,7 +23,7 @@ fun NavGraphBuilder.vaultGraph( onNavigateToVaultAddItemScreen: ( vaultItemCipherType: VaultItemCipherType, selectedFolderId: String?, - ) -> Unit, + ) -> Unit, onNavigateToVaultItemScreen: (vaultItemId: String) -> Unit, onNavigateToVaultEditItemScreen: (vaultItemId: String) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt index 1e21bc9cfb1..6035771f0a4 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingViewModelTest.kt @@ -944,23 +944,24 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { @Suppress("MaxLineLength") @Test - fun `AddVaultItemClick inside a folder should emit NavigateToAddVaultItem with a selected folder id`() = runTest { - val viewModel = createVaultItemListingViewModel( - savedStateHandle = createSavedStateHandleWithVaultItemListingType( - vaultItemListingType = VaultItemListingType.Folder(folderId = "id"), - ), - ) - viewModel.eventFlow.test { - viewModel.trySendAction(VaultItemListingsAction.AddVaultItemClick) - assertEquals( - VaultItemListingEvent.NavigateToAddVaultItem( - VaultItemCipherType.LOGIN, - selectedFolderId = "id", + fun `AddVaultItemClick inside a folder should emit NavigateToAddVaultItem with a selected folder id`() = + runTest { + val viewModel = createVaultItemListingViewModel( + savedStateHandle = createSavedStateHandleWithVaultItemListingType( + vaultItemListingType = VaultItemListingType.Folder(folderId = "id"), ), - awaitItem(), ) + viewModel.eventFlow.test { + viewModel.trySendAction(VaultItemListingsAction.AddVaultItemClick) + assertEquals( + VaultItemListingEvent.NavigateToAddVaultItem( + VaultItemCipherType.LOGIN, + selectedFolderId = "id", + ), + awaitItem(), + ) + } } - } @Test fun `AddVaultItemClick for vault item should emit NavigateToAddVaultItem`() = runTest { From 0387f0b10a00cd9b8b647f777fd081fa4ced446d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Fri, 8 Nov 2024 09:23:36 +0000 Subject: [PATCH 09/13] [PM-11304] Code clean up --- .../feature/addedit/VaultAddEditViewModel.kt | 11 ++- .../addedit/util/CipherViewExtensions.kt | 41 ++++++--- .../itemlisting/VaultItemListingNavigation.kt | 2 +- .../itemlisting/VaultItemListingScreen.kt | 4 +- .../feature/vault/VaultGraphNavigation.kt | 2 +- .../VaultUnlockedNavBarScreenTest.kt | 32 +++++-- .../itemlisting/VaultItemListingScreenTest.kt | 88 ++++++++++++++----- 7 files changed, 131 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt index bc35183f646..ce283d8a58b 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt @@ -217,7 +217,8 @@ class VaultAddEditViewModel @Inject constructor( .onEach(::sendAction) .launchIn(viewModelScope) - featureFlagManager.getFeatureFlagFlow(FlagKey.SshKeyCipherItems) + featureFlagManager + .getFeatureFlagFlow(FlagKey.SshKeyCipherItems) .map { VaultAddEditAction.Internal.SshKeyCipherItemsFeatureFlagReceive(it) } .onEach(::sendAction) .launchIn(viewModelScope) @@ -1094,7 +1095,9 @@ class VaultAddEditViewModel @Inject constructor( updateLoginContent { loginType -> loginType.copy( uriList = loginType.uriList + UriItem( - id = UUID.randomUUID().toString(), + id = UUID + .randomUUID() + .toString(), uri = "", match = null, checksum = null, @@ -2158,7 +2161,9 @@ data class VaultAddEditState( val canEditItem: Boolean = true, val uriList: List = listOf( UriItem( - id = UUID.randomUUID().toString(), + id = UUID + .randomUUID() + .toString(), uri = "", match = null, checksum = null, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt index 318cd8f9e3d..ef4aeb10d94 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt @@ -107,7 +107,9 @@ fun CipherView.toViewState( notes = this.notes.orEmpty(), availableOwners = emptyList(), hasOrganizations = false, - customFieldData = this.fields.orEmpty().map { it.toCustomField() }, + customFieldData = this.fields + .orEmpty() + .map { it.toCustomField() }, ), isIndividualVaultDisabled = isIndividualVaultDisabled, ) @@ -128,7 +130,7 @@ fun VaultAddEditState.ViewState.appendFolderAndOwnerData( selectedFolderId = folderViewList.toSelectedFolderId( cipherView = currentContentState.common.originalCipher, ) - ?: currentContentState.common.selectedFolderId, + ?: currentContentState.common.selectedFolderId, availableFolders = folderViewList.toAvailableFolders( resourceManager = resourceManager, ), @@ -201,11 +203,12 @@ private fun UserState.Account.toAvailableOwners( selectedCollectionId: String? = null, ): List = listOfNotNull( - VaultAddEditState.Owner( - name = email, - id = null, - collections = emptyList(), - ) + VaultAddEditState + .Owner( + name = email, + id = null, + collections = emptyList(), + ) .takeUnless { isIndividualVaultDisabled }, *organizations .map { @@ -236,25 +239,33 @@ private fun UserState.Account.toAvailableOwners( private fun FieldView.toCustomField() = when (this.type) { FieldType.TEXT -> VaultAddEditState.Custom.TextField( - itemId = UUID.randomUUID().toString(), + itemId = UUID + .randomUUID() + .toString(), name = this.name.orEmpty(), value = this.value.orEmpty(), ) FieldType.HIDDEN -> VaultAddEditState.Custom.HiddenField( - itemId = UUID.randomUUID().toString(), + itemId = UUID + .randomUUID() + .toString(), name = this.name.orEmpty(), value = this.value.orEmpty(), ) FieldType.BOOLEAN -> VaultAddEditState.Custom.BooleanField( - itemId = UUID.randomUUID().toString(), + itemId = UUID + .randomUUID() + .toString(), name = this.name.orEmpty(), value = this.value.toBoolean(), ) FieldType.LINKED -> VaultAddEditState.Custom.LinkedField( - itemId = UUID.randomUUID().toString(), + itemId = UUID + .randomUUID() + .toString(), name = this.name.orEmpty(), vaultLinkedFieldType = fromId(requireNotNull(this.linkedId)), ) @@ -291,7 +302,9 @@ private fun List?.toUriItems(): List = if (this.isNullOrEmpty()) { listOf( UriItem( - id = UUID.randomUUID().toString(), + id = UUID + .randomUUID() + .toString(), uri = "", match = null, checksum = null, @@ -300,7 +313,9 @@ private fun List?.toUriItems(): List = } else { this.map { loginUriView -> UriItem( - id = UUID.randomUUID().toString(), + id = UUID + .randomUUID() + .toString(), uri = loginUriView.uri, match = loginUriView.match, checksum = loginUriView.uriChecksum, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt index 2bc0bac02f1..e447270eb5a 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt @@ -95,7 +95,7 @@ fun NavGraphBuilder.vaultItemListingDestinationAsRoot( cipherType: VaultItemCipherType, selectedFolderId: String?, selectedCollectionId: String?, - ) -> Unit, + ) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, ) { composableWithStayTransitions( diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt index 06f0b8dc1b0..9826d332069 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt @@ -113,7 +113,9 @@ fun VaultItemListingScreen( } is VaultItemListingEvent.ShowToast -> { - Toast.makeText(context, event.text(resources), Toast.LENGTH_SHORT).show() + Toast + .makeText(context, event.text(resources), Toast.LENGTH_SHORT) + .show() } is VaultItemListingEvent.NavigateToAddVaultItem -> { diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt index bd57f4d2d98..40069a2f36d 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/vault/VaultGraphNavigation.kt @@ -24,7 +24,7 @@ fun NavGraphBuilder.vaultGraph( vaultItemCipherType: VaultItemCipherType, selectedFolderId: String?, selectedCollectionId: String?, - ) -> Unit, + ) -> Unit, onNavigateToVaultItemScreen: (vaultItemId: String) -> Unit, onNavigateToVaultEditItemScreen: (vaultItemId: String) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt index ca324e073f0..b8b9b337073 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt @@ -63,7 +63,9 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { @Test fun `vault tab click should send VaultTabClick action`() { - composeTestRule.onNodeWithText("My vault").performClick() + composeTestRule + .onNodeWithText("My vault") + .performClick() verify { viewModel.trySendAction(VaultUnlockedNavBarAction.VaultTabClick) } } @@ -120,7 +122,9 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { @Test fun `send tab click should send SendTabClick action`() { - composeTestRule.onNodeWithText("Send").performClick() + composeTestRule + .onNodeWithText("Send") + .performClick() verify { viewModel.trySendAction(VaultUnlockedNavBarAction.SendTabClick) } } @@ -140,7 +144,9 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { @Test fun `generator tab click should send GeneratorTabClick action`() { - composeTestRule.onNodeWithText("Generator").performClick() + composeTestRule + .onNodeWithText("Generator") + .performClick() verify { viewModel.trySendAction(VaultUnlockedNavBarAction.GeneratorTabClick) } } @@ -174,7 +180,9 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { @Test fun `settings tab click should send SendTabClick action`() { - composeTestRule.onNodeWithText("Settings").performClick() + composeTestRule + .onNodeWithText("Settings") + .performClick() verify { viewModel.trySendAction(VaultUnlockedNavBarAction.SettingsTabClick) } } @@ -194,8 +202,12 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { @Test fun `vault nav bar should update according to state`() { - composeTestRule.onNodeWithText("My vault").assertExists() - composeTestRule.onNodeWithText("Vaults").assertDoesNotExist() + composeTestRule + .onNodeWithText("My vault") + .assertExists() + composeTestRule + .onNodeWithText("Vaults") + .assertDoesNotExist() mutableStateFlow.tryEmit( VaultUnlockedNavBarState( @@ -207,8 +219,12 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { ), ) - composeTestRule.onNodeWithText("My vault").assertDoesNotExist() - composeTestRule.onNodeWithText("Vaults").assertExists() + composeTestRule + .onNodeWithText("My vault") + .assertDoesNotExist() + composeTestRule + .onNodeWithText("Vaults") + .assertExists() } @Suppress("MaxLineLength") diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt index 52642bffa36..eac2747e7c0 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt @@ -517,7 +517,9 @@ class VaultItemListingScreenTest : BaseComposeTest() { mutableStateFlow.update { DEFAULT_STATE } // There are 2 because of the pull-to-refresh - composeTestRule.onAllNodes(isProgressBar).assertCountEquals(2) + composeTestRule + .onAllNodes(isProgressBar) + .assertCountEquals(2) mutableStateFlow.update { it.copy( @@ -531,7 +533,9 @@ class VaultItemListingScreenTest : BaseComposeTest() { } // Only pull-to-refresh remains - composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1) + composeTestRule + .onAllNodes(isProgressBar) + .assertCountEquals(1) } @Test @@ -1501,8 +1505,12 @@ class VaultItemListingScreenTest : BaseComposeTest() { ), ) } - composeTestRule.onNode(isDialog()).assertDoesNotExist() - composeTestRule.onNodeWithText(message).assertDoesNotExist() + composeTestRule + .onNode(isDialog()) + .assertDoesNotExist() + composeTestRule + .onNodeWithText(message) + .assertDoesNotExist() composeTestRule .onNodeWithContentDescription("Options") @@ -1534,8 +1542,12 @@ class VaultItemListingScreenTest : BaseComposeTest() { @Test fun `error dialog should be displayed according to state`() { val errorMessage = "Fail" - composeTestRule.onNode(isDialog()).assertDoesNotExist() - composeTestRule.onNodeWithText(errorMessage).assertDoesNotExist() + composeTestRule + .onNode(isDialog()) + .assertDoesNotExist() + composeTestRule + .onNodeWithText(errorMessage) + .assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1555,8 +1567,12 @@ class VaultItemListingScreenTest : BaseComposeTest() { @Test fun `loading dialog should be displayed according to state`() { val loadingMessage = "syncing" - composeTestRule.onNode(isDialog()).assertDoesNotExist() - composeTestRule.onNodeWithText(loadingMessage).assertDoesNotExist() + composeTestRule + .onNode(isDialog()) + .assertDoesNotExist() + composeTestRule + .onNodeWithText(loadingMessage) + .assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1576,8 +1592,12 @@ class VaultItemListingScreenTest : BaseComposeTest() { fun `fido2 master password prompt dialog should display and function according to state`() { val selectedCipherId = "selectedCipherId" val dialogTitle = "Master password confirmation" - composeTestRule.onNode(isDialog()).assertDoesNotExist() - composeTestRule.onNodeWithText(dialogTitle).assertDoesNotExist() + composeTestRule + .onNode(isDialog()) + .assertDoesNotExist() + composeTestRule + .onNodeWithText(dialogTitle) + .assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1635,8 +1655,12 @@ class VaultItemListingScreenTest : BaseComposeTest() { fun `fido2 master password error dialog should display and function according to state`() { val selectedCipherId = "selectedCipherId" val dialogMessage = "Invalid master password. Try again." - composeTestRule.onNode(isDialog()).assertDoesNotExist() - composeTestRule.onNodeWithText(dialogMessage).assertDoesNotExist() + composeTestRule + .onNode(isDialog()) + .assertDoesNotExist() + composeTestRule + .onNodeWithText(dialogMessage) + .assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1670,8 +1694,12 @@ class VaultItemListingScreenTest : BaseComposeTest() { fun `fido2 pin prompt dialog should display and function according to state`() { val selectedCipherId = "selectedCipherId" val dialogTitle = "Verify PIN" - composeTestRule.onNode(isDialog()).assertDoesNotExist() - composeTestRule.onNodeWithText(dialogTitle).assertDoesNotExist() + composeTestRule + .onNode(isDialog()) + .assertDoesNotExist() + composeTestRule + .onNodeWithText(dialogTitle) + .assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1729,8 +1757,12 @@ class VaultItemListingScreenTest : BaseComposeTest() { fun `fido2 pin error dialog should display and function according to state`() { val selectedCipherId = "selectedCipherId" val dialogMessage = "Invalid PIN. Try again." - composeTestRule.onNode(isDialog()).assertDoesNotExist() - composeTestRule.onNodeWithText(dialogMessage).assertDoesNotExist() + composeTestRule + .onNode(isDialog()) + .assertDoesNotExist() + composeTestRule + .onNodeWithText(dialogMessage) + .assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1764,8 +1796,12 @@ class VaultItemListingScreenTest : BaseComposeTest() { fun `fido2 pin set up dialog should display and function according to state`() { val selectedCipherId = "selectedCipherId" val dialogMessage = "Enter your PIN code" - composeTestRule.onNode(isDialog()).assertDoesNotExist() - composeTestRule.onNodeWithText(dialogMessage).assertDoesNotExist() + composeTestRule + .onNode(isDialog()) + .assertDoesNotExist() + composeTestRule + .onNodeWithText(dialogMessage) + .assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1808,8 +1844,12 @@ class VaultItemListingScreenTest : BaseComposeTest() { fun `fido2 pin set up error dialog should display and function according to state`() { val selectedCipherId = "selectedCipherId" val dialogMessage = "The PIN field is required." - composeTestRule.onNode(isDialog()).assertDoesNotExist() - composeTestRule.onNodeWithText(dialogMessage).assertDoesNotExist() + composeTestRule + .onNode(isDialog()) + .assertDoesNotExist() + composeTestRule + .onNodeWithText(dialogMessage) + .assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1837,8 +1877,12 @@ class VaultItemListingScreenTest : BaseComposeTest() { @Test fun `fido2 error dialog should display and function according to state`() { val dialogMessage = "Passkey error message" - composeTestRule.onNode(isDialog()).assertDoesNotExist() - composeTestRule.onNodeWithText(dialogMessage).assertDoesNotExist() + composeTestRule + .onNode(isDialog()) + .assertDoesNotExist() + composeTestRule + .onNodeWithText(dialogMessage) + .assertDoesNotExist() mutableStateFlow.update { it.copy( From a0e3ae0cc253b663dc1bf31836e08b27600d762b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Fri, 8 Nov 2024 09:27:42 +0000 Subject: [PATCH 10/13] [PM-11304] Lint --- .../vault/feature/addedit/util/CipherViewExtensions.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt index ef4aeb10d94..dbb1deda18d 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt @@ -134,12 +134,10 @@ fun VaultAddEditState.ViewState.appendFolderAndOwnerData( availableFolders = folderViewList.toAvailableFolders( resourceManager = resourceManager, ), - selectedOwnerId = activeAccount.toSelectedOwnerId( - cipherView = currentContentState.common.originalCipher, - ) - ?: collectionViewList.firstOrNull { - it.id == currentContentState.common.selectedCollectionId - } + selectedOwnerId = activeAccount + .toSelectedOwnerId(cipherView = currentContentState.common.originalCipher) + ?: collectionViewList + .firstOrNull { it.id == currentContentState.common.selectedCollectionId } ?.organizationId, availableOwners = activeAccount.toAvailableOwners( collectionViewList = collectionViewList, From 7bb0eb2c4be3494161b069b501f0fcf776803ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Tue, 12 Nov 2024 11:10:37 +0000 Subject: [PATCH 11/13] [PM-11304] Fix merge --- .../feature/addedit/VaultAddEditViewModel.kt | 43 +++++++++++++++++++ .../addedit/VaultAddEditViewModelTest.kt | 8 ++++ 2 files changed, 51 insertions(+) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt index ce283d8a58b..42db52ea777 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt @@ -1597,6 +1597,29 @@ class VaultAddEditViewModel @Inject constructor( currentAccount = userData?.activeAccount, vaultAddEditType = vaultAddEditType, ) { currentAccount, cipherView -> + + // Deletion is not allowed when the item is in a collection that the user + // does not have "manage" permission for. + val canDelete = vaultData.collectionViewList + .none { + val isItemInCollection = cipherView + ?.collectionIds + ?.contains(it.id) == true + + isItemInCollection && !it.manage + } + + // Assigning to a collection is not allowed when the item is in a collection + // that the user does not have "manage" and "edit" permission for. + val canAssignToCollections = vaultData.collectionViewList + .none { + val isItemInCollection = cipherView + ?.collectionIds + ?.contains(it.id) == true + + isItemInCollection && (!it.manage || it.readOnly) + } + // Derive the view state from the current Cipher for Edit mode // or use the current state for Add (cipherView @@ -1606,6 +1629,8 @@ class VaultAddEditViewModel @Inject constructor( totpData = totpData, resourceManager = resourceManager, clock = clock, + canDelete = canDelete, + canAssignToCollections = canAssignToCollections, ) ?: viewState) .appendFolderAndOwnerData( @@ -2034,6 +2059,21 @@ data class VaultAddEditState( */ val isCloneMode: Boolean get() = vaultAddEditType is VaultAddEditType.CloneItem + /** + * Helper to determine if the UI should allow deletion of this item. + */ + val canDelete: Boolean + get() = (viewState as? ViewState.Content) + ?.common + ?.canDelete + ?: false + + val canAssociateToCollections: Boolean + get() = (viewState as? ViewState.Content) + ?.common + ?.canAssignToCollections + ?: false + /** * Enum representing the main type options for the vault, such as LOGIN, CARD, etc. * @@ -2093,6 +2133,7 @@ data class VaultAddEditState( * @property selectedOwnerId The ID of the owner associated with the item. * @property availableOwners A list of available owners. * @property hasOrganizations Indicates if the user is part of any organizations. + * @property canDelete Indicates whether the current user can delete the item. */ @Parcelize data class Common( @@ -2110,6 +2151,8 @@ data class VaultAddEditState( val selectedOwnerId: String? = null, val availableOwners: List = emptyList(), val hasOrganizations: Boolean = false, + val canDelete: Boolean = true, + val canAssignToCollections: Boolean = true, ) : Parcelable { /** diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt index 7333f069b82..7e6bb80fae0 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt @@ -25,12 +25,14 @@ import com.x8bit.bitwarden.data.autofill.fido2.model.createMockFido2CredentialRe import com.x8bit.bitwarden.data.autofill.model.AutofillSaveItem import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager +import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState +import com.x8bit.bitwarden.data.platform.manager.model.FlagKey import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance import com.x8bit.bitwarden.data.platform.repository.SettingsRepository @@ -154,6 +156,10 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { every { trackEvent(event = any()) } just runs } + private val featureFlagManager: FeatureFlagManager = mockk(relaxed = true) { + every { getFeatureFlag(FlagKey.SshKeyCipherItems) } returns false + } + @BeforeEach fun setup() { mockkStatic(CipherView::toViewState) @@ -3126,6 +3132,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { resourceManager = resourceManager, clock = fixedClock, organizationEventManager = organizationEventManager, + featureFlagManager = featureFlagManager, ) } @@ -4355,6 +4362,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { resourceManager = bitwardenResourceManager, clock = clock, organizationEventManager = organizationEventManager, + featureFlagManager = featureFlagManager, ) private fun createVaultData( From e722c5567f29da1107daa93062ac6ddd5d0ad039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Wed, 13 Nov 2024 11:08:08 +0000 Subject: [PATCH 12/13] [PM-11304] Fix merge, prevent ssh creation --- .../feature/addedit/VaultAddEditViewModel.kt | 50 +++---------------- .../addedit/VaultAddEditViewModelTest.kt | 8 --- 2 files changed, 8 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt index 42db52ea777..4cf7f5e9685 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt @@ -16,12 +16,10 @@ import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2CredentialRequest import com.x8bit.bitwarden.data.autofill.fido2.model.Fido2RegisterCredentialResult import com.x8bit.bitwarden.data.autofill.fido2.model.UserVerificationRequirement import com.x8bit.bitwarden.data.autofill.util.isActiveWithFido2Credentials -import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager -import com.x8bit.bitwarden.data.platform.manager.model.FlagKey import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent import com.x8bit.bitwarden.data.platform.manager.util.toAutofillSaveItemOrNull import com.x8bit.bitwarden.data.platform.manager.util.toAutofillSelectionDataOrNull @@ -103,7 +101,6 @@ class VaultAddEditViewModel @Inject constructor( private val resourceManager: ResourceManager, private val clock: Clock, private val organizationEventManager: OrganizationEventManager, - private val featureFlagManager: FeatureFlagManager, ) : BaseViewModel( // We load the state from the savedStateHandle for testing purposes. initialState = savedStateHandle[KEY_STATE] @@ -170,11 +167,7 @@ class VaultAddEditViewModel @Inject constructor( // Set special conditions for autofill and fido2 save shouldShowCloseButton = autofillSaveItem == null && fido2AttestationOptions == null, shouldExitOnSave = shouldExitOnSave, - supportedItemTypes = getSupportedItemTypeOptions( - isSshKeyVaultItemSupported = featureFlagManager.getFeatureFlag( - key = FlagKey.SshKeyCipherItems, - ), - ), + supportedItemTypes = getSupportedItemTypeOptions(), ) }, ) { @@ -216,12 +209,6 @@ class VaultAddEditViewModel @Inject constructor( } .onEach(::sendAction) .launchIn(viewModelScope) - - featureFlagManager - .getFeatureFlagFlow(FlagKey.SshKeyCipherItems) - .map { VaultAddEditAction.Internal.SshKeyCipherItemsFeatureFlagReceive(it) } - .onEach(::sendAction) - .launchIn(viewModelScope) } override fun handleAction(action: VaultAddEditAction) { @@ -1450,10 +1437,6 @@ class VaultAddEditViewModel @Inject constructor( is VaultAddEditAction.Internal.ValidateFido2PinResultReceive -> { handleValidateFido2PinResultReceive(action) } - - is VaultAddEditAction.Internal.SshKeyCipherItemsFeatureFlagReceive -> { - handleSshKeyCipherItemsFeatureFlagReceive(action) - } } } @@ -1788,19 +1771,6 @@ class VaultAddEditViewModel @Inject constructor( getRequestAndRegisterCredential() } - - private fun handleSshKeyCipherItemsFeatureFlagReceive( - action: VaultAddEditAction.Internal.SshKeyCipherItemsFeatureFlagReceive, - ) { - mutableStateFlow.update { - it.copy( - supportedItemTypes = getSupportedItemTypeOptions( - isSshKeyVaultItemSupported = action.enabled, - ), - ) - } - } - //endregion Internal Type Handlers //region Utility Functions @@ -3118,13 +3088,6 @@ sealed class VaultAddEditAction { val generatorResult: GeneratorResult, ) : Internal() - /** - * Indicates that the the SSH key vault item feature flag state has been received. - */ - data class SshKeyCipherItemsFeatureFlagReceive( - val enabled: Boolean, - ) : Internal() - /** * Indicates that the vault item data has been received. */ @@ -3179,7 +3142,10 @@ sealed class VaultAddEditAction { } } -private fun getSupportedItemTypeOptions( - isSshKeyVaultItemSupported: Boolean, -) = VaultAddEditState.ItemTypeOption.entries - .filter { isSshKeyVaultItemSupported || it != VaultAddEditState.ItemTypeOption.SSH_KEYS } +/** + * Returns a list of item type options that can be selected during item creation. + * + * TODO: [PM-10413] Allow SSH key creation when the SDK supports it. + */ +private fun getSupportedItemTypeOptions() = VaultAddEditState.ItemTypeOption.entries + .filter { it != VaultAddEditState.ItemTypeOption.SSH_KEYS } diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt index 7e6bb80fae0..7333f069b82 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModelTest.kt @@ -25,14 +25,12 @@ import com.x8bit.bitwarden.data.autofill.fido2.model.createMockFido2CredentialRe import com.x8bit.bitwarden.data.autofill.model.AutofillSaveItem import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager -import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager import com.x8bit.bitwarden.data.platform.manager.event.OrganizationEventManager import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState -import com.x8bit.bitwarden.data.platform.manager.model.FlagKey import com.x8bit.bitwarden.data.platform.manager.model.OrganizationEvent import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance import com.x8bit.bitwarden.data.platform.repository.SettingsRepository @@ -156,10 +154,6 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { every { trackEvent(event = any()) } just runs } - private val featureFlagManager: FeatureFlagManager = mockk(relaxed = true) { - every { getFeatureFlag(FlagKey.SshKeyCipherItems) } returns false - } - @BeforeEach fun setup() { mockkStatic(CipherView::toViewState) @@ -3132,7 +3126,6 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { resourceManager = resourceManager, clock = fixedClock, organizationEventManager = organizationEventManager, - featureFlagManager = featureFlagManager, ) } @@ -4362,7 +4355,6 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { resourceManager = bitwardenResourceManager, clock = clock, organizationEventManager = organizationEventManager, - featureFlagManager = featureFlagManager, ) private fun createVaultData( From 2ecd65e21deba0c067aca7af5f12f9ae8a32379a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Bispo?= Date: Wed, 13 Nov 2024 11:43:51 +0000 Subject: [PATCH 13/13] [PM-11304] Revert unwanted wrap chained functions --- .../feature/addedit/VaultAddEditViewModel.kt | 8 +- .../addedit/util/CipherViewExtensions.kt | 24 ++--- .../itemlisting/VaultItemListingScreen.kt | 4 +- .../VaultUnlockedNavBarScreenTest.kt | 32 ++----- .../itemlisting/VaultItemListingScreenTest.kt | 88 +++++-------------- 5 files changed, 39 insertions(+), 117 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt index 4cf7f5e9685..15ce1b3c91d 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt @@ -1082,9 +1082,7 @@ class VaultAddEditViewModel @Inject constructor( updateLoginContent { loginType -> loginType.copy( uriList = loginType.uriList + UriItem( - id = UUID - .randomUUID() - .toString(), + id = UUID.randomUUID().toString(), uri = "", match = null, checksum = null, @@ -2174,9 +2172,7 @@ data class VaultAddEditState( val canEditItem: Boolean = true, val uriList: List = listOf( UriItem( - id = UUID - .randomUUID() - .toString(), + id = UUID.randomUUID().toString(), uri = "", match = null, checksum = null, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt index a8599757d5b..805dda6e13b 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensions.kt @@ -239,33 +239,25 @@ private fun UserState.Account.toAvailableOwners( private fun FieldView.toCustomField() = when (this.type) { FieldType.TEXT -> VaultAddEditState.Custom.TextField( - itemId = UUID - .randomUUID() - .toString(), + itemId = UUID.randomUUID().toString(), name = this.name.orEmpty(), value = this.value.orEmpty(), ) FieldType.HIDDEN -> VaultAddEditState.Custom.HiddenField( - itemId = UUID - .randomUUID() - .toString(), + itemId = UUID.randomUUID().toString(), name = this.name.orEmpty(), value = this.value.orEmpty(), ) FieldType.BOOLEAN -> VaultAddEditState.Custom.BooleanField( - itemId = UUID - .randomUUID() - .toString(), + itemId = UUID.randomUUID().toString(), name = this.name.orEmpty(), value = this.value.toBoolean(), ) FieldType.LINKED -> VaultAddEditState.Custom.LinkedField( - itemId = UUID - .randomUUID() - .toString(), + itemId = UUID.randomUUID().toString(), name = this.name.orEmpty(), vaultLinkedFieldType = fromId(requireNotNull(this.linkedId)), ) @@ -302,9 +294,7 @@ private fun List?.toUriItems(): List = if (this.isNullOrEmpty()) { listOf( UriItem( - id = UUID - .randomUUID() - .toString(), + id = UUID.randomUUID().toString(), uri = "", match = null, checksum = null, @@ -313,9 +303,7 @@ private fun List?.toUriItems(): List = } else { this.map { loginUriView -> UriItem( - id = UUID - .randomUUID() - .toString(), + id = UUID.randomUUID().toString(), uri = loginUriView.uri, match = loginUriView.match, checksum = loginUriView.uriChecksum, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt index 9826d332069..06f0b8dc1b0 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreen.kt @@ -113,9 +113,7 @@ fun VaultItemListingScreen( } is VaultItemListingEvent.ShowToast -> { - Toast - .makeText(context, event.text(resources), Toast.LENGTH_SHORT) - .show() + Toast.makeText(context, event.text(resources), Toast.LENGTH_SHORT).show() } is VaultItemListingEvent.NavigateToAddVaultItem -> { diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt index b8b9b337073..ca324e073f0 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreenTest.kt @@ -63,9 +63,7 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { @Test fun `vault tab click should send VaultTabClick action`() { - composeTestRule - .onNodeWithText("My vault") - .performClick() + composeTestRule.onNodeWithText("My vault").performClick() verify { viewModel.trySendAction(VaultUnlockedNavBarAction.VaultTabClick) } } @@ -122,9 +120,7 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { @Test fun `send tab click should send SendTabClick action`() { - composeTestRule - .onNodeWithText("Send") - .performClick() + composeTestRule.onNodeWithText("Send").performClick() verify { viewModel.trySendAction(VaultUnlockedNavBarAction.SendTabClick) } } @@ -144,9 +140,7 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { @Test fun `generator tab click should send GeneratorTabClick action`() { - composeTestRule - .onNodeWithText("Generator") - .performClick() + composeTestRule.onNodeWithText("Generator").performClick() verify { viewModel.trySendAction(VaultUnlockedNavBarAction.GeneratorTabClick) } } @@ -180,9 +174,7 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { @Test fun `settings tab click should send SendTabClick action`() { - composeTestRule - .onNodeWithText("Settings") - .performClick() + composeTestRule.onNodeWithText("Settings").performClick() verify { viewModel.trySendAction(VaultUnlockedNavBarAction.SettingsTabClick) } } @@ -202,12 +194,8 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { @Test fun `vault nav bar should update according to state`() { - composeTestRule - .onNodeWithText("My vault") - .assertExists() - composeTestRule - .onNodeWithText("Vaults") - .assertDoesNotExist() + composeTestRule.onNodeWithText("My vault").assertExists() + composeTestRule.onNodeWithText("Vaults").assertDoesNotExist() mutableStateFlow.tryEmit( VaultUnlockedNavBarState( @@ -219,12 +207,8 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() { ), ) - composeTestRule - .onNodeWithText("My vault") - .assertDoesNotExist() - composeTestRule - .onNodeWithText("Vaults") - .assertExists() + composeTestRule.onNodeWithText("My vault").assertDoesNotExist() + composeTestRule.onNodeWithText("Vaults").assertExists() } @Suppress("MaxLineLength") diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt index eac2747e7c0..52642bffa36 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingScreenTest.kt @@ -517,9 +517,7 @@ class VaultItemListingScreenTest : BaseComposeTest() { mutableStateFlow.update { DEFAULT_STATE } // There are 2 because of the pull-to-refresh - composeTestRule - .onAllNodes(isProgressBar) - .assertCountEquals(2) + composeTestRule.onAllNodes(isProgressBar).assertCountEquals(2) mutableStateFlow.update { it.copy( @@ -533,9 +531,7 @@ class VaultItemListingScreenTest : BaseComposeTest() { } // Only pull-to-refresh remains - composeTestRule - .onAllNodes(isProgressBar) - .assertCountEquals(1) + composeTestRule.onAllNodes(isProgressBar).assertCountEquals(1) } @Test @@ -1505,12 +1501,8 @@ class VaultItemListingScreenTest : BaseComposeTest() { ), ) } - composeTestRule - .onNode(isDialog()) - .assertDoesNotExist() - composeTestRule - .onNodeWithText(message) - .assertDoesNotExist() + composeTestRule.onNode(isDialog()).assertDoesNotExist() + composeTestRule.onNodeWithText(message).assertDoesNotExist() composeTestRule .onNodeWithContentDescription("Options") @@ -1542,12 +1534,8 @@ class VaultItemListingScreenTest : BaseComposeTest() { @Test fun `error dialog should be displayed according to state`() { val errorMessage = "Fail" - composeTestRule - .onNode(isDialog()) - .assertDoesNotExist() - composeTestRule - .onNodeWithText(errorMessage) - .assertDoesNotExist() + composeTestRule.onNode(isDialog()).assertDoesNotExist() + composeTestRule.onNodeWithText(errorMessage).assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1567,12 +1555,8 @@ class VaultItemListingScreenTest : BaseComposeTest() { @Test fun `loading dialog should be displayed according to state`() { val loadingMessage = "syncing" - composeTestRule - .onNode(isDialog()) - .assertDoesNotExist() - composeTestRule - .onNodeWithText(loadingMessage) - .assertDoesNotExist() + composeTestRule.onNode(isDialog()).assertDoesNotExist() + composeTestRule.onNodeWithText(loadingMessage).assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1592,12 +1576,8 @@ class VaultItemListingScreenTest : BaseComposeTest() { fun `fido2 master password prompt dialog should display and function according to state`() { val selectedCipherId = "selectedCipherId" val dialogTitle = "Master password confirmation" - composeTestRule - .onNode(isDialog()) - .assertDoesNotExist() - composeTestRule - .onNodeWithText(dialogTitle) - .assertDoesNotExist() + composeTestRule.onNode(isDialog()).assertDoesNotExist() + composeTestRule.onNodeWithText(dialogTitle).assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1655,12 +1635,8 @@ class VaultItemListingScreenTest : BaseComposeTest() { fun `fido2 master password error dialog should display and function according to state`() { val selectedCipherId = "selectedCipherId" val dialogMessage = "Invalid master password. Try again." - composeTestRule - .onNode(isDialog()) - .assertDoesNotExist() - composeTestRule - .onNodeWithText(dialogMessage) - .assertDoesNotExist() + composeTestRule.onNode(isDialog()).assertDoesNotExist() + composeTestRule.onNodeWithText(dialogMessage).assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1694,12 +1670,8 @@ class VaultItemListingScreenTest : BaseComposeTest() { fun `fido2 pin prompt dialog should display and function according to state`() { val selectedCipherId = "selectedCipherId" val dialogTitle = "Verify PIN" - composeTestRule - .onNode(isDialog()) - .assertDoesNotExist() - composeTestRule - .onNodeWithText(dialogTitle) - .assertDoesNotExist() + composeTestRule.onNode(isDialog()).assertDoesNotExist() + composeTestRule.onNodeWithText(dialogTitle).assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1757,12 +1729,8 @@ class VaultItemListingScreenTest : BaseComposeTest() { fun `fido2 pin error dialog should display and function according to state`() { val selectedCipherId = "selectedCipherId" val dialogMessage = "Invalid PIN. Try again." - composeTestRule - .onNode(isDialog()) - .assertDoesNotExist() - composeTestRule - .onNodeWithText(dialogMessage) - .assertDoesNotExist() + composeTestRule.onNode(isDialog()).assertDoesNotExist() + composeTestRule.onNodeWithText(dialogMessage).assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1796,12 +1764,8 @@ class VaultItemListingScreenTest : BaseComposeTest() { fun `fido2 pin set up dialog should display and function according to state`() { val selectedCipherId = "selectedCipherId" val dialogMessage = "Enter your PIN code" - composeTestRule - .onNode(isDialog()) - .assertDoesNotExist() - composeTestRule - .onNodeWithText(dialogMessage) - .assertDoesNotExist() + composeTestRule.onNode(isDialog()).assertDoesNotExist() + composeTestRule.onNodeWithText(dialogMessage).assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1844,12 +1808,8 @@ class VaultItemListingScreenTest : BaseComposeTest() { fun `fido2 pin set up error dialog should display and function according to state`() { val selectedCipherId = "selectedCipherId" val dialogMessage = "The PIN field is required." - composeTestRule - .onNode(isDialog()) - .assertDoesNotExist() - composeTestRule - .onNodeWithText(dialogMessage) - .assertDoesNotExist() + composeTestRule.onNode(isDialog()).assertDoesNotExist() + composeTestRule.onNodeWithText(dialogMessage).assertDoesNotExist() mutableStateFlow.update { it.copy( @@ -1877,12 +1837,8 @@ class VaultItemListingScreenTest : BaseComposeTest() { @Test fun `fido2 error dialog should display and function according to state`() { val dialogMessage = "Passkey error message" - composeTestRule - .onNode(isDialog()) - .assertDoesNotExist() - composeTestRule - .onNodeWithText(dialogMessage) - .assertDoesNotExist() + composeTestRule.onNode(isDialog()).assertDoesNotExist() + composeTestRule.onNodeWithText(dialogMessage).assertDoesNotExist() mutableStateFlow.update { it.copy(