From 37c5ba4b94fc1c6804da92aab1925181e4924a35 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Nov 2025 16:22:56 +0100 Subject: [PATCH 01/11] item can be reordered, so hasPendingChanges should compare set and not list. --- .../rolesandpermissions/impl/roles/ChangeRolesPresenter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 86012462ce..d92ecaf0a1 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 @@ -104,7 +104,7 @@ class ChangeRolesPresenter( } } - val hasPendingChanges = usersWithRole.value != selectedUsers.value + val hasPendingChanges = usersWithRole.value.toSet() != selectedUsers.value.toSet() val roomInfo by room.roomInfoFlow.collectAsState() fun canChangeMemberRole(userId: UserId): Boolean { From 0110cf018a3433f812816fd5ab9f85578d3845a2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Nov 2025 16:23:41 +0100 Subject: [PATCH 02/11] Comparing mutable state was wrong --- .../rolesandpermissions/impl/roles/ChangeRolesPresenter.kt | 3 +-- 1 file changed, 1 insertion(+), 2 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 d92ecaf0a1..6030279b98 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 @@ -134,11 +134,10 @@ class ChangeRolesPresenter( is ChangeRolesEvent.Save -> { val currentUserIsAdmin = roomInfo.roleOf(room.sessionId) == RoomMember.Role.Admin val isModifyingAdmins = role == RoomMember.Role.Admin - val hasChanges = selectedUsers != usersWithRole val isConfirming = saveState.value.isConfirming() val modifyingOwners = role is RoomMember.Role.Owner - val needsConfirmation = (modifyingOwners || currentUserIsAdmin && isModifyingAdmins) && hasChanges && !isConfirming + val needsConfirmation = (modifyingOwners || currentUserIsAdmin && isModifyingAdmins) && hasPendingChanges && !isConfirming when { needsConfirmation -> { From 57708bd4621b94e4cc3cedd87cfde39176c315be Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Nov 2025 16:56:01 +0100 Subject: [PATCH 03/11] Improve code around confirmation. --- .../impl/roles/ChangeRolesPresenter.kt | 17 +++++--- .../impl/roles/ChangeRolesView.kt | 40 ++++++++----------- .../impl/roles/ConfirmingModifyingAdmins.kt | 12 ++++++ .../impl/roles/ConfirmingModifyingOwners.kt | 12 ++++++ .../impl/roles/ChangeRolesPresenterTest.kt | 4 +- 5 files changed, 54 insertions(+), 31 deletions(-) create mode 100644 features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ConfirmingModifyingAdmins.kt create mode 100644 features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ConfirmingModifyingOwners.kt 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 6030279b98..781a909f4f 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 @@ -136,13 +136,18 @@ class ChangeRolesPresenter( val isModifyingAdmins = role == RoomMember.Role.Admin val isConfirming = saveState.value.isConfirming() val modifyingOwners = role is RoomMember.Role.Owner - - val needsConfirmation = (modifyingOwners || currentUserIsAdmin && isModifyingAdmins) && hasPendingChanges && !isConfirming - + val confirmationValue = if (hasPendingChanges && !isConfirming) { + when { + modifyingOwners -> ConfirmingModifyingOwners + currentUserIsAdmin && isModifyingAdmins -> ConfirmingModifyingAdmins + else -> null + } + } else { + null + } when { - needsConfirmation -> { - // Confirm modifying users - saveState.value = AsyncAction.ConfirmingNoParams + confirmationValue != null -> { + saveState.value = confirmationValue } !saveState.value.isLoading() -> { roomCoroutineScope.save(usersWithRole.value, selectedUsers, saveState) 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 3a981b66b6..76cb334037 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 @@ -178,29 +178,23 @@ fun ChangeRolesView( onDismiss = { state.eventSink(ChangeRolesEvent.CloseDialog) } ) } - else -> { - when (state.role) { - is RoomMember.Role.Owner -> { - ConfirmationDialog( - title = stringResource(R.string.screen_room_change_role_confirm_change_owners_title), - content = stringResource(R.string.screen_room_change_role_confirm_change_owners_description), - submitText = stringResource(CommonStrings.action_continue), - onSubmitClick = { state.eventSink(ChangeRolesEvent.Save) }, - onDismiss = { state.eventSink(ChangeRolesEvent.CloseDialog) }, - destructiveSubmit = true, - ) - } - is RoomMember.Role.Admin -> { - ConfirmationDialog( - title = stringResource(R.string.screen_room_change_role_confirm_add_admin_title), - content = stringResource(R.string.screen_room_change_role_confirm_add_admin_description), - onSubmitClick = { state.eventSink(ChangeRolesEvent.Save) }, - onDismiss = { state.eventSink(ChangeRolesEvent.CloseDialog) } - ) - } - // No confirmation needed for Moderator or User roles - else -> Unit - } + is ConfirmingModifyingOwners -> { + ConfirmationDialog( + title = stringResource(R.string.screen_room_change_role_confirm_change_owners_title), + content = stringResource(R.string.screen_room_change_role_confirm_change_owners_description), + submitText = stringResource(CommonStrings.action_continue), + onSubmitClick = { state.eventSink(ChangeRolesEvent.Save) }, + onDismiss = { state.eventSink(ChangeRolesEvent.CloseDialog) }, + destructiveSubmit = true, + ) + } + is ConfirmingModifyingAdmins -> { + ConfirmationDialog( + title = stringResource(R.string.screen_room_change_role_confirm_add_admin_title), + content = stringResource(R.string.screen_room_change_role_confirm_add_admin_description), + onSubmitClick = { state.eventSink(ChangeRolesEvent.Save) }, + onDismiss = { state.eventSink(ChangeRolesEvent.CloseDialog) } + ) } } }, diff --git a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ConfirmingModifyingAdmins.kt b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ConfirmingModifyingAdmins.kt new file mode 100644 index 0000000000..10d46abbc3 --- /dev/null +++ b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ConfirmingModifyingAdmins.kt @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025 Element Creations 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.rolesandpermissions.impl.roles + +import io.element.android.libraries.architecture.AsyncAction + +data object ConfirmingModifyingAdmins : AsyncAction.Confirming diff --git a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ConfirmingModifyingOwners.kt b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ConfirmingModifyingOwners.kt new file mode 100644 index 0000000000..9799f68408 --- /dev/null +++ b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ConfirmingModifyingOwners.kt @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025 Element Creations 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.rolesandpermissions.impl.roles + +import io.element.android.libraries.architecture.AsyncAction + +data object ConfirmingModifyingOwners : AsyncAction.Confirming diff --git a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenterTest.kt b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenterTest.kt index c5e28a5078..9b7a8971c3 100644 --- a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenterTest.kt +++ b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenterTest.kt @@ -358,7 +358,7 @@ class ChangeRolesPresenterTest { initialState.eventSink(ChangeRolesEvent.UserSelectionToggled(MatrixUser(A_USER_ID_2))) awaitItem().eventSink(ChangeRolesEvent.Save) val confirmingState = awaitItem() - assertThat(confirmingState.savingState).isEqualTo(AsyncAction.ConfirmingNoParams) + assertThat(confirmingState.savingState).isEqualTo(ConfirmingModifyingAdmins) confirmingState.eventSink(ChangeRolesEvent.Save) assertThat(awaitItem().savingState).isInstanceOf(AsyncAction.Loading::class.java) assertThat(awaitItem().savingState).isEqualTo(AsyncAction.Success(true)) @@ -383,7 +383,7 @@ class ChangeRolesPresenterTest { awaitItem().eventSink(ChangeRolesEvent.Save) val confirmingState = awaitItem() - assertThat(confirmingState.savingState).isEqualTo(AsyncAction.ConfirmingNoParams) + assertThat(confirmingState.savingState).isEqualTo(ConfirmingModifyingAdmins) confirmingState.eventSink(ChangeRolesEvent.CloseDialog) assertThat(awaitItem().savingState).isEqualTo(AsyncAction.Uninitialized) From 423154e1538387de1f7a756c5f1cea2dcfdf573e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Nov 2025 17:23:21 +0100 Subject: [PATCH 04/11] Render room version in room detail screen if developer mode is enabled. --- .../roomdetails/impl/RoomDetailsPresenter.kt | 1 + .../roomdetails/impl/RoomDetailsState.kt | 1 + .../impl/RoomDetailsStateProvider.kt | 1 + .../roomdetails/impl/RoomDetailsView.kt | 19 ++++++++++++++++++- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt index ec805731ec..232f4d626c 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt @@ -205,6 +205,7 @@ class RoomDetailsPresenter( canReportRoom = canReportRoom, isTombstoned = roomInfo.successorRoom != null, showDebugInfo = isDeveloperModeEnabled, + roomVersion = roomInfo.roomVersion, eventSink = ::handleEvent, ) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt index 6e8d563d4a..2332776e96 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsState.kt @@ -49,6 +49,7 @@ data class RoomDetailsState( val canReportRoom: Boolean, val isTombstoned: Boolean, val showDebugInfo: Boolean, + val roomVersion: String?, val eventSink: (RoomDetailsEvent) -> Unit ) { val roomBadges = buildList { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt index cbb54071a1..783fcfaf10 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt @@ -146,6 +146,7 @@ fun aRoomDetailsState( canReportRoom = canReportRoom, isTombstoned = isTombstoned, showDebugInfo = showDebugInfo, + roomVersion = "12", eventSink = eventSink, ) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt index fe4a002af8..de0a2cba1b 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt @@ -264,6 +264,7 @@ fun RoomDetailsView( if (state.showDebugInfo) { DebugInfoSection( roomId = state.roomId, + roomVersion = state.roomVersion, ) } } @@ -714,7 +715,10 @@ private fun OtherActionsSection( } @Composable -private fun DebugInfoSection(roomId: RoomId) { +private fun DebugInfoSection( + roomId: RoomId, + roomVersion: String?, +) { val context = LocalContext.current PreferenceCategory(showTopDivider = true) { ListItem( @@ -737,6 +741,19 @@ private fun DebugInfoSection(roomId: RoomId) { ) }, ) + ListItem( + headlineContent = { + Text("Room version") + }, + supportingContent = { + Text( + text = roomVersion ?: "Unknown", + style = ElementTheme.typography.fontBodySmRegular, + color = ElementTheme.colors.textSecondary, + ) + }, + leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Info())), + ) } } From 966eab8796bc4d56f342e2fcaaca99224f6f1b75 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Nov 2025 17:29:01 +0100 Subject: [PATCH 05/11] Fix roleOf extension. Creator are Owner Role only if privilegedCreatorRole is true. --- .../matrix/test/room/RoomInfoFixture.kt | 2 +- .../matrix/ui/model/RoomInfoExtension.kt | 4 +- .../matrix/ui/model/RoomInfoExtensionTest.kt | 79 +++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtensionTest.kt diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomInfoFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomInfoFixture.kt index abb24fc153..71ed8b83be 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomInfoFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomInfoFixture.kt @@ -53,7 +53,7 @@ fun aRoomInfo( notificationCount: Long = 0, userDefinedNotificationMode: RoomNotificationMode? = null, hasRoomCall: Boolean = false, - roomPowerLevels: RoomPowerLevels = RoomPowerLevels( + roomPowerLevels: RoomPowerLevels? = RoomPowerLevels( values = defaultRoomPowerLevelValues(), users = persistentMapOf(), ), diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtension.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtension.kt index 52e7d43085..f9a86c9bd7 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtension.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtension.kt @@ -23,12 +23,12 @@ fun RoomInfo.getAvatarData(size: AvatarSize) = AvatarData( /** * Returns the role of the user in the room. - * If the user is a creator, returns [RoomMember.Role.Owner]. + * If the user is a creator and [RoomInfo.privilegedCreatorRole] is true, returns [RoomMember.Role.Owner]. * Otherwise, checks the power levels and returns the corresponding role. * If no specific power level is set for the user, defaults to [RoomMember.Role.User]. */ fun RoomInfo.roleOf(userId: UserId): RoomMember.Role { - return if (creators.contains(userId)) { + return if (privilegedCreatorRole && creators.contains(userId)) { RoomMember.Role.Owner(isCreator = true) } else { roomPowerLevels?.roleOf(userId) ?: RoomMember.Role.User diff --git a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtensionTest.kt b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtensionTest.kt new file mode 100644 index 0000000000..c6dcc27bba --- /dev/null +++ b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/model/RoomInfoExtensionTest.kt @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 Element Creations 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.libraries.matrix.ui.model + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.api.room.RoomMember +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels +import io.element.android.libraries.matrix.test.A_USER_ID +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.room.aRoomInfo +import io.element.android.libraries.matrix.test.room.defaultRoomPowerLevelValues +import kotlinx.collections.immutable.toImmutableMap +import org.junit.Test + +class RoomInfoExtensionTest { + @Test + fun `roleOf returns Owner for creator with privilegedCreatorRole true`() { + val roomInfo = aRoomInfo( + privilegedCreatorRole = true, + roomCreators = listOf(A_USER_ID), + ) + assertThat(roomInfo.roleOf(A_USER_ID)).isEqualTo(RoomMember.Role.Owner(isCreator = true)) + } + + @Test + fun `roleOf returns User for not creator with privilegedCreatorRole true`() { + val roomInfo = aRoomInfo( + privilegedCreatorRole = true, + roomCreators = listOf(A_USER_ID), + ) + assertThat(roomInfo.roleOf(A_USER_ID_2)).isEqualTo(RoomMember.Role.User) + } + + @Test + fun `roleOf returns User for creator with privilegedCreatorRole false`() { + val roomInfo = aRoomInfo( + privilegedCreatorRole = false, + roomCreators = listOf(A_USER_ID), + ) + assertThat(roomInfo.roleOf(A_USER_ID)).isEqualTo(RoomMember.Role.User) + } + + @Test + fun `roleOf returns role from the power level`() { + val roomInfo = aRoomInfo( + privilegedCreatorRole = false, + roomPowerLevels = RoomPowerLevels( + values = defaultRoomPowerLevelValues(), + users = mapOf( + A_USER_ID to 100L, // Admin + A_USER_ID_2 to 50L, // Moderator + A_USER_ID_3 to 0L, // User + ).toImmutableMap(), + ), + roomCreators = listOf(A_USER_ID), + ) + assertThat(roomInfo.roleOf(A_USER_ID)).isEqualTo(RoomMember.Role.Admin) + assertThat(roomInfo.roleOf(A_USER_ID_2)).isEqualTo(RoomMember.Role.Moderator) + assertThat(roomInfo.roleOf(A_USER_ID_3)).isEqualTo(RoomMember.Role.User) + } + + @Test + fun `roleOf returns User when the power level is null`() { + val roomInfo = aRoomInfo( + privilegedCreatorRole = false, + roomPowerLevels = null, + roomCreators = listOf(A_USER_ID), + ) + assertThat(roomInfo.roleOf(A_USER_ID)).isEqualTo(RoomMember.Role.User) + assertThat(roomInfo.roleOf(A_USER_ID_2)).isEqualTo(RoomMember.Role.User) + assertThat(roomInfo.roleOf(A_USER_ID_3)).isEqualTo(RoomMember.Role.User) + } +} From f66f61fc3918d826f31563cbbc736af05cf800f0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Nov 2025 18:06:55 +0100 Subject: [PATCH 06/11] Fix and add missing preview. --- .../impl/roles/ChangeRolesStateProvider.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 df74b71ae1..2594681850 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 @@ -46,7 +46,7 @@ class ChangeRolesStateProvider : PreviewParameterProvider { selectedUsers = aMatrixUserList().take(1).toImmutableList(), ), aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.ConfirmingCancellation), - aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.ConfirmingNoParams), + aChangeRolesStateWithSelectedUsers().copy(savingState = ConfirmingModifyingAdmins), aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.Loading), aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.Success(true)), aChangeRolesStateWithSelectedUsers().copy(savingState = AsyncAction.Failure(Exception("boom"))), @@ -58,6 +58,8 @@ class ChangeRolesStateProvider : PreviewParameterProvider { ) ), aChangeRolesStateWithOwners(role = RoomMember.Role.Owner(isCreator = false)), + aChangeRolesStateWithOwners(role = RoomMember.Role.Owner(isCreator = false)) + .copy(savingState = ConfirmingModifyingOwners), ) } From 74b658eea96d259332a909b93ada1b111f2e8f4a Mon Sep 17 00:00:00 2001 From: ElementBot Date: Fri, 21 Nov 2025 08:35:49 +0000 Subject: [PATCH 07/11] Update screenshots --- ...olesandpermissions.impl.roles_ChangeRolesView_Day_13_en.png | 3 +++ ...esandpermissions.impl.roles_ChangeRolesView_Night_13_en.png | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_13_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_en.png new file mode 100644 index 0000000000..5ae55a94d8 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Day_13_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fbee2417fcd701fce6d3f4d20e677681de6d529e5a17f0bfffc1c1592d73398a +size 58939 diff --git a/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_13_en.png b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_13_en.png new file mode 100644 index 0000000000..8fb608a939 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.rolesandpermissions.impl.roles_ChangeRolesView_Night_13_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:41698290446bc0f2e58fac106cdef381c1b46f3655ff51fff574ff867cd70d10 +size 57006 From ab3d7ab75ceafb61bd910cfb6a8d52a58b2d9150 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 21 Nov 2025 09:33:41 +0100 Subject: [PATCH 08/11] Avoid computing the boolean on each recomposition. --- .../rolesandpermissions/impl/roles/ChangeRolesPresenter.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 781a909f4f..fdb17d6e04 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 @@ -12,6 +12,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState @@ -104,7 +105,11 @@ class ChangeRolesPresenter( } } - val hasPendingChanges = usersWithRole.value.toSet() != selectedUsers.value.toSet() + val hasPendingChanges by remember { + derivedStateOf { + usersWithRole.value.toSet() != selectedUsers.value.toSet() + } + } val roomInfo by room.roomInfoFlow.collectAsState() fun canChangeMemberRole(userId: UserId): Boolean { From 8f25c972d857a135762bf475f4466a1be12b7988 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 21 Nov 2025 09:40:32 +0100 Subject: [PATCH 09/11] Fix and add test --- .../impl/roles/ChangeRolesPresenterTest.kt | 54 ++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenterTest.kt b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenterTest.kt index 9b7a8971c3..5c2491e0d3 100644 --- a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenterTest.kt +++ b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenterTest.kt @@ -74,7 +74,7 @@ class ChangeRolesPresenterTest { } @Test - fun `present - canChangeRole of users with lower power level unless they are owners`() = runTest { + fun `present - canChangeRole of users with lower power level unless they are owners - privilegedCreatorRole is true`() = runTest { val creatorUserId = UserId("@creator:matrix.org") val superAdminUserId = UserId("@super_admin:matrix.org") @@ -82,6 +82,7 @@ class ChangeRolesPresenterTest { // User is a creator, so they can change roles of other members. So is `creatorUserId`. givenRoomInfo( aRoomInfo( + privilegedCreatorRole = true, roomCreators = listOf(sessionId, creatorUserId), roomPowerLevels = RoomPowerLevels( defaultRoomPowerLevelValues(), @@ -99,7 +100,7 @@ class ChangeRolesPresenterTest { val roomMemberList = aRoomMemberList() + listOf( // Owner - superadmin - aRoomMember(userId = superAdminUserId, role = RoomMember.Role.Owner(isCreator = true)), + aRoomMember(userId = superAdminUserId, role = RoomMember.Role.Owner(isCreator = false)), // Owner - creator aRoomMember(userId = creatorUserId, role = RoomMember.Role.Owner(isCreator = true)) ) @@ -118,6 +119,55 @@ class ChangeRolesPresenterTest { } } + @Test + fun `present - canChangeRole of users with lower power level unless they are owners - privilegedCreatorRole is false`() = runTest { + val creatorUserId = UserId("@creator:matrix.org") + val superAdminUserId = UserId("@super_admin:matrix.org") + + val room = FakeJoinedRoom().apply { + // User is a creator, so they can change roles of other members. So is `creatorUserId`. + givenRoomInfo( + aRoomInfo( + privilegedCreatorRole = false, + roomCreators = listOf(sessionId, creatorUserId), + roomPowerLevels = RoomPowerLevels( + defaultRoomPowerLevelValues(), + users = persistentMapOf( + // Creator is an admin + sessionId to RoomMember.Role.Admin.powerLevel, + creatorUserId to RoomMember.Role.Admin.powerLevel, + // bob is Admin + A_USER_ID_2 to RoomMember.Role.Admin.powerLevel, + // carol is Moderator + A_USER_ID_3 to RoomMember.Role.Moderator.powerLevel, + // super_admin is Owner - Superadmin + superAdminUserId to RoomMember.Role.Owner(isCreator = false).powerLevel, + ) + ) + ) + ) + + val roomMemberList = aRoomMemberList() + listOf( + // Owner - superadmin + aRoomMember(userId = superAdminUserId, role = RoomMember.Role.Owner(isCreator = false)), + // Owner - creator + aRoomMember(userId = creatorUserId, role = RoomMember.Role.Owner(isCreator = true)) + ) + givenRoomMembersState(RoomMembersState.Ready(roomMemberList.toImmutableList())) + } + val presenter = createChangeRolesPresenter(room = room) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + skipItems(1) + awaitItem().run { + assertThat(canChangeMemberRole(A_USER_ID_2)).isFalse() // Creator cannot update Admin in this case + assertThat(canChangeMemberRole(A_USER_ID_3)).isTrue() // Moderator + assertThat(canChangeMemberRole(creatorUserId)).isFalse() // Owner + } + } + } + @Test fun `present - when modifying admins, creators are displayed too`() = runTest { val room = FakeJoinedRoom().apply { From a82254d2d5170af0dc99f6eee5da26aa0041b67c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 21 Nov 2025 09:42:49 +0100 Subject: [PATCH 10/11] Use test extension --- .../impl/roles/ChangeRolesPresenterTest.kt | 80 +++++-------------- 1 file changed, 20 insertions(+), 60 deletions(-) diff --git a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenterTest.kt b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenterTest.kt index 5c2491e0d3..472426ff85 100644 --- a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenterTest.kt +++ b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesPresenterTest.kt @@ -8,9 +8,6 @@ package io.element.android.features.rolesandpermissions.impl.roles -import app.cash.molecule.RecompositionMode -import app.cash.molecule.moleculeFlow -import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import im.vector.app.features.analytics.plan.RoomModeration import io.element.android.libraries.architecture.AsyncAction @@ -31,6 +28,7 @@ import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.room.defaultRoomPowerLevelValues import io.element.android.libraries.previewutils.room.aRoomMemberList import io.element.android.services.analytics.test.FakeAnalyticsService +import io.element.android.tests.testutils.test import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.toImmutableList @@ -43,9 +41,7 @@ class ChangeRolesPresenterTest { @Test fun `present - initial state`() = runTest { val presenter = createChangeRolesPresenter() - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { with(awaitItem()) { assertThat(role).isEqualTo(RoomMember.Role.Admin) assertThat(query).isNull() @@ -65,9 +61,7 @@ class ChangeRolesPresenterTest { givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) } val presenter = createChangeRolesPresenter(room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(1) assertThat(awaitItem().searchResults).isInstanceOf(SearchBarResultState.Results::class.java) } @@ -107,9 +101,7 @@ class ChangeRolesPresenterTest { givenRoomMembersState(RoomMembersState.Ready(roomMemberList.toImmutableList())) } val presenter = createChangeRolesPresenter(room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(1) awaitItem().run { assertThat(canChangeMemberRole(A_USER_ID_2)).isTrue() // Admin @@ -156,9 +148,7 @@ class ChangeRolesPresenterTest { givenRoomMembersState(RoomMembersState.Ready(roomMemberList.toImmutableList())) } val presenter = createChangeRolesPresenter(room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(1) awaitItem().run { assertThat(canChangeMemberRole(A_USER_ID_2)).isFalse() // Creator cannot update Admin in this case @@ -179,9 +169,7 @@ class ChangeRolesPresenterTest { givenRoomMembersState(RoomMembersState.Ready(memberList)) } val presenter = createChangeRolesPresenter(room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(1) awaitItem().searchResults.run { assertThat(this).isInstanceOf(SearchBarResultState.Results::class.java) @@ -199,9 +187,7 @@ class ChangeRolesPresenterTest { givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) } val presenter = createChangeRolesPresenter(room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() initialState.eventSink(ChangeRolesEvent.ToggleSearchActive) @@ -218,9 +204,7 @@ class ChangeRolesPresenterTest { givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) } val presenter = createChangeRolesPresenter(room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { val initialState = awaitItem() val initialResults = (awaitItem().searchResults as? SearchBarResultState.Results)?.results assertThat(initialResults?.members).hasSize(8) @@ -244,9 +228,7 @@ class ChangeRolesPresenterTest { givenRoomMembersState(RoomMembersState.Ready(aRoomMemberList())) } val presenter = createChangeRolesPresenter(room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(1) val initialResults = (awaitItem().searchResults as? SearchBarResultState.Results)?.results assertThat(initialResults?.members).hasSize(8) @@ -271,9 +253,7 @@ class ChangeRolesPresenterTest { givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin))) } val presenter = createChangeRolesPresenter(room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(1) val initialState = awaitItem() assertThat(initialState.selectedUsers).hasSize(1) @@ -293,9 +273,7 @@ class ChangeRolesPresenterTest { givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin))) } val presenter = createChangeRolesPresenter(room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(1) val initialState = awaitItem() assertThat(initialState.hasPendingChanges).isFalse() @@ -322,9 +300,7 @@ class ChangeRolesPresenterTest { givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin))) } val presenter = createChangeRolesPresenter(room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(1) val initialState = awaitItem() assertThat(initialState.hasPendingChanges).isFalse() @@ -342,9 +318,7 @@ class ChangeRolesPresenterTest { givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin))) } val presenter = createChangeRolesPresenter(room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(1) val initialState = awaitItem() assertThat(initialState.hasPendingChanges).isFalse() @@ -368,9 +342,7 @@ class ChangeRolesPresenterTest { givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin))) } val presenter = createChangeRolesPresenter(room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(1) val initialState = awaitItem() assertThat(initialState.hasPendingChanges).isFalse() @@ -399,9 +371,7 @@ class ChangeRolesPresenterTest { givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin))) } val presenter = createChangeRolesPresenter(role = RoomMember.Role.Admin, room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(2) val initialState = awaitItem() assertThat(initialState.selectedUsers).hasSize(1) @@ -422,9 +392,7 @@ class ChangeRolesPresenterTest { givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(RoomMember.Role.Admin))) } val presenter = createChangeRolesPresenter(role = RoomMember.Role.Admin, room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(1) val initialState = awaitItem() assertThat(initialState.selectedUsers).hasSize(1) @@ -455,9 +423,7 @@ class ChangeRolesPresenterTest { room = room, analyticsService = analyticsService ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(2) val initialState = awaitItem() assertThat(initialState.selectedUsers).hasSize(1) @@ -492,9 +458,7 @@ class ChangeRolesPresenterTest { room = room, analyticsService = analyticsService ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(1) val initialState = awaitItem() assertThat(initialState.selectedUsers).hasSize(1) @@ -527,9 +491,7 @@ class ChangeRolesPresenterTest { room = room, analyticsService = analyticsService ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(2) val initialState = awaitItem() assertThat(initialState.selectedUsers).hasSize(1) @@ -554,9 +516,7 @@ class ChangeRolesPresenterTest { givenRoomInfo(aRoomInfo(roomPowerLevels = roomPowerLevelsWithRole(role = RoomMember.Role.Moderator, userId = A_USER_ID))) } val presenter = createChangeRolesPresenter(role = RoomMember.Role.Moderator, room = room) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { + presenter.test { skipItems(2) val initialState = awaitItem() assertThat(initialState.selectedUsers).hasSize(1) From b0da504bc59cde717554a29b222a6617bcc06bc9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 21 Nov 2025 16:36:56 +0100 Subject: [PATCH 11/11] Fix test --- .../impl/roles/ChangeRolesViewTest.kt | 46 ++++++++----------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesViewTest.kt b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesViewTest.kt index 63fa9f3b19..fd45e5408c 100644 --- a/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesViewTest.kt +++ b/features/rolesandpermissions/impl/src/test/kotlin/io/element/android/features/rolesandpermissions/impl/roles/ChangeRolesViewTest.kt @@ -50,7 +50,6 @@ class ChangeRolesViewTest { ), ) }.exceptionOrNull() - assertThat(exception).isNotNull() } @@ -63,9 +62,7 @@ class ChangeRolesViewTest { eventSink = eventsRecorder, ), ) - rule.pressBackKey() - eventsRecorder.assertSingle(ChangeRolesEvent.ToggleSearchActive) } @@ -78,9 +75,7 @@ class ChangeRolesViewTest { eventSink = eventsRecorder, ), ) - rule.pressBackKey() - eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged(""), ChangeRolesEvent.Exit)) } @@ -93,9 +88,7 @@ class ChangeRolesViewTest { eventSink = eventsRecorder, ), ) - rule.pressBack() - eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged(""), ChangeRolesEvent.Exit)) } @@ -108,9 +101,7 @@ class ChangeRolesViewTest { eventSink = eventsRecorder, ), ) - rule.clickOn(CommonStrings.action_save) - eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged(""), ChangeRolesEvent.Save)) } @@ -123,9 +114,7 @@ class ChangeRolesViewTest { eventSink = eventsRecorder, ), ) - rule.clickOn(CommonStrings.action_save) - eventsRecorder.assertList(listOf(ChangeRolesEvent.QueryChanged(""))) } @@ -139,9 +128,7 @@ class ChangeRolesViewTest { eventSink = eventsRecorder, ), ) - rule.clickOn(CommonStrings.action_ok) - eventsRecorder.assertSingle(ChangeRolesEvent.Exit) } @@ -155,26 +142,22 @@ class ChangeRolesViewTest { eventSink = eventsRecorder, ), ) - rule.clickOn(CommonStrings.action_cancel) - eventsRecorder.assertSingle(ChangeRolesEvent.CloseDialog) } @Test - fun `save confirmation dialog - submit saves the changes`() { + fun `save admins confirmation dialog - submit saves the changes`() { val eventsRecorder = EventsRecorder() rule.setChangeRolesContent( state = aChangeRolesState( role = RoomMember.Role.Admin, isSearchActive = true, - savingState = AsyncAction.ConfirmingNoParams, + savingState = ConfirmingModifyingAdmins, eventSink = eventsRecorder, ), ) - rule.clickOn(CommonStrings.action_ok) - eventsRecorder.assertSingle(ChangeRolesEvent.Save) } @@ -185,30 +168,41 @@ class ChangeRolesViewTest { state = aChangeRolesState( role = RoomMember.Role.Owner(isCreator = false), isSearchActive = true, - savingState = AsyncAction.ConfirmingNoParams, + savingState = ConfirmingModifyingOwners, eventSink = eventsRecorder, ), ) - rule.clickOn(CommonStrings.action_continue) - eventsRecorder.assertSingle(ChangeRolesEvent.Save) } @Test - fun `save confirmation dialog - cancel removes the dialog`() { + fun `save admins confirmation dialog - cancel removes the dialog`() { val eventsRecorder = EventsRecorder() rule.setChangeRolesContent( state = aChangeRolesState( role = RoomMember.Role.Admin, isSearchActive = true, - savingState = AsyncAction.ConfirmingNoParams, + savingState = ConfirmingModifyingAdmins, eventSink = eventsRecorder, ), ) - rule.clickOn(CommonStrings.action_cancel) + eventsRecorder.assertSingle(ChangeRolesEvent.CloseDialog) + } + @Test + fun `save owners confirmation dialog - cancel removes the dialog`() { + val eventsRecorder = EventsRecorder() + rule.setChangeRolesContent( + state = aChangeRolesState( + role = RoomMember.Role.Owner(isCreator = false), + isSearchActive = true, + savingState = ConfirmingModifyingOwners, + eventSink = eventsRecorder, + ), + ) + rule.clickOn(CommonStrings.action_cancel) eventsRecorder.assertSingle(ChangeRolesEvent.CloseDialog) } @@ -222,9 +216,7 @@ class ChangeRolesViewTest { eventSink = eventsRecorder, ), ) - rule.clickOn(CommonStrings.action_ok) - eventsRecorder.assertSingle(ChangeRolesEvent.CloseDialog) }