misc(power level) : expose RoomMemberModerationPermissions after PR review
This commit is contained in:
parent
5c8fd831e3
commit
0476cbd4d9
9 changed files with 52 additions and 30 deletions
|
|
@ -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.RoomCallState
|
||||||
import io.element.android.features.roomcall.api.aStandByCallState
|
import io.element.android.features.roomcall.api.aStandByCallState
|
||||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
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.RoomMemberModerationState
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
|
|
@ -164,11 +165,9 @@ fun aMessagesState(
|
||||||
)
|
)
|
||||||
|
|
||||||
fun aRoomMemberModerationState(
|
fun aRoomMemberModerationState(
|
||||||
canKick: Boolean = false,
|
permissions: RoomMemberModerationPermissions = RoomMemberModerationPermissions.DEFAULT,
|
||||||
canBan: Boolean = false,
|
|
||||||
) = object : RoomMemberModerationState {
|
) = object : RoomMemberModerationState {
|
||||||
override val canKick: Boolean = canKick
|
override val permissions: RoomMemberModerationPermissions = permissions
|
||||||
override val canBan: Boolean = canBan
|
|
||||||
override val eventSink: (RoomMemberModerationEvents) -> Unit = {}
|
override val eventSink: (RoomMemberModerationEvents) -> Unit = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ data class RoomMemberListState(
|
||||||
val moderationState: RoomMemberModerationState,
|
val moderationState: RoomMemberModerationState,
|
||||||
val eventSink: (RoomMemberListEvents) -> Unit,
|
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 {
|
enum class SelectedSection {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ package io.element.android.features.roomdetails.impl.members
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
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.RoomMemberModerationState
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.architecture.map
|
import io.element.android.libraries.architecture.map
|
||||||
|
|
@ -99,8 +100,10 @@ fun aRoomMemberModerationState(
|
||||||
canKick: Boolean = false,
|
canKick: Boolean = false,
|
||||||
): RoomMemberModerationState {
|
): RoomMemberModerationState {
|
||||||
return object : RoomMemberModerationState {
|
return object : RoomMemberModerationState {
|
||||||
override val canKick: Boolean = canKick
|
override val permissions: RoomMemberModerationPermissions = RoomMemberModerationPermissions(
|
||||||
override val canBan: Boolean = canBan
|
canBan = canBan,
|
||||||
|
canKick = canKick,
|
||||||
|
)
|
||||||
override val eventSink: (RoomMemberModerationEvents) -> Unit = {}
|
override val eventSink: (RoomMemberModerationEvents) -> Unit = {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -12,8 +12,7 @@ import androidx.compose.runtime.Immutable
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
interface RoomMemberModerationState {
|
interface RoomMemberModerationState {
|
||||||
val canKick: Boolean
|
val permissions: RoomMemberModerationPermissions
|
||||||
val canBan: Boolean
|
|
||||||
val eventSink: (RoomMemberModerationEvents) -> Unit
|
val eventSink: (RoomMemberModerationEvents) -> Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.ModerationActionState
|
||||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
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.RoomMemberModerationState
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
data class InternalRoomMemberModerationState(
|
data class InternalRoomMemberModerationState(
|
||||||
override val canKick: Boolean,
|
override val permissions: RoomMemberModerationPermissions,
|
||||||
override val canBan: Boolean,
|
|
||||||
val selectedUser: MatrixUser?,
|
val selectedUser: MatrixUser?,
|
||||||
val actions: ImmutableList<ModerationActionState>,
|
val actions: ImmutableList<ModerationActionState>,
|
||||||
val kickUserAsyncAction: AsyncAction<Unit>,
|
val kickUserAsyncAction: AsyncAction<Unit>,
|
||||||
|
|
|
||||||
|
|
@ -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.ModerationAction
|
||||||
import io.element.android.features.roommembermoderation.api.ModerationActionState
|
import io.element.android.features.roommembermoderation.api.ModerationActionState
|
||||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
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.architecture.AsyncAction
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
|
|
@ -83,8 +84,7 @@ fun anAlice() = MatrixUser(
|
||||||
)
|
)
|
||||||
|
|
||||||
fun aRoomMembersModerationState(
|
fun aRoomMembersModerationState(
|
||||||
canKick: Boolean = false,
|
permissions: RoomMemberModerationPermissions = RoomMemberModerationPermissions.DEFAULT,
|
||||||
canBan: Boolean = false,
|
|
||||||
selectedUser: MatrixUser? = null,
|
selectedUser: MatrixUser? = null,
|
||||||
actions: List<ModerationActionState> = emptyList(),
|
actions: List<ModerationActionState> = emptyList(),
|
||||||
kickUserAsyncAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
kickUserAsyncAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||||
|
|
@ -92,8 +92,7 @@ fun aRoomMembersModerationState(
|
||||||
unbanUserAsyncAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
unbanUserAsyncAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||||
eventSink: (RoomMemberModerationEvents) -> Unit = {},
|
eventSink: (RoomMemberModerationEvents) -> Unit = {},
|
||||||
) = InternalRoomMemberModerationState(
|
) = InternalRoomMemberModerationState(
|
||||||
canKick = canKick,
|
permissions = permissions,
|
||||||
canBan = canBan,
|
|
||||||
selectedUser = selectedUser,
|
selectedUser = selectedUser,
|
||||||
actions = actions.toImmutableList(),
|
actions = actions.toImmutableList(),
|
||||||
kickUserAsyncAction = kickUserAsyncAction,
|
kickUserAsyncAction = kickUserAsyncAction,
|
||||||
|
|
|
||||||
|
|
@ -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.ModerationAction
|
||||||
import io.element.android.features.roommembermoderation.api.ModerationActionState
|
import io.element.android.features.roommembermoderation.api.ModerationActionState
|
||||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
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.RoomMemberModerationState
|
||||||
|
import io.element.android.features.roommembermoderation.api.roomMemberModerationPermissions
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.runUpdatingState
|
import io.element.android.libraries.architecture.runUpdatingState
|
||||||
|
|
@ -55,11 +57,8 @@ class RoomMemberModerationPresenter(
|
||||||
override fun present(): RoomMemberModerationState {
|
override fun present(): RoomMemberModerationState {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
|
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
|
||||||
val permissions by room.permissionsAsState(Permissions()) { perms ->
|
val permissions by room.permissionsAsState(RoomMemberModerationPermissions.DEFAULT) { perms ->
|
||||||
Permissions(
|
perms.roomMemberModerationPermissions()
|
||||||
canKick = perms.canOwnUserKick(),
|
|
||||||
canBan = perms.canOwnUserBan(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
val currentUserMemberPowerLevel = room.userPowerLevelAsState(syncUpdateFlow.value)
|
val currentUserMemberPowerLevel = room.userPowerLevelAsState(syncUpdateFlow.value)
|
||||||
|
|
||||||
|
|
@ -136,8 +135,7 @@ class RoomMemberModerationPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
return InternalRoomMemberModerationState(
|
return InternalRoomMemberModerationState(
|
||||||
canKick = permissions.canKick,
|
permissions = permissions,
|
||||||
canBan = permissions.canBan,
|
|
||||||
selectedUser = selectedUser,
|
selectedUser = selectedUser,
|
||||||
actions = moderationActions.value,
|
actions = moderationActions.value,
|
||||||
kickUserAsyncAction = kickUserAsyncAction.value,
|
kickUserAsyncAction = kickUserAsyncAction.value,
|
||||||
|
|
@ -149,7 +147,7 @@ class RoomMemberModerationPresenter(
|
||||||
|
|
||||||
private fun computeModerationActions(
|
private fun computeModerationActions(
|
||||||
member: RoomMember?,
|
member: RoomMember?,
|
||||||
permissions: Permissions,
|
permissions: RoomMemberModerationPermissions,
|
||||||
currentUserMemberPowerLevel: Long,
|
currentUserMemberPowerLevel: Long,
|
||||||
): ImmutableList<ModerationActionState> {
|
): ImmutableList<ModerationActionState> {
|
||||||
return buildList {
|
return buildList {
|
||||||
|
|
@ -209,11 +207,6 @@ class RoomMemberModerationPresenter(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class Permissions(
|
|
||||||
val canKick: Boolean = false,
|
|
||||||
val canBan: Boolean = false,
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun <T> CoroutineScope.runActionAndWaitForMembershipChange(
|
private fun <T> CoroutineScope.runActionAndWaitForMembershipChange(
|
||||||
action: MutableState<AsyncAction<T>>,
|
action: MutableState<AsyncAction<T>>,
|
||||||
block: suspend () -> Result<T>
|
block: suspend () -> Result<T>
|
||||||
|
|
|
||||||
|
|
@ -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.ModerationAction
|
||||||
import io.element.android.features.roommembermoderation.api.ModerationActionState
|
import io.element.android.features.roommembermoderation.api.ModerationActionState
|
||||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
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.RoomMemberModerationState
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
|
|
@ -49,8 +50,7 @@ class RoomMemberModerationPresenterTest {
|
||||||
val room = aJoinedRoom()
|
val room = aJoinedRoom()
|
||||||
createRoomMemberModerationPresenter(room = room).test {
|
createRoomMemberModerationPresenter(room = room).test {
|
||||||
val initialState = awaitState()
|
val initialState = awaitState()
|
||||||
assertThat(initialState.canKick).isFalse()
|
assertThat(initialState.permissions).isEqualTo(RoomMemberModerationPermissions.DEFAULT)
|
||||||
assertThat(initialState.canBan).isFalse()
|
|
||||||
assertThat(initialState.selectedUser).isNull()
|
assertThat(initialState.selectedUser).isNull()
|
||||||
assertThat(initialState.banUserAsyncAction).isEqualTo(AsyncAction.Uninitialized)
|
assertThat(initialState.banUserAsyncAction).isEqualTo(AsyncAction.Uninitialized)
|
||||||
assertThat(initialState.kickUserAsyncAction).isEqualTo(AsyncAction.Uninitialized)
|
assertThat(initialState.kickUserAsyncAction).isEqualTo(AsyncAction.Uninitialized)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue