mirror of
https://github.com/bitwarden/android.git
synced 2026-03-12 05:04:17 -05:00
BWA-124 - 'Copy' Option Missing from Long-Press Menu (#300)
This commit is contained in:
@@ -53,6 +53,8 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bitwarden.authenticator.R
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.ItemListingExpandableFabAction
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.SharedCodesDisplayState
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VaultDropdownMenuAction
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem
|
||||
import com.bitwarden.authenticator.ui.platform.base.util.EventsEffect
|
||||
import com.bitwarden.authenticator.ui.platform.base.util.asText
|
||||
import com.bitwarden.authenticator.ui.platform.components.appbar.BitwardenMediumTopAppBar
|
||||
@@ -211,17 +213,13 @@ fun ItemListingScreen(
|
||||
)
|
||||
}
|
||||
},
|
||||
onEditItemClick = remember(viewModel) {
|
||||
{
|
||||
onDropdownMenuClick = remember(viewModel) {
|
||||
{ action, item ->
|
||||
viewModel.trySendAction(
|
||||
ItemListingAction.EditItemClick(it),
|
||||
)
|
||||
}
|
||||
},
|
||||
onDeleteItemClick = remember(viewModel) {
|
||||
{
|
||||
viewModel.trySendAction(
|
||||
ItemListingAction.DeleteItemClick(it),
|
||||
ItemListingAction.DropdownMenuClick(
|
||||
menuAction = action,
|
||||
item = item,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -245,11 +243,6 @@ fun ItemListingScreen(
|
||||
viewModel.trySendAction(ItemListingAction.SyncWithBitwardenDismiss)
|
||||
}
|
||||
},
|
||||
onMoveToBitwardenClick = remember(viewModel) {
|
||||
{
|
||||
viewModel.trySendAction(ItemListingAction.MoveToBitwardenClick(it))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -354,9 +347,7 @@ private fun ItemListingContent(
|
||||
onScanQrCodeClick: () -> Unit,
|
||||
onEnterSetupKeyClick: () -> Unit,
|
||||
onItemClick: (String) -> Unit,
|
||||
onEditItemClick: (String) -> Unit,
|
||||
onDeleteItemClick: (String) -> Unit,
|
||||
onMoveToBitwardenClick: (String) -> Unit,
|
||||
onDropdownMenuClick: (VaultDropdownMenuAction, VerificationCodeDisplayItem) -> Unit,
|
||||
onDownloadBitwardenClick: () -> Unit,
|
||||
onDismissDownloadBitwardenClick: () -> Unit,
|
||||
onSyncWithBitwardenClick: () -> Unit,
|
||||
@@ -467,9 +458,9 @@ private fun ItemListingContent(
|
||||
alertThresholdSeconds = it.alertThresholdSeconds,
|
||||
startIcon = it.startIcon,
|
||||
onItemClick = { onItemClick(it.authCode) },
|
||||
onEditItemClick = { onEditItemClick(it.id) },
|
||||
onDeleteItemClick = { onDeleteItemClick(it.id) },
|
||||
onMoveToBitwardenClick = { onMoveToBitwardenClick(it.id) },
|
||||
onDropdownMenuClick = { action ->
|
||||
onDropdownMenuClick(action, it)
|
||||
},
|
||||
showMoveToBitwarden = it.showMoveToBitwarden,
|
||||
allowLongPress = it.allowLongPressActions,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
@@ -508,9 +499,9 @@ private fun ItemListingContent(
|
||||
alertThresholdSeconds = it.alertThresholdSeconds,
|
||||
startIcon = it.startIcon,
|
||||
onItemClick = { onItemClick(it.authCode) },
|
||||
onEditItemClick = { onEditItemClick(it.id) },
|
||||
onDeleteItemClick = { onDeleteItemClick(it.id) },
|
||||
onMoveToBitwardenClick = { onMoveToBitwardenClick(it.id) },
|
||||
onDropdownMenuClick = { action ->
|
||||
onDropdownMenuClick(action, it)
|
||||
},
|
||||
showMoveToBitwarden = it.showMoveToBitwarden,
|
||||
allowLongPress = it.allowLongPressActions,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
@@ -544,9 +535,9 @@ private fun ItemListingContent(
|
||||
alertThresholdSeconds = it.alertThresholdSeconds,
|
||||
startIcon = it.startIcon,
|
||||
onItemClick = { onItemClick(it.authCode) },
|
||||
onEditItemClick = { },
|
||||
onDeleteItemClick = { },
|
||||
onMoveToBitwardenClick = { },
|
||||
onDropdownMenuClick = { action ->
|
||||
onDropdownMenuClick(action, it)
|
||||
},
|
||||
showMoveToBitwarden = it.showMoveToBitwarden,
|
||||
allowLongPress = it.allowLongPressActions,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.bitwarden.authenticator.data.platform.manager.imports.model.GoogleAut
|
||||
import com.bitwarden.authenticator.data.platform.repository.SettingsRepository
|
||||
import com.bitwarden.authenticator.data.platform.repository.model.DataState
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.SharedCodesDisplayState
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VaultDropdownMenuAction
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util.toDisplayItem
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util.toSharedCodesDisplayState
|
||||
@@ -62,7 +63,6 @@ class ItemListingViewModel @Inject constructor(
|
||||
) {
|
||||
|
||||
init {
|
||||
|
||||
settingsRepository
|
||||
.authenticatorAlertThresholdSecondsFlow
|
||||
.map { ItemListingAction.Internal.AlertThresholdSecondsReceive(it) }
|
||||
@@ -110,10 +110,6 @@ class ItemListingViewModel @Inject constructor(
|
||||
sendEvent(ItemListingEvent.NavigateBack)
|
||||
}
|
||||
|
||||
is ItemListingAction.DeleteItemClick -> {
|
||||
handleDeleteItemClick(action)
|
||||
}
|
||||
|
||||
is ItemListingAction.ConfirmDeleteClick -> {
|
||||
handleConfirmDeleteClick(action)
|
||||
}
|
||||
@@ -123,11 +119,7 @@ class ItemListingViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
is ItemListingAction.ItemClick -> {
|
||||
handleItemClick(action)
|
||||
}
|
||||
|
||||
is ItemListingAction.EditItemClick -> {
|
||||
handleEditItemClick(action)
|
||||
handleCopyItemClick(action.authCode)
|
||||
}
|
||||
|
||||
is ItemListingAction.DialogDismiss -> {
|
||||
@@ -142,6 +134,10 @@ class ItemListingViewModel @Inject constructor(
|
||||
handleInternalAction(action)
|
||||
}
|
||||
|
||||
is ItemListingAction.DropdownMenuClick -> {
|
||||
handleDropdownMenuClick(action)
|
||||
}
|
||||
|
||||
ItemListingAction.DownloadBitwardenClick -> {
|
||||
handleDownloadBitwardenClick()
|
||||
}
|
||||
@@ -157,10 +153,6 @@ class ItemListingViewModel @Inject constructor(
|
||||
ItemListingAction.SyncWithBitwardenDismiss -> {
|
||||
handleSyncWithBitwardenDismiss()
|
||||
}
|
||||
|
||||
is ItemListingAction.MoveToBitwardenClick -> {
|
||||
handleMoveToBitwardenClick(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,27 +160,22 @@ class ItemListingViewModel @Inject constructor(
|
||||
sendEvent(ItemListingEvent.NavigateToAppSettings)
|
||||
}
|
||||
|
||||
private fun handleItemClick(action: ItemListingAction.ItemClick) {
|
||||
clipboardManager.setText(action.authCode)
|
||||
sendEvent(
|
||||
ItemListingEvent.ShowToast(
|
||||
message = R.string.value_has_been_copied.asText(action.authCode),
|
||||
),
|
||||
)
|
||||
private fun handleCopyItemClick(authCode: String) {
|
||||
clipboardManager.setText(authCode)
|
||||
}
|
||||
|
||||
private fun handleEditItemClick(action: ItemListingAction.EditItemClick) {
|
||||
sendEvent(ItemListingEvent.NavigateToEditItem(action.itemId))
|
||||
private fun handleEditItemClick(itemId: String) {
|
||||
sendEvent(ItemListingEvent.NavigateToEditItem(itemId))
|
||||
}
|
||||
|
||||
private fun handleMoveToBitwardenClick(action: ItemListingAction.MoveToBitwardenClick) {
|
||||
private fun handleMoveToBitwardenClick(itemId: String) {
|
||||
viewModelScope.launch {
|
||||
val item = authenticatorRepository
|
||||
.getItemStateFlow(action.entityId)
|
||||
.getItemStateFlow(itemId)
|
||||
.first { it.data != null }
|
||||
|
||||
val didLaunchAddTotpFlow = authenticatorBridgeManager.startAddTotpLoginItemFlow(
|
||||
totpUri = item.data!!.toOtpAuthUriString(),
|
||||
totpUri = item.data?.toOtpAuthUriString().orEmpty(),
|
||||
)
|
||||
if (!didLaunchAddTotpFlow) {
|
||||
mutableStateFlow.update {
|
||||
@@ -203,12 +190,12 @@ class ItemListingViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDeleteItemClick(action: ItemListingAction.DeleteItemClick) {
|
||||
private fun handleDeleteItemClick(itemId: String) {
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
dialog = ItemListingState.DialogState.DeleteConfirmationPrompt(
|
||||
message = R.string.do_you_really_want_to_permanently_delete_cipher.asText(),
|
||||
itemId = action.itemId,
|
||||
itemId = itemId,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -528,6 +515,15 @@ class ItemListingViewModel @Inject constructor(
|
||||
sendEvent(ItemListingEvent.NavigateToBitwardenListing)
|
||||
}
|
||||
|
||||
private fun handleDropdownMenuClick(action: ItemListingAction.DropdownMenuClick) {
|
||||
when (action.menuAction) {
|
||||
VaultDropdownMenuAction.COPY -> handleCopyItemClick(action.item.authCode)
|
||||
VaultDropdownMenuAction.EDIT -> handleEditItemClick(action.item.id)
|
||||
VaultDropdownMenuAction.MOVE -> handleMoveToBitwardenClick(action.item.id)
|
||||
VaultDropdownMenuAction.DELETE -> handleDeleteItemClick(action.item.id)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDownloadBitwardenDismiss() {
|
||||
settingsRepository.hasUserDismissedDownloadBitwardenCard = true
|
||||
mutableStateFlow.update {
|
||||
@@ -663,7 +659,6 @@ data class ItemListingState(
|
||||
val viewState: ViewState,
|
||||
val dialog: DialogState?,
|
||||
) : Parcelable {
|
||||
|
||||
/**
|
||||
* Represents the different view states of the [ItemListingScreen].
|
||||
*/
|
||||
@@ -714,7 +709,6 @@ data class ItemListingState(
|
||||
* Display an action card on the item [ItemListingScreen].
|
||||
*/
|
||||
sealed class ActionCardState : Parcelable {
|
||||
|
||||
/**
|
||||
* Display no action card.
|
||||
*/
|
||||
@@ -738,7 +732,6 @@ data class ItemListingState(
|
||||
* Display a dialog on the [ItemListingScreen].
|
||||
*/
|
||||
sealed class DialogState : Parcelable {
|
||||
|
||||
/**
|
||||
* Displays the loading dialog to the user.
|
||||
*/
|
||||
@@ -769,7 +762,6 @@ data class ItemListingState(
|
||||
* Represents a set of events related to viewing the item listing.
|
||||
*/
|
||||
sealed class ItemListingEvent {
|
||||
|
||||
/**
|
||||
* Navigates to the Create Account screen.
|
||||
*/
|
||||
@@ -830,7 +822,6 @@ sealed class ItemListingEvent {
|
||||
* Each subclass of this sealed class denotes a distinct action that can be taken.
|
||||
*/
|
||||
sealed class ItemListingAction {
|
||||
|
||||
/**
|
||||
* The user clicked the back button.
|
||||
*/
|
||||
@@ -856,11 +847,6 @@ sealed class ItemListingAction {
|
||||
*/
|
||||
data class ItemClick(val authCode: String) : ItemListingAction()
|
||||
|
||||
/**
|
||||
* The user clicked edit item.
|
||||
*/
|
||||
data class EditItemClick(val itemId: String) : ItemListingAction()
|
||||
|
||||
/**
|
||||
* The user dismissed the dialog.
|
||||
*/
|
||||
@@ -892,15 +878,25 @@ sealed class ItemListingAction {
|
||||
data object SyncWithBitwardenDismiss : ItemListingAction()
|
||||
|
||||
/**
|
||||
* The user clicked the "Move to Bitwarden" action on a local verification item.
|
||||
* The user clicked confirm when prompted to delete an item.
|
||||
*/
|
||||
data class MoveToBitwardenClick(val entityId: String) : ItemListingAction()
|
||||
data class ConfirmDeleteClick(val itemId: String) : ItemListingAction()
|
||||
|
||||
/**
|
||||
* Represents an action triggered when the user clicks an item in the dropdown menu.
|
||||
*
|
||||
* @param menuAction The action selected from the dropdown menu.
|
||||
* @param id The identifier of the item on which the action is being performed.
|
||||
*/
|
||||
data class DropdownMenuClick(
|
||||
val menuAction: VaultDropdownMenuAction,
|
||||
val item: VerificationCodeDisplayItem,
|
||||
) : ItemListingAction()
|
||||
|
||||
/**
|
||||
* Models actions that [ItemListingScreen] itself may send.
|
||||
*/
|
||||
sealed class Internal : ItemListingAction() {
|
||||
|
||||
/**
|
||||
* Indicates verification items have been received.
|
||||
*/
|
||||
@@ -941,14 +937,4 @@ sealed class ItemListingAction {
|
||||
*/
|
||||
data object FirstTimeUserSyncReceive : Internal()
|
||||
}
|
||||
|
||||
/**
|
||||
* The user clicked Delete.
|
||||
*/
|
||||
data class DeleteItemClick(val itemId: String) : ItemListingAction()
|
||||
|
||||
/**
|
||||
* The user clicked confirm when prompted to delete an item.
|
||||
*/
|
||||
data class ConfirmDeleteClick(val itemId: String) : ItemListingAction()
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.bitwarden.authenticator.R
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VaultDropdownMenuAction
|
||||
import com.bitwarden.authenticator.ui.platform.components.icon.BitwardenIcon
|
||||
import com.bitwarden.authenticator.ui.platform.components.indicator.BitwardenCircularCountdownIndicator
|
||||
import com.bitwarden.authenticator.ui.platform.components.model.IconData
|
||||
@@ -46,8 +47,12 @@ import com.bitwarden.authenticator.ui.platform.theme.AuthenticatorTheme
|
||||
* @param secondaryLabel The supporting label for the item. Represents the OTP account name.
|
||||
* @param periodSeconds The times span where the code is valid.
|
||||
* @param timeLeftSeconds The seconds remaining until a new code is needed.
|
||||
* @param alertThresholdSeconds The time threshold in seconds to display an expiration warning.
|
||||
* @param startIcon The leading icon for the item.
|
||||
* @param onItemClick The lambda function to be invoked when the item is clicked.
|
||||
* @param onDropdownMenuClick A lambda function invoked when a dropdown menu action is clicked.
|
||||
* @param allowLongPress Whether long-press interactions are enabled for the item.
|
||||
* @param showMoveToBitwarden Whether the option to move the item to Bitwarden is displayed.
|
||||
* @param modifier The modifier for the item.
|
||||
*/
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@@ -62,9 +67,7 @@ fun VaultVerificationCodeItem(
|
||||
alertThresholdSeconds: Int,
|
||||
startIcon: IconData,
|
||||
onItemClick: () -> Unit,
|
||||
onEditItemClick: () -> Unit,
|
||||
onDeleteItemClick: () -> Unit,
|
||||
onMoveToBitwardenClick: () -> Unit,
|
||||
onDropdownMenuClick: (VaultDropdownMenuAction) -> Unit,
|
||||
allowLongPress: Boolean,
|
||||
showMoveToBitwarden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
@@ -155,13 +158,29 @@ fun VaultVerificationCodeItem(
|
||||
expanded = shouldShowDropdownMenu,
|
||||
onDismissRequest = { shouldShowDropdownMenu = false },
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(text = stringResource(id = R.string.copy))
|
||||
},
|
||||
onClick = {
|
||||
shouldShowDropdownMenu = false
|
||||
onDropdownMenuClick(VaultDropdownMenuAction.COPY)
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_copy),
|
||||
contentDescription = stringResource(id = R.string.copy),
|
||||
)
|
||||
},
|
||||
)
|
||||
HorizontalDivider()
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(text = stringResource(id = R.string.edit_item))
|
||||
},
|
||||
onClick = {
|
||||
shouldShowDropdownMenu = false
|
||||
onEditItemClick()
|
||||
onDropdownMenuClick(VaultDropdownMenuAction.EDIT)
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
@@ -174,16 +193,16 @@ fun VaultVerificationCodeItem(
|
||||
HorizontalDivider()
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(text = stringResource(id = R.string.copy_to_bitwarden))
|
||||
Text(text = stringResource(id = R.string.move_to_bitwarden))
|
||||
},
|
||||
onClick = {
|
||||
shouldShowDropdownMenu = false
|
||||
onMoveToBitwardenClick()
|
||||
onDropdownMenuClick(VaultDropdownMenuAction.MOVE)
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_arrow_right),
|
||||
contentDescription = stringResource(id = R.string.copy_to_bitwarden),
|
||||
contentDescription = stringResource(id = R.string.move_to_bitwarden),
|
||||
)
|
||||
},
|
||||
)
|
||||
@@ -195,7 +214,7 @@ fun VaultVerificationCodeItem(
|
||||
},
|
||||
onClick = {
|
||||
shouldShowDropdownMenu = false
|
||||
onDeleteItemClick()
|
||||
onDropdownMenuClick(VaultDropdownMenuAction.DELETE)
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
@@ -222,9 +241,7 @@ private fun VerificationCodeItem_preview() {
|
||||
alertThresholdSeconds = 7,
|
||||
startIcon = IconData.Local(R.drawable.ic_login_item),
|
||||
onItemClick = {},
|
||||
onEditItemClick = {},
|
||||
onDeleteItemClick = {},
|
||||
onMoveToBitwardenClick = {},
|
||||
onDropdownMenuClick = {},
|
||||
allowLongPress = true,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
showMoveToBitwarden = true,
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model
|
||||
|
||||
/**
|
||||
* Enum representing the available actions in the Vault dropdown menu.
|
||||
*/
|
||||
enum class VaultDropdownMenuAction {
|
||||
COPY,
|
||||
EDIT,
|
||||
MOVE,
|
||||
DELETE,
|
||||
}
|
||||
@@ -132,7 +132,7 @@
|
||||
<string name="sync_with_bitwarden_action_card_message">Allow Authenticator app syncing in settings to view all of your verification codes here.</string>
|
||||
<string name="something_went_wrong">Something went wrong</string>
|
||||
<string name="please_try_again">Please try again</string>
|
||||
<string name="copy_to_bitwarden">Copy to Bitwarden</string>
|
||||
<string name="move_to_bitwarden">Move to Bitwarden</string>
|
||||
<string name="default_save_option">Default save option</string>
|
||||
<string name="save_to_bitwarden">Save to Bitwarden</string>
|
||||
<string name="save_here">Save here</string>
|
||||
|
||||
@@ -10,6 +10,7 @@ import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.compose.ui.test.performTouchInput
|
||||
import com.bitwarden.authenticator.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.SharedCodesDisplayState
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VaultDropdownMenuAction
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem
|
||||
import com.bitwarden.authenticator.ui.platform.base.BaseComposeTest
|
||||
import com.bitwarden.authenticator.ui.platform.base.util.asText
|
||||
@@ -202,7 +203,7 @@ class ItemListingScreenTest : BaseComposeTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking Copy to Bitwarden should send MoveToBitwardenClick`() {
|
||||
fun `clicking Move to Bitwarden should send MoveToBitwardenClick`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(
|
||||
viewState = ItemListingState.ViewState.Content(
|
||||
actionCard = ItemListingState.ActionCardState.None,
|
||||
@@ -216,10 +217,17 @@ class ItemListingScreenTest : BaseComposeTest() {
|
||||
.performTouchInput { longClick() }
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Copy to Bitwarden")
|
||||
.onNodeWithText("Move to Bitwarden")
|
||||
.performClick()
|
||||
|
||||
verify { viewModel.trySendAction(ItemListingAction.MoveToBitwardenClick("1")) }
|
||||
verify {
|
||||
viewModel.trySendAction(
|
||||
ItemListingAction.DropdownMenuClick(
|
||||
menuAction = VaultDropdownMenuAction.MOVE,
|
||||
item = LOCAL_CODE,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -12,6 +12,8 @@ import com.bitwarden.authenticator.data.platform.manager.clipboard.BitwardenClip
|
||||
import com.bitwarden.authenticator.data.platform.repository.SettingsRepository
|
||||
import com.bitwarden.authenticator.data.platform.repository.model.DataState
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.SharedCodesDisplayState
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VaultDropdownMenuAction
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util.toDisplayItem
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util.toSharedCodesDisplayState
|
||||
import com.bitwarden.authenticator.ui.platform.base.BaseViewModelTest
|
||||
@@ -31,7 +33,7 @@ import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class ItemListViewModelTest : BaseViewModelTest() {
|
||||
class ItemListingViewModelTest : BaseViewModelTest() {
|
||||
|
||||
private val mutableAuthenticatorAlertThresholdFlow =
|
||||
MutableStateFlow(AUTHENTICATOR_ALERT_SECONDS)
|
||||
@@ -381,7 +383,12 @@ class ItemListViewModelTest : BaseViewModelTest() {
|
||||
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.trySendAction(ItemListingAction.MoveToBitwardenClick(entityId = "1"))
|
||||
viewModel.trySendAction(
|
||||
ItemListingAction.DropdownMenuClick(
|
||||
menuAction = VaultDropdownMenuAction.MOVE,
|
||||
item = LOCAL_CODE,
|
||||
),
|
||||
)
|
||||
verify { authenticatorBridgeManager.startAddTotpLoginItemFlow(expectedUriString) }
|
||||
}
|
||||
|
||||
@@ -406,7 +413,9 @@ class ItemListViewModelTest : BaseViewModelTest() {
|
||||
} returns false
|
||||
|
||||
val viewModel = createViewModel()
|
||||
viewModel.trySendAction(ItemListingAction.MoveToBitwardenClick(entityId = "1"))
|
||||
viewModel.trySendAction(
|
||||
ItemListingAction.DropdownMenuClick(VaultDropdownMenuAction.MOVE, LOCAL_CODE),
|
||||
)
|
||||
assertEquals(
|
||||
expectedState,
|
||||
viewModel.stateFlow.value,
|
||||
@@ -423,6 +432,66 @@ class ItemListViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should copy text to clipboard when DropdownMenuClick COPY is triggered`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
|
||||
every { clipboardManager.setText(text = LOCAL_CODE.authCode) } just runs
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(
|
||||
ItemListingAction.DropdownMenuClick(
|
||||
menuAction = VaultDropdownMenuAction.COPY,
|
||||
item = LOCAL_CODE,
|
||||
),
|
||||
)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(text = LOCAL_CODE.authCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should trigger edit action when DropdownMenuClick EDIT is triggered`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(
|
||||
ItemListingAction.DropdownMenuClick(VaultDropdownMenuAction.EDIT, LOCAL_CODE),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
ItemListingEvent.NavigateToEditItem(LOCAL_CODE.id),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should trigger delete prompt when DropdownMenuClick DELETE is triggered`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
|
||||
val expectedState = DEFAULT_STATE.copy(
|
||||
dialog = ItemListingState.DialogState.DeleteConfirmationPrompt(
|
||||
message = R.string.do_you_really_want_to_permanently_delete_cipher.asText(),
|
||||
itemId = LOCAL_CODE.id,
|
||||
),
|
||||
)
|
||||
|
||||
viewModel.trySendAction(
|
||||
ItemListingAction.DropdownMenuClick(
|
||||
menuAction = VaultDropdownMenuAction.DELETE,
|
||||
item = LOCAL_CODE,
|
||||
),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
expectedState,
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createViewModel() = ItemListingViewModel(
|
||||
authenticatorRepository = authenticatorRepository,
|
||||
authenticatorBridgeManager = authenticatorBridgeManager,
|
||||
@@ -441,6 +510,19 @@ private val DEFAULT_STATE = ItemListingState(
|
||||
dialog = null,
|
||||
)
|
||||
|
||||
private val LOCAL_CODE = VerificationCodeDisplayItem(
|
||||
id = "1",
|
||||
title = "issuer",
|
||||
subtitle = null,
|
||||
timeLeftSeconds = 10,
|
||||
periodSeconds = 30,
|
||||
alertThresholdSeconds = 7,
|
||||
authCode = "123456",
|
||||
favorite = false,
|
||||
allowLongPressActions = true,
|
||||
showMoveToBitwarden = true,
|
||||
)
|
||||
|
||||
private val LOCAL_VERIFICATION_ITEMS = listOf(
|
||||
VerificationCodeItem(
|
||||
code = "123456",
|
||||
Reference in New Issue
Block a user