mirror of
https://github.com/bitwarden/android.git
synced 2025-12-11 22:52:20 -06:00
[PM-25394] Sort default user collections by Organization name (#5819)
This commit is contained in:
parent
9adc25471e
commit
1c4e4dcaf4
@ -82,7 +82,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.UpdateSendResult
|
|||||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultData
|
import com.x8bit.bitwarden.data.vault.repository.model.VaultData
|
||||||
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult
|
import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult
|
||||||
import com.x8bit.bitwarden.data.vault.repository.util.sortAlphabetically
|
import com.x8bit.bitwarden.data.vault.repository.util.sortAlphabetically
|
||||||
import com.x8bit.bitwarden.data.vault.repository.util.sortAlphabeticallyByType
|
import com.x8bit.bitwarden.data.vault.repository.util.sortAlphabeticallyByTypeAndOrganization
|
||||||
import com.x8bit.bitwarden.data.vault.repository.util.toDomainsData
|
import com.x8bit.bitwarden.data.vault.repository.util.toDomainsData
|
||||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedNetworkFolder
|
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedNetworkFolder
|
||||||
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedNetworkSend
|
import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedNetworkSend
|
||||||
@ -1168,7 +1168,11 @@ class VaultRepositoryImpl(
|
|||||||
.fold(
|
.fold(
|
||||||
onSuccess = { collections ->
|
onSuccess = { collections ->
|
||||||
DataState.Loaded(
|
DataState.Loaded(
|
||||||
collections.sortAlphabeticallyByType(),
|
collections.sortAlphabeticallyByTypeAndOrganization(
|
||||||
|
userOrganizations = authDiskSource
|
||||||
|
.getOrganizations(userId = userId)
|
||||||
|
.orEmpty(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onFailure = { throwable -> DataState.Error(throwable) },
|
onFailure = { throwable -> DataState.Error(throwable) },
|
||||||
|
|||||||
@ -32,21 +32,45 @@ fun List<SyncResponseJson.Collection>.toEncryptedSdkCollectionList(): List<Colle
|
|||||||
map { it.toEncryptedSdkCollection() }
|
map { it.toEncryptedSdkCollection() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts the collections, grouping them by type, with `DEFAULT_USER_COLLECTION` types displayed
|
* Sorts a list of [CollectionView] objects based on a multi-level sorting logic.
|
||||||
* first. Within each group, collections are sorted alphabetically by name.
|
*
|
||||||
|
* The sorting criteria are as follows, in order of precedence:
|
||||||
|
* 1. Collections of type `DEFAULT_USER_COLLECTION` are placed first.
|
||||||
|
* 2. All other collections are grouped by their `CollectionType`.
|
||||||
|
* 3. Within each group, collections are sorted alphabetically by name. For collections of
|
||||||
|
* type `DEFAULT_USER_COLLECTION`, the corresponding organization's name is used for sorting
|
||||||
|
* instead of the collection's own name.
|
||||||
|
*
|
||||||
|
* This function uses a [SpecialCharWithPrecedenceComparator] for the alphabetical sort.
|
||||||
|
*
|
||||||
|
* @param userOrganizations A list of the user's organizations, used to find the name for
|
||||||
|
* `DEFAULT_USER_COLLECTION` types.
|
||||||
|
* @return A new list containing the sorted [CollectionView] objects.
|
||||||
*/
|
*/
|
||||||
@JvmName("toAlphabeticallySortedCollectionList")
|
fun List<CollectionView>.sortAlphabeticallyByTypeAndOrganization(
|
||||||
fun List<CollectionView>.sortAlphabeticallyByType(): List<CollectionView> {
|
userOrganizations: List<SyncResponseJson.Profile.Organization>,
|
||||||
|
): List<CollectionView> {
|
||||||
return this.sortedWith(
|
return this.sortedWith(
|
||||||
// DEFAULT_USER_COLLECTION come first
|
// DEFAULT_USER_COLLECTION come first
|
||||||
comparator = compareBy<CollectionView> { it.type != CollectionType.DEFAULT_USER_COLLECTION }
|
comparator = compareBy<CollectionView> { it.type != CollectionType.DEFAULT_USER_COLLECTION }
|
||||||
// Then sort by other CollectionType ordinals
|
// Then sort by other CollectionType ordinals
|
||||||
.thenBy { it.type }
|
.thenBy { it.type }
|
||||||
// Finally, sort by name within each group
|
// Finally, sort within each group. For default collections, use the
|
||||||
.thenComparing(
|
// organization's name; for others, use the collection's name.
|
||||||
CollectionView::name,
|
.thenBy(SpecialCharWithPrecedenceComparator) {
|
||||||
SpecialCharWithPrecedenceComparator,
|
if (it.type == CollectionType.DEFAULT_USER_COLLECTION) {
|
||||||
),
|
// For default collections, sort by the organization's name
|
||||||
|
userOrganizations
|
||||||
|
.find { org -> org.id == it.organizationId }
|
||||||
|
?.name
|
||||||
|
?: it.name
|
||||||
|
} else {
|
||||||
|
// For other collections, sort by the collection's name
|
||||||
|
it.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// As a final fallback if names are identical, sort by ID to ensure a stable order
|
||||||
|
.thenBy { it.id },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import com.bitwarden.collections.Collection
|
|||||||
import com.bitwarden.collections.CollectionType
|
import com.bitwarden.collections.CollectionType
|
||||||
import com.bitwarden.network.model.CollectionTypeJson
|
import com.bitwarden.network.model.CollectionTypeJson
|
||||||
import com.bitwarden.network.model.SyncResponseJson
|
import com.bitwarden.network.model.SyncResponseJson
|
||||||
|
import com.bitwarden.network.model.createMockOrganization
|
||||||
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView
|
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
@ -103,7 +104,7 @@ class VaultSdkCollectionExtensionsTest {
|
|||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `toSortAlphabetically should sort collections by type and name`() {
|
fun `toSortAlphabeticallyByTypeAndOrganization should sort collections by type and name`() {
|
||||||
val list = listOf(
|
val list = listOf(
|
||||||
createMockCollectionView(1).copy(name = "c"),
|
createMockCollectionView(1).copy(name = "c"),
|
||||||
createMockCollectionView(1).copy(name = "B"),
|
createMockCollectionView(1).copy(name = "B"),
|
||||||
@ -111,16 +112,28 @@ class VaultSdkCollectionExtensionsTest {
|
|||||||
createMockCollectionView(1).copy(name = "4"),
|
createMockCollectionView(1).copy(name = "4"),
|
||||||
createMockCollectionView(1).copy(name = "A"),
|
createMockCollectionView(1).copy(name = "A"),
|
||||||
createMockCollectionView(1).copy(name = "#"),
|
createMockCollectionView(1).copy(name = "#"),
|
||||||
createMockCollectionView(1).copy(
|
createMockCollectionView(2).copy(
|
||||||
name = "D",
|
name = "Org2 items",
|
||||||
type = CollectionType.DEFAULT_USER_COLLECTION,
|
type = CollectionType.DEFAULT_USER_COLLECTION,
|
||||||
|
organizationId = "mockId-2",
|
||||||
|
),
|
||||||
|
createMockCollectionView(1).copy(
|
||||||
|
name = "Org1 items",
|
||||||
|
type = CollectionType.DEFAULT_USER_COLLECTION,
|
||||||
|
organizationId = "mockId-1",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
val expected = listOf(
|
val expected = listOf(
|
||||||
createMockCollectionView(1).copy(
|
createMockCollectionView(1).copy(
|
||||||
name = "D",
|
name = "Org1 items",
|
||||||
type = CollectionType.DEFAULT_USER_COLLECTION,
|
type = CollectionType.DEFAULT_USER_COLLECTION,
|
||||||
|
organizationId = "mockId-1",
|
||||||
|
),
|
||||||
|
createMockCollectionView(2).copy(
|
||||||
|
name = "Org2 items",
|
||||||
|
type = CollectionType.DEFAULT_USER_COLLECTION,
|
||||||
|
organizationId = "mockId-2",
|
||||||
),
|
),
|
||||||
createMockCollectionView(1).copy(name = "#"),
|
createMockCollectionView(1).copy(name = "#"),
|
||||||
createMockCollectionView(1).copy(name = "4"),
|
createMockCollectionView(1).copy(name = "4"),
|
||||||
@ -132,7 +145,12 @@ class VaultSdkCollectionExtensionsTest {
|
|||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
expected,
|
expected,
|
||||||
list.sortAlphabeticallyByType(),
|
list.sortAlphabeticallyByTypeAndOrganization(
|
||||||
|
userOrganizations = listOf(
|
||||||
|
createMockOrganization(number = 1),
|
||||||
|
createMockOrganization(number = 2),
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user