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:
parent
0c07a8165f
commit
fccd881b1f
76 changed files with 647 additions and 431 deletions
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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.core.coroutine
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
fun <T> suspendLazy(coroutineContext: CoroutineContext = EmptyCoroutineContext, block: suspend () -> T): Lazy<Deferred<T>> {
|
||||
return lazy(LazyThreadSafetyMode.NONE) {
|
||||
val deferred = CompletableDeferred<T>()
|
||||
CoroutineScope(coroutineContext).launch {
|
||||
deferred.complete(block())
|
||||
}
|
||||
deferred
|
||||
}
|
||||
}
|
||||
|
|
@ -18,8 +18,8 @@ fun MatrixRoom.toAnalyticsViewRoom(
|
|||
val activeSpace = selectedSpace?.toActiveSpace() ?: ViewRoom.ActiveSpace.Home
|
||||
|
||||
return ViewRoom(
|
||||
isDM = isDirect,
|
||||
isSpace = isSpace,
|
||||
isDM = info().isDirect,
|
||||
isSpace = info().isSpace,
|
||||
trigger = trigger,
|
||||
activeSpace = activeSpace,
|
||||
viaKeyboard = viaKeyboard
|
||||
|
|
@ -27,5 +27,5 @@ fun MatrixRoom.toAnalyticsViewRoom(
|
|||
}
|
||||
|
||||
private fun MatrixRoom.toActiveSpace(): ViewRoom.ActiveSpace {
|
||||
return if (isPublic) ViewRoom.ActiveSpace.Public else ViewRoom.ActiveSpace.Private
|
||||
return if (info().isPublic) ViewRoom.ActiveSpace.Public else ViewRoom.ActiveSpace.Private
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,34 +8,12 @@
|
|||
package io.element.android.libraries.matrix.api.auth
|
||||
|
||||
sealed interface OidcPrompt {
|
||||
/**
|
||||
* The Authorization Server must not display any authentication or consent
|
||||
* user interface pages.
|
||||
*/
|
||||
data object None : OidcPrompt
|
||||
|
||||
/**
|
||||
* The Authorization Server should prompt the End-User for
|
||||
* reauthentication.
|
||||
*/
|
||||
data object Login : OidcPrompt
|
||||
|
||||
/**
|
||||
* The Authorization Server should prompt the End-User for consent before
|
||||
* returning information to the Client.
|
||||
*/
|
||||
data object Consent : OidcPrompt
|
||||
|
||||
/**
|
||||
* The Authorization Server should prompt the End-User to select a user
|
||||
* account.
|
||||
*
|
||||
* This enables an End-User who has multiple accounts at the Authorization
|
||||
* Server to select amongst the multiple accounts that they might have
|
||||
* current sessions for.
|
||||
*/
|
||||
data object SelectAccount : OidcPrompt
|
||||
|
||||
/**
|
||||
* The Authorization Server should prompt the End-User to create a user
|
||||
* account.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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.api.platform
|
||||
|
||||
import io.element.android.libraries.matrix.api.tracing.TracingConfiguration
|
||||
|
||||
/**
|
||||
* This service is responsible for initializing the platform-related settings of the SDK.
|
||||
*/
|
||||
interface InitPlatformService {
|
||||
/**
|
||||
* Initialize the platform-related settings of the SDK.
|
||||
* @param tracingConfiguration the tracing configuration to use for logging.
|
||||
*/
|
||||
fun init(tracingConfiguration: TracingConfiguration)
|
||||
}
|
||||
|
|
@ -45,21 +45,10 @@ import java.io.File
|
|||
interface MatrixRoom : Closeable {
|
||||
val sessionId: SessionId
|
||||
val roomId: RoomId
|
||||
val displayName: String
|
||||
val canonicalAlias: RoomAlias?
|
||||
val alternativeAliases: List<RoomAlias>
|
||||
val topic: String?
|
||||
val avatarUrl: String?
|
||||
val isEncrypted: Boolean
|
||||
val isSpace: Boolean
|
||||
val isDirect: Boolean
|
||||
val isPublic: Boolean
|
||||
val activeMemberCount: Long
|
||||
val joinedMemberCount: Long
|
||||
|
||||
val roomCoroutineScope: CoroutineScope
|
||||
|
||||
val roomInfoFlow: Flow<MatrixRoomInfo>
|
||||
val roomInfoFlow: StateFlow<MatrixRoomInfo>
|
||||
val roomTypingMembersFlow: Flow<List<UserId>>
|
||||
val identityStateChangesFlow: Flow<List<IdentityStateChange>>
|
||||
|
||||
|
|
@ -72,7 +61,7 @@ interface MatrixRoom : Closeable {
|
|||
* A one-to-one is a room with exactly 2 members.
|
||||
* See [the Matrix spec](https://spec.matrix.org/latest/client-server-api/#default-underride-rules).
|
||||
*/
|
||||
val isOneToOne: Boolean get() = activeMemberCount == 2L
|
||||
val isOneToOne: Boolean get() = info().activeMembersCount == 2L
|
||||
|
||||
/**
|
||||
* The current loaded members as a StateFlow.
|
||||
|
|
@ -83,6 +72,11 @@ interface MatrixRoom : Closeable {
|
|||
|
||||
val roomNotificationSettingsStateFlow: StateFlow<MatrixRoomNotificationSettingsState>
|
||||
|
||||
/**
|
||||
* Get the latest room info we have received from the SDK stream.
|
||||
*/
|
||||
fun info(): MatrixRoomInfo = roomInfoFlow.value
|
||||
|
||||
/**
|
||||
* Try to load the room members and update the membersFlow.
|
||||
*/
|
||||
|
|
@ -453,4 +447,6 @@ interface MatrixRoom : Closeable {
|
|||
* Update the join rule for this room.
|
||||
*/
|
||||
suspend fun updateJoinRule(joinRule: JoinRule): Result<Unit>
|
||||
|
||||
suspend fun getUpdatedIsEncrypted(): Result<Boolean>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ data class MatrixRoomInfo(
|
|||
val rawName: String?,
|
||||
val topic: String?,
|
||||
val avatarUrl: String?,
|
||||
val isPublic: Boolean,
|
||||
val isDirect: Boolean,
|
||||
val isEncrypted: Boolean?,
|
||||
val joinRule: JoinRule?,
|
||||
val isSpace: Boolean,
|
||||
val isTombstoned: Boolean,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
package io.element.android.libraries.matrix.api.room
|
||||
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
/**
|
||||
* Returns whether the room with the provided info is a DM.
|
||||
* A DM is a room with at most 2 active members (one of them may have left).
|
||||
|
|
@ -19,9 +21,9 @@ fun isDm(isDirect: Boolean, activeMembersCount: Int): Boolean {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns whether the [MatrixRoom] is a DM.
|
||||
* Returns whether the [MatrixRoom] is a DM, with an updated state from the latest [MatrixRoomInfo].
|
||||
*/
|
||||
val MatrixRoom.isDm get() = isDm(isDirect, activeMemberCount.toInt())
|
||||
suspend fun MatrixRoom.isDm() = roomInfoFlow.first().isDm
|
||||
|
||||
/**
|
||||
* Returns whether the [MatrixRoomInfo] is from a DM.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ fun MatrixRoom.matches(roomIdOrAlias: RoomIdOrAlias): Boolean {
|
|||
roomIdOrAlias.roomId == roomId
|
||||
}
|
||||
is RoomIdOrAlias.Alias -> {
|
||||
roomIdOrAlias.roomAlias == canonicalAlias || roomIdOrAlias.roomAlias in alternativeAliases
|
||||
roomIdOrAlias.roomAlias == info().canonicalAlias || roomIdOrAlias.roomAlias in info().alternativeAliases
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ suspend fun MatrixClient.getRecentDirectRooms(
|
|||
getRecentlyVisitedRooms().getOrNull()?.let { roomIds ->
|
||||
roomIds
|
||||
.mapNotNull { roomId -> getRoom(roomId) }
|
||||
.filter { it.isDm && it.isJoined() }
|
||||
.filter { it.isDm() && it.isJoined() }
|
||||
.map { room ->
|
||||
val otherUser = room.getMembers().getOrNull()
|
||||
?.firstOrNull { it.userId != sessionId }
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@ package io.element.android.libraries.matrix.api.timeline.item.event
|
|||
enum class TimelineItemEventOrigin {
|
||||
LOCAL,
|
||||
SYNC,
|
||||
PAGINATION
|
||||
PAGINATION,
|
||||
CACHE,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,5 @@ package io.element.android.libraries.matrix.api.tracing
|
|||
import timber.log.Timber
|
||||
|
||||
interface TracingService {
|
||||
fun setupTracing(tracingConfiguration: TracingConfiguration)
|
||||
fun createTimberTree(target: String): Timber.Tree
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ fun TestScope.createRustMatrixClientFactory(
|
|||
) = RustMatrixClientFactory(
|
||||
baseDirectory = baseDirectory,
|
||||
cacheDirectory = cacheDirectory,
|
||||
appCoroutineScope = this,
|
||||
appCoroutineScope = backgroundScope,
|
||||
coroutineDispatchers = testCoroutineDispatchers(),
|
||||
sessionStore = sessionStore,
|
||||
userAgentProvider = SimpleUserAgentProvider(),
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class RustMatrixClientTest {
|
|||
innerClient = FakeRustClient(),
|
||||
baseDirectory = File(""),
|
||||
sessionStore = sessionStore,
|
||||
appCoroutineScope = this,
|
||||
appCoroutineScope = backgroundScope,
|
||||
sessionDelegate = aRustClientSessionDelegate(
|
||||
sessionStore = sessionStore,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ class RustNotificationSettingsServiceTest {
|
|||
client = FakeRustClient(
|
||||
notificationSettings = notificationSettings,
|
||||
),
|
||||
sessionCoroutineScope = this,
|
||||
dispatchers = testCoroutineDispatchers(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
package io.element.android.libraries.matrix.test.room
|
||||
|
||||
import io.element.android.libraries.core.bool.orFalse
|
||||
import io.element.android.libraries.matrix.api.core.DeviceId
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.ProgressCallback
|
||||
|
|
@ -66,19 +67,9 @@ import java.io.File
|
|||
class FakeMatrixRoom(
|
||||
override val sessionId: SessionId = A_SESSION_ID,
|
||||
override val roomId: RoomId = A_ROOM_ID,
|
||||
override val displayName: String = "",
|
||||
override val topic: String? = null,
|
||||
override val avatarUrl: String? = null,
|
||||
override var isEncrypted: Boolean = false,
|
||||
override val canonicalAlias: RoomAlias? = null,
|
||||
override val alternativeAliases: List<RoomAlias> = emptyList(),
|
||||
override val isPublic: Boolean = true,
|
||||
override val isSpace: Boolean = false,
|
||||
override val isDirect: Boolean = false,
|
||||
override val joinedMemberCount: Long = 123L,
|
||||
override val activeMemberCount: Long = 234L,
|
||||
val notificationSettingsService: NotificationSettingsService = FakeNotificationSettingsService(),
|
||||
override val liveTimeline: Timeline = FakeTimeline(),
|
||||
initialRoomInfo: MatrixRoomInfo = aRoomInfo(),
|
||||
override val roomCoroutineScope: CoroutineScope = TestScope(),
|
||||
private var roomPermalinkResult: () -> Result<String> = { lambdaError() },
|
||||
private var eventPermalinkResult: (EventId) -> Result<String> = { lambdaError() },
|
||||
|
|
@ -156,8 +147,8 @@ class FakeMatrixRoom(
|
|||
private val enableEncryptionResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val updateJoinRuleResult: (JoinRule) -> Result<Unit> = { lambdaError() },
|
||||
) : MatrixRoom {
|
||||
private val _roomInfoFlow: MutableSharedFlow<MatrixRoomInfo> = MutableSharedFlow(replay = 1)
|
||||
override val roomInfoFlow: Flow<MatrixRoomInfo> = _roomInfoFlow
|
||||
private val _roomInfoFlow: MutableStateFlow<MatrixRoomInfo> = MutableStateFlow(initialRoomInfo)
|
||||
override val roomInfoFlow: StateFlow<MatrixRoomInfo> = _roomInfoFlow
|
||||
|
||||
fun givenRoomInfo(roomInfo: MatrixRoomInfo) {
|
||||
_roomInfoFlow.tryEmit(roomInfo)
|
||||
|
|
@ -200,14 +191,14 @@ class FakeMatrixRoom(
|
|||
}
|
||||
|
||||
override suspend fun updateRoomNotificationSettings(): Result<Unit> = simulateLongTask {
|
||||
val notificationSettings = notificationSettingsService.getRoomNotificationSettings(roomId, isEncrypted, isOneToOne).getOrThrow()
|
||||
val notificationSettings = notificationSettingsService.getRoomNotificationSettings(roomId, info().isEncrypted.orFalse(), isOneToOne).getOrThrow()
|
||||
roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Ready(notificationSettings)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun enableEncryption(): Result<Unit> = simulateLongTask {
|
||||
enableEncryptionResult().onSuccess {
|
||||
isEncrypted = true
|
||||
givenRoomInfo(info().copy(isEncrypted = true))
|
||||
emitSyncUpdate()
|
||||
}
|
||||
}
|
||||
|
|
@ -616,6 +607,10 @@ class FakeMatrixRoom(
|
|||
updateJoinRuleResult(joinRule)
|
||||
}
|
||||
|
||||
override suspend fun getUpdatedIsEncrypted(): Result<Boolean> = simulateLongTask {
|
||||
Result.success(info().isEncrypted.orFalse())
|
||||
}
|
||||
|
||||
fun givenRoomMembersState(state: MatrixRoomMembersState) {
|
||||
membersStateFlow.value = state
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ fun aRoomInfo(
|
|||
rawName: String? = A_ROOM_RAW_NAME,
|
||||
topic: String? = A_ROOM_TOPIC,
|
||||
avatarUrl: String? = AN_AVATAR_URL,
|
||||
isPublic: Boolean = true,
|
||||
isDirect: Boolean = false,
|
||||
isEncrypted: Boolean = false,
|
||||
joinRule: JoinRule? = JoinRule.Public,
|
||||
isSpace: Boolean = false,
|
||||
isTombstoned: Boolean = false,
|
||||
|
|
@ -65,7 +67,9 @@ fun aRoomInfo(
|
|||
rawName = rawName,
|
||||
topic = topic,
|
||||
avatarUrl = avatarUrl,
|
||||
isPublic = isPublic,
|
||||
isDirect = isDirect,
|
||||
isEncrypted = isEncrypted,
|
||||
joinRule = joinRule,
|
||||
isSpace = isSpace,
|
||||
isTombstoned = isTombstoned,
|
||||
|
|
|
|||
|
|
@ -46,7 +46,9 @@ fun aRoomSummary(
|
|||
rawName: String? = A_ROOM_RAW_NAME,
|
||||
topic: String? = A_ROOM_TOPIC,
|
||||
avatarUrl: String? = null,
|
||||
isPublic: Boolean = true,
|
||||
isDirect: Boolean = false,
|
||||
isEncrypted: Boolean = false,
|
||||
joinRule: JoinRule? = JoinRule.Public,
|
||||
isSpace: Boolean = false,
|
||||
isTombstoned: Boolean = false,
|
||||
|
|
@ -80,7 +82,9 @@ fun aRoomSummary(
|
|||
rawName = rawName,
|
||||
topic = topic,
|
||||
avatarUrl = avatarUrl,
|
||||
isPublic = isPublic,
|
||||
isDirect = isDirect,
|
||||
isEncrypted = isEncrypted,
|
||||
joinRule = joinRule,
|
||||
isSpace = isSpace,
|
||||
isTombstoned = isTombstoned,
|
||||
|
|
|
|||
|
|
@ -40,11 +40,12 @@ fun getRoomMemberAsState(roomMembersState: MatrixRoomMembersState, userId: UserI
|
|||
@Composable
|
||||
fun MatrixRoom.getDirectRoomMember(roomMembersState: MatrixRoomMembersState): State<RoomMember?> {
|
||||
val roomMembers = roomMembersState.roomMembers()
|
||||
return remember(roomMembersState) {
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
return remember(roomMembersState, roomInfo.isDirect) {
|
||||
derivedStateOf {
|
||||
roomMembers
|
||||
?.filter { it.membership.isActive() }
|
||||
?.takeIf { it.size == 2 && isDirect }
|
||||
?.takeIf { it.size == 2 && roomInfo.isDirect == true }
|
||||
?.find { it.userId != sessionId }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,9 +67,9 @@ fun MatrixRoom.canPinUnpin(updateKey: Long): State<Boolean> {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.isDmAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = isDm
|
||||
fun MatrixRoom.isDmAsState(): State<Boolean> {
|
||||
return produceState(initialValue = false) {
|
||||
roomInfoFlow.collect { value = it.isDm }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -105,25 +105,25 @@ fun MatrixRoom.userPowerLevelAsState(updateKey: Long): State<Long> {
|
|||
|
||||
@Composable
|
||||
fun MatrixRoom.isOwnUserAdmin(): Boolean {
|
||||
val roomInfo by roomInfoFlow.collectAsState(initial = null)
|
||||
val powerLevel = roomInfo?.userPowerLevels?.get(sessionId) ?: 0L
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
val powerLevel = roomInfo.userPowerLevels[sessionId] ?: 0L
|
||||
return RoomMember.Role.forPowerLevel(powerLevel) == RoomMember.Role.ADMIN
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.rawName(): String? {
|
||||
val roomInfo by roomInfoFlow.collectAsState(initial = null)
|
||||
return roomInfo?.rawName
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
return roomInfo.rawName
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.topic(): String? {
|
||||
val roomInfo by roomInfoFlow.collectAsState(initial = null)
|
||||
return roomInfo?.topic
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
return roomInfo.topic
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.avatarUrl(): String? {
|
||||
val roomInfo by roomInfoFlow.collectAsState(initial = null)
|
||||
return roomInfo?.avatarUrl
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
return roomInfo.avatarUrl
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@ import kotlinx.coroutines.flow.onEach
|
|||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun MatrixRoom.roomMemberIdentityStateChange(): Flow<ImmutableList<RoomMemberIdentityStateChange>> {
|
||||
return syncUpdateFlow
|
||||
return roomInfoFlow
|
||||
.filter {
|
||||
// Room cannot become unencrypted, so we can just apply a filter here.
|
||||
isEncrypted
|
||||
it.isEncrypted == true
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
.flatMapLatest {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID
|
|||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
||||
import io.element.android.libraries.matrix.test.A_USER_ID_3
|
||||
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.aRoomMember
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
|
|
@ -31,8 +32,10 @@ class MatrixRoomMembersTest {
|
|||
fun `getDirectRoomMember emits other member for encrypted DM with 2 joined members`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
sessionId = A_USER_ID,
|
||||
isEncrypted = true,
|
||||
isDirect = true,
|
||||
initialRoomInfo = aRoomInfo(
|
||||
isDirect = true,
|
||||
joinedMembersCount = 2,
|
||||
)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
|
|
@ -47,8 +50,7 @@ class MatrixRoomMembersTest {
|
|||
fun `getDirectRoomMember emit null if the room is not a dm`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
sessionId = A_USER_ID,
|
||||
isEncrypted = true,
|
||||
isDirect = false,
|
||||
initialRoomInfo = aRoomInfo(isDirect = false)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
|
|
@ -63,8 +65,10 @@ class MatrixRoomMembersTest {
|
|||
fun `getDirectRoomMember emits other member even if the room is not encrypted`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
sessionId = A_USER_ID,
|
||||
isEncrypted = false,
|
||||
isDirect = true,
|
||||
initialRoomInfo = aRoomInfo(
|
||||
isDirect = true,
|
||||
activeMembersCount = 2,
|
||||
)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
|
|
@ -79,8 +83,7 @@ class MatrixRoomMembersTest {
|
|||
fun `getDirectRoomMember emit null if the room has only 1 member`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
sessionId = A_USER_ID,
|
||||
isEncrypted = true,
|
||||
isDirect = true,
|
||||
initialRoomInfo = aRoomInfo(isDirect = true)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
|
|
@ -95,9 +98,9 @@ class MatrixRoomMembersTest {
|
|||
fun `getDirectRoomMember emit null if the room has only 3 members`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
sessionId = A_USER_ID,
|
||||
isEncrypted = true,
|
||||
isDirect = true,
|
||||
)
|
||||
).apply {
|
||||
givenRoomInfo(aRoomInfo(isDirect = true))
|
||||
}
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(persistentListOf(roomMember1, roomMember2, roomMember3))
|
||||
|
|
@ -111,8 +114,7 @@ class MatrixRoomMembersTest {
|
|||
fun `getDirectRoomMember emit null if the other member is not active`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
sessionId = A_USER_ID,
|
||||
isEncrypted = true,
|
||||
isDirect = true,
|
||||
initialRoomInfo = aRoomInfo(isDirect = true),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
|
|
@ -132,8 +134,10 @@ class MatrixRoomMembersTest {
|
|||
fun `getDirectRoomMember emit the other member if there are 2 active members`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
sessionId = A_USER_ID,
|
||||
isEncrypted = true,
|
||||
isDirect = true,
|
||||
initialRoomInfo = aRoomInfo(
|
||||
isDirect = true,
|
||||
activeMembersCount = 2,
|
||||
)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class MediaGalleryPresenter @AssistedInject constructor(
|
|||
val coroutineScope = rememberCoroutineScope()
|
||||
var mode by remember { mutableStateOf(MediaGalleryMode.Images) }
|
||||
|
||||
val roomInfo by room.roomInfoFlow.collectAsState(null)
|
||||
val roomInfo by room.roomInfoFlow.collectAsState()
|
||||
|
||||
var mediaBottomSheetState by remember { mutableStateOf<MediaBottomSheetState>(MediaBottomSheetState.Hidden) }
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ class MediaGalleryPresenter @AssistedInject constructor(
|
|||
}
|
||||
|
||||
return MediaGalleryState(
|
||||
roomName = roomInfo?.name ?: room.displayName,
|
||||
roomName = roomInfo.name.orEmpty(),
|
||||
mode = mode,
|
||||
groupedMediaItems = groupedMediaItems,
|
||||
mediaBottomSheetState = mediaBottomSheetState,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID
|
|||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
||||
import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader
|
||||
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.timeline.FakeTimeline
|
||||
import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource
|
||||
import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource
|
||||
|
|
@ -51,7 +52,7 @@ class MediaGalleryPresenterTest {
|
|||
startLambda = startLambda,
|
||||
),
|
||||
room = FakeMatrixRoom(
|
||||
displayName = A_ROOM_NAME,
|
||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||
createTimelineResult = { Result.success(FakeTimeline()) },
|
||||
)
|
||||
)
|
||||
|
|
@ -70,7 +71,7 @@ class MediaGalleryPresenterTest {
|
|||
fun `present - change mode`() = runTest {
|
||||
val presenter = createMediaGalleryPresenter(
|
||||
room = FakeMatrixRoom(
|
||||
displayName = A_ROOM_NAME,
|
||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||
createTimelineResult = { Result.success(FakeTimeline()) },
|
||||
)
|
||||
)
|
||||
|
|
@ -100,7 +101,7 @@ class MediaGalleryPresenterTest {
|
|||
val presenter = createMediaGalleryPresenter(
|
||||
room = FakeMatrixRoom(
|
||||
sessionId = A_USER_ID,
|
||||
displayName = A_ROOM_NAME,
|
||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||
createTimelineResult = { Result.success(FakeTimeline()) },
|
||||
canRedactOwnResult = { Result.success(canDeleteOwn) }
|
||||
)
|
||||
|
|
@ -143,7 +144,7 @@ class MediaGalleryPresenterTest {
|
|||
val presenter = createMediaGalleryPresenter(
|
||||
room = FakeMatrixRoom(
|
||||
sessionId = A_USER_ID,
|
||||
displayName = A_ROOM_NAME,
|
||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||
createTimelineResult = { Result.success(FakeTimeline()) },
|
||||
canRedactOtherResult = { Result.success(canDeleteOther) }
|
||||
)
|
||||
|
|
@ -176,7 +177,7 @@ class MediaGalleryPresenterTest {
|
|||
fun `present - delete bottom sheet`() = runTest {
|
||||
val presenter = createMediaGalleryPresenter(
|
||||
room = FakeMatrixRoom(
|
||||
displayName = A_ROOM_NAME,
|
||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||
createTimelineResult = { Result.success(FakeTimeline()) },
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -152,8 +152,8 @@ class NotificationBroadcastReceiverHandler @Inject constructor(
|
|||
imageUriString = null,
|
||||
imageMimeType = null,
|
||||
threadId = threadId,
|
||||
roomName = room.displayName,
|
||||
roomIsDm = room.isDm,
|
||||
roomName = room.info().name,
|
||||
roomIsDm = room.isDm(),
|
||||
outGoingMessage = true,
|
||||
)
|
||||
onNotifiableEventReceived.onNotifiableEventReceived(notifiableMessageEvent)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.test.FakeMatrixClient
|
|||
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||
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.aRoomMember
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
||||
|
|
@ -337,7 +338,14 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
val matrixRoom = FakeMatrixRoom(
|
||||
liveTimeline = liveTimeline,
|
||||
getUpdatedMemberResult = { Result.success(aRoomMember()) },
|
||||
)
|
||||
).apply {
|
||||
givenRoomInfo(
|
||||
aRoomInfo(
|
||||
isDirect = true,
|
||||
activeMembersCount = 2,
|
||||
)
|
||||
)
|
||||
}
|
||||
val onNotifiableEventReceivedResult = lambdaRecorder<NotifiableEvent, Unit> { _ -> }
|
||||
val onNotifiableEventReceived = FakeOnNotifiableEventReceived(onNotifiableEventReceivedResult = onNotifiableEventReceivedResult)
|
||||
val sut = createNotificationBroadcastReceiverHandler(
|
||||
|
|
@ -396,7 +404,14 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
val matrixRoom = FakeMatrixRoom(
|
||||
liveTimeline = liveTimeline,
|
||||
getUpdatedMemberResult = { Result.success(aRoomMember()) },
|
||||
)
|
||||
).apply {
|
||||
givenRoomInfo(
|
||||
aRoomInfo(
|
||||
isDirect = true,
|
||||
activeMembersCount = 2,
|
||||
)
|
||||
)
|
||||
}
|
||||
val onNotifiableEventReceivedResult = lambdaRecorder<NotifiableEvent, Unit> { _ -> }
|
||||
val onNotifiableEventReceived = FakeOnNotifiableEventReceived(onNotifiableEventReceivedResult = onNotifiableEventReceivedResult)
|
||||
val sut = createNotificationBroadcastReceiverHandler(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue