Merge pull request #5786 from element-hq/feature/bma/addAdminConfirmation

Ensure confirmation dialog is displayed when an admin add other admin to a room
This commit is contained in:
Benoit Marty 2025-11-21 17:06:42 +01:00 committed by GitHub
commit 80d799c4db
16 changed files with 260 additions and 124 deletions

View file

@ -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 != selectedUsers.value
val hasPendingChanges by remember {
derivedStateOf {
usersWithRole.value.toSet() != selectedUsers.value.toSet()
}
}
val roomInfo by room.roomInfoFlow.collectAsState()
fun canChangeMemberRole(userId: UserId): Boolean {
@ -134,16 +139,20 @@ 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 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)

View file

@ -46,7 +46,7 @@ class ChangeRolesStateProvider : PreviewParameterProvider<ChangeRolesState> {
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<ChangeRolesState> {
)
),
aChangeRolesStateWithOwners(role = RoomMember.Role.Owner(isCreator = false)),
aChangeRolesStateWithOwners(role = RoomMember.Role.Owner(isCreator = false))
.copy(savingState = ConfirmingModifyingOwners),
)
}

View file

@ -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) }
)
}
}
},

View file

@ -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

View file

@ -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