BWA-224: bug: Add sort order for Authenticator items (#6740)

This commit is contained in:
David Perez
2026-03-30 14:05:51 -05:00
committed by GitHub
parent 8263a178ca
commit 0871a2a33d
11 changed files with 253 additions and 50 deletions

View File

@@ -629,6 +629,7 @@ private fun EmptyListingContentPreview() {
@Composable
@Preview(showBackground = true)
private fun ContentPreview() {
val email = "longemailaddress+verification+codes@email.com"
BitwardenTheme {
ItemListingContent(
state = ItemListingState.ViewState.Content(
@@ -652,9 +653,7 @@ private fun ContentPreview() {
sections = persistentListOf(
SharedCodesDisplayState.SharedCodesAccountSection(
id = "id",
label =
"longemailaddress+verification+codes@email.com | Bitawrden.eu (1)"
.asText(),
label = "$email | Bitawrden.eu (1)".asText(),
codes = persistentListOf(
VerificationCodeDisplayItem(
id = "",
@@ -670,6 +669,7 @@ private fun ContentPreview() {
),
),
isExpanded = true,
sortKey = email,
),
),
),

View File

@@ -23,6 +23,7 @@ import com.bitwarden.authenticator.ui.authenticator.feature.util.toSharedCodesDi
import com.bitwarden.authenticator.ui.platform.components.listitem.model.SharedCodesDisplayState
import com.bitwarden.authenticator.ui.platform.components.listitem.model.VaultDropdownMenuAction
import com.bitwarden.authenticator.ui.platform.components.listitem.model.VerificationCodeDisplayItem
import com.bitwarden.authenticator.ui.platform.components.listitem.model.util.sortAlphabetically
import com.bitwarden.authenticator.ui.platform.model.SnackbarRelay
import com.bitwarden.authenticatorbridge.manager.AuthenticatorBridgeManager
import com.bitwarden.core.data.repository.model.DataState
@@ -509,6 +510,7 @@ class ItemListingViewModel @Inject constructor(
showOverflow = true,
)
}
.sortAlphabetically()
.toImmutableList(),
itemList = localItems
.filter { it.source is AuthenticatorItem.Source.Local && !it.source.isFavorite }
@@ -521,6 +523,7 @@ class ItemListingViewModel @Inject constructor(
showOverflow = true,
)
}
.sortAlphabetically()
.toImmutableList(),
sharedItems = sharedItemsState,
actionCard = action.sharedCodesState.toActionCard(),

View File

@@ -4,6 +4,7 @@ import com.bitwarden.authenticator.data.authenticator.repository.model.Authentic
import com.bitwarden.authenticator.data.authenticator.repository.model.SharedVerificationCodesState
import com.bitwarden.authenticator.ui.platform.components.listitem.model.SharedCodesDisplayState
import com.bitwarden.authenticator.ui.platform.components.listitem.model.VerificationCodeDisplayItem
import com.bitwarden.authenticator.ui.platform.components.listitem.model.util.sortAlphabetically
import com.bitwarden.ui.platform.resource.BitwardenString
import com.bitwarden.ui.util.asText
import kotlinx.collections.immutable.toImmutableList
@@ -41,12 +42,14 @@ fun SharedVerificationCodesState.Success.toSharedCodesDisplayState(
it.key.environmentLabel,
it.value.size,
),
codes = it.value.toImmutableList(),
codes = it.value.sortAlphabetically().toImmutableList(),
isExpanded = currentSections
.find { section -> section.id == it.key.userId }
?.isExpanded
?: true,
sortKey = it.key.email,
)
}
.sortAlphabetically()
.let { SharedCodesDisplayState.Codes(it.toImmutableList()) }
}

View File

@@ -33,6 +33,7 @@ sealed class SharedCodesDisplayState : Parcelable {
val label: Text,
val codes: ImmutableList<VerificationCodeDisplayItem>,
val isExpanded: Boolean,
val sortKey: String,
) : Parcelable
/**

View File

@@ -0,0 +1,15 @@
package com.bitwarden.authenticator.ui.platform.components.listitem.model.util
import com.bitwarden.authenticator.ui.platform.components.listitem.model.SharedCodesDisplayState.SharedCodesAccountSection
import com.bitwarden.core.data.repository.util.SpecialCharWithPrecedenceComparator
/**
* Sorts the data in alphabetical order by name. Using lexicographical sorting but giving
* precedence to special characters over letters and digits.
*/
fun List<SharedCodesAccountSection>.sortAlphabetically(): List<SharedCodesAccountSection> =
this.sortedWith(
comparator = { item1, item2 ->
SpecialCharWithPrecedenceComparator.compare(item1.sortKey, item2.sortKey)
},
)

View File

@@ -0,0 +1,15 @@
package com.bitwarden.authenticator.ui.platform.components.listitem.model.util
import com.bitwarden.authenticator.ui.platform.components.listitem.model.VerificationCodeDisplayItem
import com.bitwarden.core.data.repository.util.SpecialCharWithPrecedenceComparator
/**
* Sorts the data in alphabetical order by name. Using lexicographical sorting but giving
* precedence to special characters over letters and digits.
*/
fun List<VerificationCodeDisplayItem>.sortAlphabetically(): List<VerificationCodeDisplayItem> =
this.sortedWith(
comparator = { item1, item2 ->
SpecialCharWithPrecedenceComparator.compare(item1.title, item2.title)
},
)

View File

@@ -570,6 +570,7 @@ private val SHARED_ACCOUNTS_SECTION = SharedCodesDisplayState.SharedCodesAccount
),
),
isExpanded = true,
sortKey = "test@test.com",
)
private val DEFAULT_STATE = ItemListingState(

View File

@@ -410,6 +410,7 @@ private val SHARED_DISPLAY_ITEMS = SharedCodesDisplayState.Codes(
),
),
isExpanded = true,
sortKey = "mockEmail-2",
),
),
)

View File

@@ -61,29 +61,6 @@ class SharedVerificationCodesStateTest {
)
val expected = SharedCodesDisplayState.Codes(
sections = persistentListOf(
SharedCodesDisplayState.SharedCodesAccountSection(
id = "user1",
label = BitwardenString.shared_accounts_header.asText(
"John@test.com",
"bitwarden.com",
1,
),
codes = persistentListOf(
VerificationCodeDisplayItem(
authCode = "123456",
periodSeconds = 30,
timeLeftSeconds = 10,
id = "123",
title = "--",
subtitle = null,
favorite = false,
showOverflow = false,
alertThresholdSeconds = ALERT_THRESHOLD,
showMoveToBitwarden = false,
),
),
isExpanded = true,
),
SharedCodesDisplayState.SharedCodesAccountSection(
id = "user1",
label = BitwardenString.shared_accounts_header.asText(
@@ -106,6 +83,31 @@ class SharedVerificationCodesStateTest {
),
),
isExpanded = true,
sortKey = "Jane@test.com",
),
SharedCodesDisplayState.SharedCodesAccountSection(
id = "user1",
label = BitwardenString.shared_accounts_header.asText(
"John@test.com",
"bitwarden.com",
1,
),
codes = persistentListOf(
VerificationCodeDisplayItem(
authCode = "123456",
periodSeconds = 30,
timeLeftSeconds = 10,
id = "123",
title = "--",
subtitle = null,
favorite = false,
showOverflow = false,
alertThresholdSeconds = ALERT_THRESHOLD,
showMoveToBitwarden = false,
),
),
isExpanded = true,
sortKey = "John@test.com",
),
),
)
@@ -153,29 +155,6 @@ class SharedVerificationCodesStateTest {
)
val expected = SharedCodesDisplayState.Codes(
sections = persistentListOf(
SharedCodesDisplayState.SharedCodesAccountSection(
id = "user1",
label = BitwardenString.shared_accounts_header.asText(
"John@test.com",
"bitwarden.com",
1,
),
codes = persistentListOf(
VerificationCodeDisplayItem(
authCode = "123456",
periodSeconds = 30,
timeLeftSeconds = 10,
id = "123",
title = "--",
subtitle = null,
favorite = false,
showOverflow = false,
alertThresholdSeconds = ALERT_THRESHOLD,
showMoveToBitwarden = false,
),
),
isExpanded = false,
),
SharedCodesDisplayState.SharedCodesAccountSection(
id = "user1",
label = BitwardenString.shared_accounts_header.asText(
@@ -198,6 +177,31 @@ class SharedVerificationCodesStateTest {
),
),
isExpanded = false,
sortKey = "Jane@test.com",
),
SharedCodesDisplayState.SharedCodesAccountSection(
id = "user1",
label = BitwardenString.shared_accounts_header.asText(
"John@test.com",
"bitwarden.com",
1,
),
codes = persistentListOf(
VerificationCodeDisplayItem(
authCode = "123456",
periodSeconds = 30,
timeLeftSeconds = 10,
id = "123",
title = "--",
subtitle = null,
favorite = false,
showOverflow = false,
alertThresholdSeconds = ALERT_THRESHOLD,
showMoveToBitwarden = false,
),
),
isExpanded = false,
sortKey = "John@test.com",
),
),
)

View File

@@ -0,0 +1,67 @@
package com.bitwarden.authenticator.ui.platform.components.listitem.model.util
import com.bitwarden.authenticator.ui.platform.components.listitem.model.SharedCodesDisplayState
import com.bitwarden.ui.platform.resource.BitwardenString
import com.bitwarden.ui.util.asText
import kotlinx.collections.immutable.persistentListOf
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
class SharedCodesAccountSectionExtensionsTest {
@Test
fun `toSortAlphabetically should sort ciphers by sortKey`() {
val codes = persistentListOf(
SharedCodesDisplayState.SharedCodesAccountSection(
id = "user1",
label = BitwardenString.shared_accounts_header.asText(
"John@test.com",
"bitwarden.com",
1,
),
codes = persistentListOf(),
isExpanded = true,
sortKey = "John@test.com",
),
SharedCodesDisplayState.SharedCodesAccountSection(
id = "user1",
label = BitwardenString.shared_accounts_header.asText(
"Jane@test.com",
"bitwarden.eu",
1,
),
codes = persistentListOf(),
isExpanded = true,
sortKey = "Jane@test.com",
),
)
val expected = persistentListOf(
SharedCodesDisplayState.SharedCodesAccountSection(
id = "user1",
label = BitwardenString.shared_accounts_header.asText(
"Jane@test.com",
"bitwarden.eu",
1,
),
codes = persistentListOf(),
isExpanded = true,
sortKey = "Jane@test.com",
),
SharedCodesDisplayState.SharedCodesAccountSection(
id = "user1",
label = BitwardenString.shared_accounts_header.asText(
"John@test.com",
"bitwarden.com",
1,
),
codes = persistentListOf(),
isExpanded = true,
sortKey = "John@test.com",
),
)
assertEquals(
expected,
codes.sortAlphabetically(),
)
}
}

View File

@@ -0,0 +1,93 @@
package com.bitwarden.authenticator.ui.platform.components.listitem.model.util
import com.bitwarden.authenticator.ui.platform.components.listitem.model.VerificationCodeDisplayItem
import kotlinx.collections.immutable.persistentListOf
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
class VerificationCodeDisplayItemExtensionsTest {
@Test
fun `toSortAlphabetically should sort ciphers by title`() {
val codes = persistentListOf(
VerificationCodeDisplayItem(
authCode = "123456",
periodSeconds = 30,
timeLeftSeconds = 10,
id = "123",
title = "Bitwarden",
subtitle = null,
favorite = false,
showOverflow = false,
alertThresholdSeconds = 7,
showMoveToBitwarden = false,
),
VerificationCodeDisplayItem(
authCode = "123456",
periodSeconds = 30,
timeLeftSeconds = 10,
id = "7643",
title = "--",
subtitle = null,
favorite = false,
showOverflow = false,
alertThresholdSeconds = 7,
showMoveToBitwarden = false,
),
VerificationCodeDisplayItem(
authCode = "123456",
periodSeconds = 30,
timeLeftSeconds = 10,
id = "84345",
title = "bitwarden",
subtitle = null,
favorite = false,
showOverflow = false,
alertThresholdSeconds = 7,
showMoveToBitwarden = false,
),
)
val expected = persistentListOf(
VerificationCodeDisplayItem(
authCode = "123456",
periodSeconds = 30,
timeLeftSeconds = 10,
id = "7643",
title = "--",
subtitle = null,
favorite = false,
showOverflow = false,
alertThresholdSeconds = 7,
showMoveToBitwarden = false,
),
VerificationCodeDisplayItem(
authCode = "123456",
periodSeconds = 30,
timeLeftSeconds = 10,
id = "84345",
title = "bitwarden",
subtitle = null,
favorite = false,
showOverflow = false,
alertThresholdSeconds = 7,
showMoveToBitwarden = false,
),
VerificationCodeDisplayItem(
authCode = "123456",
periodSeconds = 30,
timeLeftSeconds = 10,
id = "123",
title = "Bitwarden",
subtitle = null,
favorite = false,
showOverflow = false,
alertThresholdSeconds = 7,
showMoveToBitwarden = false,
),
)
assertEquals(
expected,
codes.sortAlphabetically(),
)
}
}