mirror of
https://github.com/bitwarden/android.git
synced 2026-10-23 03:23:53 -05:00
BITAU-180 Show "Move to Bitwarden" long press action (#250)
This commit is contained in:
1 parent
5d7656323b
commit
5fdfb26950
14 files changed
+358
-27
No files matched your search
Binary file not shown.
+2
@@ -51,6 +51,8 @@ object AuthenticatorBridgeModule {
|
||||
object : AuthenticatorBridgeManager {
|
||||
override val accountSyncStateFlow: StateFlow<AccountSyncState>
|
||||
get() = MutableStateFlow(AccountSyncState.Loading)
|
||||
|
||||
override fun startAddTotpLoginItemFlow(totpUri: String): Boolean = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
@@ -237,6 +237,11 @@ fun ItemListingScreen(
|
||||
viewModel.trySendAction(ItemListingAction.SyncWithBitwardenDismiss)
|
||||
}
|
||||
},
|
||||
onMoveToBitwardenClick = remember(viewModel) {
|
||||
{
|
||||
viewModel.trySendAction(ItemListingAction.MoveToBitwardenClick(it))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -342,6 +347,7 @@ private fun ItemListingContent(
|
||||
onItemClick: (String) -> Unit,
|
||||
onEditItemClick: (String) -> Unit,
|
||||
onDeleteItemClick: (String) -> Unit,
|
||||
onMoveToBitwardenClick: (String) -> Unit,
|
||||
onDownloadBitwardenClick: () -> Unit,
|
||||
onDismissDownloadBitwardenClick: () -> Unit,
|
||||
onSyncWithBitwardenClick: () -> Unit,
|
||||
@@ -453,6 +459,8 @@ private fun ItemListingContent(
|
||||
onItemClick = { onItemClick(it.authCode) },
|
||||
onEditItemClick = { onEditItemClick(it.id) },
|
||||
onDeleteItemClick = { onDeleteItemClick(it.id) },
|
||||
onMoveToBitwardenClick = { onMoveToBitwardenClick(it.id) },
|
||||
showMoveToBitwarden = it.showMoveToBitwarden,
|
||||
allowLongPress = it.allowLongPressActions,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
@@ -481,6 +489,8 @@ private fun ItemListingContent(
|
||||
onItemClick = { onItemClick(it.authCode) },
|
||||
onEditItemClick = { onEditItemClick(it.id) },
|
||||
onDeleteItemClick = { onDeleteItemClick(it.id) },
|
||||
onMoveToBitwardenClick = { onMoveToBitwardenClick(it.id) },
|
||||
showMoveToBitwarden = it.showMoveToBitwarden,
|
||||
allowLongPress = it.allowLongPressActions,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
@@ -515,6 +525,8 @@ private fun ItemListingContent(
|
||||
onItemClick = { onItemClick(it.authCode) },
|
||||
onEditItemClick = { },
|
||||
onDeleteItemClick = { },
|
||||
onMoveToBitwardenClick = { },
|
||||
showMoveToBitwarden = it.showMoveToBitwarden,
|
||||
allowLongPress = it.allowLongPressActions,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
|
||||
+49
-4
@@ -28,8 +28,10 @@ import com.bitwarden.authenticator.ui.platform.base.BaseViewModel
|
||||
import com.bitwarden.authenticator.ui.platform.base.util.Text
|
||||
import com.bitwarden.authenticator.ui.platform.base.util.asText
|
||||
import com.bitwarden.authenticator.ui.platform.feature.settings.appearance.model.AppTheme
|
||||
import com.bitwarden.authenticatorbridge.manager.AuthenticatorBridgeManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
@@ -46,6 +48,7 @@ import javax.inject.Inject
|
||||
@HiltViewModel
|
||||
class ItemListingViewModel @Inject constructor(
|
||||
private val authenticatorRepository: AuthenticatorRepository,
|
||||
private val authenticatorBridgeManager: AuthenticatorBridgeManager,
|
||||
private val clipboardManager: BitwardenClipboardManager,
|
||||
private val encodingManager: BitwardenEncodingManager,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
@@ -144,9 +147,14 @@ class ItemListingViewModel @Inject constructor(
|
||||
ItemListingAction.SyncWithBitwardenClick -> {
|
||||
handleSyncWithBitwardenClick()
|
||||
}
|
||||
|
||||
ItemListingAction.SyncWithBitwardenDismiss -> {
|
||||
handleSyncWithBitwardenDismiss()
|
||||
}
|
||||
|
||||
is ItemListingAction.MoveToBitwardenClick -> {
|
||||
handleMoveToBitwardenClick(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +175,28 @@ class ItemListingViewModel @Inject constructor(
|
||||
sendEvent(ItemListingEvent.NavigateToEditItem(action.itemId))
|
||||
}
|
||||
|
||||
private fun handleMoveToBitwardenClick(action: ItemListingAction.MoveToBitwardenClick) {
|
||||
viewModelScope.launch {
|
||||
val item = authenticatorRepository
|
||||
.getItemStateFlow(action.entityId)
|
||||
.first { it.data != null }
|
||||
|
||||
val didLaunchAddTotpFlow = authenticatorBridgeManager.startAddTotpLoginItemFlow(
|
||||
totpUri = item.data!!.toOtpAuthUriString(),
|
||||
)
|
||||
if (!didLaunchAddTotpFlow) {
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
dialog = ItemListingState.DialogState.Error(
|
||||
title = R.string.something_went_wrong.asText(),
|
||||
message = R.string.please_try_again.asText(),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleDeleteItemClick(action: ItemListingAction.DeleteItemClick) {
|
||||
mutableStateFlow.update {
|
||||
it.copy(
|
||||
@@ -439,7 +469,9 @@ class ItemListingViewModel @Inject constructor(
|
||||
-> SharedCodesDisplayState.Codes(emptyList())
|
||||
|
||||
is SharedVerificationCodesState.Success ->
|
||||
action.sharedCodesState.toSharedCodesDisplayState(state.alertThresholdSeconds)
|
||||
action.sharedCodesState.toSharedCodesDisplayState(
|
||||
alertThresholdSeconds = state.alertThresholdSeconds,
|
||||
)
|
||||
}
|
||||
|
||||
if (localItems.isEmpty() && sharedItemsState.isEmpty()) {
|
||||
@@ -456,12 +488,20 @@ class ItemListingViewModel @Inject constructor(
|
||||
favoriteItems = localItems
|
||||
.filter { it.source is AuthenticatorItem.Source.Local && it.source.isFavorite }
|
||||
.map {
|
||||
it.toDisplayItem(alertThresholdSeconds = state.alertThresholdSeconds)
|
||||
it.toDisplayItem(
|
||||
alertThresholdSeconds = state.alertThresholdSeconds,
|
||||
sharedVerificationCodesState =
|
||||
authenticatorRepository.sharedCodesStateFlow.value,
|
||||
)
|
||||
},
|
||||
itemList = localItems
|
||||
.filter { it.source is AuthenticatorItem.Source.Local && !it.source.isFavorite }
|
||||
.map {
|
||||
it.toDisplayItem(alertThresholdSeconds = state.alertThresholdSeconds)
|
||||
it.toDisplayItem(
|
||||
alertThresholdSeconds = state.alertThresholdSeconds,
|
||||
sharedVerificationCodesState =
|
||||
authenticatorRepository.sharedCodesStateFlow.value,
|
||||
)
|
||||
},
|
||||
sharedItems = sharedItemsState,
|
||||
actionCard = action.sharedCodesState.toActionCard(),
|
||||
@@ -538,7 +578,7 @@ class ItemListingViewModel @Inject constructor(
|
||||
SharedVerificationCodesState.Loading,
|
||||
SharedVerificationCodesState.OsVersionNotSupported,
|
||||
is SharedVerificationCodesState.Success,
|
||||
-> ItemListingState.ActionCardState.None
|
||||
-> ItemListingState.ActionCardState.None
|
||||
}
|
||||
|
||||
private fun String.toAuthenticatorEntityOrNull(): AuthenticatorItemEntity? {
|
||||
@@ -818,6 +858,11 @@ sealed class ItemListingAction {
|
||||
*/
|
||||
data object SyncWithBitwardenDismiss : ItemListingAction()
|
||||
|
||||
/**
|
||||
* The user clicked the "Move to Bitwarden" action on a local verification item.
|
||||
*/
|
||||
data class MoveToBitwardenClick(val entityId: String) : ItemListingAction()
|
||||
|
||||
/**
|
||||
* Models actions that [ItemListingScreen] itself may send.
|
||||
*/
|
||||
|
||||
+22
@@ -64,7 +64,9 @@ fun VaultVerificationCodeItem(
|
||||
onItemClick: () -> Unit,
|
||||
onEditItemClick: () -> Unit,
|
||||
onDeleteItemClick: () -> Unit,
|
||||
onMoveToBitwardenClick: () -> Unit,
|
||||
allowLongPress: Boolean,
|
||||
showMoveToBitwarden: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var shouldShowDropdownMenu by remember { mutableStateOf(value = false) }
|
||||
@@ -168,6 +170,24 @@ fun VaultVerificationCodeItem(
|
||||
)
|
||||
},
|
||||
)
|
||||
if (showMoveToBitwarden) {
|
||||
HorizontalDivider()
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(text = stringResource(id = R.string.move_to_bitwarden))
|
||||
},
|
||||
onClick = {
|
||||
shouldShowDropdownMenu = false
|
||||
onMoveToBitwardenClick()
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_arrow_right),
|
||||
contentDescription = stringResource(id = R.string.move_to_bitwarden),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
HorizontalDivider()
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
@@ -204,8 +224,10 @@ private fun VerificationCodeItem_preview() {
|
||||
onItemClick = {},
|
||||
onEditItemClick = {},
|
||||
onDeleteItemClick = {},
|
||||
onMoveToBitwardenClick = {},
|
||||
allowLongPress = true,
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
showMoveToBitwarden = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
+1
@@ -20,4 +20,5 @@ data class VerificationCodeDisplayItem(
|
||||
val startIcon: IconData = IconData.Local(R.drawable.ic_login_item),
|
||||
val favorite: Boolean,
|
||||
val allowLongPressActions: Boolean,
|
||||
val showMoveToBitwarden: Boolean,
|
||||
) : Parcelable
|
||||
+8
-1
@@ -19,7 +19,14 @@ fun SharedVerificationCodesState.Success.toSharedCodesDisplayState(
|
||||
// codes for that account:
|
||||
this.items.forEach {
|
||||
codesMap.putIfAbsent(it.source as AuthenticatorItem.Source.Shared, mutableListOf())
|
||||
codesMap[it.source]?.add(it.toDisplayItem(alertThresholdSeconds))
|
||||
codesMap[it.source]?.add(
|
||||
it.toDisplayItem(
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
// Always map based on Error state, because shared codes will never
|
||||
// show "Move to Bitwarden" action.
|
||||
sharedVerificationCodesState = SharedVerificationCodesState.Error,
|
||||
),
|
||||
)
|
||||
}
|
||||
// Flatten that map down to a list of accounts that each has a list of codes:
|
||||
return codesMap
|
||||
|
||||
+35
-15
@@ -2,23 +2,43 @@ package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util
|
||||
|
||||
import com.bitwarden.authenticator.data.authenticator.manager.model.VerificationCodeItem
|
||||
import com.bitwarden.authenticator.data.authenticator.repository.model.AuthenticatorItem
|
||||
import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem
|
||||
|
||||
/**
|
||||
* Converts [VerificationCodeItem] to a [VerificationCodeDisplayItem].
|
||||
*/
|
||||
fun VerificationCodeItem.toDisplayItem(alertThresholdSeconds: Int) =
|
||||
VerificationCodeDisplayItem(
|
||||
id = id,
|
||||
issuer = issuer,
|
||||
label = accountName,
|
||||
timeLeftSeconds = timeLeftSeconds,
|
||||
periodSeconds = periodSeconds,
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
authCode = code,
|
||||
allowLongPressActions = when (source) {
|
||||
is AuthenticatorItem.Source.Local -> true
|
||||
is AuthenticatorItem.Source.Shared -> false
|
||||
},
|
||||
favorite = (source as? AuthenticatorItem.Source.Local)?.isFavorite ?: false,
|
||||
)
|
||||
fun VerificationCodeItem.toDisplayItem(
|
||||
alertThresholdSeconds: Int,
|
||||
sharedVerificationCodesState: SharedVerificationCodesState,
|
||||
) = VerificationCodeDisplayItem(
|
||||
id = id,
|
||||
issuer = issuer,
|
||||
label = accountName,
|
||||
timeLeftSeconds = timeLeftSeconds,
|
||||
periodSeconds = periodSeconds,
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
authCode = code,
|
||||
allowLongPressActions = when (source) {
|
||||
is AuthenticatorItem.Source.Local -> true
|
||||
is AuthenticatorItem.Source.Shared -> false
|
||||
},
|
||||
favorite = (source as? AuthenticatorItem.Source.Local)?.isFavorite ?: false,
|
||||
showMoveToBitwarden = when (source) {
|
||||
// Shared items should never show Move to Bitwarden action:
|
||||
is AuthenticatorItem.Source.Shared -> false
|
||||
|
||||
// Local items should only show Move to Bitwarden if we are successfully syncing: =
|
||||
is AuthenticatorItem.Source.Local -> when (sharedVerificationCodesState) {
|
||||
SharedVerificationCodesState.AppNotInstalled,
|
||||
SharedVerificationCodesState.Error,
|
||||
SharedVerificationCodesState.FeatureNotEnabled,
|
||||
SharedVerificationCodesState.Loading,
|
||||
SharedVerificationCodesState.OsVersionNotSupported,
|
||||
SharedVerificationCodesState.SyncNotEnabled,
|
||||
-> false
|
||||
|
||||
is SharedVerificationCodesState.Success -> true
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M15.616,10.5C15.247,10.888 9.462,16.961 8.962,17.5C8.446,18.057 9.202,19.084 9.975,18.244C10.747,17.405 16.759,11.113 16.759,11.113C17.301,10.447 17.301,9.539 16.759,8.874L10.002,1.77C9.151,0.832 8.201,1.678 8.987,2.5C11.77,5.412 15.124,8.963 15.631,9.5H2.5C2.224,9.5 2,9.724 2,10C2,10.276 2.224,10.5 2.5,10.5H15.616Z"
|
||||
android:fillColor="#45464F"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
@@ -130,4 +130,7 @@
|
||||
<string name="sync_with_the_bitwarden_app">Sync with the Bitwarden app</string>
|
||||
<string name="go_to_settings">Go to settings</string>
|
||||
<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="move_to_bitwarden">Move to Bitwarden</string>
|
||||
</resources>
|
||||
+61
-4
@@ -1,6 +1,8 @@
|
||||
package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.bitwarden.authenticator.R
|
||||
import com.bitwarden.authenticator.data.authenticator.datasource.disk.entity.AuthenticatorItemEntity
|
||||
import com.bitwarden.authenticator.data.authenticator.manager.model.VerificationCodeItem
|
||||
import com.bitwarden.authenticator.data.authenticator.repository.AuthenticatorRepository
|
||||
import com.bitwarden.authenticator.data.authenticator.repository.model.AuthenticatorItem
|
||||
@@ -13,7 +15,9 @@ import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.Sh
|
||||
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
|
||||
import com.bitwarden.authenticator.ui.platform.base.util.asText
|
||||
import com.bitwarden.authenticator.ui.platform.feature.settings.appearance.model.AppTheme
|
||||
import com.bitwarden.authenticatorbridge.manager.AuthenticatorBridgeManager
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
@@ -40,6 +44,7 @@ class ItemListViewModelTest : BaseViewModelTest() {
|
||||
every { getLocalVerificationCodesFlow() } returns mutableVerificationCodesFlow
|
||||
every { sharedCodesStateFlow } returns mutableSharedCodesFlow
|
||||
}
|
||||
private val authenticatorBridgeManager: AuthenticatorBridgeManager = mockk()
|
||||
private val clipboardManager: BitwardenClipboardManager = mockk()
|
||||
private val encodingManager: BitwardenEncodingManager = mockk()
|
||||
private val settingsRepository: SettingsRepository = mockk {
|
||||
@@ -144,12 +149,12 @@ class ItemListViewModelTest : BaseViewModelTest() {
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `stateFlow sharedItems value should be Codes with empty list when shared state is Error `() {
|
||||
fun `stateFlow sharedItems value should be Codes with empty list when shared state is Success `() {
|
||||
val expectedState = DEFAULT_STATE.copy(
|
||||
viewState = ItemListingState.ViewState.Content(
|
||||
actionCard = ItemListingState.ActionCardState.None,
|
||||
favoriteItems = LOCAL_FAVORITE_ITEMS,
|
||||
itemList = LOCAL_NON_FAVORITE_ITEMS,
|
||||
favoriteItems = LOCAL_FAVORITE_ITEMS.map { it.copy(showMoveToBitwarden = true) },
|
||||
itemList = LOCAL_NON_FAVORITE_ITEMS.map { it.copy(showMoveToBitwarden = true) },
|
||||
sharedItems = SHARED_DISPLAY_ITEMS,
|
||||
),
|
||||
)
|
||||
@@ -356,8 +361,57 @@ class ItemListViewModelTest : BaseViewModelTest() {
|
||||
assertEquals(expectedState, viewModel.stateFlow.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on MoveToBitwardenClick receive should call startAddTotpLoginItemFlow`() {
|
||||
val expectedUriString = "expectedUriString"
|
||||
val entity: AuthenticatorItemEntity = mockk {
|
||||
every { toOtpAuthUriString() } returns expectedUriString
|
||||
}
|
||||
every {
|
||||
authenticatorRepository.getItemStateFlow("1")
|
||||
} returns MutableStateFlow(DataState.Loaded(data = entity))
|
||||
every {
|
||||
authenticatorBridgeManager.startAddTotpLoginItemFlow(expectedUriString)
|
||||
} returns true
|
||||
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.trySendAction(ItemListingAction.MoveToBitwardenClick(entityId = "1"))
|
||||
verify { authenticatorBridgeManager.startAddTotpLoginItemFlow(expectedUriString) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `on MoveToBitwardenClick should show error dialog when startAddTotpLoginItemFlow returns false`() {
|
||||
val expectedState = DEFAULT_STATE.copy(
|
||||
dialog = ItemListingState.DialogState.Error(
|
||||
title = R.string.something_went_wrong.asText(),
|
||||
message = R.string.please_try_again.asText(),
|
||||
),
|
||||
)
|
||||
val expectedUriString = "expectedUriString"
|
||||
val entity: AuthenticatorItemEntity = mockk {
|
||||
every { toOtpAuthUriString() } returns expectedUriString
|
||||
}
|
||||
every {
|
||||
authenticatorRepository.getItemStateFlow("1")
|
||||
} returns MutableStateFlow(DataState.Loaded(data = entity))
|
||||
every {
|
||||
authenticatorBridgeManager.startAddTotpLoginItemFlow(expectedUriString)
|
||||
} returns false
|
||||
|
||||
val viewModel = createViewModel()
|
||||
viewModel.trySendAction(ItemListingAction.MoveToBitwardenClick(entityId = "1"))
|
||||
assertEquals(
|
||||
expectedState,
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
verify { authenticatorBridgeManager.startAddTotpLoginItemFlow(expectedUriString) }
|
||||
}
|
||||
|
||||
private fun createViewModel() = ItemListingViewModel(
|
||||
authenticatorRepository = authenticatorRepository,
|
||||
authenticatorBridgeManager = authenticatorBridgeManager,
|
||||
clipboardManager = clipboardManager,
|
||||
encodingManager = encodingManager,
|
||||
settingsRepository = settingsRepository,
|
||||
@@ -415,7 +469,10 @@ private val SHARED_VERIFICATION_ITEMS = listOf(
|
||||
)
|
||||
|
||||
private val LOCAL_DISPLAY_ITEMS = LOCAL_VERIFICATION_ITEMS.map {
|
||||
it.toDisplayItem(AUTHENTICATOR_ALERT_SECONDS)
|
||||
it.toDisplayItem(
|
||||
AUTHENTICATOR_ALERT_SECONDS,
|
||||
SharedVerificationCodesState.AppNotInstalled,
|
||||
)
|
||||
}
|
||||
|
||||
private val SHARED_DISPLAY_ITEMS = SharedVerificationCodesState.Success(SHARED_VERIFICATION_ITEMS)
|
||||
|
||||
+54
@@ -199,11 +199,64 @@ class ItemListingScreenTest : BaseComposeTest() {
|
||||
.performClick()
|
||||
verify { viewModel.trySendAction(ItemListingAction.SyncWithBitwardenDismiss) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking Move to Bitwarden should send MoveToBitwardenClick`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(
|
||||
viewState = ItemListingState.ViewState.Content(
|
||||
actionCard = ItemListingState.ActionCardState.None,
|
||||
favoriteItems = emptyList(),
|
||||
itemList = listOf(LOCAL_CODE),
|
||||
sharedItems = SharedCodesDisplayState.Error,
|
||||
),
|
||||
)
|
||||
composeTestRule
|
||||
.onNodeWithText("issuer")
|
||||
.performTouchInput { longClick() }
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Move to Bitwarden")
|
||||
.performClick()
|
||||
|
||||
verify { viewModel.trySendAction(ItemListingAction.MoveToBitwardenClick("1")) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Move to Bitwarden long press action should not show when showMoveToBitwarden is false`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(
|
||||
viewState = ItemListingState.ViewState.Content(
|
||||
actionCard = ItemListingState.ActionCardState.None,
|
||||
favoriteItems = emptyList(),
|
||||
itemList = listOf(LOCAL_CODE.copy(showMoveToBitwarden = false)),
|
||||
sharedItems = SharedCodesDisplayState.Error,
|
||||
),
|
||||
)
|
||||
composeTestRule
|
||||
.onNodeWithText("issuer")
|
||||
.performTouchInput { longClick() }
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Move to Bitwarden")
|
||||
.assertDoesNotExist()
|
||||
}
|
||||
}
|
||||
|
||||
private val APP_THEME = AppTheme.DEFAULT
|
||||
private const val ALERT_THRESHOLD = 7
|
||||
|
||||
private val LOCAL_CODE = VerificationCodeDisplayItem(
|
||||
id = "1",
|
||||
issuer = "issuer",
|
||||
label = null,
|
||||
timeLeftSeconds = 10,
|
||||
periodSeconds = 30,
|
||||
alertThresholdSeconds = 7,
|
||||
authCode = "123456",
|
||||
favorite = false,
|
||||
allowLongPressActions = true,
|
||||
showMoveToBitwarden = true,
|
||||
)
|
||||
|
||||
private val SHARED_ACCOUNTS_SECTION = SharedCodesDisplayState.SharedCodesAccountSection(
|
||||
label = "test@test.com".asText(),
|
||||
codes = listOf(
|
||||
@@ -217,6 +270,7 @@ private val SHARED_ACCOUNTS_SECTION = SharedCodesDisplayState.SharedCodesAccount
|
||||
authCode = "123456",
|
||||
favorite = false,
|
||||
allowLongPressActions = false,
|
||||
showMoveToBitwarden = false,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
+2
@@ -76,6 +76,7 @@ class SharedVerificationCodesStateTest {
|
||||
favorite = false,
|
||||
allowLongPressActions = false,
|
||||
alertThresholdSeconds = ALERT_THRESHOLD,
|
||||
showMoveToBitwarden = false,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -95,6 +96,7 @@ class SharedVerificationCodesStateTest {
|
||||
favorite = false,
|
||||
allowLongPressActions = false,
|
||||
alertThresholdSeconds = ALERT_THRESHOLD,
|
||||
showMoveToBitwarden = false,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
+99
-3
@@ -2,6 +2,7 @@ package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util
|
||||
|
||||
import com.bitwarden.authenticator.data.authenticator.manager.util.createMockVerificationCodeItem
|
||||
import com.bitwarden.authenticator.data.authenticator.repository.model.AuthenticatorItem
|
||||
import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState
|
||||
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
@@ -24,6 +25,7 @@ class VerificationCodeItemExtensionsTest {
|
||||
authCode = favoriteItem.code,
|
||||
favorite = (favoriteItem.source as AuthenticatorItem.Source.Local).isFavorite,
|
||||
allowLongPressActions = true,
|
||||
showMoveToBitwarden = false,
|
||||
)
|
||||
|
||||
val expectedNonFavoriteItem = VerificationCodeDisplayItem(
|
||||
@@ -36,10 +38,97 @@ class VerificationCodeItemExtensionsTest {
|
||||
authCode = nonFavoriteItem.code,
|
||||
favorite = (nonFavoriteItem.source as AuthenticatorItem.Source.Local).isFavorite,
|
||||
allowLongPressActions = true,
|
||||
showMoveToBitwarden = false,
|
||||
)
|
||||
|
||||
assertEquals(expectedFavoriteItem, favoriteItem.toDisplayItem(alertThresholdSeconds))
|
||||
assertEquals(expectedNonFavoriteItem, nonFavoriteItem.toDisplayItem(alertThresholdSeconds))
|
||||
assertEquals(
|
||||
expectedFavoriteItem,
|
||||
favoriteItem.toDisplayItem(
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
sharedVerificationCodesState = SharedVerificationCodesState.Error,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
expectedNonFavoriteItem,
|
||||
nonFavoriteItem.toDisplayItem(
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
sharedVerificationCodesState = SharedVerificationCodesState.Error,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Suppress("MaxLineLength")
|
||||
fun `toDisplayItem should only showMoveToBitwarden when SharedVerificationCodesState is Success`() {
|
||||
val alertThresholdSeconds = 7
|
||||
val item = createMockVerificationCodeItem(1)
|
||||
val expectedDontShowMoveToBitwardenItem =
|
||||
VerificationCodeDisplayItem(
|
||||
id = item.id,
|
||||
issuer = item.issuer,
|
||||
label = item.accountName,
|
||||
timeLeftSeconds = item.timeLeftSeconds,
|
||||
periodSeconds = item.periodSeconds,
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
authCode = item.code,
|
||||
favorite = false,
|
||||
allowLongPressActions = true,
|
||||
showMoveToBitwarden = false,
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
expectedDontShowMoveToBitwardenItem,
|
||||
item.toDisplayItem(
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
sharedVerificationCodesState = SharedVerificationCodesState.AppNotInstalled,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
expectedDontShowMoveToBitwardenItem,
|
||||
item.toDisplayItem(
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
sharedVerificationCodesState = SharedVerificationCodesState.Error,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
expectedDontShowMoveToBitwardenItem,
|
||||
item.toDisplayItem(
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
sharedVerificationCodesState = SharedVerificationCodesState.FeatureNotEnabled,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
expectedDontShowMoveToBitwardenItem,
|
||||
item.toDisplayItem(
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
sharedVerificationCodesState = SharedVerificationCodesState.Loading,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
expectedDontShowMoveToBitwardenItem,
|
||||
item.toDisplayItem(
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
sharedVerificationCodesState = SharedVerificationCodesState.OsVersionNotSupported,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
expectedDontShowMoveToBitwardenItem,
|
||||
item.toDisplayItem(
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
sharedVerificationCodesState = SharedVerificationCodesState.SyncNotEnabled,
|
||||
),
|
||||
)
|
||||
|
||||
val expectedShouldShowMoveToBitwardenItem = expectedDontShowMoveToBitwardenItem.copy(
|
||||
showMoveToBitwarden = true,
|
||||
)
|
||||
assertEquals(
|
||||
expectedShouldShowMoveToBitwardenItem,
|
||||
item.toDisplayItem(
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
sharedVerificationCodesState = SharedVerificationCodesState.Success(emptyList()),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -65,8 +154,15 @@ class VerificationCodeItemExtensionsTest {
|
||||
authCode = favoriteItem.code,
|
||||
favorite = false,
|
||||
allowLongPressActions = false,
|
||||
showMoveToBitwarden = false,
|
||||
)
|
||||
|
||||
assertEquals(expectedFavoriteItem, favoriteItem.toDisplayItem(alertThresholdSeconds))
|
||||
assertEquals(
|
||||
expectedFavoriteItem,
|
||||
favoriteItem.toDisplayItem(
|
||||
alertThresholdSeconds = alertThresholdSeconds,
|
||||
sharedVerificationCodesState = SharedVerificationCodesState.Error,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user