From ff361a7b617d5d176272091b7527a4ffe3dfa69f Mon Sep 17 00:00:00 2001 From: David Perez Date: Wed, 17 Jan 2024 23:36:02 -0600 Subject: [PATCH] Implement navigation for listing sends (#661) --- .../VaultUnlockedNavBarScreen.kt | 1 + .../tools/feature/send/SendGraphNavigation.kt | 15 ++++ .../ui/tools/feature/send/SendNavigation.kt | 4 + .../ui/tools/feature/send/SendScreen.kt | 5 ++ .../ui/tools/feature/send/SendViewModel.kt | 16 +++- .../itemlisting/VaultItemListingNavigation.kt | 72 ++++++++++++++- .../itemlisting/VaultItemListingScreen.kt | 10 +++ .../itemlisting/VaultItemListingViewModel.kt | 90 +++++++++++++++---- .../util/VaultItemListingDataExtensions.kt | 49 +++++++++- .../util/VaultItemListingTypeExtensions.kt | 3 + .../ui/vault/model/VaultItemListingType.kt | 10 +++ .../ui/tools/feature/send/SendScreenTest.kt | 16 ++++ .../tools/feature/send/SendViewModelTest.kt | 8 +- .../itemlisting/VaultItemListingScreenTest.kt | 17 ++++ .../VaultItemListingViewModelTest.kt | 30 ++++++- 15 files changed, 317 insertions(+), 29 deletions(-) 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 d15d93d34f..0746fe221c 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 @@ -215,6 +215,7 @@ private fun VaultUnlockedNavBarScaffold( }, ) sendGraph( + navController = navController, onNavigateToAddSend = navigateToAddSend, onNavigateToEditSend = onNavigateToEditSend, ) diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendGraphNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendGraphNavigation.kt index 15917f81f9..3147b7b752 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendGraphNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendGraphNavigation.kt @@ -4,6 +4,9 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.navigation +import com.x8bit.bitwarden.ui.vault.feature.itemlisting.navigateToSendItemListing +import com.x8bit.bitwarden.ui.vault.feature.itemlisting.sendItemListingDestination +import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType const val SEND_GRAPH_ROUTE: String = "send_graph" @@ -11,6 +14,7 @@ const val SEND_GRAPH_ROUTE: String = "send_graph" * Add send destination to the nav graph. */ fun NavGraphBuilder.sendGraph( + navController: NavController, onNavigateToAddSend: () -> Unit, onNavigateToEditSend: (sendItemId: String) -> Unit, ) { @@ -21,6 +25,17 @@ fun NavGraphBuilder.sendGraph( sendDestination( onNavigateToAddSend = onNavigateToAddSend, onNavigateToEditSend = onNavigateToEditSend, + onNavigateToSendFilesList = { + navController.navigateToSendItemListing(VaultItemListingType.SendFile) + }, + onNavigateToSendTextList = { + navController.navigateToSendItemListing(VaultItemListingType.SendText) + }, + ) + sendItemListingDestination( + onNavigateBack = { navController.popBackStack() }, + onNavigateToAddSendItem = onNavigateToAddSend, + onNavigateToEditSendItem = onNavigateToEditSend, ) } } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendNavigation.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendNavigation.kt index f6d3b4b42c..4513960ca2 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendNavigation.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendNavigation.kt @@ -13,6 +13,8 @@ const val SEND_ROUTE: String = "send" fun NavGraphBuilder.sendDestination( onNavigateToAddSend: () -> Unit, onNavigateToEditSend: (sendItemId: String) -> Unit, + onNavigateToSendFilesList: () -> Unit, + onNavigateToSendTextList: () -> Unit, ) { composableWithRootPushTransitions( route = SEND_ROUTE, @@ -20,6 +22,8 @@ fun NavGraphBuilder.sendDestination( SendScreen( onNavigateToAddSend = onNavigateToAddSend, onNavigateToEditSend = onNavigateToEditSend, + onNavigateToSendFilesList = onNavigateToSendFilesList, + onNavigateToSendTextList = onNavigateToSendTextList, ) } } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendScreen.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendScreen.kt index 8353c67594..48e7114e2e 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendScreen.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendScreen.kt @@ -53,6 +53,8 @@ import kotlinx.collections.immutable.persistentListOf fun SendScreen( onNavigateToAddSend: () -> Unit, onNavigateToEditSend: (sendItemId: String) -> Unit, + onNavigateToSendFilesList: () -> Unit, + onNavigateToSendTextList: () -> Unit, viewModel: SendViewModel = hiltViewModel(), intentManager: IntentManager = LocalIntentManager.current, ) { @@ -87,6 +89,9 @@ fun SendScreen( .makeText(context, event.message(context.resources), Toast.LENGTH_SHORT) .show() } + + SendEvent.NavigateToFileSends -> onNavigateToSendFilesList() + SendEvent.NavigateToTextSends -> onNavigateToSendTextList() } } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModel.kt index 886722c9e5..2b7cb29b59 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModel.kt @@ -257,13 +257,11 @@ class SendViewModel @Inject constructor( } private fun handleFileTypeClick() { - // TODO: Navigate to the file type send list screen (BIT-1388) - sendEvent(SendEvent.ShowToast("Not yet implemented".asText())) + sendEvent(SendEvent.NavigateToFileSends) } private fun handleTextTypeClick() { - // TODO: Navigate to the text type send list screen (BIT-1388) - sendEvent(SendEvent.ShowToast("Not yet implemented".asText())) + sendEvent(SendEvent.NavigateToTextSends) } private fun handleDeleteSendClick(action: SendAction.DeleteSendClick) { @@ -563,6 +561,16 @@ sealed class SendEvent { */ data object NavigateToAboutSend : SendEvent() + /** + * Navigate to the send file list screen. + */ + data object NavigateToFileSends : SendEvent() + + /** + * Navigate to the send text screen. + */ + data object NavigateToTextSends : SendEvent() + /** * Show a share sheet with the given content. */ 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 d20f81717d..5847495526 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 @@ -16,6 +16,8 @@ private const val FOLDER: String = "folder" private const val IDENTITY: String = "identity" private const val LOGIN: String = "login" private const val SECURE_NOTE: String = "secure_note" +private const val SEND_FILE: String = "send_file" +private const val SEND_TEXT: String = "send_text" private const val TRASH: String = "trash" private const val VAULT_ITEM_LISTING_PREFIX: String = "vault_item_listing" private const val VAULT_ITEM_LISTING_TYPE: String = "vault_item_listing_type" @@ -23,6 +25,10 @@ private const val ID: String = "id" private const val VAULT_ITEM_LISTING_ROUTE: String = "$VAULT_ITEM_LISTING_PREFIX/{$VAULT_ITEM_LISTING_TYPE}" + "?$ID={$ID}" +private const val SEND_ITEM_LISTING_PREFIX: String = "send_item_listing" +private const val SEND_ITEM_LISTING_ROUTE: String = + "$SEND_ITEM_LISTING_PREFIX/{$VAULT_ITEM_LISTING_TYPE}" + + "?$ID={$ID}" /** * Class to retrieve vault item listing arguments from the [SavedStateHandle]. @@ -49,8 +55,48 @@ fun NavGraphBuilder.vaultItemListingDestination( onNavigateToVaultItemScreen: (id: String) -> Unit, onNavigateToVaultAddItemScreen: () -> Unit, ) { - composableWithPushTransitions( + internalVaultItemListingDestination( route = VAULT_ITEM_LISTING_ROUTE, + onNavigateBack = onNavigateBack, + onNavigateToAddSendItem = { }, + onNavigateToEditSendItem = { }, + onNavigateToVaultAddItemScreen = onNavigateToVaultAddItemScreen, + onNavigateToVaultItemScreen = onNavigateToVaultItemScreen, + ) +} + +/** + * Add the [VaultItemListingScreen] to the nav graph. + */ +fun NavGraphBuilder.sendItemListingDestination( + onNavigateBack: () -> Unit, + onNavigateToAddSendItem: () -> Unit, + onNavigateToEditSendItem: (sendId: String) -> Unit, +) { + internalVaultItemListingDestination( + route = SEND_ITEM_LISTING_ROUTE, + onNavigateBack = onNavigateBack, + onNavigateToAddSendItem = onNavigateToAddSendItem, + onNavigateToEditSendItem = onNavigateToEditSendItem, + onNavigateToVaultAddItemScreen = { }, + onNavigateToVaultItemScreen = { }, + ) +} + +/** + * Add the [VaultItemListingScreen] to the nav graph. + */ +@Suppress("LongParameterList") +private fun NavGraphBuilder.internalVaultItemListingDestination( + route: String, + onNavigateBack: () -> Unit, + onNavigateToVaultItemScreen: (id: String) -> Unit, + onNavigateToVaultAddItemScreen: () -> Unit, + onNavigateToAddSendItem: () -> Unit, + onNavigateToEditSendItem: (sendId: String) -> Unit, +) { + composableWithPushTransitions( + route = route, arguments = listOf( navArgument( name = VAULT_ITEM_LISTING_TYPE, @@ -69,12 +115,14 @@ fun NavGraphBuilder.vaultItemListingDestination( onNavigateBack = onNavigateBack, onNavigateToVaultItem = onNavigateToVaultItemScreen, onNavigateToVaultAddItemScreen = onNavigateToVaultAddItemScreen, + onNavigateToAddSendItem = onNavigateToAddSendItem, + onNavigateToEditSendItem = onNavigateToEditSendItem, ) } } /** - * Navigate to the [VaultItemListingScreen]. + * Navigate to the [VaultItemListingScreen] for vault. */ fun NavController.navigateToVaultItemListing( vaultItemListingType: VaultItemListingType, @@ -87,6 +135,20 @@ fun NavController.navigateToVaultItemListing( ) } +/** + * Navigate to the [VaultItemListingScreen] for sends. + */ +fun NavController.navigateToSendItemListing( + vaultItemListingType: VaultItemListingType, + navOptions: NavOptions? = null, +) { + navigate( + route = "$SEND_ITEM_LISTING_PREFIX/${vaultItemListingType.toTypeString()}" + + "?$ID=${vaultItemListingType.toIdOrNull()}", + navOptions = navOptions, + ) +} + private fun VaultItemListingType.toTypeString(): String { return when (this) { is VaultItemListingType.Card -> CARD @@ -96,6 +158,8 @@ private fun VaultItemListingType.toTypeString(): String { is VaultItemListingType.Login -> LOGIN is VaultItemListingType.SecureNote -> SECURE_NOTE is VaultItemListingType.Trash -> TRASH + is VaultItemListingType.SendFile -> SEND_FILE + is VaultItemListingType.SendText -> SEND_TEXT } } @@ -108,6 +172,8 @@ private fun VaultItemListingType.toIdOrNull(): String? = is VaultItemListingType.Login -> null is VaultItemListingType.SecureNote -> null is VaultItemListingType.Trash -> null + is VaultItemListingType.SendFile -> null + is VaultItemListingType.SendText -> null } private fun determineVaultItemListingType( @@ -122,6 +188,8 @@ private fun determineVaultItemListingType( TRASH -> VaultItemListingType.Trash FOLDER -> VaultItemListingType.Folder(folderId = id) COLLECTION -> VaultItemListingType.Collection(collectionId = requireNotNull(id)) + SEND_FILE -> VaultItemListingType.SendFile + SEND_TEXT -> VaultItemListingType.SendText // This should never occur, vaultItemListingTypeString must match else -> throw IllegalStateException() } 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 b299b03b42..72318cae44 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 @@ -35,6 +35,8 @@ fun VaultItemListingScreen( onNavigateBack: () -> Unit, onNavigateToVaultItem: (id: String) -> Unit, onNavigateToVaultAddItemScreen: () -> Unit, + onNavigateToAddSendItem: () -> Unit, + onNavigateToEditSendItem: (sendId: String) -> Unit, viewModel: VaultItemListingViewModel = hiltViewModel(), ) { val context = LocalContext.current @@ -55,6 +57,14 @@ fun VaultItemListingScreen( onNavigateToVaultAddItemScreen() } + is VaultItemListingEvent.NavigateToAddSendItem -> { + onNavigateToAddSendItem() + } + + is VaultItemListingEvent.NavigateToSendItem -> { + onNavigateToEditSendItem(event.id) + } + is VaultItemListingEvent.NavigateToVaultSearchScreen -> { // TODO Create vault search screen and navigation implementation BIT-213 Toast 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 4a2b457292..3c3ef08616 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 @@ -77,17 +77,29 @@ class VaultItemListingViewModel @Inject constructor( } private fun handleAddVaultItemClick() { - sendEvent( - event = VaultItemListingEvent.NavigateToAddVaultItem, - ) + val event = when (state.itemListingType) { + is VaultItemListingState.ItemListingType.Vault -> { + VaultItemListingEvent.NavigateToAddVaultItem + } + + is VaultItemListingState.ItemListingType.Send -> { + VaultItemListingEvent.NavigateToAddSendItem + } + } + sendEvent(event) } private fun handleItemClick(action: VaultItemListingsAction.ItemClick) { - sendEvent( - event = VaultItemListingEvent.NavigateToVaultItem( - id = action.id, - ), - ) + val event = when (state.itemListingType) { + is VaultItemListingState.ItemListingType.Vault -> { + VaultItemListingEvent.NavigateToVaultItem(id = action.id) + } + + is VaultItemListingState.ItemListingType.Send -> { + VaultItemListingEvent.NavigateToSendItem(id = action.id) + } + } + sendEvent(event) } private fun handleBackClick() { @@ -180,15 +192,28 @@ class VaultItemListingViewModel @Inject constructor( collectionList = vaultData .collectionViewList, ), - viewState = vaultData - .cipherViewList - .filter { cipherView -> - cipherView.determineListingPredicate(currentState.itemListingType) + viewState = when (val listingType = currentState.itemListingType) { + is VaultItemListingState.ItemListingType.Vault -> { + vaultData + .cipherViewList + .filter { cipherView -> + cipherView.determineListingPredicate(listingType) + } + .toViewState( + baseIconUrl = state.baseIconUrl, + isIconLoadingDisabled = state.isIconLoadingDisabled, + ) } - .toViewState( - baseIconUrl = state.baseIconUrl, - isIconLoadingDisabled = state.isIconLoadingDisabled, - ), + + is VaultItemListingState.ItemListingType.Send -> { + vaultData + .sendViewList + .filter { sendView -> + sendView.determineListingPredicate(listingType) + } + .toViewState() + } + }, ) } } @@ -344,6 +369,27 @@ data class VaultItemListingState( override val hasFab: Boolean get() = false } } + + /** + * Represents different types of vault item listings. + */ + sealed class Send : ItemListingType() { + /** + * A Send File item listing. + */ + data object SendFile : Send() { + override val titleText: Text get() = R.string.file.asText() + override val hasFab: Boolean get() = true + } + + /** + * A Send Text item listing. + */ + data object SendText : Send() { + override val titleText: Text get() = R.string.text.asText() + override val hasFab: Boolean get() = true + } + } } } @@ -362,6 +408,18 @@ sealed class VaultItemListingEvent { */ data object NavigateToAddVaultItem : VaultItemListingEvent() + /** + * Navigates to the AddSendItemScreen. + */ + data object NavigateToAddSendItem : VaultItemListingEvent() + + /** + * Navigates to the AddSendScreen. + * + * @property id the id of the send to navigate to. + */ + data class NavigateToSendItem(val id: String) : VaultItemListingEvent() + /** * Navigates to the VaultItemScreen. * diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensions.kt index 24e985b9e6..16cc02596a 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingDataExtensions.kt @@ -5,6 +5,8 @@ import com.bitwarden.core.CipherType import com.bitwarden.core.CipherView import com.bitwarden.core.CollectionView import com.bitwarden.core.FolderView +import com.bitwarden.core.SendType +import com.bitwarden.core.SendView import com.x8bit.bitwarden.R import com.x8bit.bitwarden.ui.platform.components.model.IconData import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingState @@ -15,7 +17,7 @@ import com.x8bit.bitwarden.ui.vault.feature.vault.util.toLoginIconData * [VaultItemListingState.ItemListingType]. */ fun CipherView.determineListingPredicate( - itemListingType: VaultItemListingState.ItemListingType, + itemListingType: VaultItemListingState.ItemListingType.Vault, ): Boolean = when (itemListingType) { is VaultItemListingState.ItemListingType.Vault.Card -> { @@ -47,6 +49,23 @@ fun CipherView.determineListingPredicate( } } +/** + * Determines a predicate to filter a list of [CipherView] based on the + * [VaultItemListingState.ItemListingType]. + */ +fun SendView.determineListingPredicate( + itemListingType: VaultItemListingState.ItemListingType.Send, +): Boolean = + when (itemListingType) { + is VaultItemListingState.ItemListingType.Send.SendFile -> { + type == SendType.FILE + } + + is VaultItemListingState.ItemListingType.Send.SendText -> { + type == SendType.TEXT + } + } + /** * Transforms a list of [CipherView] into [VaultItemListingState.ViewState]. */ @@ -65,6 +84,16 @@ fun List.toViewState( VaultItemListingState.ViewState.NoItems } +/** + * Transforms a list of [CipherView] into [VaultItemListingState.ViewState]. + */ +fun List.toViewState(): VaultItemListingState.ViewState = + if (isNotEmpty()) { + VaultItemListingState.ViewState.Content(displayItemList = toDisplayItemList()) + } else { + VaultItemListingState.ViewState.NoItems + } + /** * Updates a [VaultItemListingState.ItemListingType] with the given data if necessary. */ fun VaultItemListingState.ItemListingType.updateWithAdditionalDataIfNecessary( folderList: List, @@ -90,6 +119,8 @@ fun VaultItemListingState.ItemListingType.updateWithAdditionalDataIfNecessary( is VaultItemListingState.ItemListingType.Vault.Login -> this is VaultItemListingState.ItemListingType.Vault.SecureNote -> this is VaultItemListingState.ItemListingType.Vault.Trash -> this + is VaultItemListingState.ItemListingType.Send.SendFile -> this + is VaultItemListingState.ItemListingType.Send.SendText -> this } private fun List.toDisplayItemList( @@ -103,6 +134,9 @@ private fun List.toDisplayItemList( ) } +private fun List.toDisplayItemList(): List = + this.map { it.toDisplayItem() } + private fun CipherView.toDisplayItem( baseIconUrl: String, isIconLoadingDisabled: Boolean, @@ -135,6 +169,19 @@ private fun CipherView.toIconData( } } +private fun SendView.toDisplayItem(): VaultItemListingState.DisplayItem = + VaultItemListingState.DisplayItem( + id = id.orEmpty(), + title = name, + subtitle = deletionDate.toString(), + iconData = IconData.Local( + iconRes = when (type) { + SendType.TEXT -> R.drawable.ic_send_text + SendType.FILE -> R.drawable.ic_send_file + }, + ), + ) + @Suppress("MagicNumber") private val CipherView.subtitle: String? get() = when (type) { diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingTypeExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingTypeExtensions.kt index 076329e31c..86a99c31bf 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingTypeExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/feature/itemlisting/util/VaultItemListingTypeExtensions.kt @@ -20,4 +20,7 @@ fun VaultItemListingType.toItemListingType(): VaultItemListingState.ItemListingT is VaultItemListingType.Collection -> { VaultItemListingState.ItemListingType.Vault.Collection(collectionId = collectionId) } + + is VaultItemListingType.SendFile -> VaultItemListingState.ItemListingType.Send.SendFile + is VaultItemListingType.SendText -> VaultItemListingState.ItemListingType.Send.SendText } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/vault/model/VaultItemListingType.kt b/app/src/main/java/com/x8bit/bitwarden/ui/vault/model/VaultItemListingType.kt index 8aca8cab72..dc8b567608 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/vault/model/VaultItemListingType.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/vault/model/VaultItemListingType.kt @@ -43,4 +43,14 @@ sealed class VaultItemListingType { * @param collectionId the ID of the collection. */ data class Collection(val collectionId: String) : VaultItemListingType() + + /** + * A Send File listing. + */ + data object SendFile : VaultItemListingType() + + /** + * A Send Text listing. + */ + data object SendText : VaultItemListingType() } diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/SendScreenTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/SendScreenTest.kt index 13d116ca16..5012673920 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/SendScreenTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/SendScreenTest.kt @@ -39,6 +39,8 @@ import org.junit.Test class SendScreenTest : BaseComposeTest() { private var onNavigateToNewSendCalled = false + private var onNavigateToSendFilesListCalled = false + private var onNavigateToSendTextListCalled = false private var onNavigateToEditSendId: String? = null private val intentManager = mockk { @@ -59,6 +61,8 @@ class SendScreenTest : BaseComposeTest() { viewModel = viewModel, onNavigateToAddSend = { onNavigateToNewSendCalled = true }, onNavigateToEditSend = { onNavigateToEditSendId = it }, + onNavigateToSendFilesList = { onNavigateToSendFilesListCalled = true }, + onNavigateToSendTextList = { onNavigateToSendTextListCalled = true }, intentManager = intentManager, ) } @@ -77,6 +81,18 @@ class SendScreenTest : BaseComposeTest() { assertEquals(sendId, onNavigateToEditSendId) } + @Test + fun `on NavigateToFileSends should call onNavigateToSendFilesList`() { + mutableEventFlow.tryEmit(SendEvent.NavigateToFileSends) + assertTrue(onNavigateToSendFilesListCalled) + } + + @Test + fun `on NavigateToTextSends should call onNavigateToSendTextList`() { + mutableEventFlow.tryEmit(SendEvent.NavigateToTextSends) + assertTrue(onNavigateToSendTextListCalled) + } + @Test fun `on NavigateToAboutSend should call launchUri on intentManager`() { mutableEventFlow.tryEmit(SendEvent.NavigateToAboutSend) diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModelTest.kt index da7ff199d8..fd3001b959 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/tools/feature/send/SendViewModelTest.kt @@ -275,20 +275,20 @@ class SendViewModelTest : BaseViewModelTest() { } @Test - fun `FileTypeClick should emit ShowToast`() = runTest { + fun `FileTypeClick should emit NavigateToFileSends`() = runTest { val viewModel = createViewModel() viewModel.eventFlow.test { viewModel.trySendAction(SendAction.FileTypeClick) - assertEquals(SendEvent.ShowToast("Not yet implemented".asText()), awaitItem()) + assertEquals(SendEvent.NavigateToFileSends, awaitItem()) } } @Test - fun `TextTypeClick should emit ShowToast`() = runTest { + fun `TextTypeClick should emit NavigateToTextSends`() = runTest { val viewModel = createViewModel() viewModel.eventFlow.test { viewModel.trySendAction(SendAction.TextTypeClick) - assertEquals(SendEvent.ShowToast("Not yet implemented".asText()), awaitItem()) + assertEquals(SendEvent.NavigateToTextSends, awaitItem()) } } 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 bbabd8b38f..ebc285f084 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 @@ -31,6 +31,8 @@ class VaultItemListingScreenTest : BaseComposeTest() { private var onNavigateBackCalled = false private var onNavigateToVaultAddItemScreenCalled = false + private var onNavigateToAddSendScreenCalled = false + private var onNavigateToEditSendItemId: String? = null private var onNavigateToVaultItemId: String? = null private val mutableEventFlow = bufferedMutableSharedFlow() @@ -48,6 +50,8 @@ class VaultItemListingScreenTest : BaseComposeTest() { onNavigateBack = { onNavigateBackCalled = true }, onNavigateToVaultItem = { onNavigateToVaultItemId = it }, onNavigateToVaultAddItemScreen = { onNavigateToVaultAddItemScreenCalled = true }, + onNavigateToAddSendItem = { onNavigateToAddSendScreenCalled = true }, + onNavigateToEditSendItem = { onNavigateToEditSendItemId = it }, ) } } @@ -108,6 +112,19 @@ class VaultItemListingScreenTest : BaseComposeTest() { assertTrue(onNavigateToVaultAddItemScreenCalled) } + @Test + fun `NavigateToAddSendItem should call onNavigateToAddSendScreen`() { + mutableEventFlow.tryEmit(VaultItemListingEvent.NavigateToAddSendItem) + assertTrue(onNavigateToAddSendScreenCalled) + } + + @Test + fun `NavigateToSendItem event should call onNavigateToEditSendItemId`() { + val sendId = "sendId" + mutableEventFlow.tryEmit(VaultItemListingEvent.NavigateToSendItem(sendId)) + assertEquals(sendId, onNavigateToEditSendItemId) + } + @Test fun `NavigateToVaultItem event should call NavigateToVaultItemScreen`() { val id = "id4321" 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 b801ca40fa..f526dc22e0 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 @@ -84,7 +84,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { } @Test - fun `ItemClick should emit NavigateToVaultItem`() = runTest { + fun `ItemClick for vault item should emit NavigateToVaultItem`() = runTest { val viewModel = createVaultItemListingViewModel() viewModel.eventFlow.test { viewModel.actionChannel.trySend(VaultItemListingsAction.ItemClick(id = "mock")) @@ -93,7 +93,18 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { } @Test - fun `AddVaultItemClick should emit NavigateToAddVaultItem`() = runTest { + fun `ItemClick for send item should emit NavigateToSendItem`() = runTest { + val viewModel = createVaultItemListingViewModel( + createSavedStateHandleWithVaultItemListingType(VaultItemListingType.SendFile), + ) + viewModel.eventFlow.test { + viewModel.actionChannel.trySend(VaultItemListingsAction.ItemClick(id = "mock")) + assertEquals(VaultItemListingEvent.NavigateToSendItem(id = "mock"), awaitItem()) + } + } + + @Test + fun `AddVaultItemClick for vault item should emit NavigateToAddVaultItem`() = runTest { val viewModel = createVaultItemListingViewModel() viewModel.eventFlow.test { viewModel.actionChannel.trySend(VaultItemListingsAction.AddVaultItemClick) @@ -101,6 +112,17 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { } } + @Test + fun `AddVaultItemClick for send item should emit NavigateToAddVaultItem`() = runTest { + val viewModel = createVaultItemListingViewModel( + createSavedStateHandleWithVaultItemListingType(VaultItemListingType.SendText), + ) + viewModel.eventFlow.test { + viewModel.actionChannel.trySend(VaultItemListingsAction.AddVaultItemClick) + assertEquals(VaultItemListingEvent.NavigateToAddSendItem, awaitItem()) + } + } + @Test fun `RefreshClick should sync`() = runTest { val viewModel = createVaultItemListingViewModel() @@ -489,6 +511,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { is VaultItemListingType.Login -> "login" is VaultItemListingType.SecureNote -> "secure_note" is VaultItemListingType.Trash -> "trash" + is VaultItemListingType.SendFile -> "send_file" + is VaultItemListingType.SendText -> "send_text" }, ) set( @@ -501,6 +525,8 @@ class VaultItemListingViewModelTest : BaseViewModelTest() { is VaultItemListingType.Login -> null is VaultItemListingType.SecureNote -> null is VaultItemListingType.Trash -> null + is VaultItemListingType.SendFile -> null + is VaultItemListingType.SendText -> null }, ) }