diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt index 7831265fd0..cec9f68b45 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesStateProvider.kt @@ -41,6 +41,7 @@ import io.element.android.features.messages.impl.timeline.protection.aTimelinePr import io.element.android.features.roomcall.api.RoomCallState import io.element.android.features.roomcall.api.aStandByCallState import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents +import io.element.android.features.roommembermoderation.api.RoomMemberModerationPermissions import io.element.android.features.roommembermoderation.api.RoomMemberModerationState import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.components.avatar.AvatarData @@ -164,11 +165,9 @@ fun aMessagesState( ) fun aRoomMemberModerationState( - canKick: Boolean = false, - canBan: Boolean = false, + permissions: RoomMemberModerationPermissions = RoomMemberModerationPermissions.DEFAULT, ) = object : RoomMemberModerationState { - override val canKick: Boolean = canKick - override val canBan: Boolean = canBan + override val permissions: RoomMemberModerationPermissions = permissions override val eventSink: (RoomMemberModerationEvents) -> Unit = {} } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListState.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListState.kt index 007d276dd3..7c928fb27a 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListState.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListState.kt @@ -26,7 +26,7 @@ data class RoomMemberListState( val moderationState: RoomMemberModerationState, val eventSink: (RoomMemberListEvents) -> Unit, ) { - val showBannedSection: Boolean = moderationState.canBan && roomMembers.dataOrNull()?.banned?.isNotEmpty() == true + val showBannedSection: Boolean = moderationState.permissions.canBan && roomMembers.dataOrNull()?.banned?.isNotEmpty() == true } enum class SelectedSection { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt index 580db7667a..b37738c30f 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/RoomMemberListStateProvider.kt @@ -10,6 +10,7 @@ package io.element.android.features.roomdetails.impl.members import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents +import io.element.android.features.roommembermoderation.api.RoomMemberModerationPermissions import io.element.android.features.roommembermoderation.api.RoomMemberModerationState import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.map @@ -99,8 +100,10 @@ fun aRoomMemberModerationState( canKick: Boolean = false, ): RoomMemberModerationState { return object : RoomMemberModerationState { - override val canKick: Boolean = canKick - override val canBan: Boolean = canBan + override val permissions: RoomMemberModerationPermissions = RoomMemberModerationPermissions( + canBan = canBan, + canKick = canKick, + ) override val eventSink: (RoomMemberModerationEvents) -> Unit = {} } } diff --git a/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationPermissions.kt b/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationPermissions.kt new file mode 100644 index 0000000000..223456de69 --- /dev/null +++ b/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationPermissions.kt @@ -0,0 +1,29 @@ +/* + * 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.roommembermoderation.api + +import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions + +data class RoomMemberModerationPermissions( + val canKick: Boolean, + val canBan: Boolean, +) { + companion object { + val DEFAULT = RoomMemberModerationPermissions( + canKick = false, + canBan = false, + ) + } +} + +fun RoomPermissions.roomMemberModerationPermissions(): RoomMemberModerationPermissions { + return RoomMemberModerationPermissions( + canKick = canOwnUserKick(), + canBan = canOwnUserBan(), + ) +} diff --git a/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationState.kt b/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationState.kt index 85f3e8ec19..c9ee958f6f 100644 --- a/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationState.kt +++ b/features/roommembermoderation/api/src/main/kotlin/io/element/android/features/roommembermoderation/api/RoomMemberModerationState.kt @@ -12,8 +12,7 @@ import androidx.compose.runtime.Immutable @Immutable interface RoomMemberModerationState { - val canKick: Boolean - val canBan: Boolean + val permissions: RoomMemberModerationPermissions val eventSink: (RoomMemberModerationEvents) -> Unit } diff --git a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/InternalRoomMemberModerationState.kt b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/InternalRoomMemberModerationState.kt index fe48ece1fd..f45a277992 100644 --- a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/InternalRoomMemberModerationState.kt +++ b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/InternalRoomMemberModerationState.kt @@ -10,14 +10,14 @@ package io.element.android.features.roommembermoderation.impl import io.element.android.features.roommembermoderation.api.ModerationActionState import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents +import io.element.android.features.roommembermoderation.api.RoomMemberModerationPermissions import io.element.android.features.roommembermoderation.api.RoomMemberModerationState import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.collections.immutable.ImmutableList data class InternalRoomMemberModerationState( - override val canKick: Boolean, - override val canBan: Boolean, + override val permissions: RoomMemberModerationPermissions, val selectedUser: MatrixUser?, val actions: ImmutableList, val kickUserAsyncAction: AsyncAction, diff --git a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/InternalRoomMemberModerationStateProvider.kt b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/InternalRoomMemberModerationStateProvider.kt index d90f352cfa..120a299a7d 100644 --- a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/InternalRoomMemberModerationStateProvider.kt +++ b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/InternalRoomMemberModerationStateProvider.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.roommembermoderation.api.ModerationAction import io.element.android.features.roommembermoderation.api.ModerationActionState import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents +import io.element.android.features.roommembermoderation.api.RoomMemberModerationPermissions import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.user.MatrixUser @@ -83,8 +84,7 @@ fun anAlice() = MatrixUser( ) fun aRoomMembersModerationState( - canKick: Boolean = false, - canBan: Boolean = false, + permissions: RoomMemberModerationPermissions = RoomMemberModerationPermissions.DEFAULT, selectedUser: MatrixUser? = null, actions: List = emptyList(), kickUserAsyncAction: AsyncAction = AsyncAction.Uninitialized, @@ -92,8 +92,7 @@ fun aRoomMembersModerationState( unbanUserAsyncAction: AsyncAction = AsyncAction.Uninitialized, eventSink: (RoomMemberModerationEvents) -> Unit = {}, ) = InternalRoomMemberModerationState( - canKick = canKick, - canBan = canBan, + permissions = permissions, selectedUser = selectedUser, actions = actions.toImmutableList(), kickUserAsyncAction = kickUserAsyncAction, diff --git a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationPresenter.kt b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationPresenter.kt index 96749ba5ac..16a11aee96 100644 --- a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationPresenter.kt +++ b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationPresenter.kt @@ -21,7 +21,9 @@ import im.vector.app.features.analytics.plan.RoomModeration import io.element.android.features.roommembermoderation.api.ModerationAction import io.element.android.features.roommembermoderation.api.ModerationActionState import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents +import io.element.android.features.roommembermoderation.api.RoomMemberModerationPermissions import io.element.android.features.roommembermoderation.api.RoomMemberModerationState +import io.element.android.features.roommembermoderation.api.roomMemberModerationPermissions import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runUpdatingState @@ -55,11 +57,8 @@ class RoomMemberModerationPresenter( override fun present(): RoomMemberModerationState { val coroutineScope = rememberCoroutineScope() val syncUpdateFlow = room.syncUpdateFlow.collectAsState() - val permissions by room.permissionsAsState(Permissions()) { perms -> - Permissions( - canKick = perms.canOwnUserKick(), - canBan = perms.canOwnUserBan(), - ) + val permissions by room.permissionsAsState(RoomMemberModerationPermissions.DEFAULT) { perms -> + perms.roomMemberModerationPermissions() } val currentUserMemberPowerLevel = room.userPowerLevelAsState(syncUpdateFlow.value) @@ -136,8 +135,7 @@ class RoomMemberModerationPresenter( } return InternalRoomMemberModerationState( - canKick = permissions.canKick, - canBan = permissions.canBan, + permissions = permissions, selectedUser = selectedUser, actions = moderationActions.value, kickUserAsyncAction = kickUserAsyncAction.value, @@ -149,7 +147,7 @@ class RoomMemberModerationPresenter( private fun computeModerationActions( member: RoomMember?, - permissions: Permissions, + permissions: RoomMemberModerationPermissions, currentUserMemberPowerLevel: Long, ): ImmutableList { return buildList { @@ -209,11 +207,6 @@ class RoomMemberModerationPresenter( ) } - private data class Permissions( - val canKick: Boolean = false, - val canBan: Boolean = false, - ) - private fun CoroutineScope.runActionAndWaitForMembershipChange( action: MutableState>, block: suspend () -> Result diff --git a/features/roommembermoderation/impl/src/test/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationPresenterTest.kt b/features/roommembermoderation/impl/src/test/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationPresenterTest.kt index 4ce50a2488..3f59151eea 100644 --- a/features/roommembermoderation/impl/src/test/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationPresenterTest.kt +++ b/features/roommembermoderation/impl/src/test/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationPresenterTest.kt @@ -13,6 +13,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.features.roommembermoderation.api.ModerationAction import io.element.android.features.roommembermoderation.api.ModerationActionState import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents +import io.element.android.features.roommembermoderation.api.RoomMemberModerationPermissions import io.element.android.features.roommembermoderation.api.RoomMemberModerationState import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.core.coroutine.CoroutineDispatchers @@ -49,8 +50,7 @@ class RoomMemberModerationPresenterTest { val room = aJoinedRoom() createRoomMemberModerationPresenter(room = room).test { val initialState = awaitState() - assertThat(initialState.canKick).isFalse() - assertThat(initialState.canBan).isFalse() + assertThat(initialState.permissions).isEqualTo(RoomMemberModerationPermissions.DEFAULT) assertThat(initialState.selectedUser).isNull() assertThat(initialState.banUserAsyncAction).isEqualTo(AsyncAction.Uninitialized) assertThat(initialState.kickUserAsyncAction).isEqualTo(AsyncAction.Uninitialized)