Split MatrixRoom into BaseRoom and JoinedRoom (#4561)
`JoinedRoom` will now contain both a mandatory live timeline reference and all the functionality associated to it. `BaseRoom` on the other hand will contain only functionality that's shared for both joined and not joined rooms. `NotJoinedRoom` is a wrapper around `RoomPreviewInfo` data and a possible local `BaseRoom`, if it exists. The `RustRoomFactory` cache is now gone since the persistent event cache should have the same effect.
This commit is contained in:
parent
91cb84ce8d
commit
619aa6f2de
193 changed files with 2921 additions and 2567 deletions
|
|
@ -57,7 +57,7 @@ import org.robolectric.annotation.Config
|
|||
|
||||
@Suppress("LargeClass")
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class DefaultRoomLastMessageFormatterTest {
|
||||
class DefaultBaseRoomLastMessageFormatterTest {
|
||||
private lateinit var context: Context
|
||||
private lateinit var fakeMatrixClient: FakeMatrixClient
|
||||
private lateinit var formatter: DefaultRoomLastMessageFormatter
|
||||
|
|
@ -23,10 +23,11 @@ import io.element.android.libraries.matrix.api.notification.NotificationService
|
|||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
||||
import io.element.android.libraries.matrix.api.pusher.PushersService
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.NotJoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.RoomPreview
|
||||
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
|
|
@ -52,8 +53,8 @@ interface MatrixClient {
|
|||
val mediaLoader: MatrixMediaLoader
|
||||
val sessionCoroutineScope: CoroutineScope
|
||||
val ignoredUsersFlow: StateFlow<ImmutableList<UserId>>
|
||||
suspend fun getRoom(roomId: RoomId): MatrixRoom?
|
||||
suspend fun getPendingRoom(roomId: RoomId): RoomPreview?
|
||||
suspend fun getJoinedRoom(roomId: RoomId): JoinedRoom?
|
||||
suspend fun getRoom(roomId: RoomId): BaseRoom?
|
||||
suspend fun findDM(userId: UserId): RoomId?
|
||||
suspend fun ignoreUser(userId: UserId): Result<Unit>
|
||||
suspend fun unignoreUser(userId: UserId): Result<Unit>
|
||||
|
|
@ -147,7 +148,7 @@ interface MatrixClient {
|
|||
/**
|
||||
* Get a room preview for a given room ID or alias. This is especially useful for rooms that the user is not a member of, or hasn't joined yet.
|
||||
*/
|
||||
suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreview>
|
||||
suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<NotJoinedRoom>
|
||||
|
||||
/**
|
||||
* Returns the currently used sliding sync version.
|
||||
|
|
@ -168,7 +169,7 @@ interface MatrixClient {
|
|||
* The flow will emit a new value whenever the room info is updated.
|
||||
* The flow will emit Optional.empty item if the room is not found.
|
||||
*/
|
||||
fun MatrixClient.getRoomInfoFlow(roomIdOrAlias: RoomIdOrAlias): Flow<Optional<MatrixRoomInfo>> {
|
||||
fun MatrixClient.getRoomInfoFlow(roomIdOrAlias: RoomIdOrAlias): Flow<Optional<RoomInfo>> {
|
||||
return getRoomSummaryFlow(roomIdOrAlias)
|
||||
.map { roomSummary -> roomSummary.map { it.info } }
|
||||
.distinctUntilChanged()
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
package io.element.android.libraries.matrix.api.analytics
|
||||
|
||||
import im.vector.app.features.analytics.plan.ViewRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
|
||||
fun MatrixRoom.toAnalyticsViewRoom(
|
||||
fun BaseRoom.toAnalyticsViewRoom(
|
||||
trigger: ViewRoom.Trigger? = null,
|
||||
selectedSpace: MatrixRoom? = null,
|
||||
selectedSpace: BaseRoom? = null,
|
||||
viaKeyboard: Boolean? = null,
|
||||
): ViewRoom {
|
||||
val activeSpace = selectedSpace?.toActiveSpace() ?: ViewRoom.ActiveSpace.Home
|
||||
|
|
@ -26,6 +26,6 @@ fun MatrixRoom.toAnalyticsViewRoom(
|
|||
)
|
||||
}
|
||||
|
||||
private fun MatrixRoom.toActiveSpace(): ViewRoom.ActiveSpace {
|
||||
private fun BaseRoom.toActiveSpace(): ViewRoom.ActiveSpace {
|
||||
return if (info().isPublic) ViewRoom.ActiveSpace.Public else ViewRoom.ActiveSpace.Private
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@
|
|||
package io.element.android.libraries.matrix.api.notificationsettings
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomNotificationSettingsState
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationSettings
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationSettingsState
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
|
||||
interface NotificationSettingsService {
|
||||
/**
|
||||
* State of the current room notification settings flow ([MatrixRoomNotificationSettingsState.Unknown] if not started).
|
||||
* State of the current room notification settings flow ([RoomNotificationSettingsState.Unknown] if not started).
|
||||
*/
|
||||
val notificationSettingsChangeFlow: SharedFlow<Unit>
|
||||
suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationSettings>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 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.room
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.io.Closeable
|
||||
|
||||
/**
|
||||
* This interface represents the common functionality for a local room, whether it's joined, invited, knocked, or left.
|
||||
*/
|
||||
interface BaseRoom : Closeable {
|
||||
/**
|
||||
* The session id of the current user.
|
||||
*/
|
||||
val sessionId: SessionId
|
||||
|
||||
/**
|
||||
* The id of the room.
|
||||
*/
|
||||
val roomId: RoomId
|
||||
|
||||
/**
|
||||
* The coroutine scope that will handle all jobs related to this room.
|
||||
*/
|
||||
val roomCoroutineScope: CoroutineScope
|
||||
|
||||
/**
|
||||
* The current loaded members as a StateFlow.
|
||||
* Initial value is [RoomMembersState.Unknown].
|
||||
* To update them you should call [updateMembers].
|
||||
*/
|
||||
val membersStateFlow: StateFlow<RoomMembersState>
|
||||
|
||||
/**
|
||||
* A flow that emits the current [RoomInfo] state.
|
||||
*/
|
||||
val roomInfoFlow: StateFlow<RoomInfo>
|
||||
|
||||
/**
|
||||
* Get the latest room info we have received from the SDK stream.
|
||||
*/
|
||||
fun info(): RoomInfo = roomInfoFlow.value
|
||||
|
||||
/**
|
||||
* Try to load the room members and update the membersFlow.
|
||||
*/
|
||||
suspend fun updateMembers()
|
||||
|
||||
/**
|
||||
* Get the members of the room. Note: generally this should not be used, please use
|
||||
* [membersStateFlow] and [updateMembers] instead.
|
||||
*/
|
||||
suspend fun getMembers(limit: Int = 5): Result<List<RoomMember>>
|
||||
|
||||
/**
|
||||
* Will return an updated member or an error.
|
||||
*/
|
||||
suspend fun getUpdatedMember(userId: UserId): Result<RoomMember>
|
||||
|
||||
/**
|
||||
* Adds the room to the sync subscription list.
|
||||
*/
|
||||
suspend fun subscribeToSync()
|
||||
|
||||
/**
|
||||
* Gets the power levels of the room.
|
||||
*/
|
||||
suspend fun powerLevels(): Result<RoomPowerLevels>
|
||||
|
||||
/**
|
||||
* Gets the role of the user with the provided [userId] in the room.
|
||||
*/
|
||||
suspend fun userRole(userId: UserId): Result<RoomMember.Role>
|
||||
|
||||
/**
|
||||
* Gets the display name of the user with the provided [userId] in the room.
|
||||
*/
|
||||
suspend fun userDisplayName(userId: UserId): Result<String?>
|
||||
|
||||
/**
|
||||
* Gets the avatar of the user with the provided [userId] in the room.
|
||||
*/
|
||||
suspend fun userAvatarUrl(userId: UserId): Result<String?>
|
||||
|
||||
/**
|
||||
* Leaves and forgets the room. Only joined, invited or knocked rooms can be left.
|
||||
*/
|
||||
suspend fun leave(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Joins the room. Only invited rooms can be joined.
|
||||
*/
|
||||
suspend fun join(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Forgets about the room, removing it from the server and the local cache. Only left and banned rooms can be forgotten.
|
||||
*/
|
||||
suspend fun forget(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can invite other users to the room.
|
||||
*/
|
||||
suspend fun canUserInvite(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can kick other users from the room.
|
||||
*/
|
||||
suspend fun canUserKick(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can ban other users from the room.
|
||||
*/
|
||||
suspend fun canUserBan(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can redact their own messages.
|
||||
*/
|
||||
suspend fun canUserRedactOwn(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can redact messages from other users.
|
||||
*/
|
||||
suspend fun canUserRedactOther(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can send state events.
|
||||
*/
|
||||
suspend fun canUserSendState(userId: UserId, type: StateEventType): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can send messages.
|
||||
*/
|
||||
suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can trigger an `@room` notification.
|
||||
*/
|
||||
suspend fun canUserTriggerRoomNotification(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can pin or unpin messages.
|
||||
*/
|
||||
suspend fun canUserPinUnpin(userId: UserId): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Returns `true` if the user with the provided [userId] can join or starts calls.
|
||||
*/
|
||||
suspend fun canUserJoinCall(userId: UserId): Result<Boolean> =
|
||||
canUserSendState(userId, StateEventType.CALL_MEMBER)
|
||||
|
||||
/**
|
||||
* Sets the room as favorite or not, based on the [isFavorite] parameter.
|
||||
*/
|
||||
suspend fun setIsFavorite(isFavorite: Boolean): Result<Unit>
|
||||
|
||||
/**
|
||||
* Mark the room as read by trying to attach an unthreaded read receipt to the latest room event.
|
||||
* @param receiptType The type of receipt to send.
|
||||
*/
|
||||
suspend fun markAsRead(receiptType: ReceiptType): Result<Unit>
|
||||
|
||||
/**
|
||||
* Sets a flag on the room to indicate that the user has explicitly marked it as unread, or reverts the flag.
|
||||
* @param isUnread true to mark the room as unread, false to remove the flag.
|
||||
*/
|
||||
suspend fun setUnreadFlag(isUnread: Boolean): Result<Unit>
|
||||
|
||||
/**
|
||||
* Clear the event cache storage for the current room.
|
||||
*/
|
||||
suspend fun clearEventCacheStorage(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Get the permalink for the room.
|
||||
*/
|
||||
suspend fun getPermalink(): Result<String>
|
||||
|
||||
/**
|
||||
* Get the permalink for the provided [eventId].
|
||||
* @param eventId The event id to get the permalink for.
|
||||
* @return The permalink, or a failure.
|
||||
*/
|
||||
suspend fun getPermalinkFor(eventId: EventId): Result<String>
|
||||
|
||||
/**
|
||||
* Returns the visibility for this room in the room directory.
|
||||
* If the room is not published, the result will be [RoomVisibility.Private].
|
||||
*/
|
||||
suspend fun getRoomVisibility(): Result<RoomVisibility>
|
||||
|
||||
/**
|
||||
* Returns the visibility for this room in the room directory, fetching it from the homeserver if needed.
|
||||
*/
|
||||
suspend fun getUpdatedIsEncrypted(): Result<Boolean>
|
||||
|
||||
/**
|
||||
* Store the given `ComposerDraft` in the state store of this room.
|
||||
*/
|
||||
suspend fun saveComposerDraft(composerDraft: ComposerDraft): Result<Unit>
|
||||
|
||||
/**
|
||||
* Retrieve the `ComposerDraft` stored in the state store for this room.
|
||||
*/
|
||||
suspend fun loadComposerDraft(): Result<ComposerDraft?>
|
||||
|
||||
/**
|
||||
* Clear the `ComposerDraft` stored in the state store for this room.
|
||||
*/
|
||||
suspend fun clearComposerDraft(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Destroy the room and release all resources associated to it.
|
||||
*/
|
||||
fun destroy()
|
||||
|
||||
override fun close() = destroy()
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
* 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.
|
||||
|
|
@ -13,7 +13,6 @@ import io.element.android.libraries.matrix.api.core.ProgressCallback
|
|||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SendHandle
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.TransactionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange
|
||||
|
|
@ -23,35 +22,28 @@ import io.element.android.libraries.matrix.api.media.ImageInfo
|
|||
import io.element.android.libraries.matrix.api.media.MediaUploadHandler
|
||||
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.draft.ComposerDraft
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.room.knock.KnockRequest
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.room.message.ReplyParameters
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
|
||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
|
||||
interface MatrixRoom : Closeable {
|
||||
val sessionId: SessionId
|
||||
val roomId: RoomId
|
||||
interface JoinedRoom : BaseRoom {
|
||||
val syncUpdateFlow: StateFlow<Long>
|
||||
|
||||
val roomCoroutineScope: CoroutineScope
|
||||
|
||||
val roomInfoFlow: StateFlow<MatrixRoomInfo>
|
||||
val roomTypingMembersFlow: Flow<List<UserId>>
|
||||
val identityStateChangesFlow: Flow<List<IdentityStateChange>>
|
||||
val roomNotificationSettingsStateFlow: StateFlow<RoomNotificationSettingsState>
|
||||
|
||||
/**
|
||||
* The current knock requests in the room as a Flow.
|
||||
|
|
@ -64,40 +56,6 @@ interface MatrixRoom : Closeable {
|
|||
*/
|
||||
val isOneToOne: Boolean get() = info().activeMembersCount == 2L
|
||||
|
||||
/**
|
||||
* The current loaded members as a StateFlow.
|
||||
* Initial value is [MatrixRoomMembersState.Unknown].
|
||||
* To update them you should call [updateMembers].
|
||||
*/
|
||||
val membersStateFlow: StateFlow<MatrixRoomMembersState>
|
||||
|
||||
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.
|
||||
*/
|
||||
suspend fun updateMembers()
|
||||
|
||||
/**
|
||||
* Get the members of the room. Note: generally this should not be used, please use
|
||||
* [membersStateFlow] and [updateMembers] instead.
|
||||
*/
|
||||
suspend fun getMembers(limit: Int = 5): Result<List<RoomMember>>
|
||||
|
||||
/**
|
||||
* Will return an updated member or an error.
|
||||
*/
|
||||
suspend fun getUpdatedMember(userId: UserId): Result<RoomMember>
|
||||
|
||||
suspend fun updateRoomNotificationSettings(): Result<Unit>
|
||||
|
||||
val syncUpdateFlow: StateFlow<Long>
|
||||
|
||||
/**
|
||||
* The live timeline of the room. Must be used to send Event to a room.
|
||||
*/
|
||||
|
|
@ -111,24 +69,6 @@ interface MatrixRoom : Closeable {
|
|||
createTimelineParams: CreateTimelineParams,
|
||||
): Result<Timeline>
|
||||
|
||||
fun destroy()
|
||||
|
||||
suspend fun subscribeToSync()
|
||||
|
||||
suspend fun powerLevels(): Result<MatrixRoomPowerLevels>
|
||||
|
||||
suspend fun updatePowerLevels(matrixRoomPowerLevels: MatrixRoomPowerLevels): Result<Unit>
|
||||
|
||||
suspend fun resetPowerLevels(): Result<MatrixRoomPowerLevels>
|
||||
|
||||
suspend fun userRole(userId: UserId): Result<RoomMember.Role>
|
||||
|
||||
suspend fun updateUsersRoles(changes: List<UserRoleChange>): Result<Unit>
|
||||
|
||||
suspend fun userDisplayName(userId: UserId): Result<String?>
|
||||
|
||||
suspend fun userAvatarUrl(userId: UserId): Result<String?>
|
||||
|
||||
suspend fun sendMessage(body: String, htmlBody: String?, intentionalMentions: List<IntentionalMention>): Result<Unit>
|
||||
|
||||
suspend fun editMessage(eventId: EventId, body: String, htmlBody: String?, intentionalMentions: List<IntentionalMention>): Result<Unit>
|
||||
|
|
@ -198,75 +138,6 @@ interface MatrixRoom : Closeable {
|
|||
assetType: AssetType? = null,
|
||||
): Result<Unit>
|
||||
|
||||
suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Unit>
|
||||
|
||||
suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit>
|
||||
|
||||
suspend fun cancelSend(transactionId: TransactionId): Result<Unit>
|
||||
|
||||
suspend fun leave(): Result<Unit>
|
||||
|
||||
suspend fun join(): Result<Unit>
|
||||
|
||||
suspend fun inviteUserById(id: UserId): Result<Unit>
|
||||
|
||||
suspend fun canUserInvite(userId: UserId): Result<Boolean>
|
||||
|
||||
suspend fun canUserKick(userId: UserId): Result<Boolean>
|
||||
|
||||
suspend fun canUserBan(userId: UserId): Result<Boolean>
|
||||
|
||||
suspend fun canUserRedactOwn(userId: UserId): Result<Boolean>
|
||||
|
||||
suspend fun canUserRedactOther(userId: UserId): Result<Boolean>
|
||||
|
||||
suspend fun canUserSendState(userId: UserId, type: StateEventType): Result<Boolean>
|
||||
|
||||
suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result<Boolean>
|
||||
|
||||
suspend fun canUserTriggerRoomNotification(userId: UserId): Result<Boolean>
|
||||
|
||||
suspend fun canUserPinUnpin(userId: UserId): Result<Boolean>
|
||||
|
||||
suspend fun canUserJoinCall(userId: UserId): Result<Boolean> =
|
||||
canUserSendState(userId, StateEventType.CALL_MEMBER)
|
||||
|
||||
suspend fun updateAvatar(mimeType: String, data: ByteArray): Result<Unit>
|
||||
|
||||
suspend fun removeAvatar(): Result<Unit>
|
||||
|
||||
suspend fun setName(name: String): Result<Unit>
|
||||
|
||||
suspend fun setTopic(topic: String): Result<Unit>
|
||||
|
||||
suspend fun reportContent(eventId: EventId, reason: String, blockUserId: UserId?): Result<Unit>
|
||||
|
||||
suspend fun kickUser(userId: UserId, reason: String? = null): Result<Unit>
|
||||
|
||||
suspend fun banUser(userId: UserId, reason: String? = null): Result<Unit>
|
||||
|
||||
suspend fun unbanUser(userId: UserId, reason: String? = null): Result<Unit>
|
||||
|
||||
suspend fun setIsFavorite(isFavorite: Boolean): Result<Unit>
|
||||
|
||||
/**
|
||||
* Mark the room as read by trying to attach an unthreaded read receipt to the latest room event.
|
||||
* @param receiptType The type of receipt to send.
|
||||
*/
|
||||
suspend fun markAsRead(receiptType: ReceiptType): Result<Unit>
|
||||
|
||||
/**
|
||||
* Sets a flag on the room to indicate that the user has explicitly marked it as unread, or reverts the flag.
|
||||
* @param isUnread true to mark the room as unread, false to remove the flag.
|
||||
*
|
||||
*/
|
||||
suspend fun setUnreadFlag(isUnread: Boolean): Result<Unit>
|
||||
|
||||
/**
|
||||
* Clear the event cache storage for the current room.
|
||||
*/
|
||||
suspend fun clearEventCacheStorage(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Create a poll in the room.
|
||||
*
|
||||
|
|
@ -321,82 +192,19 @@ interface MatrixRoom : Closeable {
|
|||
*/
|
||||
suspend fun typingNotice(isTyping: Boolean): Result<Unit>
|
||||
|
||||
/**
|
||||
* Generates a Widget url to display in a [android.webkit.WebView] given the provided parameters.
|
||||
* @param widgetSettings The widget settings to use.
|
||||
* @param clientId The client id to use. It should be unique per app install.
|
||||
* @param languageTag The language tag to use. If null, the default language will be used.
|
||||
* @param theme The theme to use. If null, the default theme will be used.
|
||||
* @return The resulting url, or a failure.
|
||||
*/
|
||||
suspend fun generateWidgetWebViewUrl(
|
||||
widgetSettings: MatrixWidgetSettings,
|
||||
clientId: String,
|
||||
languageTag: String?,
|
||||
theme: String?,
|
||||
): Result<String>
|
||||
suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Unit>
|
||||
|
||||
/**
|
||||
* Get a [MatrixWidgetDriver] for the provided [widgetSettings].
|
||||
* @param widgetSettings The widget settings to use.
|
||||
* @return The resulting [MatrixWidgetDriver], or a failure.
|
||||
*/
|
||||
fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result<MatrixWidgetDriver>
|
||||
suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit>
|
||||
|
||||
/**
|
||||
* Get the permalink for the room.
|
||||
*/
|
||||
suspend fun getPermalink(): Result<String>
|
||||
suspend fun cancelSend(transactionId: TransactionId): Result<Unit>
|
||||
|
||||
/**
|
||||
* Get the permalink for the provided [eventId].
|
||||
* @param eventId The event id to get the permalink for.
|
||||
* @return The permalink, or a failure.
|
||||
*/
|
||||
suspend fun getPermalinkFor(eventId: EventId): Result<String>
|
||||
suspend fun inviteUserById(id: UserId): Result<Unit>
|
||||
|
||||
/**
|
||||
* Send an Element Call started notification if needed.
|
||||
*/
|
||||
suspend fun sendCallNotificationIfNeeded(): Result<Unit>
|
||||
suspend fun updateAvatar(mimeType: String, data: ByteArray): Result<Unit>
|
||||
|
||||
suspend fun setSendQueueEnabled(enabled: Boolean)
|
||||
suspend fun removeAvatar(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Store the given `ComposerDraft` in the state store of this room.
|
||||
*/
|
||||
suspend fun saveComposerDraft(composerDraft: ComposerDraft): Result<Unit>
|
||||
|
||||
/**
|
||||
* Retrieve the `ComposerDraft` stored in the state store for this room.
|
||||
*/
|
||||
suspend fun loadComposerDraft(): Result<ComposerDraft?>
|
||||
|
||||
/**
|
||||
* Clear the `ComposerDraft` stored in the state store for this room.
|
||||
*/
|
||||
suspend fun clearComposerDraft(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Ignore the local trust for the given devices and resend messages that failed to send because said devices are unverified.
|
||||
*
|
||||
* @param devices The map of users identifiers to device identifiers received in the error
|
||||
* @param sendHandle The send queue handle of the local echo the send error applies to. It can be used to retry the upload.
|
||||
*
|
||||
*/
|
||||
suspend fun ignoreDeviceTrustAndResend(devices: Map<UserId, List<DeviceId>>, sendHandle: SendHandle): Result<Unit>
|
||||
|
||||
/**
|
||||
* Remove verification requirements for the given users and
|
||||
* resend messages that failed to send because their identities were no longer verified.
|
||||
*
|
||||
* @param userIds The list of users identifiers received in the error.
|
||||
* @param sendHandle The send queue handle of the local echo the send error applies to. It can be used to retry the upload.
|
||||
*
|
||||
*/
|
||||
suspend fun withdrawVerificationAndResend(userIds: List<UserId>, sendHandle: SendHandle): Result<Unit>
|
||||
|
||||
override fun close() = destroy()
|
||||
suspend fun updateRoomNotificationSettings(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Update the canonical alias of the room.
|
||||
|
|
@ -418,12 +226,6 @@ interface MatrixRoom : Closeable {
|
|||
*/
|
||||
suspend fun updateHistoryVisibility(historyVisibility: RoomHistoryVisibility): Result<Unit>
|
||||
|
||||
/**
|
||||
* Returns the visibility for this room in the room directory.
|
||||
* If the room is not published, the result will be [RoomVisibility.Private].
|
||||
*/
|
||||
suspend fun getRoomVisibility(): Result<RoomVisibility>
|
||||
|
||||
/**
|
||||
* Publish a new room alias for this room in the room directory.
|
||||
*
|
||||
|
|
@ -454,5 +256,69 @@ interface MatrixRoom : Closeable {
|
|||
*/
|
||||
suspend fun updateJoinRule(joinRule: JoinRule): Result<Unit>
|
||||
|
||||
suspend fun getUpdatedIsEncrypted(): Result<Boolean>
|
||||
suspend fun updateUsersRoles(changes: List<UserRoleChange>): Result<Unit>
|
||||
|
||||
suspend fun updatePowerLevels(roomPowerLevels: RoomPowerLevels): Result<Unit>
|
||||
|
||||
suspend fun resetPowerLevels(): Result<RoomPowerLevels>
|
||||
|
||||
suspend fun setName(name: String): Result<Unit>
|
||||
|
||||
suspend fun setTopic(topic: String): Result<Unit>
|
||||
|
||||
suspend fun reportContent(eventId: EventId, reason: String, blockUserId: UserId?): Result<Unit>
|
||||
|
||||
suspend fun kickUser(userId: UserId, reason: String? = null): Result<Unit>
|
||||
|
||||
suspend fun banUser(userId: UserId, reason: String? = null): Result<Unit>
|
||||
|
||||
suspend fun unbanUser(userId: UserId, reason: String? = null): Result<Unit>
|
||||
|
||||
/**
|
||||
* Generates a Widget url to display in a [android.webkit.WebView] given the provided parameters.
|
||||
* @param widgetSettings The widget settings to use.
|
||||
* @param clientId The client id to use. It should be unique per app install.
|
||||
* @param languageTag The language tag to use. If null, the default language will be used.
|
||||
* @param theme The theme to use. If null, the default theme will be used.
|
||||
* @return The resulting url, or a failure.
|
||||
*/
|
||||
suspend fun generateWidgetWebViewUrl(
|
||||
widgetSettings: MatrixWidgetSettings,
|
||||
clientId: String,
|
||||
languageTag: String?,
|
||||
theme: String?,
|
||||
): Result<String>
|
||||
|
||||
/**
|
||||
* Get a [MatrixWidgetDriver] for the provided [widgetSettings].
|
||||
* @param widgetSettings The widget settings to use.
|
||||
* @return The resulting [MatrixWidgetDriver], or a failure.
|
||||
*/
|
||||
fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result<MatrixWidgetDriver>
|
||||
|
||||
/**
|
||||
* Send an Element Call started notification if needed.
|
||||
*/
|
||||
suspend fun sendCallNotificationIfNeeded(): Result<Unit>
|
||||
|
||||
suspend fun setSendQueueEnabled(enabled: Boolean)
|
||||
|
||||
/**
|
||||
* Ignore the local trust for the given devices and resend messages that failed to send because said devices are unverified.
|
||||
*
|
||||
* @param devices The map of users identifiers to device identifiers received in the error
|
||||
* @param sendHandle The send queue handle of the local echo the send error applies to. It can be used to retry the upload.
|
||||
*
|
||||
*/
|
||||
suspend fun ignoreDeviceTrustAndResend(devices: Map<UserId, List<DeviceId>>, sendHandle: SendHandle): Result<Unit>
|
||||
|
||||
/**
|
||||
* Remove verification requirements for the given users and
|
||||
* resend messages that failed to send because their identities were no longer verified.
|
||||
*
|
||||
* @param userIds The list of users identifiers received in the error.
|
||||
* @param sendHandle The send queue handle of the local echo the send error applies to. It can be used to retry the upload.
|
||||
*
|
||||
*/
|
||||
suspend fun withdrawVerificationAndResend(userIds: List<UserId>, sendHandle: SendHandle): Result<Unit>
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 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.room
|
||||
|
||||
sealed interface MatrixRoomNotificationSettingsState {
|
||||
data object Unknown : MatrixRoomNotificationSettingsState
|
||||
data class Pending(val prevRoomNotificationSettings: RoomNotificationSettings? = null) : MatrixRoomNotificationSettingsState
|
||||
data class Error(val failure: Throwable, val prevRoomNotificationSettings: RoomNotificationSettings? = null) : MatrixRoomNotificationSettingsState
|
||||
data class Ready(val roomNotificationSettings: RoomNotificationSettings) : MatrixRoomNotificationSettingsState
|
||||
}
|
||||
|
||||
fun MatrixRoomNotificationSettingsState.roomNotificationSettings(): RoomNotificationSettings? {
|
||||
return when (this) {
|
||||
is MatrixRoomNotificationSettingsState.Ready -> roomNotificationSettings
|
||||
is MatrixRoomNotificationSettingsState.Pending -> prevRoomNotificationSettings
|
||||
is MatrixRoomNotificationSettingsState.Error -> prevRoomNotificationSettings
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
@ -7,21 +7,12 @@
|
|||
|
||||
package io.element.android.libraries.matrix.api.room
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
|
||||
|
||||
/** A reference to a room either invited, knocked or banned. */
|
||||
interface RoomPreview : AutoCloseable {
|
||||
val sessionId: SessionId
|
||||
val info: RoomPreviewInfo
|
||||
|
||||
/** Leave the room ie.decline invite or cancel knock. */
|
||||
suspend fun leave(): Result<Unit>
|
||||
|
||||
/**
|
||||
* Forget the room if we had access to it, and it was left or banned.
|
||||
*/
|
||||
suspend fun forget(): Result<Unit>
|
||||
interface NotJoinedRoom : AutoCloseable {
|
||||
val previewInfo: RoomPreviewInfo
|
||||
val localRoom: BaseRoom?
|
||||
|
||||
/**
|
||||
* Get the membership details of the user in the room, as well as from the user who sent the `m.room.member` event.
|
||||
|
|
@ -19,7 +19,7 @@ import kotlinx.collections.immutable.ImmutableList
|
|||
import kotlinx.collections.immutable.ImmutableMap
|
||||
|
||||
@Immutable
|
||||
data class MatrixRoomInfo(
|
||||
data class RoomInfo(
|
||||
val id: RoomId,
|
||||
/** The room's name from the room state event if received from sync, or one that's been computed otherwise. */
|
||||
val name: String?,
|
||||
|
|
@ -21,11 +21,11 @@ fun isDm(isDirect: Boolean, activeMembersCount: Int): Boolean {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns whether the [MatrixRoom] is a DM, with an updated state from the latest [MatrixRoomInfo].
|
||||
* Returns whether the [BaseRoom] is a DM, with an updated state from the latest [RoomInfo].
|
||||
*/
|
||||
suspend fun MatrixRoom.isDm() = roomInfoFlow.first().isDm
|
||||
suspend fun BaseRoom.isDm() = roomInfoFlow.first().isDm
|
||||
|
||||
/**
|
||||
* Returns whether the [MatrixRoomInfo] is from a DM.
|
||||
* Returns whether the [RoomInfo] is from a DM.
|
||||
*/
|
||||
val MatrixRoomInfo.isDm get() = isDm(isDirect, activeMembersCount.toInt())
|
||||
val RoomInfo.isDm get() = isDm(isDirect, activeMembersCount.toInt())
|
||||
|
|
|
|||
|
|
@ -11,26 +11,26 @@ import androidx.compose.runtime.Immutable
|
|||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Immutable
|
||||
sealed interface MatrixRoomMembersState {
|
||||
data object Unknown : MatrixRoomMembersState
|
||||
data class Pending(val prevRoomMembers: ImmutableList<RoomMember>? = null) : MatrixRoomMembersState
|
||||
data class Error(val failure: Throwable, val prevRoomMembers: ImmutableList<RoomMember>? = null) : MatrixRoomMembersState
|
||||
data class Ready(val roomMembers: ImmutableList<RoomMember>) : MatrixRoomMembersState
|
||||
sealed interface RoomMembersState {
|
||||
data object Unknown : RoomMembersState
|
||||
data class Pending(val prevRoomMembers: ImmutableList<RoomMember>? = null) : RoomMembersState
|
||||
data class Error(val failure: Throwable, val prevRoomMembers: ImmutableList<RoomMember>? = null) : RoomMembersState
|
||||
data class Ready(val roomMembers: ImmutableList<RoomMember>) : RoomMembersState
|
||||
}
|
||||
|
||||
fun MatrixRoomMembersState.roomMembers(): List<RoomMember>? {
|
||||
fun RoomMembersState.roomMembers(): List<RoomMember>? {
|
||||
return when (this) {
|
||||
is MatrixRoomMembersState.Ready -> roomMembers
|
||||
is MatrixRoomMembersState.Pending -> prevRoomMembers
|
||||
is MatrixRoomMembersState.Error -> prevRoomMembers
|
||||
is RoomMembersState.Ready -> roomMembers
|
||||
is RoomMembersState.Pending -> prevRoomMembers
|
||||
is RoomMembersState.Error -> prevRoomMembers
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun MatrixRoomMembersState.joinedRoomMembers(): List<RoomMember> {
|
||||
fun RoomMembersState.joinedRoomMembers(): List<RoomMember> {
|
||||
return roomMembers().orEmpty().filter { it.membership == RoomMembershipState.JOIN }
|
||||
}
|
||||
|
||||
fun MatrixRoomMembersState.activeRoomMembers(): List<RoomMember> {
|
||||
fun RoomMembersState.activeRoomMembers(): List<RoomMember> {
|
||||
return roomMembers().orEmpty().filter { it.membership.isActive() }
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 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.room
|
||||
|
||||
sealed interface RoomNotificationSettingsState {
|
||||
data object Unknown : RoomNotificationSettingsState
|
||||
data class Pending(val prevRoomNotificationSettings: RoomNotificationSettings? = null) : RoomNotificationSettingsState
|
||||
data class Error(val failure: Throwable, val prevRoomNotificationSettings: RoomNotificationSettings? = null) : RoomNotificationSettingsState
|
||||
data class Ready(val roomNotificationSettings: RoomNotificationSettings) : RoomNotificationSettingsState
|
||||
}
|
||||
|
||||
fun RoomNotificationSettingsState.roomNotificationSettings(): RoomNotificationSettings? {
|
||||
return when (this) {
|
||||
is RoomNotificationSettingsState.Ready -> roomNotificationSettings
|
||||
is RoomNotificationSettingsState.Pending -> prevRoomNotificationSettings
|
||||
is RoomNotificationSettingsState.Error -> prevRoomNotificationSettings
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
@ -8,12 +8,12 @@
|
|||
package io.element.android.libraries.matrix.api.room.alias
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
|
||||
/**
|
||||
* Return true if the given roomIdOrAlias is the same room as this room.
|
||||
*/
|
||||
fun MatrixRoom.matches(roomIdOrAlias: RoomIdOrAlias): Boolean {
|
||||
fun BaseRoom.matches(roomIdOrAlias: RoomIdOrAlias): Boolean {
|
||||
return when (roomIdOrAlias) {
|
||||
is RoomIdOrAlias.Id -> {
|
||||
roomIdOrAlias.roomId == roomId
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
package io.element.android.libraries.matrix.api.room.powerlevels
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.activeRoomMembers
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.map
|
|||
/**
|
||||
* Return a flow of the list of active room members who have the given role.
|
||||
*/
|
||||
fun MatrixRoom.usersWithRole(role: RoomMember.Role): Flow<ImmutableList<RoomMember>> {
|
||||
fun BaseRoom.usersWithRole(role: RoomMember.Role): Flow<ImmutableList<RoomMember>> {
|
||||
return roomInfoFlow
|
||||
.map { it.userPowerLevels.filter { (_, powerLevel) -> RoomMember.Role.forPowerLevel(powerLevel) == role } }
|
||||
.combine(membersStateFlow) { powerLevels, membersState ->
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 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.room.powerlevels
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
|
||||
data class MatrixRoomPowerLevels(
|
||||
val ban: Long,
|
||||
val invite: Long,
|
||||
val kick: Long,
|
||||
val sendEvents: Long,
|
||||
val redactEvents: Long,
|
||||
val roomName: Long,
|
||||
val roomAvatar: Long,
|
||||
val roomTopic: Long,
|
||||
)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [MatrixRoom.canUserInvite] with our own user.
|
||||
*/
|
||||
suspend fun MatrixRoom.canInvite(): Result<Boolean> = canUserInvite(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [MatrixRoom.canUserKick] with our own user.
|
||||
*/
|
||||
suspend fun MatrixRoom.canKick(): Result<Boolean> = canUserKick(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [MatrixRoom.canUserBan] with our own user.
|
||||
*/
|
||||
suspend fun MatrixRoom.canBan(): Result<Boolean> = canUserBan(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [MatrixRoom.canUserSendState] with our own user.
|
||||
*/
|
||||
suspend fun MatrixRoom.canSendState(type: StateEventType): Result<Boolean> = canUserSendState(sessionId, type)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [MatrixRoom.canUserSendMessage] with our own user.
|
||||
*/
|
||||
suspend fun MatrixRoom.canSendMessage(type: MessageEventType): Result<Boolean> = canUserSendMessage(sessionId, type)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [MatrixRoom.canUserRedactOwn] with our own user.
|
||||
*/
|
||||
suspend fun MatrixRoom.canRedactOwn(): Result<Boolean> = canUserRedactOwn(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [MatrixRoom.canRedactOther] with our own user.
|
||||
*/
|
||||
suspend fun MatrixRoom.canRedactOther(): Result<Boolean> = canUserRedactOther(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for checking if current user can handle knock requests.
|
||||
*/
|
||||
suspend fun MatrixRoom.canHandleKnockRequests(): Result<Boolean> = runCatching {
|
||||
canInvite().getOrThrow() || canBan().getOrThrow() || canKick().getOrThrow()
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for calling [MatrixRoom.canUserPinUnpin] with our own user.
|
||||
*/
|
||||
suspend fun MatrixRoom.canPinUnpin(): Result<Boolean> = canUserPinUnpin(sessionId)
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 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.room.powerlevels
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
|
||||
data class RoomPowerLevels(
|
||||
val ban: Long,
|
||||
val invite: Long,
|
||||
val kick: Long,
|
||||
val sendEvents: Long,
|
||||
val redactEvents: Long,
|
||||
val roomName: Long,
|
||||
val roomAvatar: Long,
|
||||
val roomTopic: Long,
|
||||
)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserInvite] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canInvite(): Result<Boolean> = canUserInvite(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserKick] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canKick(): Result<Boolean> = canUserKick(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserBan] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canBan(): Result<Boolean> = canUserBan(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserSendState] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canSendState(type: StateEventType): Result<Boolean> = canUserSendState(sessionId, type)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserSendMessage] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canSendMessage(type: MessageEventType): Result<Boolean> = canUserSendMessage(sessionId, type)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserRedactOwn] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canRedactOwn(): Result<Boolean> = canUserRedactOwn(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canRedactOther] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canRedactOther(): Result<Boolean> = canUserRedactOther(sessionId)
|
||||
|
||||
/**
|
||||
* Shortcut for checking if current user can handle knock requests.
|
||||
*/
|
||||
suspend fun BaseRoom.canHandleKnockRequests(): Result<Boolean> = runCatching {
|
||||
canInvite().getOrThrow() || canBan().getOrThrow() || canKick().getOrThrow()
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for calling [BaseRoom.canUserPinUnpin] with our own user.
|
||||
*/
|
||||
suspend fun BaseRoom.canPinUnpin(): Result<Boolean> = canUserPinUnpin(sessionId)
|
||||
|
|
@ -10,8 +10,8 @@ package io.element.android.libraries.matrix.api.room.recent
|
|||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.isDm
|
||||
import io.element.android.libraries.matrix.api.room.toMatrixUser
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
|
|
@ -52,6 +52,6 @@ suspend fun MatrixClient.getRecentDirectRooms(
|
|||
return result
|
||||
}
|
||||
|
||||
suspend fun MatrixRoom.isJoined(): Boolean {
|
||||
suspend fun BaseRoom.isJoined(): Boolean {
|
||||
return roomInfoFlow.first().currentUserMembership == CurrentUserMembership.JOINED
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
package io.element.android.libraries.matrix.api.roomlist
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.message.RoomMessage
|
||||
|
||||
data class RoomSummary(
|
||||
val info: MatrixRoomInfo,
|
||||
val info: RoomInfo,
|
||||
val lastMessage: RoomMessage?,
|
||||
) {
|
||||
val roomId = info.id
|
||||
|
|
|
|||
|
|
@ -30,11 +30,12 @@ import io.element.android.libraries.matrix.api.notification.NotificationService
|
|||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
||||
import io.element.android.libraries.matrix.api.pusher.PushersService
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.NotJoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.RoomPreview
|
||||
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
||||
|
|
@ -55,13 +56,15 @@ import io.element.android.libraries.matrix.impl.notification.RustNotificationSer
|
|||
import io.element.android.libraries.matrix.impl.notificationsettings.RustNotificationSettingsService
|
||||
import io.element.android.libraries.matrix.impl.oidc.toRustAction
|
||||
import io.element.android.libraries.matrix.impl.pushers.RustPushersService
|
||||
import io.element.android.libraries.matrix.impl.room.GetRoomResult
|
||||
import io.element.android.libraries.matrix.impl.room.NotJoinedRustRoom
|
||||
import io.element.android.libraries.matrix.impl.room.RoomContentForwarder
|
||||
import io.element.android.libraries.matrix.impl.room.RoomSyncSubscriber
|
||||
import io.element.android.libraries.matrix.impl.room.RustRoomFactory
|
||||
import io.element.android.libraries.matrix.impl.room.RustRoomPreview
|
||||
import io.element.android.libraries.matrix.impl.room.TimelineEventTypeFilterFactory
|
||||
import io.element.android.libraries.matrix.impl.room.history.map
|
||||
import io.element.android.libraries.matrix.impl.room.join.map
|
||||
import io.element.android.libraries.matrix.impl.room.preview.RoomPreviewInfoMapper
|
||||
import io.element.android.libraries.matrix.impl.roomdirectory.RustRoomDirectoryService
|
||||
import io.element.android.libraries.matrix.impl.roomdirectory.map
|
||||
import io.element.android.libraries.matrix.impl.roomlist.RoomListFactory
|
||||
|
|
@ -186,6 +189,7 @@ class RustMatrixClient(
|
|||
|
||||
private val roomMembershipObserver = RoomMembershipObserver()
|
||||
private val roomFactory = RustRoomFactory(
|
||||
innerClient = innerClient,
|
||||
roomListService = roomListService,
|
||||
innerRoomListService = innerRoomListService,
|
||||
sessionId = sessionId,
|
||||
|
|
@ -263,12 +267,17 @@ class RustMatrixClient(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun getRoom(roomId: RoomId): MatrixRoom? {
|
||||
return roomFactory.create(roomId)
|
||||
override suspend fun getRoom(roomId: RoomId): BaseRoom? {
|
||||
return roomFactory.getBaseRoom(roomId)
|
||||
}
|
||||
|
||||
override suspend fun getPendingRoom(roomId: RoomId): RoomPreview? {
|
||||
return roomFactory.createRoomPreview(roomId)
|
||||
override suspend fun getJoinedRoom(roomId: RoomId): JoinedRoom? {
|
||||
return try {
|
||||
(roomFactory.getJoinedRoomOrPreview(roomId) as GetRoomResult.Joined).joinedRoom
|
||||
} catch (e: ClassCastException) {
|
||||
Timber.e(e, "Room $roomId is not a joined room")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -455,13 +464,29 @@ class RustMatrixClient(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreview> = withContext(sessionDispatcher) {
|
||||
override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<NotJoinedRoom> = withContext(sessionDispatcher) {
|
||||
runCatching {
|
||||
val roomPreview = when (roomIdOrAlias) {
|
||||
is RoomIdOrAlias.Alias -> innerClient.getRoomPreviewFromRoomAlias(roomIdOrAlias.roomAlias.value)
|
||||
is RoomIdOrAlias.Id -> innerClient.getRoomPreviewFromRoomId(roomIdOrAlias.roomId.value, serverNames)
|
||||
when (roomIdOrAlias) {
|
||||
is RoomIdOrAlias.Alias -> {
|
||||
val roomId = innerClient.resolveRoomAlias(roomIdOrAlias.roomAlias.value)?.roomId?.let { RoomId(it) }
|
||||
|
||||
var room = (roomId?.let { roomFactory.getJoinedRoomOrPreview(it) } as? GetRoomResult.NotJoined)?.notJoinedRoom
|
||||
if (room == null) {
|
||||
val preview = innerClient.getRoomPreviewFromRoomAlias(roomIdOrAlias.roomAlias.value)
|
||||
room = NotJoinedRustRoom(sessionId, null, RoomPreviewInfoMapper.map(preview.info()))
|
||||
}
|
||||
room
|
||||
}
|
||||
is RoomIdOrAlias.Id -> {
|
||||
var room = (roomFactory.getJoinedRoomOrPreview(roomIdOrAlias.roomId) as? GetRoomResult.NotJoined)?.notJoinedRoom
|
||||
|
||||
if (room == null) {
|
||||
val preview = innerClient.getRoomPreviewFromRoomId(roomIdOrAlias.roomId.value, serverNames)
|
||||
room = NotJoinedRustRoom(sessionId, null, RoomPreviewInfoMapper.map(preview.info()))
|
||||
}
|
||||
room
|
||||
}
|
||||
}
|
||||
RustRoomPreview(sessionId, roomPreview, roomMembershipObserver)
|
||||
}.mapFailure { it.mapClientException() }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
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.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.isDm
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ private fun Long.toAnalyticsRoomSize(): JoinedRoom.RoomSize {
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun MatrixRoom.toAnalyticsJoinedRoom(trigger: JoinedRoom.Trigger?): JoinedRoom {
|
||||
suspend fun BaseRoom.toAnalyticsJoinedRoom(trigger: JoinedRoom.Trigger?): JoinedRoom {
|
||||
val roomInfo = roomInfoFlow.first()
|
||||
return JoinedRoom(
|
||||
isDM = roomInfo.isDm,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
* 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.
|
||||
|
|
@ -17,7 +17,6 @@ import io.element.android.libraries.matrix.api.core.ProgressCallback
|
|||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SendHandle
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.TransactionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange
|
||||
|
|
@ -28,55 +27,43 @@ import io.element.android.libraries.matrix.api.media.MediaUploadHandler
|
|||
import io.element.android.libraries.matrix.api.media.VideoInfo
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.CreateTimelineParams
|
||||
import io.element.android.libraries.matrix.api.room.IntentionalMention
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomNotificationSettingsState
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationSettingsState
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.room.knock.KnockRequest
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.room.message.ReplyParameters
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
|
||||
import io.element.android.libraries.matrix.api.room.roomNotificationSettings
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
|
||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
|
||||
import io.element.android.libraries.matrix.impl.core.RustSendHandle
|
||||
import io.element.android.libraries.matrix.impl.mapper.map
|
||||
import io.element.android.libraries.matrix.impl.room.draft.into
|
||||
import io.element.android.libraries.matrix.impl.room.history.map
|
||||
import io.element.android.libraries.matrix.impl.room.join.map
|
||||
import io.element.android.libraries.matrix.impl.room.knock.RustKnockRequest
|
||||
import io.element.android.libraries.matrix.impl.room.member.RoomMemberListFetcher
|
||||
import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper
|
||||
import io.element.android.libraries.matrix.impl.room.powerlevels.RoomPowerLevelsMapper
|
||||
import io.element.android.libraries.matrix.impl.roomdirectory.map
|
||||
import io.element.android.libraries.matrix.impl.timeline.RustTimeline
|
||||
import io.element.android.libraries.matrix.impl.timeline.toRustReceiptType
|
||||
import io.element.android.libraries.matrix.impl.util.MessageEventContent
|
||||
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
|
||||
import io.element.android.libraries.matrix.impl.widget.RustWidgetDriver
|
||||
import io.element.android.libraries.matrix.impl.widget.generateWidgetWebViewUrl
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
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
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.drop
|
||||
|
|
@ -89,7 +76,6 @@ 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.RoomMessageEventMessageType
|
||||
import org.matrix.rustcomponents.sdk.TimelineConfiguration
|
||||
|
|
@ -103,40 +89,36 @@ 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
|
||||
import org.matrix.rustcomponents.sdk.KnockRequest as InnerKnockRequest
|
||||
import org.matrix.rustcomponents.sdk.Room as InnerRoom
|
||||
import org.matrix.rustcomponents.sdk.RoomInfo as InnerRoomInfo
|
||||
import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline
|
||||
|
||||
@Suppress("LargeClass")
|
||||
class RustMatrixRoom(
|
||||
override val sessionId: SessionId,
|
||||
private val deviceId: DeviceId,
|
||||
private val innerRoom: InnerRoom,
|
||||
innerTimeline: InnerTimeline,
|
||||
class JoinedRustRoom(
|
||||
private val baseRoom: RustBaseRoom,
|
||||
private val liveInnerTimeline: InnerTimeline,
|
||||
private val notificationSettingsService: NotificationSettingsService,
|
||||
sessionCoroutineScope: CoroutineScope,
|
||||
private val coroutineDispatchers: CoroutineDispatchers,
|
||||
private val roomInfoMapper: RoomInfoMapper,
|
||||
private val systemClock: SystemClock,
|
||||
private val roomContentForwarder: RoomContentForwarder,
|
||||
private val roomSyncSubscriber: RoomSyncSubscriber,
|
||||
private val matrixRoomInfoMapper: MatrixRoomInfoMapper,
|
||||
private val featureFlagService: FeatureFlagService,
|
||||
private val roomMembershipObserver: RoomMembershipObserver,
|
||||
initialRoomInfo: MatrixRoomInfo,
|
||||
) : MatrixRoom {
|
||||
override val roomId = RoomId(innerRoom.id())
|
||||
) : JoinedRoom, BaseRoom by baseRoom {
|
||||
// Create a dispatcher for all room methods...
|
||||
private val roomDispatcher = coroutineDispatchers.io.limitedParallelism(32)
|
||||
private val innerRoom = baseRoom.innerRoom
|
||||
|
||||
override val roomInfoFlow: StateFlow<MatrixRoomInfo> = mxCallbackFlow {
|
||||
override val syncUpdateFlow = MutableStateFlow(0L)
|
||||
|
||||
override val roomInfoFlow: StateFlow<io.element.android.libraries.matrix.api.room.RoomInfo> = mxCallbackFlow {
|
||||
innerRoom.subscribeToRoomInfoUpdates(object : RoomInfoListener {
|
||||
override fun call(roomInfo: RoomInfo) {
|
||||
channel.trySend(matrixRoomInfoMapper.map(roomInfo))
|
||||
override fun call(roomInfo: InnerRoomInfo) {
|
||||
channel.trySend(roomInfoMapper.map(roomInfo))
|
||||
}
|
||||
})
|
||||
}.stateIn(sessionCoroutineScope, started = SharingStarted.Lazily, initialValue = initialRoomInfo)
|
||||
}.stateIn(roomCoroutineScope, started = SharingStarted.Lazily, initialValue = baseRoom.info())
|
||||
|
||||
override val roomTypingMembersFlow: Flow<List<UserId>> = mxCallbackFlow {
|
||||
val initial = emptyList<UserId>()
|
||||
|
|
@ -178,27 +160,12 @@ class RustMatrixRoom(
|
|||
})
|
||||
}
|
||||
|
||||
// Create a dispatcher for all room methods...
|
||||
private val roomDispatcher = coroutineDispatchers.io.limitedParallelism(32)
|
||||
override val roomNotificationSettingsStateFlow = MutableStateFlow<RoomNotificationSettingsState>(RoomNotificationSettingsState.Unknown)
|
||||
|
||||
// ...except getMember methods as it could quickly fill the roomDispatcher...
|
||||
private val roomMembersDispatcher = coroutineDispatchers.io.limitedParallelism(8)
|
||||
|
||||
override val roomCoroutineScope = sessionCoroutineScope.childScope(coroutineDispatchers.main, "RoomScope-$roomId")
|
||||
private val _syncUpdateFlow = MutableStateFlow(0L)
|
||||
private val roomMemberListFetcher = RoomMemberListFetcher(innerRoom, roomMembersDispatcher)
|
||||
|
||||
private val _roomNotificationSettingsStateFlow = MutableStateFlow<MatrixRoomNotificationSettingsState>(MatrixRoomNotificationSettingsState.Unknown)
|
||||
override val roomNotificationSettingsStateFlow: StateFlow<MatrixRoomNotificationSettingsState> = _roomNotificationSettingsStateFlow
|
||||
|
||||
override val liveTimeline = createTimeline(innerTimeline, mode = Timeline.Mode.LIVE) {
|
||||
_syncUpdateFlow.value = systemClock.epochMillis()
|
||||
override val liveTimeline = liveInnerTimeline.map(mode = Timeline.Mode.LIVE) {
|
||||
syncUpdateFlow.value = systemClock.epochMillis()
|
||||
}
|
||||
|
||||
override val membersStateFlow: StateFlow<MatrixRoomMembersState> = roomMemberListFetcher.membersFlow
|
||||
|
||||
override val syncUpdateFlow: StateFlow<Long> = _syncUpdateFlow.asStateFlow()
|
||||
|
||||
init {
|
||||
val powerLevelChanges = roomInfoFlow.map { it.userPowerLevels }.distinctUntilChanged()
|
||||
val membershipChanges = liveTimeline.membershipChangeEventReceived.onStart { emit(Unit) }
|
||||
|
|
@ -206,12 +173,13 @@ class RustMatrixRoom(
|
|||
// Skip initial one
|
||||
.drop(1)
|
||||
// The new events should already be in the SDK cache, no need to fetch them from the server
|
||||
.onEach { roomMemberListFetcher.fetchRoomMembers(source = RoomMemberListFetcher.Source.CACHE) }
|
||||
.onEach { baseRoom.roomMemberListFetcher.fetchRoomMembers(source = RoomMemberListFetcher.Source.CACHE) }
|
||||
.launchIn(roomCoroutineScope)
|
||||
.invokeOnCompletion {
|
||||
Timber.d("Observing membership changes for room $roomId stopped, reason: $it")
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun subscribeToSync() = roomSyncSubscriber.subscribe(roomId)
|
||||
|
||||
override suspend fun createTimeline(
|
||||
createTimelineParams: CreateTimelineParams,
|
||||
): Result<Timeline> = withContext(roomDispatcher) {
|
||||
|
|
@ -273,17 +241,14 @@ class RustMatrixRoom(
|
|||
dateDividerMode = dateDividerMode,
|
||||
trackReadReceipts = trackReadReceipts,
|
||||
)
|
||||
).let { inner ->
|
||||
).let { innerTimeline ->
|
||||
val mode = when (createTimelineParams) {
|
||||
is CreateTimelineParams.Focused -> Timeline.Mode.FOCUSED_ON_EVENT
|
||||
is CreateTimelineParams.MediaOnly -> Timeline.Mode.MEDIA
|
||||
is CreateTimelineParams.MediaOnlyFocused -> Timeline.Mode.FOCUSED_ON_EVENT
|
||||
CreateTimelineParams.PinnedOnly -> Timeline.Mode.PINNED_EVENTS
|
||||
}
|
||||
createTimeline(
|
||||
timeline = inner,
|
||||
mode = mode,
|
||||
)
|
||||
innerTimeline.map(mode = mode)
|
||||
}
|
||||
}.mapFailure {
|
||||
when (createTimelineParams) {
|
||||
|
|
@ -299,105 +264,8 @@ class RustMatrixRoom(
|
|||
}
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
roomCoroutineScope.cancel()
|
||||
liveTimeline.close()
|
||||
}
|
||||
|
||||
override suspend fun updateMembers() {
|
||||
val useCache = membersStateFlow.value is MatrixRoomMembersState.Unknown
|
||||
val source = if (useCache) {
|
||||
RoomMemberListFetcher.Source.CACHE_AND_SERVER
|
||||
} else {
|
||||
RoomMemberListFetcher.Source.SERVER
|
||||
}
|
||||
roomMemberListFetcher.fetchRoomMembers(source = source)
|
||||
}
|
||||
|
||||
override suspend fun getMembers(limit: Int) = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.members().use {
|
||||
it.nextChunk(limit.toUInt()).orEmpty().map { roomMember ->
|
||||
RoomMemberMapper.map(roomMember)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getUpdatedMember(userId: UserId): Result<RoomMember> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
RoomMemberMapper.map(innerRoom.member(userId.value))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun userDisplayName(userId: UserId): Result<String?> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.memberDisplayName(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateRoomNotificationSettings(): Result<Unit> = withContext(roomDispatcher) {
|
||||
val currentState = _roomNotificationSettingsStateFlow.value
|
||||
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)
|
||||
}.onFailure {
|
||||
_roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Error(
|
||||
prevRoomNotificationSettings = currentRoomNotificationSettings,
|
||||
failure = it
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun userRole(userId: UserId): Result<RoomMember.Role> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
RoomMemberMapper.mapRole(innerRoom.suggestedRoleForUser(userId.value))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateUsersRoles(changes: List<UserRoleChange>): Result<Unit> {
|
||||
return runCatching {
|
||||
val powerLevelChanges = changes.map { UserPowerLevelUpdate(it.userId.value, it.powerLevel) }
|
||||
innerRoom.updatePowerLevelsForUsers(powerLevelChanges)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun powerLevels(): Result<MatrixRoomPowerLevels> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
RoomPowerLevelsMapper.map(innerRoom.getPowerLevels())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updatePowerLevels(matrixRoomPowerLevels: MatrixRoomPowerLevels): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
val changes = RoomPowerLevelChanges(
|
||||
ban = matrixRoomPowerLevels.ban,
|
||||
invite = matrixRoomPowerLevels.invite,
|
||||
kick = matrixRoomPowerLevels.kick,
|
||||
redact = matrixRoomPowerLevels.redactEvents,
|
||||
eventsDefault = matrixRoomPowerLevels.sendEvents,
|
||||
roomName = matrixRoomPowerLevels.roomName,
|
||||
roomAvatar = matrixRoomPowerLevels.roomAvatar,
|
||||
roomTopic = matrixRoomPowerLevels.roomTopic,
|
||||
)
|
||||
innerRoom.applyPowerLevelChanges(changes)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun resetPowerLevels(): Result<MatrixRoomPowerLevels> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
RoomPowerLevelsMapper.map(innerRoom.resetPowerLevels())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun userAvatarUrl(userId: UserId): Result<String?> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.memberAvatarUrl(userId.value)
|
||||
}
|
||||
override suspend fun sendMessage(body: String, htmlBody: String?, intentionalMentions: List<IntentionalMention>): Result<Unit> {
|
||||
return liveTimeline.sendMessage(body, htmlBody, intentionalMentions)
|
||||
}
|
||||
|
||||
override suspend fun editMessage(
|
||||
|
|
@ -413,84 +281,6 @@ class RustMatrixRoom(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun sendMessage(body: String, htmlBody: String?, intentionalMentions: List<IntentionalMention>): Result<Unit> {
|
||||
return liveTimeline.sendMessage(body, htmlBody, intentionalMentions)
|
||||
}
|
||||
|
||||
override suspend fun leave(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.leave()
|
||||
}.onSuccess {
|
||||
roomMembershipObserver.notifyUserLeftRoom(roomId)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun join(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.join()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun inviteUserById(id: UserId): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.inviteUserById(id.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserInvite(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserInvite(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserKick(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserKick(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserBan(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserBan(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserRedactOwn(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserRedactOwn(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserRedactOther(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserRedactOther(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserSendState(userId: UserId, type: StateEventType): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserSendState(userId.value, type.map())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserSendMessage(userId.value, type.map())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserTriggerRoomNotification(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserTriggerRoomNotification(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserPinUnpin(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserPinUnpin(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun sendImage(
|
||||
file: File,
|
||||
thumbnailFile: File?,
|
||||
|
|
@ -593,93 +383,6 @@ class RustMatrixRoom(
|
|||
return liveTimeline.sendLocation(body, geoUri, description, zoomLevel, assetType)
|
||||
}
|
||||
|
||||
override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Unit> {
|
||||
return liveTimeline.toggleReaction(emoji, eventOrTransactionId)
|
||||
}
|
||||
|
||||
override suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit> {
|
||||
return liveTimeline.forwardEvent(eventId, roomIds)
|
||||
}
|
||||
|
||||
override suspend fun cancelSend(transactionId: TransactionId): Result<Unit> {
|
||||
return liveTimeline.cancelSend(transactionId)
|
||||
}
|
||||
|
||||
override suspend fun updateAvatar(mimeType: String, data: ByteArray): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.uploadAvatar(mimeType, data, null)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun removeAvatar(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.removeAvatar()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setName(name: String): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.setName(name)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setTopic(topic: String): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.setTopic(topic)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun reportContent(eventId: EventId, reason: String, blockUserId: UserId?): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.reportContent(eventId = eventId.value, score = null, reason = reason)
|
||||
if (blockUserId != null) {
|
||||
innerRoom.ignoreUser(blockUserId.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun clearEventCacheStorage(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.clearEventCacheStorage()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun kickUser(userId: UserId, reason: String?): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.kickUser(userId.value, reason)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun banUser(userId: UserId, reason: String?): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.banUser(userId.value, reason)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun unbanUser(userId: UserId, reason: String?): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.unbanUser(userId.value, reason)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setIsFavorite(isFavorite: Boolean): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.setIsFavourite(isFavorite, null)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun markAsRead(receiptType: ReceiptType): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.markAsRead(receiptType.toRustReceiptType())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setUnreadFlag(isUnread: Boolean): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.setUnreadFlag(isUnread)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun createPoll(
|
||||
question: String,
|
||||
answers: List<String>,
|
||||
|
|
@ -719,95 +422,70 @@ class RustMatrixRoom(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun generateWidgetWebViewUrl(
|
||||
widgetSettings: MatrixWidgetSettings,
|
||||
clientId: String,
|
||||
languageTag: String?,
|
||||
theme: String?,
|
||||
) = withContext(roomDispatcher) {
|
||||
override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Unit> {
|
||||
return liveTimeline.toggleReaction(emoji, eventOrTransactionId)
|
||||
}
|
||||
|
||||
override suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit> {
|
||||
return liveTimeline.forwardEvent(eventId, roomIds)
|
||||
}
|
||||
|
||||
override suspend fun cancelSend(transactionId: TransactionId): Result<Unit> {
|
||||
return liveTimeline.cancelSend(transactionId)
|
||||
}
|
||||
|
||||
override suspend fun inviteUserById(id: UserId): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
widgetSettings.generateWidgetWebViewUrl(innerRoom, clientId, languageTag, theme)
|
||||
innerRoom.inviteUserById(id.value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result<MatrixWidgetDriver> {
|
||||
return runCatching {
|
||||
RustWidgetDriver(
|
||||
widgetSettings = widgetSettings,
|
||||
room = innerRoom,
|
||||
widgetCapabilitiesProvider = object : WidgetCapabilitiesProvider {
|
||||
override fun acquireCapabilities(capabilities: WidgetCapabilities): WidgetCapabilities {
|
||||
return getElementCallRequiredPermissions(sessionId.value, deviceId.value)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getPermalink(): Result<String> = withContext(roomDispatcher) {
|
||||
override suspend fun updateAvatar(mimeType: String, data: ByteArray): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.matrixToPermalink()
|
||||
innerRoom.uploadAvatar(mimeType, data, null)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getPermalinkFor(eventId: EventId): Result<String> = withContext(roomDispatcher) {
|
||||
override suspend fun removeAvatar(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.matrixToEventPermalink(eventId.value)
|
||||
innerRoom.removeAvatar()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun sendCallNotificationIfNeeded(): Result<Unit> = withContext(roomDispatcher) {
|
||||
override suspend fun setName(name: String): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.sendCallNotificationIfNeeded()
|
||||
innerRoom.setName(name)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setSendQueueEnabled(enabled: Boolean) {
|
||||
withContext(roomDispatcher) {
|
||||
Timber.d("setSendQueuesEnabled: $enabled")
|
||||
runCatching {
|
||||
innerRoom.enableSendQueue(enabled)
|
||||
override suspend fun setTopic(topic: String): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.setTopic(topic)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun reportContent(eventId: EventId, reason: String, blockUserId: UserId?): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.reportContent(eventId = eventId.value, score = null, reason = reason)
|
||||
if (blockUserId != null) {
|
||||
innerRoom.ignoreUser(blockUserId.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun saveComposerDraft(composerDraft: ComposerDraft): Result<Unit> = withContext(roomDispatcher) {
|
||||
override suspend fun updateRoomNotificationSettings(): Result<Unit> = withContext(roomDispatcher) {
|
||||
val currentState = roomNotificationSettingsStateFlow.value
|
||||
val currentRoomNotificationSettings = currentState.roomNotificationSettings()
|
||||
roomNotificationSettingsStateFlow.value = RoomNotificationSettingsState.Pending(prevRoomNotificationSettings = currentRoomNotificationSettings)
|
||||
runCatching {
|
||||
Timber.d("saveComposerDraft: $composerDraft into $roomId")
|
||||
innerRoom.saveComposerDraft(composerDraft.into())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadComposerDraft(): Result<ComposerDraft?> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
Timber.d("loadComposerDraft for $roomId")
|
||||
innerRoom.loadComposerDraft()?.into()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun clearComposerDraft(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
Timber.d("clearComposerDraft for $roomId")
|
||||
innerRoom.clearComposerDraft()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun ignoreDeviceTrustAndResend(devices: Map<UserId, List<DeviceId>>, sendHandle: SendHandle) = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.ignoreDeviceTrustAndResend(
|
||||
devices = devices.entries.associate { entry ->
|
||||
entry.key.value to entry.value.map { it.value }
|
||||
},
|
||||
sendHandle = (sendHandle as RustSendHandle).inner,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun withdrawVerificationAndResend(userIds: List<UserId>, sendHandle: SendHandle) = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.withdrawVerificationAndResend(
|
||||
userIds = userIds.map { it.value },
|
||||
sendHandle = (sendHandle as RustSendHandle).inner,
|
||||
val isEncrypted = roomInfoFlow.value.isEncrypted ?: getUpdatedIsEncrypted().getOrThrow()
|
||||
notificationSettingsService.getRoomNotificationSettings(roomId, isEncrypted, isOneToOne).getOrThrow()
|
||||
}.map {
|
||||
roomNotificationSettingsStateFlow.value = RoomNotificationSettingsState.Ready(it)
|
||||
}.onFailure {
|
||||
roomNotificationSettingsStateFlow.value = RoomNotificationSettingsState.Error(
|
||||
prevRoomNotificationSettings = currentRoomNotificationSettings,
|
||||
failure = it
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -842,12 +520,6 @@ class RustMatrixRoom(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun getRoomVisibility(): Result<RoomVisibility> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.getRoomVisibility().map()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun enableEncryption(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.enableEncryption()
|
||||
|
|
@ -860,22 +532,128 @@ class RustMatrixRoom(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun getUpdatedIsEncrypted(): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.latestEncryptionState() == EncryptionState.ENCRYPTED
|
||||
override suspend fun updateUsersRoles(changes: List<UserRoleChange>): Result<Unit> {
|
||||
return runCatching {
|
||||
val powerLevelChanges = changes.map { UserPowerLevelUpdate(it.userId.value, it.powerLevel) }
|
||||
innerRoom.updatePowerLevelsForUsers(powerLevelChanges)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTimeline(
|
||||
timeline: InnerTimeline,
|
||||
override suspend fun updatePowerLevels(roomPowerLevels: RoomPowerLevels): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
val changes = RoomPowerLevelChanges(
|
||||
ban = roomPowerLevels.ban,
|
||||
invite = roomPowerLevels.invite,
|
||||
kick = roomPowerLevels.kick,
|
||||
redact = roomPowerLevels.redactEvents,
|
||||
eventsDefault = roomPowerLevels.sendEvents,
|
||||
roomName = roomPowerLevels.roomName,
|
||||
roomAvatar = roomPowerLevels.roomAvatar,
|
||||
roomTopic = roomPowerLevels.roomTopic,
|
||||
)
|
||||
innerRoom.applyPowerLevelChanges(changes)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun resetPowerLevels(): Result<RoomPowerLevels> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
RoomPowerLevelsMapper.map(innerRoom.resetPowerLevels())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun kickUser(userId: UserId, reason: String?): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.kickUser(userId.value, reason)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun banUser(userId: UserId, reason: String?): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.banUser(userId.value, reason)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun unbanUser(userId: UserId, reason: String?): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.unbanUser(userId.value, reason)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun generateWidgetWebViewUrl(
|
||||
widgetSettings: MatrixWidgetSettings,
|
||||
clientId: String,
|
||||
languageTag: String?,
|
||||
theme: String?,
|
||||
) = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
widgetSettings.generateWidgetWebViewUrl(innerRoom, clientId, languageTag, theme)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result<MatrixWidgetDriver> {
|
||||
return runCatching {
|
||||
RustWidgetDriver(
|
||||
widgetSettings = widgetSettings,
|
||||
room = innerRoom,
|
||||
widgetCapabilitiesProvider = object : WidgetCapabilitiesProvider {
|
||||
override fun acquireCapabilities(capabilities: WidgetCapabilities): WidgetCapabilities {
|
||||
return getElementCallRequiredPermissions(sessionId.value, baseRoom.deviceId.value)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun sendCallNotificationIfNeeded(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.sendCallNotificationIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setSendQueueEnabled(enabled: Boolean) {
|
||||
withContext(roomDispatcher) {
|
||||
Timber.d("setSendQueuesEnabled: $enabled")
|
||||
runCatching {
|
||||
innerRoom.enableSendQueue(enabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun ignoreDeviceTrustAndResend(devices: Map<UserId, List<DeviceId>>, sendHandle: SendHandle) = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.ignoreDeviceTrustAndResend(
|
||||
devices = devices.entries.associate { entry ->
|
||||
entry.key.value to entry.value.map { it.value }
|
||||
},
|
||||
sendHandle = (sendHandle as RustSendHandle).inner,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun withdrawVerificationAndResend(userIds: List<UserId>, sendHandle: SendHandle) = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.withdrawVerificationAndResend(
|
||||
userIds = userIds.map { it.value },
|
||||
sendHandle = (sendHandle as RustSendHandle).inner,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
baseRoom.destroy()
|
||||
liveInnerTimeline.close()
|
||||
roomCoroutineScope.cancel()
|
||||
}
|
||||
|
||||
private fun InnerTimeline.map(
|
||||
mode: Timeline.Mode,
|
||||
onNewSyncedEvent: () -> Unit = {},
|
||||
): Timeline {
|
||||
val timelineCoroutineScope = roomCoroutineScope.childScope(coroutineDispatchers.main, "TimelineScope-$roomId-$timeline")
|
||||
val timelineCoroutineScope = roomCoroutineScope.childScope(coroutineDispatchers.main, "TimelineScope-$roomId-$this")
|
||||
return RustTimeline(
|
||||
mode = mode,
|
||||
matrixRoom = this,
|
||||
inner = timeline,
|
||||
joinedRoom = this@JoinedRustRoom,
|
||||
inner = this@map,
|
||||
systemClock = systemClock,
|
||||
coroutineScope = timelineCoroutineScope,
|
||||
dispatcher = roomDispatcher,
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.room
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.room.NotJoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipDetails
|
||||
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
|
||||
import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper
|
||||
|
||||
@Immutable
|
||||
class NotJoinedRustRoom(
|
||||
private val sessionId: SessionId,
|
||||
override val localRoom: RustBaseRoom?,
|
||||
override val previewInfo: RoomPreviewInfo,
|
||||
) : NotJoinedRoom {
|
||||
override suspend fun membershipDetails(): Result<RoomMembershipDetails?> = runCatching {
|
||||
val room = localRoom?.innerRoom ?: return@runCatching null
|
||||
val (ownMember, senderInfo) = room.memberWithSenderInfo(sessionId.value)
|
||||
RoomMembershipDetails(
|
||||
currentUserMember = RoomMemberMapper.map(ownMember),
|
||||
senderMember = senderInfo?.let { RoomMemberMapper.map(it) },
|
||||
)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
localRoom?.close()
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
|
|||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.impl.room.history.map
|
||||
|
|
@ -28,9 +28,9 @@ import org.matrix.rustcomponents.sdk.Membership as RustMembership
|
|||
import org.matrix.rustcomponents.sdk.RoomInfo as RustRoomInfo
|
||||
import org.matrix.rustcomponents.sdk.RoomNotificationMode as RustRoomNotificationMode
|
||||
|
||||
class MatrixRoomInfoMapper {
|
||||
fun map(rustRoomInfo: RustRoomInfo): MatrixRoomInfo = rustRoomInfo.let {
|
||||
return MatrixRoomInfo(
|
||||
class RoomInfoMapper {
|
||||
fun map(rustRoomInfo: RustRoomInfo): RoomInfo = rustRoomInfo.let {
|
||||
return RoomInfo(
|
||||
id = RoomId(it.id),
|
||||
creator = it.creator?.let(::UserId),
|
||||
name = it.displayName,
|
||||
|
|
@ -70,44 +70,6 @@ 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) {
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.room
|
||||
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.core.coroutine.childScope
|
||||
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.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.impl.room.draft.into
|
||||
import io.element.android.libraries.matrix.impl.room.member.RoomMemberListFetcher
|
||||
import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper
|
||||
import io.element.android.libraries.matrix.impl.room.powerlevels.RoomPowerLevelsMapper
|
||||
import io.element.android.libraries.matrix.impl.roomdirectory.map
|
||||
import io.element.android.libraries.matrix.impl.timeline.toRustReceiptType
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.use
|
||||
import timber.log.Timber
|
||||
import uniffi.matrix_sdk_base.EncryptionState
|
||||
import org.matrix.rustcomponents.sdk.Room as InnerRoom
|
||||
|
||||
class RustBaseRoom(
|
||||
override val sessionId: SessionId,
|
||||
internal val deviceId: DeviceId,
|
||||
internal val innerRoom: InnerRoom,
|
||||
coroutineDispatchers: CoroutineDispatchers,
|
||||
private val roomSyncSubscriber: RoomSyncSubscriber,
|
||||
private val roomMembershipObserver: RoomMembershipObserver,
|
||||
sessionCoroutineScope: CoroutineScope,
|
||||
initialRoomInfo: RoomInfo,
|
||||
) : BaseRoom {
|
||||
override val roomId = RoomId(innerRoom.id())
|
||||
|
||||
// Create a dispatcher for all room methods...
|
||||
private val roomDispatcher = coroutineDispatchers.io.limitedParallelism(32)
|
||||
|
||||
// ...except getMember methods as it could quickly fill the roomDispatcher...
|
||||
private val roomMembersDispatcher = coroutineDispatchers.io.limitedParallelism(8)
|
||||
|
||||
internal val roomMemberListFetcher = RoomMemberListFetcher(innerRoom, roomMembersDispatcher)
|
||||
|
||||
override val membersStateFlow: StateFlow<RoomMembersState> = roomMemberListFetcher.membersFlow
|
||||
|
||||
override val roomInfoFlow: StateFlow<RoomInfo> = MutableStateFlow(initialRoomInfo)
|
||||
|
||||
override val roomCoroutineScope = sessionCoroutineScope.childScope(coroutineDispatchers.main, "RoomScope-$roomId")
|
||||
|
||||
override suspend fun subscribeToSync() = roomSyncSubscriber.subscribe(roomId)
|
||||
|
||||
override suspend fun updateMembers() {
|
||||
val useCache = membersStateFlow.value is RoomMembersState.Unknown
|
||||
val source = if (useCache) {
|
||||
RoomMemberListFetcher.Source.CACHE_AND_SERVER
|
||||
} else {
|
||||
RoomMemberListFetcher.Source.SERVER
|
||||
}
|
||||
roomMemberListFetcher.fetchRoomMembers(source = source)
|
||||
}
|
||||
|
||||
override suspend fun getMembers(limit: Int) = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.members().use {
|
||||
it.nextChunk(limit.toUInt()).orEmpty().map { roomMember ->
|
||||
RoomMemberMapper.map(roomMember)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getUpdatedMember(userId: UserId): Result<RoomMember> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
RoomMemberMapper.map(innerRoom.member(userId.value))
|
||||
}
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
innerRoom.destroy()
|
||||
}
|
||||
|
||||
override suspend fun userDisplayName(userId: UserId): Result<String?> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.memberDisplayName(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun userRole(userId: UserId): Result<RoomMember.Role> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
RoomMemberMapper.mapRole(innerRoom.suggestedRoleForUser(userId.value))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun powerLevels(): Result<RoomPowerLevels> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
RoomPowerLevelsMapper.map(innerRoom.getPowerLevels())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun userAvatarUrl(userId: UserId): Result<String?> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.memberAvatarUrl(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun leave(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.leave()
|
||||
}.onSuccess {
|
||||
roomMembershipObserver.notifyUserLeftRoom(roomId)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun join(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.join()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun forget(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.forget()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserInvite(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserInvite(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserKick(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserKick(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserBan(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserBan(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserRedactOwn(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserRedactOwn(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserRedactOther(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserRedactOther(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserSendState(userId: UserId, type: StateEventType): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserSendState(userId.value, type.map())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserSendMessage(userId.value, type.map())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserTriggerRoomNotification(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserTriggerRoomNotification(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun canUserPinUnpin(userId: UserId): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.canUserPinUnpin(userId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun clearEventCacheStorage(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.clearEventCacheStorage()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setIsFavorite(isFavorite: Boolean): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.setIsFavourite(isFavorite, null)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun markAsRead(receiptType: ReceiptType): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.markAsRead(receiptType.toRustReceiptType())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setUnreadFlag(isUnread: Boolean): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.setUnreadFlag(isUnread)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getPermalink(): Result<String> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.matrixToPermalink()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getPermalinkFor(eventId: EventId): Result<String> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.matrixToEventPermalink(eventId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getRoomVisibility(): Result<RoomVisibility> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.getRoomVisibility().map()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getUpdatedIsEncrypted(): Result<Boolean> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.latestEncryptionState() == EncryptionState.ENCRYPTED
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun saveComposerDraft(composerDraft: ComposerDraft): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
Timber.d("saveComposerDraft: $composerDraft into $roomId")
|
||||
innerRoom.saveComposerDraft(composerDraft.into())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadComposerDraft(): Result<ComposerDraft?> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
Timber.d("loadComposerDraft for $roomId")
|
||||
innerRoom.loadComposerDraft()?.into()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun clearComposerDraft(): Result<Unit> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
Timber.d("clearComposerDraft for $roomId")
|
||||
innerRoom.clearComposerDraft()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,20 +7,20 @@
|
|||
|
||||
package io.element.android.libraries.matrix.impl.room
|
||||
|
||||
import androidx.collection.lruCache
|
||||
import io.element.android.appconfig.TimelineConfig
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.core.data.tryOrNull
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.matrix.api.core.DeviceId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.RoomPreview
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.api.roomlist.awaitLoaded
|
||||
import io.element.android.libraries.matrix.impl.roomlist.fullRoomWithTimeline
|
||||
import io.element.android.libraries.matrix.impl.room.preview.RoomPreviewInfoMapper
|
||||
import io.element.android.libraries.matrix.impl.roomlist.roomOrNull
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
@ -28,17 +28,18 @@ import kotlinx.coroutines.NonCancellable
|
|||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.Room
|
||||
import org.matrix.rustcomponents.sdk.RoomListException
|
||||
import org.matrix.rustcomponents.sdk.Client
|
||||
import org.matrix.rustcomponents.sdk.Membership
|
||||
import org.matrix.rustcomponents.sdk.RoomListItem
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import org.matrix.rustcomponents.sdk.Room as SdkRoom
|
||||
import org.matrix.rustcomponents.sdk.RoomListService as InnerRoomListService
|
||||
|
||||
private const val CACHE_SIZE = 16
|
||||
|
||||
class RustRoomFactory(
|
||||
private val sessionId: SessionId,
|
||||
private val deviceId: DeviceId,
|
||||
private val innerClient: Client,
|
||||
private val notificationSettingsService: NotificationSettingsService,
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
|
|
@ -53,23 +54,14 @@ class RustRoomFactory(
|
|||
) {
|
||||
private val dispatcher = dispatchers.io.limitedParallelism(1)
|
||||
private val mutex = Mutex()
|
||||
private var isDestroyed: Boolean = false
|
||||
private val isDestroyed: AtomicBoolean = AtomicBoolean(false)
|
||||
|
||||
private data class RustRoomReferences(
|
||||
val roomListItem: RoomListItem,
|
||||
val fullRoom: Room,
|
||||
val room: SdkRoom,
|
||||
)
|
||||
|
||||
private val cache = lruCache<RoomId, RustRoomReferences>(
|
||||
maxSize = CACHE_SIZE,
|
||||
onEntryRemoved = { evicted, roomId, oldRoom, _ ->
|
||||
Timber.d("On room removed from cache: $roomId, evicted: $evicted")
|
||||
oldRoom.roomListItem.close()
|
||||
oldRoom.fullRoom.close()
|
||||
}
|
||||
)
|
||||
|
||||
private val matrixRoomInfoMapper = MatrixRoomInfoMapper()
|
||||
private val roomInfoMapper = RoomInfoMapper()
|
||||
|
||||
private val eventFilters = TimelineConfig.excludedEvents
|
||||
.takeIf { it.isNotEmpty() }
|
||||
|
|
@ -81,102 +73,123 @@ class RustRoomFactory(
|
|||
withContext(NonCancellable + dispatcher) {
|
||||
mutex.withLock {
|
||||
Timber.d("Destroying room factory")
|
||||
cache.snapshot().values.forEach { (listItem, innerRoom) ->
|
||||
innerRoom.destroy()
|
||||
listItem.destroy()
|
||||
}
|
||||
cache.evictAll()
|
||||
isDestroyed = true
|
||||
isDestroyed.set(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun create(roomId: RoomId): MatrixRoom? = withContext(dispatcher) {
|
||||
suspend fun getBaseRoom(roomId: RoomId): RustBaseRoom? = withContext(dispatcher) {
|
||||
mutex.withLock {
|
||||
if (isDestroyed) {
|
||||
if (isDestroyed.get()) {
|
||||
Timber.d("Room factory is destroyed, returning null for $roomId")
|
||||
return@withContext null
|
||||
}
|
||||
var roomReferences: RustRoomReferences? = getRoomReferences(roomId)
|
||||
if (roomReferences == null) {
|
||||
// ... otherwise, lets wait for the SS to load all rooms and check again.
|
||||
roomListService.allRooms.awaitLoaded()
|
||||
roomReferences = getRoomReferences(roomId)
|
||||
}
|
||||
if (roomReferences == null) {
|
||||
Timber.d("No room found for $roomId, returning null")
|
||||
return@withContext null
|
||||
}
|
||||
val liveTimeline = roomReferences.fullRoom.timeline()
|
||||
val initialRoomInfo = roomReferences.fullRoom.roomInfo()
|
||||
RustMatrixRoom(
|
||||
sessionId = sessionId,
|
||||
deviceId = deviceId,
|
||||
innerRoom = roomReferences.fullRoom,
|
||||
innerTimeline = liveTimeline,
|
||||
sessionCoroutineScope = sessionCoroutineScope,
|
||||
notificationSettingsService = notificationSettingsService,
|
||||
coroutineDispatchers = dispatchers,
|
||||
systemClock = systemClock,
|
||||
roomContentForwarder = roomContentForwarder,
|
||||
roomSyncSubscriber = roomSyncSubscriber,
|
||||
matrixRoomInfoMapper = matrixRoomInfoMapper,
|
||||
featureFlagService = featureFlagService,
|
||||
roomMembershipObserver = roomMembershipObserver,
|
||||
initialRoomInfo = matrixRoomInfoMapper.map(initialRoomInfo),
|
||||
)
|
||||
val roomReferences = awaitRoomReferences(roomId) ?: return@withContext null
|
||||
getBaseRoom(roomReferences)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun createRoomPreview(roomId: RoomId): RoomPreview? = withContext(dispatcher) {
|
||||
if (isDestroyed) {
|
||||
Timber.d("Room factory is destroyed, returning null for $roomId")
|
||||
return@withContext null
|
||||
}
|
||||
val roomListItem = innerRoomListService.roomOrNull(roomId.value)
|
||||
if (roomListItem == null) {
|
||||
Timber.d("Room not found for $roomId")
|
||||
return@withContext null
|
||||
}
|
||||
if (roomListItem.membership() !in RustRoomPreview.ALLOWED_MEMBERSHIPS) {
|
||||
Timber.d("Room $roomId is not in allowed membership")
|
||||
return@withContext null
|
||||
}
|
||||
val innerRoom = try {
|
||||
roomListItem.previewRoom(via = emptyList())
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Failed to get room preview for $roomId")
|
||||
return@withContext null
|
||||
}
|
||||
RustRoomPreview(
|
||||
private suspend fun getBaseRoom(roomReferences: RustRoomReferences): RustBaseRoom? {
|
||||
val initialRoomInfo = roomReferences.room.roomInfo()
|
||||
return RustBaseRoom(
|
||||
sessionId = sessionId,
|
||||
inner = innerRoom,
|
||||
deviceId = deviceId,
|
||||
innerRoom = roomReferences.room,
|
||||
coroutineDispatchers = dispatchers,
|
||||
roomSyncSubscriber = roomSyncSubscriber,
|
||||
roomMembershipObserver = roomMembershipObserver,
|
||||
initialRoomInfo = roomInfoMapper.map(initialRoomInfo),
|
||||
sessionCoroutineScope = sessionCoroutineScope,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun getRoomReferences(roomId: RoomId): RustRoomReferences? {
|
||||
cache[roomId]?.let {
|
||||
Timber.d("Room found in cache for $roomId")
|
||||
return it
|
||||
suspend fun getJoinedRoomOrPreview(roomId: RoomId): GetRoomResult? = withContext(dispatcher) {
|
||||
mutex.withLock {
|
||||
if (isDestroyed.get()) {
|
||||
Timber.d("Room factory is destroyed, returning null for $roomId")
|
||||
return@withContext null
|
||||
}
|
||||
val roomReferences = awaitRoomReferences(roomId) ?: return@withContext null
|
||||
|
||||
if (roomReferences.room.membership() == Membership.JOINED) {
|
||||
val baseRoom = getBaseRoom(roomReferences) ?: return@withContext null
|
||||
|
||||
// Init the live timeline in the SDK from the RoomListItem
|
||||
if (!roomReferences.roomListItem.isTimelineInitialized()) {
|
||||
roomReferences.roomListItem.initTimeline(eventFilters, "LIVE")
|
||||
}
|
||||
|
||||
GetRoomResult.Joined(
|
||||
JoinedRustRoom(
|
||||
baseRoom = baseRoom,
|
||||
notificationSettingsService = notificationSettingsService,
|
||||
roomContentForwarder = roomContentForwarder,
|
||||
liveInnerTimeline = roomReferences.room.timeline(),
|
||||
coroutineDispatchers = dispatchers,
|
||||
systemClock = systemClock,
|
||||
roomInfoMapper = roomInfoMapper,
|
||||
featureFlagService = featureFlagService,
|
||||
)
|
||||
)
|
||||
} else {
|
||||
val preview = try {
|
||||
roomReferences.roomListItem.previewRoom(via = emptyList())
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Failed to get room preview for $roomId")
|
||||
return@withContext null
|
||||
}
|
||||
|
||||
GetRoomResult.NotJoined(
|
||||
NotJoinedRustRoom(
|
||||
sessionId = sessionId,
|
||||
localRoom = getBaseRoom(roomReferences),
|
||||
previewInfo = RoomPreviewInfoMapper.map(preview.info()),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRoomReferences(roomId: RoomId): RustRoomReferences? {
|
||||
val roomListItem = innerRoomListService.roomOrNull(roomId.value)
|
||||
if (roomListItem == null) {
|
||||
Timber.d("Room not found for $roomId")
|
||||
return null
|
||||
}
|
||||
val fullRoom = try {
|
||||
roomListItem.fullRoomWithTimeline(filter = eventFilters)
|
||||
} catch (e: RoomListException) {
|
||||
Timber.e(e, "Failed to get full room with timeline for $roomId")
|
||||
return null
|
||||
}
|
||||
Timber.d("Got full room with timeline for $roomId")
|
||||
val room = tryOrNull {
|
||||
innerClient.getRoom(roomId.value)
|
||||
} ?: error("Failed to get room for room id: $roomId")
|
||||
|
||||
Timber.d("Got room for $roomId")
|
||||
return RustRoomReferences(
|
||||
roomListItem = roomListItem,
|
||||
fullRoom = fullRoom,
|
||||
).also {
|
||||
cache.put(roomId, it)
|
||||
room = room,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Rust room references for a room, retrying after the room list is loaded if necessary.
|
||||
*/
|
||||
private suspend fun awaitRoomReferences(roomId: RoomId): RustRoomReferences? {
|
||||
var roomReferences = getRoomReferences(roomId)
|
||||
|
||||
if (roomReferences == null) {
|
||||
// ... otherwise, lets wait for the SS to load all rooms and check again.
|
||||
roomListService.allRooms.awaitLoaded()
|
||||
roomReferences = getRoomReferences(roomId)
|
||||
}
|
||||
|
||||
return roomReferences
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface GetRoomResult {
|
||||
data class Joined(val joinedRoom: JoinedRoom) : GetRoomResult
|
||||
data class NotJoined(val notJoinedRoom: NotJoinedRustRoom) : GetRoomResult
|
||||
|
||||
val room: BaseRoom?
|
||||
get() = when (this) {
|
||||
is Joined -> joinedRoom
|
||||
is NotJoined -> notJoinedRoom.localRoom
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.room
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipDetails
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.RoomPreview
|
||||
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
|
||||
import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper
|
||||
import io.element.android.libraries.matrix.impl.room.preview.RoomPreviewInfoMapper
|
||||
import org.matrix.rustcomponents.sdk.Membership
|
||||
import org.matrix.rustcomponents.sdk.RoomPreview as InnerRoomPreview
|
||||
|
||||
@Immutable
|
||||
class RustRoomPreview(
|
||||
override val sessionId: SessionId,
|
||||
private val inner: InnerRoomPreview,
|
||||
private val roomMembershipObserver: RoomMembershipObserver?,
|
||||
) : RoomPreview {
|
||||
companion object {
|
||||
val ALLOWED_MEMBERSHIPS = setOf(Membership.INVITED, Membership.KNOCKED, Membership.BANNED)
|
||||
}
|
||||
|
||||
override val info: RoomPreviewInfo = RoomPreviewInfoMapper.map(inner.info())
|
||||
|
||||
override suspend fun leave(): Result<Unit> = runCatching {
|
||||
inner.leave()
|
||||
}.onSuccess {
|
||||
when (info.membership) {
|
||||
CurrentUserMembership.INVITED -> roomMembershipObserver?.notifyUserDeclinedInvite(info.roomId)
|
||||
CurrentUserMembership.KNOCKED -> roomMembershipObserver?.notifyUserCanceledKnock(info.roomId)
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun forget(): Result<Unit> = runCatching {
|
||||
inner.forget()
|
||||
}
|
||||
|
||||
override suspend fun membershipDetails(): Result<RoomMembershipDetails?> = runCatching {
|
||||
val details = inner.ownMembershipDetails() ?: return@runCatching null
|
||||
RoomMembershipDetails(
|
||||
currentUserMember = RoomMemberMapper.map(details.roomMember),
|
||||
senderMember = details.senderInfo?.let { RoomMemberMapper.map(it) },
|
||||
)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
inner.destroy()
|
||||
}
|
||||
}
|
||||
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
package io.element.android.libraries.matrix.impl.room.member
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||
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.roomMembers
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
@ -42,8 +42,8 @@ internal class RoomMemberListFetcher(
|
|||
private val updatedRoomMemberMutex = Mutex()
|
||||
private val roomId = room.id()
|
||||
|
||||
private val _membersFlow = MutableStateFlow<MatrixRoomMembersState>(MatrixRoomMembersState.Unknown)
|
||||
val membersFlow: StateFlow<MatrixRoomMembersState> = _membersFlow
|
||||
private val _membersFlow = MutableStateFlow<RoomMembersState>(RoomMembersState.Unknown)
|
||||
val membersFlow: StateFlow<RoomMembersState> = _membersFlow
|
||||
|
||||
/**
|
||||
* Fetches the room members for the given room.
|
||||
|
|
@ -75,16 +75,16 @@ internal class RoomMemberListFetcher(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun MutableStateFlow<MatrixRoomMembersState>.fetchCachedRoomMembers(asPendingState: Boolean = true) {
|
||||
private suspend fun MutableStateFlow<RoomMembersState>.fetchCachedRoomMembers(asPendingState: Boolean = true) {
|
||||
Timber.i("Loading cached members for room $roomId")
|
||||
try {
|
||||
// Send current member list with pending state to notify the UI that we are loading new members
|
||||
emit(pendingWithCurrentMembers())
|
||||
val members = parseAndEmitMembers(room.membersNoSync())
|
||||
val newState = if (asPendingState) {
|
||||
MatrixRoomMembersState.Pending(prevRoomMembers = members)
|
||||
RoomMembersState.Pending(prevRoomMembers = members)
|
||||
} else {
|
||||
MatrixRoomMembersState.Ready(members)
|
||||
RoomMembersState.Ready(members)
|
||||
}
|
||||
emit(newState)
|
||||
} catch (exception: CancellationException) {
|
||||
|
|
@ -92,22 +92,22 @@ internal class RoomMemberListFetcher(
|
|||
throw exception
|
||||
} catch (exception: Exception) {
|
||||
Timber.e(exception, "Failed to load cached members for room $roomId")
|
||||
emit(MatrixRoomMembersState.Error(exception, _membersFlow.value.roomMembers()?.toImmutableList()))
|
||||
emit(RoomMembersState.Error(exception, _membersFlow.value.roomMembers()?.toImmutableList()))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun MutableStateFlow<MatrixRoomMembersState>.fetchRemoteRoomMembers() {
|
||||
private suspend fun MutableStateFlow<RoomMembersState>.fetchRemoteRoomMembers() {
|
||||
try {
|
||||
// Send current member list with pending state to notify the UI that we are loading new members
|
||||
emit(pendingWithCurrentMembers())
|
||||
// Start loading new members
|
||||
emit(MatrixRoomMembersState.Ready(parseAndEmitMembers(room.members())))
|
||||
emit(RoomMembersState.Ready(parseAndEmitMembers(room.members())))
|
||||
} catch (exception: CancellationException) {
|
||||
Timber.d("Cancelled loading updated members for room $roomId")
|
||||
throw exception
|
||||
} catch (exception: Exception) {
|
||||
Timber.e(exception, "Failed to load updated members for room $roomId")
|
||||
emit(MatrixRoomMembersState.Error(exception, _membersFlow.value.roomMembers()?.toImmutableList()))
|
||||
emit(RoomMembersState.Error(exception, _membersFlow.value.roomMembers()?.toImmutableList()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -129,5 +129,5 @@ internal class RoomMemberListFetcher(
|
|||
}
|
||||
}
|
||||
|
||||
private fun pendingWithCurrentMembers() = MatrixRoomMembersState.Pending(_membersFlow.value.roomMembers().orEmpty().toImmutableList())
|
||||
private fun pendingWithCurrentMembers() = RoomMembersState.Pending(_membersFlow.value.roomMembers().orEmpty().toImmutableList())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@
|
|||
|
||||
package io.element.android.libraries.matrix.impl.room.powerlevels
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels
|
||||
import org.matrix.rustcomponents.sdk.RoomPowerLevels as RustRoomPowerLevels
|
||||
|
||||
object RoomPowerLevelsMapper {
|
||||
fun map(roomPowerLevels: RustRoomPowerLevels): MatrixRoomPowerLevels {
|
||||
return MatrixRoomPowerLevels(
|
||||
fun map(roomPowerLevels: RustRoomPowerLevels): RoomPowerLevels {
|
||||
return RoomPowerLevels(
|
||||
ban = roomPowerLevels.ban,
|
||||
invite = roomPowerLevels.invite,
|
||||
kick = roomPowerLevels.kick,
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@
|
|||
package io.element.android.libraries.matrix.impl.roomlist
|
||||
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import io.element.android.libraries.matrix.impl.room.MatrixRoomInfoMapper
|
||||
import io.element.android.libraries.matrix.impl.room.RoomInfoMapper
|
||||
import io.element.android.libraries.matrix.impl.room.message.RoomMessageFactory
|
||||
import org.matrix.rustcomponents.sdk.RoomListItem
|
||||
import org.matrix.rustcomponents.sdk.use
|
||||
|
||||
class RoomSummaryFactory(
|
||||
private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory(),
|
||||
private val roomInfoMapper: MatrixRoomInfoMapper = MatrixRoomInfoMapper(),
|
||||
private val roomInfoMapper: RoomInfoMapper = RoomInfoMapper(),
|
||||
) {
|
||||
suspend fun create(roomListItem: RoomListItem): RoomSummary {
|
||||
val roomInfo = roomListItem.roomInfo().let(roomInfoMapper::map)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import io.element.android.libraries.matrix.api.media.MediaUploadHandler
|
|||
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.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.isDm
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.room.message.ReplyParameters
|
||||
|
|
@ -86,7 +86,7 @@ class RustTimeline(
|
|||
private val inner: InnerTimeline,
|
||||
mode: Timeline.Mode,
|
||||
systemClock: SystemClock,
|
||||
private val matrixRoom: MatrixRoom,
|
||||
private val joinedRoom: JoinedRoom,
|
||||
private val coroutineScope: CoroutineScope,
|
||||
private val dispatcher: CoroutineDispatcher,
|
||||
private val roomContentForwarder: RoomContentForwarder,
|
||||
|
|
@ -137,7 +137,10 @@ class RustTimeline(
|
|||
)
|
||||
|
||||
init {
|
||||
coroutineScope.fetchMembers()
|
||||
if (mode != Timeline.Mode.PINNED_EVENTS) {
|
||||
coroutineScope.fetchMembers()
|
||||
}
|
||||
|
||||
if (mode == Timeline.Mode.LIVE) {
|
||||
// When timeline is live, we need to listen to the back pagination status as
|
||||
// sdk can automatically paginate backwards.
|
||||
|
|
@ -186,10 +189,10 @@ class RustTimeline(
|
|||
}
|
||||
}.onFailure { error ->
|
||||
if (error is TimelineException.CannotPaginate) {
|
||||
Timber.d("Can't paginate $direction on room ${matrixRoom.roomId} with paginationStatus: ${backwardPaginationStatus.value}")
|
||||
Timber.d("Can't paginate $direction on room ${joinedRoom.roomId} with paginationStatus: ${backwardPaginationStatus.value}")
|
||||
} else {
|
||||
updatePaginationStatus(direction) { it.copy(isPaginating = false) }
|
||||
Timber.e(error, "Error paginating $direction on room ${matrixRoom.roomId}")
|
||||
Timber.e(error, "Error paginating $direction on room ${joinedRoom.roomId}")
|
||||
}
|
||||
}.onSuccess { hasReachedEnd ->
|
||||
updatePaginationStatus(direction) { it.copy(isPaginating = false, hasMoreToLoad = !hasReachedEnd) }
|
||||
|
|
@ -209,7 +212,7 @@ class RustTimeline(
|
|||
_timelineItems,
|
||||
backwardPaginationStatus,
|
||||
forwardPaginationStatus,
|
||||
matrixRoom.roomInfoFlow.map { it.creator to it.isDm }.distinctUntilChanged(),
|
||||
joinedRoom.roomInfoFlow.map { it.creator to it.isDm }.distinctUntilChanged(),
|
||||
isTimelineInitialized,
|
||||
) { timelineItems,
|
||||
backwardPaginationStatus,
|
||||
|
|
@ -261,7 +264,7 @@ class RustTimeline(
|
|||
try {
|
||||
inner.fetchMembers()
|
||||
} catch (exception: Exception) {
|
||||
Timber.e(exception, "Error fetching members for room ${matrixRoom.roomId}")
|
||||
Timber.e(exception, "Error fetching members for room ${joinedRoom.roomId}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ 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.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
class JoinedRoomExtKtTest {
|
||||
class JoinedExtKtTest {
|
||||
@Test
|
||||
fun `test room size mapping`() = runTest {
|
||||
mapOf(
|
||||
|
|
@ -26,7 +26,7 @@ class JoinedRoomExtKtTest {
|
|||
listOf(1001L, 2000L) to JoinedRoom.RoomSize.MoreThanAThousand
|
||||
).forEach { (joinedMemberCounts, expectedRoomSize) ->
|
||||
joinedMemberCounts.forEach { joinedMemberCount ->
|
||||
assertThat(aMatrixRoom(joinedMemberCount = joinedMemberCount).toAnalyticsJoinedRoom(null))
|
||||
assertThat(aRoom(joinedMemberCount = joinedMemberCount).toAnalyticsJoinedRoom(null))
|
||||
.isEqualTo(
|
||||
JoinedRoom(
|
||||
isDM = false,
|
||||
|
|
@ -41,7 +41,7 @@ class JoinedRoomExtKtTest {
|
|||
|
||||
@Test
|
||||
fun `test isDirect parameter mapping`() = runTest {
|
||||
assertThat(aMatrixRoom(isDirect = true).toAnalyticsJoinedRoom(null))
|
||||
assertThat(aRoom(isDirect = true).toAnalyticsJoinedRoom(null))
|
||||
.isEqualTo(
|
||||
JoinedRoom(
|
||||
isDM = true,
|
||||
|
|
@ -54,7 +54,7 @@ class JoinedRoomExtKtTest {
|
|||
|
||||
@Test
|
||||
fun `test isSpace parameter mapping`() = runTest {
|
||||
assertThat(aMatrixRoom(isSpace = true).toAnalyticsJoinedRoom(null))
|
||||
assertThat(aRoom(isSpace = true).toAnalyticsJoinedRoom(null))
|
||||
.isEqualTo(
|
||||
JoinedRoom(
|
||||
isDM = false,
|
||||
|
|
@ -67,7 +67,7 @@ class JoinedRoomExtKtTest {
|
|||
|
||||
@Test
|
||||
fun `test trigger parameter mapping`() = runTest {
|
||||
assertThat(aMatrixRoom(isDirect = false, isSpace = false, joinedMemberCount = 1).toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite))
|
||||
assertThat(aRoom(isDirect = false, isSpace = false, joinedMemberCount = 1).toAnalyticsJoinedRoom(JoinedRoom.Trigger.Invite))
|
||||
.isEqualTo(
|
||||
JoinedRoom(
|
||||
isDM = false,
|
||||
|
|
@ -78,12 +78,12 @@ class JoinedRoomExtKtTest {
|
|||
)
|
||||
}
|
||||
|
||||
private fun aMatrixRoom(
|
||||
private fun aRoom(
|
||||
isDirect: Boolean = false,
|
||||
isSpace: Boolean = false,
|
||||
joinedMemberCount: Long = 0
|
||||
): FakeMatrixRoom {
|
||||
return FakeMatrixRoom().apply {
|
||||
): FakeBaseRoom {
|
||||
return FakeBaseRoom().apply {
|
||||
givenRoomInfo(aRoomInfo(isDirect = isDirect, isSpace = isSpace, joinedMembersCount = joinedMemberCount))
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ import io.element.android.libraries.matrix.api.core.EventId
|
|||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
|
|
@ -38,11 +38,11 @@ import org.matrix.rustcomponents.sdk.JoinRule as RustJoinRule
|
|||
import org.matrix.rustcomponents.sdk.RoomHistoryVisibility as RustRoomHistoryVisibility
|
||||
import org.matrix.rustcomponents.sdk.RoomNotificationMode as RustRoomNotificationMode
|
||||
|
||||
class MatrixRoomInfoMapperTest {
|
||||
class RoomInfoMapperTest {
|
||||
@Test
|
||||
fun `mapping of RustRoomInfo should map all the fields`() {
|
||||
assertThat(
|
||||
MatrixRoomInfoMapper().map(
|
||||
RoomInfoMapper().map(
|
||||
aRustRoomInfo(
|
||||
id = A_ROOM_ID.value,
|
||||
displayName = "displayName",
|
||||
|
|
@ -80,7 +80,7 @@ class MatrixRoomInfoMapperTest {
|
|||
)
|
||||
)
|
||||
).isEqualTo(
|
||||
MatrixRoomInfo(
|
||||
RoomInfo(
|
||||
id = A_ROOM_ID,
|
||||
name = "displayName",
|
||||
rawName = "rawName",
|
||||
|
|
@ -127,7 +127,7 @@ class MatrixRoomInfoMapperTest {
|
|||
@Test
|
||||
fun `mapping of RustRoomInfo with null members should map all the fields`() {
|
||||
assertThat(
|
||||
MatrixRoomInfoMapper().map(
|
||||
RoomInfoMapper().map(
|
||||
aRustRoomInfo(
|
||||
id = A_ROOM_ID.value,
|
||||
displayName = null,
|
||||
|
|
@ -164,7 +164,7 @@ class MatrixRoomInfoMapperTest {
|
|||
)
|
||||
)
|
||||
).isEqualTo(
|
||||
MatrixRoomInfo(
|
||||
RoomInfo(
|
||||
id = A_ROOM_ID,
|
||||
name = null,
|
||||
rawName = null,
|
||||
|
|
@ -18,7 +18,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ALIAS
|
|||
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.FakeBaseRoom
|
||||
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
|
||||
|
|
@ -33,7 +33,7 @@ class DefaultJoinRoomTest {
|
|||
val roomSummary = aRoomSummary()
|
||||
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) }
|
||||
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List<String> -> Result.success(roomSummary) }
|
||||
val roomResult = FakeMatrixRoom().apply {
|
||||
val roomResult = FakeBaseRoom().apply {
|
||||
givenRoomInfo(aRoomInfo())
|
||||
}
|
||||
val aTrigger = JoinedRoom.Trigger.MobilePermalink
|
||||
|
|
@ -70,7 +70,7 @@ class DefaultJoinRoomTest {
|
|||
val roomSummary = aRoomSummary()
|
||||
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) }
|
||||
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List<String> -> Result.success(roomSummary) }
|
||||
val roomResult = FakeMatrixRoom().apply {
|
||||
val roomResult = FakeBaseRoom().apply {
|
||||
givenRoomInfo(aRoomInfo())
|
||||
}
|
||||
val aTrigger = JoinedRoom.Trigger.MobilePermalink
|
||||
|
|
@ -108,7 +108,7 @@ class DefaultJoinRoomTest {
|
|||
val roomSummary = aRoomSummary()
|
||||
val joinRoomLambda = lambdaRecorder { _: RoomId -> Result.success(roomSummary) }
|
||||
val joinRoomByIdOrAliasLambda = lambdaRecorder { _: RoomIdOrAlias, _: List<String> -> Result.success(roomSummary) }
|
||||
val roomResult = FakeMatrixRoom().apply {
|
||||
val roomResult = FakeBaseRoom().apply {
|
||||
givenRoomInfo(aRoomInfo())
|
||||
}
|
||||
val aTrigger = JoinedRoom.Trigger.MobilePermalink
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ package io.element.android.libraries.matrix.impl.room.member
|
|||
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.roomMembers
|
||||
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustRoomMember
|
||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoom
|
||||
|
|
@ -40,16 +40,16 @@ class RoomMemberListFetcherTest {
|
|||
|
||||
val fetcher = RoomMemberListFetcher(room, Dispatchers.Default)
|
||||
fetcher.membersFlow.test {
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java)
|
||||
|
||||
fetcher.fetchRoomMembers(source = CACHE)
|
||||
|
||||
// Loading state
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Pending::class.java)
|
||||
|
||||
val cachedItemsState = awaitItem()
|
||||
assertThat(cachedItemsState).isInstanceOf(MatrixRoomMembersState.Ready::class.java)
|
||||
assertThat((cachedItemsState as? MatrixRoomMembersState.Ready)?.roomMembers).hasSize(3)
|
||||
assertThat(cachedItemsState).isInstanceOf(RoomMembersState.Ready::class.java)
|
||||
assertThat((cachedItemsState as? RoomMembersState.Ready)?.roomMembers).hasSize(3)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -62,9 +62,9 @@ class RoomMemberListFetcherTest {
|
|||
val fetcher = RoomMemberListFetcher(room, Dispatchers.Default)
|
||||
fetcher.membersFlow.test {
|
||||
fetcher.fetchRoomMembers(source = CACHE)
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java)
|
||||
assertThat((awaitItem() as? MatrixRoomMembersState.Ready)?.roomMembers).isEmpty()
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Pending::class.java)
|
||||
assertThat((awaitItem() as? RoomMembersState.Ready)?.roomMembers).isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,9 +77,9 @@ class RoomMemberListFetcherTest {
|
|||
val fetcher = RoomMemberListFetcher(room, Dispatchers.Default)
|
||||
fetcher.membersFlow.test {
|
||||
fetcher.fetchRoomMembers(source = CACHE)
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Error::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Pending::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Error::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -100,11 +100,11 @@ class RoomMemberListFetcherTest {
|
|||
fetcher.fetchRoomMembers(source = CACHE)
|
||||
|
||||
// Initial state
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java)
|
||||
// Started loading cached members
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Pending::class.java)
|
||||
// Finished loading cached members
|
||||
assertThat((awaitItem() as? MatrixRoomMembersState.Ready)?.roomMembers).hasSize(3)
|
||||
assertThat((awaitItem() as? RoomMembersState.Ready)?.roomMembers).hasSize(3)
|
||||
|
||||
ensureAllEventsConsumed()
|
||||
}
|
||||
|
|
@ -126,9 +126,9 @@ class RoomMemberListFetcherTest {
|
|||
fetcher.membersFlow.test {
|
||||
fetcher.fetchRoomMembers(source = SERVER)
|
||||
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java)
|
||||
assertThat((awaitItem() as? MatrixRoomMembersState.Ready)?.roomMembers?.size).isEqualTo(3)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Pending::class.java)
|
||||
assertThat((awaitItem() as? RoomMembersState.Ready)?.roomMembers?.size).isEqualTo(3)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,9 +140,9 @@ class RoomMemberListFetcherTest {
|
|||
fetcher.membersFlow.test {
|
||||
fetcher.fetchRoomMembers(source = SERVER)
|
||||
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Pending::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Error::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Pending::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Error::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -167,20 +167,20 @@ class RoomMemberListFetcherTest {
|
|||
fetcher.membersFlow.test {
|
||||
fetcher.fetchRoomMembers(source = CACHE_AND_SERVER)
|
||||
// Initial
|
||||
assertThat(awaitItem()).isInstanceOf(MatrixRoomMembersState.Unknown::class.java)
|
||||
assertThat(awaitItem()).isInstanceOf(RoomMembersState.Unknown::class.java)
|
||||
// Loading cached
|
||||
awaitItem().let { pending ->
|
||||
assertThat(pending).isInstanceOf(MatrixRoomMembersState.Pending::class.java)
|
||||
assertThat(pending).isInstanceOf(RoomMembersState.Pending::class.java)
|
||||
assertThat(pending.roomMembers()).isEmpty()
|
||||
}
|
||||
// Loaded cached
|
||||
awaitItem().let { cached ->
|
||||
assertThat(cached).isInstanceOf(MatrixRoomMembersState.Pending::class.java)
|
||||
assertThat(cached).isInstanceOf(RoomMembersState.Pending::class.java)
|
||||
assertThat(cached.roomMembers()).hasSize(1)
|
||||
}
|
||||
// Start loading new
|
||||
awaitItem().let { ready ->
|
||||
assertThat(ready).isInstanceOf(MatrixRoomMembersState.Ready::class.java)
|
||||
assertThat(ready).isInstanceOf(RoomMembersState.Ready::class.java)
|
||||
assertThat(ready.roomMembers()).hasSize(3)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
package io.element.android.libraries.matrix.impl.room.powerlevels
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels
|
||||
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustRoomPowerLevels
|
||||
import org.junit.Test
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ class RoomPowerLevelsMapperTest {
|
|||
)
|
||||
)
|
||||
).isEqualTo(
|
||||
MatrixRoomPowerLevels(
|
||||
RoomPowerLevels(
|
||||
ban = 1,
|
||||
invite = 2,
|
||||
kick = 3,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import org.matrix.rustcomponents.sdk.RoomDirectorySearch
|
|||
import org.matrix.rustcomponents.sdk.RoomDirectorySearchEntryUpdate
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class RustRoomDirectoryListTest {
|
||||
class RustBaseRoomDirectoryListTest {
|
||||
@Test
|
||||
fun `check that the state emits the expected values`() = runTest {
|
||||
val roomDirectorySearch = FakeRustRoomDirectorySearch()
|
||||
|
|
@ -12,7 +12,7 @@ import kotlinx.coroutines.test.StandardTestDispatcher
|
|||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
class RustRoomDirectoryServiceTest {
|
||||
class RustBaseRoomDirectoryServiceTest {
|
||||
@Test
|
||||
fun test() = runTest {
|
||||
val client = FakeRustClient()
|
||||
|
|
@ -23,7 +23,7 @@ import org.matrix.rustcomponents.sdk.RoomListServiceSyncIndicator
|
|||
import org.matrix.rustcomponents.sdk.RoomListService as RustRoomListService
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class RustRoomListServiceTest {
|
||||
class RustBaseRoomListServiceTest {
|
||||
@Test
|
||||
fun `syncIndicator should emit the expected values`() = runTest {
|
||||
val roomListService = FakeRustRoomListService()
|
||||
|
|
@ -12,7 +12,7 @@ import app.cash.turbine.test
|
|||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
|
||||
|
|
@ -20,7 +20,7 @@ import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoomListS
|
|||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustTimeline
|
||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustTimelineDiff
|
||||
import io.element.android.libraries.matrix.impl.room.RoomContentForwarder
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP
|
||||
|
|
@ -103,7 +103,7 @@ private fun TestScope.createRustTimeline(
|
|||
inner: InnerTimeline,
|
||||
mode: Timeline.Mode = Timeline.Mode.LIVE,
|
||||
systemClock: SystemClock = FakeSystemClock(),
|
||||
matrixRoom: MatrixRoom = FakeMatrixRoom().apply { givenRoomInfo(aRoomInfo()) },
|
||||
joinedRoom: JoinedRoom = FakeJoinedRoom().apply { givenRoomInfo(aRoomInfo()) },
|
||||
coroutineScope: CoroutineScope = backgroundScope,
|
||||
dispatcher: CoroutineDispatcher = testCoroutineDispatchers().io,
|
||||
roomContentForwarder: RoomContentForwarder = RoomContentForwarder(FakeRustRoomListService()),
|
||||
|
|
@ -114,7 +114,7 @@ private fun TestScope.createRustTimeline(
|
|||
inner = inner,
|
||||
mode = mode,
|
||||
systemClock = systemClock,
|
||||
matrixRoom = matrixRoom,
|
||||
joinedRoom = joinedRoom,
|
||||
coroutineScope = coroutineScope,
|
||||
dispatcher = dispatcher,
|
||||
roomContentForwarder = roomContentForwarder,
|
||||
|
|
|
|||
|
|
@ -22,9 +22,10 @@ import io.element.android.libraries.matrix.api.notification.NotificationService
|
|||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
||||
import io.element.android.libraries.matrix.api.pusher.PushersService
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.NotJoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.RoomPreview
|
||||
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
|
|
@ -77,7 +78,7 @@ class FakeMatrixClient(
|
|||
Optional.of(ResolvedRoomAlias(A_ROOM_ID, emptyList()))
|
||||
)
|
||||
},
|
||||
private val getRoomPreviewResult: (RoomIdOrAlias, List<String>) -> Result<RoomPreview> = { _, _ -> Result.failure(AN_EXCEPTION) },
|
||||
private val getNotJoinedRoomResult: (RoomIdOrAlias, List<String>) -> Result<NotJoinedRoom> = { _, _ -> Result.failure(AN_EXCEPTION) },
|
||||
private val clearCacheLambda: () -> Unit = { lambdaError() },
|
||||
private val userIdServerNameLambda: () -> String = { lambdaError() },
|
||||
private val getUrlLambda: (String) -> Result<String> = { lambdaError() },
|
||||
|
|
@ -102,7 +103,7 @@ class FakeMatrixClient(
|
|||
private var createRoomResult: Result<RoomId> = Result.success(A_ROOM_ID)
|
||||
private var createDmResult: Result<RoomId> = Result.success(A_ROOM_ID)
|
||||
private var findDmResult: RoomId? = A_ROOM_ID
|
||||
private val getRoomResults = mutableMapOf<RoomId, MatrixRoom>()
|
||||
private val getRoomResults = mutableMapOf<RoomId, BaseRoom>()
|
||||
private val searchUserResults = mutableMapOf<String, Result<MatrixSearchUserResults>>()
|
||||
private val getProfileResults = mutableMapOf<UserId, Result<MatrixUser>>()
|
||||
private var uploadMediaResult: Result<String> = Result.success(AN_AVATAR_URL)
|
||||
|
|
@ -123,12 +124,12 @@ class FakeMatrixClient(
|
|||
}
|
||||
var logoutLambda: (Boolean, Boolean) -> Unit = { _, _ -> }
|
||||
|
||||
override suspend fun getRoom(roomId: RoomId): MatrixRoom? {
|
||||
override suspend fun getRoom(roomId: RoomId): BaseRoom? {
|
||||
return getRoomResults[roomId]
|
||||
}
|
||||
|
||||
override suspend fun getPendingRoom(roomId: RoomId): RoomPreview? = simulateLongTask {
|
||||
getRoomPreviewResult(RoomIdOrAlias.Id(roomId), emptyList()).getOrNull()
|
||||
override suspend fun getJoinedRoom(roomId: RoomId): JoinedRoom? {
|
||||
return getRoomResults[roomId] as? JoinedRoom
|
||||
}
|
||||
|
||||
override suspend fun findDM(userId: UserId): RoomId? {
|
||||
|
|
@ -250,7 +251,7 @@ class FakeMatrixClient(
|
|||
findDmResult = result
|
||||
}
|
||||
|
||||
fun givenGetRoomResult(roomId: RoomId, result: MatrixRoom?) {
|
||||
fun givenGetRoomResult(roomId: RoomId, result: BaseRoom?) {
|
||||
if (result == null) {
|
||||
getRoomResults.remove(roomId)
|
||||
} else {
|
||||
|
|
@ -294,8 +295,8 @@ class FakeMatrixClient(
|
|||
resolveRoomAliasResult(roomAlias)
|
||||
}
|
||||
|
||||
override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreview> = simulateLongTask {
|
||||
getRoomPreviewResult(roomIdOrAlias, serverNames)
|
||||
override suspend fun getRoomPreview(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<NotJoinedRoom> = simulateLongTask {
|
||||
getNotJoinedRoomResult(roomIdOrAlias, serverNames)
|
||||
}
|
||||
|
||||
override suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>> {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 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.test.room
|
||||
|
||||
import io.element.android.libraries.core.bool.orFalse
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.simulateLongTask
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
|
||||
class FakeBaseRoom(
|
||||
override val sessionId: SessionId = A_SESSION_ID,
|
||||
override val roomId: RoomId = A_ROOM_ID,
|
||||
initialRoomInfo: RoomInfo = aRoomInfo(),
|
||||
override val roomCoroutineScope: CoroutineScope = TestScope(),
|
||||
private var roomPermalinkResult: () -> Result<String> = { lambdaError() },
|
||||
private var eventPermalinkResult: (EventId) -> Result<String> = { lambdaError() },
|
||||
private val userDisplayNameResult: (UserId) -> Result<String?> = { lambdaError() },
|
||||
private val userAvatarUrlResult: () -> Result<String?> = { lambdaError() },
|
||||
private val userRoleResult: () -> Result<RoomMember.Role> = { lambdaError() },
|
||||
private val getUpdatedMemberResult: (UserId) -> Result<RoomMember> = { lambdaError() },
|
||||
private val joinRoomResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val canInviteResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canKickResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canBanResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canRedactOwnResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canRedactOtherResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canSendStateResult: (UserId, StateEventType) -> Result<Boolean> = { _, _ -> lambdaError() },
|
||||
private val canUserSendMessageResult: (UserId, MessageEventType) -> Result<Boolean> = { _, _ -> lambdaError() },
|
||||
private val canUserTriggerRoomNotificationResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canUserJoinCallResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canUserPinUnpinResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val setIsFavoriteResult: (Boolean) -> Result<Unit> = { lambdaError() },
|
||||
private val powerLevelsResult: () -> Result<RoomPowerLevels> = { lambdaError() },
|
||||
private val leaveRoomLambda: () -> Result<Unit> = { lambdaError() },
|
||||
private val updateMembersResult: () -> Unit = { lambdaError() },
|
||||
private val getMembersResult: (Int) -> Result<List<RoomMember>> = { lambdaError() },
|
||||
private val saveComposerDraftLambda: (ComposerDraft) -> Result<Unit> = { _: ComposerDraft -> Result.success(Unit) },
|
||||
private val loadComposerDraftLambda: () -> Result<ComposerDraft?> = { Result.success<ComposerDraft?>(null) },
|
||||
private val clearComposerDraftLambda: () -> Result<Unit> = { Result.success(Unit) },
|
||||
private val subscribeToSyncLambda: () -> Unit = { lambdaError() },
|
||||
private val getRoomVisibilityResult: () -> Result<RoomVisibility> = { lambdaError() },
|
||||
private val forgetResult: () -> Result<Unit> = { lambdaError() },
|
||||
) : BaseRoom {
|
||||
private val _roomInfoFlow: MutableStateFlow<RoomInfo> = MutableStateFlow(initialRoomInfo)
|
||||
override val roomInfoFlow: StateFlow<RoomInfo> = _roomInfoFlow
|
||||
|
||||
fun givenRoomInfo(roomInfo: RoomInfo) {
|
||||
_roomInfoFlow.tryEmit(roomInfo)
|
||||
}
|
||||
|
||||
override val membersStateFlow: MutableStateFlow<RoomMembersState> = MutableStateFlow(RoomMembersState.Unknown)
|
||||
|
||||
override suspend fun updateMembers() = updateMembersResult()
|
||||
|
||||
override suspend fun getUpdatedMember(userId: UserId): Result<RoomMember> {
|
||||
return getUpdatedMemberResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun getMembers(limit: Int): Result<List<RoomMember>> {
|
||||
return getMembersResult(limit)
|
||||
}
|
||||
|
||||
override suspend fun subscribeToSync() {
|
||||
subscribeToSyncLambda()
|
||||
}
|
||||
|
||||
override suspend fun powerLevels(): Result<RoomPowerLevels> {
|
||||
return powerLevelsResult()
|
||||
}
|
||||
|
||||
override fun destroy() = Unit
|
||||
|
||||
override suspend fun userDisplayName(userId: UserId): Result<String?> = simulateLongTask {
|
||||
userDisplayNameResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun userAvatarUrl(userId: UserId): Result<String?> = simulateLongTask {
|
||||
userAvatarUrlResult()
|
||||
}
|
||||
|
||||
override suspend fun userRole(userId: UserId): Result<RoomMember.Role> {
|
||||
return userRoleResult()
|
||||
}
|
||||
|
||||
override suspend fun getPermalink(): Result<String> {
|
||||
return roomPermalinkResult()
|
||||
}
|
||||
|
||||
override suspend fun getPermalinkFor(eventId: EventId): Result<String> {
|
||||
return eventPermalinkResult(eventId)
|
||||
}
|
||||
|
||||
override suspend fun getRoomVisibility(): Result<RoomVisibility> = simulateLongTask {
|
||||
getRoomVisibilityResult()
|
||||
}
|
||||
|
||||
override suspend fun leave(): Result<Unit> = simulateLongTask {
|
||||
return leaveRoomLambda()
|
||||
}
|
||||
|
||||
override suspend fun join(): Result<Unit> {
|
||||
return joinRoomResult()
|
||||
}
|
||||
|
||||
override suspend fun forget(): Result<Unit> {
|
||||
return forgetResult()
|
||||
}
|
||||
|
||||
override suspend fun canUserBan(userId: UserId): Result<Boolean> {
|
||||
return canBanResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserKick(userId: UserId): Result<Boolean> {
|
||||
return canKickResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserInvite(userId: UserId): Result<Boolean> {
|
||||
return canInviteResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserRedactOwn(userId: UserId): Result<Boolean> {
|
||||
return canRedactOwnResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserRedactOther(userId: UserId): Result<Boolean> {
|
||||
return canRedactOtherResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserSendState(userId: UserId, type: StateEventType): Result<Boolean> {
|
||||
return canSendStateResult(userId, type)
|
||||
}
|
||||
|
||||
override suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result<Boolean> {
|
||||
return canUserSendMessageResult(userId, type)
|
||||
}
|
||||
|
||||
override suspend fun canUserTriggerRoomNotification(userId: UserId): Result<Boolean> {
|
||||
return canUserTriggerRoomNotificationResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserJoinCall(userId: UserId): Result<Boolean> {
|
||||
return canUserJoinCallResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserPinUnpin(userId: UserId): Result<Boolean> {
|
||||
return canUserPinUnpinResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun setIsFavorite(isFavorite: Boolean): Result<Unit> {
|
||||
return setIsFavoriteResult(isFavorite)
|
||||
}
|
||||
|
||||
val markAsReadCalls = mutableListOf<ReceiptType>()
|
||||
|
||||
override suspend fun markAsRead(receiptType: ReceiptType): Result<Unit> {
|
||||
markAsReadCalls.add(receiptType)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
var setUnreadFlagCalls = mutableListOf<Boolean>()
|
||||
private set
|
||||
|
||||
override suspend fun setUnreadFlag(isUnread: Boolean): Result<Unit> {
|
||||
setUnreadFlagCalls.add(isUnread)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun saveComposerDraft(composerDraft: ComposerDraft) = saveComposerDraftLambda(composerDraft)
|
||||
|
||||
override suspend fun loadComposerDraft() = loadComposerDraftLambda()
|
||||
|
||||
override suspend fun clearComposerDraft() = clearComposerDraftLambda()
|
||||
|
||||
override suspend fun getUpdatedIsEncrypted(): Result<Boolean> = simulateLongTask {
|
||||
Result.success(info().isEncrypted.orFalse())
|
||||
}
|
||||
|
||||
fun givenRoomMembersState(state: RoomMembersState) {
|
||||
membersStateFlow.value = state
|
||||
}
|
||||
|
||||
override suspend fun clearEventCacheStorage(): Result<Unit> {
|
||||
return Result.success(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun defaultRoomPowerLevels() = RoomPowerLevels(
|
||||
ban = 50,
|
||||
invite = 0,
|
||||
kick = 50,
|
||||
sendEvents = 0,
|
||||
redactEvents = 50,
|
||||
roomName = 100,
|
||||
roomAvatar = 100,
|
||||
roomTopic = 100
|
||||
)
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
* 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.
|
||||
|
|
@ -14,7 +14,6 @@ import io.element.android.libraries.matrix.api.core.ProgressCallback
|
|||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SendHandle
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.TransactionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.encryption.identity.IdentityStateChange
|
||||
|
|
@ -23,33 +22,26 @@ import io.element.android.libraries.matrix.api.media.FileInfo
|
|||
import io.element.android.libraries.matrix.api.media.ImageInfo
|
||||
import io.element.android.libraries.matrix.api.media.MediaUploadHandler
|
||||
import io.element.android.libraries.matrix.api.media.VideoInfo
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.CreateTimelineParams
|
||||
import io.element.android.libraries.matrix.api.room.IntentionalMention
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomNotificationSettingsState
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationSettingsState
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||
import io.element.android.libraries.matrix.api.room.knock.KnockRequest
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.room.message.ReplyParameters
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.MatrixRoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevels
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
|
||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver
|
||||
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler
|
||||
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
|
|
@ -58,36 +50,25 @@ import io.element.android.tests.testutils.simulateLongTask
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import java.io.File
|
||||
|
||||
class FakeMatrixRoom(
|
||||
override val sessionId: SessionId = A_SESSION_ID,
|
||||
override val roomId: RoomId = A_ROOM_ID,
|
||||
val notificationSettingsService: NotificationSettingsService = FakeNotificationSettingsService(),
|
||||
class FakeJoinedRoom(
|
||||
val baseRoom: FakeBaseRoom = FakeBaseRoom(),
|
||||
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() },
|
||||
private val sendCallNotificationIfNeededResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val userDisplayNameResult: (UserId) -> Result<String?> = { lambdaError() },
|
||||
private val userAvatarUrlResult: () -> Result<String?> = { lambdaError() },
|
||||
private val userRoleResult: () -> Result<RoomMember.Role> = { lambdaError() },
|
||||
private val getUpdatedMemberResult: (UserId) -> Result<RoomMember> = { lambdaError() },
|
||||
private val joinRoomResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val inviteUserResult: (UserId) -> Result<Unit> = { lambdaError() },
|
||||
private val canInviteResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canKickResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canBanResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canRedactOwnResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canRedactOtherResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canSendStateResult: (UserId, StateEventType) -> Result<Boolean> = { _, _ -> lambdaError() },
|
||||
private val canUserSendMessageResult: (UserId, MessageEventType) -> Result<Boolean> = { _, _ -> lambdaError() },
|
||||
override val syncUpdateFlow: StateFlow<Long> = MutableStateFlow(0),
|
||||
override val roomTypingMembersFlow: Flow<List<UserId>> = MutableStateFlow(emptyList()),
|
||||
override val identityStateChangesFlow: Flow<List<IdentityStateChange>> = MutableStateFlow(emptyList()),
|
||||
override val roomNotificationSettingsStateFlow: StateFlow<RoomNotificationSettingsState> =
|
||||
MutableStateFlow(RoomNotificationSettingsState.Unknown),
|
||||
override val knockRequestsFlow: Flow<List<KnockRequest>> = MutableStateFlow(emptyList()),
|
||||
private val roomNotificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
|
||||
private var createTimelineResult: (CreateTimelineParams) -> Result<Timeline> = { lambdaError() },
|
||||
private val sendMessageResult: (String, String?, List<IntentionalMention>) -> Result<Unit> = { _, _, _ -> lambdaError() },
|
||||
private val editMessageLambda: (EventId, String, String?, List<IntentionalMention>) -> Result<Unit> = { _, _, _, _ -> lambdaError() },
|
||||
private val sendImageResult: (File, File?, ImageInfo, String?, String?, ProgressCallback?, ReplyParameters?) -> Result<FakeMediaUploadHandler> =
|
||||
{ _, _, _, _, _, _, _ -> lambdaError() },
|
||||
private val sendVideoResult: (File, File?, VideoInfo, String?, String?, ProgressCallback?, ReplyParameters?) -> Result<FakeMediaUploadHandler> =
|
||||
|
|
@ -98,233 +79,65 @@ class FakeMatrixRoom(
|
|||
{ _, _, _, _, _, _ -> lambdaError() },
|
||||
private val sendVoiceMessageResult: (File, AudioInfo, List<Float>, ProgressCallback?, ReplyParameters?) -> Result<FakeMediaUploadHandler> =
|
||||
{ _, _, _, _, _ -> lambdaError() },
|
||||
private val setNameResult: (String) -> Result<Unit> = { lambdaError() },
|
||||
private val setTopicResult: (String) -> Result<Unit> = { lambdaError() },
|
||||
private val updateAvatarResult: (String, ByteArray) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val removeAvatarResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val editMessageLambda: (EventId, String, String?, List<IntentionalMention>) -> Result<Unit> = { _, _, _, _ -> lambdaError() },
|
||||
private val sendMessageResult: (String, String?, List<IntentionalMention>) -> Result<Unit> = { _, _, _ -> lambdaError() },
|
||||
private val updateUserRoleResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val toggleReactionResult: (String, EventOrTransactionId) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val cancelSendResult: (TransactionId) -> Result<Unit> = { lambdaError() },
|
||||
private val forwardEventResult: (EventId, List<RoomId>) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val reportContentResult: (EventId, String, UserId?) -> Result<Unit> = { _, _, _ -> lambdaError() },
|
||||
private val kickUserResult: (UserId, String?) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val banUserResult: (UserId, String?) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val unBanUserResult: (UserId, String?) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val sendLocationResult: (String, String, String?, Int?, AssetType?) -> Result<Unit> = { _, _, _, _, _ -> lambdaError() },
|
||||
private val sendCallNotificationIfNeededResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val progressCallbackValues: List<Pair<Long, Long>> = emptyList(),
|
||||
private val createPollResult: (String, List<String>, Int, PollKind) -> Result<Unit> = { _, _, _, _ -> lambdaError() },
|
||||
private val editPollResult: (EventId, String, List<String>, Int, PollKind) -> Result<Unit> = { _, _, _, _, _ -> lambdaError() },
|
||||
private val sendPollResponseResult: (EventId, List<String>) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val endPollResult: (EventId, String) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val progressCallbackValues: List<Pair<Long, Long>> = emptyList(),
|
||||
private val generateWidgetWebViewUrlResult: (MatrixWidgetSettings, String, String?, String?) -> Result<String> = { _, _, _, _ -> lambdaError() },
|
||||
private val getWidgetDriverResult: (MatrixWidgetSettings) -> Result<MatrixWidgetDriver> = { lambdaError() },
|
||||
private val canUserTriggerRoomNotificationResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canUserJoinCallResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val canUserPinUnpinResult: (UserId) -> Result<Boolean> = { lambdaError() },
|
||||
private val setIsFavoriteResult: (Boolean) -> Result<Unit> = { lambdaError() },
|
||||
private val powerLevelsResult: () -> Result<MatrixRoomPowerLevels> = { lambdaError() },
|
||||
private val updatePowerLevelsResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val resetPowerLevelsResult: () -> Result<MatrixRoomPowerLevels> = { lambdaError() },
|
||||
private val typingNoticeResult: (Boolean) -> Result<Unit> = { lambdaError() },
|
||||
private val leaveRoomLambda: () -> Result<Unit> = { lambdaError() },
|
||||
private val updateMembersResult: () -> Unit = { lambdaError() },
|
||||
private val getMembersResult: (Int) -> Result<List<RoomMember>> = { lambdaError() },
|
||||
private val createTimelineResult: (CreateTimelineParams) -> Result<Timeline> = { lambdaError() },
|
||||
private val setSendQueueEnabledLambda: (Boolean) -> Unit = { _: Boolean -> },
|
||||
private val saveComposerDraftLambda: (ComposerDraft) -> Result<Unit> = { _: ComposerDraft -> Result.success(Unit) },
|
||||
private val loadComposerDraftLambda: () -> Result<ComposerDraft?> = { Result.success<ComposerDraft?>(null) },
|
||||
private val clearComposerDraftLambda: () -> Result<Unit> = { Result.success(Unit) },
|
||||
private val subscribeToSyncLambda: () -> Unit = { lambdaError() },
|
||||
private val toggleReactionResult: (String, EventOrTransactionId) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val forwardEventResult: (EventId, List<RoomId>) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val cancelSendResult: (TransactionId) -> Result<Unit> = { lambdaError() },
|
||||
private val inviteUserResult: (UserId) -> Result<Unit> = { lambdaError() },
|
||||
private val setNameResult: (String) -> Result<Unit> = { lambdaError() },
|
||||
private val setTopicResult: (String) -> Result<Unit> = { lambdaError() },
|
||||
private val updateAvatarResult: (String, ByteArray) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val removeAvatarResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val updateUserRoleResult: (List<UserRoleChange>) -> Result<Unit> = { lambdaError() },
|
||||
private val updatePowerLevelsResult: (RoomPowerLevels) -> Result<Unit> = { lambdaError() },
|
||||
private val resetPowerLevelsResult: () -> Result<RoomPowerLevels> = { lambdaError() },
|
||||
private val reportContentResult: (EventId, String, UserId?) -> Result<Unit> = { _, _, _ -> lambdaError() },
|
||||
private val kickUserResult: (UserId, String?) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val banUserResult: (UserId, String?) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val unBanUserResult: (UserId, String?) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val ignoreDeviceTrustAndResendResult: (Map<UserId, List<DeviceId>>, SendHandle) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val withdrawVerificationAndResendResult: (List<UserId>, SendHandle) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val updateCanonicalAliasResult: (RoomAlias?, List<RoomAlias>) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||
private val updateRoomVisibilityResult: (RoomVisibility) -> Result<Unit> = { lambdaError() },
|
||||
private val updateRoomHistoryVisibilityResult: (RoomHistoryVisibility) -> Result<Unit> = { lambdaError() },
|
||||
private val roomVisibilityResult: () -> Result<RoomVisibility> = { lambdaError() },
|
||||
private val publishRoomAliasInRoomDirectoryResult: (RoomAlias) -> Result<Boolean> = { lambdaError() },
|
||||
private val removeRoomAliasFromRoomDirectoryResult: (RoomAlias) -> Result<Boolean> = { lambdaError() },
|
||||
private val enableEncryptionResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val updateJoinRuleResult: (JoinRule) -> Result<Unit> = { lambdaError() },
|
||||
) : MatrixRoom {
|
||||
private val _roomInfoFlow: MutableStateFlow<MatrixRoomInfo> = MutableStateFlow(initialRoomInfo)
|
||||
override val roomInfoFlow: StateFlow<MatrixRoomInfo> = _roomInfoFlow
|
||||
|
||||
fun givenRoomInfo(roomInfo: MatrixRoomInfo) {
|
||||
_roomInfoFlow.tryEmit(roomInfo)
|
||||
private val setSendQueueEnabledResult: (Boolean) -> Unit = { _: Boolean -> },
|
||||
) : JoinedRoom, BaseRoom by baseRoom {
|
||||
fun givenRoomMembersState(state: RoomMembersState) {
|
||||
baseRoom.givenRoomMembersState(state)
|
||||
}
|
||||
|
||||
private val _roomTypingMembersFlow: MutableSharedFlow<List<UserId>> = MutableSharedFlow(replay = 1)
|
||||
override val roomTypingMembersFlow: Flow<List<UserId>> = _roomTypingMembersFlow
|
||||
|
||||
fun givenRoomTypingMembers(typingMembers: List<UserId>) {
|
||||
_roomTypingMembersFlow.tryEmit(typingMembers)
|
||||
fun givenRoomInfo(roomInfo: RoomInfo) {
|
||||
baseRoom.givenRoomInfo(roomInfo)
|
||||
}
|
||||
|
||||
private val _identityStateChangesFlow: MutableSharedFlow<List<IdentityStateChange>> = MutableSharedFlow(replay = 1)
|
||||
override val identityStateChangesFlow: Flow<List<IdentityStateChange>> = _identityStateChangesFlow
|
||||
|
||||
fun emitIdentityStateChanges(identityStateChanges: List<IdentityStateChange>) {
|
||||
_identityStateChangesFlow.tryEmit(identityStateChanges)
|
||||
}
|
||||
|
||||
private val _knockRequestsFlow: MutableSharedFlow<List<KnockRequest>> = MutableSharedFlow(replay = 1)
|
||||
override val knockRequestsFlow: Flow<List<KnockRequest>> = _knockRequestsFlow
|
||||
|
||||
fun emitKnockRequests(knockRequests: List<KnockRequest>) {
|
||||
_knockRequestsFlow.tryEmit(knockRequests)
|
||||
}
|
||||
|
||||
override val membersStateFlow: MutableStateFlow<MatrixRoomMembersState> = MutableStateFlow(MatrixRoomMembersState.Unknown)
|
||||
|
||||
override val roomNotificationSettingsStateFlow: MutableStateFlow<MatrixRoomNotificationSettingsState> =
|
||||
MutableStateFlow(MatrixRoomNotificationSettingsState.Unknown)
|
||||
|
||||
override suspend fun updateMembers() = updateMembersResult()
|
||||
|
||||
override suspend fun getUpdatedMember(userId: UserId): Result<RoomMember> {
|
||||
return getUpdatedMemberResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun getMembers(limit: Int): Result<List<RoomMember>> {
|
||||
return getMembersResult(limit)
|
||||
}
|
||||
|
||||
override suspend fun updateRoomNotificationSettings(): Result<Unit> = simulateLongTask {
|
||||
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 {
|
||||
givenRoomInfo(info().copy(isEncrypted = true))
|
||||
emitSyncUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
private val _syncUpdateFlow = MutableStateFlow(0L)
|
||||
override val syncUpdateFlow: StateFlow<Long> = _syncUpdateFlow.asStateFlow()
|
||||
|
||||
fun emitSyncUpdate() {
|
||||
_syncUpdateFlow.tryEmit(_syncUpdateFlow.value + 1)
|
||||
}
|
||||
|
||||
override suspend fun createTimeline(
|
||||
createTimelineParams: CreateTimelineParams,
|
||||
): Result<Timeline> = simulateLongTask {
|
||||
override suspend fun createTimeline(createTimelineParams: CreateTimelineParams): Result<Timeline> = simulateLongTask {
|
||||
createTimelineResult(createTimelineParams)
|
||||
}
|
||||
|
||||
override suspend fun subscribeToSync() {
|
||||
subscribeToSyncLambda()
|
||||
}
|
||||
|
||||
override suspend fun powerLevels(): Result<MatrixRoomPowerLevels> {
|
||||
return powerLevelsResult()
|
||||
}
|
||||
|
||||
override suspend fun updatePowerLevels(matrixRoomPowerLevels: MatrixRoomPowerLevels): Result<Unit> = simulateLongTask {
|
||||
updatePowerLevelsResult()
|
||||
}
|
||||
|
||||
override suspend fun resetPowerLevels(): Result<MatrixRoomPowerLevels> = simulateLongTask {
|
||||
resetPowerLevelsResult()
|
||||
}
|
||||
|
||||
override fun destroy() = Unit
|
||||
|
||||
override suspend fun userDisplayName(userId: UserId): Result<String?> = simulateLongTask {
|
||||
userDisplayNameResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun userAvatarUrl(userId: UserId): Result<String?> = simulateLongTask {
|
||||
userAvatarUrlResult()
|
||||
}
|
||||
|
||||
override suspend fun userRole(userId: UserId): Result<RoomMember.Role> {
|
||||
return userRoleResult()
|
||||
}
|
||||
|
||||
override suspend fun updateUsersRoles(changes: List<UserRoleChange>): Result<Unit> {
|
||||
return updateUserRoleResult()
|
||||
}
|
||||
|
||||
override suspend fun editMessage(eventId: EventId, body: String, htmlBody: String?, intentionalMentions: List<IntentionalMention>) = simulateLongTask {
|
||||
editMessageLambda(eventId, body, htmlBody, intentionalMentions)
|
||||
}
|
||||
|
||||
override suspend fun sendMessage(body: String, htmlBody: String?, intentionalMentions: List<IntentionalMention>) = simulateLongTask {
|
||||
override suspend fun sendMessage(body: String, htmlBody: String?, intentionalMentions: List<IntentionalMention>): Result<Unit> = simulateLongTask {
|
||||
sendMessageResult(body, htmlBody, intentionalMentions)
|
||||
}
|
||||
|
||||
override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Unit> {
|
||||
return toggleReactionResult(emoji, eventOrTransactionId)
|
||||
}
|
||||
|
||||
override suspend fun cancelSend(transactionId: TransactionId): Result<Unit> {
|
||||
return cancelSendResult(transactionId)
|
||||
}
|
||||
|
||||
override suspend fun getPermalink(): Result<String> {
|
||||
return roomPermalinkResult()
|
||||
}
|
||||
|
||||
override suspend fun getPermalinkFor(eventId: EventId): Result<String> {
|
||||
return eventPermalinkResult(eventId)
|
||||
}
|
||||
|
||||
override suspend fun leave(): Result<Unit> {
|
||||
return leaveRoomLambda()
|
||||
}
|
||||
|
||||
override suspend fun join(): Result<Unit> {
|
||||
return joinRoomResult()
|
||||
}
|
||||
|
||||
override suspend fun inviteUserById(id: UserId): Result<Unit> = simulateLongTask {
|
||||
inviteUserResult(id)
|
||||
}
|
||||
|
||||
override suspend fun canUserBan(userId: UserId): Result<Boolean> {
|
||||
return canBanResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserKick(userId: UserId): Result<Boolean> {
|
||||
return canKickResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserInvite(userId: UserId): Result<Boolean> {
|
||||
return canInviteResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserRedactOwn(userId: UserId): Result<Boolean> {
|
||||
return canRedactOwnResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserRedactOther(userId: UserId): Result<Boolean> {
|
||||
return canRedactOtherResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserSendState(userId: UserId, type: StateEventType): Result<Boolean> {
|
||||
return canSendStateResult(userId, type)
|
||||
}
|
||||
|
||||
override suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result<Boolean> {
|
||||
return canUserSendMessageResult(userId, type)
|
||||
}
|
||||
|
||||
override suspend fun canUserTriggerRoomNotification(userId: UserId): Result<Boolean> {
|
||||
return canUserTriggerRoomNotificationResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserJoinCall(userId: UserId): Result<Boolean> {
|
||||
return canUserJoinCallResult(userId)
|
||||
}
|
||||
|
||||
override suspend fun canUserPinUnpin(userId: UserId): Result<Boolean> {
|
||||
return canUserPinUnpinResult(userId)
|
||||
override suspend fun editMessage(
|
||||
eventId: EventId,
|
||||
body: String,
|
||||
htmlBody: String?,
|
||||
intentionalMentions: List<IntentionalMention>
|
||||
): Result<Unit> = simulateLongTask {
|
||||
editMessageLambda(eventId, body, htmlBody, intentionalMentions)
|
||||
}
|
||||
|
||||
override suspend fun sendImage(
|
||||
|
|
@ -440,78 +253,7 @@ class FakeMatrixRoom(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun simulateSendMediaProgress(progressCallback: ProgressCallback?) {
|
||||
progressCallbackValues.forEach { (current, total) ->
|
||||
progressCallback?.onProgress(current, total)
|
||||
delay(1)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit> = simulateLongTask {
|
||||
forwardEventResult(eventId, roomIds)
|
||||
}
|
||||
|
||||
override suspend fun updateAvatar(mimeType: String, data: ByteArray): Result<Unit> = simulateLongTask {
|
||||
updateAvatarResult(mimeType, data)
|
||||
}
|
||||
|
||||
override suspend fun removeAvatar(): Result<Unit> = simulateLongTask {
|
||||
removeAvatarResult()
|
||||
}
|
||||
|
||||
override suspend fun setName(name: String): Result<Unit> = simulateLongTask {
|
||||
setNameResult(name)
|
||||
}
|
||||
|
||||
override suspend fun setTopic(topic: String): Result<Unit> = simulateLongTask {
|
||||
setTopicResult(topic)
|
||||
}
|
||||
|
||||
override suspend fun reportContent(
|
||||
eventId: EventId,
|
||||
reason: String,
|
||||
blockUserId: UserId?
|
||||
): Result<Unit> = simulateLongTask {
|
||||
return reportContentResult(eventId, reason, blockUserId)
|
||||
}
|
||||
|
||||
override suspend fun kickUser(userId: UserId, reason: String?): Result<Unit> {
|
||||
return kickUserResult(userId, reason)
|
||||
}
|
||||
|
||||
override suspend fun banUser(userId: UserId, reason: String?): Result<Unit> {
|
||||
return banUserResult(userId, reason)
|
||||
}
|
||||
|
||||
override suspend fun unbanUser(userId: UserId, reason: String?): Result<Unit> {
|
||||
return unBanUserResult(userId, reason)
|
||||
}
|
||||
|
||||
override suspend fun setIsFavorite(isFavorite: Boolean): Result<Unit> {
|
||||
return setIsFavoriteResult(isFavorite)
|
||||
}
|
||||
|
||||
val markAsReadCalls = mutableListOf<ReceiptType>()
|
||||
|
||||
override suspend fun markAsRead(receiptType: ReceiptType): Result<Unit> {
|
||||
markAsReadCalls.add(receiptType)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
var setUnreadFlagCalls = mutableListOf<Boolean>()
|
||||
private set
|
||||
|
||||
override suspend fun setUnreadFlag(isUnread: Boolean): Result<Unit> {
|
||||
setUnreadFlagCalls.add(isUnread)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun createPoll(
|
||||
question: String,
|
||||
answers: List<String>,
|
||||
maxSelections: Int,
|
||||
pollKind: PollKind
|
||||
): Result<Unit> = simulateLongTask {
|
||||
override suspend fun createPoll(question: String, answers: List<String>, maxSelections: Int, pollKind: PollKind): Result<Unit> = simulateLongTask {
|
||||
return createPollResult(
|
||||
question,
|
||||
answers,
|
||||
|
|
@ -536,58 +278,53 @@ class FakeMatrixRoom(
|
|||
)
|
||||
}
|
||||
|
||||
override suspend fun sendPollResponse(
|
||||
pollStartId: EventId,
|
||||
answers: List<String>
|
||||
): Result<Unit> = simulateLongTask {
|
||||
return sendPollResponseResult(pollStartId, answers)
|
||||
override suspend fun sendPollResponse(pollStartId: EventId, answers: List<String>): Result<Unit> = simulateLongTask {
|
||||
return sendPollResponseResult(
|
||||
pollStartId,
|
||||
answers,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun endPoll(
|
||||
pollStartId: EventId,
|
||||
text: String
|
||||
): Result<Unit> = simulateLongTask {
|
||||
return endPollResult(pollStartId, text)
|
||||
override suspend fun endPoll(pollStartId: EventId, text: String): Result<Unit> = simulateLongTask {
|
||||
endPollResult(
|
||||
pollStartId,
|
||||
text,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun typingNotice(isTyping: Boolean): Result<Unit> {
|
||||
return typingNoticeResult(isTyping)
|
||||
override suspend fun typingNotice(isTyping: Boolean): Result<Unit> = simulateLongTask {
|
||||
typingNoticeResult(isTyping)
|
||||
}
|
||||
|
||||
override suspend fun generateWidgetWebViewUrl(
|
||||
widgetSettings: MatrixWidgetSettings,
|
||||
clientId: String,
|
||||
languageTag: String?,
|
||||
theme: String?,
|
||||
): Result<String> = generateWidgetWebViewUrlResult(
|
||||
widgetSettings,
|
||||
clientId,
|
||||
languageTag,
|
||||
theme,
|
||||
)
|
||||
|
||||
override suspend fun sendCallNotificationIfNeeded(): Result<Unit> {
|
||||
return sendCallNotificationIfNeededResult()
|
||||
override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Unit> = simulateLongTask {
|
||||
toggleReactionResult(emoji, eventOrTransactionId)
|
||||
}
|
||||
|
||||
override suspend fun setSendQueueEnabled(enabled: Boolean) = setSendQueueEnabledLambda(enabled)
|
||||
|
||||
override suspend fun saveComposerDraft(composerDraft: ComposerDraft) = saveComposerDraftLambda(composerDraft)
|
||||
|
||||
override suspend fun loadComposerDraft() = loadComposerDraftLambda()
|
||||
|
||||
override suspend fun clearComposerDraft() = clearComposerDraftLambda()
|
||||
|
||||
override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result<MatrixWidgetDriver> {
|
||||
return getWidgetDriverResult(widgetSettings)
|
||||
override suspend fun forwardEvent(eventId: EventId, roomIds: List<RoomId>): Result<Unit> = simulateLongTask {
|
||||
forwardEventResult(eventId, roomIds)
|
||||
}
|
||||
|
||||
override suspend fun ignoreDeviceTrustAndResend(devices: Map<UserId, List<DeviceId>>, sendHandle: SendHandle): Result<Unit> = simulateLongTask {
|
||||
return ignoreDeviceTrustAndResendResult(devices, sendHandle)
|
||||
override suspend fun cancelSend(transactionId: TransactionId): Result<Unit> = simulateLongTask {
|
||||
cancelSendResult(transactionId)
|
||||
}
|
||||
|
||||
override suspend fun withdrawVerificationAndResend(userIds: List<UserId>, sendHandle: SendHandle): Result<Unit> = simulateLongTask {
|
||||
return withdrawVerificationAndResendResult(userIds, sendHandle)
|
||||
override suspend fun inviteUserById(id: UserId): Result<Unit> = simulateLongTask {
|
||||
inviteUserResult(id)
|
||||
}
|
||||
|
||||
override suspend fun updateAvatar(mimeType: String, data: ByteArray): Result<Unit> = simulateLongTask {
|
||||
simulateSendMediaProgress(null)
|
||||
updateAvatarResult(mimeType, data)
|
||||
}
|
||||
|
||||
override suspend fun removeAvatar(): Result<Unit> = simulateLongTask {
|
||||
removeAvatarResult()
|
||||
}
|
||||
|
||||
override suspend fun updateRoomNotificationSettings(): Result<Unit> = simulateLongTask {
|
||||
val notificationSettings = roomNotificationSettingsService.getRoomNotificationSettings(roomId, info().isEncrypted.orFalse(), isOneToOne).getOrThrow()
|
||||
(roomNotificationSettingsStateFlow as MutableStateFlow).value = RoomNotificationSettingsState.Ready(notificationSettings)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun updateCanonicalAlias(canonicalAlias: RoomAlias?, alternativeAliases: List<RoomAlias>): Result<Unit> = simulateLongTask {
|
||||
|
|
@ -602,10 +339,6 @@ class FakeMatrixRoom(
|
|||
updateRoomHistoryVisibilityResult(historyVisibility)
|
||||
}
|
||||
|
||||
override suspend fun getRoomVisibility(): Result<RoomVisibility> = simulateLongTask {
|
||||
roomVisibilityResult()
|
||||
}
|
||||
|
||||
override suspend fun publishRoomAliasInRoomDirectory(roomAlias: RoomAlias): Result<Boolean> = simulateLongTask {
|
||||
publishRoomAliasInRoomDirectoryResult(roomAlias)
|
||||
}
|
||||
|
|
@ -614,30 +347,90 @@ class FakeMatrixRoom(
|
|||
removeRoomAliasFromRoomDirectoryResult(roomAlias)
|
||||
}
|
||||
|
||||
override suspend fun enableEncryption(): Result<Unit> = simulateLongTask {
|
||||
enableEncryptionResult().onSuccess {
|
||||
baseRoom.givenRoomInfo(info().copy(isEncrypted = true))
|
||||
emitSyncUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateJoinRule(joinRule: JoinRule): Result<Unit> = simulateLongTask {
|
||||
updateJoinRuleResult(joinRule)
|
||||
}
|
||||
|
||||
override suspend fun getUpdatedIsEncrypted(): Result<Boolean> = simulateLongTask {
|
||||
Result.success(info().isEncrypted.orFalse())
|
||||
override suspend fun updateUsersRoles(changes: List<UserRoleChange>): Result<Unit> = simulateLongTask {
|
||||
updateUserRoleResult(changes)
|
||||
}
|
||||
|
||||
fun givenRoomMembersState(state: MatrixRoomMembersState) {
|
||||
membersStateFlow.value = state
|
||||
override suspend fun updatePowerLevels(roomPowerLevels: RoomPowerLevels): Result<Unit> = simulateLongTask {
|
||||
updatePowerLevelsResult(roomPowerLevels)
|
||||
}
|
||||
|
||||
override suspend fun clearEventCacheStorage(): Result<Unit> {
|
||||
return Result.success(Unit)
|
||||
override suspend fun resetPowerLevels(): Result<RoomPowerLevels> = simulateLongTask {
|
||||
resetPowerLevelsResult()
|
||||
}
|
||||
|
||||
override suspend fun setName(name: String): Result<Unit> = simulateLongTask {
|
||||
setNameResult(name)
|
||||
}
|
||||
|
||||
override suspend fun setTopic(topic: String): Result<Unit> = simulateLongTask {
|
||||
setTopicResult(topic)
|
||||
}
|
||||
|
||||
override suspend fun reportContent(eventId: EventId, reason: String, blockUserId: UserId?): Result<Unit> = simulateLongTask {
|
||||
reportContentResult(eventId, reason, blockUserId)
|
||||
}
|
||||
|
||||
override suspend fun kickUser(userId: UserId, reason: String?): Result<Unit> = simulateLongTask {
|
||||
kickUserResult(userId, reason)
|
||||
}
|
||||
|
||||
override suspend fun banUser(userId: UserId, reason: String?): Result<Unit> = simulateLongTask {
|
||||
banUserResult(userId, reason)
|
||||
}
|
||||
|
||||
override suspend fun unbanUser(userId: UserId, reason: String?): Result<Unit> = simulateLongTask {
|
||||
unBanUserResult(userId, reason)
|
||||
}
|
||||
|
||||
override suspend fun generateWidgetWebViewUrl(
|
||||
widgetSettings: MatrixWidgetSettings,
|
||||
clientId: String,
|
||||
languageTag: String?,
|
||||
theme: String?
|
||||
): Result<String> = simulateLongTask {
|
||||
generateWidgetWebViewUrlResult(widgetSettings, clientId, languageTag, theme)
|
||||
}
|
||||
|
||||
override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result<MatrixWidgetDriver> {
|
||||
return getWidgetDriverResult(widgetSettings)
|
||||
}
|
||||
|
||||
override suspend fun sendCallNotificationIfNeeded(): Result<Unit> = simulateLongTask {
|
||||
sendCallNotificationIfNeededResult()
|
||||
}
|
||||
|
||||
override suspend fun setSendQueueEnabled(enabled: Boolean) = simulateLongTask {
|
||||
setSendQueueEnabledResult(enabled)
|
||||
}
|
||||
|
||||
override suspend fun ignoreDeviceTrustAndResend(devices: Map<UserId, List<DeviceId>>, sendHandle: SendHandle): Result<Unit> = simulateLongTask {
|
||||
ignoreDeviceTrustAndResendResult(devices, sendHandle)
|
||||
}
|
||||
|
||||
override suspend fun withdrawVerificationAndResend(userIds: List<UserId>, sendHandle: SendHandle): Result<Unit> = simulateLongTask {
|
||||
withdrawVerificationAndResendResult(userIds, sendHandle)
|
||||
}
|
||||
|
||||
private suspend fun simulateSendMediaProgress(progressCallback: ProgressCallback?) {
|
||||
progressCallbackValues.forEach { (current, total) ->
|
||||
progressCallback?.onProgress(current, total)
|
||||
delay(1)
|
||||
}
|
||||
}
|
||||
|
||||
fun emitSyncUpdate() {
|
||||
(syncUpdateFlow as MutableStateFlow).value = syncUpdateFlow.value + 1
|
||||
}
|
||||
}
|
||||
|
||||
fun defaultRoomPowerLevels() = MatrixRoomPowerLevels(
|
||||
ban = 50,
|
||||
invite = 0,
|
||||
kick = 50,
|
||||
sendEvents = 0,
|
||||
redactEvents = 50,
|
||||
roomName = 100,
|
||||
roomAvatar = 100,
|
||||
roomTopic = 100
|
||||
)
|
||||
|
|
@ -8,30 +8,19 @@
|
|||
package io.element.android.libraries.matrix.test.room
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.NotJoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipDetails
|
||||
import io.element.android.libraries.matrix.api.room.RoomPreview
|
||||
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.simulateLongTask
|
||||
|
||||
@Immutable
|
||||
class FakeRoomPreview(
|
||||
override val sessionId: SessionId = A_SESSION_ID,
|
||||
override val info: RoomPreviewInfo = aRoomPreviewInfo(),
|
||||
private val declineInviteResult: () -> Result<Unit> = { lambdaError() },
|
||||
private val forgetRoomResult: () -> Result<Unit> = { lambdaError() },
|
||||
class FakeNotJoinedRoom(
|
||||
override val localRoom: BaseRoom? = null,
|
||||
override val previewInfo: RoomPreviewInfo = aRoomPreviewInfo(),
|
||||
private val roomMembershipDetails: () -> Result<RoomMembershipDetails?> = { lambdaError() },
|
||||
) : RoomPreview {
|
||||
override suspend fun leave(): Result<Unit> = simulateLongTask {
|
||||
declineInviteResult()
|
||||
}
|
||||
|
||||
override suspend fun forget(): Result<Unit> = simulateLongTask {
|
||||
forgetRoomResult()
|
||||
}
|
||||
|
||||
) : NotJoinedRoom {
|
||||
override suspend fun membershipDetails(): Result<RoomMembershipDetails?> = simulateLongTask {
|
||||
roomMembershipDetails()
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
|
|||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
|
|
@ -61,7 +61,7 @@ fun aRoomInfo(
|
|||
numUnreadNotifications: Long = 0,
|
||||
numUnreadMentions: Long = 0,
|
||||
historyVisibility: RoomHistoryVisibility = RoomHistoryVisibility.Joined,
|
||||
) = MatrixRoomInfo(
|
||||
) = RoomInfo(
|
||||
id = id,
|
||||
name = name,
|
||||
rawName = rawName,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ package io.element.android.libraries.matrix.test.room
|
|||
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipDetails
|
||||
import io.element.android.libraries.matrix.api.room.RoomType
|
||||
|
|
@ -19,20 +18,15 @@ import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
|||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_TOPIC
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
|
||||
fun aRoomPreview(
|
||||
sessionId: SessionId = A_SESSION_ID,
|
||||
localRoom: FakeBaseRoom? = null,
|
||||
info: RoomPreviewInfo = aRoomPreviewInfo(),
|
||||
declineInviteResult: () -> Result<Unit> = { lambdaError() },
|
||||
forgetRoomResult: () -> Result<Unit> = { lambdaError() },
|
||||
roomMembershipDetails: () -> Result<RoomMembershipDetails?> = { lambdaError() },
|
||||
) = FakeRoomPreview(
|
||||
sessionId = sessionId,
|
||||
info = info,
|
||||
declineInviteResult = declineInviteResult,
|
||||
forgetRoomResult = forgetRoomResult,
|
||||
) = FakeNotJoinedRoom(
|
||||
localRoom = localRoom,
|
||||
previewInfo = info,
|
||||
roomMembershipDetails = roomMembershipDetails,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
|
|||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||
|
|
@ -33,7 +33,7 @@ import kotlinx.collections.immutable.persistentMapOf
|
|||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
fun aRoomSummary(
|
||||
info: MatrixRoomInfo = aRoomInfo(),
|
||||
info: RoomInfo = aRoomInfo(),
|
||||
lastMessage: RoomMessage? = aRoomMessage(),
|
||||
) = RoomSummary(
|
||||
info = info,
|
||||
|
|
@ -76,7 +76,7 @@ fun aRoomSummary(
|
|||
historyVisibility: RoomHistoryVisibility = RoomHistoryVisibility.Joined,
|
||||
lastMessage: RoomMessage? = aRoomMessage(),
|
||||
) = RoomSummary(
|
||||
info = MatrixRoomInfo(
|
||||
info = RoomInfo(
|
||||
id = roomId,
|
||||
name = name,
|
||||
rawName = rawName,
|
||||
|
|
|
|||
|
|
@ -7,14 +7,14 @@
|
|||
|
||||
package io.element.android.libraries.matrix.test.timeline
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.TimelineProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
class LiveTimelineProvider(
|
||||
private val room: MatrixRoom,
|
||||
private val room: JoinedRoom,
|
||||
) : TimelineProvider {
|
||||
override fun activeTimelineFlow(): StateFlow<Timeline> = MutableStateFlow(room.liveTimeline)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ package io.element.android.libraries.matrix.ui.model
|
|||
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||
|
||||
fun MatrixRoomInfo.getAvatarData(size: AvatarSize) = AvatarData(
|
||||
fun RoomInfo.getAvatarData(size: AvatarSize) = AvatarData(
|
||||
id = id.value,
|
||||
name = name,
|
||||
url = avatarUrl,
|
||||
|
|
|
|||
|
|
@ -14,19 +14,19 @@ import androidx.compose.runtime.derivedStateOf
|
|||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
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.roomMembers
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.getRoomMemberAsState(userId: UserId): State<RoomMember?> {
|
||||
fun BaseRoom.getRoomMemberAsState(userId: UserId): State<RoomMember?> {
|
||||
val roomMembersState by membersStateFlow.collectAsState()
|
||||
return getRoomMemberAsState(roomMembersState = roomMembersState, userId = userId)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun getRoomMemberAsState(roomMembersState: MatrixRoomMembersState, userId: UserId): State<RoomMember?> {
|
||||
fun getRoomMemberAsState(roomMembersState: RoomMembersState, userId: UserId): State<RoomMember?> {
|
||||
val roomMembers = roomMembersState.roomMembers()
|
||||
return remember(roomMembers) {
|
||||
derivedStateOf {
|
||||
|
|
@ -38,7 +38,7 @@ fun getRoomMemberAsState(roomMembersState: MatrixRoomMembersState, userId: UserI
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.getDirectRoomMember(roomMembersState: MatrixRoomMembersState): State<RoomMember?> {
|
||||
fun BaseRoom.getDirectRoomMember(roomMembersState: RoomMembersState): State<RoomMember?> {
|
||||
val roomMembers = roomMembersState.roomMembers()
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
return remember(roomMembersState, roomInfo.isDirect) {
|
||||
|
|
@ -52,6 +52,6 @@ fun MatrixRoom.getDirectRoomMember(roomMembersState: MatrixRoomMembersState): St
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.getCurrentRoomMember(roomMembersState: MatrixRoomMembersState): State<RoomMember?> {
|
||||
fun BaseRoom.getCurrentRoomMember(roomMembersState: RoomMembersState): State<RoomMember?> {
|
||||
return getRoomMemberAsState(roomMembersState = roomMembersState, userId = sessionId)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import androidx.compose.runtime.State
|
|||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.produceState
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.isDm
|
||||
|
|
@ -25,77 +25,77 @@ import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
|
|||
import io.element.android.libraries.matrix.api.room.powerlevels.canSendMessage
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canSendMessageAsState(type: MessageEventType, updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canSendMessageAsState(type: MessageEventType, updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = true, key1 = updateKey) {
|
||||
value = canSendMessage(type).getOrElse { true }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canInviteAsState(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canInviteAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canInvite().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canRedactOwnAsState(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canRedactOwnAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canRedactOwn().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canRedactOtherAsState(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canRedactOtherAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canRedactOther().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canCall(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canCall(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canUserJoinCall(sessionId).getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canPinUnpin(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canPinUnpin(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canUserPinUnpin(sessionId).getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.isDmAsState(): State<Boolean> {
|
||||
fun BaseRoom.isDmAsState(): State<Boolean> {
|
||||
return produceState(initialValue = false) {
|
||||
roomInfoFlow.collect { value = it.isDm }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canKickAsState(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canKickAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canKick().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canBanAsState(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canBanAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canBan().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.canHandleKnockRequestsAsState(updateKey: Long): State<Boolean> {
|
||||
fun BaseRoom.canHandleKnockRequestsAsState(updateKey: Long): State<Boolean> {
|
||||
return produceState(initialValue = false, key1 = updateKey) {
|
||||
value = canHandleKnockRequests().getOrElse { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.userPowerLevelAsState(updateKey: Long): State<Long> {
|
||||
fun BaseRoom.userPowerLevelAsState(updateKey: Long): State<Long> {
|
||||
return produceState(initialValue = 0, key1 = updateKey) {
|
||||
value = userRole(sessionId)
|
||||
.getOrDefault(RoomMember.Role.USER)
|
||||
|
|
@ -104,26 +104,26 @@ fun MatrixRoom.userPowerLevelAsState(updateKey: Long): State<Long> {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.isOwnUserAdmin(): Boolean {
|
||||
fun BaseRoom.isOwnUserAdmin(): Boolean {
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
val powerLevel = roomInfo.userPowerLevels[sessionId] ?: 0L
|
||||
return RoomMember.Role.forPowerLevel(powerLevel) == RoomMember.Role.ADMIN
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.rawName(): String? {
|
||||
fun BaseRoom.rawName(): String? {
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
return roomInfo.rawName
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.topic(): String? {
|
||||
fun BaseRoom.topic(): String? {
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
return roomInfo.topic
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MatrixRoom.avatarUrl(): String? {
|
||||
fun BaseRoom.avatarUrl(): String? {
|
||||
val roomInfo by roomInfoFlow.collectAsState()
|
||||
return roomInfo.avatarUrl
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
|||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
import io.element.android.libraries.matrix.api.room.roomMembers
|
||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||
|
|
@ -29,7 +29,7 @@ import kotlinx.coroutines.flow.launchIn
|
|||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun MatrixRoom.roomMemberIdentityStateChange(): Flow<ImmutableList<RoomMemberIdentityStateChange>> {
|
||||
fun JoinedRoom.roomMemberIdentityStateChange(): Flow<ImmutableList<RoomMemberIdentityStateChange>> {
|
||||
return roomInfoFlow
|
||||
.filter {
|
||||
// Room cannot become unencrypted, so we can just apply a filter here.
|
||||
|
|
@ -52,7 +52,7 @@ fun MatrixRoom.roomMemberIdentityStateChange(): Flow<ImmutableList<RoomMemberIde
|
|||
}
|
||||
}
|
||||
|
||||
fun ProduceStateScope<PersistentList<RoomMemberIdentityStateChange>>.observeRoomMemberIdentityStateChange(room: MatrixRoom) {
|
||||
fun ProduceStateScope<PersistentList<RoomMemberIdentityStateChange>>.observeRoomMemberIdentityStateChange(room: JoinedRoom) {
|
||||
room.roomMemberIdentityStateChange()
|
||||
.onEach { roomMemberIdentityStateChanges ->
|
||||
value = roomMemberIdentityStateChanges.toPersistentList()
|
||||
|
|
|
|||
|
|
@ -11,26 +11,26 @@ import app.cash.molecule.RecompositionMode
|
|||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipState
|
||||
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.FakeBaseRoom
|
||||
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
|
||||
import org.junit.Test
|
||||
|
||||
class MatrixRoomMembersTest {
|
||||
class RoomMembersTest {
|
||||
private val roomMember1 = aRoomMember(A_USER_ID)
|
||||
private val roomMember2 = aRoomMember(A_USER_ID_2)
|
||||
private val roomMember3 = aRoomMember(A_USER_ID_3)
|
||||
|
||||
@Test
|
||||
fun `getDirectRoomMember emits other member for encrypted DM with 2 joined members`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(
|
||||
isDirect = true,
|
||||
|
|
@ -38,8 +38,8 @@ class MatrixRoomMembersTest {
|
|||
)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(persistentListOf(roomMember1, roomMember2))
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(persistentListOf(roomMember1, roomMember2))
|
||||
)
|
||||
}.test {
|
||||
assertThat(awaitItem().value).isEqualTo(roomMember2)
|
||||
|
|
@ -48,13 +48,13 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getDirectRoomMember emit null if the room is not a dm`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(isDirect = false)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(persistentListOf(roomMember1, roomMember2))
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(persistentListOf(roomMember1, roomMember2))
|
||||
)
|
||||
}.test {
|
||||
assertThat(awaitItem().value).isNull()
|
||||
|
|
@ -63,7 +63,7 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getDirectRoomMember emits other member even if the room is not encrypted`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(
|
||||
isDirect = true,
|
||||
|
|
@ -71,8 +71,8 @@ class MatrixRoomMembersTest {
|
|||
)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(persistentListOf(roomMember1, roomMember2))
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(persistentListOf(roomMember1, roomMember2))
|
||||
)
|
||||
}.test {
|
||||
assertThat(awaitItem().value).isEqualTo(roomMember2)
|
||||
|
|
@ -81,13 +81,13 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getDirectRoomMember emit null if the room has only 1 member`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(isDirect = true)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(persistentListOf(roomMember1))
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(persistentListOf(roomMember1))
|
||||
)
|
||||
}.test {
|
||||
assertThat(awaitItem().value).isNull()
|
||||
|
|
@ -96,14 +96,14 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getDirectRoomMember emit null if the room has only 3 members`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
).apply {
|
||||
givenRoomInfo(aRoomInfo(isDirect = true))
|
||||
}
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(persistentListOf(roomMember1, roomMember2, roomMember3))
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(persistentListOf(roomMember1, roomMember2, roomMember3))
|
||||
)
|
||||
}.test {
|
||||
assertThat(awaitItem().value).isNull()
|
||||
|
|
@ -112,13 +112,13 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getDirectRoomMember emit null if the other member is not active`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(isDirect = true),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(
|
||||
persistentListOf(
|
||||
roomMember1,
|
||||
roomMember2.copy(membership = RoomMembershipState.BAN),
|
||||
|
|
@ -132,7 +132,7 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getDirectRoomMember emit the other member if there are 2 active members`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(
|
||||
isDirect = true,
|
||||
|
|
@ -140,8 +140,8 @@ class MatrixRoomMembersTest {
|
|||
)
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getDirectRoomMember(
|
||||
MatrixRoomMembersState.Ready(
|
||||
joinedRoom.getDirectRoomMember(
|
||||
RoomMembersState.Ready(
|
||||
persistentListOf(
|
||||
roomMember1,
|
||||
roomMember2,
|
||||
|
|
@ -156,10 +156,10 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getCurrentRoomMember returns the current user`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(sessionId = A_USER_ID)
|
||||
val joinedRoom = FakeBaseRoom(sessionId = A_USER_ID)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getCurrentRoomMember(
|
||||
MatrixRoomMembersState.Ready(
|
||||
joinedRoom.getCurrentRoomMember(
|
||||
RoomMembersState.Ready(
|
||||
persistentListOf(
|
||||
roomMember1,
|
||||
roomMember2,
|
||||
|
|
@ -174,10 +174,10 @@ class MatrixRoomMembersTest {
|
|||
|
||||
@Test
|
||||
fun `getCurrentRoomMember returns null if the member is not found`() = runTest {
|
||||
val matrixRoom = FakeMatrixRoom(sessionId = A_USER_ID)
|
||||
val joinedRoom = FakeBaseRoom(sessionId = A_USER_ID)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
matrixRoom.getCurrentRoomMember(
|
||||
MatrixRoomMembersState.Ready(
|
||||
joinedRoom.getCurrentRoomMember(
|
||||
RoomMembersState.Ready(
|
||||
persistentListOf(
|
||||
roomMember2,
|
||||
roomMember3,
|
||||
|
|
@ -11,7 +11,7 @@ import android.net.Uri
|
|||
import io.element.android.libraries.core.extensions.flatMapCatching
|
||||
import io.element.android.libraries.matrix.api.core.ProgressCallback
|
||||
import io.element.android.libraries.matrix.api.media.MediaUploadHandler
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.message.ReplyParameters
|
||||
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
||||
import kotlinx.coroutines.CancellationException
|
||||
|
|
@ -22,7 +22,7 @@ import javax.inject.Inject
|
|||
|
||||
class MediaSender @Inject constructor(
|
||||
private val preProcessor: MediaPreProcessor,
|
||||
private val room: MatrixRoom,
|
||||
private val room: JoinedRoom,
|
||||
private val sessionPreferencesStore: SessionPreferencesStore,
|
||||
) {
|
||||
private val ongoingUploadJobs = ConcurrentHashMap<Job.Key, MediaUploadHandler>()
|
||||
|
|
@ -130,7 +130,7 @@ class MediaSender @Inject constructor(
|
|||
ongoingUploadJobs.remove(Job)
|
||||
}
|
||||
|
||||
private suspend fun MatrixRoom.sendMedia(
|
||||
private suspend fun JoinedRoom.sendMedia(
|
||||
uploadInfo: MediaUploadInfo,
|
||||
progressCallback: ProgressCallback?,
|
||||
caption: String?,
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ import io.element.android.libraries.core.mimetype.MimeTypes
|
|||
import io.element.android.libraries.matrix.api.core.ProgressCallback
|
||||
import io.element.android.libraries.matrix.api.media.FileInfo
|
||||
import io.element.android.libraries.matrix.api.media.ImageInfo
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.message.ReplyParameters
|
||||
import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor
|
||||
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
||||
import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore
|
||||
|
|
@ -45,12 +45,12 @@ class MediaSenderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `given an attachment when sending it the MatrixRoom will call sendMedia`() = runTest {
|
||||
fun `given an attachment when sending it the Room will call sendMedia`() = runTest {
|
||||
val sendImageResult =
|
||||
lambdaRecorder { _: File, _: File?, _: ImageInfo, _: String?, _: String?, _: ProgressCallback?, _: ReplyParameters? ->
|
||||
Result.success(FakeMediaUploadHandler())
|
||||
}
|
||||
val room = FakeMatrixRoom(
|
||||
val room = FakeJoinedRoom(
|
||||
sendImageResult = sendImageResult
|
||||
)
|
||||
val sender = createMediaSender(room = room)
|
||||
|
|
@ -78,7 +78,7 @@ class MediaSenderTest {
|
|||
lambdaRecorder { _: File, _: File?, _: ImageInfo, _: String?, _: String?, _: ProgressCallback?, _: ReplyParameters? ->
|
||||
Result.failure<FakeMediaUploadHandler>(Exception())
|
||||
}
|
||||
val room = FakeMatrixRoom(
|
||||
val room = FakeJoinedRoom(
|
||||
sendImageResult = sendImageResult
|
||||
)
|
||||
val sender = createMediaSender(room = room)
|
||||
|
|
@ -96,7 +96,7 @@ class MediaSenderTest {
|
|||
lambdaRecorder<File, FileInfo, String?, String?, ProgressCallback?, ReplyParameters?, Result<FakeMediaUploadHandler>> { _, _, _, _, _, _ ->
|
||||
Result.success(FakeMediaUploadHandler())
|
||||
}
|
||||
val room = FakeMatrixRoom(
|
||||
val room = FakeJoinedRoom(
|
||||
sendFileResult = sendFileResult
|
||||
)
|
||||
val sender = createMediaSender(room = room)
|
||||
|
|
@ -123,7 +123,7 @@ class MediaSenderTest {
|
|||
|
||||
private fun createMediaSender(
|
||||
preProcessor: MediaPreProcessor = FakeMediaPreProcessor(),
|
||||
room: MatrixRoom = FakeMatrixRoom(),
|
||||
room: JoinedRoom = FakeJoinedRoom(),
|
||||
sessionPreferencesStore: SessionPreferencesStore = InMemorySessionPreferencesStore(),
|
||||
) = MediaSender(
|
||||
preProcessor = preProcessor,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ package io.element.android.libraries.mediaviewer.impl.datasource
|
|||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ interface FocusedTimelineMediaGalleryDataSourceFactory {
|
|||
|
||||
@ContributesBinding(RoomScope::class)
|
||||
class DefaultFocusedTimelineMediaGalleryDataSourceFactory @Inject constructor(
|
||||
private val room: MatrixRoom,
|
||||
private val room: JoinedRoom,
|
||||
private val timelineMediaItemsFactory: TimelineMediaItemsFactory,
|
||||
private val mediaItemsPostProcessor: MediaItemsPostProcessor,
|
||||
) : FocusedTimelineMediaGalleryDataSourceFactory {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import io.element.android.libraries.architecture.AsyncData
|
|||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
|
||||
import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems
|
||||
|
|
@ -40,7 +40,7 @@ interface MediaGalleryDataSource {
|
|||
@SingleIn(RoomScope::class)
|
||||
@ContributesBinding(RoomScope::class)
|
||||
class TimelineMediaGalleryDataSource @Inject constructor(
|
||||
private val room: MatrixRoom,
|
||||
private val room: BaseRoom,
|
||||
private val mediaTimeline: MediaTimeline,
|
||||
private val timelineMediaItemsFactory: TimelineMediaItemsFactory,
|
||||
private val mediaItemsPostProcessor: MediaItemsPostProcessor,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import io.element.android.libraries.di.SingleIn
|
|||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.UniqueId
|
||||
import io.element.android.libraries.matrix.api.room.CreateTimelineParams
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems
|
||||
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
|
||||
|
|
@ -37,7 +37,7 @@ interface MediaTimeline {
|
|||
@SingleIn(RoomScope::class)
|
||||
@ContributesBinding(RoomScope::class)
|
||||
class LiveMediaTimeline @Inject constructor(
|
||||
private val room: MatrixRoom,
|
||||
private val room: JoinedRoom,
|
||||
) : MediaTimeline {
|
||||
private var timeline: Timeline? = null
|
||||
private val mutex = Mutex()
|
||||
|
|
@ -62,7 +62,7 @@ class LiveMediaTimeline @Inject constructor(
|
|||
* Optionally, the timeline will only contain the pinned events.
|
||||
*/
|
||||
class FocusedMediaTimeline(
|
||||
private val room: MatrixRoom,
|
||||
private val room: JoinedRoom,
|
||||
private val eventId: EventId,
|
||||
private val onlyPinnedEvents: Boolean,
|
||||
initialMediaItem: MediaItem.Event,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
|
|||
import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
|
||||
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
||||
|
|
@ -45,7 +45,7 @@ import kotlinx.coroutines.launch
|
|||
|
||||
class MediaGalleryPresenter @AssistedInject constructor(
|
||||
@Assisted private val navigator: MediaGalleryNavigator,
|
||||
private val room: MatrixRoom,
|
||||
private val room: BaseRoom,
|
||||
private val mediaGalleryDataSource: MediaGalleryDataSource,
|
||||
private val localMediaFactory: LocalMediaFactory,
|
||||
private val mediaLoader: MatrixMediaLoader,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatch
|
|||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
|
||||
|
|
@ -53,7 +53,7 @@ class MediaViewerPresenter @AssistedInject constructor(
|
|||
@Assisted private val inputs: MediaViewerEntryPoint.Params,
|
||||
@Assisted private val navigator: MediaViewerNavigator,
|
||||
@Assisted private val dataSource: MediaViewerDataSource,
|
||||
private val room: MatrixRoom,
|
||||
private val room: JoinedRoom,
|
||||
private val localMediaActions: LocalMediaActions,
|
||||
) : Presenter<MediaViewerState> {
|
||||
@AssistedFactory
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ package io.element.android.libraries.mediaviewer.impl.datasource
|
|||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
|
@ -18,7 +18,7 @@ class DefaultFocusedTimelineMediaGalleryDataSourceFactoryTest {
|
|||
@Test
|
||||
fun `createFor should create a TimelineMediaGalleryDataSource`() = runTest {
|
||||
val sut = DefaultFocusedTimelineMediaGalleryDataSourceFactory(
|
||||
room = FakeMatrixRoom(),
|
||||
room = FakeJoinedRoom(),
|
||||
timelineMediaItemsFactory = createTimelineMediaItemsFactory(),
|
||||
mediaItemsPostProcessor = MediaItemsPostProcessor(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ package io.element.android.libraries.mediaviewer.impl.datasource
|
|||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.room.CreateTimelineParams
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems
|
||||
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
|
||||
|
|
@ -79,7 +79,7 @@ class FocusedMediaTimelineTest {
|
|||
val createTimelineResult = lambdaRecorder<CreateTimelineParams, Result<Timeline>> {
|
||||
Result.success(FakeTimeline())
|
||||
}
|
||||
val room = FakeMatrixRoom(
|
||||
val room = FakeJoinedRoom(
|
||||
createTimelineResult = createTimelineResult,
|
||||
)
|
||||
val sut = createFocusedMediaTimeline(
|
||||
|
|
@ -96,7 +96,7 @@ class FocusedMediaTimelineTest {
|
|||
val createTimelineResult = lambdaRecorder<CreateTimelineParams, Result<Timeline>> {
|
||||
Result.success(FakeTimeline())
|
||||
}
|
||||
val room = FakeMatrixRoom(
|
||||
val room = FakeJoinedRoom(
|
||||
createTimelineResult = createTimelineResult,
|
||||
)
|
||||
val sut = createFocusedMediaTimeline(
|
||||
|
|
@ -110,7 +110,7 @@ class FocusedMediaTimelineTest {
|
|||
}
|
||||
|
||||
private fun createFocusedMediaTimeline(
|
||||
room: MatrixRoom = FakeMatrixRoom(),
|
||||
room: JoinedRoom = FakeJoinedRoom(),
|
||||
eventId: EventId = AN_EVENT_ID,
|
||||
initialMediaItem: MediaItem.Event = aMediaItemImage(),
|
||||
onlyPinnedEvent: Boolean = false,
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ package io.element.android.libraries.mediaviewer.impl.datasource
|
|||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.room.CreateTimelineParams
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
|
|
@ -31,7 +31,7 @@ class LiveMediaTimelineTest {
|
|||
val createTimelineResult = lambdaRecorder<CreateTimelineParams, Result<Timeline>> {
|
||||
Result.success(FakeTimeline())
|
||||
}
|
||||
val room = FakeMatrixRoom(
|
||||
val room = FakeJoinedRoom(
|
||||
createTimelineResult = createTimelineResult,
|
||||
)
|
||||
val sut = createLiveMediaTimeline(
|
||||
|
|
@ -47,7 +47,7 @@ class LiveMediaTimelineTest {
|
|||
}
|
||||
|
||||
private fun createLiveMediaTimeline(
|
||||
room: MatrixRoom = FakeMatrixRoom(),
|
||||
room: JoinedRoom = FakeJoinedRoom(),
|
||||
) = LiveMediaTimeline(
|
||||
room = room,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import io.element.android.libraries.dateformatter.test.FakeDateFormatter
|
|||
import io.element.android.libraries.matrix.api.media.ImageInfo
|
||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||
import io.element.android.libraries.matrix.api.media.ThumbnailInfo
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
||||
|
|
@ -28,7 +28,7 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
|||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||
import io.element.android.libraries.matrix.test.A_UNIQUE_ID
|
||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.libraries.matrix.test.timeline.aMessageContent
|
||||
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
||||
|
|
@ -56,7 +56,7 @@ class TimelineMediaGalleryDataSourceTest {
|
|||
fun `test - not started TimelineMediaGalleryDataSource emits no events`() = runTest {
|
||||
val fakeTimeline = FakeTimeline()
|
||||
val sut = createTimelineMediaGalleryDataSource(
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(
|
||||
createTimelineResult = { Result.success(fakeTimeline) },
|
||||
roomCoroutineScope = backgroundScope,
|
||||
)
|
||||
|
|
@ -74,7 +74,7 @@ class TimelineMediaGalleryDataSourceTest {
|
|||
val fakeTimeline = FakeTimeline()
|
||||
runTest {
|
||||
val sut = createTimelineMediaGalleryDataSource(
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(
|
||||
createTimelineResult = { Result.success(fakeTimeline) },
|
||||
roomCoroutineScope = backgroundScope,
|
||||
)
|
||||
|
|
@ -111,7 +111,7 @@ class TimelineMediaGalleryDataSourceTest {
|
|||
paginateLambda = paginateLambdaRecorder
|
||||
}
|
||||
val sut = createTimelineMediaGalleryDataSource(
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(
|
||||
createTimelineResult = { Result.success(fakeTimeline) },
|
||||
roomCoroutineScope = backgroundScope,
|
||||
)
|
||||
|
|
@ -134,7 +134,7 @@ class TimelineMediaGalleryDataSourceTest {
|
|||
redactEventLambda = redactEventLambdaRecorder
|
||||
}
|
||||
val sut = createTimelineMediaGalleryDataSource(
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(
|
||||
createTimelineResult = { Result.success(fakeTimeline) },
|
||||
roomCoroutineScope = backgroundScope,
|
||||
)
|
||||
|
|
@ -153,7 +153,7 @@ class TimelineMediaGalleryDataSourceTest {
|
|||
@Test
|
||||
fun `test - failing to load timeline should emit an error`() = runTest {
|
||||
val sut = createTimelineMediaGalleryDataSource(
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(
|
||||
createTimelineResult = { Result.failure(AN_EXCEPTION) },
|
||||
roomCoroutineScope = backgroundScope,
|
||||
)
|
||||
|
|
@ -175,7 +175,7 @@ class TimelineMediaGalleryDataSourceTest {
|
|||
timelineItems = timelineItems,
|
||||
)
|
||||
val sut = createTimelineMediaGalleryDataSource(
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(
|
||||
createTimelineResult = { Result.success(fakeTimeline) },
|
||||
roomCoroutineScope = backgroundScope,
|
||||
)
|
||||
|
|
@ -256,7 +256,7 @@ class TimelineMediaGalleryDataSourceTest {
|
|||
}
|
||||
|
||||
private fun TestScope.createTimelineMediaGalleryDataSource(
|
||||
room: MatrixRoom = FakeMatrixRoom(
|
||||
room: JoinedRoom = FakeJoinedRoom(
|
||||
liveTimeline = FakeTimeline(),
|
||||
),
|
||||
): TimelineMediaGalleryDataSource {
|
||||
|
|
|
|||
|
|
@ -12,14 +12,15 @@ import app.cash.turbine.ReceiveTurbine
|
|||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||
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.FakeBaseRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource
|
||||
|
|
@ -51,8 +52,8 @@ class MediaGalleryPresenterTest {
|
|||
mediaGalleryDataSource = FakeMediaGalleryDataSource(
|
||||
startLambda = startLambda,
|
||||
),
|
||||
room = FakeMatrixRoom(
|
||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(initialRoomInfo = aRoomInfo(name = A_ROOM_NAME)),
|
||||
createTimelineResult = { Result.success(FakeTimeline()) },
|
||||
)
|
||||
)
|
||||
|
|
@ -70,8 +71,8 @@ class MediaGalleryPresenterTest {
|
|||
@Test
|
||||
fun `present - change mode`() = runTest {
|
||||
val presenter = createMediaGalleryPresenter(
|
||||
room = FakeMatrixRoom(
|
||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(initialRoomInfo = aRoomInfo(name = A_ROOM_NAME)),
|
||||
createTimelineResult = { Result.success(FakeTimeline()) },
|
||||
)
|
||||
)
|
||||
|
|
@ -99,11 +100,13 @@ class MediaGalleryPresenterTest {
|
|||
|
||||
private suspend fun `present - bottom sheet state - own message`(canDeleteOwn: Boolean) {
|
||||
val presenter = createMediaGalleryPresenter(
|
||||
room = FakeMatrixRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||
room = FakeJoinedRoom(
|
||||
createTimelineResult = { Result.success(FakeTimeline()) },
|
||||
canRedactOwnResult = { Result.success(canDeleteOwn) }
|
||||
baseRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||
canRedactOwnResult = { Result.success(canDeleteOwn) }
|
||||
),
|
||||
)
|
||||
)
|
||||
presenter.test {
|
||||
|
|
@ -142,11 +145,13 @@ class MediaGalleryPresenterTest {
|
|||
|
||||
private suspend fun `present - bottom sheet state - other message`(canDeleteOther: Boolean) {
|
||||
val presenter = createMediaGalleryPresenter(
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
sessionId = A_USER_ID,
|
||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||
createTimelineResult = { Result.success(FakeTimeline()) },
|
||||
canRedactOtherResult = { Result.success(canDeleteOther) }
|
||||
canRedactOtherResult = { Result.success(canDeleteOther) },
|
||||
),
|
||||
createTimelineResult = { Result.success(FakeTimeline()) }
|
||||
)
|
||||
)
|
||||
presenter.test {
|
||||
|
|
@ -176,8 +181,8 @@ class MediaGalleryPresenterTest {
|
|||
@Test
|
||||
fun `present - delete bottom sheet`() = runTest {
|
||||
val presenter = createMediaGalleryPresenter(
|
||||
room = FakeMatrixRoom(
|
||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(initialRoomInfo = aRoomInfo(name = A_ROOM_NAME)),
|
||||
createTimelineResult = { Result.success(FakeTimeline()) },
|
||||
)
|
||||
)
|
||||
|
|
@ -244,7 +249,7 @@ class MediaGalleryPresenterTest {
|
|||
onViewInTimelineClickLambda = onViewInTimelineClickLambda,
|
||||
)
|
||||
val presenter = createMediaGalleryPresenter(
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(
|
||||
createTimelineResult = { Result.success(FakeTimeline()) },
|
||||
),
|
||||
navigator = navigator,
|
||||
|
|
@ -284,7 +289,7 @@ class MediaGalleryPresenterTest {
|
|||
localMediaActions: FakeLocalMediaActions = FakeLocalMediaActions(),
|
||||
snackbarDispatcher: SnackbarDispatcher = SnackbarDispatcher(),
|
||||
navigator: MediaGalleryNavigator = FakeMediaGalleryNavigator(),
|
||||
room: MatrixRoom = FakeMatrixRoom(
|
||||
room: JoinedRoom = FakeJoinedRoom(
|
||||
liveTimeline = FakeTimeline(),
|
||||
),
|
||||
): MediaGalleryPresenter {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import com.google.common.truth.Truth.assertThat
|
|||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
|
||||
|
|
@ -24,7 +24,8 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID_2
|
|||
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||
import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.test.media.aMediaSource
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
|
||||
import io.element.android.libraries.mediaviewer.api.anApkMediaInfo
|
||||
|
|
@ -77,10 +78,12 @@ class MediaViewerPresenterTest {
|
|||
@Test
|
||||
fun `present - initial state null Event`() = runTest {
|
||||
val presenter = createMediaViewerPresenter(
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
)
|
||||
)
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = awaitFirstItem()
|
||||
assertThat(initialState.listData).isEmpty()
|
||||
|
|
@ -95,10 +98,12 @@ class MediaViewerPresenterTest {
|
|||
fun `present - initial state cannot show info`() = runTest {
|
||||
val presenter = createMediaViewerPresenter(
|
||||
canShowInfo = false,
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
)
|
||||
)
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = awaitFirstItem()
|
||||
assertThat(initialState.listData).isEmpty()
|
||||
|
|
@ -113,10 +118,12 @@ class MediaViewerPresenterTest {
|
|||
fun `present - initial state Event`() = runTest {
|
||||
val presenter = createMediaViewerPresenter(
|
||||
eventId = AN_EVENT_ID,
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
)
|
||||
)
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = awaitFirstItem()
|
||||
assertThat(initialState.listData).isEmpty()
|
||||
|
|
@ -131,11 +138,13 @@ class MediaViewerPresenterTest {
|
|||
fun `present - initial state Event from other`() = runTest {
|
||||
val presenter = createMediaViewerPresenter(
|
||||
eventId = AN_EVENT_ID,
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
sessionId = A_SESSION_ID_2,
|
||||
canRedactOtherResult = { Result.success(false) },
|
||||
)
|
||||
)
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = awaitFirstItem()
|
||||
assertThat(initialState.listData).isEmpty()
|
||||
|
|
@ -216,9 +225,9 @@ class MediaViewerPresenterTest {
|
|||
)
|
||||
val presenter = createMediaViewerPresenter(
|
||||
mediaGalleryDataSource = mediaGalleryDataSource,
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(baseRoom = FakeBaseRoom(
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
)
|
||||
))
|
||||
)
|
||||
val anImage = aMediaItemImage(
|
||||
mediaSourceUrl = aUrl,
|
||||
|
|
@ -432,9 +441,9 @@ class MediaViewerPresenterTest {
|
|||
startLambda = { },
|
||||
)
|
||||
val presenter = createMediaViewerPresenter(
|
||||
room = FakeMatrixRoom(
|
||||
room = FakeJoinedRoom(
|
||||
liveTimeline = timeline,
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }),
|
||||
),
|
||||
mediaGalleryDataSource = mediaGalleryDataSource,
|
||||
mediaViewerNavigator = FakeMediaViewerNavigator(
|
||||
|
|
@ -736,8 +745,8 @@ class MediaViewerPresenterTest {
|
|||
)
|
||||
val presenter = createMediaViewerPresenter(
|
||||
mediaViewerNavigator = navigator,
|
||||
room = FakeMatrixRoom(
|
||||
canRedactOwnResult = { Result.success(true) },
|
||||
room = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }),
|
||||
)
|
||||
)
|
||||
presenter.test {
|
||||
|
|
@ -766,7 +775,7 @@ class MediaViewerPresenterTest {
|
|||
),
|
||||
canShowInfo: Boolean = true,
|
||||
mediaViewerNavigator: MediaViewerNavigator = FakeMediaViewerNavigator(),
|
||||
room: MatrixRoom = FakeMatrixRoom(
|
||||
room: JoinedRoom = FakeJoinedRoom(
|
||||
liveTimeline = FakeTimeline(),
|
||||
),
|
||||
): MediaViewerPresenter {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import io.element.android.libraries.matrix.api.core.EventId
|
|||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
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.message.replyInThread
|
||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||
|
|
@ -117,7 +117,7 @@ class NotificationBroadcastReceiverHandler @Inject constructor(
|
|||
return@launch
|
||||
}
|
||||
val client = matrixClientProvider.getOrRestore(sessionId).getOrNull() ?: return@launch
|
||||
client.getRoom(roomId)?.let { room ->
|
||||
client.getJoinedRoom(roomId)?.let { room ->
|
||||
sendMatrixEvent(
|
||||
sessionId = sessionId,
|
||||
roomId = roomId,
|
||||
|
|
@ -134,7 +134,7 @@ class NotificationBroadcastReceiverHandler @Inject constructor(
|
|||
roomId: RoomId,
|
||||
threadId: ThreadId?,
|
||||
replyToEventId: EventId?,
|
||||
room: MatrixRoom,
|
||||
room: JoinedRoom,
|
||||
message: String,
|
||||
) {
|
||||
// Create a new event to be displayed in the notification drawer, right now
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ import io.element.android.libraries.featureflag.api.FeatureFlagService
|
|||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableRingingCallEvent
|
||||
|
|
@ -37,7 +38,7 @@ class SyncOnNotifiableEvent @Inject constructor(
|
|||
}
|
||||
val client = matrixClientProvider.getOrRestore(notifiableEvent.sessionId).getOrNull() ?: return@withContext
|
||||
|
||||
client.getRoom(notifiableEvent.roomId)?.use { room ->
|
||||
client.getJoinedRoom(notifiableEvent.roomId)?.use { room ->
|
||||
room.subscribeToSync()
|
||||
|
||||
// If the app is in foreground, sync is already running, so we just add the subscription above.
|
||||
|
|
@ -60,7 +61,7 @@ class SyncOnNotifiableEvent @Inject constructor(
|
|||
* User can be in the call if they answer using another session.
|
||||
* If the user does not join the call, the timeout will be reached.
|
||||
*/
|
||||
private suspend fun MatrixRoom.waitsUntilUserIsInTheCall(timeout: Duration) {
|
||||
private suspend fun BaseRoom.waitsUntilUserIsInTheCall(timeout: Duration) {
|
||||
withTimeoutOrNull(timeout) {
|
||||
roomInfoFlow.first {
|
||||
sessionId in it.activeRoomCallParticipants
|
||||
|
|
@ -68,7 +69,7 @@ class SyncOnNotifiableEvent @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun MatrixRoom.waitsUntilEventIsKnown(eventId: EventId, timeout: Duration) {
|
||||
private suspend fun JoinedRoom.waitsUntilEventIsKnown(eventId: EventId, timeout: Duration) {
|
||||
withTimeoutOrNull(timeout) {
|
||||
liveTimeline.timelineItems.first { timelineItems ->
|
||||
timelineItems.any { timelineItem ->
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ private const val A_USER_AVATAR_1 = "mxc://userAvatar1"
|
|||
private const val A_USER_AVATAR_2 = "mxc://userAvatar2"
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class DefaultRoomGroupMessageCreatorTest {
|
||||
class DefaultBaseRoomGroupMessageCreatorTest {
|
||||
@Test
|
||||
fun `test createRoomMessage with one Event`() = runTest {
|
||||
val sut = createRoomGroupMessageCreator()
|
||||
|
|
@ -27,7 +27,8 @@ import io.element.android.libraries.matrix.test.A_THREAD_ID
|
|||
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.FakeBaseRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||
import io.element.android.libraries.matrix.test.room.aRoomMember
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
|
|
@ -50,6 +51,7 @@ import io.element.android.tests.testutils.lambda.value
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
|
@ -221,13 +223,13 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
getLambda = getLambda
|
||||
)
|
||||
val clearMessagesForRoomLambda = lambdaRecorder<SessionId, RoomId, Unit> { _, _ -> }
|
||||
val matrixRoom = FakeMatrixRoom()
|
||||
val joinedRoom = FakeJoinedRoom()
|
||||
val fakeNotificationCleaner = FakeNotificationCleaner(
|
||||
clearMessagesForRoomLambda = clearMessagesForRoomLambda,
|
||||
)
|
||||
val sut = createNotificationBroadcastReceiverHandler(
|
||||
sessionPreferencesStore = sessionPreferencesStore,
|
||||
matrixRoom = matrixRoom,
|
||||
joinedRoom = joinedRoom,
|
||||
notificationCleaner = fakeNotificationCleaner
|
||||
)
|
||||
sut.onReceive(
|
||||
|
|
@ -240,7 +242,7 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
clearMessagesForRoomLambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(value(A_SESSION_ID), value(A_ROOM_ID))
|
||||
assertThat(matrixRoom.markAsReadCalls).isEqualTo(listOf(expectedReceiptType))
|
||||
assertThat(joinedRoom.baseRoom.markAsReadCalls).isEqualTo(listOf(expectedReceiptType))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -292,15 +294,15 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
@Test
|
||||
fun `Test reject room`() = runTest {
|
||||
val leaveRoom = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
leaveRoomLambda = leaveRoom
|
||||
val joinedRoom = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(leaveRoomLambda = leaveRoom),
|
||||
)
|
||||
val clearMembershipNotificationForRoomLambda = lambdaRecorder<SessionId, RoomId, Unit> { _, _ -> }
|
||||
val fakeNotificationCleaner = FakeNotificationCleaner(
|
||||
clearMembershipNotificationForRoomLambda = clearMembershipNotificationForRoomLambda,
|
||||
)
|
||||
val sut = createNotificationBroadcastReceiverHandler(
|
||||
matrixRoom = matrixRoom,
|
||||
joinedRoom = joinedRoom,
|
||||
notificationCleaner = fakeNotificationCleaner
|
||||
)
|
||||
sut.onReceive(
|
||||
|
|
@ -313,6 +315,9 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
clearMembershipNotificationForRoomLambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(value(A_SESSION_ID), value(A_ROOM_ID))
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
leaveRoom.assertions()
|
||||
.isCalledOnce()
|
||||
.with()
|
||||
|
|
@ -337,9 +342,9 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
sendMessageLambda = sendMessage
|
||||
replyMessageLambda = replyMessage
|
||||
}
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeJoinedRoom(
|
||||
liveTimeline = liveTimeline,
|
||||
getUpdatedMemberResult = { Result.success(aRoomMember()) },
|
||||
baseRoom = FakeBaseRoom(getUpdatedMemberResult = { Result.success(aRoomMember()) }),
|
||||
).apply {
|
||||
givenRoomInfo(
|
||||
aRoomInfo(
|
||||
|
|
@ -351,7 +356,7 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
val onNotifiableEventReceivedResult = lambdaRecorder<NotifiableEvent, Unit> { _ -> }
|
||||
val onNotifiableEventReceived = FakeOnNotifiableEventReceived(onNotifiableEventReceivedResult = onNotifiableEventReceivedResult)
|
||||
val sut = createNotificationBroadcastReceiverHandler(
|
||||
matrixRoom = matrixRoom,
|
||||
joinedRoom = joinedRoom,
|
||||
onNotifiableEventReceived = onNotifiableEventReceived,
|
||||
replyMessageExtractor = FakeReplyMessageExtractor(A_MESSAGE)
|
||||
)
|
||||
|
|
@ -377,11 +382,11 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
val liveTimeline = FakeTimeline().apply {
|
||||
sendMessageLambda = sendMessage
|
||||
}
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeJoinedRoom(
|
||||
liveTimeline = liveTimeline
|
||||
)
|
||||
val sut = createNotificationBroadcastReceiverHandler(
|
||||
matrixRoom = matrixRoom,
|
||||
joinedRoom = joinedRoom,
|
||||
replyMessageExtractor = FakeReplyMessageExtractor(" "),
|
||||
)
|
||||
sut.onReceive(
|
||||
|
|
@ -404,9 +409,9 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
sendMessageLambda = sendMessage
|
||||
replyMessageLambda = replyMessage
|
||||
}
|
||||
val matrixRoom = FakeMatrixRoom(
|
||||
val joinedRoom = FakeJoinedRoom(
|
||||
liveTimeline = liveTimeline,
|
||||
getUpdatedMemberResult = { Result.success(aRoomMember()) },
|
||||
baseRoom = FakeBaseRoom(getUpdatedMemberResult = { Result.success(aRoomMember()) }),
|
||||
).apply {
|
||||
givenRoomInfo(
|
||||
aRoomInfo(
|
||||
|
|
@ -418,7 +423,7 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
val onNotifiableEventReceivedResult = lambdaRecorder<NotifiableEvent, Unit> { _ -> }
|
||||
val onNotifiableEventReceived = FakeOnNotifiableEventReceived(onNotifiableEventReceivedResult = onNotifiableEventReceivedResult)
|
||||
val sut = createNotificationBroadcastReceiverHandler(
|
||||
matrixRoom = matrixRoom,
|
||||
joinedRoom = joinedRoom,
|
||||
onNotifiableEventReceived = onNotifiableEventReceived,
|
||||
replyMessageExtractor = FakeReplyMessageExtractor(A_MESSAGE)
|
||||
)
|
||||
|
|
@ -460,10 +465,10 @@ class NotificationBroadcastReceiverHandlerTest {
|
|||
}
|
||||
|
||||
private fun TestScope.createNotificationBroadcastReceiverHandler(
|
||||
matrixRoom: FakeMatrixRoom? = FakeMatrixRoom(),
|
||||
joinedRoom: FakeJoinedRoom? = FakeJoinedRoom(),
|
||||
joinRoom: (RoomId) -> Result<RoomSummary?> = { lambdaError() },
|
||||
matrixClient: MatrixClient? = FakeMatrixClient().apply {
|
||||
givenGetRoomResult(A_ROOM_ID, matrixRoom)
|
||||
givenGetRoomResult(A_ROOM_ID, joinedRoom)
|
||||
joinRoomLambda = joinRoom
|
||||
},
|
||||
sessionPreferencesStore: SessionPreferencesStoreFactory = FakeSessionPreferencesStoreFactory(),
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
|
|||
import io.element.android.libraries.matrix.test.A_UNIQUE_ID
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||
import io.element.android.libraries.matrix.test.sync.FakeSyncService
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
|
|
@ -49,10 +50,12 @@ class SyncOnNotifiableEventTest {
|
|||
private val liveTimeline = FakeTimeline(
|
||||
timelineItems = timelineItems,
|
||||
)
|
||||
private val room = FakeMatrixRoom(
|
||||
roomId = A_ROOM_ID,
|
||||
private val room = FakeJoinedRoom(
|
||||
liveTimeline = liveTimeline,
|
||||
subscribeToSyncLambda = subscribeToSyncLambda
|
||||
baseRoom = FakeBaseRoom(
|
||||
roomId = A_ROOM_ID,
|
||||
subscribeToSyncLambda = subscribeToSyncLambda,
|
||||
),
|
||||
)
|
||||
private val syncService = FakeSyncService(SyncState.Idle).also {
|
||||
it.startSyncLambda = startSyncLambda
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import io.element.android.libraries.core.hash.md5
|
|||
import io.element.android.libraries.di.CacheDirectory
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
|
@ -21,7 +21,7 @@ import javax.inject.Inject
|
|||
class DefaultVoiceFileManager @Inject constructor(
|
||||
@CacheDirectory private val cacheDir: File,
|
||||
private val config: VoiceFileConfig,
|
||||
room: MatrixRoom,
|
||||
room: BaseRoom,
|
||||
) : VoiceFileManager {
|
||||
private val roomId: RoomId = room.roomId
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue