Skip to content

Commit 28401e6

Browse files
feat(moderators): Show the participant sheet to non-moderators too
The participants list carries owner and moderator as an icon only. Anyone without moderation rights had no way to read it: the row was clickable but inert, so the rank had no text form for them anywhere in the app. Open the sheet for everyone. Without moderation rights it renders the header - display name and role - and no action rows, which is exactly the information the icon was withholding. The attendee PIN stays hidden as well; it is a SIP credential the server only hands to moderators. Hiding rows is presentation, not access control, so the canModerate() check does not simply disappear into the sheet: it moves to handleParticipantOpsAction, where it guards the API call itself rather than the drawing of a button. Assisted-by: Claude Code:claude-opus-5 Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
1 parent 2e71f8e commit 28401e6

3 files changed

Lines changed: 38 additions & 16 deletions

File tree

app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -727,17 +727,16 @@ class ConversationInfoActivity : BaseActivity() {
727727
conversationUser?.let { viewModel.banActor(it, conversationToken, actorType, actorId, internalNote) }
728728
}
729729

730-
@Suppress("ReturnCount")
731730
private fun handleParticipantClick(model: ParticipantModel) {
732-
val state = viewModel.uiState.value
733-
val conv = state.conversation ?: return
734-
val caps = state.spreedCapabilities ?: return
735-
if (!ConversationUtils.canModerate(conv, caps)) return
736-
737731
viewModel.setParticipantForOps(model)
738732
}
739733

734+
@Suppress("ReturnCount")
740735
private fun handleParticipantOpsAction(action: ParticipantOpsAction, model: ParticipantModel) {
736+
val state = viewModel.uiState.value
737+
val conv = state.conversation ?: return
738+
val caps = state.spreedCapabilities ?: return
739+
if (!ConversationUtils.canModerate(conv, caps)) return
741740
val user = conversationUser ?: return
742741
val participant = model.participant
743742
val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, 1))

app/src/main/java/com/nextcloud/talk/conversationinfo/ui/ParticipantOperationsSheet.kt

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,21 @@ import com.nextcloud.talk.models.domain.ConversationModel
4545
import com.nextcloud.talk.models.json.capabilities.SpreedCapability
4646
import com.nextcloud.talk.models.json.participants.Participant
4747
import com.nextcloud.talk.utils.CapabilitiesUtil
48+
import com.nextcloud.talk.utils.ConversationUtils
4849
import com.nextcloud.talk.utils.ParticipantRole
4950
import com.nextcloud.talk.utils.ParticipantRoleUtils
5051

5152
private data class RemoveOption(@DrawableRes val iconRes: Int, val label: String)
5253

5354
private data class ParticipantOpsVisibility(
54-
val infoPin: String?,
55-
val showPromote: Boolean,
56-
val showDemote: Boolean,
57-
val showPromoteToOwner: Boolean,
58-
val showDemoteOwnerToModerator: Boolean,
59-
val showDemoteOwnerToUser: Boolean,
60-
val remove: RemoveOption?,
61-
val showBan: Boolean
55+
val infoPin: String? = null,
56+
val showPromote: Boolean = false,
57+
val showDemote: Boolean = false,
58+
val showPromoteToOwner: Boolean = false,
59+
val showDemoteOwnerToModerator: Boolean = false,
60+
val showDemoteOwnerToUser: Boolean = false,
61+
val remove: RemoveOption? = null,
62+
val showBan: Boolean = false
6263
)
6364

6465
@Composable
@@ -73,8 +74,12 @@ private fun computeVisibility(
7374
val deleteIcon = R.drawable.ic_delete_grey600_24dp
7475
val canDemoteFromOwner = ParticipantRoleUtils.canBeDemotedFromOwner(participant, conversation, spreedCapabilities)
7576
val isOwner = participant.type == Participant.ParticipantType.OWNER
77+
val canModerate = conversation != null && ConversationUtils.canModerate(conversation, spreedCapabilities)
7678

7779
return when {
80+
// Without moderation rights the sheet is informational: the header and nothing else
81+
!canModerate -> ParticipantOpsVisibility()
82+
7883
model.isSelf -> ParticipantOpsVisibility(
7984
infoPin = null,
8085
showPromote = false,
@@ -352,6 +357,25 @@ private fun ParticipantOperationsSheetUserWithPinPreview() {
352357
}
353358
}
354359

360+
/** Without moderation rights the sheet only names the participant and their rank. */
361+
@Preview(showBackground = true, name = "Light")
362+
@Preview(showBackground = true, name = "Dark", uiMode = Configuration.UI_MODE_NIGHT_YES)
363+
@Composable
364+
private fun ParticipantOperationsSheetInformationalPreview() {
365+
ParticipantOpsPreviewWrapper {
366+
ParticipantOperationsContent(
367+
model = previewParticipant(
368+
"Alice Johnson",
369+
Participant.ParticipantType.OWNER,
370+
ParticipantRole.OWNER
371+
),
372+
conversation = null,
373+
spreedCapabilities = null,
374+
onAction = {}
375+
)
376+
}
377+
}
378+
355379
@Preview(showBackground = true, name = "Light")
356380
@Preview(showBackground = true, name = "Dark", uiMode = Configuration.UI_MODE_NIGHT_YES)
357381
@Composable

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -469,8 +469,7 @@ How to translate with transifex:
469469
<!-- Shown when the server refuses to change a participant's rank -->
470470
<string name="nc_participant_type_change_failed">Could not change the type of the participant</string>
471471
<!-- Shown when demoting would leave the conversation without any moderator -->
472-
<string name="nc_last_moderator_cannot_be_demoted">The last moderator of a conversation can not be
473-
demoted</string>
472+
<string name="nc_last_moderator_cannot_be_demoted">The last moderator of a conversation can not be demoted</string>
474473
<string name="nc_remove_participant">Remove participant</string>
475474
<string name="nc_remove_team_and_members">Remove team and members</string>
476475
<string name="nc_remove_group_and_members">Remove group and members</string>

0 commit comments

Comments
 (0)