Update SDK version to 25.03.13 and fix breaking changes (#4406)

Breaking changes addressed:
* Make `MatrixClient.getNotificationSettings()` async, cache its result.
* Use `RoomInfo` for accessing the updated room's info.
* Refactor `MatrixRoom` so it always receives an initial `MatrixRoomInfo` value: this value will be used to make `MatrixRoom.roomInfoFlow` a `StateFlow` so we can assume the initial updated Room data will be present.
* Fetch encryption state when loading a room if it's unknown
This commit is contained in:
Jorge Martin Espinosa 2025-03-19 12:52:57 +01:00 committed by GitHub
parent 0c07a8165f
commit fccd881b1f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
76 changed files with 647 additions and 431 deletions

View file

@ -151,8 +151,7 @@ class RustMatrixClient(
private val notificationProcessSetup = NotificationProcessSetup.SingleProcess(innerSyncService)
private val innerNotificationClient = runBlocking { innerClient.notificationClient(notificationProcessSetup) }
private val notificationService = RustNotificationService(innerNotificationClient, dispatchers, clock)
private val notificationSettingsService = RustNotificationSettingsService(innerClient, dispatchers)
.apply { start() }
private val notificationSettingsService = RustNotificationSettingsService(innerClient, sessionCoroutineScope, dispatchers)
private val encryptionService = RustEncryptionService(
client = innerClient,
syncService = rustSyncService,
@ -216,7 +215,7 @@ class RustMatrixClient(
userId = sessionId,
// TODO cache for displayName?
displayName = null,
avatarUrl = innerClient.cachedAvatarUrl(),
avatarUrl = null,
)
)
@ -237,6 +236,9 @@ class RustMatrixClient(
sessionDelegate.bindClient(this)
sessionCoroutineScope.launch {
// Start notification settings
notificationSettingsService.start()
// Force a refresh of the profile
getUserProfile()
}
@ -479,10 +481,10 @@ class RustMatrixClient(
appCoroutineScope.launch {
roomFactory.destroy()
rustSyncService.destroy()
notificationSettingsService.destroy()
}
sessionCoroutineScope.cancel()
clientDelegateTaskHandle?.cancelAndDestroy()
notificationSettingsService.destroy()
verificationService.destroy()
sessionDelegate.clearCurrentClient()

View file

@ -9,6 +9,8 @@ package io.element.android.libraries.matrix.impl.analytics
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.isDm
import kotlinx.coroutines.flow.first
private fun Long.toAnalyticsRoomSize(): JoinedRoom.RoomSize {
return when (this) {
@ -22,11 +24,12 @@ private fun Long.toAnalyticsRoomSize(): JoinedRoom.RoomSize {
}
}
fun MatrixRoom.toAnalyticsJoinedRoom(trigger: JoinedRoom.Trigger?): JoinedRoom {
suspend fun MatrixRoom.toAnalyticsJoinedRoom(trigger: JoinedRoom.Trigger?): JoinedRoom {
val roomInfo = roomInfoFlow.first()
return JoinedRoom(
isDM = isDirect,
isSpace = isSpace,
roomSize = joinedMemberCount.toAnalyticsRoomSize(),
isDM = roomInfo.isDm,
isSpace = roomInfo.isSpace,
roomSize = roomInfo.joinedMembersCount.toAnalyticsRoomSize(),
trigger = trigger
)
}

View file

@ -12,10 +12,7 @@ import org.matrix.rustcomponents.sdk.OidcPrompt as RustOidcPrompt
internal fun OidcPrompt.toRustPrompt(): RustOidcPrompt {
return when (this) {
OidcPrompt.None -> RustOidcPrompt.None
OidcPrompt.Login -> RustOidcPrompt.Login
OidcPrompt.Consent -> RustOidcPrompt.Consent
OidcPrompt.SelectAccount -> RustOidcPrompt.SelectAccount
OidcPrompt.Login -> RustOidcPrompt.Unknown("consent")
OidcPrompt.Create -> RustOidcPrompt.Create
is OidcPrompt.Unknown -> RustOidcPrompt.Unknown(value)
}

View file

@ -8,10 +8,12 @@
package io.element.android.libraries.matrix.impl.notificationsettings
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.coroutine.suspendLazy
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.RoomNotificationSettings
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
@ -24,9 +26,10 @@ import timber.log.Timber
class RustNotificationSettingsService(
client: Client,
sessionCoroutineScope: CoroutineScope,
private val dispatchers: CoroutineDispatchers,
) : NotificationSettingsService {
private val notificationSettings = client.getNotificationSettings()
private val notificationSettings by suspendLazy(sessionCoroutineScope.coroutineContext + dispatchers.io) { client.getNotificationSettings() }
private val _notificationSettingsChangeFlow = MutableSharedFlow<Unit>(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
override val notificationSettingsChangeFlow: SharedFlow<Unit> = _notificationSettingsChangeFlow.asSharedFlow()
@ -36,22 +39,22 @@ class RustNotificationSettingsService(
}
}
fun start() {
notificationSettings.setDelegate(notificationSettingsDelegate)
suspend fun start() {
notificationSettings.await().setDelegate(notificationSettingsDelegate)
}
fun destroy() {
notificationSettings.setDelegate(null)
suspend fun destroy() {
notificationSettings.await().setDelegate(null)
}
override suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationSettings> =
runCatching {
notificationSettings.getRoomNotificationSettings(roomId.value, isEncrypted, isOneToOne).let(RoomNotificationSettingsMapper::map)
notificationSettings.await().getRoomNotificationSettings(roomId.value, isEncrypted, isOneToOne).let(RoomNotificationSettingsMapper::map)
}
override suspend fun getDefaultRoomNotificationMode(isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationMode> =
runCatching {
notificationSettings.getDefaultRoomNotificationMode(isEncrypted, isOneToOne).let(RoomNotificationSettingsMapper::mapMode)
notificationSettings.await().getDefaultRoomNotificationMode(isEncrypted, isOneToOne).let(RoomNotificationSettingsMapper::mapMode)
}
override suspend fun setDefaultRoomNotificationMode(
@ -61,7 +64,7 @@ class RustNotificationSettingsService(
): Result<Unit> = withContext(dispatchers.io) {
runCatching {
try {
notificationSettings.setDefaultRoomNotificationMode(isEncrypted, isOneToOne, mode.let(RoomNotificationSettingsMapper::mapMode))
notificationSettings.await().setDefaultRoomNotificationMode(isEncrypted, isOneToOne, 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
@ -72,13 +75,13 @@ class RustNotificationSettingsService(
override suspend fun setRoomNotificationMode(roomId: RoomId, mode: RoomNotificationMode): Result<Unit> = withContext(dispatchers.io) {
runCatching {
notificationSettings.setRoomNotificationMode(roomId.value, mode.let(RoomNotificationSettingsMapper::mapMode))
notificationSettings.await().setRoomNotificationMode(roomId.value, mode.let(RoomNotificationSettingsMapper::mapMode))
}
}
override suspend fun restoreDefaultRoomNotificationMode(roomId: RoomId): Result<Unit> = withContext(dispatchers.io) {
runCatching {
notificationSettings.restoreDefaultRoomNotificationMode(roomId.value)
notificationSettings.await().restoreDefaultRoomNotificationMode(roomId.value)
}
}
@ -86,53 +89,53 @@ class RustNotificationSettingsService(
override suspend fun unmuteRoom(roomId: RoomId, isEncrypted: Boolean, isOneToOne: Boolean) = withContext(dispatchers.io) {
runCatching {
notificationSettings.unmuteRoom(roomId.value, isEncrypted, isOneToOne)
notificationSettings.await().unmuteRoom(roomId.value, isEncrypted, isOneToOne)
}
}
override suspend fun isRoomMentionEnabled(): Result<Boolean> = withContext(dispatchers.io) {
runCatching {
notificationSettings.isRoomMentionEnabled()
notificationSettings.await().isRoomMentionEnabled()
}
}
override suspend fun setRoomMentionEnabled(enabled: Boolean): Result<Unit> = withContext(dispatchers.io) {
runCatching {
notificationSettings.setRoomMentionEnabled(enabled)
notificationSettings.await().setRoomMentionEnabled(enabled)
}
}
override suspend fun isCallEnabled(): Result<Boolean> = withContext(dispatchers.io) {
runCatching {
notificationSettings.isCallEnabled()
notificationSettings.await().isCallEnabled()
}
}
override suspend fun setCallEnabled(enabled: Boolean): Result<Unit> = withContext(dispatchers.io) {
runCatching {
notificationSettings.setCallEnabled(enabled)
notificationSettings.await().setCallEnabled(enabled)
}
}
override suspend fun isInviteForMeEnabled(): Result<Boolean> = withContext(dispatchers.io) {
runCatching {
notificationSettings.isInviteForMeEnabled()
notificationSettings.await().isInviteForMeEnabled()
}
}
override suspend fun setInviteForMeEnabled(enabled: Boolean): Result<Unit> = withContext(dispatchers.io) {
runCatching {
notificationSettings.setInviteForMeEnabled(enabled)
notificationSettings.await().setInviteForMeEnabled(enabled)
}
}
override suspend fun getRoomsWithUserDefinedRules(): Result<List<String>> =
runCatching {
notificationSettings.getRoomsWithUserDefinedRules(enabled = true)
notificationSettings.await().getRoomsWithUserDefinedRules(enabled = true)
}
override suspend fun canHomeServerPushEncryptedEventsToDevice(): Result<Boolean> =
runCatching {
notificationSettings.canPushEncryptedEventToDevice()
notificationSettings.await().canPushEncryptedEventToDevice()
}
}

View file

@ -0,0 +1,26 @@
/*
* 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.platform
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.api.platform.InitPlatformService
import io.element.android.libraries.matrix.api.tracing.TracingConfiguration
import io.element.android.libraries.matrix.impl.tracing.map
import org.matrix.rustcomponents.sdk.initPlatform
import javax.inject.Inject
@ContributesBinding(AppScope::class)
class RustInitPlatformService @Inject constructor() : InitPlatformService {
override fun init(tracingConfiguration: TracingConfiguration) {
initPlatform(
config = tracingConfiguration.map(),
useLightweightTokioRuntime = false
)
}
}

View file

@ -23,6 +23,7 @@ import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toPersistentMap
import org.matrix.rustcomponents.sdk.Membership
import org.matrix.rustcomponents.sdk.RoomHero
import uniffi.matrix_sdk_base.EncryptionState
import org.matrix.rustcomponents.sdk.Membership as RustMembership
import org.matrix.rustcomponents.sdk.RoomInfo as RustRoomInfo
import org.matrix.rustcomponents.sdk.RoomNotificationMode as RustRoomNotificationMode
@ -36,7 +37,13 @@ class MatrixRoomInfoMapper {
rawName = it.rawName,
topic = it.topic,
avatarUrl = it.avatarUrl,
isPublic = it.isPublic,
isDirect = it.isDirect,
isEncrypted = when (it.encryptionState) {
EncryptionState.ENCRYPTED -> true
EncryptionState.NOT_ENCRYPTED -> false
EncryptionState.UNKNOWN -> null
},
joinRule = it.joinRule?.map(),
isSpace = it.isSpace,
isTombstoned = it.isTombstoned,
@ -63,6 +70,44 @@ class MatrixRoomInfoMapper {
historyVisibility = it.historyVisibility.map(),
)
}
// fun map(rustRoom: Room): MatrixRoomInfo = with(rustRoom) {
// return MatrixRoomInfo(
// id = RoomId(id()),
// name = rawName(),
// rawName = displayName(),
// topic = topic(),
// avatarUrl = avatarUrl(),
// isPublic = isPublic(),
// isDirect = null,
// isEncrypted = encryptionState() == EncryptionState.ENCRYPTED,
// joinRule = null,
// isSpace = isSpace(),
// isTombstoned = isTombstoned(),
// isFavorite = null,
// canonicalAlias = canonicalAlias()?.let(::RoomAlias),
// alternativeAliases = alternativeAliases().map(::RoomAlias).toImmutableList(),
// currentUserMembership = membership().map(),
// inviter = null,
// activeMembersCount = activeMembersCount().toLong(),
// invitedMembersCount = invitedMembersCount().toLong(),
// joinedMembersCount = joinedMembersCount().toLong(),
// userPowerLevels = persistentMapOf(),
// highlightCount = 0,
// notificationCount = 0,
// userDefinedNotificationMode = null,
// hasRoomCall = hasActiveRoomCall(),
// activeRoomCallParticipants = activeRoomCallParticipants().map(::UserId).toImmutableList(),
// isMarkedUnread = false,
// numUnreadMessages = 0,
// numUnreadNotifications = 0,
// numUnreadMentions = 0,
// heroes = heroes().map(RoomHero::map).toImmutableList(),
// pinnedEventIds = persistentListOf(),
// creator = null,
// historyVisibility = null,
// )
// }
}
fun RustMembership.map(): CurrentUserMembership = when (this) {

View file

@ -73,6 +73,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
@ -82,13 +83,13 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.DateDividerMode
import org.matrix.rustcomponents.sdk.IdentityStatusChangeListener
import org.matrix.rustcomponents.sdk.KnockRequestsListener
import org.matrix.rustcomponents.sdk.RoomInfo
import org.matrix.rustcomponents.sdk.RoomInfoListener
import org.matrix.rustcomponents.sdk.RoomListItem
import org.matrix.rustcomponents.sdk.RoomMessageEventMessageType
import org.matrix.rustcomponents.sdk.TimelineConfiguration
import org.matrix.rustcomponents.sdk.TimelineFilter
@ -101,6 +102,7 @@ import org.matrix.rustcomponents.sdk.getElementCallRequiredPermissions
import org.matrix.rustcomponents.sdk.use
import timber.log.Timber
import uniffi.matrix_sdk.RoomPowerLevelChanges
import uniffi.matrix_sdk_base.EncryptionState
import java.io.File
import kotlin.coroutines.cancellation.CancellationException
import org.matrix.rustcomponents.sdk.IdentityStatusChange as RustIdentityStateChange
@ -112,7 +114,6 @@ import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline
class RustMatrixRoom(
override val sessionId: SessionId,
private val deviceId: DeviceId,
private val roomListItem: RoomListItem,
private val innerRoom: InnerRoom,
innerTimeline: InnerTimeline,
private val notificationSettingsService: NotificationSettingsService,
@ -124,22 +125,17 @@ class RustMatrixRoom(
private val matrixRoomInfoMapper: MatrixRoomInfoMapper,
private val featureFlagService: FeatureFlagService,
private val roomMembershipObserver: RoomMembershipObserver,
initialRoomInfo: MatrixRoomInfo,
) : MatrixRoom {
override val roomId = RoomId(innerRoom.id())
override val roomInfoFlow: Flow<MatrixRoomInfo> = mxCallbackFlow {
runCatching { innerRoom.roomInfo() }
.getOrNull()
?.let(matrixRoomInfoMapper::map)
?.let { initial ->
channel.trySend(initial)
}
override val roomInfoFlow: StateFlow<MatrixRoomInfo> = mxCallbackFlow {
innerRoom.subscribeToRoomInfoUpdates(object : RoomInfoListener {
override fun call(roomInfo: RoomInfo) {
channel.trySend(matrixRoomInfoMapper.map(roomInfo))
}
})
}
}.stateIn(sessionCoroutineScope, started = SharingStarted.Lazily, initialValue = initialRoomInfo)
override val roomTypingMembersFlow: Flow<List<UserId>> = mxCallbackFlow {
val initial = emptyList<UserId>()
@ -307,39 +303,6 @@ class RustMatrixRoom(
liveTimeline.close()
}
override val displayName: String
get() = runCatching { innerRoom.displayName() ?: "" }.getOrDefault("")
override val topic: String?
get() = runCatching { innerRoom.topic() }.getOrDefault(null)
override val avatarUrl: String?
get() = runCatching { roomListItem.avatarUrl() ?: innerRoom.avatarUrl() }.getOrDefault(null)
override val isEncrypted: Boolean
get() = runCatching { innerRoom.isEncrypted() }.getOrDefault(false)
override val canonicalAlias: RoomAlias?
get() = runCatching { innerRoom.canonicalAlias()?.let(::RoomAlias) }.getOrDefault(null)
override val alternativeAliases: List<RoomAlias>
get() = runCatching { innerRoom.alternativeAliases().map { RoomAlias(it) } }.getOrDefault(emptyList())
override val isPublic: Boolean
get() = runCatching { innerRoom.isPublic() }.getOrDefault(false)
override val isSpace: Boolean
get() = runCatching { innerRoom.isSpace() }.getOrDefault(false)
override val isDirect: Boolean
get() = runCatching { innerRoom.isDirect() }.getOrDefault(false)
override val joinedMemberCount: Long
get() = runCatching { innerRoom.joinedMembersCount().toLong() }.getOrDefault(0)
override val activeMemberCount: Long
get() = runCatching { innerRoom.activeMembersCount().toLong() }.getOrDefault(0)
override suspend fun updateMembers() {
val useCache = membersStateFlow.value is MatrixRoomMembersState.Unknown
val source = if (useCache) {
@ -377,6 +340,7 @@ class RustMatrixRoom(
val currentRoomNotificationSettings = currentState.roomNotificationSettings()
_roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Pending(prevRoomNotificationSettings = currentRoomNotificationSettings)
runCatching {
val isEncrypted = roomInfoFlow.value.isEncrypted ?: getUpdatedIsEncrypted().getOrThrow()
notificationSettingsService.getRoomNotificationSettings(roomId, isEncrypted, isOneToOne).getOrThrow()
}.map {
_roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Ready(it)
@ -866,6 +830,12 @@ class RustMatrixRoom(
}
}
override suspend fun getUpdatedIsEncrypted(): Result<Boolean> = withContext(roomDispatcher) {
runCatching {
innerRoom.latestEncryptionState() == EncryptionState.ENCRYPTED
}
}
private fun createTimeline(
timeline: InnerTimeline,
mode: Timeline.Mode,

View file

@ -104,10 +104,10 @@ class RustRoomFactory(
return@withContext null
}
val liveTimeline = roomReferences.fullRoom.timeline()
val initialRoomInfo = roomReferences.fullRoom.roomInfo()
RustMatrixRoom(
sessionId = sessionId,
deviceId = deviceId,
roomListItem = roomReferences.roomListItem,
innerRoom = roomReferences.fullRoom,
innerTimeline = liveTimeline,
sessionCoroutineScope = sessionCoroutineScope,
@ -119,6 +119,7 @@ class RustRoomFactory(
matrixRoomInfoMapper = matrixRoomInfoMapper,
featureFlagService = featureFlagService,
roomMembershipObserver = roomMembershipObserver,
initialRoomInfo = matrixRoomInfoMapper.map(initialRoomInfo),
)
}
}

View file

@ -56,6 +56,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.getAndUpdate
import kotlinx.coroutines.flow.launchIn
@ -214,19 +215,19 @@ class RustTimeline(
_timelineItems,
backPaginationStatus,
forwardPaginationStatus,
matrixRoom.roomInfoFlow.map { it.creator },
matrixRoom.roomInfoFlow.map { it.creator to it.isDm }.distinctUntilChanged(),
isTimelineInitialized,
) { timelineItems,
backwardPaginationStatus,
forwardPaginationStatus,
roomCreator,
(roomCreator, isDm),
isTimelineInitialized ->
withContext(dispatcher) {
timelineItems
.let { items ->
roomBeginningPostProcessor.process(
items = items,
isDm = matrixRoom.isDm,
isDm = isDm,
roomCreator = roomCreator,
hasMoreToLoadBackwards = backwardPaginationStatus.hasMoreToLoad,
)

View file

@ -152,6 +152,7 @@ private fun RustEventItemOrigin.map(): TimelineItemEventOrigin {
RustEventItemOrigin.LOCAL -> TimelineItemEventOrigin.LOCAL
RustEventItemOrigin.SYNC -> TimelineItemEventOrigin.SYNC
RustEventItemOrigin.PAGINATION -> TimelineItemEventOrigin.PAGINATION
RustEventItemOrigin.CACHE -> TimelineItemEventOrigin.CACHE
}
}

View file

@ -20,17 +20,6 @@ import javax.inject.Inject
@ContributesBinding(AppScope::class)
class RustTracingService @Inject constructor(private val buildMeta: BuildMeta) : TracingService {
override fun setupTracing(tracingConfiguration: TracingConfiguration) {
val rustTracingConfiguration = org.matrix.rustcomponents.sdk.TracingConfiguration(
writeToStdoutOrSystem = tracingConfiguration.writesToLogcat,
logLevel = tracingConfiguration.logLevel.toRustLogLevel(),
extraTargets = tracingConfiguration.extraTargets,
writeToFiles = tracingConfiguration.writesToFilesConfiguration.toTracingFileConfiguration(),
)
org.matrix.rustcomponents.sdk.setupTracing(rustTracingConfiguration)
Timber.d("setupTracing: $rustTracingConfiguration")
}
override fun createTimberTree(target: String): Timber.Tree {
return RustTracingTree(target = target, retrieveFromStackTrace = buildMeta.isDebuggable)
}
@ -57,3 +46,10 @@ private fun WriteToFilesConfiguration.toTracingFileConfiguration(): TracingFileC
)
}
}
fun TracingConfiguration.map(): org.matrix.rustcomponents.sdk.TracingConfiguration = org.matrix.rustcomponents.sdk.TracingConfiguration(
writeToStdoutOrSystem = writesToLogcat,
logLevel = logLevel.toRustLogLevel(),
extraTargets = extraTargets,
writeToFiles = writesToFilesConfiguration.toTracingFileConfiguration(),
)

View file

@ -42,7 +42,7 @@ fun TestScope.createRustMatrixClientFactory(
) = RustMatrixClientFactory(
baseDirectory = baseDirectory,
cacheDirectory = cacheDirectory,
appCoroutineScope = this,
appCoroutineScope = backgroundScope,
coroutineDispatchers = testCoroutineDispatchers(),
sessionStore = sessionStore,
userAgentProvider = SimpleUserAgentProvider(),

View file

@ -38,7 +38,7 @@ class RustMatrixClientTest {
innerClient = FakeRustClient(),
baseDirectory = File(""),
sessionStore = sessionStore,
appCoroutineScope = this,
appCoroutineScope = backgroundScope,
sessionDelegate = aRustClientSessionDelegate(
sessionStore = sessionStore,
),

View file

@ -9,13 +9,14 @@ package io.element.android.libraries.matrix.impl.analytics
import com.google.common.truth.Truth.assertThat
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.test.room.aRoomInfo
import kotlinx.coroutines.test.runTest
import org.junit.Test
class JoinedRoomExtKtTest {
@Test
fun `test room size mapping`() {
fun `test room size mapping`() = runTest {
mapOf(
listOf(0L, 1L) to JoinedRoom.RoomSize.One,
listOf(2L, 2L) to JoinedRoom.RoomSize.Two,
@ -39,7 +40,7 @@ class JoinedRoomExtKtTest {
}
@Test
fun `test isDirect parameter mapping`() {
fun `test isDirect parameter mapping`() = runTest {
assertThat(aMatrixRoom(isDirect = true).toAnalyticsJoinedRoom(null))
.isEqualTo(
JoinedRoom(
@ -52,7 +53,7 @@ class JoinedRoomExtKtTest {
}
@Test
fun `test isSpace parameter mapping`() {
fun `test isSpace parameter mapping`() = runTest {
assertThat(aMatrixRoom(isSpace = true).toAnalyticsJoinedRoom(null))
.isEqualTo(
JoinedRoom(
@ -65,8 +66,8 @@ class JoinedRoomExtKtTest {
}
@Test
fun `test trigger parameter mapping`() {
assertThat(aMatrixRoom().toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite))
fun `test trigger parameter mapping`() = runTest {
assertThat(aMatrixRoom(isDirect = false, isSpace = false, joinedMemberCount = 1).toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite))
.isEqualTo(
JoinedRoom(
isDM = false,
@ -81,11 +82,9 @@ class JoinedRoomExtKtTest {
isDirect: Boolean = false,
isSpace: Boolean = false,
joinedMemberCount: Long = 0
): MatrixRoom {
return FakeMatrixRoom(
isDirect = isDirect,
isSpace = isSpace,
joinedMemberCount = joinedMemberCount
)
): FakeMatrixRoom {
return FakeMatrixRoom().apply {
givenRoomInfo(aRoomInfo(isDirect = isDirect, isSpace = isSpace, joinedMembersCount = joinedMemberCount))
}
}
}

View file

@ -17,6 +17,7 @@ import org.matrix.rustcomponents.sdk.RoomHistoryVisibility
import org.matrix.rustcomponents.sdk.RoomInfo
import org.matrix.rustcomponents.sdk.RoomMember
import org.matrix.rustcomponents.sdk.RoomNotificationMode
import uniffi.matrix_sdk_base.EncryptionState
fun aRustRoomInfo(
id: String = A_ROOM_ID.value,
@ -24,6 +25,7 @@ fun aRustRoomInfo(
rawName: String? = A_ROOM_NAME,
topic: String? = null,
avatarUrl: String? = null,
encryptionState: EncryptionState = EncryptionState.UNKNOWN,
isDirect: Boolean = false,
isPublic: Boolean = false,
isSpace: Boolean = false,
@ -57,6 +59,7 @@ fun aRustRoomInfo(
rawName = rawName,
topic = topic,
avatarUrl = avatarUrl,
encryptionState = encryptionState,
isDirect = isDirect,
isPublic = isPublic,
isSpace = isSpace,

View file

@ -35,11 +35,11 @@ class FakeRustClient(
override fun userId(): String = userId
override fun deviceId(): String = deviceId
override suspend fun notificationClient(processSetup: NotificationProcessSetup) = notificationClient
override fun getNotificationSettings(): NotificationSettings = notificationSettings
override suspend fun getNotificationSettings(): NotificationSettings = notificationSettings
override fun encryption(): Encryption = encryption
override fun session(): Session = session
override fun setDelegate(delegate: ClientDelegate?): TaskHandle = FakeRustTaskHandle()
override fun cachedAvatarUrl(): String? = null
override suspend fun cachedAvatarUrl(): String? = null
override suspend fun restoreSession(session: Session) = Unit
override fun syncService(): SyncServiceBuilder = FakeRustSyncServiceBuilder()
override fun roomDirectorySearch(): RoomDirectorySearch = FakeRustRoomDirectorySearch()

View file

@ -37,6 +37,7 @@ class RustNotificationSettingsServiceTest {
client = FakeRustClient(
notificationSettings = notificationSettings,
),
sessionCoroutineScope = this,
dispatchers = testCoroutineDispatchers(),
)
}

View file

@ -33,6 +33,7 @@ import kotlinx.collections.immutable.toImmutableMap
import kotlinx.collections.immutable.toPersistentList
import org.junit.Test
import org.matrix.rustcomponents.sdk.Membership
import uniffi.matrix_sdk_base.EncryptionState
import org.matrix.rustcomponents.sdk.JoinRule as RustJoinRule
import org.matrix.rustcomponents.sdk.RoomHistoryVisibility as RustRoomHistoryVisibility
import org.matrix.rustcomponents.sdk.RoomNotificationMode as RustRoomNotificationMode
@ -48,6 +49,7 @@ class MatrixRoomInfoMapperTest {
rawName = "rawName",
topic = "topic",
avatarUrl = AN_AVATAR_URL,
encryptionState = EncryptionState.ENCRYPTED,
isDirect = true,
isPublic = false,
isSpace = false,
@ -84,7 +86,9 @@ class MatrixRoomInfoMapperTest {
rawName = "rawName",
topic = "topic",
avatarUrl = AN_AVATAR_URL,
isPublic = false,
isDirect = true,
isEncrypted = true,
isSpace = false,
isTombstoned = false,
isFavorite = false,
@ -130,6 +134,7 @@ class MatrixRoomInfoMapperTest {
rawName = null,
topic = null,
avatarUrl = null,
encryptionState = EncryptionState.UNKNOWN,
isDirect = false,
isPublic = true,
joinRule = null,
@ -165,6 +170,8 @@ class MatrixRoomInfoMapperTest {
rawName = null,
topic = null,
avatarUrl = null,
isEncrypted = null,
isPublic = true,
isDirect = false,
joinRule = null,
isSpace = false,

View file

@ -19,6 +19,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SERVER_LIST
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.aRoomSummary
import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.lambda.lambdaRecorder
@ -32,7 +33,9 @@ class DefaultJoinRoomTest {
val roomSummary = aRoomSummary()
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) }
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List<String> -> Result.success(roomSummary) }
val roomResult = FakeMatrixRoom()
val roomResult = FakeMatrixRoom().apply {
givenRoomInfo(aRoomInfo())
}
val aTrigger = JoinedRoom.Trigger.MobilePermalink
val client: MatrixClient = FakeMatrixClient().also {
it.joinRoomLambda = joinRoomLambda
@ -67,7 +70,9 @@ class DefaultJoinRoomTest {
val roomSummary = aRoomSummary()
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) }
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List<String> -> Result.success(roomSummary) }
val roomResult = FakeMatrixRoom()
val roomResult = FakeMatrixRoom().apply {
givenRoomInfo(aRoomInfo())
}
val aTrigger = JoinedRoom.Trigger.MobilePermalink
val client: MatrixClient = FakeMatrixClient().also {
it.joinRoomLambda = joinRoomLambda
@ -103,7 +108,9 @@ class DefaultJoinRoomTest {
val roomSummary = aRoomSummary()
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) }
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List<String> -> Result.success(roomSummary) }
val roomResult = FakeMatrixRoom()
val roomResult = FakeMatrixRoom().apply {
givenRoomInfo(aRoomInfo())
}
val aTrigger = JoinedRoom.Trigger.MobilePermalink
val client: MatrixClient = FakeMatrixClient().also {
it.joinRoomLambda = joinRoomLambda