mirror of
https://github.com/bitwarden/android.git
synced 2025-02-17 04:19:54 +03:00
Vault screen overflow option actions (#739)
This commit is contained in:
parent
9a371843ee
commit
376278e97a
8 changed files with 285 additions and 14 deletions
|
@ -79,6 +79,8 @@ fun VaultContent(
|
|||
label = favoriteItem.name(),
|
||||
supportingLabel = favoriteItem.supportingLabel?.invoke(),
|
||||
onClick = { vaultHandlers.vaultItemClick(favoriteItem) },
|
||||
overflowOptions = favoriteItem.overflowOptions,
|
||||
onOverflowOptionClick = vaultHandlers.overflowOptionClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
|
@ -227,12 +229,13 @@ fun VaultContent(
|
|||
)
|
||||
}
|
||||
items(state.noFolderItems) { noFolderItem ->
|
||||
|
||||
VaultEntryListItem(
|
||||
startIcon = noFolderItem.startIcon,
|
||||
label = noFolderItem.name(),
|
||||
supportingLabel = noFolderItem.supportingLabel?.invoke(),
|
||||
onClick = { vaultHandlers.vaultItemClick(noFolderItem) },
|
||||
overflowOptions = noFolderItem.overflowOptions,
|
||||
onOverflowOptionClick = vaultHandlers.overflowOptionClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.vault
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenListItem
|
||||
import com.x8bit.bitwarden.ui.platform.components.SelectionItemData
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.IconData
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
/**
|
||||
* A Composable function that displays a row item for different types of vault entries.
|
||||
|
@ -18,6 +17,8 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
* @param label The primary text label to display for the item.
|
||||
* @param supportingLabel An optional secondary text label to display beneath the primary label.
|
||||
* @param onClick The lambda to be invoked when the item is clicked.
|
||||
* @param overflowOptions List of options to display for the item.
|
||||
* @param onOverflowOptionClick The lambda to be invoked when an overflow option is clicked.
|
||||
* @param modifier An optional [Modifier] for this Composable, defaulting to an empty Modifier.
|
||||
* This allows the caller to specify things like padding, size, etc.
|
||||
*/
|
||||
|
@ -26,25 +27,25 @@ fun VaultEntryListItem(
|
|||
startIcon: IconData,
|
||||
label: String,
|
||||
onClick: () -> Unit,
|
||||
overflowOptions: List<ListingItemOverflowAction.VaultAction>,
|
||||
onOverflowOptionClick: (ListingItemOverflowAction.VaultAction) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
supportingLabel: String? = null,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
BitwardenListItem(
|
||||
modifier = modifier,
|
||||
label = label,
|
||||
supportingLabel = supportingLabel,
|
||||
startIcon = startIcon,
|
||||
onClick = onClick,
|
||||
selectionDataList = persistentListOf(
|
||||
SelectionItemData(
|
||||
text = "Not yet implemented",
|
||||
onClick = {
|
||||
// TODO: Provide dialog-based implementation (BIT-1353 - BIT-1356)
|
||||
Toast.makeText(context, "Not yet implemented.", Toast.LENGTH_SHORT).show()
|
||||
},
|
||||
),
|
||||
),
|
||||
selectionDataList = overflowOptions
|
||||
.map { option ->
|
||||
SelectionItemData(
|
||||
text = option.title(),
|
||||
onClick = { onOverflowOptionClick(option) },
|
||||
)
|
||||
}
|
||||
.toImmutableList(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -57,6 +58,8 @@ private fun VaultEntryListItem_preview() {
|
|||
label = "Example Login",
|
||||
supportingLabel = "Username",
|
||||
onClick = {},
|
||||
overflowOptions = emptyList(),
|
||||
onOverflowOptionClick = {},
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -31,6 +31,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 com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
|
@ -51,7 +52,9 @@ import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
|
|||
import com.x8bit.bitwarden.ui.platform.components.OverflowMenuItemData
|
||||
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||
import com.x8bit.bitwarden.ui.platform.manager.exit.ExitManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.theme.LocalExitManager
|
||||
import com.x8bit.bitwarden.ui.platform.theme.LocalIntentManager
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.handlers.VaultHandlers
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
@ -73,6 +76,7 @@ fun VaultScreen(
|
|||
onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit,
|
||||
onDimBottomNavBarRequest: (shouldDim: Boolean) -> Unit,
|
||||
exitManager: ExitManager = LocalExitManager.current,
|
||||
intentManager: IntentManager = LocalIntentManager.current,
|
||||
) {
|
||||
val state by viewModel.stateFlow.collectAsState()
|
||||
val context = LocalContext.current
|
||||
|
@ -102,6 +106,8 @@ fun VaultScreen(
|
|||
onNavigateToVaultItemListingScreen(event.itemListingType)
|
||||
}
|
||||
|
||||
is VaultEvent.NavigateToUrl -> intentManager.launchUri(event.url.toUri())
|
||||
|
||||
VaultEvent.NavigateOutOfApp -> exitManager.exitApplication()
|
||||
is VaultEvent.ShowToast -> {
|
||||
Toast
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.x8bit.bitwarden.R
|
|||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.SwitchAccountResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.baseIconUrl
|
||||
|
@ -19,6 +20,7 @@ import com.x8bit.bitwarden.ui.platform.base.util.concat
|
|||
import com.x8bit.bitwarden.ui.platform.base.util.hexToColor
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.IconData
|
||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterData
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.util.initials
|
||||
|
@ -43,6 +45,7 @@ import javax.inject.Inject
|
|||
@Suppress("TooManyFunctions")
|
||||
@HiltViewModel
|
||||
class VaultViewModel @Inject constructor(
|
||||
private val clipboardManager: BitwardenClipboardManager,
|
||||
private val authRepository: AuthRepository,
|
||||
private val vaultRepository: VaultRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
|
@ -128,6 +131,7 @@ class VaultViewModel @Inject constructor(
|
|||
is VaultAction.TryAgainClick -> handleTryAgainClick()
|
||||
is VaultAction.DialogDismiss -> handleDialogDismiss()
|
||||
is VaultAction.RefreshPull -> handleRefreshPull()
|
||||
is VaultAction.OverflowOptionClick -> handleOverflowOptionClick(action)
|
||||
is VaultAction.Internal -> handleInternalAction(action)
|
||||
}
|
||||
}
|
||||
|
@ -270,6 +274,82 @@ class VaultViewModel @Inject constructor(
|
|||
vaultRepository.sync()
|
||||
}
|
||||
|
||||
private fun handleOverflowOptionClick(action: VaultAction.OverflowOptionClick) {
|
||||
when (val overflowAction = action.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 -> {
|
||||
handleEditClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.LaunchClick -> {
|
||||
handleLaunchClick(overflowAction)
|
||||
}
|
||||
|
||||
is ListingItemOverflowAction.VaultAction.ViewClick -> {
|
||||
handleViewClick(overflowAction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 handleEditClick(action: ListingItemOverflowAction.VaultAction.EditClick) {
|
||||
sendEvent(VaultEvent.NavigateToEditVaultItem(action.cipherId))
|
||||
}
|
||||
|
||||
private fun handleLaunchClick(action: ListingItemOverflowAction.VaultAction.LaunchClick) {
|
||||
sendEvent(VaultEvent.NavigateToUrl(action.url))
|
||||
}
|
||||
|
||||
private fun handleViewClick(action: ListingItemOverflowAction.VaultAction.ViewClick) {
|
||||
sendEvent(VaultEvent.NavigateToVaultItem(action.cipherId))
|
||||
}
|
||||
|
||||
private fun handleInternalAction(action: VaultAction.Internal) {
|
||||
when (action) {
|
||||
is VaultAction.Internal.PullToRefreshEnableReceive -> {
|
||||
|
@ -584,6 +664,11 @@ data class VaultState(
|
|||
*/
|
||||
abstract val supportingLabel: Text?
|
||||
|
||||
/**
|
||||
* The overflow options to be displayed for the vault item.
|
||||
*/
|
||||
abstract val overflowOptions: List<ListingItemOverflowAction.VaultAction>
|
||||
|
||||
/**
|
||||
* Represents a login item within the vault.
|
||||
*
|
||||
|
@ -594,6 +679,7 @@ data class VaultState(
|
|||
override val id: String,
|
||||
override val name: Text,
|
||||
override val startIcon: IconData = IconData.Local(R.drawable.ic_login_item),
|
||||
override val overflowOptions: List<ListingItemOverflowAction.VaultAction>,
|
||||
val username: Text?,
|
||||
) : VaultItem() {
|
||||
override val supportingLabel: Text? get() = username
|
||||
|
@ -610,6 +696,7 @@ data class VaultState(
|
|||
override val id: String,
|
||||
override val name: Text,
|
||||
override val startIcon: IconData = IconData.Local(R.drawable.ic_card_item),
|
||||
override val overflowOptions: List<ListingItemOverflowAction.VaultAction>,
|
||||
val brand: Text? = null,
|
||||
val lastFourDigits: Text? = null,
|
||||
) : VaultItem() {
|
||||
|
@ -636,6 +723,7 @@ data class VaultState(
|
|||
override val id: String,
|
||||
override val name: Text,
|
||||
override val startIcon: IconData = IconData.Local(R.drawable.ic_identity_item),
|
||||
override val overflowOptions: List<ListingItemOverflowAction.VaultAction>,
|
||||
val firstName: Text?,
|
||||
) : VaultItem() {
|
||||
override val supportingLabel: Text? get() = firstName
|
||||
|
@ -650,6 +738,7 @@ data class VaultState(
|
|||
override val id: String,
|
||||
override val name: Text,
|
||||
override val startIcon: IconData = IconData.Local(R.drawable.ic_secure_note_item),
|
||||
override val overflowOptions: List<ListingItemOverflowAction.VaultAction>,
|
||||
) : VaultItem() {
|
||||
override val supportingLabel: Text? get() = null
|
||||
}
|
||||
|
@ -726,6 +815,13 @@ sealed class VaultEvent {
|
|||
val itemListingType: VaultItemListingType,
|
||||
) : VaultEvent()
|
||||
|
||||
/**
|
||||
* Navigates to the given [url].
|
||||
*/
|
||||
data class NavigateToUrl(
|
||||
val url: String,
|
||||
) : VaultEvent()
|
||||
|
||||
/**
|
||||
* Navigate to the verification code screen.
|
||||
*/
|
||||
|
@ -874,6 +970,13 @@ sealed class VaultAction {
|
|||
*/
|
||||
data object TryAgainClick : VaultAction()
|
||||
|
||||
/**
|
||||
* User clicked an overflow action.
|
||||
*/
|
||||
data class OverflowOptionClick(
|
||||
val overflowAction: ListingItemOverflowAction.VaultAction,
|
||||
) : VaultAction()
|
||||
|
||||
/**
|
||||
* Models actions that the [VaultViewModel] itself might send.
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.vault.handlers
|
||||
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
|
||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.VaultAction
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.VaultState
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.VaultViewModel
|
||||
|
@ -31,6 +32,7 @@ data class VaultHandlers(
|
|||
val trashClick: () -> Unit,
|
||||
val tryAgainClick: () -> Unit,
|
||||
val dialogDismiss: () -> Unit,
|
||||
val overflowOptionClick: (ListingItemOverflowAction.VaultAction) -> Unit,
|
||||
) {
|
||||
companion object {
|
||||
/**
|
||||
|
@ -74,6 +76,9 @@ data class VaultHandlers(
|
|||
trashClick = { viewModel.trySendAction(VaultAction.TrashClick) },
|
||||
tryAgainClick = { viewModel.trySendAction(VaultAction.TryAgainClick) },
|
||||
dialogDismiss = { viewModel.trySendAction(VaultAction.DialogDismiss) },
|
||||
overflowOptionClick = {
|
||||
viewModel.trySendAction(VaultAction.OverflowOptionClick(it))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.x8bit.bitwarden.R
|
|||
import com.x8bit.bitwarden.data.vault.repository.model.VaultData
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.IconData
|
||||
import com.x8bit.bitwarden.ui.vault.feature.util.toOverflowActions
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.VaultState
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType
|
||||
|
||||
|
@ -156,11 +157,13 @@ private fun CipherView.toVaultItemOrNull(
|
|||
isIconLoadingDisabled = isIconLoadingDisabled,
|
||||
baseIconUrl = baseIconUrl,
|
||||
),
|
||||
overflowOptions = toOverflowActions(),
|
||||
)
|
||||
|
||||
CipherType.SECURE_NOTE -> VaultState.ViewState.VaultItem.SecureNote(
|
||||
id = id,
|
||||
name = name.asText(),
|
||||
overflowOptions = toOverflowActions(),
|
||||
)
|
||||
|
||||
CipherType.CARD -> VaultState.ViewState.VaultItem.Card(
|
||||
|
@ -170,12 +173,14 @@ private fun CipherView.toVaultItemOrNull(
|
|||
lastFourDigits = card?.number
|
||||
?.takeLast(4)
|
||||
?.asText(),
|
||||
overflowOptions = toOverflowActions(),
|
||||
)
|
||||
|
||||
CipherType.IDENTITY -> VaultState.ViewState.VaultItem.Identity(
|
||||
id = id,
|
||||
name = name.asText(),
|
||||
firstName = identity?.firstName?.asText(),
|
||||
overflowOptions = toOverflowActions(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,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
|
||||
|
@ -23,6 +24,7 @@ import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
|||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
|
||||
import com.x8bit.bitwarden.ui.platform.manager.exit.ExitManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
import com.x8bit.bitwarden.ui.util.assertLockOrLogoutDialogIsDisplayed
|
||||
import com.x8bit.bitwarden.ui.util.assertLogoutConfirmationDialogIsDisplayed
|
||||
import com.x8bit.bitwarden.ui.util.assertNoDialogExists
|
||||
|
@ -63,6 +65,7 @@ class VaultScreenTest : BaseComposeTest() {
|
|||
private var onNavigateToVerificationCodeScreen = false
|
||||
private var onNavigateToSearchScreen = false
|
||||
private val exitManager = mockk<ExitManager>(relaxed = true)
|
||||
private val intentManager = mockk<IntentManager>(relaxed = true)
|
||||
|
||||
private val mutableEventFlow = bufferedMutableSharedFlow<VaultEvent>()
|
||||
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
|
||||
|
@ -84,6 +87,7 @@ class VaultScreenTest : BaseComposeTest() {
|
|||
onNavigateToVerificationCodeScreen = { onNavigateToVerificationCodeScreen = true },
|
||||
onNavigateToSearchVault = { onNavigateToSearchScreen = true },
|
||||
exitManager = exitManager,
|
||||
intentManager = intentManager,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -653,6 +657,15 @@ class VaultScreenTest : BaseComposeTest() {
|
|||
assertEquals(VaultItemListingType.Folder(mockFolderId), onNavigateToVaultItemListingType)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `NavigateToUrl event should call launchUri`() {
|
||||
val url = "www.test.com"
|
||||
mutableEventFlow.tryEmit(VaultEvent.NavigateToUrl(url))
|
||||
verify(exactly = 1) {
|
||||
intentManager.launchUri(url.toUri())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `NavigateOutOfApp event should call exitApplication on the ExitManager`() {
|
||||
mutableEventFlow.tryEmit(VaultEvent.NavigateOutOfApp)
|
||||
|
@ -722,6 +735,7 @@ class VaultScreenTest : BaseComposeTest() {
|
|||
id = "12345",
|
||||
name = itemText.asText(),
|
||||
username = username.asText(),
|
||||
overflowOptions = emptyList(),
|
||||
)
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
|
@ -842,6 +856,7 @@ class VaultScreenTest : BaseComposeTest() {
|
|||
id = "12345",
|
||||
name = itemText.asText(),
|
||||
username = userName.asText(),
|
||||
overflowOptions = emptyList(),
|
||||
)
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
|
|
|
@ -6,6 +6,7 @@ import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
|||
import com.x8bit.bitwarden.data.auth.repository.model.Organization
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.SwitchAccountResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
|
@ -19,6 +20,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.VaultData
|
|||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
|
||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterData
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.util.toViewState
|
||||
|
@ -38,6 +40,10 @@ import org.junit.jupiter.api.Test
|
|||
@Suppress("LargeClass")
|
||||
class VaultViewModelTest : BaseViewModelTest() {
|
||||
|
||||
private val clipboardManager: BitwardenClipboardManager = mockk {
|
||||
every { setText(any<String>()) } just runs
|
||||
}
|
||||
|
||||
private val mutablePullToRefreshEnabledFlow = MutableStateFlow(false)
|
||||
private val mutableIsIconLoadingDisabledFlow = MutableStateFlow(false)
|
||||
|
||||
|
@ -1055,8 +1061,133 @@ class VaultViewModelTest : BaseViewModelTest() {
|
|||
assertTrue(viewModel.stateFlow.value.isIconLoadingDisabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault CopyNoteClick should call setText on the ClipboardManager`() =
|
||||
runTest {
|
||||
val notes = "notes"
|
||||
val viewModel = createViewModel()
|
||||
viewModel.actionChannel.trySend(
|
||||
VaultAction.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(
|
||||
VaultAction.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(
|
||||
VaultAction.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(
|
||||
VaultAction.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(
|
||||
VaultAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.CopyUsernameClick(
|
||||
username = username,
|
||||
),
|
||||
),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(username)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OverflowOptionClick Vault EditClick should emit NavigateToEditVaultItem`() = runTest {
|
||||
val cipherId = "cipherId-1234"
|
||||
val viewModel = createViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(
|
||||
VaultAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.EditClick(cipherId = cipherId),
|
||||
),
|
||||
)
|
||||
assertEquals(VaultEvent.NavigateToEditVaultItem(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(
|
||||
VaultAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.LaunchClick(url = url),
|
||||
),
|
||||
)
|
||||
assertEquals(VaultEvent.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(
|
||||
VaultAction.OverflowOptionClick(
|
||||
ListingItemOverflowAction.VaultAction.ViewClick(cipherId = cipherId),
|
||||
),
|
||||
)
|
||||
assertEquals(VaultEvent.NavigateToVaultItem(cipherId), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
private fun createViewModel(): VaultViewModel =
|
||||
VaultViewModel(
|
||||
clipboardManager = clipboardManager,
|
||||
authRepository = authRepository,
|
||||
settingsRepository = settingsRepository,
|
||||
vaultRepository = vaultRepository,
|
||||
|
|
Loading…
Add table
Reference in a new issue