mirror of
https://github.com/bitwarden/android.git
synced 2026-05-10 16:45:43 -05:00
Add overflow options to the listing screen and the search screen (#734)
This commit is contained in:
@@ -56,6 +56,14 @@ fun SearchContent(
|
||||
is ListingItemOverflowAction.SendAction.EditClick,
|
||||
is ListingItemOverflowAction.SendAction.RemovePasswordClick,
|
||||
is ListingItemOverflowAction.SendAction.ShareUrlClick,
|
||||
is ListingItemOverflowAction.VaultAction.CopyNoteClick,
|
||||
is ListingItemOverflowAction.VaultAction.CopyNumberClick,
|
||||
is ListingItemOverflowAction.VaultAction.CopyPasswordClick,
|
||||
is ListingItemOverflowAction.VaultAction.CopySecurityCodeClick,
|
||||
is ListingItemOverflowAction.VaultAction.CopyUsernameClick,
|
||||
is ListingItemOverflowAction.VaultAction.EditClick,
|
||||
is ListingItemOverflowAction.VaultAction.LaunchClick,
|
||||
is ListingItemOverflowAction.VaultAction.ViewClick,
|
||||
null,
|
||||
-> Unit
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.net.toUri
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.x8bit.bitwarden.R
|
||||
@@ -61,6 +62,7 @@ fun SearchScreen(
|
||||
is SearchEvent.NavigateToEditSend -> onNavigateToEditSend(event.sendId)
|
||||
is SearchEvent.NavigateToEditCipher -> onNavigateToEditCipher(event.cipherId)
|
||||
is SearchEvent.NavigateToViewCipher -> onNavigateToViewCipher(event.cipherId)
|
||||
is SearchEvent.NavigateToUrl -> intentManager.launchUri(event.url.toUri())
|
||||
is SearchEvent.ShowShareSheet -> intentManager.shareText(event.content)
|
||||
is SearchEvent.ShowToast -> {
|
||||
Toast
|
||||
|
||||
@@ -158,6 +158,38 @@ class SearchViewModel @Inject constructor(
|
||||
is ListingItemOverflowAction.SendAction.ShareUrlClick -> {
|
||||
handleShareUrlClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.CopyNoteClick -> {
|
||||
handleCopyNoteClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.CopyNumberClick -> {
|
||||
handleCopyNumberClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.CopyPasswordClick -> {
|
||||
handleCopyPasswordClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.CopySecurityCodeClick -> {
|
||||
handleCopySecurityCodeClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.CopyUsernameClick -> {
|
||||
handleCopyUsernameClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.EditClick -> {
|
||||
handleEditCipherClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.LaunchClick -> {
|
||||
handleLaunchCipherUrlClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.ViewClick -> {
|
||||
handleViewCipherClick(overflowAction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +231,48 @@ class SearchViewModel @Inject constructor(
|
||||
sendEvent(SearchEvent.ShowShareSheet(action.sendUrl))
|
||||
}
|
||||
|
||||
private fun handleCopyNoteClick(action: ListingItemOverflowAction.VaultAction.CopyNoteClick) {
|
||||
clipboardManager.setText(action.notes)
|
||||
}
|
||||
|
||||
private fun handleCopyNumberClick(
|
||||
action: ListingItemOverflowAction.VaultAction.CopyNumberClick,
|
||||
) {
|
||||
clipboardManager.setText(action.number)
|
||||
}
|
||||
|
||||
private fun handleCopyPasswordClick(
|
||||
action: ListingItemOverflowAction.VaultAction.CopyPasswordClick,
|
||||
) {
|
||||
clipboardManager.setText(action.password)
|
||||
}
|
||||
|
||||
private fun handleCopySecurityCodeClick(
|
||||
action: ListingItemOverflowAction.VaultAction.CopySecurityCodeClick,
|
||||
) {
|
||||
clipboardManager.setText(action.securityCode)
|
||||
}
|
||||
|
||||
private fun handleCopyUsernameClick(
|
||||
action: ListingItemOverflowAction.VaultAction.CopyUsernameClick,
|
||||
) {
|
||||
clipboardManager.setText(action.username)
|
||||
}
|
||||
|
||||
private fun handleEditCipherClick(action: ListingItemOverflowAction.VaultAction.EditClick) {
|
||||
sendEvent(SearchEvent.NavigateToEditCipher(action.cipherId))
|
||||
}
|
||||
|
||||
private fun handleLaunchCipherUrlClick(
|
||||
action: ListingItemOverflowAction.VaultAction.LaunchClick,
|
||||
) {
|
||||
sendEvent(SearchEvent.NavigateToUrl(action.url))
|
||||
}
|
||||
|
||||
private fun handleViewCipherClick(action: ListingItemOverflowAction.VaultAction.ViewClick) {
|
||||
sendEvent(SearchEvent.NavigateToViewCipher(action.cipherId))
|
||||
}
|
||||
|
||||
private fun handleInternalAction(action: SearchAction.Internal) {
|
||||
when (action) {
|
||||
is SearchAction.Internal.IconLoadingSettingReceive -> {
|
||||
@@ -719,6 +793,13 @@ sealed class SearchEvent {
|
||||
val cipherId: String,
|
||||
) : SearchEvent()
|
||||
|
||||
/**
|
||||
* Navigates to the given [url].
|
||||
*/
|
||||
data class NavigateToUrl(
|
||||
val url: String,
|
||||
) : SearchEvent()
|
||||
|
||||
/**
|
||||
* Shares the [content] with share sheet.
|
||||
*/
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.x8bit.bitwarden.ui.platform.feature.search.SearchTypeData
|
||||
import com.x8bit.bitwarden.ui.platform.util.toFormattedPattern
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.util.toLabelIcons
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.util.toOverflowActions
|
||||
import com.x8bit.bitwarden.ui.vault.feature.util.toOverflowActions
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.util.toLoginIconData
|
||||
import java.time.Clock
|
||||
|
||||
@@ -169,7 +170,7 @@ private fun CipherView.toDisplayItem(
|
||||
isIconLoadingDisabled = isIconLoadingDisabled,
|
||||
),
|
||||
extraIconList = emptyList(),
|
||||
overflowOptions = emptyList(),
|
||||
overflowOptions = toOverflowActions(),
|
||||
)
|
||||
|
||||
private fun CipherView.toIconData(
|
||||
|
||||
@@ -35,6 +35,41 @@ fun VaultItemListingContent(
|
||||
onOverflowItemClick: (action: ListingItemOverflowAction) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var showConfirmationDialog: ListingItemOverflowAction? by rememberSaveable {
|
||||
mutableStateOf(null)
|
||||
}
|
||||
when (val option = showConfirmationDialog) {
|
||||
is ListingItemOverflowAction.SendAction.DeleteClick -> {
|
||||
BitwardenTwoButtonDialog(
|
||||
title = stringResource(id = R.string.delete),
|
||||
message = stringResource(id = R.string.are_you_sure_delete_send),
|
||||
confirmButtonText = stringResource(id = R.string.yes),
|
||||
dismissButtonText = stringResource(id = R.string.cancel),
|
||||
onConfirmClick = {
|
||||
showConfirmationDialog = null
|
||||
onOverflowItemClick(option)
|
||||
},
|
||||
onDismissClick = { showConfirmationDialog = null },
|
||||
onDismissRequest = { showConfirmationDialog = null },
|
||||
)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.SendAction.CopyUrlClick,
|
||||
is ListingItemOverflowAction.SendAction.EditClick,
|
||||
is ListingItemOverflowAction.SendAction.RemovePasswordClick,
|
||||
is ListingItemOverflowAction.SendAction.ShareUrlClick,
|
||||
is ListingItemOverflowAction.VaultAction.CopyNoteClick,
|
||||
is ListingItemOverflowAction.VaultAction.CopyNumberClick,
|
||||
is ListingItemOverflowAction.VaultAction.CopyPasswordClick,
|
||||
is ListingItemOverflowAction.VaultAction.CopySecurityCodeClick,
|
||||
is ListingItemOverflowAction.VaultAction.CopyUsernameClick,
|
||||
is ListingItemOverflowAction.VaultAction.EditClick,
|
||||
is ListingItemOverflowAction.VaultAction.LaunchClick,
|
||||
is ListingItemOverflowAction.VaultAction.ViewClick,
|
||||
null,
|
||||
-> Unit
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
) {
|
||||
@@ -48,9 +83,6 @@ fun VaultItemListingContent(
|
||||
)
|
||||
}
|
||||
items(state.displayItemList) {
|
||||
var showConfirmationDialog: ListingItemOverflowAction? by rememberSaveable {
|
||||
mutableStateOf(null)
|
||||
}
|
||||
BitwardenListItem(
|
||||
startIcon = it.iconData,
|
||||
label = it.title,
|
||||
@@ -86,29 +118,6 @@ fun VaultItemListingContent(
|
||||
end = 12.dp,
|
||||
),
|
||||
)
|
||||
when (val option = showConfirmationDialog) {
|
||||
is ListingItemOverflowAction.SendAction.DeleteClick -> {
|
||||
BitwardenTwoButtonDialog(
|
||||
title = stringResource(id = R.string.delete),
|
||||
message = stringResource(id = R.string.are_you_sure_delete_send),
|
||||
confirmButtonText = stringResource(id = R.string.yes),
|
||||
dismissButtonText = stringResource(id = R.string.cancel),
|
||||
onConfirmClick = {
|
||||
showConfirmationDialog = null
|
||||
onOverflowItemClick(option)
|
||||
},
|
||||
onDismissClick = { showConfirmationDialog = null },
|
||||
onDismissRequest = { showConfirmationDialog = null },
|
||||
)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.SendAction.CopyUrlClick,
|
||||
is ListingItemOverflowAction.SendAction.EditClick,
|
||||
is ListingItemOverflowAction.SendAction.RemovePasswordClick,
|
||||
is ListingItemOverflowAction.SendAction.ShareUrlClick,
|
||||
null,
|
||||
-> Unit
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
|
||||
@@ -54,6 +54,7 @@ data class VaultItemListingArgs(
|
||||
fun NavGraphBuilder.vaultItemListingDestination(
|
||||
onNavigateBack: () -> Unit,
|
||||
onNavigateToVaultItemScreen: (id: String) -> Unit,
|
||||
onNavigateToVaultEditItemScreen: (cipherId: String) -> Unit,
|
||||
onNavigateToVaultAddItemScreen: () -> Unit,
|
||||
onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit,
|
||||
) {
|
||||
@@ -64,6 +65,7 @@ fun NavGraphBuilder.vaultItemListingDestination(
|
||||
onNavigateToEditSendItem = { },
|
||||
onNavigateToVaultAddItemScreen = onNavigateToVaultAddItemScreen,
|
||||
onNavigateToVaultItemScreen = onNavigateToVaultItemScreen,
|
||||
onNavigateToVaultEditItemScreen = onNavigateToVaultEditItemScreen,
|
||||
onNavigateToSearch = { onNavigateToSearchVault(it as SearchType.Vault) },
|
||||
)
|
||||
}
|
||||
@@ -84,6 +86,7 @@ fun NavGraphBuilder.sendItemListingDestination(
|
||||
onNavigateToEditSendItem = onNavigateToEditSendItem,
|
||||
onNavigateToVaultAddItemScreen = { },
|
||||
onNavigateToVaultItemScreen = { },
|
||||
onNavigateToVaultEditItemScreen = { },
|
||||
onNavigateToSearch = { onNavigateToSearchSend(it as SearchType.Sends) },
|
||||
)
|
||||
}
|
||||
@@ -96,6 +99,7 @@ private fun NavGraphBuilder.internalVaultItemListingDestination(
|
||||
route: String,
|
||||
onNavigateBack: () -> Unit,
|
||||
onNavigateToVaultItemScreen: (id: String) -> Unit,
|
||||
onNavigateToVaultEditItemScreen: (cipherId: String) -> Unit,
|
||||
onNavigateToVaultAddItemScreen: () -> Unit,
|
||||
onNavigateToAddSendItem: () -> Unit,
|
||||
onNavigateToEditSendItem: (sendId: String) -> Unit,
|
||||
@@ -120,6 +124,7 @@ private fun NavGraphBuilder.internalVaultItemListingDestination(
|
||||
VaultItemListingScreen(
|
||||
onNavigateBack = onNavigateBack,
|
||||
onNavigateToVaultItem = onNavigateToVaultItemScreen,
|
||||
onNavigateToVaultEditItemScreen = onNavigateToVaultEditItemScreen,
|
||||
onNavigateToVaultAddItemScreen = onNavigateToVaultAddItemScreen,
|
||||
onNavigateToAddSendItem = onNavigateToAddSendItem,
|
||||
onNavigateToEditSendItem = onNavigateToEditSendItem,
|
||||
|
||||
@@ -21,6 +21,7 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.core.net.toUri
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
@@ -49,6 +50,7 @@ import kotlinx.collections.immutable.persistentListOf
|
||||
fun VaultItemListingScreen(
|
||||
onNavigateBack: () -> Unit,
|
||||
onNavigateToVaultItem: (id: String) -> Unit,
|
||||
onNavigateToVaultEditItemScreen: (cipherId: String) -> Unit,
|
||||
onNavigateToVaultAddItemScreen: () -> Unit,
|
||||
onNavigateToAddSendItem: () -> Unit,
|
||||
onNavigateToEditSendItem: (sendId: String) -> Unit,
|
||||
@@ -88,6 +90,14 @@ fun VaultItemListingScreen(
|
||||
onNavigateToVaultAddItemScreen()
|
||||
}
|
||||
|
||||
is VaultItemListingEvent.NavigateToEditCipher -> {
|
||||
onNavigateToVaultEditItemScreen(event.cipherId)
|
||||
}
|
||||
|
||||
is VaultItemListingEvent.NavigateToUrl -> {
|
||||
intentManager.launchUri(event.url.toUri())
|
||||
}
|
||||
|
||||
is VaultItemListingEvent.NavigateToAddSendItem -> {
|
||||
onNavigateToAddSendItem()
|
||||
}
|
||||
|
||||
@@ -182,6 +182,48 @@ class VaultItemListingViewModel @Inject constructor(
|
||||
sendEvent(event)
|
||||
}
|
||||
|
||||
private fun handleCopyNoteClick(action: ListingItemOverflowAction.VaultAction.CopyNoteClick) {
|
||||
clipboardManager.setText(action.notes)
|
||||
}
|
||||
|
||||
private fun handleCopyNumberClick(
|
||||
action: ListingItemOverflowAction.VaultAction.CopyNumberClick,
|
||||
) {
|
||||
clipboardManager.setText(action.number)
|
||||
}
|
||||
|
||||
private fun handleCopyPasswordClick(
|
||||
action: ListingItemOverflowAction.VaultAction.CopyPasswordClick,
|
||||
) {
|
||||
clipboardManager.setText(action.password)
|
||||
}
|
||||
|
||||
private fun handleCopySecurityCodeClick(
|
||||
action: ListingItemOverflowAction.VaultAction.CopySecurityCodeClick,
|
||||
) {
|
||||
clipboardManager.setText(action.securityCode)
|
||||
}
|
||||
|
||||
private fun handleCopyUsernameClick(
|
||||
action: ListingItemOverflowAction.VaultAction.CopyUsernameClick,
|
||||
) {
|
||||
clipboardManager.setText(action.username)
|
||||
}
|
||||
|
||||
private fun handleEditCipherClick(action: ListingItemOverflowAction.VaultAction.EditClick) {
|
||||
sendEvent(VaultItemListingEvent.NavigateToEditCipher(action.cipherId))
|
||||
}
|
||||
|
||||
private fun handleLaunchCipherUrlClick(
|
||||
action: ListingItemOverflowAction.VaultAction.LaunchClick,
|
||||
) {
|
||||
sendEvent(VaultItemListingEvent.NavigateToUrl(action.url))
|
||||
}
|
||||
|
||||
private fun handleViewCipherClick(action: ListingItemOverflowAction.VaultAction.ViewClick) {
|
||||
sendEvent(VaultItemListingEvent.NavigateToVaultItem(action.cipherId))
|
||||
}
|
||||
|
||||
private fun handleDismissDialogClick() {
|
||||
mutableStateFlow.update { it.copy(dialogState = null) }
|
||||
}
|
||||
@@ -236,6 +278,38 @@ class VaultItemListingViewModel @Inject constructor(
|
||||
is ListingItemOverflowAction.SendAction.ShareUrlClick -> {
|
||||
handleShareSendUrlClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.CopyNoteClick -> {
|
||||
handleCopyNoteClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.CopyNumberClick -> {
|
||||
handleCopyNumberClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.CopyPasswordClick -> {
|
||||
handleCopyPasswordClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.CopySecurityCodeClick -> {
|
||||
handleCopySecurityCodeClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.CopyUsernameClick -> {
|
||||
handleCopyUsernameClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.EditClick -> {
|
||||
handleEditCipherClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.LaunchClick -> {
|
||||
handleLaunchCipherUrlClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.ViewClick -> {
|
||||
handleViewCipherClick(overflowAction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -696,6 +770,20 @@ sealed class VaultItemListingEvent {
|
||||
*/
|
||||
data class NavigateToVaultItem(val id: String) : VaultItemListingEvent()
|
||||
|
||||
/**
|
||||
* Navigates to view a cipher.
|
||||
*/
|
||||
data class NavigateToEditCipher(
|
||||
val cipherId: String,
|
||||
) : VaultItemListingEvent()
|
||||
|
||||
/**
|
||||
* Navigates to the given [url].
|
||||
*/
|
||||
data class NavigateToUrl(
|
||||
val url: String,
|
||||
) : VaultItemListingEvent()
|
||||
|
||||
/**
|
||||
* Navigates to the SearchScreen with the given type filter.
|
||||
*/
|
||||
|
||||
@@ -60,4 +60,73 @@ sealed class ListingItemOverflowAction : Parcelable {
|
||||
override val title: Text get() = R.string.delete.asText()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the vault actions.
|
||||
*/
|
||||
sealed class VaultAction : ListingItemOverflowAction() {
|
||||
/**
|
||||
* Click on the view cipher overflow option.
|
||||
*/
|
||||
@Parcelize
|
||||
data class ViewClick(val cipherId: String) : VaultAction() {
|
||||
override val title: Text get() = R.string.view.asText()
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on the edit cipher overflow option.
|
||||
*/
|
||||
@Parcelize
|
||||
data class EditClick(val cipherId: String) : VaultAction() {
|
||||
override val title: Text get() = R.string.edit.asText()
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on the copy username overflow option.
|
||||
*/
|
||||
@Parcelize
|
||||
data class CopyUsernameClick(val username: String) : VaultAction() {
|
||||
override val title: Text get() = R.string.copy_username.asText()
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on the copy password overflow option.
|
||||
*/
|
||||
@Parcelize
|
||||
data class CopyPasswordClick(val password: String) : VaultAction() {
|
||||
override val title: Text get() = R.string.copy_password.asText()
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on the copy number overflow option.
|
||||
*/
|
||||
@Parcelize
|
||||
data class CopyNumberClick(val number: String) : VaultAction() {
|
||||
override val title: Text get() = R.string.copy_number.asText()
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on the copy security code overflow option.
|
||||
*/
|
||||
@Parcelize
|
||||
data class CopySecurityCodeClick(val securityCode: String) : VaultAction() {
|
||||
override val title: Text get() = R.string.copy_security_code.asText()
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on the copy secure note overflow option.
|
||||
*/
|
||||
@Parcelize
|
||||
data class CopyNoteClick(val notes: String) : VaultAction() {
|
||||
override val title: Text get() = R.string.copy_notes.asText()
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on the launch overflow option.
|
||||
*/
|
||||
@Parcelize
|
||||
data class LaunchClick(val url: String) : VaultAction() {
|
||||
override val title: Text get() = R.string.launch.asText()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.x8bit.bitwarden.ui.platform.util.toFormattedPattern
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.util.toLabelIcons
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.util.toOverflowActions
|
||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingState
|
||||
import com.x8bit.bitwarden.ui.vault.feature.util.toOverflowActions
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.util.toLoginIconData
|
||||
import java.time.Clock
|
||||
|
||||
@@ -173,7 +174,7 @@ private fun CipherView.toDisplayItem(
|
||||
isIconLoadingDisabled = isIconLoadingDisabled,
|
||||
),
|
||||
extraIconList = emptyList(),
|
||||
overflowOptions = emptyList(),
|
||||
overflowOptions = toOverflowActions(),
|
||||
)
|
||||
|
||||
private fun CipherView.toIconData(
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.x8bit.bitwarden.ui.vault.feature.util
|
||||
|
||||
import com.bitwarden.core.CipherType
|
||||
import com.bitwarden.core.CipherView
|
||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction
|
||||
|
||||
/**
|
||||
* Creates the list of overflow actions to be displayed for a [CipherView].
|
||||
*/
|
||||
fun CipherView.toOverflowActions(): List<ListingItemOverflowAction.VaultAction> =
|
||||
this
|
||||
.id
|
||||
?.let { cipherId ->
|
||||
listOfNotNull(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = cipherId),
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = cipherId)
|
||||
.takeUnless { this.deletedDate != null },
|
||||
this.login?.username?.let {
|
||||
ListingItemOverflowAction.VaultAction.CopyUsernameClick(username = it)
|
||||
},
|
||||
this.login?.password?.let {
|
||||
ListingItemOverflowAction.VaultAction.CopyPasswordClick(password = it)
|
||||
},
|
||||
this.card?.number?.let {
|
||||
ListingItemOverflowAction.VaultAction.CopyNumberClick(number = it)
|
||||
},
|
||||
this.card?.code?.let {
|
||||
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(securityCode = it)
|
||||
},
|
||||
this.notes
|
||||
?.let { ListingItemOverflowAction.VaultAction.CopyNoteClick(notes = it) }
|
||||
.takeIf { this.type == CipherType.SECURE_NOTE },
|
||||
this.login?.uris?.firstOrNull { it.uri != null }?.uri?.let {
|
||||
ListingItemOverflowAction.VaultAction.LaunchClick(url = it)
|
||||
},
|
||||
)
|
||||
}
|
||||
.orEmpty()
|
||||
@@ -44,6 +44,7 @@ fun NavGraphBuilder.vaultGraph(
|
||||
onNavigateToVaultItemScreen = onNavigateToVaultItemScreen,
|
||||
onNavigateToVaultAddItemScreen = onNavigateToVaultAddItemScreen,
|
||||
onNavigateToSearchVault = onNavigateToSearchVault,
|
||||
onNavigateToVaultEditItemScreen = onNavigateToVaultEditItemScreen,
|
||||
)
|
||||
|
||||
vaultVerificationCodeDestination(
|
||||
|
||||
@@ -37,7 +37,7 @@ fun createMockCipherView(
|
||||
name = "mockName-$number",
|
||||
notes = "mockNotes-$number",
|
||||
type = cipherType,
|
||||
login = createMockLoginView(number = number),
|
||||
login = createMockLoginView(number = number).takeIf { cipherType == CipherType.LOGIN },
|
||||
creationDate = ZonedDateTime
|
||||
.parse("2023-10-27T12:00:00Z")
|
||||
.toInstant(),
|
||||
@@ -52,13 +52,15 @@ fun createMockCipherView(
|
||||
.parse("2023-10-27T12:00:00Z")
|
||||
.toInstant(),
|
||||
attachments = listOf(createMockAttachmentView(number = number)),
|
||||
card = createMockCardView(number = number),
|
||||
card = createMockCardView(number = number).takeIf { cipherType == CipherType.CARD },
|
||||
fields = listOf(createMockFieldView(number = number)),
|
||||
identity = createMockIdentityView(number = number),
|
||||
identity = createMockIdentityView(number = number).takeIf {
|
||||
cipherType == CipherType.IDENTITY
|
||||
},
|
||||
favorite = false,
|
||||
passwordHistory = listOf(createMockPasswordHistoryView(number = number)),
|
||||
reprompt = CipherRepromptType.NONE,
|
||||
secureNote = createMockSecureNoteView(),
|
||||
secureNote = createMockSecureNoteView().takeIf { cipherType == CipherType.SECURE_NOTE },
|
||||
edit = false,
|
||||
organizationUseTotp = false,
|
||||
viewPassword = false,
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollToNode
|
||||
import androidx.core.net.toUri
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
@@ -43,6 +44,7 @@ class SearchScreenTest : BaseComposeTest() {
|
||||
}
|
||||
private val intentManager: IntentManager = mockk {
|
||||
every { shareText(any()) } just runs
|
||||
every { launchUri(any()) } just runs
|
||||
}
|
||||
|
||||
private var onNavigateBackCalled = false
|
||||
@@ -91,6 +93,15 @@ class SearchScreenTest : BaseComposeTest() {
|
||||
assertEquals(cipherId, onNavigateToViewCipherId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `NavigateToUrl should call launchUri on the IntentManager`() {
|
||||
val url = "www.test.com"
|
||||
mutableEventFlow.tryEmit(SearchEvent.NavigateToUrl(url))
|
||||
verify(exactly = 1) {
|
||||
intentManager.launchUri(url.toUri())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ShowShareSheet should call onNavigateBack`() {
|
||||
val sendUrl = "www.test.com"
|
||||
|
||||
@@ -301,6 +301,130 @@ class SearchViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault CopyNoteClick should call setText on the ClipboardManager`() =
|
||||
runTest {
|
||||
val notes = "notes"
|
||||
val viewModel = createViewModel()
|
||||
viewModel.actionChannel.trySend(
|
||||
SearchAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.CopyNoteClick(notes = notes),
|
||||
),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(notes)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault CopyNumberClick should call setText on the ClipboardManager`() =
|
||||
runTest {
|
||||
val number = "12345-4321-9876-6789"
|
||||
val viewModel = createViewModel()
|
||||
viewModel.actionChannel.trySend(
|
||||
SearchAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.CopyNumberClick(number = number),
|
||||
),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(number)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault CopyPasswordClick should call setText on the ClipboardManager`() =
|
||||
runTest {
|
||||
val password = "passTheWord"
|
||||
val viewModel = createViewModel()
|
||||
viewModel.actionChannel.trySend(
|
||||
SearchAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.CopyPasswordClick(password = password),
|
||||
),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(password)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault CopySecurityCodeClick should call setText on the ClipboardManager`() =
|
||||
runTest {
|
||||
val securityCode = "234"
|
||||
val viewModel = createViewModel()
|
||||
viewModel.actionChannel.trySend(
|
||||
SearchAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(
|
||||
securityCode = securityCode,
|
||||
),
|
||||
),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(securityCode)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault CopyUsernameClick should call setText on the ClipboardManager`() =
|
||||
runTest {
|
||||
val username = "bitwarden"
|
||||
val viewModel = createViewModel()
|
||||
viewModel.actionChannel.trySend(
|
||||
SearchAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.CopyUsernameClick(
|
||||
username = username,
|
||||
),
|
||||
),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(username)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault EditClick should emit NavigateToEditCipher`() = runTest {
|
||||
val cipherId = "cipherId-1234"
|
||||
val viewModel = createViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(
|
||||
SearchAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = cipherId),
|
||||
),
|
||||
)
|
||||
assertEquals(SearchEvent.NavigateToEditCipher(cipherId), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault LaunchClick should emit NavigateToUrl`() = runTest {
|
||||
val url = "www.test.com"
|
||||
val viewModel = createViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(
|
||||
SearchAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.LaunchClick(url = url),
|
||||
),
|
||||
)
|
||||
assertEquals(SearchEvent.NavigateToUrl(url), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault ViewClick should emit NavigateToUrl`() = runTest {
|
||||
val cipherId = "cipherId-9876"
|
||||
val viewModel = createViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(
|
||||
SearchAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = cipherId),
|
||||
),
|
||||
)
|
||||
assertEquals(SearchEvent.NavigateToViewCipher(cipherId), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Loaded with items should update ViewState to Content`() = runTest {
|
||||
setupMockUri()
|
||||
|
||||
@@ -27,7 +27,19 @@ fun createMockDisplayItemForCipher(
|
||||
fallbackIconRes = R.drawable.ic_login_item,
|
||||
),
|
||||
extraIconList = emptyList(),
|
||||
overflowOptions = emptyList(),
|
||||
overflowOptions = listOf(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.CopyUsernameClick(
|
||||
username = "mockUsername-$number",
|
||||
),
|
||||
ListingItemOverflowAction.VaultAction.CopyPasswordClick(
|
||||
password = "mockPassword-$number",
|
||||
),
|
||||
ListingItemOverflowAction.VaultAction.LaunchClick(
|
||||
url = "www.mockuri$number.com",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -38,7 +50,13 @@ fun createMockDisplayItemForCipher(
|
||||
subtitle = null,
|
||||
iconData = IconData.Local(R.drawable.ic_secure_note_item),
|
||||
extraIconList = emptyList(),
|
||||
overflowOptions = emptyList(),
|
||||
overflowOptions = listOf(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.CopyNoteClick(
|
||||
notes = "mockNotes-$number",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -49,7 +67,16 @@ fun createMockDisplayItemForCipher(
|
||||
subtitle = "er-$number",
|
||||
iconData = IconData.Local(R.drawable.ic_card_item),
|
||||
extraIconList = emptyList(),
|
||||
overflowOptions = emptyList(),
|
||||
overflowOptions = listOf(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.CopyNumberClick(
|
||||
number = "mockNumber-$number",
|
||||
),
|
||||
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(
|
||||
securityCode = "mockCode-$number",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -60,7 +87,10 @@ fun createMockDisplayItemForCipher(
|
||||
subtitle = "mockFirstName-${number}mockLastName-$number",
|
||||
iconData = IconData.Local(R.drawable.ic_identity_item),
|
||||
extraIconList = emptyList(),
|
||||
overflowOptions = emptyList(),
|
||||
overflowOptions = listOf(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollToNode
|
||||
import androidx.core.net.toUri
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.baseIconUrl
|
||||
@@ -51,10 +52,12 @@ class VaultItemListingScreenTest : BaseComposeTest() {
|
||||
private var onNavigateToAddSendScreenCalled = false
|
||||
private var onNavigateToEditSendItemId: String? = null
|
||||
private var onNavigateToVaultItemId: String? = null
|
||||
private var onNavigateToVaultEditItemScreenId: String? = null
|
||||
private var onNavigateToSearchType: SearchType? = null
|
||||
|
||||
private val intentManager: IntentManager = mockk {
|
||||
every { shareText(any()) } just runs
|
||||
every { launchUri(any()) } just runs
|
||||
}
|
||||
private val mutableEventFlow = bufferedMutableSharedFlow<VaultItemListingEvent>()
|
||||
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
|
||||
@@ -75,6 +78,7 @@ class VaultItemListingScreenTest : BaseComposeTest() {
|
||||
onNavigateToAddSendItem = { onNavigateToAddSendScreenCalled = true },
|
||||
onNavigateToEditSendItem = { onNavigateToEditSendItemId = it },
|
||||
onNavigateToSearch = { onNavigateToSearchType = it },
|
||||
onNavigateToVaultEditItemScreen = { onNavigateToVaultEditItemScreenId = it },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -157,6 +161,13 @@ class VaultItemListingScreenTest : BaseComposeTest() {
|
||||
assertEquals(searchType, onNavigateToSearchType)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `NavigateToEditCipher should call onNavigateToVaultEditItemScreen`() {
|
||||
val cipherId = "cipherId"
|
||||
mutableEventFlow.tryEmit(VaultItemListingEvent.NavigateToEditCipher(cipherId))
|
||||
assertEquals(cipherId, onNavigateToVaultEditItemScreenId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `NavigateToSendItem event should call onNavigateToEditSendItemId`() {
|
||||
val sendId = "sendId"
|
||||
@@ -171,6 +182,15 @@ class VaultItemListingScreenTest : BaseComposeTest() {
|
||||
assertEquals(id, onNavigateToVaultItemId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `NavigateToUrl should call launchUri on the IntentManager`() {
|
||||
val url = "www.test.com"
|
||||
mutableEventFlow.tryEmit(VaultItemListingEvent.NavigateToUrl(url))
|
||||
verify(exactly = 1) {
|
||||
intentManager.launchUri(url.toUri())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `progressbar should be displayed according to state`() {
|
||||
mutableStateFlow.update { DEFAULT_STATE }
|
||||
|
||||
@@ -53,7 +53,9 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
ZoneOffset.UTC,
|
||||
)
|
||||
|
||||
private val clipboardManager: BitwardenClipboardManager = mockk()
|
||||
private val clipboardManager: BitwardenClipboardManager = mockk {
|
||||
every { setText(any<String>()) } just runs
|
||||
}
|
||||
|
||||
private val mutableVaultDataStateFlow =
|
||||
MutableStateFlow<DataState<VaultData>>(DataState.Loading)
|
||||
@@ -350,18 +352,138 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault CopyNoteClick should call setText on the ClipboardManager`() =
|
||||
runTest {
|
||||
val notes = "notes"
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.actionChannel.trySend(
|
||||
VaultItemListingsAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.CopyNoteClick(notes = notes),
|
||||
),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(notes)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault CopyNumberClick should call setText on the ClipboardManager`() =
|
||||
runTest {
|
||||
val number = "12345-4321-9876-6789"
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.actionChannel.trySend(
|
||||
VaultItemListingsAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.CopyNumberClick(number = number),
|
||||
),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(number)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault CopyPasswordClick should call setText on the ClipboardManager`() =
|
||||
runTest {
|
||||
val password = "passTheWord"
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.actionChannel.trySend(
|
||||
VaultItemListingsAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.CopyPasswordClick(password = password),
|
||||
),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(password)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault CopySecurityCodeClick should call setText on the ClipboardManager`() =
|
||||
runTest {
|
||||
val securityCode = "234"
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.actionChannel.trySend(
|
||||
VaultItemListingsAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(
|
||||
securityCode = securityCode,
|
||||
),
|
||||
),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(securityCode)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault CopyUsernameClick should call setText on the ClipboardManager`() =
|
||||
runTest {
|
||||
val username = "bitwarden"
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.actionChannel.trySend(
|
||||
VaultItemListingsAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.CopyUsernameClick(
|
||||
username = username,
|
||||
),
|
||||
),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(username)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault EditClick should emit NavigateToEditCipher`() = runTest {
|
||||
val cipherId = "cipherId-1234"
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(
|
||||
VaultItemListingsAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = cipherId),
|
||||
),
|
||||
)
|
||||
assertEquals(VaultItemListingEvent.NavigateToEditCipher(cipherId), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault LaunchClick should emit NavigateToUrl`() = runTest {
|
||||
val url = "www.test.com"
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(
|
||||
VaultItemListingsAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.LaunchClick(url = url),
|
||||
),
|
||||
)
|
||||
assertEquals(VaultItemListingEvent.NavigateToUrl(url), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault ViewClick should emit NavigateToUrl`() = runTest {
|
||||
val cipherId = "cipherId-9876"
|
||||
val viewModel = createVaultItemListingViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(
|
||||
VaultItemListingsAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = cipherId),
|
||||
),
|
||||
)
|
||||
assertEquals(VaultItemListingEvent.NavigateToVaultItem(cipherId), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `vaultDataStateFlow Loaded with items should update ViewState to Content`() =
|
||||
runTest {
|
||||
setupMockUri()
|
||||
|
||||
val dataState = DataState.Loaded(
|
||||
data = VaultData(
|
||||
cipherViewList = listOf(
|
||||
createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = false,
|
||||
),
|
||||
),
|
||||
cipherViewList = listOf(createMockCipherView(number = 1, isDeleted = false)),
|
||||
folderViewList = listOf(createMockFolderView(number = 1)),
|
||||
collectionViewList = listOf(createMockCollectionView(number = 1)),
|
||||
sendViewList = listOf(createMockSendView(number = 1)),
|
||||
|
||||
@@ -28,7 +28,19 @@ fun createMockDisplayItemForCipher(
|
||||
fallbackIconRes = R.drawable.ic_login_item,
|
||||
),
|
||||
extraIconList = emptyList(),
|
||||
overflowOptions = emptyList(),
|
||||
overflowOptions = listOf(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.CopyUsernameClick(
|
||||
username = "mockUsername-$number",
|
||||
),
|
||||
ListingItemOverflowAction.VaultAction.CopyPasswordClick(
|
||||
password = "mockPassword-$number",
|
||||
),
|
||||
ListingItemOverflowAction.VaultAction.LaunchClick(
|
||||
url = "www.mockuri$number.com",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -39,7 +51,13 @@ fun createMockDisplayItemForCipher(
|
||||
subtitle = subtitle,
|
||||
iconData = IconData.Local(R.drawable.ic_secure_note_item),
|
||||
extraIconList = emptyList(),
|
||||
overflowOptions = emptyList(),
|
||||
overflowOptions = listOf(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.CopyNoteClick(
|
||||
notes = "mockNotes-$number",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -50,7 +68,16 @@ fun createMockDisplayItemForCipher(
|
||||
subtitle = subtitle,
|
||||
iconData = IconData.Local(R.drawable.ic_card_item),
|
||||
extraIconList = emptyList(),
|
||||
overflowOptions = emptyList(),
|
||||
overflowOptions = listOf(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.CopyNumberClick(
|
||||
number = "mockNumber-$number",
|
||||
),
|
||||
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(
|
||||
securityCode = "mockCode-$number",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -61,7 +88,10 @@ fun createMockDisplayItemForCipher(
|
||||
subtitle = subtitle,
|
||||
iconData = IconData.Local(R.drawable.ic_identity_item),
|
||||
extraIconList = emptyList(),
|
||||
overflowOptions = emptyList(),
|
||||
overflowOptions = listOf(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = "mockId-$number"),
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = "mockId-$number"),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
package com.x8bit.bitwarden.ui.vault.feature.util
|
||||
|
||||
import com.bitwarden.core.CipherType
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCardView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCipherView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockIdentityView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockLoginView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockSecureNoteView
|
||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockUriView
|
||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class CipherViewExtensionsTest {
|
||||
|
||||
@Test
|
||||
fun `toOverflowActions should return all actions for a login cipher`() {
|
||||
val id = "mockId-1"
|
||||
val username = "Bitwarden"
|
||||
val password = "password"
|
||||
val uri = "www.test.com"
|
||||
val cipher = createMockCipherView(number = 1, cipherType = CipherType.LOGIN).copy(
|
||||
id = id,
|
||||
login = createMockLoginView(number = 1).copy(
|
||||
username = username,
|
||||
password = password,
|
||||
uris = listOf(createMockUriView(number = 1).copy(uri = uri)),
|
||||
),
|
||||
)
|
||||
|
||||
val result = cipher.toOverflowActions()
|
||||
|
||||
assertEquals(
|
||||
listOf(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id),
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = id),
|
||||
ListingItemOverflowAction.VaultAction.CopyUsernameClick(username = username),
|
||||
ListingItemOverflowAction.VaultAction.CopyPasswordClick(password = password),
|
||||
ListingItemOverflowAction.VaultAction.LaunchClick(url = uri),
|
||||
),
|
||||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toOverflowActions should return minimum actions for a login cipher`() {
|
||||
val id = "mockId-1"
|
||||
val cipher = createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = true,
|
||||
cipherType = CipherType.LOGIN,
|
||||
)
|
||||
.copy(
|
||||
id = id,
|
||||
login = createMockLoginView(number = 1).copy(
|
||||
username = null,
|
||||
password = null,
|
||||
uris = null,
|
||||
),
|
||||
)
|
||||
|
||||
val result = cipher.toOverflowActions()
|
||||
|
||||
assertEquals(
|
||||
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
|
||||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toOverflowActions should return all actions for a card cipher`() {
|
||||
val id = "mockId-1"
|
||||
val number = "1322-2414-7634-2354"
|
||||
val securityCode = "123"
|
||||
val cipher = createMockCipherView(number = 1, cipherType = CipherType.CARD).copy(
|
||||
id = id,
|
||||
card = createMockCardView(number = 1).copy(
|
||||
number = number,
|
||||
code = securityCode,
|
||||
),
|
||||
)
|
||||
|
||||
val result = cipher.toOverflowActions()
|
||||
|
||||
assertEquals(
|
||||
listOf(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id),
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = id),
|
||||
ListingItemOverflowAction.VaultAction.CopyNumberClick(number = number),
|
||||
ListingItemOverflowAction.VaultAction.CopySecurityCodeClick(
|
||||
securityCode = securityCode,
|
||||
),
|
||||
),
|
||||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toOverflowActions should return minimum actions for a card cipher`() {
|
||||
val id = "mockId-1"
|
||||
val cipher = createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = true,
|
||||
cipherType = CipherType.CARD,
|
||||
)
|
||||
.copy(
|
||||
id = id,
|
||||
card = createMockCardView(number = 1).copy(
|
||||
number = null,
|
||||
code = null,
|
||||
),
|
||||
)
|
||||
|
||||
val result = cipher.toOverflowActions()
|
||||
|
||||
assertEquals(
|
||||
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
|
||||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toOverflowActions should return all actions for a identity cipher`() {
|
||||
val id = "mockId-1"
|
||||
val cipher = createMockCipherView(number = 1, cipherType = CipherType.IDENTITY).copy(
|
||||
id = id,
|
||||
identity = createMockIdentityView(number = 1),
|
||||
)
|
||||
|
||||
val result = cipher.toOverflowActions()
|
||||
|
||||
assertEquals(
|
||||
listOf(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id),
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = id),
|
||||
),
|
||||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toOverflowActions should return minimum actions for a identity cipher`() {
|
||||
val id = "mockId-1"
|
||||
val cipher = createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = true,
|
||||
cipherType = CipherType.IDENTITY,
|
||||
)
|
||||
.copy(
|
||||
id = id,
|
||||
identity = createMockIdentityView(number = 1),
|
||||
)
|
||||
|
||||
val result = cipher.toOverflowActions()
|
||||
|
||||
assertEquals(
|
||||
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
|
||||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toOverflowActions should return all actions for a secure note cipher`() {
|
||||
val id = "mockId-1"
|
||||
val notes = "so secure"
|
||||
val cipher = createMockCipherView(number = 1, cipherType = CipherType.SECURE_NOTE).copy(
|
||||
id = id,
|
||||
secureNote = createMockSecureNoteView(),
|
||||
notes = notes,
|
||||
)
|
||||
|
||||
val result = cipher.toOverflowActions()
|
||||
|
||||
assertEquals(
|
||||
listOf(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id),
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = id),
|
||||
ListingItemOverflowAction.VaultAction.CopyNoteClick(notes = notes),
|
||||
),
|
||||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toOverflowActions should return minimum actions for a secure note cipher`() {
|
||||
val id = "mockId-1"
|
||||
val cipher = createMockCipherView(
|
||||
number = 1,
|
||||
isDeleted = true,
|
||||
cipherType = CipherType.SECURE_NOTE,
|
||||
)
|
||||
.copy(
|
||||
id = id,
|
||||
secureNote = createMockSecureNoteView(),
|
||||
notes = null,
|
||||
)
|
||||
|
||||
val result = cipher.toOverflowActions()
|
||||
|
||||
assertEquals(
|
||||
listOf(ListingItemOverflowAction.VaultAction.ViewClick(cipherId = id)),
|
||||
result,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user