From 992bafc16c59c9d78de91b5ec2fd82be1b768f5f Mon Sep 17 00:00:00 2001 From: Ramsey Smith <142836716+ramsey-livefront@users.noreply.github.com> Date: Tue, 26 Mar 2024 11:32:03 -0600 Subject: [PATCH] BIT-2128: Item creation screen cipher type error (#1169) --- .../platform/feature/rootnav/RootNavScreen.kt | 5 +- .../vaultunlocked/VaultUnlockedNavigation.kt | 4 +- .../VaultUnlockedNavBarNavigation.kt | 3 +- .../VaultUnlockedNavBarScreen.kt | 5 +- .../feature/addedit/VaultAddEditNavigation.kt | 27 ++++++- .../feature/addedit/VaultAddEditViewModel.kt | 29 ++++---- .../addedit/util/VaultAddEditExtensions.kt | 13 ++++ .../itemlisting/VaultItemListingNavigation.kt | 7 +- .../itemlisting/VaultItemListingScreen.kt | 5 +- .../itemlisting/VaultItemListingViewModel.kt | 12 +++- .../util/VaultItemListingStateExtensions.kt | 16 +++++ .../feature/vault/VaultGraphNavigation.kt | 7 +- .../ui/vault/model/VaultAddEditType.kt | 6 +- .../ui/vault/model/VaultItemCipherType.kt | 27 +++++++ .../feature/addedit/VaultAddEditScreenTest.kt | 15 ++-- .../addedit/VaultAddEditViewModelTest.kt | 70 ++++++++++--------- .../addedit/util/CipherViewExtensionsTest.kt | 5 +- .../util/VaultAddEditExtensionsTest.kt | 48 +++++++++++++ .../itemlisting/VaultItemListingScreenTest.kt | 5 +- .../VaultItemListingViewModelTest.kt | 6 +- .../VaultItemListingStateExtensionsTest.kt | 41 +++++++++++ 21 files changed, 279 insertions(+), 77 deletions(-) create mode 100644 app/src/main/java/com/x8bit/bitwarden/ui/vault/model/VaultItemCipherType.kt create mode 100644 app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/VaultAddEditExtensionsTest.kt diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavScreen.kt index c2a853bdc8..08c58c8da8 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavScreen.kt @@ -40,6 +40,7 @@ import com.x8bit.bitwarden.ui.tools.feature.send.addsend.navigateToAddSend import com.x8bit.bitwarden.ui.vault.feature.addedit.navigateToVaultAddEdit import com.x8bit.bitwarden.ui.vault.feature.itemlisting.navigateToVaultItemListingAsRoot import com.x8bit.bitwarden.ui.vault.model.VaultAddEditType +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import java.util.concurrent.atomic.AtomicReference @@ -147,7 +148,9 @@ fun RootNavScreen( is RootNavState.VaultUnlockedForAutofillSave -> { navController.navigateToVaultUnlockedGraph(rootNavOptions) navController.navigateToVaultAddEdit( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem( + vaultItemCipherType = VaultItemCipherType.LOGIN, + ), navOptions = rootNavOptions, ) } 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 3c598491a4..94028600db 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 @@ -68,7 +68,7 @@ fun NavGraphBuilder.vaultUnlockedGraph( onNavigateBack = { navController.popBackStack() }, onNavigateToVaultItemScreen = { navController.navigateToVaultItem(vaultItemId = it) }, onNavigateToVaultAddItemScreen = { - navController.navigateToVaultAddEdit(VaultAddEditType.AddItem) + navController.navigateToVaultAddEdit(VaultAddEditType.AddItem(it)) }, onNavigateToSearchVault = { navController.navigateToSearch(searchType = it) }, onNavigateToVaultEditItemScreen = { @@ -79,7 +79,7 @@ fun NavGraphBuilder.vaultUnlockedGraph( onNavigateToExportVault = { navController.navigateToExportVault() }, onNavigateToFolders = { navController.navigateToFolders() }, onNavigateToVaultAddItem = { - navController.navigateToVaultAddEdit(VaultAddEditType.AddItem) + navController.navigateToVaultAddEdit(VaultAddEditType.AddItem(it)) }, 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 4cbef03536..48bd04f2f0 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 @@ -5,6 +5,7 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import com.x8bit.bitwarden.ui.platform.base.util.composableWithStayTransitions import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType /** * The functions below pertain to entry into the [VaultUnlockedNavBarScreen]. @@ -23,7 +24,7 @@ fun NavController.navigateToVaultUnlockedNavBar(navOptions: NavOptions? = null) */ @Suppress("LongParameterList") fun NavGraphBuilder.vaultUnlockedNavBarDestination( - onNavigateToVaultAddItem: () -> Unit, + onNavigateToVaultAddItem: (VaultItemCipherType) -> 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 c61d8f895a..f46a41ab5d 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 @@ -63,6 +63,7 @@ import com.x8bit.bitwarden.ui.tools.feature.send.sendGraph import com.x8bit.bitwarden.ui.vault.feature.vault.VAULT_GRAPH_ROUTE import com.x8bit.bitwarden.ui.vault.feature.vault.navigateToVaultGraph import com.x8bit.bitwarden.ui.vault.feature.vault.vaultGraph +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.parcelize.Parcelize @@ -75,7 +76,7 @@ import kotlinx.parcelize.Parcelize fun VaultUnlockedNavBarScreen( viewModel: VaultUnlockedNavBarViewModel = hiltViewModel(), navController: NavHostController = rememberNavController(), - onNavigateToVaultAddItem: () -> Unit, + onNavigateToVaultAddItem: (VaultItemCipherType) -> Unit, onNavigateToVaultItem: (vaultItemId: String) -> Unit, onNavigateToVaultEditItem: (vaultItemId: String) -> Unit, onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit, @@ -160,7 +161,7 @@ private fun VaultUnlockedNavBarScaffold( sendTabClickedAction: () -> Unit, generatorTabClickedAction: () -> Unit, settingsTabClickedAction: () -> Unit, - navigateToVaultAddItem: () -> Unit, + navigateToVaultAddItem: (VaultItemCipherType) -> 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 213aaa4062..5d58cc219d 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 @@ -10,17 +10,23 @@ import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage import com.x8bit.bitwarden.ui.platform.base.util.composableWithSlideTransitions import com.x8bit.bitwarden.ui.tools.feature.generator.model.GeneratorMode import com.x8bit.bitwarden.ui.vault.model.VaultAddEditType +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType private const val ADD_TYPE: String = "add" private const val EDIT_TYPE: String = "edit" private const val CLONE_TYPE: String = "clone" private const val EDIT_ITEM_ID: String = "vault_edit_id" +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_EDIT_ITEM_ROUTE: String = - "$ADD_EDIT_ITEM_PREFIX/{$ADD_EDIT_ITEM_TYPE}?$EDIT_ITEM_ID={$EDIT_ITEM_ID}" + ADD_EDIT_ITEM_PREFIX + + "/{$ADD_EDIT_ITEM_TYPE}" + + "?$EDIT_ITEM_ID={$EDIT_ITEM_ID}" + + "?$ADD_ITEM_TYPE={$ADD_ITEM_TYPE}" /** * Class to retrieve vault add & edit arguments from the [SavedStateHandle]. @@ -31,7 +37,12 @@ data class VaultAddEditArgs( ) { constructor(savedStateHandle: SavedStateHandle) : this( vaultAddEditType = when (requireNotNull(savedStateHandle[ADD_EDIT_ITEM_TYPE])) { - ADD_TYPE -> VaultAddEditType.AddItem + ADD_TYPE -> VaultAddEditType.AddItem( + vaultItemCipherType = requireNotNull( + savedStateHandle.get(ADD_ITEM_TYPE), + ), + ) + EDIT_TYPE -> VaultAddEditType.EditItem(requireNotNull(savedStateHandle[EDIT_ITEM_ID])) CLONE_TYPE -> VaultAddEditType.CloneItem(requireNotNull(savedStateHandle[EDIT_ITEM_ID])) else -> throw IllegalStateException("Unknown VaultAddEditType.") @@ -55,6 +66,7 @@ fun NavGraphBuilder.vaultAddEditDestination( route = ADD_EDIT_ITEM_ROUTE, arguments = listOf( navArgument(ADD_EDIT_ITEM_TYPE) { type = NavType.StringType }, + navArgument(ADD_ITEM_TYPE) { type = NavType.EnumType(VaultItemCipherType::class.java) }, ), ) { VaultAddEditScreen( @@ -77,7 +89,8 @@ fun NavController.navigateToVaultAddEdit( ) { navigate( route = "$ADD_EDIT_ITEM_PREFIX/${vaultAddEditType.toTypeString()}" + - "?$EDIT_ITEM_ID=${vaultAddEditType.toIdOrNull()}", + "?$EDIT_ITEM_ID=${vaultAddEditType.toIdOrNull()}" + + "?$ADD_ITEM_TYPE=${vaultAddEditType.toVaultItemCipherTypeOrNull()}", navOptions = navOptions, ) } @@ -95,3 +108,11 @@ private fun VaultAddEditType.toIdOrNull(): String? = is VaultAddEditType.CloneItem -> vaultItemId is VaultAddEditType.EditItem -> vaultItemId } + +private fun VaultAddEditType.toVaultItemCipherTypeOrNull(): VaultItemCipherType? = + when (this) { + is VaultAddEditType.AddItem -> vaultItemCipherType + is VaultAddEditType.CloneItem, + is VaultAddEditType.EditItem, + -> null + } 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 3b2b1f1875..9dd12741b9 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 @@ -37,6 +37,7 @@ import com.x8bit.bitwarden.ui.vault.feature.addedit.model.UriItem import com.x8bit.bitwarden.ui.vault.feature.addedit.model.toCustomField import com.x8bit.bitwarden.ui.vault.feature.addedit.util.appendFolderAndOwnerData import com.x8bit.bitwarden.ui.vault.feature.addedit.util.toDefaultAddTypeContent +import com.x8bit.bitwarden.ui.vault.feature.addedit.util.toItemType import com.x8bit.bitwarden.ui.vault.feature.addedit.util.toViewState import com.x8bit.bitwarden.ui.vault.feature.addedit.util.validateCipherOrReturnErrorState import com.x8bit.bitwarden.ui.vault.feature.vault.util.toCipherView @@ -111,20 +112,20 @@ class VaultAddEditViewModel @Inject constructor( null } - val defaultAddTypeContent = autofillSelectionData - ?.toDefaultAddTypeContent(isIndividualVaultDisabled) - ?: autofillSaveItem - ?.toDefaultAddTypeContent(isIndividualVaultDisabled) - ?: VaultAddEditState.ViewState.Content( - common = VaultAddEditState.ViewState.Content.Common(), - isIndividualVaultDisabled = isIndividualVaultDisabled, - type = VaultAddEditState.ViewState.Content.ItemType.Login(), - ) - VaultAddEditState( vaultAddEditType = vaultAddEditType, viewState = when (vaultAddEditType) { - VaultAddEditType.AddItem -> defaultAddTypeContent + is VaultAddEditType.AddItem -> { + autofillSelectionData + ?.toDefaultAddTypeContent(isIndividualVaultDisabled) + ?: autofillSaveItem + ?.toDefaultAddTypeContent(isIndividualVaultDisabled) + ?: VaultAddEditState.ViewState.Content( + common = VaultAddEditState.ViewState.Content.Common(), + isIndividualVaultDisabled = isIndividualVaultDisabled, + type = vaultAddEditType.vaultItemCipherType.toItemType(), + ) + } is VaultAddEditType.EditItem -> VaultAddEditState.ViewState.Loading is VaultAddEditType.CloneItem -> VaultAddEditState.ViewState.Loading }, @@ -318,7 +319,7 @@ class VaultAddEditViewModel @Inject constructor( viewModelScope.launch { when (val vaultAddEditType = state.vaultAddEditType) { - VaultAddEditType.AddItem -> { + is VaultAddEditType.AddItem -> { val result = content.createCipherForAddAndCloneItemStates() sendAction(VaultAddEditAction.Internal.CreateCipherResultReceive(result)) } @@ -1425,7 +1426,7 @@ data class VaultAddEditState( */ val screenDisplayName: Text get() = when (vaultAddEditType) { - VaultAddEditType.AddItem -> R.string.add_item.asText() + is VaultAddEditType.AddItem -> R.string.add_item.asText() is VaultAddEditType.EditItem -> R.string.edit_item.asText() is VaultAddEditType.CloneItem -> R.string.add_item.asText() } @@ -1444,7 +1445,7 @@ data class VaultAddEditState( /** * Helper to determine if the UI should display the content in add item mode. */ - val isAddItemMode: Boolean get() = vaultAddEditType == VaultAddEditType.AddItem + val isAddItemMode: Boolean get() = vaultAddEditType is VaultAddEditType.AddItem /** * Helper to determine if the UI should display the content in clone mode. diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/VaultAddEditExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/VaultAddEditExtensions.kt index d7674ece94..807c43f22d 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/VaultAddEditExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/VaultAddEditExtensions.kt @@ -4,6 +4,8 @@ import com.x8bit.bitwarden.R import com.x8bit.bitwarden.ui.platform.base.util.Text import com.x8bit.bitwarden.ui.platform.base.util.asText import com.x8bit.bitwarden.ui.platform.base.util.concat +import com.x8bit.bitwarden.ui.vault.feature.addedit.VaultAddEditState +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType /** * Default, "select" Text to show on multi select buttons in the VaultAddEdit package. @@ -13,3 +15,14 @@ val SELECT_TEXT: Text .asText() .concat(R.string.select.asText()) .concat(" --".asText()) + +/** + * Transforms a [VaultItemCipherType] into [VaultAddEditState.ViewState.Content.ItemType]. + */ +fun VaultItemCipherType.toItemType(): VaultAddEditState.ViewState.Content.ItemType = + when (this) { + VaultItemCipherType.LOGIN -> VaultAddEditState.ViewState.Content.ItemType.Login() + VaultItemCipherType.CARD -> VaultAddEditState.ViewState.Content.ItemType.Card() + VaultItemCipherType.IDENTITY -> VaultAddEditState.ViewState.Content.ItemType.Identity() + VaultItemCipherType.SECURE_NOTE -> VaultAddEditState.ViewState.Content.ItemType.SecureNotes + } 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 5fffa7661c..daf653fed9 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 @@ -10,6 +10,7 @@ import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage import com.x8bit.bitwarden.ui.platform.base.util.composableWithPushTransitions import com.x8bit.bitwarden.ui.platform.base.util.composableWithStayTransitions import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType private const val CARD: String = "card" @@ -62,7 +63,7 @@ fun NavGraphBuilder.vaultItemListingDestination( onNavigateToVaultItemScreen: (id: String) -> Unit, onNavigateToVaultEditItemScreen: (cipherId: String) -> Unit, onNavigateToVaultItemListing: (vaultItemListingType: VaultItemListingType) -> Unit, - onNavigateToVaultAddItemScreen: () -> Unit, + onNavigateToVaultAddItemScreen: (vaultItemCipherType: VaultItemCipherType) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, ) { internalVaultItemListingDestination( @@ -85,7 +86,7 @@ fun NavGraphBuilder.vaultItemListingDestinationAsRoot( onNavigateBack: () -> Unit, onNavigateToVaultItemScreen: (id: String) -> Unit, onNavigateToVaultEditItemScreen: (cipherId: String) -> Unit, - onNavigateToVaultAddItemScreen: () -> Unit, + onNavigateToVaultAddItemScreen: (VaultItemCipherType) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, ) { composableWithStayTransitions( @@ -144,7 +145,7 @@ private fun NavGraphBuilder.internalVaultItemListingDestination( onNavigateToVaultItemScreen: (id: String) -> Unit, onNavigateToVaultEditItemScreen: (cipherId: String) -> Unit, onNavigateToVaultItemListing: (vaultItemListingType: VaultItemListingType) -> Unit, - onNavigateToVaultAddItemScreen: () -> Unit, + onNavigateToVaultAddItemScreen: (vaultItemCipherType: VaultItemCipherType) -> 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 e905b78e4a..35bbe2ec90 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 @@ -49,6 +49,7 @@ import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager import com.x8bit.bitwarden.ui.platform.theme.LocalIntentManager import com.x8bit.bitwarden.ui.vault.feature.itemlisting.handlers.VaultItemListingHandlers import com.x8bit.bitwarden.ui.vault.feature.vault.util.initials +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @@ -64,7 +65,7 @@ fun VaultItemListingScreen( onNavigateToVaultItem: (id: String) -> Unit, onNavigateToVaultEditItemScreen: (cipherVaultId: String) -> Unit, onNavigateToVaultItemListing: (vaultItemListingType: VaultItemListingType) -> Unit, - onNavigateToVaultAddItemScreen: () -> Unit, + onNavigateToVaultAddItemScreen: (vaultItemCipherType: VaultItemCipherType) -> Unit, onNavigateToAddSendItem: () -> Unit, onNavigateToEditSendItem: (sendId: String) -> Unit, onNavigateToSearch: (searchType: SearchType) -> Unit, @@ -100,7 +101,7 @@ fun VaultItemListingScreen( } is VaultItemListingEvent.NavigateToAddVaultItem -> { - onNavigateToVaultAddItemScreen() + onNavigateToVaultAddItemScreen(event.vaultItemCipherType) } 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 221a5db315..0643aadf7f 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 @@ -38,12 +38,14 @@ import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflo import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.determineListingPredicate import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.toItemListingType import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.toSearchType +import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.toVaultItemCipherType import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.toViewState import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.updateWithAdditionalDataIfNecessary import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType import com.x8bit.bitwarden.ui.vault.feature.vault.util.toAccountSummaries import com.x8bit.bitwarden.ui.vault.feature.vault.util.toActiveAccountSummary import com.x8bit.bitwarden.ui.vault.feature.vault.util.toFilteredList +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map @@ -228,9 +230,11 @@ class VaultItemListingViewModel @Inject constructor( } private fun handleAddVaultItemClick() { - val event = when (state.itemListingType) { + val event = when (val itemListingType = state.itemListingType) { is VaultItemListingState.ItemListingType.Vault -> { - VaultItemListingEvent.NavigateToAddVaultItem + VaultItemListingEvent.NavigateToAddVaultItem( + vaultItemCipherType = itemListingType.toVaultItemCipherType(), + ) } is VaultItemListingState.ItemListingType.Send -> { @@ -1057,7 +1061,9 @@ sealed class VaultItemListingEvent { /** * Navigates to the VaultAddItemScreen. */ - data object NavigateToAddVaultItem : VaultItemListingEvent() + data class NavigateToAddVaultItem( + val vaultItemCipherType: VaultItemCipherType, + ) : VaultItemListingEvent() /** * Navigates to the collection. 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 65f2b3e7c1..e285b30ba9 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 @@ -2,6 +2,7 @@ package com.x8bit.bitwarden.ui.vault.feature.itemlisting.util import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingState +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType /** * Transforms a [VaultItemListingState.ItemListingType] into a [SearchType]. @@ -26,3 +27,18 @@ fun VaultItemListingState.ItemListingType.toSearchType(): SearchType = is VaultItemListingState.ItemListingType.Send.SendFile -> SearchType.Sends.Files is VaultItemListingState.ItemListingType.Send.SendText -> SearchType.Sends.Texts } + +/** + * Transforms a [VaultItemListingState.ItemListingType.Vault] into a [VaultItemCipherType]. + */ +fun VaultItemListingState.ItemListingType.Vault.toVaultItemCipherType(): VaultItemCipherType = + when (this) { + is VaultItemListingState.ItemListingType.Vault.Card -> VaultItemCipherType.CARD + is VaultItemListingState.ItemListingType.Vault.Identity -> VaultItemCipherType.IDENTITY + is VaultItemListingState.ItemListingType.Vault.SecureNote -> VaultItemCipherType.SECURE_NOTE + is VaultItemListingState.ItemListingType.Vault.Login -> VaultItemCipherType.LOGIN + is VaultItemListingState.ItemListingType.Vault.Trash, + is VaultItemListingState.ItemListingType.Vault.Collection, + is VaultItemListingState.ItemListingType.Vault.Folder, + -> throw IllegalStateException("Cannot create vault item from this VaultItemListingState!") + } 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 7904af5850..40a83b9628 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 @@ -9,6 +9,7 @@ import com.x8bit.bitwarden.ui.vault.feature.itemlisting.navigateToVaultItemListi import com.x8bit.bitwarden.ui.vault.feature.itemlisting.vaultItemListingDestination import com.x8bit.bitwarden.ui.vault.feature.verificationcode.navigateToVerificationCodeScreen import com.x8bit.bitwarden.ui.vault.feature.verificationcode.vaultVerificationCodeDestination +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType const val VAULT_GRAPH_ROUTE: String = "vault_graph" @@ -18,7 +19,7 @@ const val VAULT_GRAPH_ROUTE: String = "vault_graph" @Suppress("LongParameterList") fun NavGraphBuilder.vaultGraph( navController: NavController, - onNavigateToVaultAddItemScreen: () -> Unit, + onNavigateToVaultAddItemScreen: (vaultItemCipherType: VaultItemCipherType) -> Unit, onNavigateToVaultItemScreen: (vaultItemId: String) -> Unit, onNavigateToVaultEditItemScreen: (vaultItemId: String) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, @@ -29,7 +30,9 @@ fun NavGraphBuilder.vaultGraph( startDestination = VAULT_ROUTE, ) { vaultDestination( - onNavigateToVaultAddItemScreen = onNavigateToVaultAddItemScreen, + onNavigateToVaultAddItemScreen = { + onNavigateToVaultAddItemScreen(VaultItemCipherType.LOGIN) + }, onNavigateToVaultItemScreen = onNavigateToVaultItemScreen, onNavigateToVaultEditItemScreen = onNavigateToVaultEditItemScreen, onNavigateToVaultItemListingScreen = { navController.navigateToVaultItemListing(it) }, diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/model/VaultAddEditType.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/model/VaultAddEditType.kt index 8ed396a917..c6e6f7f100 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/model/VaultAddEditType.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/model/VaultAddEditType.kt @@ -15,9 +15,13 @@ sealed class VaultAddEditType : Parcelable { /** * Indicates that we want to create a completely new vault item. + * + * @property vaultItemCipherType The specified [VaultItemCipherType]. */ @Parcelize - data object AddItem : VaultAddEditType() { + data class AddItem( + val vaultItemCipherType: VaultItemCipherType, + ) : VaultAddEditType() { override val vaultItemId: String? get() = null } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/model/VaultItemCipherType.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/model/VaultItemCipherType.kt new file mode 100644 index 0000000000..a44c95207d --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/model/VaultItemCipherType.kt @@ -0,0 +1,27 @@ +package com.x8bit.bitwarden.ui.vault.model + +/** + * Represents different types of ciphers that can be added/viewed. + */ +enum class VaultItemCipherType { + + /** + * A login cipher. + */ + LOGIN, + + /** + * A card cipher. + */ + CARD, + + /** + * A identity cipher. + */ + IDENTITY, + + /** + * A secure note cipher. + */ + SECURE_NOTE, +} diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt index 83c4188cab..5515f9fe9c 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt @@ -54,6 +54,7 @@ import com.x8bit.bitwarden.ui.vault.model.VaultCardBrand import com.x8bit.bitwarden.ui.vault.model.VaultCardExpirationMonth import com.x8bit.bitwarden.ui.vault.model.VaultCollection import com.x8bit.bitwarden.ui.vault.model.VaultIdentityTitle +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType import io.mockk.every import io.mockk.just import io.mockk.mockk @@ -2602,7 +2603,7 @@ class VaultAddEditScreenTest : BaseComposeTest() { fun `should display policy warning when personal vault is disabled for add item type`() { mutableStateFlow.update { it.copy( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), viewState = VaultAddEditState.ViewState.Content( common = VaultAddEditState.ViewState.Content.Common( originalCipher = createMockCipherView(1), @@ -2853,11 +2854,11 @@ class VaultAddEditScreenTest : BaseComposeTest() { isIndividualVaultDisabled = false, ), dialog = VaultAddEditState.DialogState.Generic(message = "test".asText()), - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ) private val DEFAULT_STATE_LOGIN = VaultAddEditState( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), viewState = VaultAddEditState.ViewState.Content( common = VaultAddEditState.ViewState.Content.Common(), type = VaultAddEditState.ViewState.Content.ItemType.Login(), @@ -2867,7 +2868,7 @@ class VaultAddEditScreenTest : BaseComposeTest() { ) private val DEFAULT_STATE_IDENTITY = VaultAddEditState( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.IDENTITY), viewState = VaultAddEditState.ViewState.Content( common = VaultAddEditState.ViewState.Content.Common(), type = VaultAddEditState.ViewState.Content.ItemType.Identity(), @@ -2877,7 +2878,7 @@ class VaultAddEditScreenTest : BaseComposeTest() { ) private val DEFAULT_STATE_CARD = VaultAddEditState( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.CARD), viewState = VaultAddEditState.ViewState.Content( common = VaultAddEditState.ViewState.Content.Common(), type = VaultAddEditState.ViewState.Content.ItemType.Card(), @@ -2904,11 +2905,11 @@ class VaultAddEditScreenTest : BaseComposeTest() { isIndividualVaultDisabled = false, ), dialog = null, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.SECURE_NOTE), ) private val DEFAULT_STATE_SECURE_NOTES = VaultAddEditState( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.SECURE_NOTE), viewState = VaultAddEditState.ViewState.Content( common = VaultAddEditState.ViewState.Content.Common(), type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes, 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 77930beb4e..1c1baf5d4b 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 @@ -52,6 +52,7 @@ import com.x8bit.bitwarden.ui.vault.model.VaultCardBrand import com.x8bit.bitwarden.ui.vault.model.VaultCardExpirationMonth import com.x8bit.bitwarden.ui.vault.model.VaultCollection import com.x8bit.bitwarden.ui.vault.model.VaultIdentityTitle +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType import com.x8bit.bitwarden.ui.vault.model.VaultLinkedFieldType import io.mockk.coEvery import io.mockk.coVerify @@ -97,7 +98,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { ) private val loginInitialSavedStateHandle = createSavedStateHandleWithState( state = loginInitialState, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ) private val totpTestCodeFlow: MutableSharedFlow = bufferedMutableSharedFlow() @@ -139,7 +140,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( savedStateHandle = createSavedStateHandleWithState( state = null, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) viewModel.stateFlow.test { @@ -158,7 +159,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { @Test fun `initial add state should be correct when not autofill`() = runTest { - val vaultAddEditType = VaultAddEditType.AddItem + val vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN) val initState = createVaultAddItemState(vaultAddEditType = vaultAddEditType) val viewModel = createAddVaultItemViewModel( savedStateHandle = createSavedStateHandleWithState( @@ -188,7 +189,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { data = null, ), ) - val vaultAddEditType = VaultAddEditType.AddItem + val vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN) mutableVaultDataFlow.value = DataState.Loaded( data = createVaultData(), ) @@ -239,7 +240,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val autofillContentState = autofillSelectionData.toDefaultAddTypeContent( isIndividualVaultDisabled = false, ) - val vaultAddEditType = VaultAddEditType.AddItem + val vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN) val initState = createVaultAddItemState( vaultAddEditType = vaultAddEditType, commonContentViewState = autofillContentState.common, @@ -271,7 +272,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { autofillSaveItem = autofillSaveItem, ) val autofillContentState = autofillSaveItem.toDefaultAddTypeContent(false) - val vaultAddEditType = VaultAddEditType.AddItem + val vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN) val initState = createVaultAddItemState( vaultAddEditType = vaultAddEditType, commonContentViewState = autofillContentState.common, @@ -500,7 +501,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { fun `in add mode, SaveClick should show dialog, remove it once an item is saved, and emit NavigateBack`() = runTest { val stateWithDialog = createVaultAddItemState( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), dialogState = VaultAddEditState.DialogState.Loading( R.string.saving.asText(), ), @@ -509,7 +510,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { ), ) val stateWithName = createVaultAddItemState( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), commonContentViewState = createCommonContentViewState( name = "mockName-1", ), @@ -520,7 +521,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( createSavedStateHandleWithState( state = stateWithName, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) coEvery { @@ -567,7 +568,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { autofillSaveItem = autofillSaveItem, ) val stateWithDialog = createVaultAddItemState( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), dialogState = VaultAddEditState.DialogState.Loading( R.string.saving.asText(), ), @@ -577,7 +578,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { ) .copy(shouldExitOnSave = true) val stateWithName = createVaultAddItemState( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), commonContentViewState = createCommonContentViewState( name = "mockName-1", ), @@ -589,7 +590,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( createSavedStateHandleWithState( state = stateWithName, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) coEvery { @@ -621,7 +622,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { fun `in add mode, createCipherInOrganization success should ShowToast and NavigateBack`() = runTest { val stateWithName = createVaultAddItemState( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), commonContentViewState = createCommonContentViewState( name = "mockName-1", ), @@ -632,7 +633,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( createSavedStateHandleWithState( state = stateWithName, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) @@ -667,7 +668,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( createSavedStateHandleWithState( state = stateWithName, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) @@ -690,7 +691,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { fun `in add mode, SaveClick createCipher error should show error dialog`() = runTest { val stateWithName = createVaultAddItemState( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), commonContentViewState = createCommonContentViewState( name = "mockName-1", ), @@ -700,7 +701,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( createSavedStateHandleWithState( state = stateWithName, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) @@ -941,7 +942,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( createSavedStateHandleWithState( state = stateWithNoName, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) coEvery { vaultRepository.createCipher(any()) } returns CreateCipherResult.Success @@ -958,7 +959,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { createVaultData(cipherView = createMockCipherView(1)), ) val errorState = createVaultAddItemState( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), dialogState = VaultAddEditState.DialogState.Generic( title = R.string.an_error_has_occurred.asText(), message = R.string.validation_field_required.asText(R.string.name.asText()), @@ -968,7 +969,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( createSavedStateHandleWithState( state = errorState, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) @@ -1176,7 +1177,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( savedStateHandle = createSavedStateHandleWithState( state = loginState, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) @@ -1454,7 +1455,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { ) identityInitialSavedStateHandle = createSavedStateHandleWithState( state = vaultAddItemInitialState, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ) viewModel = createAddVaultItemViewModel( savedStateHandle = identityInitialSavedStateHandle, @@ -1748,7 +1749,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { ) identityInitialSavedStateHandle = createSavedStateHandleWithState( state = vaultAddItemInitialState, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ) viewModel = createAddVaultItemViewModel( savedStateHandle = identityInitialSavedStateHandle, @@ -1861,7 +1862,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { vaultAddItemInitialState = createVaultAddItemState() secureNotesInitialSavedStateHandle = createSavedStateHandleWithState( state = vaultAddItemInitialState, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ) viewModel = VaultAddEditViewModel( savedStateHandle = secureNotesInitialSavedStateHandle, @@ -2038,7 +2039,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { @Test fun `CustomFieldValueChange should allow a user to update a text custom field`() = runTest { val initState = createVaultAddItemState( - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), typeContentViewState = VaultAddEditState.ViewState.Content.ItemType.SecureNotes, commonContentViewState = VaultAddEditState.ViewState.Content.Common( customFieldData = listOf( @@ -2139,7 +2140,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( savedStateHandle = createSavedStateHandleWithState( state = initState, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) val currentContentState = @@ -2194,7 +2195,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( savedStateHandle = createSavedStateHandleWithState( state = initState, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) val currentContentState = @@ -2260,7 +2261,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( savedStateHandle = createSavedStateHandleWithState( state = initState, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) val currentContentState = @@ -2340,7 +2341,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { @Suppress("MaxLineLength") private fun createVaultAddItemState( - vaultAddEditType: VaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType: VaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), commonContentViewState: VaultAddEditState.ViewState.Content.Common = createCommonContentViewState(), isIndividualVaultDisabled: Boolean = false, typeContentViewState: VaultAddEditState.ViewState.Content.ItemType = createLoginTypeContentViewState(), @@ -2412,12 +2413,17 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { set( "vault_add_edit_type", when (vaultAddEditType) { - VaultAddEditType.AddItem -> "add" + is VaultAddEditType.AddItem -> "add" is VaultAddEditType.EditItem -> "edit" is VaultAddEditType.CloneItem -> "clone" }, ) set("vault_edit_id", (vaultAddEditType as? VaultAddEditType.EditItem)?.vaultItemId) + set( + "vault_add_item_type", + (vaultAddEditType as? VaultAddEditType.AddItem) + ?.vaultItemCipherType, + ) } @Suppress("LongParameterList") @@ -2582,7 +2588,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( savedStateHandle = createSavedStateHandleWithState( state = initialState, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) @@ -2611,7 +2617,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() { val viewModel = createAddVaultItemViewModel( savedStateHandle = createSavedStateHandleWithState( state = initialState, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ), ) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensionsTest.kt index 60738429bd..cbca77a642 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensionsTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/CipherViewExtensionsTest.kt @@ -28,6 +28,7 @@ import com.x8bit.bitwarden.ui.vault.feature.addedit.model.UriItem import com.x8bit.bitwarden.ui.vault.model.VaultAddEditType import com.x8bit.bitwarden.ui.vault.model.VaultCardBrand import com.x8bit.bitwarden.ui.vault.model.VaultCollection +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType import com.x8bit.bitwarden.ui.vault.model.VaultLinkedFieldType import io.mockk.every import io.mockk.mockk @@ -279,7 +280,7 @@ class CipherViewExtensionsTest { val result = createMockCipherView(number = 1) .validateCipherOrReturnErrorState( currentAccount = createAccount(), - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ) { _, _ -> providedState } assertEquals(providedState, result) @@ -308,7 +309,7 @@ class CipherViewExtensionsTest { val result = createMockCipherView(number = 1) .validateCipherOrReturnErrorState( currentAccount = null, - vaultAddEditType = VaultAddEditType.AddItem, + vaultAddEditType = VaultAddEditType.AddItem(VaultItemCipherType.LOGIN), ) { _, _ -> providedState } assertEquals( diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/VaultAddEditExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/VaultAddEditExtensionsTest.kt new file mode 100644 index 0000000000..aa4d499979 --- /dev/null +++ b/app/src/test/java/com/x8bit/bitwarden/ui/vault/feature/addedit/util/VaultAddEditExtensionsTest.kt @@ -0,0 +1,48 @@ +package com.x8bit.bitwarden.ui.vault.feature.addedit.util + +import com.x8bit.bitwarden.ui.vault.feature.addedit.VaultAddEditState +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType +import io.mockk.every +import io.mockk.mockkStatic +import io.mockk.unmockkStatic +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import java.util.UUID + +class VaultAddEditExtensionsTest { + + @BeforeEach + fun setup() { + mockkStatic(UUID::randomUUID) + every { UUID.randomUUID().toString() } returns "123" + } + + @AfterEach + fun teardown() { + unmockkStatic(UUID::randomUUID) + } + + @Test + fun `toItemType should return the correct response`() { + val vaultItemCipherTypeList = listOf( + VaultItemCipherType.LOGIN, + VaultItemCipherType.CARD, + VaultItemCipherType.SECURE_NOTE, + VaultItemCipherType.IDENTITY, + ) + + val result = vaultItemCipherTypeList.map { it.toItemType() } + + assertEquals( + listOf( + VaultAddEditState.ViewState.Content.ItemType.Login(), + VaultAddEditState.ViewState.Content.ItemType.Card(), + VaultAddEditState.ViewState.Content.ItemType.SecureNotes, + VaultAddEditState.ViewState.Content.ItemType.Identity(), + ), + result, + ) + } +} 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 f1639212fe..b2a9fb13de 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 @@ -45,6 +45,7 @@ import com.x8bit.bitwarden.ui.util.performLogoutAccountClick import com.x8bit.bitwarden.ui.util.performLogoutAccountConfirmationClick import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType import io.mockk.every import io.mockk.just @@ -366,7 +367,9 @@ class VaultItemListingScreenTest : BaseComposeTest() { @Test fun `NavigateToAdd VaultItem event should call NavigateToVaultAddItemScreen`() { - mutableEventFlow.tryEmit(VaultItemListingEvent.NavigateToAddVaultItem) + mutableEventFlow.tryEmit( + VaultItemListingEvent.NavigateToAddVaultItem(VaultItemCipherType.LOGIN), + ) assertTrue(onNavigateToVaultAddItemScreenCalled) } 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 c5686d5fcc..4862b02969 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 @@ -43,6 +43,7 @@ import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.createMockDisplayIt import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType import com.x8bit.bitwarden.ui.vault.feature.vault.util.toAccountSummaries import com.x8bit.bitwarden.ui.vault.feature.vault.util.toActiveAccountSummary +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType import io.mockk.coEvery import io.mockk.every @@ -461,7 +462,10 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { val viewModel = createVaultItemListingViewModel() viewModel.eventFlow.test { viewModel.trySendAction(VaultItemListingsAction.AddVaultItemClick) - assertEquals(VaultItemListingEvent.NavigateToAddVaultItem, awaitItem()) + assertEquals( + VaultItemListingEvent.NavigateToAddVaultItem(VaultItemCipherType.LOGIN), + awaitItem(), + ) } } 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 b5499806ca..0950ec9bab 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 @@ -2,8 +2,10 @@ package com.x8bit.bitwarden.ui.vault.feature.itemlisting.util import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingState +import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows class VaultItemListingStateExtensionsTest { @@ -108,4 +110,43 @@ class VaultItemListingStateExtensionsTest { assertEquals(expected, result) } + + @Test + fun `toVaultItemCipherType should return the correct response`() { + val itemListingTypes = listOf( + VaultItemListingState.ItemListingType.Vault.Card, + VaultItemListingState.ItemListingType.Vault.Identity, + VaultItemListingState.ItemListingType.Vault.SecureNote, + VaultItemListingState.ItemListingType.Vault.Login, + ) + + val result = itemListingTypes.map { it.toVaultItemCipherType() } + + assertEquals( + listOf( + VaultItemCipherType.CARD, + VaultItemCipherType.IDENTITY, + VaultItemCipherType.SECURE_NOTE, + VaultItemCipherType.LOGIN, + ), + result, + ) + } + + @Test + fun `toVaultItemCipherType should throw an exception for unsupported ItemListingTypes`() { + val itemListingTypes = listOf( + VaultItemListingState.ItemListingType.Vault.Trash, + VaultItemListingState.ItemListingType.Vault.Collection( + collectionId = "mockId", + ), + VaultItemListingState.ItemListingType.Vault.Folder( + folderId = "mockId", + ), + ) + + itemListingTypes.forEach { + assertThrows { it.toVaultItemCipherType() } + } + } }