From d799fa3b5af57f3c1bda77fcee8b1acfd532d733 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Nov 2025 17:16:07 +0100 Subject: [PATCH 01/11] Fix reported crash. https://github.com/element-hq/element-x-android-rageshakes/issues/8517 --- .../edit/EditDefaultNotificationSettingPresenter.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt index bb6cb823d2..3d2356cb94 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt @@ -138,7 +138,12 @@ class EditDefaultNotificationSettingPresenter( ) } // locale sensitive sorting - .sortedWith(compareBy(Collator.getInstance()) { roomSummary -> roomSummary.name }) + .sortedWith( + compareBy(Collator.getInstance()) { roomSummary -> + // Collator does not handle null values, so we provide a fallback + roomSummary.name ?: roomSummary.roomId.value + } + ) } private fun CoroutineScope.setDefaultNotificationMode(mode: RoomNotificationMode, action: MutableState>) = launch { From a50844c0e6c54cb6951b03e469a9e88ffe5696de Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Nov 2025 17:17:26 +0100 Subject: [PATCH 02/11] Avoid creating a new Collator and apply same decomposition across codebase. --- .../edit/EditDefaultNotificationSettingPresenter.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt index 3d2356cb94..e13d8422ef 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt @@ -49,6 +49,10 @@ class EditDefaultNotificationSettingPresenter( fun create(oneToOne: Boolean): EditDefaultNotificationSettingPresenter } + private val collator = Collator.getInstance().apply { + decomposition = Collator.CANONICAL_DECOMPOSITION + } + @Composable override fun present(): EditDefaultNotificationSettingState { var displayMentionsOnlyDisclaimer by remember { mutableStateOf(false) } @@ -139,7 +143,7 @@ class EditDefaultNotificationSettingPresenter( } // locale sensitive sorting .sortedWith( - compareBy(Collator.getInstance()) { roomSummary -> + compareBy(collator) { roomSummary -> // Collator does not handle null values, so we provide a fallback roomSummary.name ?: roomSummary.roomId.value } From b3969fdb8e6ab9b69bd12853994b2fb8b8f87b7e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Nov 2025 17:24:45 +0100 Subject: [PATCH 03/11] Remove class duplication. --- .../members/PowerLevelRoomMemberComparator.kt | 30 ------------------- .../impl/members/RoomMemberListPresenter.kt | 7 +++-- .../PowerLevelBaseRoomMemberComparatorTest.kt | 3 +- 3 files changed, 7 insertions(+), 33 deletions(-) delete mode 100644 features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/PowerLevelRoomMemberComparator.kt rename {features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members => libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room}/PowerLevelBaseRoomMemberComparatorTest.kt (96%) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/PowerLevelRoomMemberComparator.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/PowerLevelRoomMemberComparator.kt deleted file mode 100644 index a14a0205cc..0000000000 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/PowerLevelRoomMemberComparator.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2024, 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.features.roomdetails.impl.members - -import io.element.android.libraries.matrix.api.room.RoomMember -import io.element.android.libraries.matrix.ui.room.sortingName -import java.text.Collator - -// Comparator used to sort room members by power level (descending) and then by name (ascending) -internal class PowerLevelRoomMemberComparator : Comparator { - // Used to simplify and compare unicode and ASCII chars (รก == a) - private val collator = Collator.getInstance().apply { - decomposition = Collator.CANONICAL_DECOMPOSITION - } - override fun compare(o1: RoomMember, o2: RoomMember): Int { - return when { - o1.powerLevel > o2.powerLevel -> return -1 - o1.powerLevel < o2.powerLevel -> return 1 - else -> { - collator.compare(o1.sortingName(), o2.sortingName()) - } - } - } -} diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt index 92705b1775..aceb5ee095 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt @@ -33,6 +33,7 @@ import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.matrix.api.room.toMatrixUser +import io.element.android.libraries.matrix.ui.room.PowerLevelRoomMemberComparator import io.element.android.libraries.matrix.ui.room.canInviteAsState import io.element.android.libraries.matrix.ui.room.roomMemberIdentityStateChange import kotlinx.collections.immutable.ImmutableMap @@ -54,6 +55,8 @@ class RoomMemberListPresenter( ) : Presenter { var roomMembers: AsyncData by mutableStateOf(AsyncData.Loading()) + private val powerLevelRoomMemberComparator = PowerLevelRoomMemberComparator() + @Composable override fun present(): RoomMemberListState { var searchQuery by rememberSaveable { mutableStateOf("") } @@ -103,7 +106,7 @@ class RoomMemberListPresenter( .map { it.withIdentityState(roomMemberIdentityStates) } .toImmutableList(), joined = members.getOrDefault(RoomMembershipState.JOIN, emptyList()) - .sortedWith(PowerLevelRoomMemberComparator()) + .sortedWith(powerLevelRoomMemberComparator) .map { it.withIdentityState(roomMemberIdentityStates) } .toImmutableList(), banned = members.getOrDefault(RoomMembershipState.BAN, emptyList()) @@ -133,7 +136,7 @@ class RoomMemberListPresenter( .map { it.withIdentityState(roomMemberIdentityStates) } .toImmutableList(), joined = results.getOrDefault(RoomMembershipState.JOIN, emptyList()) - .sortedWith(PowerLevelRoomMemberComparator()) + .sortedWith(powerLevelRoomMemberComparator) .map { it.withIdentityState(roomMemberIdentityStates) } .toImmutableList(), banned = results.getOrDefault(RoomMembershipState.BAN, emptyList()) diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/PowerLevelBaseRoomMemberComparatorTest.kt b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/PowerLevelBaseRoomMemberComparatorTest.kt similarity index 96% rename from features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/PowerLevelBaseRoomMemberComparatorTest.kt rename to libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/PowerLevelBaseRoomMemberComparatorTest.kt index ce6a21b0e5..c0f345265f 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/members/PowerLevelBaseRoomMemberComparatorTest.kt +++ b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/PowerLevelBaseRoomMemberComparatorTest.kt @@ -6,7 +6,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.features.roomdetails.impl.members +package io.element.android.libraries.matrix.ui.room import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.test.A_USER_ID @@ -14,6 +14,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.A_USER_ID_3 import io.element.android.libraries.matrix.test.A_USER_ID_4 import io.element.android.libraries.matrix.test.A_USER_ID_5 +import io.element.android.libraries.matrix.test.room.aRoomMember import org.junit.Test class PowerLevelBaseRoomMemberComparatorTest { From 1dbf2319ff677360f67e05b6a8ee1750810c9008 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Nov 2025 17:37:15 +0100 Subject: [PATCH 04/11] Avoid creating many PowerLevelRoomMemberComparator instance and also avoid doing the sorting twice. --- .../impl/roles/ChangeRolesPresenter.kt | 14 +++-------- .../impl/roles/ChangeRolesState.kt | 23 ++++++++++++------- .../impl/roles/ChangeRolesStateProvider.kt | 14 ++++++++--- .../impl/roles/ChangeRolesView.kt | 2 +- .../impl/roles/MembersByRoleTest.kt | 5 ++-- 5 files changed, 33 insertions(+), 25 deletions(-) diff --git a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenter.kt b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenter.kt index 2b02cdfdb2..86012462ce 100644 --- a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenter.kt +++ b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenter.kt @@ -61,6 +61,8 @@ class ChangeRolesPresenter( fun create(role: RoomMember.Role): ChangeRolesPresenter } + private val powerLevelRoomMemberComparator = PowerLevelRoomMemberComparator() + @Composable override fun present(): ChangeRolesState { val dataSource = remember { RoomMemberListDataSource(room, dispatchers) } @@ -176,17 +178,7 @@ class ChangeRolesPresenter( } private fun List.groupedByRole(): MembersByRole { - val groupedMembers = MembersByRole(this) - return MembersByRole( - owners = groupedMembers.owners.sorted(), - admins = groupedMembers.admins.sorted(), - moderators = groupedMembers.moderators.sorted(), - members = groupedMembers.members.sorted(), - ) - } - - private fun Iterable.sorted(): ImmutableList { - return sortedWith(PowerLevelRoomMemberComparator()).toImmutableList() + return MembersByRole(this, powerLevelRoomMemberComparator) } private fun CoroutineScope.save( diff --git a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesState.kt b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesState.kt index 45ab913a31..6bcc13fb9a 100644 --- a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesState.kt +++ b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesState.kt @@ -13,8 +13,8 @@ import io.element.android.libraries.designsystem.theme.components.SearchBarResul import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.user.MatrixUser -import io.element.android.libraries.matrix.ui.room.PowerLevelRoomMemberComparator import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList data class ChangeRolesState( @@ -35,16 +35,23 @@ data class MembersByRole( val moderators: ImmutableList, val members: ImmutableList, ) { - constructor(members: List) : this( - owners = members.filter { it.role is RoomMember.Role.Owner }.sorted(), - admins = members.filter { it.role == RoomMember.Role.Admin }.sorted(), - moderators = members.filter { it.role == RoomMember.Role.Moderator }.sorted(), - members = members.filter { it.role == RoomMember.Role.User }.sorted(), + constructor() : this( + owners = persistentListOf(), + admins = persistentListOf(), + moderators = persistentListOf(), + members = persistentListOf(), + ) + + constructor(members: List, comparator: Comparator) : this( + owners = members.filter { it.role is RoomMember.Role.Owner }.sorted(comparator), + admins = members.filter { it.role == RoomMember.Role.Admin }.sorted(comparator), + moderators = members.filter { it.role == RoomMember.Role.Moderator }.sorted(comparator), + members = members.filter { it.role == RoomMember.Role.User }.sorted(comparator), ) fun isEmpty() = owners.isEmpty() && admins.isEmpty() && moderators.isEmpty() && members.isEmpty() } -private fun Iterable.sorted(): ImmutableList { - return sortedWith(PowerLevelRoomMemberComparator()).toImmutableList() +private fun Iterable.sorted(comparator: Comparator): ImmutableList { + return sortedWith(comparator).toImmutableList() } diff --git a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesStateProvider.kt b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesStateProvider.kt index 14662bacdd..df74b71ae1 100644 --- a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesStateProvider.kt +++ b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesStateProvider.kt @@ -17,6 +17,7 @@ import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUserList +import io.element.android.libraries.matrix.ui.room.PowerLevelRoomMemberComparator import io.element.android.libraries.previewutils.room.aRoomMember import io.element.android.libraries.previewutils.room.aRoomMemberList import kotlinx.collections.immutable.ImmutableList @@ -36,7 +37,12 @@ class ChangeRolesStateProvider : PreviewParameterProvider { aChangeRolesStateWithSelectedUsers().copy( query = "Alice", isSearchActive = true, - searchResults = SearchBarResultState.Results(MembersByRole(aRoomMemberList().take(1).toImmutableList())), + searchResults = SearchBarResultState.Results( + MembersByRole( + members = aRoomMemberList().take(1), + comparator = PowerLevelRoomMemberComparator(), + ) + ), selectedUsers = aMatrixUserList().take(1).toImmutableList(), ), aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.ConfirmingCancellation), @@ -87,7 +93,8 @@ internal fun aChangeRolesStateWithSelectedUsers() = aChangeRolesState( } else { roomMember } - } + }, + comparator = PowerLevelRoomMemberComparator(), ) ), hasPendingChanges = true, @@ -126,7 +133,8 @@ internal fun aChangeRolesStateWithOwners( displayName = "David", role = RoomMember.Role.User, ), - ) + ), + comparator = PowerLevelRoomMemberComparator(), ), ), canRemoveMember = { userId -> diff --git a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesView.kt b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesView.kt index 81b11aa837..3a981b66b6 100644 --- a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesView.kt +++ b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesView.kt @@ -145,7 +145,7 @@ fun ChangeRolesView( SearchResultsList( currentRole = state.role, lazyListState = lazyListState, - searchResults = (state.searchResults as? SearchBarResultState.Results)?.results ?: MembersByRole(emptyList()), + searchResults = (state.searchResults as? SearchBarResultState.Results)?.results ?: MembersByRole(), selectedUsers = state.selectedUsers, canRemoveMember = state.canChangeMemberRole, onToggleSelection = { state.eventSink(ChangeRolesEvent.UserSelectionToggled(it.toMatrixUser())) }, diff --git a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/MembersByRoleTest.kt b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/MembersByRoleTest.kt index 2e1d18a6ca..1de879abdc 100644 --- a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/MembersByRoleTest.kt +++ b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/MembersByRoleTest.kt @@ -18,6 +18,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID_5 import io.element.android.libraries.matrix.test.A_USER_ID_6 import io.element.android.libraries.matrix.test.A_USER_ID_7 import io.element.android.libraries.matrix.test.room.aRoomMember +import io.element.android.libraries.matrix.ui.room.PowerLevelRoomMemberComparator import kotlinx.collections.immutable.persistentListOf import org.junit.Test @@ -33,7 +34,7 @@ class MembersByRoleTest { aRoomMember(A_USER_ID_6, displayName = "Justin", role = RoomMember.Role.Owner(isCreator = true)), aRoomMember(A_USER_ID_7, displayName = "Mallory", role = RoomMember.Role.Owner(isCreator = false)), ) - val membersByRole = MembersByRole(members = members) + val membersByRole = MembersByRole(members = members, comparator = PowerLevelRoomMemberComparator()) assertThat(membersByRole.owners).containsExactly( aRoomMember(A_USER_ID_6, displayName = "Justin", role = RoomMember.Role.Owner(isCreator = true)), aRoomMember(A_USER_ID_7, displayName = "Mallory", role = RoomMember.Role.Owner(isCreator = false)), @@ -52,7 +53,7 @@ class MembersByRoleTest { @Test fun `isEmpty - only returns true with no members of any role`() { - val emptyMembersByRole = MembersByRole(emptyList()) + val emptyMembersByRole = MembersByRole() assertThat(emptyMembersByRole.isEmpty()).isTrue() val membersByRoleWithOwners = MembersByRole( From c1811bb727186cf01d45d2422550f8a5e4cf04e8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Nov 2025 17:37:32 +0100 Subject: [PATCH 05/11] `roomMembers` can be private --- .../roomdetails/impl/members/RoomMemberListPresenter.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt index aceb5ee095..e69ddb744a 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListPresenter.kt @@ -53,8 +53,7 @@ class RoomMemberListPresenter( private val roomMembersModerationPresenter: Presenter, private val encryptionService: EncryptionService, ) : Presenter { - var roomMembers: AsyncData by mutableStateOf(AsyncData.Loading()) - + private var roomMembers: AsyncData by mutableStateOf(AsyncData.Loading()) private val powerLevelRoomMemberComparator = PowerLevelRoomMemberComparator() @Composable From 8be1faf70f28b4eefd16aed4eb24c9c44b8d4978 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Nov 2025 17:40:52 +0100 Subject: [PATCH 06/11] Improve code again. --- .../impl/roles/ChangeRolesState.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesState.kt b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesState.kt index 6bcc13fb9a..57c0f76f7b 100644 --- a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesState.kt +++ b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesState.kt @@ -43,15 +43,18 @@ data class MembersByRole( ) constructor(members: List, comparator: Comparator) : this( - owners = members.filter { it.role is RoomMember.Role.Owner }.sorted(comparator), - admins = members.filter { it.role == RoomMember.Role.Admin }.sorted(comparator), - moderators = members.filter { it.role == RoomMember.Role.Moderator }.sorted(comparator), - members = members.filter { it.role == RoomMember.Role.User }.sorted(comparator), + owners = members.filterAndSort(comparator) { it.role is RoomMember.Role.Owner }, + admins = members.filterAndSort(comparator) { it.role == RoomMember.Role.Admin }, + moderators = members.filterAndSort(comparator) { it.role == RoomMember.Role.Moderator }, + members = members.filterAndSort(comparator) { it.role == RoomMember.Role.User }, ) fun isEmpty() = owners.isEmpty() && admins.isEmpty() && moderators.isEmpty() && members.isEmpty() } -private fun Iterable.sorted(comparator: Comparator): ImmutableList { - return sortedWith(comparator).toImmutableList() +private fun Iterable.filterAndSort( + comparator: Comparator, + predicate: (RoomMember) -> Boolean, +): ImmutableList { + return filter(predicate).sortedWith(comparator).toImmutableList() } From e91f03181f537a05eb613c6e617687c1ff905cee Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Nov 2025 22:25:50 +0100 Subject: [PATCH 07/11] Simplify again. --- .../impl/roles/ChangeRolesState.kt | 15 ++++----------- .../impl/roles/MembersByRoleTest.kt | 12 ------------ 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesState.kt b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesState.kt index 57c0f76f7b..71fef01fa7 100644 --- a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesState.kt +++ b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesState.kt @@ -30,18 +30,11 @@ data class ChangeRolesState( ) data class MembersByRole( - val owners: ImmutableList, - val admins: ImmutableList, - val moderators: ImmutableList, - val members: ImmutableList, + val owners: ImmutableList = persistentListOf(), + val admins: ImmutableList = persistentListOf(), + val moderators: ImmutableList = persistentListOf(), + val members: ImmutableList = persistentListOf(), ) { - constructor() : this( - owners = persistentListOf(), - admins = persistentListOf(), - moderators = persistentListOf(), - members = persistentListOf(), - ) - constructor(members: List, comparator: Comparator) : this( owners = members.filterAndSort(comparator) { it.role is RoomMember.Role.Owner }, admins = members.filterAndSort(comparator) { it.role == RoomMember.Role.Admin }, diff --git a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/MembersByRoleTest.kt b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/MembersByRoleTest.kt index 1de879abdc..66a06cddc3 100644 --- a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/MembersByRoleTest.kt +++ b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/MembersByRoleTest.kt @@ -58,32 +58,20 @@ class MembersByRoleTest { val membersByRoleWithOwners = MembersByRole( owners = persistentListOf(aRoomMember(A_USER_ID, role = RoomMember.Role.Admin)), - admins = persistentListOf(), - moderators = persistentListOf(), - members = persistentListOf(), ) assertThat(membersByRoleWithOwners.isEmpty()).isFalse() val membersByRoleWithAdmins = MembersByRole( - owners = persistentListOf(), admins = persistentListOf(aRoomMember(A_USER_ID, role = RoomMember.Role.Admin)), - moderators = persistentListOf(), - members = persistentListOf(), ) assertThat(membersByRoleWithAdmins.isEmpty()).isFalse() val membersByRoleWithModerators = MembersByRole( - owners = persistentListOf(), - admins = persistentListOf(), moderators = persistentListOf(aRoomMember(A_USER_ID, role = RoomMember.Role.Moderator)), - members = persistentListOf(), ) assertThat(membersByRoleWithModerators.isEmpty()).isFalse() val membersByRoleWithMembers = MembersByRole( - owners = persistentListOf(), - admins = persistentListOf(), - moderators = persistentListOf(), members = persistentListOf(aRoomMember(A_USER_ID, role = RoomMember.Role.User)), ) assertThat(membersByRoleWithMembers.isEmpty()).isFalse() From dc53a03469b52c6bf9b8aae1e96de2cac5c12274 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 19 Nov 2025 08:03:34 +0100 Subject: [PATCH 08/11] Rename test class --- ...rComparatorTest.kt => PowerLevelRoomMemberComparatorTest.kt} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/{PowerLevelBaseRoomMemberComparatorTest.kt => PowerLevelRoomMemberComparatorTest.kt} (98%) diff --git a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/PowerLevelBaseRoomMemberComparatorTest.kt b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/PowerLevelRoomMemberComparatorTest.kt similarity index 98% rename from libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/PowerLevelBaseRoomMemberComparatorTest.kt rename to libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/PowerLevelRoomMemberComparatorTest.kt index c0f345265f..d8240715b7 100644 --- a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/PowerLevelBaseRoomMemberComparatorTest.kt +++ b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/room/PowerLevelRoomMemberComparatorTest.kt @@ -17,7 +17,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID_5 import io.element.android.libraries.matrix.test.room.aRoomMember import org.junit.Test -class PowerLevelBaseRoomMemberComparatorTest { +class PowerLevelRoomMemberComparatorTest { @Test fun `order is Admin, then Moderator, then User`() { val memberList = listOf( From a64fe57ec6d60aa14f6987efc74c6db5e5bc4d95 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 19 Nov 2025 08:12:05 +0100 Subject: [PATCH 09/11] Use test extension --- ...efaultNotificationSettingsPresenterTest.kt | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt index e7d352b453..1624963867 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt @@ -8,9 +8,6 @@ package io.element.android.features.preferences.impl.notifications -import app.cash.molecule.RecompositionMode -import app.cash.molecule.moleculeFlow -import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingPresenter import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingStateEvents @@ -21,6 +18,7 @@ import io.element.android.libraries.matrix.test.room.aRoomSummary import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.tests.testutils.awaitLastSequentialItem import io.element.android.tests.testutils.consumeItemsUntilPredicate +import io.element.android.tests.testutils.test import kotlinx.coroutines.test.runTest import org.junit.Test @@ -29,9 +27,7 @@ class EditDefaultNotificationSettingsPresenterTest { fun `present - ensures initial state is correct`() = runTest { val notificationSettingsService = FakeNotificationSettingsService() val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() assertThat(initialState.mode).isNull() assertThat(initialState.isOneToOne).isFalse() @@ -53,9 +49,7 @@ class EditDefaultNotificationSettingsPresenterTest { ) val roomListService = FakeRoomListService() val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { roomListService.postAllRooms(listOf(aRoomSummary(userDefinedNotificationMode = RoomNotificationMode.ALL_MESSAGES))) val loadedState = consumeItemsUntilPredicate { state -> state.roomsWithUserDefinedMode.any { it.notificationMode == RoomNotificationMode.ALL_MESSAGES } @@ -67,9 +61,7 @@ class EditDefaultNotificationSettingsPresenterTest { @Test fun `present - edit default notification setting`() = runTest { val presenter = createEditDefaultNotificationSettingPresenter() - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { awaitItem().eventSink(EditDefaultNotificationSettingStateEvents.SetNotificationMode(RoomNotificationMode.ALL_MESSAGES)) val loadedState = consumeItemsUntilPredicate { it.mode == RoomNotificationMode.ALL_MESSAGES @@ -83,9 +75,7 @@ class EditDefaultNotificationSettingsPresenterTest { val notificationSettingsService = FakeNotificationSettingsService() val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService) notificationSettingsService.givenSetDefaultNotificationModeError(AN_EXCEPTION) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { awaitItem().eventSink(EditDefaultNotificationSettingStateEvents.SetNotificationMode(RoomNotificationMode.ALL_MESSAGES)) val errorState = consumeItemsUntilPredicate { it.changeNotificationSettingAction.isFailure() @@ -105,9 +95,7 @@ class EditDefaultNotificationSettingsPresenterTest { givenCanHomeServerPushEncryptedEventsToDeviceResult(Result.success(false)) } val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { assertThat(awaitLastSequentialItem().displayMentionsOnlyDisclaimer).isTrue() } } From 88f0111137cb79c04d3661e4928e77264fc30c7f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 19 Nov 2025 09:59:22 +0100 Subject: [PATCH 10/11] Ensure in test that rooms are sorted. --- ...efaultNotificationSettingsPresenterTest.kt | 88 +++++++++++++++++-- .../FakeNotificationSettingsService.kt | 4 +- 2 files changed, 85 insertions(+), 7 deletions(-) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt index 1624963867..512232bcd0 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt @@ -13,6 +13,8 @@ import io.element.android.features.preferences.impl.notifications.edit.EditDefau import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingStateEvents import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.test.AN_EXCEPTION +import io.element.android.libraries.matrix.test.A_ROOM_ID +import io.element.android.libraries.matrix.test.A_ROOM_ID_2 import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService import io.element.android.libraries.matrix.test.room.aRoomSummary import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService @@ -25,12 +27,15 @@ import org.junit.Test class EditDefaultNotificationSettingsPresenterTest { @Test fun `present - ensures initial state is correct`() = runTest { - val notificationSettingsService = FakeNotificationSettingsService() + val notificationSettingsService = FakeNotificationSettingsService( + getRoomsWithUserDefinedRulesResult = { Result.success(emptyList()) }, + ) val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService) presenter.test { val initialState = awaitItem() assertThat(initialState.mode).isNull() assertThat(initialState.isOneToOne).isFalse() + assertThat(initialState.roomsWithUserDefinedMode).isEmpty() val loadedState = consumeItemsUntilPredicate { it.mode == RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY @@ -45,7 +50,8 @@ class EditDefaultNotificationSettingsPresenterTest { fun `present - ensure list of rooms with user defined mode`() = runTest { val notificationSettingsService = FakeNotificationSettingsService( initialRoomMode = RoomNotificationMode.ALL_MESSAGES, - initialRoomModeIsDefault = false + initialRoomModeIsDefault = false, + getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID.value)) }, ) val roomListService = FakeRoomListService() val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService) @@ -58,9 +64,77 @@ class EditDefaultNotificationSettingsPresenterTest { } } + @Test + fun `present - ensure list of rooms is sorted`() = runTest { + val notificationSettingsService = FakeNotificationSettingsService( + initialRoomMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, + initialRoomModeIsDefault = false, + getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID.value, A_ROOM_ID_2.value)) }, + ) + val roomListService = FakeRoomListService() + val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService) + presenter.test { + roomListService.postAllRooms( + listOf( + aRoomSummary( + roomId = A_ROOM_ID, + name = "Z", + userDefinedNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, + ), + aRoomSummary( + roomId = A_ROOM_ID_2, + name = "A", + userDefinedNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, + ), + ), + ) + val loadedState = consumeItemsUntilPredicate { state -> + state.roomsWithUserDefinedMode.any { it.notificationMode == RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY } + }.last() + assertThat(loadedState.roomsWithUserDefinedMode[0].name).isEqualTo("A") + assertThat(loadedState.roomsWithUserDefinedMode[1].name).isEqualTo("Z") + } + } + + @Test + fun `present - ensure list of rooms is sorted, with name null`() = runTest { + val notificationSettingsService = FakeNotificationSettingsService( + initialRoomMode = RoomNotificationMode.MUTE, + initialRoomModeIsDefault = false, + getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID.value, A_ROOM_ID_2.value)) }, + ) + val roomListService = FakeRoomListService() + val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService) + presenter.test { + roomListService.postAllRooms( + listOf( + aRoomSummary( + roomId = A_ROOM_ID, + name = "Z", + userDefinedNotificationMode = RoomNotificationMode.MUTE, + ), + aRoomSummary( + roomId = A_ROOM_ID_2, + name = null, + userDefinedNotificationMode = RoomNotificationMode.MUTE, + ), + ), + ) + val loadedState = consumeItemsUntilPredicate { state -> + state.roomsWithUserDefinedMode.any { it.notificationMode == RoomNotificationMode.MUTE } + }.last() + assertThat(loadedState.roomsWithUserDefinedMode[0].name).isNull() + assertThat(loadedState.roomsWithUserDefinedMode[1].name).isEqualTo("Z") + } + } + @Test fun `present - edit default notification setting`() = runTest { - val presenter = createEditDefaultNotificationSettingPresenter() + val presenter = createEditDefaultNotificationSettingPresenter( + notificationSettingsService = FakeNotificationSettingsService( + getRoomsWithUserDefinedRulesResult = { Result.success(emptyList()) }, + ), + ) presenter.test { awaitItem().eventSink(EditDefaultNotificationSettingStateEvents.SetNotificationMode(RoomNotificationMode.ALL_MESSAGES)) val loadedState = consumeItemsUntilPredicate { @@ -72,7 +146,9 @@ class EditDefaultNotificationSettingsPresenterTest { @Test fun `present - edit default notification setting failed`() = runTest { - val notificationSettingsService = FakeNotificationSettingsService() + val notificationSettingsService = FakeNotificationSettingsService( + getRoomsWithUserDefinedRulesResult = { Result.success(emptyList()) }, + ) val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService) notificationSettingsService.givenSetDefaultNotificationModeError(AN_EXCEPTION) presenter.test { @@ -91,7 +167,9 @@ class EditDefaultNotificationSettingsPresenterTest { @Test fun `present - display mentions only warning if homeserver does not support it`() = runTest { - val notificationSettingsService = FakeNotificationSettingsService().apply { + val notificationSettingsService = FakeNotificationSettingsService( + getRoomsWithUserDefinedRulesResult = { Result.success(emptyList()) }, + ).apply { givenCanHomeServerPushEncryptedEventsToDeviceResult(Result.success(false)) } val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notificationsettings/FakeNotificationSettingsService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notificationsettings/FakeNotificationSettingsService.kt index 1d60ecd4dc..998daeba14 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notificationsettings/FakeNotificationSettingsService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notificationsettings/FakeNotificationSettingsService.kt @@ -12,7 +12,6 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationSettings -import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_NOTIFICATION_MODE import io.element.android.tests.testutils.lambda.lambdaError import kotlinx.coroutines.flow.MutableStateFlow @@ -26,6 +25,7 @@ class FakeNotificationSettingsService( initialOneToOneDefaultMode: RoomNotificationMode = RoomNotificationMode.ALL_MESSAGES, initialEncryptedOneToOneDefaultMode: RoomNotificationMode = RoomNotificationMode.ALL_MESSAGES, private val getRawPushRulesResult: () -> Result = { lambdaError() }, + private val getRoomsWithUserDefinedRulesResult: () -> Result> = { lambdaError() }, ) : NotificationSettingsService { private val notificationSettingsStateFlow = MutableStateFlow(Unit) private var defaultGroupRoomNotificationMode: RoomNotificationMode = initialGroupDefaultMode @@ -155,7 +155,7 @@ class FakeNotificationSettingsService( } override suspend fun getRoomsWithUserDefinedRules(): Result> { - return Result.success(if (roomNotificationModeIsDefault) listOf() else listOf(A_ROOM_ID.value)) + return getRoomsWithUserDefinedRulesResult() } override suspend fun canHomeServerPushEncryptedEventsToDevice(): Result { From d8cacba43a912e8a8f0b6b3939ee5712bc0297fa Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 19 Nov 2025 10:07:34 +0100 Subject: [PATCH 11/11] Improve API: use RoomId instead of String. --- .../edit/EditDefaultNotificationSettingPresenter.kt | 5 +++-- .../EditDefaultNotificationSettingsPresenterTest.kt | 6 +++--- .../api/notificationsettings/NotificationSettingsService.kt | 2 +- .../notificationsettings/RustNotificationSettingsService.kt | 4 ++-- .../notificationsettings/FakeNotificationSettingsService.kt | 4 ++-- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt index e13d8422ef..df5247188a 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt @@ -23,6 +23,7 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runUpdatingStateNoSuccess import io.element.android.libraries.designsystem.components.avatar.AvatarSize +import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.roomlist.RoomListService @@ -125,10 +126,10 @@ class EditDefaultNotificationSettingPresenter( summaries: List, roomsWithUserDefinedMode: MutableState> ) { - val roomWithUserDefinedRules: Set = notificationSettingsService.getRoomsWithUserDefinedRules().getOrDefault(emptyList()).toSet() + val roomWithUserDefinedRules: Set = notificationSettingsService.getRoomsWithUserDefinedRules().getOrDefault(emptyList()).toSet() roomsWithUserDefinedMode.value = summaries .filter { roomSummary -> - roomWithUserDefinedRules.contains(roomSummary.roomId.value) && roomSummary.isOneToOne == isOneToOne + roomWithUserDefinedRules.contains(roomSummary.roomId) && roomSummary.isOneToOne == isOneToOne } .map { roomSummary -> EditNotificationSettingRoomInfo( diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt index 512232bcd0..153c265560 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt @@ -51,7 +51,7 @@ class EditDefaultNotificationSettingsPresenterTest { val notificationSettingsService = FakeNotificationSettingsService( initialRoomMode = RoomNotificationMode.ALL_MESSAGES, initialRoomModeIsDefault = false, - getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID.value)) }, + getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID)) }, ) val roomListService = FakeRoomListService() val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService) @@ -69,7 +69,7 @@ class EditDefaultNotificationSettingsPresenterTest { val notificationSettingsService = FakeNotificationSettingsService( initialRoomMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, initialRoomModeIsDefault = false, - getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID.value, A_ROOM_ID_2.value)) }, + getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID, A_ROOM_ID_2)) }, ) val roomListService = FakeRoomListService() val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService) @@ -101,7 +101,7 @@ class EditDefaultNotificationSettingsPresenterTest { val notificationSettingsService = FakeNotificationSettingsService( initialRoomMode = RoomNotificationMode.MUTE, initialRoomModeIsDefault = false, - getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID.value, A_ROOM_ID_2.value)) }, + getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID, A_ROOM_ID_2)) }, ) val roomListService = FakeRoomListService() val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notificationsettings/NotificationSettingsService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notificationsettings/NotificationSettingsService.kt index 213daa4a6b..4d8ce8afb4 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notificationsettings/NotificationSettingsService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notificationsettings/NotificationSettingsService.kt @@ -32,7 +32,7 @@ interface NotificationSettingsService { suspend fun setCallEnabled(enabled: Boolean): Result suspend fun isInviteForMeEnabled(): Result suspend fun setInviteForMeEnabled(enabled: Boolean): Result - suspend fun getRoomsWithUserDefinedRules(): Result> + suspend fun getRoomsWithUserDefinedRules(): Result> suspend fun canHomeServerPushEncryptedEventsToDevice(): Result suspend fun getRawPushRules(): Result } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt index 95b8a31cfa..7da0f14d14 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt @@ -131,9 +131,9 @@ class RustNotificationSettingsService( } } - override suspend fun getRoomsWithUserDefinedRules(): Result> = + override suspend fun getRoomsWithUserDefinedRules(): Result> = runCatchingExceptions { - notificationSettings.await().getRoomsWithUserDefinedRules(enabled = true) + notificationSettings.await().getRoomsWithUserDefinedRules(enabled = true).map(::RoomId) } override suspend fun canHomeServerPushEncryptedEventsToDevice(): Result = diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notificationsettings/FakeNotificationSettingsService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notificationsettings/FakeNotificationSettingsService.kt index 998daeba14..564cd231b2 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notificationsettings/FakeNotificationSettingsService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notificationsettings/FakeNotificationSettingsService.kt @@ -25,7 +25,7 @@ class FakeNotificationSettingsService( initialOneToOneDefaultMode: RoomNotificationMode = RoomNotificationMode.ALL_MESSAGES, initialEncryptedOneToOneDefaultMode: RoomNotificationMode = RoomNotificationMode.ALL_MESSAGES, private val getRawPushRulesResult: () -> Result = { lambdaError() }, - private val getRoomsWithUserDefinedRulesResult: () -> Result> = { lambdaError() }, + private val getRoomsWithUserDefinedRulesResult: () -> Result> = { lambdaError() }, ) : NotificationSettingsService { private val notificationSettingsStateFlow = MutableStateFlow(Unit) private var defaultGroupRoomNotificationMode: RoomNotificationMode = initialGroupDefaultMode @@ -154,7 +154,7 @@ class FakeNotificationSettingsService( return Result.success(Unit) } - override suspend fun getRoomsWithUserDefinedRules(): Result> { + override suspend fun getRoomsWithUserDefinedRules(): Result> { return getRoomsWithUserDefinedRulesResult() }