Room admins can change user roles (#2423)

Allow Admins to modify room member roles:

- Add a 'roles and permissions' option for each room.
- Allow promoting users to admins, adding or removing moderators, and demote yourself if you're and admin.

---------

Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
Jorge Martin Espinosa 2024-03-05 17:46:47 +01:00 committed by GitHub
parent 1d892b4bc8
commit b9d902e3fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
110 changed files with 2398 additions and 160 deletions

View file

@ -51,6 +51,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
@Composable
fun SelectedUser(
matrixUser: MatrixUser,
canRemove: Boolean,
onUserRemoved: (MatrixUser) -> Unit,
modifier: Modifier = Modifier,
) {
@ -70,24 +71,26 @@ fun SelectedUser(
style = MaterialTheme.typography.bodyLarge,
)
}
Surface(
color = MaterialTheme.colorScheme.primary,
modifier = Modifier
.clip(CircleShape)
.size(20.dp)
.align(Alignment.TopEnd)
.clickable(
indication = rememberRipple(),
interactionSource = remember { MutableInteractionSource() },
onClick = { onUserRemoved(matrixUser) }
),
) {
Icon(
imageVector = CompoundIcons.Close(),
contentDescription = stringResource(id = CommonStrings.action_remove),
tint = MaterialTheme.colorScheme.onPrimary,
modifier = Modifier.padding(2.dp)
)
if (canRemove) {
Surface(
color = MaterialTheme.colorScheme.primary,
modifier = Modifier
.clip(CircleShape)
.size(20.dp)
.align(Alignment.TopEnd)
.clickable(
indication = rememberRipple(),
interactionSource = remember { MutableInteractionSource() },
onClick = { onUserRemoved(matrixUser) }
),
) {
Icon(
imageVector = CompoundIcons.Close(),
contentDescription = stringResource(id = CommonStrings.action_remove),
tint = MaterialTheme.colorScheme.onPrimary,
modifier = Modifier.padding(2.dp)
)
}
}
}
}
@ -97,6 +100,17 @@ fun SelectedUser(
internal fun SelectedUserPreview() = ElementPreview {
SelectedUser(
aMatrixUser(),
canRemove = true,
onUserRemoved = {},
)
}
@PreviewsDayNight
@Composable
internal fun SelectedUserCannotRemovePreview() = ElementPreview {
SelectedUser(
aMatrixUser(),
canRemove = false,
onUserRemoved = {},
)
}

View file

@ -46,11 +46,12 @@ import kotlinx.collections.immutable.toImmutableList
import kotlin.math.floor
@Composable
fun SelectedUsersList(
fun SelectedUsersRowList(
selectedUsers: ImmutableList<MatrixUser>,
onUserRemoved: (MatrixUser) -> Unit,
modifier: Modifier = Modifier,
autoScroll: Boolean = false,
canDeselect: (MatrixUser) -> Boolean = { true },
contentPadding: PaddingValues = PaddingValues(0.dp),
) {
val lazyListState = rememberLazyListState()
@ -105,11 +106,12 @@ fun SelectedUsersList(
.fillMaxWidth(),
contentPadding = contentPadding,
) {
itemsIndexed(selectedUsers.toList()) { index, matrixUser ->
itemsIndexed(selectedUsers.toList()) { index, selectedUser ->
Layout(
content = {
SelectedUser(
matrixUser = matrixUser,
matrixUser = selectedUser,
canRemove = canDeselect(selectedUser),
onUserRemoved = onUserRemoved,
)
},
@ -133,7 +135,7 @@ fun SelectedUsersList(
internal fun SelectedUsersListPreview() = ElementPreview {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
// Two users that will be visible with no scrolling
SelectedUsersList(
SelectedUsersRowList(
selectedUsers = aMatrixUserList().take(2).toImmutableList(),
onUserRemoved = {},
modifier = Modifier
@ -143,7 +145,7 @@ internal fun SelectedUsersListPreview() = ElementPreview {
// Multiple users that don't fit, so will be spaced out per the measure policy
for (i in 0..5) {
SelectedUsersList(
SelectedUsersRowList(
selectedUsers = aMatrixUserList().take(6).toImmutableList(),
onUserRemoved = {},
modifier = Modifier

View file

@ -18,9 +18,12 @@ package io.element.android.libraries.matrix.ui.room
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MessageEventType
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
import io.element.android.libraries.matrix.api.room.powerlevels.canSendMessage
@ -45,3 +48,10 @@ fun MatrixRoom.canRedactOtherAsState(updateKey: Long): State<Boolean> {
value = canRedactOther().getOrElse { false }
}
}
@Composable
fun MatrixRoom.isOwnUserAdmin(): Boolean {
val roomInfo by roomInfoFlow.collectAsState(initial = null)
val powerLevel = roomInfo?.userPowerLevels?.get(sessionId) ?: 0L
return RoomMember.Role.forPowerLevel(powerLevel) == RoomMember.Role.ADMIN
}