Move item listing models to common location for reuse with search (#5438)

This commit is contained in:
David Perez
2025-06-27 14:06:31 -05:00
committed by GitHub
parent d279f6acae
commit ed2d6ca585
13 changed files with 60 additions and 79 deletions

View File

@@ -55,9 +55,9 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bitwarden.authenticator.R import com.bitwarden.authenticator.R
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.ItemListingExpandableFabAction 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.VaultDropdownMenuAction
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem import com.bitwarden.authenticator.ui.authenticator.feature.model.SharedCodesDisplayState
import com.bitwarden.authenticator.ui.authenticator.feature.model.VerificationCodeDisplayItem
import com.bitwarden.authenticator.ui.platform.components.appbar.AuthenticatorMediumTopAppBar import com.bitwarden.authenticator.ui.platform.components.appbar.AuthenticatorMediumTopAppBar
import com.bitwarden.authenticator.ui.platform.components.appbar.AuthenticatorTopAppBar import com.bitwarden.authenticator.ui.platform.components.appbar.AuthenticatorTopAppBar
import com.bitwarden.authenticator.ui.platform.components.appbar.action.AuthenticatorSearchActionItem import com.bitwarden.authenticator.ui.platform.components.appbar.action.AuthenticatorSearchActionItem

View File

@@ -19,11 +19,11 @@ import com.bitwarden.authenticator.data.platform.manager.BitwardenEncodingManage
import com.bitwarden.authenticator.data.platform.manager.clipboard.BitwardenClipboardManager import com.bitwarden.authenticator.data.platform.manager.clipboard.BitwardenClipboardManager
import com.bitwarden.authenticator.data.platform.manager.imports.model.GoogleAuthenticatorProtos import com.bitwarden.authenticator.data.platform.manager.imports.model.GoogleAuthenticatorProtos
import com.bitwarden.authenticator.data.platform.repository.SettingsRepository import com.bitwarden.authenticator.data.platform.repository.SettingsRepository
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.VaultDropdownMenuAction
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem import com.bitwarden.authenticator.ui.authenticator.feature.model.SharedCodesDisplayState
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util.toDisplayItem import com.bitwarden.authenticator.ui.authenticator.feature.model.VerificationCodeDisplayItem
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util.toSharedCodesDisplayState import com.bitwarden.authenticator.ui.authenticator.feature.util.toDisplayItem
import com.bitwarden.authenticator.ui.authenticator.feature.util.toSharedCodesDisplayState
import com.bitwarden.authenticatorbridge.manager.AuthenticatorBridgeManager import com.bitwarden.authenticatorbridge.manager.AuthenticatorBridgeManager
import com.bitwarden.core.data.repository.model.DataState import com.bitwarden.core.data.repository.model.DataState
import com.bitwarden.ui.platform.base.BaseViewModel import com.bitwarden.ui.platform.base.BaseViewModel

View File

@@ -1,4 +1,4 @@
package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model package com.bitwarden.authenticator.ui.authenticator.feature.model
import android.os.Parcelable import android.os.Parcelable
import com.bitwarden.ui.util.Text import com.bitwarden.ui.util.Text

View File

@@ -1,4 +1,4 @@
package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model package com.bitwarden.authenticator.ui.authenticator.feature.model
import android.os.Parcelable import android.os.Parcelable
import com.bitwarden.authenticator.R import com.bitwarden.authenticator.R

View File

@@ -21,7 +21,7 @@ fun ItemSearchContent(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
LazyColumn(modifier = modifier) { LazyColumn(modifier = modifier) {
items(viewState.displayItems) { items(viewState.itemList) {
VaultVerificationCodeItem( VaultVerificationCodeItem(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()

View File

@@ -9,11 +9,12 @@ import com.bitwarden.authenticator.data.authenticator.repository.AuthenticatorRe
import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState
import com.bitwarden.authenticator.data.authenticator.repository.util.itemsOrEmpty import com.bitwarden.authenticator.data.authenticator.repository.util.itemsOrEmpty
import com.bitwarden.authenticator.data.platform.manager.clipboard.BitwardenClipboardManager import com.bitwarden.authenticator.data.platform.manager.clipboard.BitwardenClipboardManager
import com.bitwarden.authenticator.ui.authenticator.feature.model.VerificationCodeDisplayItem
import com.bitwarden.authenticator.ui.authenticator.feature.util.toDisplayItem
import com.bitwarden.core.data.repository.model.DataState import com.bitwarden.core.data.repository.model.DataState
import com.bitwarden.core.data.repository.util.SpecialCharWithPrecedenceComparator import com.bitwarden.core.data.repository.util.SpecialCharWithPrecedenceComparator
import com.bitwarden.ui.platform.base.BaseViewModel import com.bitwarden.ui.platform.base.BaseViewModel
import com.bitwarden.ui.platform.base.util.removeDiacritics import com.bitwarden.ui.platform.base.util.removeDiacritics
import com.bitwarden.ui.platform.components.icon.model.IconData
import com.bitwarden.ui.util.Text import com.bitwarden.ui.util.Text
import com.bitwarden.ui.util.asText import com.bitwarden.ui.util.asText
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
@@ -155,7 +156,15 @@ class ItemSearchViewModel @Inject constructor(
isNotEmpty() -> { isNotEmpty() -> {
ItemSearchState.ViewState.Content( ItemSearchState.ViewState.Content(
displayItems = toDisplayItemList() itemList = this
.map {
it.toDisplayItem(
alertThresholdSeconds = 7,
sharedVerificationCodesState = authenticatorRepository
.sharedCodesStateFlow
.value,
)
}
.sortAlphabetically(), .sortAlphabetically(),
) )
} }
@@ -167,39 +176,13 @@ class ItemSearchViewModel @Inject constructor(
} }
} }
private fun List<VerificationCodeItem>.toDisplayItemList(): List<ItemSearchState.DisplayItem> =
this.map {
it.toDisplayItem()
}
private fun VerificationCodeItem.toDisplayItem(): ItemSearchState.DisplayItem =
ItemSearchState.DisplayItem(
id = id,
authCode = code,
title = issuer ?: label ?: "--",
subtitle = if (issuer != null) {
// Only show label if it is not being used as the primary title:
label
} else {
null
},
periodSeconds = periodSeconds,
timeLeftSeconds = timeLeftSeconds,
alertThresholdSeconds = 7,
startIcon = IconData.Local(iconRes = R.drawable.ic_login_item),
)
/** /**
* Sort a list of [ItemSearchState.DisplayItem] by their titles alphabetically giving digits and * Sort a list of [VerificationCodeDisplayItem] by their titles alphabetically giving digits and
* special characters higher precedence. * special characters higher precedence.
*/ */
@Suppress("MaxLineLength") private fun List<VerificationCodeDisplayItem>.sortAlphabetically() =
private fun List<ItemSearchState.DisplayItem>.sortAlphabetically() =
this.sortedWith { item1, item2 -> this.sortedWith { item1, item2 ->
SpecialCharWithPrecedenceComparator.compare( SpecialCharWithPrecedenceComparator.compare(item1.title, item2.title)
item1.title.orEmpty(),
item2.title.orEmpty(),
)
} }
//endregion Utility Functions //endregion Utility Functions
} }
@@ -222,7 +205,7 @@ data class ItemSearchState(
*/ */
@Parcelize @Parcelize
data class Content( data class Content(
val displayItems: List<DisplayItem>, val itemList: List<VerificationCodeDisplayItem>,
) : ViewState() ) : ViewState()
/** /**
@@ -231,21 +214,6 @@ data class ItemSearchState(
@Parcelize @Parcelize
data class Empty(val message: Text?) : ViewState() data class Empty(val message: Text?) : ViewState()
} }
/**
* An item to be displayed.
*/
@Parcelize
data class DisplayItem(
val id: String,
val authCode: String,
val title: String,
val subtitle: String? = null,
val periodSeconds: Int,
val timeLeftSeconds: Int,
val alertThresholdSeconds: Int,
val startIcon: IconData,
) : Parcelable
} }
/** /**

View File

@@ -1,10 +1,10 @@
package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util package com.bitwarden.authenticator.ui.authenticator.feature.util
import com.bitwarden.authenticator.R import com.bitwarden.authenticator.R
import com.bitwarden.authenticator.data.authenticator.repository.model.AuthenticatorItem import com.bitwarden.authenticator.data.authenticator.repository.model.AuthenticatorItem
import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.SharedCodesDisplayState import com.bitwarden.authenticator.ui.authenticator.feature.model.SharedCodesDisplayState
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem import com.bitwarden.authenticator.ui.authenticator.feature.model.VerificationCodeDisplayItem
import com.bitwarden.ui.util.asText import com.bitwarden.ui.util.asText
/** /**

View File

@@ -1,9 +1,9 @@
package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util package com.bitwarden.authenticator.ui.authenticator.feature.util
import com.bitwarden.authenticator.data.authenticator.manager.model.VerificationCodeItem 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.AuthenticatorItem
import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem import com.bitwarden.authenticator.ui.authenticator.feature.model.VerificationCodeDisplayItem
/** /**
* Converts [VerificationCodeItem] to a [VerificationCodeDisplayItem]. * Converts [VerificationCodeItem] to a [VerificationCodeDisplayItem].

View File

@@ -9,9 +9,9 @@ import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollTo import androidx.compose.ui.test.performScrollTo
import androidx.compose.ui.test.performTouchInput import androidx.compose.ui.test.performTouchInput
import androidx.core.net.toUri import androidx.core.net.toUri
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.VaultDropdownMenuAction
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem import com.bitwarden.authenticator.ui.authenticator.feature.model.SharedCodesDisplayState
import com.bitwarden.authenticator.ui.authenticator.feature.model.VerificationCodeDisplayItem
import com.bitwarden.authenticator.ui.platform.base.AuthenticatorComposeTest import com.bitwarden.authenticator.ui.platform.base.AuthenticatorComposeTest
import com.bitwarden.authenticator.ui.platform.manager.intent.IntentManager import com.bitwarden.authenticator.ui.platform.manager.intent.IntentManager
import com.bitwarden.authenticator.ui.platform.manager.permissions.FakePermissionManager import com.bitwarden.authenticator.ui.platform.manager.permissions.FakePermissionManager

View File

@@ -10,11 +10,11 @@ import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVer
import com.bitwarden.authenticator.data.platform.manager.BitwardenEncodingManager import com.bitwarden.authenticator.data.platform.manager.BitwardenEncodingManager
import com.bitwarden.authenticator.data.platform.manager.clipboard.BitwardenClipboardManager import com.bitwarden.authenticator.data.platform.manager.clipboard.BitwardenClipboardManager
import com.bitwarden.authenticator.data.platform.repository.SettingsRepository import com.bitwarden.authenticator.data.platform.repository.SettingsRepository
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.VaultDropdownMenuAction
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem import com.bitwarden.authenticator.ui.authenticator.feature.model.SharedCodesDisplayState
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util.toDisplayItem import com.bitwarden.authenticator.ui.authenticator.feature.model.VerificationCodeDisplayItem
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util.toSharedCodesDisplayState import com.bitwarden.authenticator.ui.authenticator.feature.util.toDisplayItem
import com.bitwarden.authenticator.ui.authenticator.feature.util.toSharedCodesDisplayState
import com.bitwarden.authenticatorbridge.manager.AuthenticatorBridgeManager import com.bitwarden.authenticatorbridge.manager.AuthenticatorBridgeManager
import com.bitwarden.core.data.repository.model.DataState import com.bitwarden.core.data.repository.model.DataState
import com.bitwarden.ui.platform.base.BaseViewModelTest import com.bitwarden.ui.platform.base.BaseViewModelTest

View File

@@ -9,6 +9,7 @@ import com.bitwarden.authenticator.data.authenticator.repository.model.Authentic
import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState
import com.bitwarden.authenticator.data.authenticator.repository.util.itemsOrEmpty import com.bitwarden.authenticator.data.authenticator.repository.util.itemsOrEmpty
import com.bitwarden.authenticator.data.platform.manager.clipboard.BitwardenClipboardManager import com.bitwarden.authenticator.data.platform.manager.clipboard.BitwardenClipboardManager
import com.bitwarden.authenticator.ui.authenticator.feature.model.VerificationCodeDisplayItem
import com.bitwarden.core.data.repository.model.DataState import com.bitwarden.core.data.repository.model.DataState
import com.bitwarden.ui.platform.base.BaseViewModelTest import com.bitwarden.ui.platform.base.BaseViewModelTest
import com.bitwarden.ui.platform.components.icon.model.IconData import com.bitwarden.ui.platform.components.icon.model.IconData
@@ -66,7 +67,7 @@ class ItemSearchViewModelTest : BaseViewModelTest() {
assertEquals( assertEquals(
ItemSearchState.ViewState.Content( ItemSearchState.ViewState.Content(
displayItems = SHARED_AND_LOCAL_DISPLAY_ITEMS, itemList = SHARED_AND_LOCAL_DISPLAY_ITEMS,
), ),
viewModel.stateFlow.value.viewState, viewModel.stateFlow.value.viewState,
) )
@@ -84,7 +85,7 @@ class ItemSearchViewModelTest : BaseViewModelTest() {
assertEquals( assertEquals(
ItemSearchState.ViewState.Content( ItemSearchState.ViewState.Content(
displayItems = listOf(SHARED_AND_LOCAL_DISPLAY_ITEMS[1]), itemList = listOf(SHARED_AND_LOCAL_DISPLAY_ITEMS[1]),
), ),
viewModel.stateFlow.value.viewState, viewModel.stateFlow.value.viewState,
) )
@@ -116,7 +117,7 @@ private val LOCAL_ITEMS = listOf(
private val SHARED_ITEMS = listOf( private val SHARED_ITEMS = listOf(
VerificationCodeItem( VerificationCodeItem(
"123456", code = "123456",
periodSeconds = 60, periodSeconds = 60,
timeLeftSeconds = 30, timeLeftSeconds = 30,
issueTime = 1, issueTime = 1,
@@ -133,24 +134,36 @@ private val SHARED_ITEMS = listOf(
) )
private val SHARED_AND_LOCAL_DISPLAY_ITEMS = listOf( private val SHARED_AND_LOCAL_DISPLAY_ITEMS = listOf(
ItemSearchState.DisplayItem( VerificationCodeDisplayItem(
id = SHARED_ITEMS[0].id, id = SHARED_ITEMS[0].id,
authCode = SHARED_ITEMS[0].code, authCode = SHARED_ITEMS[0].code,
title = SHARED_ITEMS[0].issuer!!, title = SHARED_ITEMS[0].issuer!!,
periodSeconds = SHARED_ITEMS[0].periodSeconds, periodSeconds = SHARED_ITEMS[0].periodSeconds,
timeLeftSeconds = SHARED_ITEMS[0].timeLeftSeconds, timeLeftSeconds = SHARED_ITEMS[0].timeLeftSeconds,
alertThresholdSeconds = 7, alertThresholdSeconds = 7,
startIcon = IconData.Local(iconRes = R.drawable.ic_login_item), startIcon = IconData.Local(
iconRes = R.drawable.ic_login_item,
testTag = "BitwardenIcon",
),
subtitle = SHARED_ITEMS[0].label, subtitle = SHARED_ITEMS[0].label,
favorite = false,
allowLongPressActions = false,
showMoveToBitwarden = false,
), ),
ItemSearchState.DisplayItem( VerificationCodeDisplayItem(
id = LOCAL_ITEMS[0].id, id = LOCAL_ITEMS[0].id,
authCode = LOCAL_ITEMS[0].code, authCode = LOCAL_ITEMS[0].code,
title = LOCAL_ITEMS[0].issuer!!, title = LOCAL_ITEMS[0].issuer!!,
periodSeconds = LOCAL_ITEMS[0].periodSeconds, periodSeconds = LOCAL_ITEMS[0].periodSeconds,
timeLeftSeconds = LOCAL_ITEMS[0].timeLeftSeconds, timeLeftSeconds = LOCAL_ITEMS[0].timeLeftSeconds,
alertThresholdSeconds = 7, alertThresholdSeconds = 7,
startIcon = IconData.Local(iconRes = R.drawable.ic_login_item), startIcon = IconData.Local(
iconRes = R.drawable.ic_login_item,
testTag = "BitwardenIcon",
),
subtitle = LOCAL_ITEMS[0].label, subtitle = LOCAL_ITEMS[0].label,
favorite = false,
allowLongPressActions = true,
showMoveToBitwarden = true,
), ),
) )

View File

@@ -1,11 +1,11 @@
package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util package com.bitwarden.authenticator.ui.authenticator.feature.util
import com.bitwarden.authenticator.R import com.bitwarden.authenticator.R
import com.bitwarden.authenticator.data.authenticator.manager.model.VerificationCodeItem 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.AuthenticatorItem
import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.SharedCodesDisplayState import com.bitwarden.authenticator.ui.authenticator.feature.model.SharedCodesDisplayState
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem import com.bitwarden.authenticator.ui.authenticator.feature.model.VerificationCodeDisplayItem
import com.bitwarden.ui.util.asText import com.bitwarden.ui.util.asText
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test

View File

@@ -1,9 +1,9 @@
package com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.util package com.bitwarden.authenticator.ui.authenticator.feature.util
import com.bitwarden.authenticator.data.authenticator.manager.util.createMockVerificationCodeItem 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.AuthenticatorItem
import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.model.VerificationCodeDisplayItem import com.bitwarden.authenticator.ui.authenticator.feature.model.VerificationCodeDisplayItem
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test