mirror of
https://github.com/vector-im/riotX-android
synced 2025-10-05 15:52:47 +02:00
change (power level) : support new InfinitePowerLevel (first draft)
This commit is contained in:
@@ -120,6 +120,7 @@
|
||||
<string name="notice_widget_modified">%1$s modified %2$s widget</string>
|
||||
<string name="notice_widget_modified_by_you">You modified %1$s widget</string>
|
||||
|
||||
<string name="power_level_owner">Owner</string>
|
||||
<string name="power_level_admin">Admin</string>
|
||||
<string name="power_level_moderator">Moderator</string>
|
||||
<string name="power_level_default">Default</string>
|
||||
@@ -2383,6 +2384,7 @@
|
||||
<string name="room_member_power_level_invites">Invites</string>
|
||||
<string name="room_member_power_level_users">Users</string>
|
||||
|
||||
<string name="room_member_power_level_owner_in">Owner in %1$s</string>
|
||||
<string name="room_member_power_level_admin_in">Admin in %1$s</string>
|
||||
<string name="room_member_power_level_moderator_in">Moderator in %1$s</string>
|
||||
<string name="room_member_power_level_default_in">Default in %1$s</string>
|
||||
|
@@ -40,7 +40,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RestrictedRoomPreset
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.common.CommonTestHelper.Companion.runSessionTest
|
||||
@@ -500,12 +500,12 @@ class SpaceHierarchyTest : InstrumentedTest {
|
||||
room.stateService().sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent!!)
|
||||
|
||||
commonTestHelper.retryPeriodically {
|
||||
val powerLevelsHelper = aliceSession.getRoom(bobRoomId)!!
|
||||
val roomPowerLevels = aliceSession.getRoom(bobRoomId)!!
|
||||
.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
|
||||
?.content
|
||||
?.toModel<PowerLevelsContent>()
|
||||
?.let { PowerLevelsHelper(it) }
|
||||
powerLevelsHelper!!.isUserAllowedToSend(aliceSession.myUserId, true, EventType.STATE_SPACE_PARENT)
|
||||
?.let { RoomPowerLevels(it) }
|
||||
roomPowerLevels!!.isUserAllowedToSend(aliceSession.myUserId, true, EventType.STATE_SPACE_PARENT)
|
||||
}
|
||||
|
||||
aliceSession.spaceService().setSpaceParent(bobRoomId, spaceAInfo.spaceId, false, listOf(bobSession.sessionParams.homeServerHost ?: ""))
|
||||
|
@@ -16,8 +16,7 @@
|
||||
package org.matrix.android.sdk.api.session.pushrules
|
||||
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
|
||||
class SenderNotificationPermissionCondition(
|
||||
/**
|
||||
@@ -35,8 +34,7 @@ class SenderNotificationPermissionCondition(
|
||||
|
||||
override fun technicalDescription() = "User power level <$key>"
|
||||
|
||||
fun isSatisfied(event: Event, powerLevels: PowerLevelsContent): Boolean {
|
||||
val powerLevelsHelper = PowerLevelsHelper(powerLevels)
|
||||
return event.senderId != null && powerLevelsHelper.getUserPowerLevelValue(event.senderId) >= powerLevels.notificationLevel(key)
|
||||
fun isSatisfied(event: Event, roomPowerLevels: RoomPowerLevels): Boolean {
|
||||
return event.senderId != null && roomPowerLevels.isUserAbleToTriggerNotification(event.senderId, key)
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,13 @@
|
||||
package org.matrix.android.sdk.api.session.room
|
||||
|
||||
import org.matrix.android.sdk.api.query.QueryStateEventValue
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.create.getRoomCreateContentWithSender
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
|
||||
/**
|
||||
@@ -34,3 +40,15 @@ fun Room.getTimelineEvent(eventId: String): TimelineEvent? =
|
||||
*/
|
||||
fun Room.getStateEvent(eventType: String, stateKey: QueryStateEventValue): Event? =
|
||||
stateService().getStateEvent(eventType, stateKey)
|
||||
|
||||
/**
|
||||
* Get the current RoomPowerLevels of the room.
|
||||
*/
|
||||
fun Room.getRoomPowerLevels(): RoomPowerLevels {
|
||||
val powerLevelsContent = getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)?.content?.toModel<PowerLevelsContent>()
|
||||
val roomCreateContent = getStateEvent(EventType.STATE_ROOM_CREATE, QueryStringValue.IsEmpty)?.getRoomCreateContentWithSender()
|
||||
return RoomPowerLevels(
|
||||
powerLevelsContent,
|
||||
roomCreateContent
|
||||
)
|
||||
}
|
||||
|
@@ -18,7 +18,8 @@ package org.matrix.android.sdk.api.session.room.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent.Companion.NOTIFICATIONS_ROOM_KEY
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.UserPowerLevel
|
||||
|
||||
/**
|
||||
* Class representing the EventType.EVENT_TYPE_STATE_ROOM_POWER_LEVELS state event content.
|
||||
@@ -88,7 +89,7 @@ data class PowerLevelsContent(
|
||||
* Get the notification level for a dedicated key.
|
||||
*
|
||||
* @param key the notification key
|
||||
* @return the level, default to Moderator if the key is not found
|
||||
* @return the level
|
||||
*/
|
||||
fun notificationLevel(key: String): Int {
|
||||
return when (val value = notifications.orEmpty()[key]) {
|
||||
@@ -96,10 +97,9 @@ data class PowerLevelsContent(
|
||||
is String -> value.toInt()
|
||||
is Double -> value.toInt()
|
||||
is Int -> value
|
||||
else -> Role.Moderator.value
|
||||
else -> defaultNotificationLevel(key)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Key to use for content.notifications and get the level required to trigger an @room notification. Defaults to 50 if unspecified.
|
||||
@@ -108,11 +108,21 @@ data class PowerLevelsContent(
|
||||
}
|
||||
}
|
||||
|
||||
private fun defaultNotificationLevel(key: String): Int {
|
||||
return when (key) {
|
||||
NOTIFICATIONS_ROOM_KEY -> UserPowerLevel.Moderator.value
|
||||
else -> UserPowerLevel.User.value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Fallback to default value, defined in the Matrix specification
|
||||
fun PowerLevelsContent.banOrDefault() = ban ?: Role.Moderator.value
|
||||
fun PowerLevelsContent.kickOrDefault() = kick ?: Role.Moderator.value
|
||||
fun PowerLevelsContent.inviteOrDefault() = invite ?: Role.Moderator.value
|
||||
fun PowerLevelsContent.redactOrDefault() = redact ?: Role.Moderator.value
|
||||
fun PowerLevelsContent.eventsDefaultOrDefault() = eventsDefault ?: Role.Default.value
|
||||
fun PowerLevelsContent.usersDefaultOrDefault() = usersDefault ?: Role.Default.value
|
||||
fun PowerLevelsContent.stateDefaultOrDefault() = stateDefault ?: Role.Moderator.value
|
||||
fun PowerLevelsContent?.banOrDefault() = this?.ban ?: UserPowerLevel.Moderator.value
|
||||
fun PowerLevelsContent?.kickOrDefault() = this?.kick ?: UserPowerLevel.Moderator.value
|
||||
fun PowerLevelsContent?.inviteOrDefault() = this?.invite ?: UserPowerLevel.User.value
|
||||
fun PowerLevelsContent?.redactOrDefault() = this?.redact ?: UserPowerLevel.Moderator.value
|
||||
fun PowerLevelsContent?.eventsDefaultOrDefault() = this?.eventsDefault ?: UserPowerLevel.User.value
|
||||
fun PowerLevelsContent?.usersDefaultOrDefault() = this?.usersDefault ?: UserPowerLevel.User.value
|
||||
fun PowerLevelsContent?.stateDefaultOrDefault() = this?.stateDefault ?: UserPowerLevel.Moderator.value
|
||||
|
||||
fun PowerLevelsContent?.notificationLevelOrDefault(key: String) = this?.notificationLevel(key) ?: defaultNotificationLevel(key)
|
||||
|
@@ -18,15 +18,39 @@ package org.matrix.android.sdk.api.session.room.model.create
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
|
||||
/**
|
||||
* Content of a m.room.create type event.
|
||||
*/
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class RoomCreateContent(
|
||||
// Creator should be replaced by the sender of the event
|
||||
@Json(name = "creator") val creator: String? = null,
|
||||
@Json(name = "room_version") val roomVersion: String? = null,
|
||||
@Json(name = "predecessor") val predecessor: Predecessor? = null,
|
||||
// Defines the room type, see #RoomType (user extensible)
|
||||
@Json(name = "type") val type: String? = null
|
||||
@Json(name = "type") val type: String? = null,
|
||||
@Json(name = "additional_creators") val additionalCreators: List<String>? = null,
|
||||
)
|
||||
|
||||
data class RoomCreateContentWithSender(
|
||||
val senderId: String,
|
||||
val inner: RoomCreateContent
|
||||
) {
|
||||
val creators = setOf(senderId) + inner.additionalCreators.orEmpty().toSet()
|
||||
}
|
||||
|
||||
fun Event.getRoomCreateContentWithSender(): RoomCreateContentWithSender? {
|
||||
if (this.type != EventType.STATE_ROOM_CREATE) return null
|
||||
val innerContent = getClearContent().toModel<RoomCreateContent>() ?: return null
|
||||
val senderId = senderId ?: return null
|
||||
return RoomCreateContentWithSender(senderId, innerContent)
|
||||
}
|
||||
|
||||
fun RoomCreateContent.explicitlyPrivilegeRoomCreators(): Boolean {
|
||||
val supportedRoomVersions = listOf("org.matrix.hydra.11", "12")
|
||||
return supportedRoomVersions.contains(roomVersion)
|
||||
}
|
||||
|
@@ -17,26 +17,22 @@
|
||||
|
||||
package org.matrix.android.sdk.api.session.room.powerlevels
|
||||
|
||||
sealed class Role(open val value: Int) : Comparable<Role> {
|
||||
object Admin : Role(100)
|
||||
object Moderator : Role(50)
|
||||
object Default : Role(0)
|
||||
data class Custom(override val value: Int) : Role(value)
|
||||
enum class Role {
|
||||
Creator,
|
||||
SuperAdmin,
|
||||
Admin,
|
||||
Moderator,
|
||||
User;
|
||||
|
||||
override fun compareTo(other: Role): Int {
|
||||
return value.compareTo(other.value)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
// Order matters, default value should be checked after defined roles
|
||||
fun fromValue(value: Int, default: Int): Role {
|
||||
return when (value) {
|
||||
Admin.value -> Admin
|
||||
Moderator.value -> Moderator
|
||||
Default.value,
|
||||
default -> Default
|
||||
else -> Custom(value)
|
||||
fun getSuggestedRole(userPowerLevel: UserPowerLevel): Role {
|
||||
return when {
|
||||
userPowerLevel == UserPowerLevel.Infinite -> Creator
|
||||
userPowerLevel >= UserPowerLevel.SuperAdmin -> SuperAdmin
|
||||
userPowerLevel >= UserPowerLevel.Admin -> Admin
|
||||
userPowerLevel >= UserPowerLevel.Moderator -> Moderator
|
||||
else -> User
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -19,17 +19,23 @@ package org.matrix.android.sdk.api.session.room.powerlevels
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.banOrDefault
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContentWithSender
|
||||
import org.matrix.android.sdk.api.session.room.model.create.explicitlyPrivilegeRoomCreators
|
||||
import org.matrix.android.sdk.api.session.room.model.eventsDefaultOrDefault
|
||||
import org.matrix.android.sdk.api.session.room.model.inviteOrDefault
|
||||
import org.matrix.android.sdk.api.session.room.model.kickOrDefault
|
||||
import org.matrix.android.sdk.api.session.room.model.notificationLevelOrDefault
|
||||
import org.matrix.android.sdk.api.session.room.model.redactOrDefault
|
||||
import org.matrix.android.sdk.api.session.room.model.stateDefaultOrDefault
|
||||
import org.matrix.android.sdk.api.session.room.model.usersDefaultOrDefault
|
||||
|
||||
/**
|
||||
* This class is an helper around PowerLevelsContent.
|
||||
* This class is an helper around PowerLevelsContent and RoomCreateContent.
|
||||
*/
|
||||
class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
||||
class RoomPowerLevels(
|
||||
val powerLevelsContent: PowerLevelsContent?,
|
||||
private val roomCreateContent: RoomCreateContentWithSender?,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Returns the user power level of a dedicated user Id.
|
||||
@@ -37,10 +43,14 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
||||
* @param userId the user id
|
||||
* @return the power level
|
||||
*/
|
||||
fun getUserPowerLevelValue(userId: String): Int {
|
||||
return powerLevelsContent.users
|
||||
fun getUserPowerLevel(userId: String): UserPowerLevel {
|
||||
if (shouldGiveInfinitePowerLevel(userId)) return UserPowerLevel.Infinite
|
||||
if (powerLevelsContent == null) return UserPowerLevel.User
|
||||
val value = powerLevelsContent.users
|
||||
?.get(userId)
|
||||
?: powerLevelsContent.usersDefaultOrDefault()
|
||||
|
||||
return UserPowerLevel.Value(value)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,9 +60,8 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
||||
* @return the power level
|
||||
*/
|
||||
fun getUserRole(userId: String): Role {
|
||||
val value = getUserPowerLevelValue(userId)
|
||||
// I think we should use powerLevelsContent.usersDefault, but Ganfra told me that it was like that on riot-Web
|
||||
return Role.fromValue(value, powerLevelsContent.eventsDefaultOrDefault())
|
||||
val value = getUserPowerLevel(userId)
|
||||
return Role.getSuggestedRole(value)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,14 +74,14 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
||||
*/
|
||||
fun isUserAllowedToSend(userId: String, isState: Boolean, eventType: String?): Boolean {
|
||||
return if (userId.isNotEmpty()) {
|
||||
val powerLevel = getUserPowerLevelValue(userId)
|
||||
val minimumPowerLevel = powerLevelsContent.events?.get(eventType)
|
||||
val powerLevel = getUserPowerLevel(userId)
|
||||
val minimumPowerLevel = powerLevelsContent?.events?.get(eventType)
|
||||
?: if (isState) {
|
||||
powerLevelsContent.stateDefaultOrDefault()
|
||||
} else {
|
||||
powerLevelsContent.eventsDefaultOrDefault()
|
||||
}
|
||||
powerLevel >= minimumPowerLevel
|
||||
powerLevel >= UserPowerLevel.Value(minimumPowerLevel)
|
||||
} else false
|
||||
}
|
||||
|
||||
@@ -82,8 +91,8 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
||||
* @return true if able to invite
|
||||
*/
|
||||
fun isUserAbleToInvite(userId: String): Boolean {
|
||||
val powerLevel = getUserPowerLevelValue(userId)
|
||||
return powerLevel >= powerLevelsContent.inviteOrDefault()
|
||||
val powerLevel = getUserPowerLevel(userId)
|
||||
return powerLevel >= UserPowerLevel.Value(powerLevelsContent.inviteOrDefault())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,8 +101,8 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
||||
* @return true if able to ban
|
||||
*/
|
||||
fun isUserAbleToBan(userId: String): Boolean {
|
||||
val powerLevel = getUserPowerLevelValue(userId)
|
||||
return powerLevel >= powerLevelsContent.banOrDefault()
|
||||
val powerLevel = getUserPowerLevel(userId)
|
||||
return powerLevel >= UserPowerLevel.Value(powerLevelsContent.banOrDefault())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,8 +111,8 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
||||
* @return true if able to kick
|
||||
*/
|
||||
fun isUserAbleToKick(userId: String): Boolean {
|
||||
val powerLevel = getUserPowerLevelValue(userId)
|
||||
return powerLevel >= powerLevelsContent.kickOrDefault()
|
||||
val powerLevel = getUserPowerLevel(userId)
|
||||
return powerLevel >= UserPowerLevel.Value(powerLevelsContent.kickOrDefault())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +121,22 @@ class PowerLevelsHelper(private val powerLevelsContent: PowerLevelsContent) {
|
||||
* @return true if able to redact
|
||||
*/
|
||||
fun isUserAbleToRedact(userId: String): Boolean {
|
||||
val powerLevel = getUserPowerLevelValue(userId)
|
||||
return powerLevel >= powerLevelsContent.redactOrDefault()
|
||||
val powerLevel = getUserPowerLevel(userId)
|
||||
return powerLevel >= UserPowerLevel.Value(powerLevelsContent.redactOrDefault())
|
||||
}
|
||||
|
||||
fun isUserAbleToTriggerNotification(userId: String, notificationKey: String): Boolean {
|
||||
val userPowerLevel = getUserPowerLevel(userId)
|
||||
val notificationPowerLevel = UserPowerLevel.Value(powerLevelsContent.notificationLevelOrDefault(key = notificationKey))
|
||||
return userPowerLevel >= notificationPowerLevel
|
||||
}
|
||||
|
||||
private fun shouldGiveInfinitePowerLevel(userId: String): Boolean {
|
||||
if (roomCreateContent == null) return false
|
||||
return if (roomCreateContent.inner.explicitlyPrivilegeRoomCreators()) {
|
||||
roomCreateContent.creators.contains(userId)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.api.session.room.powerlevels
|
||||
|
||||
sealed interface UserPowerLevel : Comparable<UserPowerLevel> {
|
||||
data object Infinite : UserPowerLevel
|
||||
|
||||
@JvmInline
|
||||
value class Value(val value: Int) : UserPowerLevel
|
||||
|
||||
override fun compareTo(other: UserPowerLevel): Int {
|
||||
return when (this) {
|
||||
Infinite -> when (other) {
|
||||
Infinite -> 0
|
||||
is Value -> 1
|
||||
}
|
||||
is Value -> when (other) {
|
||||
Infinite -> -1
|
||||
is Value -> value.compareTo(other.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val User = Value(0)
|
||||
val Moderator = Value(50)
|
||||
val Admin = Value(100)
|
||||
val SuperAdmin = Value(150)
|
||||
}
|
||||
}
|
@@ -17,15 +17,11 @@
|
||||
package org.matrix.android.sdk.internal.session.permalinks
|
||||
|
||||
import org.matrix.android.sdk.api.MatrixPatterns.getServerName
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.room.RoomGetter
|
||||
import org.matrix.android.sdk.internal.session.room.powerlevels.getRoomPowerLevels
|
||||
import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
|
||||
import java.net.URLEncoder
|
||||
import javax.inject.Inject
|
||||
@@ -101,10 +97,7 @@ internal class ViaParameterFinder @Inject constructor(
|
||||
}
|
||||
|
||||
fun userCanInvite(userId: String, roomId: String): Boolean {
|
||||
val powerLevelsHelper = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
|
||||
?.content?.toModel<PowerLevelsContent>()
|
||||
?.let { PowerLevelsHelper(it) }
|
||||
|
||||
return powerLevelsHelper?.isUserAbleToInvite(userId) ?: false
|
||||
val roomPowerLevels = stateEventDataSource.getRoomPowerLevels(roomId)
|
||||
return roomPowerLevels.isUserAbleToInvite(userId)
|
||||
}
|
||||
}
|
||||
|
@@ -24,15 +24,20 @@ import org.matrix.android.sdk.api.session.pushrules.ContainsDisplayNameCondition
|
||||
import org.matrix.android.sdk.api.session.pushrules.EventMatchCondition
|
||||
import org.matrix.android.sdk.api.session.pushrules.RoomMemberCountCondition
|
||||
import org.matrix.android.sdk.api.session.pushrules.SenderNotificationPermissionCondition
|
||||
import org.matrix.android.sdk.api.session.room.getRoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.getStateEvent
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.create.getRoomCreateContentWithSender
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.room.RoomGetter
|
||||
import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultConditionResolver @Inject constructor(
|
||||
private val roomGetter: RoomGetter,
|
||||
@UserId private val userId: String
|
||||
@UserId private val userId: String,
|
||||
private val stateEventDataSource: StateEventDataSource,
|
||||
) : ConditionResolver {
|
||||
|
||||
override fun resolveEventMatchCondition(
|
||||
@@ -55,13 +60,8 @@ internal class DefaultConditionResolver @Inject constructor(
|
||||
): Boolean {
|
||||
val roomId = event.roomId ?: return false
|
||||
val room = roomGetter.getRoom(roomId) ?: return false
|
||||
|
||||
val powerLevelsContent = room.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
|
||||
?.content
|
||||
?.toModel<PowerLevelsContent>()
|
||||
?: PowerLevelsContent()
|
||||
|
||||
return condition.isSatisfied(event, powerLevelsContent)
|
||||
val roomPowerLevels = room.getRoomPowerLevels()
|
||||
return condition.isSatisfied(event, roomPowerLevels)
|
||||
}
|
||||
|
||||
override fun resolveContainsDisplayNameCondition(
|
||||
|
@@ -16,7 +16,6 @@
|
||||
package org.matrix.android.sdk.internal.session.room
|
||||
|
||||
import io.realm.Realm
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationState
|
||||
import org.matrix.android.sdk.api.session.events.model.AggregatedAnnotation
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
@@ -27,7 +26,6 @@ import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventCon
|
||||
import org.matrix.android.sdk.api.session.events.model.getRelationContent
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
|
||||
@@ -36,7 +34,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.ReactionContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.internal.SessionManager
|
||||
import org.matrix.android.sdk.internal.crypto.verification.toState
|
||||
import org.matrix.android.sdk.internal.database.helper.findRootThreadEvent
|
||||
@@ -62,6 +60,7 @@ import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor
|
||||
import org.matrix.android.sdk.internal.session.room.aggregation.livelocation.LiveLocationAggregationProcessor
|
||||
import org.matrix.android.sdk.internal.session.room.aggregation.poll.PollAggregationProcessor
|
||||
import org.matrix.android.sdk.internal.session.room.aggregation.utd.EncryptedReferenceAggregationProcessor
|
||||
import org.matrix.android.sdk.internal.session.room.powerlevels.getRoomPowerLevels
|
||||
import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
|
||||
import org.matrix.android.sdk.internal.util.time.Clock
|
||||
import timber.log.Timber
|
||||
@@ -216,9 +215,8 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
||||
}
|
||||
in EventType.POLL_END.values -> {
|
||||
sessionManager.getSessionComponent(sessionId)?.session()?.let { session ->
|
||||
getPowerLevelsHelper(event.roomId)?.let {
|
||||
pollAggregationProcessor.handlePollEndEvent(session, it, realm, event)
|
||||
}
|
||||
val roomPowerLevels = stateEventDataSource.getRoomPowerLevels(event.roomId)
|
||||
pollAggregationProcessor.handlePollEndEvent(session, roomPowerLevels, realm, event)
|
||||
}
|
||||
}
|
||||
in EventType.STATE_ROOM_BEACON_INFO.values -> {
|
||||
@@ -381,12 +379,6 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPowerLevelsHelper(roomId: String): PowerLevelsHelper? {
|
||||
return stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
|
||||
?.content?.toModel<PowerLevelsContent>()
|
||||
?.let { PowerLevelsHelper(it) }
|
||||
}
|
||||
|
||||
private fun handleInitialAggregatedRelations(
|
||||
realm: Realm,
|
||||
event: Event,
|
||||
|
@@ -32,7 +32,7 @@ import org.matrix.android.sdk.api.session.room.model.VoteInfo
|
||||
import org.matrix.android.sdk.api.session.room.model.VoteSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponseContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
|
||||
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
|
||||
@@ -160,13 +160,13 @@ internal class DefaultPollAggregationProcessor @Inject constructor(
|
||||
return true
|
||||
}
|
||||
|
||||
override fun handlePollEndEvent(session: Session, powerLevelsHelper: PowerLevelsHelper, realm: Realm, event: Event): Boolean {
|
||||
override fun handlePollEndEvent(session: Session, roomPowerLevels: RoomPowerLevels, realm: Realm, event: Event): Boolean {
|
||||
val roomId = event.roomId ?: return false
|
||||
val pollEventId = event.getRelationContent()?.eventId ?: return false
|
||||
val pollOwnerId = getPollEvent(session, roomId, pollEventId)?.root?.senderId
|
||||
val isPollOwner = pollOwnerId == event.senderId
|
||||
|
||||
if (!isPollOwner && !powerLevelsHelper.isUserAbleToRedact(event.senderId ?: "")) {
|
||||
if (!isPollOwner && !roomPowerLevels.isUserAbleToRedact(event.senderId ?: "")) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,7 @@ package org.matrix.android.sdk.internal.session.room.aggregation.poll
|
||||
import io.realm.Realm
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
|
||||
internal interface PollAggregationProcessor {
|
||||
/**
|
||||
@@ -48,7 +48,7 @@ internal interface PollAggregationProcessor {
|
||||
*/
|
||||
fun handlePollEndEvent(
|
||||
session: Session,
|
||||
powerLevelsHelper: PowerLevelsHelper,
|
||||
roomPowerLevels: RoomPowerLevels,
|
||||
realm: Realm,
|
||||
event: Event
|
||||
): Boolean
|
||||
|
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.room.powerlevels
|
||||
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.create.getRoomCreateContentWithSender
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
|
||||
|
||||
internal fun StateEventDataSource.getRoomPowerLevels(roomId: String): RoomPowerLevels {
|
||||
val powerLevelsContent = getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
|
||||
?.content?.toModel<PowerLevelsContent>()
|
||||
val roomCreateContent = getStateEvent(roomId, EventType.STATE_ROOM_CREATE, QueryStringValue.IsEmpty)?.getRoomCreateContentWithSender()
|
||||
return RoomPowerLevels(powerLevelsContent, roomCreateContent)
|
||||
}
|
@@ -96,3 +96,4 @@ internal class StateEventDataSource @Inject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -34,7 +34,8 @@ import org.matrix.android.sdk.api.session.room.model.RoomTopicContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||
import org.matrix.android.sdk.api.session.room.model.VersioningState
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContentWithSender
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
import org.matrix.android.sdk.api.session.sync.model.RoomSyncSummary
|
||||
import org.matrix.android.sdk.api.session.sync.model.RoomSyncUnreadNotifications
|
||||
@@ -313,13 +314,25 @@ internal class RoomSummaryUpdater @Inject constructor(
|
||||
// check if sender can post child relation in parent?
|
||||
val senderId = parentInfo.stateEventSender
|
||||
val parentRoomId = parentInfo.roomId
|
||||
val powerLevelsHelper = CurrentStateEventEntity
|
||||
val powerLevelsContent = CurrentStateEventEntity
|
||||
.getOrNull(realm, parentRoomId, "", EventType.STATE_ROOM_POWER_LEVELS)
|
||||
?.root
|
||||
?.let { ContentMapper.map(it.content).toModel<PowerLevelsContent>() }
|
||||
?.let { PowerLevelsHelper(it) }
|
||||
|
||||
isValidRelation = powerLevelsHelper?.isUserAllowedToSend(senderId, true, EventType.STATE_SPACE_CHILD) ?: false
|
||||
val roomCreateContent = CurrentStateEventEntity
|
||||
.getOrNull(realm, parentRoomId, "", EventType.STATE_ROOM_CREATE)
|
||||
?.root
|
||||
?.let {
|
||||
val content = ContentMapper.map(it.content).toModel<RoomCreateContent>()
|
||||
val sender = it.sender
|
||||
if (content != null && sender != null) {
|
||||
RoomCreateContentWithSender(sender, content)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
val roomPowerLevels = RoomPowerLevels(powerLevelsContent, roomCreateContent)
|
||||
isValidRelation = roomPowerLevels.isUserAllowedToSend(senderId, true, EventType.STATE_SPACE_CHILD)
|
||||
}
|
||||
|
||||
if (isValidRelation) {
|
||||
|
@@ -25,7 +25,8 @@ import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.homeserver.RoomVersionStatus
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.model.create.getRoomCreateContentWithSender
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.version.RoomVersionService
|
||||
import org.matrix.android.sdk.internal.session.homeserver.HomeServerCapabilitiesDataSource
|
||||
import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
|
||||
@@ -71,11 +72,17 @@ internal class DefaultRoomVersionService @AssistedInject constructor(
|
||||
}
|
||||
|
||||
override fun userMayUpgradeRoom(userId: String): Boolean {
|
||||
val powerLevelsHelper = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
|
||||
val powerLevelsContent = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
|
||||
?.content?.toModel<PowerLevelsContent>()
|
||||
?.let { PowerLevelsHelper(it) }
|
||||
|
||||
return powerLevelsHelper?.isUserAllowedToSend(userId, true, EventType.STATE_ROOM_TOMBSTONE) ?: false
|
||||
val roomCreateContent = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_CREATE, QueryStringValue.IsEmpty)
|
||||
?.getRoomCreateContentWithSender()
|
||||
|
||||
val roomPowerLevels = RoomPowerLevels(
|
||||
powerLevelsContent = powerLevelsContent,
|
||||
roomCreateContent = roomCreateContent
|
||||
)
|
||||
return roomPowerLevels.isUserAllowedToSend(userId, true, EventType.STATE_ROOM_TOMBSTONE)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@@ -35,8 +35,9 @@ import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.UserPowerLevel
|
||||
import org.matrix.android.sdk.api.session.space.CreateSpaceParams
|
||||
import org.matrix.android.sdk.api.session.space.JoinSpaceResult
|
||||
import org.matrix.android.sdk.api.session.space.Space
|
||||
@@ -47,11 +48,13 @@ import org.matrix.android.sdk.api.session.space.model.SpaceChildContent
|
||||
import org.matrix.android.sdk.api.session.space.model.SpaceChildSummaryEvent
|
||||
import org.matrix.android.sdk.api.session.space.model.SpaceParentContent
|
||||
import org.matrix.android.sdk.api.session.space.peeking.SpacePeekResult
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.room.RoomGetter
|
||||
import org.matrix.android.sdk.internal.session.room.SpaceGetter
|
||||
import org.matrix.android.sdk.internal.session.room.create.CreateRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.membership.leaving.LeaveRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.powerlevels.getRoomPowerLevels
|
||||
import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
|
||||
import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource
|
||||
import org.matrix.android.sdk.internal.session.space.peeking.PeekSpaceTask
|
||||
@@ -83,7 +86,7 @@ internal class DefaultSpaceService @Inject constructor(
|
||||
if (isPublic) {
|
||||
this.roomAliasName = roomAliasLocalPart
|
||||
this.powerLevelContentOverride = (powerLevelContentOverride ?: PowerLevelsContent()).copy(
|
||||
invite = if (isPublic) Role.Default.value else Role.Moderator.value
|
||||
invite = UserPowerLevel.User.value
|
||||
)
|
||||
this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
|
||||
this.historyVisibility = RoomHistoryVisibility.WORLD_READABLE
|
||||
@@ -253,15 +256,8 @@ internal class DefaultSpaceService @Inject constructor(
|
||||
if (roomSummaryDataSource.getRoomSummary(parentSpaceId)?.membership != Membership.JOIN) {
|
||||
throw UnsupportedOperationException("Cannot add canonical child if not member of parent")
|
||||
}
|
||||
val powerLevelsEvent = stateEventDataSource.getStateEvent(
|
||||
roomId = parentSpaceId,
|
||||
eventType = EventType.STATE_ROOM_POWER_LEVELS,
|
||||
stateKey = QueryStringValue.IsEmpty
|
||||
)
|
||||
val powerLevelsContent = powerLevelsEvent?.content?.toModel<PowerLevelsContent>()
|
||||
?: throw UnsupportedOperationException("Cannot add canonical child, missing power level")
|
||||
val powerLevelsHelper = PowerLevelsHelper(powerLevelsContent)
|
||||
if (!powerLevelsHelper.isUserAllowedToSend(userId, true, EventType.STATE_SPACE_CHILD)) {
|
||||
val roomPowerLevels = stateEventDataSource.getRoomPowerLevels(parentSpaceId)
|
||||
if (!roomPowerLevels.isUserAllowedToSend(userId, true, EventType.STATE_SPACE_CHILD)) {
|
||||
throw UnsupportedOperationException("Cannot add canonical child, not enough power level")
|
||||
}
|
||||
}
|
||||
|
@@ -30,15 +30,13 @@ import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes
|
||||
import org.matrix.android.sdk.api.session.events.model.Content
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.widgets.WidgetManagementFailure
|
||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.session.SessionScope
|
||||
import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManager
|
||||
import org.matrix.android.sdk.internal.session.room.powerlevels.getRoomPowerLevels
|
||||
import org.matrix.android.sdk.internal.session.room.state.StateEventDataSource
|
||||
import org.matrix.android.sdk.internal.session.user.accountdata.UserAccountDataDataSource
|
||||
import org.matrix.android.sdk.internal.session.widgets.helper.WidgetFactory
|
||||
@@ -200,12 +198,7 @@ internal class WidgetManager @Inject constructor(
|
||||
}
|
||||
|
||||
fun hasPermissionsToHandleWidgets(roomId: String): Boolean {
|
||||
val powerLevelsEvent = stateEventDataSource.getStateEvent(
|
||||
roomId = roomId,
|
||||
eventType = EventType.STATE_ROOM_POWER_LEVELS,
|
||||
stateKey = QueryStringValue.IsEmpty
|
||||
)
|
||||
val powerLevelsContent = powerLevelsEvent?.content?.toModel<PowerLevelsContent>() ?: return false
|
||||
return PowerLevelsHelper(powerLevelsContent).isUserAllowedToSend(userId, true, EventType.STATE_ROOM_WIDGET_LEGACY)
|
||||
val roomPowerLevels = stateEventDataSource.getRoomPowerLevels(roomId)
|
||||
return roomPowerLevels.isUserAllowedToSend(userId, true, EventType.STATE_ROOM_WIDGET_LEGACY)
|
||||
}
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.room.Room
|
||||
import org.matrix.android.sdk.api.session.room.getTimelineEvent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntityFields
|
||||
import org.matrix.android.sdk.internal.database.model.PollResponseAggregatedSummaryEntity
|
||||
@@ -255,9 +255,9 @@ class DefaultPollAggregationProcessorTest {
|
||||
every { room.getTimelineEvent(eventId) } returns if (hasExistingTimelineEvent) A_TIMELINE_EVENT else null
|
||||
}
|
||||
|
||||
private fun mockRedactionPowerLevels(userId: String, isAbleToRedact: Boolean): PowerLevelsHelper {
|
||||
val powerLevelsHelper = mockk<PowerLevelsHelper>()
|
||||
every { powerLevelsHelper.isUserAbleToRedact(userId) } returns isAbleToRedact
|
||||
return powerLevelsHelper
|
||||
private fun mockRedactionPowerLevels(userId: String, isAbleToRedact: Boolean): RoomPowerLevels {
|
||||
val roomPowerLevels = mockk<RoomPowerLevels>()
|
||||
every { roomPowerLevels.isUserAbleToRedact(userId) } returns isAbleToRedact
|
||||
return roomPowerLevels
|
||||
}
|
||||
}
|
||||
|
@@ -376,8 +376,8 @@ internal class DefaultCreateLocalRoomStateEventsTaskTest {
|
||||
powerLevelsContent.kick shouldBeEqualTo Role.Moderator.value
|
||||
powerLevelsContent.invite shouldBeEqualTo Role.Moderator.value
|
||||
powerLevelsContent.redact shouldBeEqualTo Role.Moderator.value
|
||||
powerLevelsContent.eventsDefault shouldBeEqualTo Role.Default.value
|
||||
powerLevelsContent.usersDefault shouldBeEqualTo Role.Default.value
|
||||
powerLevelsContent.eventsDefault shouldBeEqualTo Role.User.value
|
||||
powerLevelsContent.usersDefault shouldBeEqualTo Role.User.value
|
||||
powerLevelsContent.stateDefault shouldBeEqualTo Role.Moderator.value
|
||||
// Guest access
|
||||
result.find { it.type == EventType.STATE_ROOM_GUEST_ACCESS }
|
||||
|
@@ -110,7 +110,6 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachme
|
||||
import org.matrix.android.sdk.api.session.room.model.message.getFileUrl
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
||||
import org.matrix.android.sdk.api.session.room.model.tombstone.RoomTombstoneContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.read.ReadService
|
||||
import org.matrix.android.sdk.api.session.room.timeline.Timeline
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
@@ -304,11 +303,11 @@ class TimelineViewModel @AssistedInject constructor(
|
||||
private fun observePowerLevel() {
|
||||
if (room == null) return
|
||||
PowerLevelsFlowFactory(room).createFlow()
|
||||
.onEach {
|
||||
val canInvite = PowerLevelsHelper(it).isUserAbleToInvite(session.myUserId)
|
||||
.onEach { powerLevels ->
|
||||
val canInvite = powerLevels.isUserAbleToInvite(session.myUserId)
|
||||
val isAllowedToManageWidgets = session.widgetService().hasPermissionsToHandleWidgets(room.roomId)
|
||||
val isAllowedToStartWebRTCCall = PowerLevelsHelper(it).isUserAllowedToSend(session.myUserId, false, EventType.CALL_INVITE)
|
||||
val isAllowedToSetupEncryption = PowerLevelsHelper(it).isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_ENCRYPTION)
|
||||
val isAllowedToStartWebRTCCall = powerLevels.isUserAllowedToSend(session.myUserId, false, EventType.CALL_INVITE)
|
||||
val isAllowedToSetupEncryption = powerLevels.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_ENCRYPTION)
|
||||
setState {
|
||||
copy(
|
||||
canInvite = canInvite,
|
||||
|
@@ -69,7 +69,6 @@ import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageContentWithFormattedBody
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.shouldRenderInThread
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.send.UserDraft
|
||||
import org.matrix.android.sdk.api.session.room.timeline.getRelationContent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.getTextEditableContent
|
||||
@@ -183,7 +182,7 @@ class MessageComposerViewModel @AssistedInject constructor(
|
||||
PowerLevelsFlowFactory(room).createFlow(),
|
||||
room.flow().liveRoomSummary().unwrap()
|
||||
) { pl, sum ->
|
||||
val canSendMessage = PowerLevelsHelper(pl).isUserAllowedToSend(session.myUserId, false, EventType.MESSAGE)
|
||||
val canSendMessage = pl.isUserAllowedToSend(session.myUserId, false, EventType.MESSAGE)
|
||||
if (canSendMessage) {
|
||||
val isE2E = sum.isEncrypted
|
||||
if (isE2E) {
|
||||
|
@@ -49,7 +49,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageType
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationRequestContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.send.SendState
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.hasBeenEdited
|
||||
@@ -117,11 +117,10 @@ class MessageActionsViewModel @AssistedInject constructor(
|
||||
return
|
||||
}
|
||||
PowerLevelsFlowFactory(room).createFlow()
|
||||
.onEach {
|
||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||
val canReact = powerLevelsHelper.isUserAllowedToSend(session.myUserId, false, EventType.REACTION)
|
||||
val canRedact = powerLevelsHelper.isUserAbleToRedact(session.myUserId)
|
||||
val canSendMessage = powerLevelsHelper.isUserAllowedToSend(session.myUserId, false, EventType.MESSAGE)
|
||||
.onEach { roomPowerLevels ->
|
||||
val canReact = roomPowerLevels.isUserAllowedToSend(session.myUserId, false, EventType.REACTION)
|
||||
val canRedact = roomPowerLevels.isUserAbleToRedact(session.myUserId)
|
||||
val canSendMessage = roomPowerLevels.isUserAllowedToSend(session.myUserId, false, EventType.MESSAGE)
|
||||
val permissions = ActionPermissions(canSendMessage = canSendMessage, canRedact = canRedact, canReact = canReact)
|
||||
setState {
|
||||
copy(actionPermissions = permissions)
|
||||
|
@@ -30,10 +30,11 @@ import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.room.getRoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.getStateEvent
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -303,9 +304,7 @@ class MergedHeaderItemFactory @Inject constructor(
|
||||
collapsedEventIds.removeAll(mergedEventIds)
|
||||
}
|
||||
val mergeId = mergedEventIds.joinToString(separator = "_") { it.toString() }
|
||||
val powerLevelsHelper = activeSessionHolder.getSafeActiveSession()?.getRoom(event.roomId)
|
||||
?.let { it.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)?.content?.toModel<PowerLevelsContent>() }
|
||||
?.let { PowerLevelsHelper(it) }
|
||||
val roomPowerLevels = activeSessionHolder.getSafeActiveSession()?.getRoom(event.roomId)?.getRoomPowerLevels()
|
||||
val currentUserId = activeSessionHolder.getSafeActiveSession()?.myUserId ?: ""
|
||||
val attributes = MergedRoomCreationItem.Attributes(
|
||||
isCollapsed = isCollapsed,
|
||||
@@ -320,10 +319,10 @@ class MergedHeaderItemFactory @Inject constructor(
|
||||
callback = callback,
|
||||
currentUserId = currentUserId,
|
||||
roomSummary = partialState.roomSummary,
|
||||
canInvite = powerLevelsHelper?.isUserAbleToInvite(currentUserId) ?: false,
|
||||
canChangeAvatar = powerLevelsHelper?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_AVATAR) ?: false,
|
||||
canChangeTopic = powerLevelsHelper?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_TOPIC) ?: false,
|
||||
canChangeName = powerLevelsHelper?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_NAME) ?: false
|
||||
canInvite = roomPowerLevels?.isUserAbleToInvite(currentUserId) ?: false,
|
||||
canChangeAvatar = roomPowerLevels?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_AVATAR) ?: false,
|
||||
canChangeTopic = roomPowerLevels?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_TOPIC) ?: false,
|
||||
canChangeName = roomPowerLevels?.isUserAllowedToSend(currentUserId, true, EventType.STATE_ROOM_NAME) ?: false
|
||||
)
|
||||
MergedRoomCreationItem_()
|
||||
.id(mergeId)
|
||||
|
@@ -41,7 +41,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomTopicContent
|
||||
import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.widgets.model.WidgetContent
|
||||
import timber.log.Timber
|
||||
@@ -122,8 +122,8 @@ class NoticeEventFormatter @Inject constructor(
|
||||
userIds.addAll(previousPowerLevelsContent.users.orEmpty().keys)
|
||||
val diffs = ArrayList<String>()
|
||||
userIds.forEach { userId ->
|
||||
val from = PowerLevelsHelper(previousPowerLevelsContent).getUserRole(userId)
|
||||
val to = PowerLevelsHelper(powerLevelsContent).getUserRole(userId)
|
||||
val from = RoomPowerLevels(previousPowerLevelsContent,null).getUserRole(userId)
|
||||
val to = RoomPowerLevels(powerLevelsContent, null).getUserRole(userId)
|
||||
if (from != to) {
|
||||
val fromStr = roleFormatter.format(from)
|
||||
val toStr = roleFormatter.format(to)
|
||||
|
@@ -34,7 +34,7 @@ import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.getUserOrDefault
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import timber.log.Timber
|
||||
|
||||
@@ -75,11 +75,10 @@ class LocationSharingViewModel @AssistedInject constructor(
|
||||
private fun observePowerLevelsForLiveLocationSharing() {
|
||||
PowerLevelsFlowFactory(room).createFlow()
|
||||
.distinctUntilChanged()
|
||||
.setOnEach {
|
||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||
.setOnEach { roomPowerLevels ->
|
||||
val canShareLiveLocation = EventType.STATE_ROOM_BEACON_INFO.values
|
||||
.all { beaconInfoType ->
|
||||
powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, beaconInfoType)
|
||||
roomPowerLevels.isUserAllowedToSend(session.myUserId, true, beaconInfoType)
|
||||
}
|
||||
|
||||
copy(canShareLiveLocation = canShareLiveLocation)
|
||||
|
@@ -9,23 +9,40 @@ package im.vector.app.features.powerlevel
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.Room
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||
import org.matrix.android.sdk.api.session.room.model.create.getRoomCreateContentWithSender
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import org.matrix.android.sdk.flow.mapOptional
|
||||
import org.matrix.android.sdk.flow.unwrap
|
||||
|
||||
class PowerLevelsFlowFactory(private val room: Room) {
|
||||
|
||||
fun createFlow(): Flow<PowerLevelsContent> {
|
||||
return room.flow()
|
||||
fun createFlow(): Flow<RoomPowerLevels> {
|
||||
val flowRoom = room.flow()
|
||||
val powerLevelsFlow = flowRoom
|
||||
.liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
|
||||
.mapOptional { it.content.toModel<PowerLevelsContent>() }
|
||||
.flowOn(Dispatchers.Default)
|
||||
.unwrap()
|
||||
|
||||
val roomCreateFlow = flowRoom
|
||||
.liveStateEvent(EventType.STATE_ROOM_CREATE, QueryStringValue.IsEmpty)
|
||||
.mapOptional { event ->
|
||||
event.getRoomCreateContentWithSender()
|
||||
}
|
||||
.flowOn(Dispatchers.Default)
|
||||
|
||||
return combine(powerLevelsFlow, roomCreateFlow) { powerLevelsContent, roomCreateContent ->
|
||||
RoomPowerLevels(
|
||||
powerLevelsContent = powerLevelsContent.getOrNull(),
|
||||
roomCreateContent = roomCreateContent.getOrNull()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@
|
||||
package im.vector.app.features.roommemberprofile
|
||||
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.UserPowerLevel
|
||||
|
||||
sealed class RoomMemberProfileAction : VectorViewModelAction {
|
||||
object RetryFetchingInfo : RoomMemberProfileAction()
|
||||
@@ -18,7 +19,7 @@ sealed class RoomMemberProfileAction : VectorViewModelAction {
|
||||
object InviteUser : RoomMemberProfileAction()
|
||||
object VerifyUser : RoomMemberProfileAction()
|
||||
object ShareRoomMemberProfile : RoomMemberProfileAction()
|
||||
data class SetPowerLevel(val previousValue: Int, val newValue: Int, val askForValidation: Boolean) : RoomMemberProfileAction()
|
||||
data class SetPowerLevel(val previousValue: UserPowerLevel, val newValue: UserPowerLevel.Value, val askForValidation: Boolean) : RoomMemberProfileAction()
|
||||
data class SetUserColorOverride(val newColorSpec: String) : RoomMemberProfileAction()
|
||||
data class OpenOrCreateDm(val userId: String) : RoomMemberProfileAction()
|
||||
}
|
||||
|
@@ -17,8 +17,8 @@ import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence
|
||||
import im.vector.lib.strings.CommonStrings
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.UserPowerLevel
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomMemberProfileController @Inject constructor(
|
||||
@@ -38,7 +38,7 @@ class RoomMemberProfileController @Inject constructor(
|
||||
fun onOverrideColorClicked()
|
||||
fun onJumpToReadReceiptClicked()
|
||||
fun onMentionClicked()
|
||||
fun onEditPowerLevel(currentRole: Role)
|
||||
fun onEditPowerLevel(userPowerLevel: UserPowerLevel)
|
||||
fun onKickClicked(isSpace: Boolean)
|
||||
fun onBanClicked(isSpace: Boolean, isUserBanned: Boolean)
|
||||
fun onCancelInviteClicked()
|
||||
@@ -243,11 +243,10 @@ class RoomMemberProfileController @Inject constructor(
|
||||
}
|
||||
|
||||
private fun buildAdminSection(state: RoomMemberProfileViewState) {
|
||||
val powerLevelsContent = state.powerLevelsContent ?: return
|
||||
val powerLevelsStr = state.userPowerLevelString() ?: return
|
||||
val powerLevelsHelper = PowerLevelsHelper(powerLevelsContent)
|
||||
val userPowerLevel = powerLevelsHelper.getUserRole(state.userId)
|
||||
val myPowerLevel = powerLevelsHelper.getUserRole(session.myUserId)
|
||||
val roomPowerLevels = state.roomPowerLevels ?: return
|
||||
val userPowerLevel = roomPowerLevels.getUserPowerLevel(state.userId)
|
||||
val myPowerLevel = roomPowerLevels.getUserPowerLevel(session.myUserId)
|
||||
if ((!state.isMine && myPowerLevel <= userPowerLevel)) {
|
||||
return
|
||||
}
|
||||
|
@@ -51,7 +51,7 @@ import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs
|
||||
import im.vector.lib.strings.CommonStrings
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.matrix.android.sdk.api.session.crypto.model.UserVerificationLevel
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.UserPowerLevel
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -377,9 +377,9 @@ class RoomMemberProfileFragment :
|
||||
.show()
|
||||
}
|
||||
|
||||
override fun onEditPowerLevel(currentRole: Role) {
|
||||
EditPowerLevelDialogs.showChoice(requireActivity(), CommonStrings.power_level_edit_title, currentRole) { newPowerLevel ->
|
||||
viewModel.handle(RoomMemberProfileAction.SetPowerLevel(currentRole.value, newPowerLevel, true))
|
||||
override fun onEditPowerLevel(userPowerLevel: UserPowerLevel) {
|
||||
EditPowerLevelDialogs.showChoice(requireActivity(), CommonStrings.power_level_edit_title, userPowerLevel) { newPowerLevel ->
|
||||
viewModel.handle(RoomMemberProfileAction.SetPowerLevel(userPowerLevel, newPowerLevel, true))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
package im.vector.app.features.roommemberprofile
|
||||
|
||||
import im.vector.app.core.platform.VectorViewEvents
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.UserPowerLevel
|
||||
|
||||
/**
|
||||
* Transient events for RoomMemberProfile.
|
||||
@@ -22,8 +23,8 @@ sealed class RoomMemberProfileViewEvents : VectorViewEvents {
|
||||
object OnInviteActionSuccess : RoomMemberProfileViewEvents()
|
||||
object OnKickActionSuccess : RoomMemberProfileViewEvents()
|
||||
object OnBanActionSuccess : RoomMemberProfileViewEvents()
|
||||
data class ShowPowerLevelValidation(val currentValue: Int, val newValue: Int) : RoomMemberProfileViewEvents()
|
||||
data class ShowPowerLevelDemoteWarning(val currentValue: Int, val newValue: Int) : RoomMemberProfileViewEvents()
|
||||
data class ShowPowerLevelValidation(val currentValue: UserPowerLevel, val newValue: UserPowerLevel.Value) : RoomMemberProfileViewEvents()
|
||||
data class ShowPowerLevelDemoteWarning(val currentValue: UserPowerLevel, val newValue: UserPowerLevel.Value) : RoomMemberProfileViewEvents()
|
||||
|
||||
data class StartVerification(
|
||||
val userId: String,
|
||||
|
@@ -42,9 +42,9 @@ import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.room.Room
|
||||
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomEncryptionAlgorithm
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
@@ -233,15 +233,15 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
|
||||
if (room == null || action.previousValue == action.newValue) {
|
||||
return@withState
|
||||
}
|
||||
val currentPowerLevelsContent = state.powerLevelsContent ?: return@withState
|
||||
val myPowerLevel = PowerLevelsHelper(currentPowerLevelsContent).getUserPowerLevelValue(session.myUserId)
|
||||
val roomPowerLevels = state.roomPowerLevels ?: return@withState
|
||||
val myPowerLevel = roomPowerLevels.getUserPowerLevel(session.myUserId)
|
||||
if (action.askForValidation && action.newValue >= myPowerLevel) {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.ShowPowerLevelValidation(action.previousValue, action.newValue))
|
||||
} else if (action.askForValidation && state.isMine) {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.ShowPowerLevelDemoteWarning(action.previousValue, action.newValue))
|
||||
} else {
|
||||
val newPowerLevelsContent = currentPowerLevelsContent
|
||||
.setUserPowerLevel(state.userId, action.newValue)
|
||||
val newPowerLevelsContent = (roomPowerLevels.powerLevelsContent ?: PowerLevelsContent())
|
||||
.setUserPowerLevel(state.userId, action.newValue.value)
|
||||
.toContent()
|
||||
viewModelScope.launch {
|
||||
_viewEvents.post(RoomMemberProfileViewEvents.Loading())
|
||||
@@ -361,19 +361,17 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
|
||||
|
||||
private fun observeRoomSummaryAndPowerLevels(room: Room) {
|
||||
val roomSummaryLive = room.flow().liveRoomSummary().unwrap()
|
||||
val powerLevelsContentLive = PowerLevelsFlowFactory(room).createFlow()
|
||||
|
||||
powerLevelsContentLive
|
||||
.onEach {
|
||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||
val powerLevelsFlow = PowerLevelsFlowFactory(room).createFlow()
|
||||
powerLevelsFlow
|
||||
.onEach { roomPowerLevels ->
|
||||
val permissions = ActionPermissions(
|
||||
canKick = powerLevelsHelper.isUserAbleToKick(session.myUserId),
|
||||
canBan = powerLevelsHelper.isUserAbleToBan(session.myUserId),
|
||||
canInvite = powerLevelsHelper.isUserAbleToInvite(session.myUserId),
|
||||
canEditPowerLevel = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_POWER_LEVELS)
|
||||
canKick = roomPowerLevels.isUserAbleToKick(session.myUserId),
|
||||
canBan = roomPowerLevels.isUserAbleToBan(session.myUserId),
|
||||
canInvite = roomPowerLevels.isUserAbleToInvite(session.myUserId),
|
||||
canEditPowerLevel = roomPowerLevels.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_POWER_LEVELS)
|
||||
)
|
||||
setState {
|
||||
copy(powerLevelsContent = it, actionPermissions = permissions)
|
||||
copy(roomPowerLevels = roomPowerLevels, actionPermissions = permissions)
|
||||
}
|
||||
}.launchIn(viewModelScope)
|
||||
|
||||
@@ -388,14 +386,14 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
|
||||
copy(isRoomEncrypted = false)
|
||||
}
|
||||
}
|
||||
roomSummaryLive.combine(powerLevelsContentLive) { roomSummary, powerLevelsContent ->
|
||||
roomSummaryLive.combine(powerLevelsFlow) { roomSummary, roomPowerLevels ->
|
||||
val roomName = roomSummary.toMatrixItem().getBestName()
|
||||
val powerLevelsHelper = PowerLevelsHelper(powerLevelsContent)
|
||||
when (val userPowerLevel = powerLevelsHelper.getUserRole(initialState.userId)) {
|
||||
when (roomPowerLevels.getUserRole(initialState.userId)) {
|
||||
Role.SuperAdmin,
|
||||
Role.Creator,
|
||||
Role.Admin -> stringProvider.getString(CommonStrings.room_member_power_level_admin_in, roomName)
|
||||
Role.Moderator -> stringProvider.getString(CommonStrings.room_member_power_level_moderator_in, roomName)
|
||||
Role.Default -> stringProvider.getString(CommonStrings.room_member_power_level_default_in, roomName)
|
||||
is Role.Custom -> stringProvider.getString(CommonStrings.room_member_power_level_custom_in, userPowerLevel.value, roomName)
|
||||
Role.User -> stringProvider.getString(CommonStrings.room_member_power_level_default_in, roomName)
|
||||
}
|
||||
}.execute {
|
||||
copy(userPowerLevelString = it)
|
||||
|
@@ -12,7 +12,7 @@ import com.airbnb.mvrx.MavericksState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
||||
data class RoomMemberProfileViewState(
|
||||
@@ -24,7 +24,7 @@ data class RoomMemberProfileViewState(
|
||||
val isIgnored: Async<Boolean> = Uninitialized,
|
||||
val isRoomEncrypted: Boolean = false,
|
||||
val isAlgorithmSupported: Boolean = true,
|
||||
val powerLevelsContent: PowerLevelsContent? = null,
|
||||
val roomPowerLevels: RoomPowerLevels? = null,
|
||||
val userPowerLevelString: Async<String> = Uninitialized,
|
||||
val userMatrixItem: Async<MatrixItem> = Uninitialized,
|
||||
val userMXCrossSigningInfo: MXCrossSigningInfo? = null,
|
||||
|
@@ -19,6 +19,7 @@ import im.vector.app.core.extensions.hideKeyboard
|
||||
import im.vector.app.databinding.DialogEditPowerLevelBinding
|
||||
import im.vector.lib.strings.CommonStrings
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.UserPowerLevel
|
||||
|
||||
object EditPowerLevelDialogs {
|
||||
|
||||
@@ -26,21 +27,21 @@ object EditPowerLevelDialogs {
|
||||
fun showChoice(
|
||||
activity: Activity,
|
||||
@StringRes titleRes: Int,
|
||||
currentRole: Role,
|
||||
listener: (Int) -> Unit
|
||||
currentPowerLevel: UserPowerLevel,
|
||||
listener: (UserPowerLevel.Value) -> Unit
|
||||
) {
|
||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_edit_power_level, null)
|
||||
val views = DialogEditPowerLevelBinding.bind(dialogLayout)
|
||||
views.powerLevelRadioGroup.setOnCheckedChangeListener { _, checkedId ->
|
||||
views.powerLevelCustomEditLayout.isVisible = checkedId == R.id.powerLevelCustomRadio
|
||||
}
|
||||
views.powerLevelCustomEdit.setText("${currentRole.value}")
|
||||
|
||||
val currentRole = Role.getSuggestedRole(currentPowerLevel)
|
||||
when (currentRole) {
|
||||
Role.Creator -> views.powerLevelAdminRadio.isChecked = true
|
||||
Role.SuperAdmin -> views.powerLevelAdminRadio.isChecked = true
|
||||
Role.Admin -> views.powerLevelAdminRadio.isChecked = true
|
||||
Role.Moderator -> views.powerLevelModeratorRadio.isChecked = true
|
||||
Role.Default -> views.powerLevelDefaultRadio.isChecked = true
|
||||
else -> views.powerLevelCustomRadio.isChecked = true
|
||||
Role.User -> views.powerLevelDefaultRadio.isChecked = true
|
||||
}
|
||||
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
@@ -48,14 +49,14 @@ object EditPowerLevelDialogs {
|
||||
.setView(dialogLayout)
|
||||
.setPositiveButton(CommonStrings.edit) { _, _ ->
|
||||
val newValue = when (views.powerLevelRadioGroup.checkedRadioButtonId) {
|
||||
R.id.powerLevelAdminRadio -> Role.Admin.value
|
||||
R.id.powerLevelModeratorRadio -> Role.Moderator.value
|
||||
R.id.powerLevelDefaultRadio -> Role.Default.value
|
||||
else -> {
|
||||
views.powerLevelCustomEdit.text?.toString()?.toInt() ?: currentRole.value
|
||||
}
|
||||
R.id.powerLevelAdminRadio -> UserPowerLevel.Admin
|
||||
R.id.powerLevelModeratorRadio -> UserPowerLevel.Moderator
|
||||
R.id.powerLevelDefaultRadio -> UserPowerLevel.User
|
||||
else -> null
|
||||
}
|
||||
if(newValue != null) {
|
||||
listener(newValue)
|
||||
}
|
||||
listener(newValue)
|
||||
}
|
||||
.setNegativeButton(CommonStrings.action_cancel, null)
|
||||
.setOnKeyListener(DialogInterface.OnKeyListener
|
||||
|
@@ -39,7 +39,7 @@ import org.matrix.android.sdk.api.session.room.getStateEvent
|
||||
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.state.isPublic
|
||||
import org.matrix.android.sdk.flow.FlowRoom
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
@@ -115,9 +115,8 @@ class RoomProfileViewModel @AssistedInject constructor(
|
||||
private fun observePowerLevels() {
|
||||
val powerLevelsContentLive = PowerLevelsFlowFactory(room).createFlow()
|
||||
powerLevelsContentLive
|
||||
.onEach {
|
||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||
val canUpdateRoomState = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_ENCRYPTION)
|
||||
.onEach { roomPowerLevels ->
|
||||
val canUpdateRoomState = roomPowerLevels.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_ENCRYPTION)
|
||||
setState {
|
||||
copy(canUpdateRoomState = canUpdateRoomState)
|
||||
}
|
||||
@@ -158,10 +157,9 @@ class RoomProfileViewModel @AssistedInject constructor(
|
||||
private fun observePermissions() {
|
||||
PowerLevelsFlowFactory(room)
|
||||
.createFlow()
|
||||
.setOnEach {
|
||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||
.setOnEach { roomPowerLevels ->
|
||||
val permissions = RoomProfileViewState.ActionPermissions(
|
||||
canEnableEncryption = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_ENCRYPTION)
|
||||
canEnableEncryption = roomPowerLevels.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_ENCRYPTION)
|
||||
)
|
||||
copy(actionPermissions = permissions)
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomCanonicalAliasContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import org.matrix.android.sdk.flow.mapOptional
|
||||
import org.matrix.android.sdk.flow.unwrap
|
||||
@@ -127,10 +127,9 @@ class RoomAliasViewModel @AssistedInject constructor(
|
||||
private fun observePowerLevel() {
|
||||
PowerLevelsFlowFactory(room)
|
||||
.createFlow()
|
||||
.onEach {
|
||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||
.onEach { roomPowerLevels ->
|
||||
val permissions = RoomAliasViewState.ActionPermissions(
|
||||
canChangeCanonicalAlias = powerLevelsHelper.isUserAllowedToSend(
|
||||
canChangeCanonicalAlias = roomPowerLevels.isUserAllowedToSend(
|
||||
userId = session.myUserId,
|
||||
isState = true,
|
||||
eventType = EventType.STATE_ROOM_CANONICAL_ALIAS
|
||||
|
@@ -29,7 +29,7 @@ import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import org.matrix.android.sdk.flow.unwrap
|
||||
|
||||
@@ -62,12 +62,10 @@ class RoomBannedMemberListViewModel @AssistedInject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
val powerLevelsContentLive = PowerLevelsFlowFactory(room).createFlow()
|
||||
|
||||
powerLevelsContentLive
|
||||
.setOnEach {
|
||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||
copy(canUserBan = powerLevelsHelper.isUserAbleToBan(session.myUserId))
|
||||
val powerLevelsFlow = PowerLevelsFlowFactory(room).createFlow()
|
||||
powerLevelsFlow
|
||||
.setOnEach { roomPowerLevels ->
|
||||
copy(canUserBan = roomPowerLevels.isUserAbleToBan(session.myUserId))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2020-2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.roomprofile.members
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomMemberListComparator @Inject constructor() : Comparator<RoomMemberWithPowerLevel> {
|
||||
|
||||
override fun compare(leftRoomMember: RoomMemberWithPowerLevel?, rightRoomMember: RoomMemberWithPowerLevel?): Int {
|
||||
return when (leftRoomMember) {
|
||||
null ->
|
||||
when (rightRoomMember) {
|
||||
null -> 0
|
||||
else -> 1
|
||||
}
|
||||
else ->
|
||||
when (rightRoomMember) {
|
||||
null -> -1
|
||||
else ->
|
||||
when {
|
||||
leftRoomMember.powerLevel > rightRoomMember.powerLevel -> 1
|
||||
leftRoomMember.powerLevel < rightRoomMember.powerLevel -> -1
|
||||
leftRoomMember.summary.displayName.isNullOrBlank() ->
|
||||
when {
|
||||
rightRoomMember.summary.displayName.isNullOrBlank() -> {
|
||||
// No display names, compare ids
|
||||
leftRoomMember.summary.userId.compareTo(rightRoomMember.summary.userId)
|
||||
}
|
||||
else -> 1
|
||||
}
|
||||
else ->
|
||||
when {
|
||||
rightRoomMember.summary.displayName.isNullOrBlank() -> -1
|
||||
else -> {
|
||||
when (leftRoomMember.summary.displayName) {
|
||||
rightRoomMember.summary.displayName ->
|
||||
// Same display name, compare id
|
||||
leftRoomMember.summary.userId.compareTo(rightRoomMember.summary.userId)
|
||||
else ->
|
||||
leftRoomMember.summary.displayName!!.compareTo(rightRoomMember.summary.displayName!!, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -16,11 +16,13 @@ import im.vector.app.core.extensions.join
|
||||
import im.vector.app.core.resources.ColorProvider
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.roomprofile.permissions.RoleFormatter
|
||||
import me.gujun.android.span.span
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import javax.inject.Inject
|
||||
@@ -29,7 +31,8 @@ class RoomMemberListController @Inject constructor(
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val stringProvider: StringProvider,
|
||||
private val colorProvider: ColorProvider,
|
||||
private val roomMemberSummaryFilter: RoomMemberSummaryFilter
|
||||
private val roomMemberSummaryFilter: RoomMemberSummaryFilter,
|
||||
private val roleFormatter: RoleFormatter,
|
||||
) : TypedEpoxyController<RoomMemberListViewState>() {
|
||||
|
||||
interface Callback {
|
||||
@@ -56,13 +59,13 @@ class RoomMemberListController @Inject constructor(
|
||||
.orEmpty()
|
||||
var threePidInvitesDone = filteredThreePidInvites.isEmpty()
|
||||
|
||||
for ((powerLevelCategory, roomMemberList) in roomMembersByPowerLevel) {
|
||||
val filteredRoomMemberList = roomMemberList.filter { roomMemberSummaryFilter.test(it) }
|
||||
for ((category, roomMemberList) in roomMembersByPowerLevel) {
|
||||
val filteredRoomMemberList = roomMemberList.filter { roomMemberSummaryFilter.test(it.summary) }
|
||||
if (filteredRoomMemberList.isEmpty()) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (powerLevelCategory == RoomMemberListCategories.USER && !threePidInvitesDone) {
|
||||
if (category == RoomMemberListCategories.USER && !threePidInvitesDone) {
|
||||
// If there is no regular invite, display threepid invite before the regular user
|
||||
buildProfileSection(
|
||||
stringProvider.getString(RoomMemberListCategories.INVITE.titleRes)
|
||||
@@ -73,20 +76,20 @@ class RoomMemberListController @Inject constructor(
|
||||
}
|
||||
|
||||
buildProfileSection(
|
||||
stringProvider.getString(powerLevelCategory.titleRes)
|
||||
stringProvider.getString(category.titleRes)
|
||||
)
|
||||
|
||||
filteredRoomMemberList.join(
|
||||
each = { _, roomMember ->
|
||||
buildRoomMember(roomMember, powerLevelCategory, host, data)
|
||||
buildRoomMember(roomMember, host, data)
|
||||
},
|
||||
between = { _, roomMemberBefore ->
|
||||
dividerItem {
|
||||
id("divider_${roomMemberBefore.userId}")
|
||||
id("divider_${roomMemberBefore.summary.userId}")
|
||||
}
|
||||
}
|
||||
)
|
||||
if (powerLevelCategory == RoomMemberListCategories.INVITE && !threePidInvitesDone) {
|
||||
if (category == RoomMemberListCategories.INVITE && !threePidInvitesDone) {
|
||||
// Display the threepid invite after the regular invite
|
||||
dividerItem {
|
||||
id("divider_threepidinvites")
|
||||
@@ -108,24 +111,24 @@ class RoomMemberListController @Inject constructor(
|
||||
}
|
||||
|
||||
private fun buildRoomMember(
|
||||
roomMember: RoomMemberSummary,
|
||||
powerLevelCategory: RoomMemberListCategories,
|
||||
roomMember: RoomMemberWithPowerLevel,
|
||||
host: RoomMemberListController,
|
||||
data: RoomMemberListViewState
|
||||
) {
|
||||
val powerLabel = stringProvider.getString(powerLevelCategory.titleRes)
|
||||
val role = Role.getSuggestedRole(roomMember.powerLevel)
|
||||
val powerLabel = roleFormatter.format(role)
|
||||
|
||||
profileMatrixItemWithPowerLevelWithPresence {
|
||||
id(roomMember.userId)
|
||||
matrixItem(roomMember.toMatrixItem())
|
||||
id(roomMember.summary.userId)
|
||||
matrixItem(roomMember.summary.toMatrixItem())
|
||||
avatarRenderer(host.avatarRenderer)
|
||||
userVerificationLevel(data.trustLevelMap.invoke()?.get(roomMember.userId))
|
||||
userVerificationLevel(data.trustLevelMap.invoke()?.get(roomMember.summary.userId))
|
||||
clickListener {
|
||||
host.callback?.onRoomMemberClicked(roomMember)
|
||||
host.callback?.onRoomMemberClicked(roomMember.summary)
|
||||
}
|
||||
showPresence(true)
|
||||
userPresence(roomMember.userPresence)
|
||||
ignoredUser(roomMember.userId in data.ignoredUserIds)
|
||||
userPresence(roomMember.summary.userPresence)
|
||||
ignoredUser(roomMember.summary.userId in data.ignoredUserIds)
|
||||
powerLevelLabel(
|
||||
span {
|
||||
span(powerLabel) {
|
||||
|
@@ -31,22 +31,19 @@ import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.model.UserVerificationLevel
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import org.matrix.android.sdk.flow.mapOptional
|
||||
import org.matrix.android.sdk.flow.unwrap
|
||||
import timber.log.Timber
|
||||
|
||||
class RoomMemberListViewModel @AssistedInject constructor(
|
||||
@Assisted initialState: RoomMemberListViewState,
|
||||
private val roomMemberSummaryComparator: RoomMemberSummaryComparator,
|
||||
private val roomMemberListComparator: RoomMemberListComparator,
|
||||
private val session: Session
|
||||
) :
|
||||
VectorViewModel<RoomMemberListViewState, RoomMemberListAction, EmptyViewEvents>(initialState) {
|
||||
@@ -75,14 +72,12 @@ class RoomMemberListViewModel @AssistedInject constructor(
|
||||
memberships = Membership.activeMemberships()
|
||||
}
|
||||
|
||||
val powerLevelsFlow = PowerLevelsFlowFactory(room).createFlow()
|
||||
combine(
|
||||
roomFlow.liveRoomMembers(roomMemberQueryParams),
|
||||
roomFlow
|
||||
.liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
|
||||
.mapOptional { it.content.toModel<PowerLevelsContent>() }
|
||||
.unwrap()
|
||||
) { roomMembers, powerLevelsContent ->
|
||||
buildRoomMemberSummaries(powerLevelsContent, roomMembers)
|
||||
powerLevelsFlow,
|
||||
) { roomMembers, roomPowerLevels ->
|
||||
buildRoomMemberSummaries(roomPowerLevels, roomMembers)
|
||||
}
|
||||
.execute { async ->
|
||||
copy(roomMemberSummaries = async)
|
||||
@@ -143,10 +138,10 @@ class RoomMemberListViewModel @AssistedInject constructor(
|
||||
|
||||
private fun observePowerLevel() {
|
||||
PowerLevelsFlowFactory(room).createFlow()
|
||||
.onEach {
|
||||
.onEach { roomPowerLevels ->
|
||||
val permissions = ActionPermissions(
|
||||
canInvite = PowerLevelsHelper(it).isUserAbleToInvite(session.myUserId),
|
||||
canRevokeThreePidInvite = PowerLevelsHelper(it).isUserAllowedToSend(
|
||||
canInvite = roomPowerLevels.isUserAbleToInvite(session.myUserId),
|
||||
canRevokeThreePidInvite = roomPowerLevels.isUserAllowedToSend(
|
||||
userId = session.myUserId,
|
||||
isState = true,
|
||||
eventType = EventType.STATE_ROOM_THIRD_PARTY_INVITE
|
||||
@@ -184,31 +179,34 @@ class RoomMemberListViewModel @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildRoomMemberSummaries(powerLevelsContent: PowerLevelsContent, roomMembers: List<RoomMemberSummary>): RoomMemberSummaries {
|
||||
val admins = ArrayList<RoomMemberSummary>()
|
||||
val moderators = ArrayList<RoomMemberSummary>()
|
||||
val users = ArrayList<RoomMemberSummary>(roomMembers.size)
|
||||
val customs = ArrayList<RoomMemberSummary>()
|
||||
val invites = ArrayList<RoomMemberSummary>()
|
||||
val powerLevelsHelper = PowerLevelsHelper(powerLevelsContent)
|
||||
private fun buildRoomMemberSummaries(roomPowerLevels: RoomPowerLevels, roomMembers: List<RoomMemberSummary>): RoomMembersByRole {
|
||||
val admins = ArrayList<RoomMemberWithPowerLevel>()
|
||||
val moderators = ArrayList<RoomMemberWithPowerLevel>()
|
||||
val users = ArrayList<RoomMemberWithPowerLevel>(roomMembers.size)
|
||||
val invites = ArrayList<RoomMemberWithPowerLevel>()
|
||||
roomMembers
|
||||
.forEach { roomMember ->
|
||||
val userRole = powerLevelsHelper.getUserRole(roomMember.userId)
|
||||
val powerLevel = roomPowerLevels.getUserPowerLevel(roomMember.userId)
|
||||
val userRole = Role.getSuggestedRole(powerLevel)
|
||||
val roomMemberWithPowerLevel = RoomMemberWithPowerLevel(
|
||||
powerLevel = powerLevel,
|
||||
summary = roomMember,
|
||||
)
|
||||
when {
|
||||
roomMember.membership == Membership.INVITE -> invites.add(roomMember)
|
||||
userRole == Role.Admin -> admins.add(roomMember)
|
||||
userRole == Role.Moderator -> moderators.add(roomMember)
|
||||
userRole == Role.Default -> users.add(roomMember)
|
||||
else -> customs.add(roomMember)
|
||||
roomMember.membership == Membership.INVITE -> invites.add(roomMemberWithPowerLevel)
|
||||
userRole == Role.SuperAdmin ||
|
||||
userRole == Role.Creator ||
|
||||
userRole == Role.Admin -> admins.add(roomMemberWithPowerLevel)
|
||||
userRole == Role.Moderator -> moderators.add(roomMemberWithPowerLevel)
|
||||
userRole == Role.User -> users.add(roomMemberWithPowerLevel)
|
||||
}
|
||||
}
|
||||
|
||||
return listOf(
|
||||
RoomMemberListCategories.ADMIN to admins.sortedWith(roomMemberSummaryComparator),
|
||||
RoomMemberListCategories.MODERATOR to moderators.sortedWith(roomMemberSummaryComparator),
|
||||
RoomMemberListCategories.CUSTOM to customs.sortedWith(roomMemberSummaryComparator),
|
||||
RoomMemberListCategories.INVITE to invites.sortedWith(roomMemberSummaryComparator),
|
||||
RoomMemberListCategories.USER to users.sortedWith(roomMemberSummaryComparator)
|
||||
RoomMemberListCategories.ADMIN to admins.sortedWith(roomMemberListComparator),
|
||||
RoomMemberListCategories.MODERATOR to moderators.sortedWith(roomMemberListComparator),
|
||||
RoomMemberListCategories.INVITE to invites.sortedWith(roomMemberListComparator),
|
||||
RoomMemberListCategories.USER to users.sortedWith(roomMemberListComparator)
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -18,11 +18,12 @@ import org.matrix.android.sdk.api.session.crypto.model.UserVerificationLevel
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.UserPowerLevel
|
||||
|
||||
data class RoomMemberListViewState(
|
||||
val roomId: String,
|
||||
val roomSummary: Async<RoomSummary> = Uninitialized,
|
||||
val roomMemberSummaries: Async<RoomMemberSummaries> = Uninitialized,
|
||||
val roomMemberSummaries: Async<RoomMembersByRole> = Uninitialized,
|
||||
val areAllMembersLoaded: Boolean = false,
|
||||
val ignoredUserIds: List<String> = emptyList(),
|
||||
val filter: String = "",
|
||||
@@ -41,12 +42,16 @@ data class ActionPermissions(
|
||||
val canRevokeThreePidInvite: Boolean = false
|
||||
)
|
||||
|
||||
typealias RoomMemberSummaries = List<Pair<RoomMemberListCategories, List<RoomMemberSummary>>>
|
||||
data class RoomMemberWithPowerLevel(
|
||||
val powerLevel: UserPowerLevel,
|
||||
val summary: RoomMemberSummary,
|
||||
)
|
||||
|
||||
typealias RoomMembersByRole = List<Pair<RoomMemberListCategories, List<RoomMemberWithPowerLevel>>>
|
||||
|
||||
enum class RoomMemberListCategories(@StringRes val titleRes: Int) {
|
||||
ADMIN(CommonStrings.room_member_power_level_admins),
|
||||
MODERATOR(CommonStrings.room_member_power_level_moderators),
|
||||
CUSTOM(CommonStrings.room_member_power_level_custom),
|
||||
INVITE(CommonStrings.room_member_power_level_invites),
|
||||
USER(CommonStrings.room_member_power_level_users)
|
||||
}
|
||||
|
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020-2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.roomprofile.members
|
||||
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomMemberSummaryComparator @Inject constructor() : Comparator<RoomMemberSummary> {
|
||||
|
||||
override fun compare(leftRoomMemberSummary: RoomMemberSummary?, rightRoomMemberSummary: RoomMemberSummary?): Int {
|
||||
return when (leftRoomMemberSummary) {
|
||||
null ->
|
||||
when (rightRoomMemberSummary) {
|
||||
null -> 0
|
||||
else -> 1
|
||||
}
|
||||
else ->
|
||||
when (rightRoomMemberSummary) {
|
||||
null -> -1
|
||||
else ->
|
||||
when {
|
||||
leftRoomMemberSummary.displayName.isNullOrBlank() ->
|
||||
when {
|
||||
rightRoomMemberSummary.displayName.isNullOrBlank() -> {
|
||||
// No display names, compare ids
|
||||
leftRoomMemberSummary.userId.compareTo(rightRoomMemberSummary.userId)
|
||||
}
|
||||
else -> 1
|
||||
}
|
||||
else ->
|
||||
when {
|
||||
rightRoomMemberSummary.displayName.isNullOrBlank() -> -1
|
||||
else -> {
|
||||
when (leftRoomMemberSummary.displayName) {
|
||||
rightRoomMemberSummary.displayName ->
|
||||
// Same display name, compare id
|
||||
leftRoomMemberSummary.userId.compareTo(rightRoomMemberSummary.userId)
|
||||
else ->
|
||||
leftRoomMemberSummary.displayName!!.compareTo(rightRoomMemberSummary.displayName!!, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -19,8 +19,9 @@ class RoleFormatter @Inject constructor(
|
||||
return when (role) {
|
||||
Role.Admin -> stringProvider.getString(CommonStrings.power_level_admin)
|
||||
Role.Moderator -> stringProvider.getString(CommonStrings.power_level_moderator)
|
||||
Role.Default -> stringProvider.getString(CommonStrings.power_level_default)
|
||||
is Role.Custom -> stringProvider.getString(CommonStrings.power_level_custom, role.value)
|
||||
Role.User -> stringProvider.getString(CommonStrings.power_level_default)
|
||||
Role.Creator -> stringProvider.getString(CommonStrings.power_level_owner)
|
||||
Role.SuperAdmin -> stringProvider.getString(CommonStrings.power_level_owner)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,9 +8,10 @@
|
||||
package im.vector.app.features.roomprofile.permissions
|
||||
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.UserPowerLevel
|
||||
|
||||
sealed class RoomPermissionsAction : VectorViewModelAction {
|
||||
object ToggleShowAllPermissions : RoomPermissionsAction()
|
||||
|
||||
data class UpdatePermission(val editablePermission: EditablePermission, val powerLevel: Int) : RoomPermissionsAction()
|
||||
data class UpdatePermission(val editablePermission: EditablePermission, val powerLevel: UserPowerLevel.Value) : RoomPermissionsAction()
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.session.room.model.redactOrDefault
|
||||
import org.matrix.android.sdk.api.session.room.model.stateDefaultOrDefault
|
||||
import org.matrix.android.sdk.api.session.room.model.usersDefaultOrDefault
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.UserPowerLevel
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomPermissionsController @Inject constructor(
|
||||
@@ -34,7 +35,7 @@ class RoomPermissionsController @Inject constructor(
|
||||
) : TypedEpoxyController<RoomPermissionsViewState>() {
|
||||
|
||||
interface Callback {
|
||||
fun onEditPermission(editablePermission: EditablePermission, currentRole: Role)
|
||||
fun onEditPermission(editablePermission: EditablePermission, currentPowerLevel: UserPowerLevel)
|
||||
fun toggleShowAllPermissions()
|
||||
}
|
||||
|
||||
@@ -165,7 +166,8 @@ class RoomPermissionsController @Inject constructor(
|
||||
editable: Boolean,
|
||||
isSpace: Boolean
|
||||
) {
|
||||
val currentRole = getCurrentRole(editablePermission, content)
|
||||
val currentPowerLevel = getPowerLevel(editablePermission, content)
|
||||
val currentRole = Role.getSuggestedRole(currentPowerLevel)
|
||||
buildProfileAction(
|
||||
id = editablePermission.labelResId.toString(),
|
||||
title = stringProvider.getString(
|
||||
@@ -177,12 +179,12 @@ class RoomPermissionsController @Inject constructor(
|
||||
action = {
|
||||
callback
|
||||
?.takeIf { editable }
|
||||
?.onEditPermission(editablePermission, currentRole)
|
||||
?.onEditPermission(editablePermission, currentPowerLevel)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun getCurrentRole(editablePermission: EditablePermission, content: PowerLevelsContent): Role {
|
||||
private fun getPowerLevel(editablePermission: EditablePermission, content: PowerLevelsContent): UserPowerLevel.Value {
|
||||
val value = when (editablePermission) {
|
||||
is EditablePermission.EventTypeEditablePermission -> content.events?.get(editablePermission.eventType) ?: content.stateDefaultOrDefault()
|
||||
is EditablePermission.DefaultRole -> content.usersDefaultOrDefault()
|
||||
@@ -194,20 +196,6 @@ class RoomPermissionsController @Inject constructor(
|
||||
is EditablePermission.RemoveMessagesSentByOthers -> content.redactOrDefault()
|
||||
is EditablePermission.NotifyEveryone -> content.notificationLevel(PowerLevelsContent.NOTIFICATIONS_ROOM_KEY)
|
||||
}
|
||||
|
||||
return Role.fromValue(
|
||||
value,
|
||||
when (editablePermission) {
|
||||
is EditablePermission.EventTypeEditablePermission -> content.stateDefaultOrDefault()
|
||||
is EditablePermission.DefaultRole -> Role.Default.value
|
||||
is EditablePermission.SendMessages -> Role.Default.value
|
||||
is EditablePermission.InviteUsers -> Role.Moderator.value
|
||||
is EditablePermission.ChangeSettings -> Role.Moderator.value
|
||||
is EditablePermission.KickUsers -> Role.Moderator.value
|
||||
is EditablePermission.BanUsers -> Role.Moderator.value
|
||||
is EditablePermission.RemoveMessagesSentByOthers -> Role.Moderator.value
|
||||
is EditablePermission.NotifyEveryone -> Role.Moderator.value
|
||||
}
|
||||
)
|
||||
return UserPowerLevel.Value(value)
|
||||
}
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.roommemberprofile.powerlevel.EditPowerLevelDialogs
|
||||
import im.vector.app.features.roomprofile.RoomProfileArgs
|
||||
import im.vector.lib.strings.CommonStrings
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.UserPowerLevel
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -93,8 +93,8 @@ class RoomPermissionsFragment :
|
||||
}
|
||||
}
|
||||
|
||||
override fun onEditPermission(editablePermission: EditablePermission, currentRole: Role) {
|
||||
EditPowerLevelDialogs.showChoice(requireActivity(), editablePermission.labelResId, currentRole) { newPowerLevel ->
|
||||
override fun onEditPermission(editablePermission: EditablePermission, currentPowerLevel: UserPowerLevel) {
|
||||
EditPowerLevelDialogs.showChoice(requireActivity(), editablePermission.labelResId, currentPowerLevel) { newPowerLevel ->
|
||||
viewModel.handle(RoomPermissionsAction.UpdatePermission(editablePermission, newPowerLevel))
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ package im.vector.app.features.roomprofile.permissions
|
||||
|
||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
@@ -24,7 +25,6 @@ import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import org.matrix.android.sdk.flow.unwrap
|
||||
|
||||
@@ -61,19 +61,23 @@ class RoomPermissionsViewModel @AssistedInject constructor(
|
||||
private fun observePowerLevel() {
|
||||
PowerLevelsFlowFactory(room)
|
||||
.createFlow()
|
||||
.onEach { powerLevelContent ->
|
||||
val powerLevelsHelper = PowerLevelsHelper(powerLevelContent)
|
||||
.onEach { roomPowerLevels ->
|
||||
val permissions = RoomPermissionsViewState.ActionPermissions(
|
||||
canChangePowerLevels = powerLevelsHelper.isUserAllowedToSend(
|
||||
canChangePowerLevels = roomPowerLevels.isUserAllowedToSend(
|
||||
userId = session.myUserId,
|
||||
isState = true,
|
||||
eventType = EventType.STATE_ROOM_POWER_LEVELS
|
||||
)
|
||||
)
|
||||
val powerLevelsContent = roomPowerLevels.powerLevelsContent
|
||||
setState {
|
||||
copy(
|
||||
actionPermissions = permissions,
|
||||
currentPowerLevelsContent = Success(powerLevelContent)
|
||||
currentPowerLevelsContent = if (powerLevelsContent != null) {
|
||||
Success(powerLevelsContent)
|
||||
} else {
|
||||
Uninitialized
|
||||
}
|
||||
)
|
||||
}
|
||||
}.launchIn(viewModelScope)
|
||||
@@ -94,26 +98,26 @@ class RoomPermissionsViewModel @AssistedInject constructor(
|
||||
|
||||
private fun updatePermission(action: RoomPermissionsAction.UpdatePermission) {
|
||||
withState { state ->
|
||||
val currentPowerLevel = state.currentPowerLevelsContent.invoke() ?: return@withState
|
||||
val currentPowerLevelsContent = state.currentPowerLevelsContent.invoke() ?: return@withState
|
||||
postLoading(true)
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val newPowerLevelsContent = when (action.editablePermission) {
|
||||
is EditablePermission.EventTypeEditablePermission -> currentPowerLevel.copy(
|
||||
events = currentPowerLevel.events.orEmpty().toMutableMap().apply {
|
||||
put(action.editablePermission.eventType, action.powerLevel)
|
||||
is EditablePermission.EventTypeEditablePermission -> currentPowerLevelsContent.copy(
|
||||
events = currentPowerLevelsContent.events.orEmpty().toMutableMap().apply {
|
||||
put(action.editablePermission.eventType, action.powerLevel.value)
|
||||
}
|
||||
)
|
||||
is EditablePermission.DefaultRole -> currentPowerLevel.copy(usersDefault = action.powerLevel)
|
||||
is EditablePermission.SendMessages -> currentPowerLevel.copy(eventsDefault = action.powerLevel)
|
||||
is EditablePermission.InviteUsers -> currentPowerLevel.copy(invite = action.powerLevel)
|
||||
is EditablePermission.ChangeSettings -> currentPowerLevel.copy(stateDefault = action.powerLevel)
|
||||
is EditablePermission.KickUsers -> currentPowerLevel.copy(kick = action.powerLevel)
|
||||
is EditablePermission.BanUsers -> currentPowerLevel.copy(ban = action.powerLevel)
|
||||
is EditablePermission.RemoveMessagesSentByOthers -> currentPowerLevel.copy(redact = action.powerLevel)
|
||||
is EditablePermission.NotifyEveryone -> currentPowerLevel.copy(
|
||||
notifications = currentPowerLevel.notifications.orEmpty().toMutableMap().apply {
|
||||
put(PowerLevelsContent.NOTIFICATIONS_ROOM_KEY, action.powerLevel)
|
||||
is EditablePermission.DefaultRole -> currentPowerLevelsContent.copy(usersDefault = action.powerLevel.value)
|
||||
is EditablePermission.SendMessages -> currentPowerLevelsContent.copy(eventsDefault = action.powerLevel.value)
|
||||
is EditablePermission.InviteUsers -> currentPowerLevelsContent.copy(invite = action.powerLevel.value)
|
||||
is EditablePermission.ChangeSettings -> currentPowerLevelsContent.copy(stateDefault = action.powerLevel.value)
|
||||
is EditablePermission.KickUsers -> currentPowerLevelsContent.copy(kick = action.powerLevel.value)
|
||||
is EditablePermission.BanUsers -> currentPowerLevelsContent.copy(ban = action.powerLevel.value)
|
||||
is EditablePermission.RemoveMessagesSentByOthers -> currentPowerLevelsContent.copy(redact = action.powerLevel.value)
|
||||
is EditablePermission.NotifyEveryone -> currentPowerLevelsContent.copy(
|
||||
notifications = currentPowerLevelsContent.notifications.orEmpty().toMutableMap().apply {
|
||||
put(PowerLevelsContent.NOTIFICATIONS_ROOM_KEY, action.powerLevel.value)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@@ -32,7 +32,6 @@ import org.matrix.android.sdk.api.session.room.model.RoomAvatarContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import org.matrix.android.sdk.flow.mapOptional
|
||||
import org.matrix.android.sdk.flow.unwrap
|
||||
@@ -115,28 +114,26 @@ class RoomSettingsViewModel @AssistedInject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
val powerLevelsContentLive = PowerLevelsFlowFactory(room).createFlow()
|
||||
|
||||
powerLevelsContentLive
|
||||
.onEach {
|
||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||
val powerLevelsFlow = PowerLevelsFlowFactory(room).createFlow()
|
||||
powerLevelsFlow
|
||||
.onEach { roomPowerLevels ->
|
||||
val permissions = RoomSettingsViewState.ActionPermissions(
|
||||
canChangeAvatar = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_AVATAR),
|
||||
canChangeName = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_NAME),
|
||||
canChangeTopic = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_TOPIC),
|
||||
canChangeHistoryVisibility = powerLevelsHelper.isUserAllowedToSend(
|
||||
canChangeAvatar = roomPowerLevels.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_AVATAR),
|
||||
canChangeName = roomPowerLevels.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_NAME),
|
||||
canChangeTopic = roomPowerLevels.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_TOPIC),
|
||||
canChangeHistoryVisibility = roomPowerLevels.isUserAllowedToSend(
|
||||
session.myUserId, true,
|
||||
EventType.STATE_ROOM_HISTORY_VISIBILITY
|
||||
),
|
||||
canChangeJoinRule = powerLevelsHelper.isUserAllowedToSend(
|
||||
canChangeJoinRule = roomPowerLevels.isUserAllowedToSend(
|
||||
session.myUserId, true,
|
||||
EventType.STATE_ROOM_JOIN_RULES
|
||||
) &&
|
||||
powerLevelsHelper.isUserAllowedToSend(
|
||||
roomPowerLevels.isUserAllowedToSend(
|
||||
session.myUserId, true,
|
||||
EventType.STATE_ROOM_GUEST_ACCESS
|
||||
),
|
||||
canAddChildren = powerLevelsHelper.isUserAllowedToSend(
|
||||
canAddChildren = roomPowerLevels.isUserAllowedToSend(
|
||||
session.myUserId, true,
|
||||
EventType.STATE_SPACE_CHILD
|
||||
)
|
||||
|
@@ -32,7 +32,6 @@ import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.getRoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
@@ -74,20 +73,19 @@ class SpaceMenuViewModel @AssistedInject constructor(
|
||||
|
||||
PowerLevelsFlowFactory(room)
|
||||
.createFlow()
|
||||
.onEach {
|
||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||
.onEach { roomPowerLevels ->
|
||||
|
||||
val canInvite = powerLevelsHelper.isUserAbleToInvite(session.myUserId)
|
||||
val canAddChild = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_SPACE_CHILD)
|
||||
val canInvite = roomPowerLevels.isUserAbleToInvite(session.myUserId)
|
||||
val canAddChild = roomPowerLevels.isUserAllowedToSend(session.myUserId, true, EventType.STATE_SPACE_CHILD)
|
||||
|
||||
val canChangeAvatar = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_AVATAR)
|
||||
val canChangeName = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_NAME)
|
||||
val canChangeTopic = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_TOPIC)
|
||||
val canChangeAvatar = roomPowerLevels.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_AVATAR)
|
||||
val canChangeName = roomPowerLevels.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_NAME)
|
||||
val canChangeTopic = roomPowerLevels.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_TOPIC)
|
||||
|
||||
val isAdmin = powerLevelsHelper.getUserRole(session.myUserId) is Role.Admin
|
||||
val isAdmin = roomPowerLevels.getUserRole(session.myUserId) == Role.Admin
|
||||
val otherAdminCount = roomSummary?.otherMemberIds
|
||||
?.map { powerLevelsHelper.getUserRole(it) }
|
||||
?.count { it is Role.Admin }
|
||||
?.map { roomPowerLevels.getUserRole(it) }
|
||||
?.count { it == Role.Admin }
|
||||
?: 0
|
||||
val isLastAdmin = isAdmin && otherAdminCount == 0
|
||||
|
||||
|
@@ -27,6 +27,7 @@ import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
|
||||
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset
|
||||
import org.matrix.android.sdk.api.session.room.model.create.RestrictedRoomPreset
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.UserPowerLevel
|
||||
import org.matrix.android.sdk.api.session.space.CreateSpaceParams
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
@@ -65,7 +66,7 @@ class CreateSpaceViewModelTask @Inject constructor(
|
||||
if (params.isPublic) {
|
||||
this.roomAliasName = params.spaceAlias
|
||||
this.powerLevelContentOverride = (powerLevelContentOverride ?: PowerLevelsContent()).copy(
|
||||
invite = Role.Default.value
|
||||
invite = UserPowerLevel.User.value
|
||||
)
|
||||
this.preset = CreateRoomPreset.PRESET_PUBLIC_CHAT
|
||||
this.historyVisibility = RoomHistoryVisibility.WORLD_READABLE
|
||||
@@ -79,7 +80,7 @@ class CreateSpaceViewModelTask @Inject constructor(
|
||||
}
|
||||
)
|
||||
this.powerLevelContentOverride = (powerLevelContentOverride ?: PowerLevelsContent()).copy(
|
||||
invite = Role.Moderator.value
|
||||
invite = UserPowerLevel.Moderator.value
|
||||
)
|
||||
}
|
||||
})
|
||||
|
@@ -36,7 +36,6 @@ import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomType
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import timber.log.Timber
|
||||
@@ -96,16 +95,14 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
||||
private fun observePermissions() {
|
||||
val room = session.getRoom(initialState.spaceId) ?: return
|
||||
|
||||
val powerLevelsContentLive = PowerLevelsFlowFactory(room).createFlow()
|
||||
val powerLevelsFlow = PowerLevelsFlowFactory(room).createFlow()
|
||||
|
||||
powerLevelsContentLive
|
||||
.onEach {
|
||||
val powerLevelsHelper = PowerLevelsHelper(it)
|
||||
powerLevelsFlow
|
||||
.onEach { roomPowerLevels ->
|
||||
setState {
|
||||
copy(
|
||||
canAddRooms = powerLevelsHelper.isUserAllowedToSend(
|
||||
session.myUserId, true,
|
||||
EventType.STATE_SPACE_CHILD
|
||||
canAddRooms = roomPowerLevels.isUserAllowedToSend(
|
||||
userId = session.myUserId, isState = true, eventType = EventType.STATE_SPACE_CHILD
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@@ -31,10 +31,11 @@ import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.room.getRoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.getStateEvent
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.Role
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
@@ -50,14 +51,12 @@ class SpaceLeaveAdvancedViewModel @AssistedInject constructor(
|
||||
init {
|
||||
val space = session.getRoom(initialState.spaceId)
|
||||
val spaceSummary = space?.roomSummary()
|
||||
|
||||
val powerLevelsEvent = space?.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
|
||||
powerLevelsEvent?.content?.toModel<PowerLevelsContent>()?.let { powerLevelsContent ->
|
||||
val powerLevelsHelper = PowerLevelsHelper(powerLevelsContent)
|
||||
val isAdmin = powerLevelsHelper.getUserRole(session.myUserId) is Role.Admin
|
||||
val roomPowerLevels = space?.getRoomPowerLevels()
|
||||
roomPowerLevels?.let {
|
||||
val isAdmin = roomPowerLevels.getUserRole(session.myUserId) == Role.Admin
|
||||
val otherAdminCount = spaceSummary?.otherMemberIds
|
||||
?.map { powerLevelsHelper.getUserRole(it) }
|
||||
?.count { it is Role.Admin }
|
||||
?.map { roomPowerLevels.getUserRole(it) }
|
||||
?.count { it == Role.Admin }
|
||||
?: 0
|
||||
val isLastAdmin = isAdmin && otherAdminCount == 0
|
||||
setState {
|
||||
|
@@ -54,7 +54,7 @@ class SpacePeopleListController @Inject constructor(
|
||||
memberSummaries.forEach { memberEntry ->
|
||||
|
||||
val filtered = memberEntry.second
|
||||
.filter { roomMemberSummaryFilter.test(it) }
|
||||
.filter { roomMemberSummaryFilter.test(it.summary) }
|
||||
if (filtered.isNotEmpty()) {
|
||||
dividerItem {
|
||||
id("divider_type_${memberEntry.first.titleRes}")
|
||||
@@ -65,10 +65,10 @@ class SpacePeopleListController @Inject constructor(
|
||||
.join(
|
||||
each = { _, roomMember ->
|
||||
profileMatrixItemWithPowerLevel {
|
||||
id(roomMember.userId)
|
||||
matrixItem(roomMember.toMatrixItem())
|
||||
id(roomMember.summary.userId)
|
||||
matrixItem(roomMember.summary.toMatrixItem())
|
||||
avatarRenderer(host.avatarRenderer)
|
||||
userVerificationLevel(data.trustLevelMap.invoke()?.get(roomMember.userId))
|
||||
userVerificationLevel(data.trustLevelMap.invoke()?.get(roomMember.summary.userId))
|
||||
.apply {
|
||||
val pl = host.toPowerLevelLabel(memberEntry.first)
|
||||
if (memberEntry.first == RoomMemberListCategories.INVITE) {
|
||||
@@ -106,13 +106,13 @@ class SpacePeopleListController @Inject constructor(
|
||||
}
|
||||
|
||||
clickListener {
|
||||
host.listener?.onSpaceMemberClicked(roomMember)
|
||||
host.listener?.onSpaceMemberClicked(roomMember.summary)
|
||||
}
|
||||
}
|
||||
},
|
||||
between = { _, roomMemberBefore ->
|
||||
dividerItem {
|
||||
id("divider_${roomMemberBefore.userId}")
|
||||
id("divider_${roomMemberBefore.summary.userId}")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@@ -23,7 +23,7 @@ import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.getRoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
|
||||
class ShareSpaceViewModel @AssistedInject constructor(
|
||||
@Assisted private val initialState: ShareSpaceViewState,
|
||||
@@ -52,11 +52,10 @@ class ShareSpaceViewModel @AssistedInject constructor(
|
||||
val room = session.getRoom(initialState.spaceId) ?: return
|
||||
PowerLevelsFlowFactory(room)
|
||||
.createFlow()
|
||||
.onEach { powerLevelContent ->
|
||||
val powerLevelsHelper = PowerLevelsHelper(powerLevelContent)
|
||||
.onEach { roomPowerLevels ->
|
||||
setState {
|
||||
copy(
|
||||
canInviteByMxId = powerLevelsHelper.isUserAbleToInvite(session.myUserId)
|
||||
canInviteByMxId = roomPowerLevels.isUserAbleToInvite(session.myUserId)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -33,10 +33,11 @@ import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.room.Room
|
||||
import org.matrix.android.sdk.api.session.room.getRoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.getStateEvent
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import org.matrix.android.sdk.flow.unwrap
|
||||
import timber.log.Timber
|
||||
@@ -139,12 +140,8 @@ class StartVoiceBroadcastUseCase @Inject constructor(
|
||||
|
||||
@VisibleForTesting
|
||||
fun assertHasEnoughPowerLevels(room: Room) {
|
||||
val powerLevelsHelper = room.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
|
||||
?.content
|
||||
?.toModel<PowerLevelsContent>()
|
||||
?.let { PowerLevelsHelper(it) }
|
||||
|
||||
if (powerLevelsHelper?.isUserAllowedToSend(session.myUserId, true, VoiceBroadcastConstants.STATE_ROOM_VOICE_BROADCAST_INFO) != true) {
|
||||
val roomPowerLevels = room.getRoomPowerLevels()
|
||||
if (!roomPowerLevels.isUserAllowedToSend(session.myUserId, true, VoiceBroadcastConstants.STATE_ROOM_VOICE_BROADCAST_INFO)) {
|
||||
Timber.d("## StartVoiceBroadcastUseCase: Cannot start voice broadcast: no permission")
|
||||
throw VoiceBroadcastFailure.RecordingError.NoPermission
|
||||
}
|
||||
|
@@ -25,10 +25,11 @@ import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.room.getRoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.room.getStateEvent
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.widgets.WidgetPostAPIMediator
|
||||
import org.matrix.android.sdk.api.util.JsonDict
|
||||
import timber.log.Timber
|
||||
@@ -146,13 +147,8 @@ class WidgetPostAPIHandler @AssistedInject constructor(
|
||||
|
||||
Timber.d("## canSendEvent() : eventType $eventType isState $isState")
|
||||
|
||||
val powerLevelsEvent = room.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
|
||||
val powerLevelsContent = powerLevelsEvent?.content?.toModel<PowerLevelsContent>()
|
||||
val canSend = if (powerLevelsContent == null) {
|
||||
false
|
||||
} else {
|
||||
PowerLevelsHelper(powerLevelsContent).isUserAllowedToSend(session.myUserId, isState, eventType)
|
||||
}
|
||||
val roomPowerLevels = room.getRoomPowerLevels()
|
||||
val canSend = roomPowerLevels.isUserAllowedToSend(session.myUserId, isState, eventType)
|
||||
if (canSend) {
|
||||
Timber.d("## canSendEvent() returns true")
|
||||
widgetPostAPIMediator.sendBoolResponse(true, eventData)
|
||||
|
@@ -19,9 +19,11 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
|
||||
import im.vector.app.features.widgets.permissions.WidgetPermissionsHelper
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
@@ -31,7 +33,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.getRoom
|
||||
import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService
|
||||
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
|
||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.android.sdk.api.session.widgets.WidgetManagementFailure
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
import org.matrix.android.sdk.flow.mapOptional
|
||||
@@ -102,11 +104,10 @@ class WidgetViewModel @AssistedInject constructor(
|
||||
if (room == null) {
|
||||
return
|
||||
}
|
||||
room.flow().liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
|
||||
.mapOptional { it.content.toModel<PowerLevelsContent>() }
|
||||
.unwrap()
|
||||
.map {
|
||||
PowerLevelsHelper(it).isUserAllowedToSend(session.myUserId, true, null)
|
||||
PowerLevelsFlowFactory(room)
|
||||
.createFlow()
|
||||
.map { roomPowerLevels ->
|
||||
roomPowerLevels.isUserAllowedToSend(session.myUserId, true, null)
|
||||
}
|
||||
.setOnEach {
|
||||
copy(canManageWidgets = it)
|
||||
|
@@ -13,7 +13,7 @@ import com.airbnb.mvrx.test.MavericksTestRule
|
||||
import im.vector.app.features.roomprofile.RoomProfileArgs
|
||||
import im.vector.app.features.roomprofile.members.RoomMemberListViewModel
|
||||
import im.vector.app.features.roomprofile.members.RoomMemberListViewState
|
||||
import im.vector.app.features.roomprofile.members.RoomMemberSummaryComparator
|
||||
import im.vector.app.features.roomprofile.members.RoomMemberListComparator
|
||||
import im.vector.app.test.test
|
||||
import im.vector.app.test.testCoroutineDispatchers
|
||||
import io.mockk.coEvery
|
||||
@@ -266,7 +266,7 @@ class MemberListViewModelTest {
|
||||
private fun createViewModel(): RoomMemberListViewModel {
|
||||
return RoomMemberListViewModel(
|
||||
RoomMemberListViewState(args),
|
||||
RoomMemberSummaryComparator(),
|
||||
RoomMemberListComparator(),
|
||||
fakeSession,
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user