change(space settings): manage permissions

This commit is contained in:
ganfra
2025-12-10 13:44:46 +01:00
parent de52c991fe
commit dfc3ebb718
6 changed files with 62 additions and 8 deletions

View File

@@ -17,11 +17,14 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import dev.zacsweers.metro.Inject
import im.vector.app.features.analytics.plan.JoinedRoom
import im.vector.app.features.analytics.plan.JoinedRoom.Trigger
import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.features.invite.api.SeenInvitesStore
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteState
import io.element.android.features.invite.api.toInviteData
import io.element.android.features.space.impl.settings.SpaceSettingsPermissions
import io.element.android.features.space.impl.settings.spaceSettingsPermissions
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.coroutine.mapState
@@ -33,6 +36,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
import io.element.android.libraries.matrix.api.spaces.SpaceRoomList
import io.element.android.libraries.matrix.ui.safety.rememberHideInvitesAvatar
@@ -50,6 +54,7 @@ import kotlin.jvm.optionals.getOrNull
@Inject
class SpacePresenter(
private val spaceRoomList: SpaceRoomList,
private val room: JoinedRoom,
private val client: MatrixClient,
private val seenInvitesStore: SeenInvitesStore,
private val joinRoom: JoinRoom,
@@ -82,6 +87,9 @@ class SpacePresenter(
}
}.collectAsState()
val permissions by room.permissionsAsState(SpaceSettingsPermissions.DEFAULT) { perms ->
perms.spaceSettingsPermissions()
}
val isSpaceSettingsEnabled by remember {
featureFlagService.isFeatureEnabledFlow(FeatureFlags.SpaceSettings)
}.collectAsState(false)
@@ -136,7 +144,7 @@ class SpacePresenter(
joinActions = joinActions.toImmutableMap(),
acceptDeclineInviteState = acceptDeclineInviteState,
topicViewerState = topicViewerState,
canAccessSpaceSettings = isSpaceSettingsEnabled,
canAccessSpaceSettings = isSpaceSettingsEnabled && permissions.hasAny,
eventSink = ::handleEvent,
)
}
@@ -150,7 +158,7 @@ class SpacePresenter(
joinRoom.invoke(
roomIdOrAlias = spaceRoom.roomId.toRoomIdOrAlias(),
serverNames = spaceRoom.via,
trigger = JoinedRoom.Trigger.SpaceHierarchy,
trigger = Trigger.SpaceHierarchy,
).onFailure {
setJoinActions(joinActions + mapOf(spaceRoom.roomId to AsyncAction.Failure(it)))
}

View File

@@ -0,0 +1,38 @@
/*
* 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.space.impl.settings
import io.element.android.features.roomdetailsedit.api.roomDetailsEditPermissions
import io.element.android.features.securityandprivacy.api.securityAndPrivacyPermissions
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
data class SpaceSettingsPermissions(
val canEditDetails: Boolean,
val canManageRolesAndPermissions: Boolean,
val canManageSecurityAndPrivacy: Boolean,
){
val hasAny = canEditDetails || canManageRolesAndPermissions || canManageSecurityAndPrivacy
companion object {
val DEFAULT = SpaceSettingsPermissions(
canEditDetails = false,
canManageRolesAndPermissions = false,
canManageSecurityAndPrivacy = false,
)
}
}
fun RoomPermissions.spaceSettingsPermissions(): SpaceSettingsPermissions {
return SpaceSettingsPermissions(
canEditDetails = roomDetailsEditPermissions().hasAny,
canManageRolesAndPermissions = canOwnUserSendState(StateEventType.ROOM_POWER_LEVELS),
canManageSecurityAndPrivacy = securityAndPrivacyPermissions().hasAny,
)
}

View File

@@ -14,7 +14,7 @@ import androidx.compose.runtime.getValue
import dev.zacsweers.metro.Inject
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.matrix.ui.room.isOwnUserAdmin
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
@Inject
class SpaceSettingsPresenter(
@@ -23,15 +23,18 @@ class SpaceSettingsPresenter(
@Composable
override fun present(): SpaceSettingsState {
val roomInfo by room.roomInfoFlow.collectAsState()
val isUserAdmin = room.isOwnUserAdmin()
val permissions by room.permissionsAsState(SpaceSettingsPermissions.DEFAULT) { perms ->
perms.spaceSettingsPermissions()
}
return SpaceSettingsState(
roomId = room.roomId,
name = roomInfo.name.orEmpty(),
canonicalAlias = roomInfo.canonicalAlias,
avatarUrl = roomInfo.avatarUrl,
memberCount = roomInfo.activeMembersCount,
showRolesAndPermissions = isUserAdmin,
showSecurityAndPrivacy = isUserAdmin,
canEditDetails = permissions.canEditDetails,
showRolesAndPermissions = permissions.canManageRolesAndPermissions,
showSecurityAndPrivacy = permissions.canManageSecurityAndPrivacy,
eventSink = {},
)
}

View File

@@ -17,6 +17,7 @@ data class SpaceSettingsState(
val canonicalAlias: RoomAlias?,
val avatarUrl: String?,
val memberCount: Long,
val canEditDetails: Boolean,
val showRolesAndPermissions: Boolean,
val showSecurityAndPrivacy: Boolean,
val eventSink: (SpaceSettingsEvents) -> Unit

View File

@@ -30,6 +30,7 @@ fun aSpaceSettingsState(
memberCount: Long = 100,
showRolesAndPermissions: Boolean = false,
showSecurityAndPrivacy: Boolean = false,
canEditDetails: Boolean = false,
eventSink: (SpaceSettingsEvents) -> Unit = {},
) = SpaceSettingsState(
roomId = roomId,
@@ -37,6 +38,7 @@ fun aSpaceSettingsState(
canonicalAlias = alias,
avatarUrl = avatarUrl,
memberCount = memberCount,
canEditDetails = canEditDetails,
showRolesAndPermissions = showRolesAndPermissions,
showSecurityAndPrivacy = showSecurityAndPrivacy,
eventSink = eventSink,

View File

@@ -73,6 +73,7 @@ fun SpaceSettingsView(
name = state.name,
avatarUrl = state.avatarUrl,
canonicalAlias = state.canonicalAlias?.value,
canEditDetails = state.canEditDetails,
onSpaceInfoClick = onSpaceInfoClick,
)
Section(isVisible = state.showSecurityAndPrivacy, content = {
@@ -101,12 +102,13 @@ private fun SpaceInfoSection(
name: String,
avatarUrl: String?,
canonicalAlias: String?,
canEditDetails: Boolean,
onSpaceInfoClick: () -> Unit,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onSpaceInfoClick)
.clickable(enabled = canEditDetails, onClick = onSpaceInfoClick)
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
) {