Adapt to new DM definition changes in the SDK (#6748)

* Set `DmRoomDefinition.TwoPeople` in `ClientBuilder`. This applies the 'direct and with at most 2 non-service members' rule to what the SDK should consider a DM.

* Map `RoomInfo.isDm` from the SDK

* Map `NotificationData.isDm` from `NotificationInfo.roomInfo.isDm`

* Remove `RoomIsDmCheck` file as its extension functions are now redundant. Move `Room.isDm` helper function to `BaseRoom`.

* Map `isDm` in `SpaceRoom` from the SDK too

* Replace `isDirect` with `isDm` where possible

* Map `RoomMember.isServiceMember` from the SDK and use it to tell apart normal members of a room from service members (i.e. `RoomMembersState.getDirectRoomMember`)
This commit is contained in:
Jorge Martin Espinosa 2026-05-11 17:22:16 +02:00 committed by GitHub
parent a38b7a61ad
commit 4975f61eb8
66 changed files with 115 additions and 232 deletions

View file

@ -41,6 +41,7 @@ import org.matrix.rustcomponents.sdk.SlidingSyncVersion
import org.matrix.rustcomponents.sdk.SlidingSyncVersionBuilder
import org.matrix.rustcomponents.sdk.use
import timber.log.Timber
import uniffi.matrix_sdk_base.DmRoomDefinition
import uniffi.matrix_sdk_base.MediaRetentionPolicy
import uniffi.matrix_sdk_crypto.CollectStrategy
import uniffi.matrix_sdk_crypto.DecryptionSettings
@ -169,6 +170,7 @@ class RustMatrixClientFactory(
)
.enableShareHistoryOnInvite(true)
.threadsEnabled(featureFlagService.isFeatureEnabled(FeatureFlags.Threads), threadSubscriptions = false)
.dmRoomDefinition(DmRoomDefinition.TWO_MEMBERS)
.requestConfig(
RequestConfig(
timeout = 30_000uL,

View file

@ -11,7 +11,6 @@ package io.element.android.libraries.matrix.impl.analytics
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.libraries.matrix.api.room.BaseRoom
import io.element.android.libraries.matrix.api.room.RoomInfo
import io.element.android.libraries.matrix.api.room.isDm
import kotlinx.coroutines.flow.first
private fun Long.toAnalyticsRoomSize(): JoinedRoom.RoomSize {

View file

@ -17,7 +17,6 @@ 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.notification.NotificationContent
import io.element.android.libraries.matrix.api.notification.NotificationData
import io.element.android.libraries.matrix.api.room.isDm
import io.element.android.libraries.matrix.impl.room.join.map
import io.element.android.services.toolbox.api.systemclock.SystemClock
import org.matrix.rustcomponents.sdk.NotificationEvent
@ -37,10 +36,6 @@ class NotificationMapper(
): Result<NotificationData> {
return runCatchingExceptions {
notificationItem.use { item ->
val isDm = isDm(
isDirect = item.roomInfo.isDirect,
activeMembersCount = item.roomInfo.joinedMembersCount.toInt(),
)
val timestamp = item.timestamp() ?: clock.epochMillis()
NotificationData(
sessionId = sessionId,
@ -50,10 +45,10 @@ class NotificationMapper(
senderAvatarUrl = item.senderInfo.avatarUrl,
senderDisplayName = item.senderInfo.displayName,
senderIsNameAmbiguous = item.senderInfo.isNameAmbiguous,
roomAvatarUrl = item.roomInfo.avatarUrl ?: item.senderInfo.avatarUrl.takeIf { isDm },
roomAvatarUrl = item.roomInfo.avatarUrl ?: item.senderInfo.avatarUrl.takeIf { item.roomInfo.isDm },
roomDisplayName = item.roomInfo.displayName,
isDirect = item.roomInfo.isDirect,
isDm = isDm,
isDm = item.roomInfo.isDm,
isSpace = item.roomInfo.isSpace,
isEncrypted = item.roomInfo.isEncrypted.orFalse(),
isNoisy = item.isNoisy.orFalse(),

View file

@ -62,11 +62,11 @@ class RustNotificationSettingsService(
override suspend fun setDefaultRoomNotificationMode(
isEncrypted: Boolean,
mode: RoomNotificationMode,
isOneToOne: Boolean
isDM: Boolean
): Result<Unit> = withContext(dispatchers.io) {
runCatchingExceptions {
try {
notificationSettings.await().setDefaultRoomNotificationMode(isEncrypted, isOneToOne, mode.let(RoomNotificationSettingsMapper::mapMode))
notificationSettings.await().setDefaultRoomNotificationMode(isEncrypted, isDM, mode.let(RoomNotificationSettingsMapper::mapMode))
} catch (exception: NotificationSettingsException.RuleNotFound) {
// `setDefaultRoomNotificationMode` updates multiple rules including unstable rules (e.g. the polls push rules defined in the MSC3930)
// since production home servers may not have these rules yet, we drop the RuleNotFound error

View file

@ -348,7 +348,7 @@ class JoinedRustRoom(
roomNotificationSettingsStateFlow.value = RoomNotificationSettingsState.Pending(prevRoomNotificationSettings = currentRoomNotificationSettings)
runCatchingExceptions {
val isEncrypted = roomInfoFlow.value.isEncrypted ?: getUpdatedIsEncrypted().getOrThrow()
notificationSettingsService.getRoomNotificationSettings(roomId, isEncrypted, isOneToOne).getOrThrow()
notificationSettingsService.getRoomNotificationSettings(roomId = roomId, isEncrypted = isEncrypted, isOneToOne = isDm()).getOrThrow()
}.map {
roomNotificationSettingsStateFlow.value = RoomNotificationSettingsState.Ready(it)
}.onFailure {

View file

@ -18,7 +18,7 @@ import org.matrix.rustcomponents.sdk.RoomInfo
*/
fun RoomInfo.elementHeroes(): List<MatrixUser> {
return heroes
.takeIf { isDirect && activeMembersCount.toLong() == 2L }
.takeIf { isDm }
?.takeIf { it.size == 1 }
?.map { it.map() }
.orEmpty()

View file

@ -43,6 +43,7 @@ class RoomInfoMapper {
avatarUrl = it.avatarUrl,
isPublic = it.isPublic,
isDirect = it.isDirect,
isDm = it.isDm,
isEncrypted = when (it.encryptionState) {
EncryptionState.ENCRYPTED -> true
EncryptionState.NOT_ENCRYPTED -> false

View file

@ -23,7 +23,6 @@ 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.draft.ComposerDraft
import io.element.android.libraries.matrix.api.room.isDm
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
@ -119,7 +118,7 @@ class RustBaseRoom(
innerRoom.membersNoSync().use { members ->
members.nextChunk(members.len())
?.map(RoomMemberMapper::map)
?.firstOrNull { roomMember -> roomMember.userId != sessionId && roomMember.membership.isActive() }
?.firstOrNull { roomMember -> !roomMember.isServiceMember && roomMember.userId != sessionId && roomMember.membership.isActive() }
}
} else {
null

View file

@ -28,7 +28,8 @@ object RoomMemberMapper {
powerLevel = powerLevel,
isIgnored = roomMember.isIgnored,
role = mapRole(roomMember.suggestedRoleForPowerLevel, powerLevel),
membershipChangeReason = roomMember.membershipChangeReason
membershipChangeReason = roomMember.membershipChangeReason,
isServiceMember = roomMember.isServiceMember,
)
}

View file

@ -36,6 +36,7 @@ class SpaceRoomMapper {
worldReadable = spaceRoom.worldReadable.orFalse(),
via = spaceRoom.via.toImmutableList(),
isDirect = spaceRoom.isDirect,
isDm = spaceRoom.isDm,
)
}
}

View file

@ -20,7 +20,6 @@ import io.element.android.libraries.matrix.api.media.VideoInfo
import io.element.android.libraries.matrix.api.poll.PollKind
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.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.MsgType