diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt index 959e7b2a77..af13899bf4 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt @@ -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.VaultUnlockResult 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.toEncryptedNetworkFolder import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedNetworkSend @@ -1168,7 +1168,11 @@ class VaultRepositoryImpl( .fold( onSuccess = { collections -> DataState.Loaded( - collections.sortAlphabeticallyByType(), + collections.sortAlphabeticallyByTypeAndOrganization( + userOrganizations = authDiskSource + .getOrganizations(userId = userId) + .orEmpty(), + ), ) }, onFailure = { throwable -> DataState.Error(throwable) }, diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/VaultSdkCollectionExtensions.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/VaultSdkCollectionExtensions.kt index 14f5b30ef5..f140c3255a 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/VaultSdkCollectionExtensions.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/VaultSdkCollectionExtensions.kt @@ -32,21 +32,45 @@ fun List.toEncryptedSdkCollectionList(): List.sortAlphabeticallyByType(): List { +fun List.sortAlphabeticallyByTypeAndOrganization( + userOrganizations: List, +): List { return this.sortedWith( // DEFAULT_USER_COLLECTION come first comparator = compareBy { it.type != CollectionType.DEFAULT_USER_COLLECTION } // Then sort by other CollectionType ordinals .thenBy { it.type } - // Finally, sort by name within each group - .thenComparing( - CollectionView::name, - SpecialCharWithPrecedenceComparator, - ), + // Finally, sort within each group. For default collections, use the + // organization's name; for others, use the collection's name. + .thenBy(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 }, ) } diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/util/VaultSdkCollectionExtensionsTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/util/VaultSdkCollectionExtensionsTest.kt index 639fd42bfc..8a0f029b06 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/util/VaultSdkCollectionExtensionsTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/util/VaultSdkCollectionExtensionsTest.kt @@ -4,6 +4,7 @@ import com.bitwarden.collections.Collection import com.bitwarden.collections.CollectionType import com.bitwarden.network.model.CollectionTypeJson import com.bitwarden.network.model.SyncResponseJson +import com.bitwarden.network.model.createMockOrganization import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView import org.junit.Test import org.junit.jupiter.api.Assertions.assertEquals @@ -103,7 +104,7 @@ class VaultSdkCollectionExtensionsTest { @Suppress("MaxLineLength") @Test - fun `toSortAlphabetically should sort collections by type and name`() { + fun `toSortAlphabeticallyByTypeAndOrganization should sort collections by type and name`() { val list = listOf( createMockCollectionView(1).copy(name = "c"), createMockCollectionView(1).copy(name = "B"), @@ -111,16 +112,28 @@ class VaultSdkCollectionExtensionsTest { createMockCollectionView(1).copy(name = "4"), createMockCollectionView(1).copy(name = "A"), createMockCollectionView(1).copy(name = "#"), - createMockCollectionView(1).copy( - name = "D", + createMockCollectionView(2).copy( + name = "Org2 items", 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( createMockCollectionView(1).copy( - name = "D", + name = "Org1 items", 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 = "4"), @@ -132,7 +145,12 @@ class VaultSdkCollectionExtensionsTest { assertEquals( expected, - list.sortAlphabeticallyByType(), + list.sortAlphabeticallyByTypeAndOrganization( + userOrganizations = listOf( + createMockOrganization(number = 1), + createMockOrganization(number = 2), + ), + ), ) }