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 98fa14fca..1c96b4a94 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 5345f8873..a6a43bf39 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 5acc57ecd..d40df2294 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 @@ -62,7 +62,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, @@ -156,7 +156,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 aa130f7f5..c62ceb612 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,7 @@ private const val ADD_EDIT_ITEM_ROUTE: String = data class VaultAddEditArgs( val vaultAddEditType: VaultAddEditType, val selectedFolderId: String? = null, + val selectedCollectionId: String? = null, ) { constructor(savedStateHandle: SavedStateHandle) : this( vaultAddEditType = when (requireNotNull(savedStateHandle[ADD_EDIT_ITEM_TYPE])) { @@ -57,6 +60,7 @@ data class VaultAddEditArgs( else -> throw IllegalStateException("Unknown VaultAddEditType.") }, selectedFolderId = savedStateHandle[ADD_SELECTED_FOLDER_ID], + selectedCollectionId = savedStateHandle[ADD_SELECTED_COLLECTION_ID], ) } @@ -80,6 +84,10 @@ fun NavGraphBuilder.vaultAddEditDestination( type = NavType.StringType nullable = true }, + navArgument(ADD_SELECTED_COLLECTION_ID) { + type = NavType.StringType + nullable = true + }, ), ) { VaultAddEditScreen( @@ -99,13 +107,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/addedit/VaultAddEditViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt index f34ab583d..15ce1b3c9 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 @@ -107,6 +107,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() @@ -147,12 +148,11 @@ class VaultAddEditViewModel @Inject constructor( attestationOptions = fido2AttestationOptions, isIndividualVaultDisabled = isIndividualVaultDisabled, ) - ?: totpData?.toDefaultAddTypeContent( - isIndividualVaultDisabled = isIndividualVaultDisabled, - ) + ?: totpData?.toDefaultAddTypeContent(isIndividualVaultDisabled) ?: VaultAddEditState.ViewState.Content( common = VaultAddEditState.ViewState.Content.Common( selectedFolderId = selectedFolderId, + selectedCollectionId = selectedCollectionId, ), isIndividualVaultDisabled = isIndividualVaultDisabled, type = vaultAddEditType.vaultItemCipherType.toItemType(), @@ -2113,6 +2113,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 cc5776772..805dda6e1 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 @@ -132,17 +132,20 @@ fun VaultAddEditState.ViewState.appendFolderAndOwnerData( 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, - ), + 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(), @@ -197,13 +200,15 @@ private fun UserState.Account.toAvailableOwners( collectionViewList: List, cipherView: CipherView?, isIndividualVaultDisabled: Boolean, + 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 { @@ -219,9 +224,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/VaultItemListingNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/VaultItemListingNavigation.kt index e9f424de7..e447270eb 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 122a93b21..5a8360bf1 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 @@ -74,6 +74,7 @@ fun VaultItemListingScreen( onNavigateToVaultAddItemScreen: ( vaultItemCipherType: VaultItemCipherType, selectedFolderId: String?, + selectedCollectionId: String?, ) -> Unit, onNavigateToAddSendItem: () -> Unit, onNavigateToEditSendItem: (sendId: String) -> Unit, @@ -118,6 +119,7 @@ fun VaultItemListingScreen( onNavigateToVaultAddItemScreen( event.vaultItemCipherType, event.selectedFolderId, + event.selectedCollectionId, ) } @@ -446,7 +448,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 d07c744e4..57d289093 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(), @@ -1739,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. */ @@ -2111,7 +2125,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 } } @@ -2158,6 +2172,7 @@ sealed class VaultItemListingEvent { data class NavigateToAddVaultItem( val vaultItemCipherType: VaultItemCipherType, val selectedFolderId: String? = null, + val selectedCollectionId: 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 c1a030d54..40069a2f3 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 6311356eb..ca324e073 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 de75be94c..52642bffa 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 },