PM-30807: Add archived header to ViewItem Screen (#6362)

This commit is contained in:
David Perez 2026-01-15 09:45:01 -06:00 committed by GitHub
parent 44274a888e
commit 98ba1690bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 73 additions and 3 deletions

View File

@ -57,6 +57,7 @@ fun VaultItemCardContent(
itemHeader(
value = commonState.name,
isFavorite = commonState.favorite,
isArchived = commonState.archived,
iconData = cardState.paymentCardBrandIconData ?: commonState.iconData,
relatedLocations = commonState.relatedLocations,
iconTestTag = "CardItemNameIcon",

View File

@ -57,6 +57,7 @@ fun VaultItemIdentityContent(
itemHeader(
value = commonState.name,
isFavorite = commonState.favorite,
isArchived = commonState.archived,
iconData = commonState.iconData,
relatedLocations = commonState.relatedLocations,
iconTestTag = "IdentityItemNameIcon",

View File

@ -65,6 +65,7 @@ fun VaultItemLoginContent(
itemHeader(
value = commonState.name,
isFavorite = commonState.favorite,
isArchived = commonState.archived,
iconData = commonState.iconData,
relatedLocations = commonState.relatedLocations,
iconTestTag = "LoginItemNameIcon",

View File

@ -51,6 +51,7 @@ fun VaultItemSecureNoteContent(
itemHeader(
value = commonState.name,
isFavorite = commonState.favorite,
isArchived = commonState.archived,
iconData = commonState.iconData,
relatedLocations = commonState.relatedLocations,
iconTestTag = "SecureNoteItemNameIcon",

View File

@ -55,6 +55,7 @@ fun VaultItemSshKeyContent(
itemHeader(
value = commonState.name,
isFavorite = commonState.favorite,
isArchived = commonState.archived,
iconData = commonState.iconData,
relatedLocations = commonState.relatedLocations,
iconTestTag = "SshKeyItemNameIcon",

View File

@ -1421,6 +1421,7 @@ data class VaultItemState(
val canAssignToCollections: Boolean,
val canEdit: Boolean,
val favorite: Boolean,
val archived: Boolean,
val passwordHistoryCount: Int?,
val iconData: IconData,
val relatedLocations: ImmutableList<VaultItemLocation>,

View File

@ -52,6 +52,7 @@ import kotlinx.collections.immutable.persistentListOf
*
* @param value The name of the cipher.
* @param isFavorite Whether the cipher is a favorite.
* @param isArchived Whether the cipher is archived.
* @param relatedLocations The locations the cipher is assigned to.
* @param iconData The icon to be displayed.
* @param isExpanded Whether the related locations are expanded.
@ -64,6 +65,7 @@ import kotlinx.collections.immutable.persistentListOf
fun LazyListScope.itemHeader(
value: String,
isFavorite: Boolean,
isArchived: Boolean,
relatedLocations: ImmutableList<VaultItemLocation>,
iconData: IconData,
isExpanded: Boolean,
@ -132,6 +134,25 @@ fun LazyListScope.itemHeader(
}
}
if (isArchived) {
item(key = "archiveItem") {
ItemLocationListItem(
vectorPainter = rememberVectorPainter(id = BitwardenDrawable.ic_archive),
text = stringResource(id = BitwardenString.archived),
iconTestTag = "ArchiveIcon",
modifier = Modifier
.standardHorizontalMargin()
.fillMaxWidth()
.animateItem()
.cardStyle(
cardStyle = CardStyle.Middle(hasDivider = false),
paddingVertical = 0.dp,
paddingHorizontal = 16.dp,
),
)
}
}
// When the item does not belong to an Org and is not assigned to a collection or folder we
// display the "No Folder" indicator.
if (relatedLocations.isEmpty()) {
@ -183,7 +204,7 @@ fun LazyListScope.itemHeader(
if (collectionLocations.size == 1 && folderLocations.size == 1) {
itemsIndexed(
items = collectionLocations + folderLocations,
key = { index, location -> "locations_$index" },
key = { index, _ -> "locations_$index" },
) { index, location ->
ItemLocationListItem(
vectorPainter = rememberVectorPainter(location.icon),
@ -263,7 +284,7 @@ fun LazyListScope.itemHeader(
itemsIndexed(
key = { index, _ -> "expandableLocations_$index" },
items = collectionLocations.drop(1) + folderLocations,
) { index, location ->
) { _, location ->
ItemLocationListItem(
vectorPainter = rememberVectorPainter(location.icon),
text = location.name,
@ -364,7 +385,7 @@ private fun LazyItemScope.ItemLocationListItem(
Text(
text = text,
style = BitwardenTheme.typography.bodyLarge,
color = BitwardenTheme.colorScheme.text.primary,
color = BitwardenTheme.colorScheme.text.secondary,
modifier = Modifier
.padding(start = 16.dp)
.testTag("ItemLocationText"),
@ -382,6 +403,7 @@ private fun ItemHeaderWithLocalIcon_Preview() {
itemHeader(
value = "Login without favicon",
isFavorite = true,
isArchived = false,
iconData = IconData.Local(
iconRes = BitwardenDrawable.ic_globe,
),
@ -403,6 +425,7 @@ private fun ItemHeaderWithNetworkIcon_Preview() {
itemHeader(
value = "Login with favicon",
isFavorite = true,
isArchived = false,
iconData = IconData.Network(
uri = "mockuri",
fallbackIconRes = BitwardenDrawable.ic_globe,
@ -425,6 +448,7 @@ private fun ItemHeaderWithOrganization_Preview() {
itemHeader(
value = "Login without favicon",
isFavorite = true,
isArchived = true,
iconData = IconData.Local(
iconRes = BitwardenDrawable.ic_globe,
),
@ -448,6 +472,7 @@ private fun ItemHeaderWithOrgAndSingleCollection_Preview() {
itemHeader(
value = "Login without favicon",
isFavorite = true,
isArchived = false,
iconData = IconData.Local(
iconRes = BitwardenDrawable.ic_globe,
),
@ -472,6 +497,7 @@ private fun ItemHeaderWithOrgAndMultiCollection_Preview() {
itemHeader(
value = "Login without favicon",
isFavorite = true,
isArchived = false,
iconData = IconData.Local(
iconRes = BitwardenDrawable.ic_payment_card_brand_visa,
),
@ -497,6 +523,7 @@ private fun ItemHeaderWithOrgSingleCollectionAndFolder_Preview() {
itemHeader(
value = "Note without favicon",
isFavorite = true,
isArchived = true,
iconData = IconData.Local(
iconRes = BitwardenDrawable.ic_note,
),
@ -522,6 +549,7 @@ private fun ItemHeaderFolderOnly_Preview() {
itemHeader(
value = "SSH key in a folder",
isFavorite = true,
isArchived = true,
iconData = IconData.Local(
iconRes = BitwardenDrawable.ic_ssh_key,
),

View File

@ -108,6 +108,7 @@ fun CipherView.toViewState(
canAssignToCollections = canAssignToCollections,
canEdit = canEdit,
favorite = this.favorite,
archived = this.archivedDate != null,
passwordHistoryCount = passwordHistory?.count(),
iconData = this.toIconData(
baseIconUrl = baseIconUrl,

View File

@ -251,6 +251,35 @@ class VaultItemScreenTest : BitwardenComposeTest() {
}
}
@Test
fun `archived icon should be displayed according to state`() {
mutableStateFlow.update {
DEFAULT_STATE.copy(
viewState = DEFAULT_LOGIN_VIEW_STATE.copy(
common = DEFAULT_COMMON.copy(
archived = false,
),
),
)
}
composeTestRule
.onNodeWithText(text = "Archived")
.assertDoesNotExist()
mutableStateFlow.update {
DEFAULT_STATE.copy(
viewState = DEFAULT_LOGIN_VIEW_STATE.copy(
common = DEFAULT_COMMON.copy(
archived = true,
),
),
)
}
composeTestRule
.onNodeWithText(text = "Archived")
.assertIsDisplayed()
}
@Test
fun `favorite icon should be displayed according to state`() {
mutableStateFlow.update {
@ -3222,6 +3251,7 @@ private val DEFAULT_COMMON: VaultItemState.ViewState.Content.Common =
canAssignToCollections = true,
canEdit = true,
favorite = false,
archived = false,
passwordHistoryCount = null,
iconData = IconData.Local(iconRes = BitwardenDrawable.ic_globe),
relatedLocations = persistentListOf(),
@ -3308,6 +3338,7 @@ private val EMPTY_COMMON: VaultItemState.ViewState.Content.Common =
canAssignToCollections = true,
canEdit = true,
favorite = false,
archived = false,
passwordHistoryCount = null,
iconData = IconData.Local(iconRes = BitwardenDrawable.ic_globe),
relatedLocations = persistentListOf(),

View File

@ -2709,6 +2709,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
canAssignToCollections = true,
canEdit = true,
favorite = false,
archived = false,
passwordHistoryCount = 1,
iconData = IconData.Local(BitwardenDrawable.ic_globe),
relatedLocations = persistentListOf(),

View File

@ -182,6 +182,7 @@ fun createCommonContent(
canAssignToCollections = true,
canEdit = true,
favorite = false,
archived = false,
passwordHistoryCount = null,
relatedLocations = persistentListOf(),
iconData = IconData.Local(iconResId),
@ -246,6 +247,7 @@ fun createCommonContent(
canAssignToCollections = true,
canEdit = true,
favorite = false,
archived = false,
passwordHistoryCount = 1,
relatedLocations = persistentListOf(),
iconData = IconData.Local(iconResId),

View File

@ -1175,5 +1175,6 @@ Do you want to switch to this account?</string>
<string name="failed_to_migrate_items_to_x">Failed to migrate items to %s</string>
<string name="search_archive">Search archive</string>
<string name="archive_noun">Archive</string>
<string name="archived">Archived</string>
<string name="hidden_items">Hidden items</string>
</resources>