Merge pull request #5879 from element-hq/feature/fga/room_permissions_rework
misc : rework power levels apis
This commit is contained in:
commit
5bb71db3b1
55 changed files with 1075 additions and 1054 deletions
|
|
@ -14,6 +14,7 @@ import io.element.android.libraries.matrix.api.core.SessionId
|
|||
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevelsValues
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
|
|
@ -99,6 +100,11 @@ interface BaseRoom : Closeable {
|
|||
*/
|
||||
suspend fun userRole(userId: UserId): Result<RoomMember.Role>
|
||||
|
||||
/**
|
||||
* Gets the permissions of the room.
|
||||
*/
|
||||
suspend fun roomPermissions(): Result<RoomPermissions>
|
||||
|
||||
/**
|
||||
* Gets the display name of the user with the provided [userId] in the room.
|
||||
*/
|
||||
|
|
@ -124,57 +130,6 @@ interface BaseRoom : Closeable {
|
|||
*/
|
||||
suspend fun forget(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can invite other users to the room.
|
||||
*/
|
||||
suspend fun canUserInvite(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can kick other users from the room.
|
||||
*/
|
||||
suspend fun canUserKick(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can ban other users from the room.
|
||||
*/
|
||||
suspend fun canUserBan(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can redact their own messages.
|
||||
*/
|
||||
suspend fun canUserRedactOwn(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can redact messages from other users.
|
||||
*/
|
||||
suspend fun canUserRedactOther(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can send state events.
|
||||
*/
|
||||
suspend fun canUserSendState(userId: UserId, type: StateEventType): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can send messages.
|
||||
*/
|
||||
suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can trigger an `@room` notification.
|
||||
*/
|
||||
suspend fun canUserTriggerRoomNotification(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can pin or unpin messages.
|
||||
*/
|
||||
suspend fun canUserPinUnpin(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can join or starts calls.
|
||||
*/
|
||||
suspend fun canUserJoinCall(userId: UserId): Result<Boolean> =
|
||||
canUserSendState(userId, StateEventType.CALL_MEMBER)
|
||||
|
||||
/**
|
||||
* Sets the room as favorite or not, based on the [isFavorite] parameter.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.api.room.powerlevels
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
/**
|
||||
* Provides information about the permissions of users in a room.
|
||||
*/
|
||||
interface RoomPermissions : AutoCloseable {
|
||||
fun canOwnUserBan(): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the current user is able to invite in the room.
|
||||
*/
|
||||
fun canOwnUserInvite(): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the current user is able to kick in the room.
|
||||
*/
|
||||
fun canOwnUserKick(): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the current user is able to pin or unpin events in the
|
||||
* room.
|
||||
*/
|
||||
fun canOwnUserPinUnpin(): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the current user user is able to redact messages of
|
||||
* other users in the room.
|
||||
*/
|
||||
fun canOwnUserRedactOther(): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the current user is able to redact their own messages in
|
||||
* the room.
|
||||
*/
|
||||
fun canOwnUserRedactOwn(): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the current user is able to send a specific message type
|
||||
* in the room.
|
||||
*/
|
||||
fun canOwnUserSendMessage(message: MessageEventType): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the current user is able to send a specific state event
|
||||
* type in the room.
|
||||
*/
|
||||
fun canOwnUserSendState(stateEvent: StateEventType): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the current user is able to trigger a notification in
|
||||
* the room.
|
||||
*/
|
||||
fun canOwnUserTriggerRoomNotification(): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the user with the given userId is able to ban in the
|
||||
* room.
|
||||
*/
|
||||
fun canUserBan(userId: UserId): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the user with the given userId is able to invite in the
|
||||
* room.
|
||||
*/
|
||||
fun canUserInvite(userId: UserId): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the user with the given userId is able to kick in the
|
||||
* room.
|
||||
*/
|
||||
fun canUserKick(userId: UserId): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the user with the given userId is able to pin or unpin
|
||||
* events in the room.
|
||||
*/
|
||||
fun canUserPinUnpin(userId: UserId): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the user with the given userId is able to redact
|
||||
* messages of other users in the room.
|
||||
*/
|
||||
fun canUserRedactOther(userId: UserId): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the user with the given userId is able to redact
|
||||
* their own messages in the room.
|
||||
*/
|
||||
fun canUserRedactOwn(userId: UserId): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the user with the given userId is able to send a
|
||||
* specific message type in the room.
|
||||
*/
|
||||
fun canUserSendMessage(userId: UserId, message: MessageEventType): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the user with the given userId is able to send a
|
||||
* specific state event type in the room.
|
||||
*/
|
||||
fun canUserSendState(userId: UserId, stateEvent: StateEventType): Boolean
|
||||
|
||||
/**
|
||||
* Returns true if the user with the given userId is able to trigger a
|
||||
* notification in the room.
|
||||
*
|
||||
* The call may fail if there is an error in getting the power levels.
|
||||
*/
|
||||
fun canUserTriggerRoomNotification(userId: UserId): Boolean
|
||||
}
|
||||
|
||||
fun RoomPermissions.canEditRolesAndPermissions(): Boolean {
|
||||
return canOwnUserSendState(StateEventType.ROOM_POWER_LEVELS)
|
||||
}
|
||||
|
||||
fun RoomPermissions.canCall(): Boolean {
|
||||
return canOwnUserSendState(StateEventType.CALL_MEMBER)
|
||||
}
|
||||
|
||||
fun <T> Result<RoomPermissions>.use(default: T, block: (RoomPermissions) -> T): T {
|
||||
return fold(
|
||||
onSuccess = { perms ->
|
||||
perms.use(block)
|
||||
},
|
||||
onFailure = {
|
||||
default
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun <T> BaseRoom.permissionsFlow(default: T, block: (RoomPermissions) -> T): Flow<T> {
|
||||
return roomInfoFlow
|
||||
.map { info ->
|
||||
// If the user is a privileged creator, we return a constant hashcode to avoid recomputing permissions
|
||||
// each time the power levels change (as they have all permissions).
|
||||
if (info.privilegedCreatorRole && info.creators.contains(sessionId)) {
|
||||
Long.MAX_VALUE
|
||||
} else {
|
||||
info.roomPowerLevels?.hashCode() ?: 0L
|
||||
}
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.map {
|
||||
roomPermissions().use(default, block)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun <T> BaseRoom.permissionsAsState(default: T, block: (RoomPermissions) -> T): State<T> {
|
||||
return remember(this, default, block) {
|
||||
permissionsFlow(default, block)
|
||||
}.collectAsState(default)
|
||||
}
|
||||
|
|
@ -8,11 +8,6 @@
|
|||
|
||||
package io.element.android.libraries.matrix.api.room.powerlevels
|
||||
|
||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
|
||||
data class RoomPowerLevelsValues(
|
||||
val ban: Long,
|
||||
val invite: Long,
|
||||
|
|
@ -24,50 +19,3 @@ data class RoomPowerLevelsValues(
|
|||
val roomTopic: Long,
|
||||
val spaceChild: Long,
|
||||
)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserInvite] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canInvite(): Result<Boolean> = canUserInvite(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserKick] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canKick(): Result<Boolean> = canUserKick(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserBan] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canBan(): Result<Boolean> = canUserBan(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserSendState] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canSendState(type: StateEventType): Result<Boolean> = canUserSendState(sessionId, type)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserSendMessage] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canSendMessage(type: MessageEventType): Result<Boolean> = canUserSendMessage(sessionId, type)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserRedactOwn] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canRedactOwn(): Result<Boolean> = canUserRedactOwn(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canRedactOther] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canRedactOther(): Result<Boolean> = canUserRedactOther(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for checking if current user can handle knock requests.
|
||||
*/
|
||||
suspend fun BaseRoom.canHandleKnockRequests(): Result<Boolean> = runCatchingExceptions {
|
||||
canInvite().getOrThrow() || canBan().getOrThrow() || canKick().getOrThrow()
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserPinUnpin] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canPinUnpin(): Result<Boolean> = canUserPinUnpin(sessionId)
|
||||
|
|
|
|||
|
|
@ -18,13 +18,12 @@ import io.element.android.libraries.matrix.api.core.SessionId
|
|||
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevelsValues
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
|
|
@ -33,6 +32,7 @@ import io.element.android.libraries.matrix.impl.room.draft.into
|
|||
import io.element.android.libraries.matrix.impl.room.member.RoomMemberListFetcher
|
||||
import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper
|
||||
import io.element.android.libraries.matrix.impl.room.powerlevels.RoomPowerLevelsValuesMapper
|
||||
import io.element.android.libraries.matrix.impl.room.powerlevels.RustRoomPermissions
|
||||
import io.element.android.libraries.matrix.impl.room.tombstone.map
|
||||
import io.element.android.libraries.matrix.impl.roomdirectory.map
|
||||
import io.element.android.libraries.matrix.impl.timeline.toRustReceiptType
|
||||
|
|
@ -180,57 +180,9 @@ class RustBaseRoom(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserInvite(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
override suspend fun roomPermissions(): Result<RoomPermissions> = withContext(roomDispatcher) {
|
||||
runCatchingExceptions {
|
||||
innerRoom.getPowerLevels().use { it.canUserInvite(userId.value) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserKick(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatchingExceptions {
|
||||
innerRoom.getPowerLevels().use { it.canUserKick(userId.value) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserBan(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatchingExceptions {
|
||||
innerRoom.getPowerLevels().use { it.canUserBan(userId.value) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserRedactOwn(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatchingExceptions {
|
||||
innerRoom.getPowerLevels().use { it.canUserRedactOwn(userId.value) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserRedactOther(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatchingExceptions {
|
||||
innerRoom.getPowerLevels().use { it.canUserRedactOther(userId.value) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserSendState(userId: UserId, type: StateEventType): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatchingExceptions {
|
||||
innerRoom.getPowerLevels().use { it.canUserSendState(userId.value, type.map()) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatchingExceptions {
|
||||
innerRoom.getPowerLevels().use { it.canUserSendMessage(userId.value, type.map()) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserTriggerRoomNotification(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatchingExceptions {
|
||||
innerRoom.getPowerLevels().use { it.canUserTriggerRoomNotification(userId.value) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserPinUnpin(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatchingExceptions {
|
||||
innerRoom.getPowerLevels().use { it.canUserPinUnpin(userId.value) }
|
||||
RustRoomPermissions(innerRoom.getPowerLevels())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.room.powerlevels
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
|
||||
import io.element.android.libraries.matrix.impl.room.map
|
||||
import org.matrix.rustcomponents.sdk.RoomPowerLevels
|
||||
|
||||
class RustRoomPermissions(
|
||||
private val inner: RoomPowerLevels,
|
||||
) : RoomPermissions {
|
||||
override fun canOwnUserBan(): Boolean {
|
||||
return inner.canOwnUserBan()
|
||||
}
|
||||
|
||||
override fun canOwnUserInvite(): Boolean {
|
||||
return inner.canOwnUserInvite()
|
||||
}
|
||||
|
||||
override fun canOwnUserKick(): Boolean {
|
||||
return inner.canOwnUserKick()
|
||||
}
|
||||
|
||||
override fun canOwnUserPinUnpin(): Boolean {
|
||||
return inner.canOwnUserPinUnpin()
|
||||
}
|
||||
|
||||
override fun canOwnUserRedactOther(): Boolean {
|
||||
return inner.canOwnUserRedactOther()
|
||||
}
|
||||
|
||||
override fun canOwnUserRedactOwn(): Boolean {
|
||||
return inner.canOwnUserRedactOwn()
|
||||
}
|
||||
|
||||
override fun canOwnUserSendMessage(message: MessageEventType): Boolean {
|
||||
return inner.canOwnUserSendMessage(message.map())
|
||||
}
|
||||
|
||||
override fun canOwnUserSendState(stateEvent: StateEventType): Boolean {
|
||||
return inner.canOwnUserSendState(stateEvent.map())
|
||||
}
|
||||
|
||||
override fun canOwnUserTriggerRoomNotification(): Boolean {
|
||||
return inner.canOwnUserTriggerRoomNotification()
|
||||
}
|
||||
|
||||
override fun canUserBan(userId: UserId): Boolean {
|
||||
return inner.canUserBan(userId.value)
|
||||
}
|
||||
|
||||
override fun canUserInvite(userId: UserId): Boolean {
|
||||
return inner.canUserInvite(userId.value)
|
||||
}
|
||||
|
||||
override fun canUserKick(userId: UserId): Boolean {
|
||||
return inner.canUserKick(userId.value)
|
||||
}
|
||||
|
||||
override fun canUserPinUnpin(userId: UserId): Boolean {
|
||||
return inner.canUserPinUnpin(userId.value)
|
||||
}
|
||||
|
||||
override fun canUserRedactOther(userId: UserId): Boolean {
|
||||
return inner.canUserRedactOther(userId.value)
|
||||
}
|
||||
|
||||
override fun canUserRedactOwn(userId: UserId): Boolean {
|
||||
return inner.canUserRedactOwn(userId.value)
|
||||
}
|
||||
|
||||
override fun canUserSendMessage(userId: UserId, message: MessageEventType): Boolean {
|
||||
return inner.canUserSendMessage(userId.value, message.map())
|
||||
}
|
||||
|
||||
override fun canUserSendState(userId: UserId, stateEvent: StateEventType): Boolean {
|
||||
return inner.canUserSendState(userId.value, stateEvent.map())
|
||||
}
|
||||
|
||||
override fun canUserTriggerRoomNotification(userId: UserId): Boolean {
|
||||
return inner.canUserTriggerRoomNotification(userId.value)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
inner.close()
|
||||
}
|
||||
}
|
||||
|
|
@ -15,18 +15,18 @@ import io.element.android.libraries.matrix.api.core.SessionId
|
|||
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevelsValues
|
||||
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.simulateLongTask
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
@ -40,6 +40,7 @@ class FakeBaseRoom(
|
|||
override val sessionId: SessionId = A_SESSION_ID,
|
||||
override val roomId: RoomId = A_ROOM_ID,
|
||||
initialRoomInfo: RoomInfo = aRoomInfo(),
|
||||
private val roomPermissions: RoomPermissions = FakeRoomPermissions(),
|
||||
override val roomCoroutineScope: CoroutineScope = TestScope(),
|
||||
private var roomPermalinkResult: () -> Result<String> = { lambdaError() },
|
||||
private var eventPermalinkResult: (EventId) -> Result<String> = { lambdaError() },
|
||||
|
|
@ -48,16 +49,6 @@ class FakeBaseRoom(
|
|||
private val userRoleResult: () -> Result<RoomMember.Role> = { lambdaError() },
|
||||
private val getUpdatedMemberResult: (UserId) -> Result<RoomMember> = { lambdaError() },
|
||||
private val joinRoomResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val canInviteResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canKickResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canBanResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canRedactOwnResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canRedactOtherResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canSendStateResult: (UserId, StateEventType) -> Result<Boolean> = { _, _ -> lambdaError() },
|
||||
private val canUserSendMessageResult: (UserId, MessageEventType) -> Result<Boolean> = { _, _ -> lambdaError() },
|
||||
private val canUserTriggerRoomNotificationResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canUserJoinCallResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canUserPinUnpinResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val setIsFavoriteResult: (Boolean) -> Result<Unit> = { lambdaError() },
|
||||
private val markAsReadResult: (ReceiptType) -> Result<Unit> = { Result.success(Unit) },
|
||||
private val powerLevelsResult: () -> Result<RoomPowerLevelsValues> = { lambdaError() },
|
||||
|
|
@ -129,6 +120,10 @@ class FakeBaseRoom(
|
|||
return userRoleResult()
|
||||
}
|
||||
|
||||
override suspend fun roomPermissions(): Result<RoomPermissions> {
|
||||
return Result.success(roomPermissions)
|
||||
}
|
||||
|
||||
override suspend fun getPermalink(): Result<String> {
|
||||
return roomPermalinkResult()
|
||||
}
|
||||
|
|
@ -153,46 +148,6 @@ class FakeBaseRoom(
|
|||
return forgetResult()
|
||||
}
|
||||
|
||||
override suspend fun canUserBan(userId: UserId): Result<Boolean> {
|
||||
return canBanResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserKick(userId: UserId): Result<Boolean> {
|
||||
return canKickResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserInvite(userId: UserId): Result<Boolean> {
|
||||
return canInviteResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserRedactOwn(userId: UserId): Result<Boolean> {
|
||||
return canRedactOwnResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserRedactOther(userId: UserId): Result<Boolean> {
|
||||
return canRedactOtherResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserSendState(userId: UserId, type: StateEventType): Result<Boolean> {
|
||||
return canSendStateResult(userId, type)
|
||||
}
|
||||
|
||||
override suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result<Boolean> {
|
||||
return canUserSendMessageResult(userId, type)
|
||||
}
|
||||
|
||||
override suspend fun canUserTriggerRoomNotification(userId: UserId): Result<Boolean> {
|
||||
return canUserTriggerRoomNotificationResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserJoinCall(userId: UserId): Result<Boolean> {
|
||||
return canUserJoinCallResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserPinUnpin(userId: UserId): Result<Boolean> {
|
||||
return canUserPinUnpinResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun setIsFavorite(isFavorite: Boolean): Result<Unit> {
|
||||
return setIsFavoriteResult(isFavorite)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.test.room.powerlevels
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
|
||||
|
||||
data class FakeRoomPermissions(
|
||||
private val canBan: Boolean = false,
|
||||
private val canInvite: Boolean = false,
|
||||
private val canKick: Boolean = false,
|
||||
private val canPinUnpin: Boolean = false,
|
||||
private val canRedactOther: Boolean = false,
|
||||
private val canRedactOwn: Boolean = false,
|
||||
private val canTriggerRoomNotification: Boolean = false,
|
||||
private val canSendMessage: (MessageEventType) -> Boolean = { false },
|
||||
private val canSendState: (StateEventType) -> Boolean = { false },
|
||||
private val canUserBan: (UserId) -> Boolean = { false },
|
||||
private val canUserInvite: (UserId) -> Boolean = { false },
|
||||
private val canUserKick: (UserId) -> Boolean = { false },
|
||||
private val canUserPinUnpin: (UserId) -> Boolean = { false },
|
||||
private val canUserRedactOther: (UserId) -> Boolean = { false },
|
||||
private val canUserRedactOwn: (UserId) -> Boolean = { false },
|
||||
private val canUserTriggerRoomNotification: (UserId) -> Boolean = { false },
|
||||
private val canUserSendMessage: (UserId, MessageEventType) -> Boolean = { _, _ -> false },
|
||||
private val canUserSendState: (UserId, StateEventType) -> Boolean = { _, _ -> false },
|
||||
) : RoomPermissions {
|
||||
override fun canOwnUserBan(): Boolean = canBan
|
||||
override fun canOwnUserInvite(): Boolean = canInvite
|
||||
override fun canOwnUserKick(): Boolean = canKick
|
||||
override fun canOwnUserPinUnpin(): Boolean = canPinUnpin
|
||||
override fun canOwnUserRedactOther(): Boolean = canRedactOther
|
||||
override fun canOwnUserRedactOwn(): Boolean = canRedactOwn
|
||||
override fun canOwnUserSendMessage(message: MessageEventType): Boolean = canSendMessage(message)
|
||||
override fun canOwnUserSendState(stateEvent: StateEventType): Boolean = canSendState(stateEvent)
|
||||
|
||||
override fun canOwnUserTriggerRoomNotification(): Boolean = canTriggerRoomNotification
|
||||
override fun canUserBan(userId: UserId): Boolean = canUserBan(userId)
|
||||
override fun canUserInvite(userId: UserId): Boolean = canUserInvite(userId)
|
||||
override fun canUserKick(userId: UserId): Boolean = canUserKick(userId)
|
||||
override fun canUserPinUnpin(userId: UserId): Boolean = canUserPinUnpin(userId)
|
||||
override fun canUserRedactOther(userId: UserId): Boolean = canUserRedactOther(userId)
|
||||
override fun canUserRedactOwn(userId: UserId): Boolean = canUserRedactOwn(userId)
|
||||
override fun canUserSendMessage(userId: UserId, message: MessageEventType): Boolean = canUserSendMessage(userId, message)
|
||||
override fun canUserSendState(userId: UserId, stateEvent: StateEventType): Boolean = canUserSendState(userId, stateEvent)
|
||||
override fun canUserTriggerRoomNotification(userId: UserId): Boolean = canUserTriggerRoomNotification(userId)
|
||||
|
||||
override fun close() {
|
||||
// no-op for the fake
|
||||
}
|
||||
}
|
||||
|
|
@ -14,88 +14,9 @@ import androidx.compose.runtime.collectAsState
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.produceState
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.isDm
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canBan
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canHandleKnockRequests
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canInvite
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canKick
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canSendMessage
|
||||
import io.element.android.libraries.matrix.ui.model.roleOf
|
||||
|
||||
@Composable
|
||||
fun BaseRoom.canSendMessageAsState(type: MessageEventType, updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = true, key1 = updateKey) {
|
||||
value = canSendMessage(type).getOrElse { true }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BaseRoom.canInviteAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canInvite().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BaseRoom.canRedactOwnAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canRedactOwn().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BaseRoom.canRedactOtherAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canRedactOther().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BaseRoom.canCall(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canUserJoinCall(sessionId).getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BaseRoom.canPinUnpin(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canUserPinUnpin(sessionId).getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BaseRoom.isDmAsState(): State<Boolean> {
|
||||
return produceState(initialValue = false) {
|
||||
roomInfoFlow.collect { value = it.isDm }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BaseRoom.canKickAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canKick().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BaseRoom.canBanAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canBan().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BaseRoom.canHandleKnockRequestsAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canHandleKnockRequests().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BaseRoom.userPowerLevelAsState(updateKey: Long): State<Long> {
|
||||
return produceState(initialValue = 0, key1 = updateKey) {
|
||||
|
|
|
|||
|
|
@ -30,8 +30,7 @@ import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarM
|
|||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
|
||||
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
||||
import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory
|
||||
import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource
|
||||
|
|
@ -39,8 +38,10 @@ import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetSta
|
|||
import io.element.android.libraries.mediaviewer.impl.local.LocalMediaActions
|
||||
import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems
|
||||
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
|
||||
import io.element.android.libraries.mediaviewer.impl.model.MediaPermissions
|
||||
import io.element.android.libraries.mediaviewer.impl.model.eventId
|
||||
import io.element.android.libraries.mediaviewer.impl.model.mediaInfo
|
||||
import io.element.android.libraries.mediaviewer.impl.model.mediaPermissions
|
||||
import io.element.android.libraries.mediaviewer.impl.model.mediaSource
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -80,6 +81,10 @@ class MediaGalleryPresenter(
|
|||
mediaGalleryDataSource.start()
|
||||
}
|
||||
|
||||
val permissions by room.permissionsAsState(MediaPermissions.DEFAULT) { perms ->
|
||||
perms.mediaPermissions()
|
||||
}
|
||||
|
||||
val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState()
|
||||
localMediaActions.Configure()
|
||||
|
||||
|
|
@ -119,8 +124,8 @@ class MediaGalleryPresenter(
|
|||
eventId = event.mediaItem.eventId(),
|
||||
canDelete = when (event.mediaItem.mediaInfo().senderId) {
|
||||
null -> false
|
||||
room.sessionId -> room.canRedactOwn().getOrElse { false } && event.mediaItem.eventId() != null
|
||||
else -> room.canRedactOther().getOrElse { false } && event.mediaItem.eventId() != null
|
||||
room.sessionId -> permissions.canRedactOwn && event.mediaItem.eventId() != null
|
||||
else -> permissions.canRedactOther && event.mediaItem.eventId() != null
|
||||
},
|
||||
mediaInfo = event.mediaItem.mediaInfo(),
|
||||
thumbnailSource = when (event.mediaItem) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.mediaviewer.impl.model
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
|
||||
|
||||
data class MediaPermissions(
|
||||
val canRedactOwn: Boolean,
|
||||
val canRedactOther: Boolean,
|
||||
) {
|
||||
companion object {
|
||||
val DEFAULT = MediaPermissions(
|
||||
canRedactOwn = false,
|
||||
canRedactOther = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun RoomPermissions.mediaPermissions(): MediaPermissions {
|
||||
return MediaPermissions(
|
||||
canRedactOwn = canOwnUserRedactOwn(),
|
||||
canRedactOther = canOwnUserRedactOther(),
|
||||
)
|
||||
}
|
||||
|
|
@ -32,8 +32,7 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
|
|||
import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
|
||||
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
|
||||
|
|
@ -41,6 +40,8 @@ import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
|||
import io.element.android.libraries.mediaviewer.impl.R
|
||||
import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState
|
||||
import io.element.android.libraries.mediaviewer.impl.local.LocalMediaActions
|
||||
import io.element.android.libraries.mediaviewer.impl.model.MediaPermissions
|
||||
import io.element.android.libraries.mediaviewer.impl.model.mediaPermissions
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
@ -81,6 +82,9 @@ class MediaViewerPresenter(
|
|||
NoMoreItemsBackwardSnackBarDisplayer(currentIndex, data)
|
||||
NoMoreItemsForwardSnackBarDisplayer(currentIndex, data)
|
||||
|
||||
val permissions by room.permissionsAsState(MediaPermissions.DEFAULT) { perms ->
|
||||
perms.mediaPermissions()
|
||||
}
|
||||
var mediaBottomSheetState by remember { mutableStateOf<MediaBottomSheetState>(MediaBottomSheetState.Hidden) }
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
|
|
@ -131,8 +135,8 @@ class MediaViewerPresenter(
|
|||
eventId = event.data.eventId,
|
||||
canDelete = when (event.data.mediaInfo.senderId) {
|
||||
null -> false
|
||||
room.sessionId -> room.canRedactOwn().getOrElse { false } && event.data.eventId != null
|
||||
else -> room.canRedactOther().getOrElse { false } && event.data.eventId != null
|
||||
room.sessionId -> permissions.canRedactOwn && event.data.eventId != null
|
||||
else -> permissions.canRedactOther && event.data.eventId != null
|
||||
},
|
||||
mediaInfo = event.data.mediaInfo,
|
||||
thumbnailSource = event.data.thumbnailSource,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader
|
|||
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource
|
||||
import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource
|
||||
|
|
@ -109,7 +110,9 @@ class MediaGalleryPresenterTest {
|
|||
baseRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||
canRedactOwnResult = { Result.success(canDeleteOwn) }
|
||||
roomPermissions = FakeRoomPermissions(
|
||||
canRedactOwn = canDeleteOwn
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
|
@ -153,7 +156,9 @@ class MediaGalleryPresenterTest {
|
|||
baseRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||
canRedactOtherResult = { Result.success(canDeleteOther) },
|
||||
roomPermissions = FakeRoomPermissions(
|
||||
canRedactOther = canDeleteOther
|
||||
),
|
||||
),
|
||||
createTimelineResult = { Result.success(FakeTimeline()) }
|
||||
)
|
||||
|
|
@ -355,7 +360,9 @@ class MediaGalleryPresenterTest {
|
|||
room = FakeJoinedRoom(
|
||||
createTimelineResult = { Result.success(FakeTimeline()) },
|
||||
baseRoom = FakeBaseRoom(
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
roomPermissions = FakeRoomPermissions(
|
||||
canRedactOwn = true
|
||||
),
|
||||
),
|
||||
),
|
||||
navigator = navigator,
|
||||
|
|
@ -386,7 +393,9 @@ class MediaGalleryPresenterTest {
|
|||
room = FakeJoinedRoom(
|
||||
createTimelineResult = { Result.success(FakeTimeline()) },
|
||||
baseRoom = FakeBaseRoom(
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
roomPermissions = FakeRoomPermissions(
|
||||
canRedactOwn = true
|
||||
),
|
||||
),
|
||||
),
|
||||
navigator = navigator,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader
|
|||
import io.element.android.libraries.matrix.test.media.aMediaSource
|
||||
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
|
||||
import io.element.android.libraries.mediaviewer.api.anApkMediaInfo
|
||||
|
|
@ -83,7 +84,9 @@ class MediaViewerPresenterTest {
|
|||
localMediaFactory = localMediaFactory,
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
roomPermissions = FakeRoomPermissions(
|
||||
canRedactOwn = true
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -104,7 +107,9 @@ class MediaViewerPresenterTest {
|
|||
canShowInfo = false,
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
roomPermissions = FakeRoomPermissions(
|
||||
canRedactOwn = true
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -125,7 +130,9 @@ class MediaViewerPresenterTest {
|
|||
eventId = AN_EVENT_ID,
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
roomPermissions = FakeRoomPermissions(
|
||||
canRedactOwn = true
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -147,7 +154,9 @@ class MediaViewerPresenterTest {
|
|||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
sessionId = A_SESSION_ID_2,
|
||||
canRedactOtherResult = { Result.success(false) },
|
||||
roomPermissions = FakeRoomPermissions(
|
||||
canRedactOther = false
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -236,7 +245,9 @@ class MediaViewerPresenterTest {
|
|||
mediaGalleryDataSource = mediaGalleryDataSource,
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
roomPermissions = FakeRoomPermissions(
|
||||
canRedactOwn = true
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -460,7 +471,11 @@ class MediaViewerPresenterTest {
|
|||
localMediaFactory = localMediaFactory,
|
||||
room = FakeJoinedRoom(
|
||||
liveTimeline = timeline,
|
||||
baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }),
|
||||
baseRoom = FakeBaseRoom(
|
||||
roomPermissions = FakeRoomPermissions(
|
||||
canRedactOwn = true
|
||||
),
|
||||
),
|
||||
),
|
||||
mediaGalleryDataSource = mediaGalleryDataSource,
|
||||
mediaViewerNavigator = FakeMediaViewerNavigator(
|
||||
|
|
@ -769,7 +784,11 @@ class MediaViewerPresenterTest {
|
|||
localMediaFactory = localMediaFactory,
|
||||
mediaViewerNavigator = navigator,
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }),
|
||||
baseRoom = FakeBaseRoom(
|
||||
roomPermissions = FakeRoomPermissions(
|
||||
canRedactOwn = true
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
presenter.test {
|
||||
|
|
@ -794,7 +813,11 @@ class MediaViewerPresenterTest {
|
|||
localMediaFactory = localMediaFactory,
|
||||
mediaViewerNavigator = navigator,
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }),
|
||||
baseRoom = FakeBaseRoom(
|
||||
roomPermissions = FakeRoomPermissions(
|
||||
canRedactOwn = true
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
presenter.test {
|
||||
|
|
@ -821,7 +844,11 @@ class MediaViewerPresenterTest {
|
|||
localMediaFactory = localMediaFactory,
|
||||
mediaViewerNavigator = navigator,
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }),
|
||||
baseRoom = FakeBaseRoom(
|
||||
roomPermissions = FakeRoomPermissions(
|
||||
canRedactOwn = true
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
presenter.test {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue