change (member moderation) : allow disabled action and render unban too
This commit is contained in:
parent
f22b921768
commit
c6eea91d69
11 changed files with 119 additions and 77 deletions
|
|
@ -263,10 +263,10 @@ class MessagesNode @AssistedInject constructor(
|
||||||
)
|
)
|
||||||
roomMemberModerationRenderer.Render(
|
roomMemberModerationRenderer.Render(
|
||||||
state = state.roomMemberModerationState,
|
state = state.roomMemberModerationState,
|
||||||
onSelectAction = { action ->
|
onSelectAction = { action, target ->
|
||||||
when (action) {
|
when (action) {
|
||||||
is ModerationAction.DisplayProfile -> onUserDataClick(action.user.userId)
|
is ModerationAction.DisplayProfile -> onUserDataClick(target.userId)
|
||||||
else -> state.roomMemberModerationState.eventSink(RoomMemberModerationEvents.ProcessAction(action))
|
else -> state.roomMemberModerationState.eventSink(RoomMemberModerationEvents.ProcessAction(action, target))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
|
|
|
||||||
|
|
@ -75,10 +75,10 @@ class RoomMemberListNode @AssistedInject constructor(
|
||||||
)
|
)
|
||||||
roomMemberModerationRenderer.Render(
|
roomMemberModerationRenderer.Render(
|
||||||
state = state.moderationState,
|
state = state.moderationState,
|
||||||
onSelectAction = { action ->
|
onSelectAction = { action, target ->
|
||||||
when (action) {
|
when (action) {
|
||||||
is ModerationAction.DisplayProfile -> openRoomMemberDetails(action.user.userId)
|
is ModerationAction.DisplayProfile -> openRoomMemberDetails(target.userId)
|
||||||
else -> state.moderationState.eventSink(RoomMemberModerationEvents.ProcessAction(action))
|
else -> state.moderationState.eventSink(RoomMemberModerationEvents.ProcessAction(action, target))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,7 @@ class RoomMemberListPresenter @AssistedInject constructor(
|
||||||
is RoomMemberListEvents.UpdateSearchQuery -> searchQuery = event.query
|
is RoomMemberListEvents.UpdateSearchQuery -> searchQuery = event.query
|
||||||
is RoomMemberListEvents.RoomMemberSelected ->
|
is RoomMemberListEvents.RoomMemberSelected ->
|
||||||
if (event.roomMember.membership == RoomMembershipState.BAN) {
|
if (event.roomMember.membership == RoomMembershipState.BAN) {
|
||||||
roomModerationState.eventSink(RoomMemberModerationEvents.ProcessAction(ModerationAction.UnbanUser(event.roomMember.toMatrixUser())))
|
roomModerationState.eventSink(RoomMemberModerationEvents.ProcessAction(ModerationAction.UnbanUser, event.roomMember.toMatrixUser()))
|
||||||
} else if (!isDm.value && (roomModerationState.canBan || roomModerationState.canKick)) {
|
} else if (!isDm.value && (roomModerationState.canBan || roomModerationState.canKick)) {
|
||||||
roomModerationState.eventSink(RoomMemberModerationEvents.ShowActionsForUser(event.roomMember.toMatrixUser()))
|
roomModerationState.eventSink(RoomMemberModerationEvents.ShowActionsForUser(event.roomMember.toMatrixUser()))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,5 @@ import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
|
|
||||||
interface RoomMemberModerationEvents {
|
interface RoomMemberModerationEvents {
|
||||||
data class ShowActionsForUser(val user: MatrixUser) : RoomMemberModerationEvents
|
data class ShowActionsForUser(val user: MatrixUser) : RoomMemberModerationEvents
|
||||||
data class ProcessAction(val action: ModerationAction) : RoomMemberModerationEvents
|
data class ProcessAction(val action: ModerationAction, val targetUser: MatrixUser) : RoomMemberModerationEvents
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,13 @@ package io.element.android.features.roommembermoderation.api
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
|
|
||||||
interface RoomMemberModerationRenderer {
|
interface RoomMemberModerationRenderer {
|
||||||
@Composable
|
@Composable
|
||||||
fun Render(
|
fun Render(
|
||||||
state: RoomMemberModerationState,
|
state: RoomMemberModerationState,
|
||||||
onSelectAction: (ModerationAction) -> Unit,
|
onSelectAction: (ModerationAction, MatrixUser) -> Unit,
|
||||||
modifier: Modifier,
|
modifier: Modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,20 @@
|
||||||
|
|
||||||
package io.element.android.features.roommembermoderation.api
|
package io.element.android.features.roommembermoderation.api
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
|
||||||
|
|
||||||
interface RoomMemberModerationState {
|
interface RoomMemberModerationState {
|
||||||
val canKick: Boolean
|
val canKick: Boolean
|
||||||
val canBan: Boolean
|
val canBan: Boolean
|
||||||
val eventSink: (RoomMemberModerationEvents) -> Unit
|
val eventSink: (RoomMemberModerationEvents) -> Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class ModerationActionState(
|
||||||
|
val action: ModerationAction,
|
||||||
|
val isEnabled: Boolean,
|
||||||
|
)
|
||||||
|
|
||||||
sealed interface ModerationAction {
|
sealed interface ModerationAction {
|
||||||
data class DisplayProfile(val user: MatrixUser) : ModerationAction
|
data object DisplayProfile : ModerationAction
|
||||||
data class KickUser(val user: MatrixUser) : ModerationAction
|
data object KickUser : ModerationAction
|
||||||
data class BanUser(val user: MatrixUser) : ModerationAction
|
data object BanUser : ModerationAction
|
||||||
data class UnbanUser(val user: MatrixUser) : ModerationAction
|
data object UnbanUser : ModerationAction
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import io.element.android.features.roommembermoderation.api.ModerationAction
|
||||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationRenderer
|
import io.element.android.features.roommembermoderation.api.RoomMemberModerationRenderer
|
||||||
import io.element.android.features.roommembermoderation.api.RoomMemberModerationState
|
import io.element.android.features.roommembermoderation.api.RoomMemberModerationState
|
||||||
import io.element.android.libraries.di.RoomScope
|
import io.element.android.libraries.di.RoomScope
|
||||||
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
@ -23,7 +24,7 @@ class DefaultRoomMemberModerationRenderer @Inject constructor() : RoomMemberMode
|
||||||
@Composable
|
@Composable
|
||||||
override fun Render(
|
override fun Render(
|
||||||
state: RoomMemberModerationState,
|
state: RoomMemberModerationState,
|
||||||
onSelectAction: (ModerationAction) -> Unit,
|
onSelectAction: (ModerationAction, MatrixUser) -> Unit,
|
||||||
modifier: Modifier
|
modifier: Modifier
|
||||||
) {
|
) {
|
||||||
if (state is InternalRoomMemberModerationState) {
|
if (state is InternalRoomMemberModerationState) {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
package io.element.android.features.roommembermoderation.impl
|
package io.element.android.features.roommembermoderation.impl
|
||||||
|
|
||||||
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.RoomMemberModerationEvents
|
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
||||||
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
|
||||||
|
|
@ -20,7 +21,7 @@ data class InternalRoomMemberModerationState(
|
||||||
override val canKick: Boolean,
|
override val canKick: Boolean,
|
||||||
override val canBan: Boolean,
|
override val canBan: Boolean,
|
||||||
val selectedUser: MatrixUser?,
|
val selectedUser: MatrixUser?,
|
||||||
val actions: ImmutableList<ModerationAction>,
|
val actions: ImmutableList<ModerationActionState>,
|
||||||
val kickUserAsyncAction: AsyncAction<Unit>,
|
val kickUserAsyncAction: AsyncAction<Unit>,
|
||||||
val banUserAsyncAction: AsyncAction<Unit>,
|
val banUserAsyncAction: AsyncAction<Unit>,
|
||||||
val unbanUserAsyncAction: AsyncAction<Unit>,
|
val unbanUserAsyncAction: AsyncAction<Unit>,
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import im.vector.app.features.analytics.plan.RoomModeration
|
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.RoomMemberModerationEvents
|
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
||||||
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
|
||||||
|
|
@ -26,7 +27,8 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
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.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||||
import io.element.android.libraries.matrix.api.room.toMatrixUser
|
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.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.ui.room.canBanAsState
|
import io.element.android.libraries.matrix.ui.room.canBanAsState
|
||||||
import io.element.android.libraries.matrix.ui.room.canKickAsState
|
import io.element.android.libraries.matrix.ui.room.canKickAsState
|
||||||
|
|
@ -64,38 +66,37 @@ class RoomMemberModerationPresenter @Inject constructor(
|
||||||
var selectedUser by remember {
|
var selectedUser by remember {
|
||||||
mutableStateOf<MatrixUser?>(null)
|
mutableStateOf<MatrixUser?>(null)
|
||||||
}
|
}
|
||||||
val moderationActions = remember { mutableStateOf(persistentListOf<ModerationAction>()) }
|
val moderationActions = remember { mutableStateOf(persistentListOf<ModerationActionState>()) }
|
||||||
|
|
||||||
fun handleEvent(event: RoomMemberModerationEvents) {
|
fun handleEvent(event: RoomMemberModerationEvents) {
|
||||||
when (event) {
|
when (event) {
|
||||||
is RoomMemberModerationEvents.ShowActionsForUser -> {
|
is RoomMemberModerationEvents.ShowActionsForUser -> {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
selectedUser = event.user
|
selectedUser = event.user
|
||||||
moderationActions.value = persistentListOf(ModerationAction.DisplayProfile(event.user))
|
val member = room.membersStateFlow.value.roomMembers()?.firstOrNull {
|
||||||
room.getUpdatedMember(event.user.userId)
|
it.userId == event.user.userId
|
||||||
.onSuccess {
|
}
|
||||||
moderationActions.value = computeModerationActions(
|
moderationActions.value = computeModerationActions(
|
||||||
member = it,
|
member = member,
|
||||||
canKick = canKick.value,
|
canKick = canKick.value,
|
||||||
canBan = canBan.value,
|
canBan = canBan.value,
|
||||||
currentUserMemberPowerLevel = currentUserMemberPowerLevel.value,
|
currentUserMemberPowerLevel = currentUserMemberPowerLevel.value,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is RoomMemberModerationEvents.ProcessAction -> {
|
is RoomMemberModerationEvents.ProcessAction -> {
|
||||||
when (val action = event.action) {
|
when (val action = event.action) {
|
||||||
is ModerationAction.DisplayProfile -> Unit
|
is ModerationAction.DisplayProfile -> Unit
|
||||||
is ModerationAction.KickUser -> {
|
is ModerationAction.KickUser -> {
|
||||||
selectedUser = action.user
|
selectedUser = event.targetUser
|
||||||
kickUserAsyncAction.value = AsyncAction.ConfirmingNoParams
|
kickUserAsyncAction.value = AsyncAction.ConfirmingNoParams
|
||||||
}
|
}
|
||||||
is ModerationAction.BanUser -> {
|
is ModerationAction.BanUser -> {
|
||||||
selectedUser = action.user
|
selectedUser = event.targetUser
|
||||||
banUserAsyncAction.value = AsyncAction.ConfirmingNoParams
|
banUserAsyncAction.value = AsyncAction.ConfirmingNoParams
|
||||||
}
|
}
|
||||||
is ModerationAction.UnbanUser -> {
|
is ModerationAction.UnbanUser -> {
|
||||||
selectedUser = action.user
|
selectedUser = event.targetUser
|
||||||
unbanUserAsyncAction.value = AsyncAction.ConfirmingNoParams
|
unbanUserAsyncAction.value = AsyncAction.ConfirmingNoParams
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -112,18 +113,18 @@ class RoomMemberModerationPresenter @Inject constructor(
|
||||||
}
|
}
|
||||||
selectedUser = null
|
selectedUser = null
|
||||||
}
|
}
|
||||||
is InternalRoomMemberModerationEvents.Reset -> {
|
|
||||||
selectedUser = null
|
|
||||||
kickUserAsyncAction.value = AsyncAction.Uninitialized
|
|
||||||
banUserAsyncAction.value = AsyncAction.Uninitialized
|
|
||||||
unbanUserAsyncAction.value = AsyncAction.Uninitialized
|
|
||||||
}
|
|
||||||
is InternalRoomMemberModerationEvents.DoUnbanUser -> {
|
is InternalRoomMemberModerationEvents.DoUnbanUser -> {
|
||||||
selectedUser?.let {
|
selectedUser?.let {
|
||||||
coroutineScope.unbanUser(it.userId, unbanUserAsyncAction)
|
coroutineScope.unbanUser(it.userId, unbanUserAsyncAction)
|
||||||
}
|
}
|
||||||
selectedUser = null
|
selectedUser = null
|
||||||
}
|
}
|
||||||
|
is InternalRoomMemberModerationEvents.Reset -> {
|
||||||
|
selectedUser = null
|
||||||
|
kickUserAsyncAction.value = AsyncAction.Uninitialized
|
||||||
|
banUserAsyncAction.value = AsyncAction.Uninitialized
|
||||||
|
unbanUserAsyncAction.value = AsyncAction.Uninitialized
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,20 +141,27 @@ class RoomMemberModerationPresenter @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun computeModerationActions(
|
private fun computeModerationActions(
|
||||||
member: RoomMember,
|
member: RoomMember?,
|
||||||
canKick: Boolean,
|
canKick: Boolean,
|
||||||
canBan: Boolean,
|
canBan: Boolean,
|
||||||
currentUserMemberPowerLevel: Long,
|
currentUserMemberPowerLevel: Long,
|
||||||
): PersistentList<ModerationAction> {
|
): PersistentList<ModerationActionState> {
|
||||||
val memberAsUser = member.toMatrixUser()
|
|
||||||
return buildList {
|
return buildList {
|
||||||
add(ModerationAction.DisplayProfile(memberAsUser))
|
add(ModerationActionState(action = ModerationAction.DisplayProfile, isEnabled = true))
|
||||||
val canModerateThisUser = member.powerLevel < currentUserMemberPowerLevel && member.membership.isActive()
|
// Assume the member is a regular user when it's unknown
|
||||||
if (canKick && canModerateThisUser) {
|
val canModerateThisUser = (member?.powerLevel ?: 0) < currentUserMemberPowerLevel
|
||||||
add(ModerationAction.KickUser(memberAsUser))
|
// Assume the member is joined when it's unknown
|
||||||
|
val membership = member?.membership ?: RoomMembershipState.JOIN
|
||||||
|
if (canKick) {
|
||||||
|
val isKickEnabled = canModerateThisUser && membership.isActive()
|
||||||
|
add(ModerationActionState(action = ModerationAction.KickUser, isEnabled = isKickEnabled))
|
||||||
}
|
}
|
||||||
if (canBan && canModerateThisUser) {
|
if (canBan) {
|
||||||
add(ModerationAction.BanUser(memberAsUser))
|
if (membership == RoomMembershipState.BAN) {
|
||||||
|
add(ModerationActionState(action = ModerationAction.UnbanUser, isEnabled = canModerateThisUser))
|
||||||
|
} else {
|
||||||
|
add(ModerationActionState(action = ModerationAction.BanUser, isEnabled = canModerateThisUser))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.toPersistentList()
|
}.toPersistentList()
|
||||||
}
|
}
|
||||||
|
|
@ -204,5 +212,4 @@ class RoomMemberModerationPresenter @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ package io.element.android.features.roommembermoderation.impl
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
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.RoomMemberModerationEvents
|
import io.element.android.features.roommembermoderation.api.RoomMemberModerationEvents
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
|
|
@ -25,24 +26,32 @@ class RoomMemberModerationStateProvider : PreviewParameterProvider<InternalRoomM
|
||||||
aRoomMembersModerationState(
|
aRoomMembersModerationState(
|
||||||
selectedUser = anAlice(),
|
selectedUser = anAlice(),
|
||||||
actions = listOf(
|
actions = listOf(
|
||||||
ModerationAction.DisplayProfile(anAlice()),
|
ModerationActionState(action = ModerationAction.DisplayProfile, isEnabled = true),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
aRoomMembersModerationState(
|
aRoomMembersModerationState(
|
||||||
selectedUser = anAlice(),
|
selectedUser = anAlice(),
|
||||||
actions = listOf(
|
actions = listOf(
|
||||||
ModerationAction.DisplayProfile(anAlice()),
|
ModerationActionState(action = ModerationAction.DisplayProfile, isEnabled = true),
|
||||||
ModerationAction.KickUser(anAlice()),
|
ModerationActionState(action = ModerationAction.KickUser, isEnabled = true),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
aRoomMembersModerationState(
|
aRoomMembersModerationState(
|
||||||
selectedUser = anAlice(),
|
selectedUser = anAlice(),
|
||||||
actions = listOf(
|
actions = listOf(
|
||||||
ModerationAction.DisplayProfile(anAlice()),
|
ModerationActionState(action = ModerationAction.DisplayProfile, isEnabled = true),
|
||||||
ModerationAction.KickUser(anAlice()),
|
ModerationActionState(action = ModerationAction.KickUser, isEnabled = false),
|
||||||
ModerationAction.BanUser(anAlice()),
|
ModerationActionState(action = ModerationAction.BanUser, isEnabled = true),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
aRoomMembersModerationState(
|
||||||
|
selectedUser = anAlice(),
|
||||||
|
actions = listOf(
|
||||||
|
ModerationActionState(action = ModerationAction.DisplayProfile, isEnabled = true),
|
||||||
|
ModerationActionState(action = ModerationAction.KickUser, isEnabled = false),
|
||||||
|
ModerationActionState(action = ModerationAction.UnbanUser, isEnabled = true),
|
||||||
|
),
|
||||||
|
),
|
||||||
aRoomMembersModerationState(
|
aRoomMembersModerationState(
|
||||||
selectedUser = anAlice(),
|
selectedUser = anAlice(),
|
||||||
kickUserAsyncAction = AsyncAction.ConfirmingNoParams,
|
kickUserAsyncAction = AsyncAction.ConfirmingNoParams,
|
||||||
|
|
@ -72,7 +81,7 @@ fun aRoomMembersModerationState(
|
||||||
canKick: Boolean = false,
|
canKick: Boolean = false,
|
||||||
canBan: Boolean = false,
|
canBan: Boolean = false,
|
||||||
selectedUser: MatrixUser? = null,
|
selectedUser: MatrixUser? = null,
|
||||||
actions: List<ModerationAction> = emptyList(),
|
actions: List<ModerationActionState> = emptyList(),
|
||||||
kickUserAsyncAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
kickUserAsyncAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||||
banUserAsyncAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
banUserAsyncAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||||
unbanUserAsyncAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
unbanUserAsyncAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.compound.theme.ElementTheme
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||||
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.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
import io.element.android.libraries.designsystem.components.async.AsyncIndicator
|
import io.element.android.libraries.designsystem.components.async.AsyncIndicator
|
||||||
import io.element.android.libraries.designsystem.components.async.AsyncIndicatorHost
|
import io.element.android.libraries.designsystem.components.async.AsyncIndicatorHost
|
||||||
|
|
@ -58,7 +59,7 @@ import timber.log.Timber
|
||||||
@Composable
|
@Composable
|
||||||
fun RoomMemberModerationView(
|
fun RoomMemberModerationView(
|
||||||
state: InternalRoomMemberModerationState,
|
state: InternalRoomMemberModerationState,
|
||||||
onSelectAction: (ModerationAction) -> Unit,
|
onSelectAction: (ModerationAction, MatrixUser) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Box(modifier = modifier) {
|
Box(modifier = modifier) {
|
||||||
|
|
@ -201,8 +202,8 @@ private fun RoomMemberAsyncActions(
|
||||||
@Composable
|
@Composable
|
||||||
private fun RoomMemberActionsBottomSheet(
|
private fun RoomMemberActionsBottomSheet(
|
||||||
user: MatrixUser,
|
user: MatrixUser,
|
||||||
actions: ImmutableList<ModerationAction>,
|
actions: ImmutableList<ModerationActionState>,
|
||||||
onSelectAction: (ModerationAction) -> Unit,
|
onSelectAction: (ModerationAction, MatrixUser) -> Unit,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
@ -223,8 +224,8 @@ private fun RoomMemberActionsBottomSheet(
|
||||||
Avatar(
|
Avatar(
|
||||||
avatarData = user.getAvatarData(size = AvatarSize.RoomListManageUser),
|
avatarData = user.getAvatarData(size = AvatarSize.RoomListManageUser),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(bottom = 28.dp)
|
.padding(bottom = 28.dp)
|
||||||
.align(Alignment.CenterHorizontally)
|
.align(Alignment.CenterHorizontally)
|
||||||
)
|
)
|
||||||
user.displayName?.let {
|
user.displayName?.let {
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -234,8 +235,8 @@ private fun RoomMemberActionsBottomSheet(
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(start = 16.dp, end = 16.dp, bottom = 8.dp)
|
.padding(start = 16.dp, end = 16.dp, bottom = 8.dp)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -246,35 +247,38 @@ private fun RoomMemberActionsBottomSheet(
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
|
||||||
for (action in actions) {
|
for (actionState in actions) {
|
||||||
when (action) {
|
when (val action = actionState.action) {
|
||||||
is ModerationAction.DisplayProfile -> {
|
is ModerationAction.DisplayProfile -> {
|
||||||
ListItem(
|
ListItem(
|
||||||
headlineContent = { Text(stringResource(R.string.screen_bottom_sheet_manage_room_member_member_user_info)) },
|
headlineContent = { Text(stringResource(R.string.screen_bottom_sheet_manage_room_member_member_user_info)) },
|
||||||
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Info())),
|
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Info())),
|
||||||
onClick = {
|
onClick = {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
onSelectAction(action)
|
onSelectAction(action, user)
|
||||||
bottomSheetState.hide()
|
bottomSheetState.hide()
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
enabled = actionState.isEnabled
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is ModerationAction.KickUser -> {
|
is ModerationAction.KickUser -> {
|
||||||
ListItem(
|
ListItem(
|
||||||
headlineContent = { Text(stringResource(R.string.screen_bottom_sheet_manage_room_member_remove)) },
|
headlineContent = { Text(stringResource(R.string.screen_bottom_sheet_manage_room_member_remove)) },
|
||||||
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Block())),
|
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Close())),
|
||||||
|
style = ListItemStyle.Destructive,
|
||||||
onClick = {
|
onClick = {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
bottomSheetState.hide()
|
bottomSheetState.hide()
|
||||||
onSelectAction(action)
|
onSelectAction(action, user)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
enabled = actionState.isEnabled
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is ModerationAction.BanUser -> {
|
is ModerationAction.BanUser -> {
|
||||||
|
|
@ -285,12 +289,26 @@ private fun RoomMemberActionsBottomSheet(
|
||||||
onClick = {
|
onClick = {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
bottomSheetState.hide()
|
bottomSheetState.hide()
|
||||||
onSelectAction(action)
|
onSelectAction(action, user)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
enabled = actionState.isEnabled
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is ModerationAction.UnbanUser -> {
|
||||||
|
ListItem(
|
||||||
|
headlineContent = { Text(stringResource(R.string.screen_room_member_list_manage_member_unban_action)) },
|
||||||
|
leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.Restart())),
|
||||||
|
style = ListItemStyle.Destructive,
|
||||||
|
onClick = {
|
||||||
|
coroutineScope.launch {
|
||||||
|
bottomSheetState.hide()
|
||||||
|
onSelectAction(action, user)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enabled = actionState.isEnabled
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is ModerationAction.UnbanUser -> Unit
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -303,12 +321,14 @@ internal fun RoomMembersModerationViewPreview(@PreviewParameter(RoomMemberModera
|
||||||
ElementPreview {
|
ElementPreview {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.heightIn(min = 64.dp)
|
.heightIn(min = 64.dp)
|
||||||
) {
|
) {
|
||||||
RoomMemberModerationView(
|
RoomMemberModerationView(
|
||||||
state = state,
|
state = state,
|
||||||
onSelectAction = {},
|
onSelectAction = { _, _ ->
|
||||||
|
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue