Update dependency org.matrix.rustcomponents:sdk-android to v25.7.23 (#5073)

* Update dependency org.matrix.rustcomponents:sdk-android to v25.7.23

* Adapt to SDK changes:

- Add 'creator' role, adapt existing logic to it.
- Remove `ReplyParameters`, replace with `EventId` where possible.
- Fix changes in OIDC auth methods.
- Add more join rules.

* Make sure both creators and users with power level >= 150 are displayed as 'owners' in the room member list.

* Don't close the roles and permissions screen if the user is a creator

* Use `MediaPreviewValue.DEFAULT` for `MediaPreviewConfig.DEFAULT` too

* Improve APIs around checking roles and power levels:
    - Ensure `RoomInfo.RoomPowerLevels.users` can't be directly used to check power levels since it can't check the power levels for creators.
    - Add a few helper functions to handle actions that relied on the previous `users` property, and docs to explain their usages.

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jorge Martín <jorgem@element.io>
This commit is contained in:
renovate[bot] 2025-07-24 11:58:30 +02:00 committed by GitHub
parent 33aa7a914f
commit 040fde7f22
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
57 changed files with 264 additions and 227 deletions

View file

@ -272,7 +272,7 @@ class RustMatrixClient(
?: sessionId.value.substringAfter(":")
}
override suspend fun getUrl(url: String): Result<String> = withContext(sessionDispatcher) {
override suspend fun getUrl(url: String): Result<ByteArray> = withContext(sessionDispatcher) {
runCatchingExceptions {
innerClient.getUrl(url)
}

View file

@ -200,6 +200,7 @@ class RustMatrixAuthenticationService @Inject constructor(
loginHint = loginHint,
// If we want to restore a previous session for which we have encryption keys, we can pass the deviceId here. At the moment, we don't
deviceId = null,
additionalScopes = emptyList(),
)
val url = oAuthAuthorizationData.loginUrl()
pendingOAuthAuthorizationData = oAuthAuthorizationData

View file

@ -79,8 +79,9 @@ private fun MediaPreviewValue.into(): MediaPreviews {
}
}
private fun MediaPreviews.into(): MediaPreviewValue {
private fun MediaPreviews?.into(): MediaPreviewValue {
return when (this) {
null -> MediaPreviewValue.DEFAULT
MediaPreviews.ON -> MediaPreviewValue.On
MediaPreviews.OFF -> MediaPreviewValue.Off
MediaPreviews.PRIVATE -> MediaPreviewValue.Private

View file

@ -35,7 +35,7 @@ class RoomInfoMapper {
fun map(rustRoomInfo: RustRoomInfo): RoomInfo = rustRoomInfo.let {
return RoomInfo(
id = RoomId(it.id),
creator = it.creator?.let(::UserId),
creators = it.creators.orEmpty().map(::UserId).toImmutableList(),
name = it.displayName,
rawName = it.rawName,
topic = it.topic,

View file

@ -293,7 +293,7 @@ class RustBaseRoom(
override suspend fun reportRoom(reason: String?): Result<Unit> = withContext(roomDispatcher) {
runCatchingExceptions {
Timber.d("reportRoom $roomId")
innerRoom.reportRoom(reason)
innerRoom.reportRoom(reason.orEmpty())
}
}
}

View file

@ -10,6 +10,7 @@ package io.element.android.libraries.matrix.impl.room.member
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.impl.room.powerlevels.into
import uniffi.matrix_sdk.RoomMemberRole
import org.matrix.rustcomponents.sdk.MembershipState as RustMembershipState
import org.matrix.rustcomponents.sdk.RoomMember as RustRoomMember
@ -21,8 +22,8 @@ object RoomMemberMapper {
avatarUrl = roomMember.avatarUrl,
membership = mapMembership(roomMember.membership),
isNameAmbiguous = roomMember.isNameAmbiguous,
powerLevel = roomMember.powerLevel,
normalizedPowerLevel = roomMember.normalizedPowerLevel,
powerLevel = roomMember.powerLevel.into(),
normalizedPowerLevel = roomMember.normalizedPowerLevel.into(),
isIgnored = roomMember.isIgnored,
role = mapRole(roomMember.suggestedRoleForPowerLevel),
membershipChangeReason = roomMember.membershipChangeReason
@ -30,6 +31,7 @@ object RoomMemberMapper {
fun mapRole(role: RoomMemberRole): RoomMember.Role =
when (role) {
RoomMemberRole.CREATOR -> RoomMember.Role.CREATOR
RoomMemberRole.ADMINISTRATOR -> RoomMember.Role.ADMIN
RoomMemberRole.MODERATOR -> RoomMember.Role.MODERATOR
RoomMemberRole.USER -> RoomMember.Role.USER

View file

@ -1,16 +0,0 @@
/*
* 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 io.element.android.libraries.matrix.impl.room.message
import io.element.android.libraries.matrix.api.room.message.ReplyParameters
fun ReplyParameters.map() = org.matrix.rustcomponents.sdk.ReplyParameters(
eventId = inReplyToEventId.value,
enforceThread = enforceThreadReply,
replyWithinThread = replyWithinThread,
)

View file

@ -7,7 +7,9 @@
package io.element.android.libraries.matrix.impl.room.powerlevels
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevelsValues
import org.matrix.rustcomponents.sdk.PowerLevel
import org.matrix.rustcomponents.sdk.RoomPowerLevelsValues as RustRoomPowerLevelsValues
object RoomPowerLevelsValuesMapper {
@ -24,3 +26,8 @@ object RoomPowerLevelsValuesMapper {
)
}
}
fun PowerLevel.into(): Long = when (this) {
PowerLevel.Infinite -> RoomMember.Role.CREATOR.powerLevel
is PowerLevel.Value -> this.value
}

View file

@ -7,14 +7,10 @@
package io.element.android.libraries.matrix.impl.room.tombstone
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
import org.matrix.rustcomponents.sdk.PredecessorRoom as RustPredecessorRoom
fun RustPredecessorRoom.map(): PredecessorRoom {
return PredecessorRoom(
roomId = RoomId(roomId),
lastEventId = EventId(lastEventId),
)
return PredecessorRoom(roomId = RoomId(roomId))
}

View file

@ -32,6 +32,9 @@ internal fun PublicRoomJoinRule?.map(): RoomDescription.JoinRule {
return when (this) {
PublicRoomJoinRule.PUBLIC -> RoomDescription.JoinRule.PUBLIC
PublicRoomJoinRule.KNOCK -> RoomDescription.JoinRule.KNOCK
PublicRoomJoinRule.RESTRICTED -> RoomDescription.JoinRule.RESTRICTED
PublicRoomJoinRule.KNOCK_RESTRICTED -> RoomDescription.JoinRule.KNOCK_RESTRICTED
PublicRoomJoinRule.INVITE -> RoomDescription.JoinRule.INVITE
null -> RoomDescription.JoinRule.UNKNOWN
}
}

View file

@ -23,7 +23,6 @@ import io.element.android.libraries.matrix.api.room.IntentionalMention
import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.matrix.api.room.isDm
import io.element.android.libraries.matrix.api.room.location.AssetType
import io.element.android.libraries.matrix.api.room.message.ReplyParameters
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.ReceiptType
import io.element.android.libraries.matrix.api.timeline.Timeline
@ -37,7 +36,6 @@ import io.element.android.libraries.matrix.impl.media.toMSC3246range
import io.element.android.libraries.matrix.impl.poll.toInner
import io.element.android.libraries.matrix.impl.room.RoomContentForwarder
import io.element.android.libraries.matrix.impl.room.location.toInner
import io.element.android.libraries.matrix.impl.room.message.map
import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper
import io.element.android.libraries.matrix.impl.timeline.item.event.TimelineEventContentMapper
import io.element.android.libraries.matrix.impl.timeline.item.virtual.VirtualTimelineItemMapper
@ -206,18 +204,18 @@ class RustTimeline(
_timelineItems,
backwardPaginationStatus,
forwardPaginationStatus,
joinedRoom.roomInfoFlow.map { it.creator to it.isDm }.distinctUntilChanged(),
joinedRoom.roomInfoFlow.map { it.creators to it.isDm }.distinctUntilChanged(),
) { timelineItems,
backwardPaginationStatus,
forwardPaginationStatus,
(roomCreator, isDm) ->
(roomCreators, isDm) ->
withContext(dispatcher) {
timelineItems
.let { items ->
roomBeginningPostProcessor.process(
items = items,
isDm = isDm,
roomCreator = roomCreator,
roomCreator = roomCreators.firstOrNull(),
hasMoreToLoadBackwards = backwardPaginationStatus.hasMoreToLoad,
)
}
@ -320,7 +318,7 @@ class RustTimeline(
}
override suspend fun replyMessage(
replyParameters: ReplyParameters,
repliedToEventId: EventId,
body: String,
htmlBody: String?,
intentionalMentions: List<IntentionalMention>,
@ -330,7 +328,7 @@ class RustTimeline(
val msg = MessageEventContent.from(body, htmlBody, intentionalMentions)
inner.sendReply(
msg = msg,
replyParams = replyParameters.map(),
eventId = repliedToEventId.value,
)
}
}
@ -342,7 +340,7 @@ class RustTimeline(
caption: String?,
formattedCaption: String?,
progressCallback: ProgressCallback?,
replyParameters: ReplyParameters?,
inReplyToEventId: EventId?,
): Result<MediaUploadHandler> {
val useSendQueue = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue)
return sendAttachment(listOfNotNull(file, thumbnailFile)) {
@ -355,7 +353,7 @@ class RustTimeline(
},
useSendQueue = useSendQueue,
mentions = null,
replyParams = replyParameters?.map(),
inReplyTo = inReplyToEventId?.value,
),
thumbnailPath = thumbnailFile?.path,
imageInfo = imageInfo.map(),
@ -371,7 +369,7 @@ class RustTimeline(
caption: String?,
formattedCaption: String?,
progressCallback: ProgressCallback?,
replyParameters: ReplyParameters?,
inReplyToEventId: EventId?,
): Result<MediaUploadHandler> {
val useSendQueue = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue)
return sendAttachment(listOfNotNull(file, thumbnailFile)) {
@ -384,7 +382,7 @@ class RustTimeline(
},
useSendQueue = useSendQueue,
mentions = null,
replyParams = replyParameters?.map(),
inReplyTo = inReplyToEventId?.value,
),
thumbnailPath = thumbnailFile?.path,
videoInfo = videoInfo.map(),
@ -399,7 +397,7 @@ class RustTimeline(
caption: String?,
formattedCaption: String?,
progressCallback: ProgressCallback?,
replyParameters: ReplyParameters?,
inReplyToEventId: EventId?,
): Result<MediaUploadHandler> {
val useSendQueue = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue)
return sendAttachment(listOf(file)) {
@ -412,7 +410,7 @@ class RustTimeline(
},
useSendQueue = useSendQueue,
mentions = null,
replyParams = replyParameters?.map(),
inReplyTo = inReplyToEventId?.value,
),
audioInfo = audioInfo.map(),
progressWatcher = progressCallback?.toProgressWatcher()
@ -426,7 +424,7 @@ class RustTimeline(
caption: String?,
formattedCaption: String?,
progressCallback: ProgressCallback?,
replyParameters: ReplyParameters?,
inReplyToEventId: EventId?,
): Result<MediaUploadHandler> {
val useSendQueue = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue)
return sendAttachment(listOf(file)) {
@ -439,7 +437,7 @@ class RustTimeline(
},
useSendQueue = useSendQueue,
mentions = null,
replyParams = replyParameters?.map(),
inReplyTo = inReplyToEventId?.value,
),
fileInfo = fileInfo.map(),
progressWatcher = progressCallback?.toProgressWatcher(),
@ -470,7 +468,7 @@ class RustTimeline(
description: String?,
zoomLevel: Int?,
assetType: AssetType?,
replyParameters: ReplyParameters?,
inReplyToEventId: EventId?,
): Result<Unit> = withContext(dispatcher) {
runCatchingExceptions {
inner.sendLocation(
@ -479,7 +477,7 @@ class RustTimeline(
description = description,
zoomLevel = zoomLevel?.toUByte(),
assetType = assetType?.toInner(),
replyParams = replyParameters?.map(),
repliedToEventId = inReplyToEventId?.value,
)
}
}
@ -489,7 +487,7 @@ class RustTimeline(
audioInfo: AudioInfo,
waveform: List<Float>,
progressCallback: ProgressCallback?,
replyParameters: ReplyParameters?,
inReplyToEventId: EventId?,
): Result<MediaUploadHandler> {
val useSendQueue = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue)
return sendAttachment(listOf(file)) {
@ -501,7 +499,7 @@ class RustTimeline(
formattedCaption = null,
useSendQueue = useSendQueue,
mentions = null,
replyParams = replyParameters?.map(),
inReplyTo = inReplyToEventId?.value,
),
audioInfo = audioInfo.map(),
waveform = waveform.toMSC3246range(),

View file

@ -7,7 +7,6 @@
package io.element.android.libraries.matrix.impl.fixtures.factories
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiRoomPowerLevels
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_ROOM_NAME
@ -52,7 +51,7 @@ fun aRustRoomInfo(
numUnreadNotifications: ULong = 0uL,
numUnreadMentions: ULong = 0uL,
pinnedEventIds: List<String> = listOf(),
roomCreator: UserId? = null,
roomCreators: List<String>? = emptyList(),
joinRule: JoinRule? = null,
historyVisibility: RoomHistoryVisibility = RoomHistoryVisibility.Joined,
successorRoom: SuccessorRoom? = null,
@ -86,7 +85,7 @@ fun aRustRoomInfo(
numUnreadNotifications = numUnreadNotifications,
numUnreadMentions = numUnreadMentions,
pinnedEventIds = pinnedEventIds,
creator = roomCreator?.value,
creators = roomCreators,
joinRule = joinRule,
historyVisibility = historyVisibility,
successorRoom = successorRoom,

View file

@ -9,6 +9,7 @@ package io.element.android.libraries.matrix.impl.fixtures.factories
import io.element.android.libraries.matrix.api.core.UserId
import org.matrix.rustcomponents.sdk.MembershipState
import org.matrix.rustcomponents.sdk.PowerLevel
import org.matrix.rustcomponents.sdk.RoomMember
import uniffi.matrix_sdk.RoomMemberRole
@ -18,7 +19,7 @@ fun aRustRoomMember(
avatarUrl: String? = null,
membership: MembershipState = MembershipState.Join,
isNameAmbiguous: Boolean = false,
powerLevel: Long = 0L,
powerLevel: PowerLevel = PowerLevel.Value(0L),
isIgnored: Boolean = false,
role: RoomMemberRole = RoomMemberRole.USER,
membershipChangeReason: String? = null,

View file

@ -31,6 +31,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID_3
import io.element.android.libraries.matrix.test.A_USER_ID_6
import io.element.android.libraries.matrix.test.room.aRoomMember
import io.element.android.libraries.matrix.test.room.defaultRoomPowerLevelValues
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toPersistentList
@ -78,7 +79,7 @@ class RoomInfoMapperTest {
numUnreadNotifications = 13uL,
numUnreadMentions = 14uL,
pinnedEventIds = listOf(AN_EVENT_ID.value),
roomCreator = A_USER_ID,
roomCreators = listOf(A_USER_ID.value),
historyVisibility = RustRoomHistoryVisibility.Joined,
)
)
@ -119,7 +120,7 @@ class RoomInfoMapperTest {
)
).toImmutableList(),
pinnedEventIds = listOf(AN_EVENT_ID).toPersistentList(),
creator = A_USER_ID,
creators = persistentListOf(A_USER_ID),
isMarkedUnread = false,
numUnreadMessages = 12L,
numUnreadNotifications = 13L,
@ -166,7 +167,7 @@ class RoomInfoMapperTest {
numUnreadNotifications = 13uL,
numUnreadMentions = 14uL,
pinnedEventIds = emptyList(),
roomCreator = null,
roomCreators = null,
)
)
).isEqualTo(
@ -201,7 +202,7 @@ class RoomInfoMapperTest {
activeRoomCallParticipants = emptyList<UserId>().toImmutableList(),
heroes = emptyList<MatrixUser>().toImmutableList(),
pinnedEventIds = emptyList<EventId>().toPersistentList(),
creator = null,
creators = persistentListOf(),
isMarkedUnread = true,
numUnreadMessages = 12L,
numUnreadNotifications = 13L,