From 39fcb1bb80c2b0ca901a5471ad8193f7ae630d4c Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 20 Jun 2023 23:22:58 +0200 Subject: [PATCH] RoomList: make the main room list working (WIP) --- .../matrix/api/room/RoomSummaryDataSource.kt | 9 ++ .../libraries/matrix/impl/RustMatrixClient.kt | 114 ++------------ .../matrix/impl/room/RoomListFlows.kt | 48 ++++++ .../impl/room/RoomSummaryDetailsFactory.kt | 15 +- .../matrix/impl/room/RustMatrixRoom.kt | 26 ++-- .../impl/room/RustRoomSummaryDataSource.kt | 144 +++++++----------- .../matrix/impl/sync/SlidingSyncListFlows.kt | 62 -------- .../impl/sync/SlidingSyncObserverProxy.kt | 43 ------ .../timeline/MatrixTimelineDiffProcessor.kt | 4 +- .../impl/timeline/RustMatrixTimeline.kt | 9 +- 10 files changed, 146 insertions(+), 328 deletions(-) create mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomListFlows.kt delete mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/SlidingSyncListFlows.kt delete mode 100644 libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/SlidingSyncObserverProxy.kt diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomSummaryDataSource.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomSummaryDataSource.kt index 0e71dd2558..6473a45bc7 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomSummaryDataSource.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/RoomSummaryDataSource.kt @@ -19,6 +19,15 @@ package io.element.android.libraries.matrix.api.room import kotlinx.coroutines.flow.StateFlow interface RoomSummaryDataSource { + + enum class LoadingState { + NotLoaded, + PreLoaded, + PartiallyLoaded, + FullyLoaded, + } + + fun loadingState(): StateFlow fun roomSummaries(): StateFlow> fun setSlidingSyncRange(range: IntRange) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index d8cd8c480f..e0cf58d3de 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -31,7 +31,6 @@ 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.RoomMembershipObserver import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource -import io.element.android.libraries.matrix.api.timeline.item.event.EventType import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.verification.SessionVerificationService @@ -40,7 +39,6 @@ import io.element.android.libraries.matrix.impl.notification.RustNotificationSer import io.element.android.libraries.matrix.impl.pushers.RustPushersService import io.element.android.libraries.matrix.impl.room.RustMatrixRoom import io.element.android.libraries.matrix.impl.room.RustRoomSummaryDataSource -import io.element.android.libraries.matrix.impl.sync.SlidingSyncObserverProxy import io.element.android.libraries.matrix.impl.usersearch.UserProfileMapper import io.element.android.libraries.matrix.impl.usersearch.UserSearchResultMapper import io.element.android.libraries.matrix.impl.verification.RustSessionVerificationService @@ -50,21 +48,12 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeout import org.matrix.rustcomponents.sdk.Client import org.matrix.rustcomponents.sdk.ClientDelegate -import org.matrix.rustcomponents.sdk.RequiredState -import org.matrix.rustcomponents.sdk.SlidingSyncList -import org.matrix.rustcomponents.sdk.SlidingSyncListBuilder -import org.matrix.rustcomponents.sdk.SlidingSyncListOnceBuilt -import org.matrix.rustcomponents.sdk.SlidingSyncRequestListFilters -import org.matrix.rustcomponents.sdk.SlidingSyncSelectiveModeBuilder import org.matrix.rustcomponents.sdk.TaskHandle import org.matrix.rustcomponents.sdk.use import timber.log.Timber @@ -101,75 +90,11 @@ class RustMatrixClient constructor( } } - private val visibleRoomsSlidingSyncFilters = SlidingSyncRequestListFilters( - isDm = null, - spaces = emptyList(), - isEncrypted = null, - isInvite = false, - isTombstoned = false, - roomTypes = emptyList(), - notRoomTypes = listOf("m.space"), - roomNameLike = null, - tags = emptyList(), - notTags = emptyList() - ) + private val roomList = client.roomList() - private val visibleRoomsSlidingSyncList = MutableSharedFlow(replay = 1) - private val visibleRoomsSlidingSyncListBuilder = SlidingSyncListBuilder("CurrentlyVisibleRooms") - .timelineLimit(limit = 1u) - .requiredState( - requiredState = listOf( - RequiredState(key = EventType.STATE_ROOM_AVATAR, value = ""), - RequiredState(key = EventType.STATE_ROOM_ENCRYPTION, value = ""), - RequiredState(key = EventType.STATE_ROOM_JOIN_RULES, value = ""), - ) - ) - .filters(visibleRoomsSlidingSyncFilters) - .syncModeSelective(SlidingSyncSelectiveModeBuilder().addRange(0u, 20u)) - .onceBuilt(object : SlidingSyncListOnceBuilt { - override fun updateList(list: SlidingSyncList): SlidingSyncList { - visibleRoomsSlidingSyncList.tryEmit(list) - return list - } - }) - - private val invitesSlidingSyncFilters = visibleRoomsSlidingSyncFilters.copy(isInvite = true) - - private val invitesSlidingSyncList = MutableSharedFlow(replay = 1) - private val invitesSlidingSyncListBuilder = SlidingSyncListBuilder("CurrentInvites") - .timelineLimit(limit = 1u) - .requiredState( - requiredState = listOf( - RequiredState(key = EventType.STATE_ROOM_AVATAR, value = ""), - RequiredState(key = EventType.STATE_ROOM_ENCRYPTION, value = ""), - RequiredState(key = EventType.STATE_ROOM_CANONICAL_ALIAS, value = ""), - ) - ) - .filters(invitesSlidingSyncFilters) - .syncModeSelective(SlidingSyncSelectiveModeBuilder().addRange(0u, 20u)) - .onceBuilt(object : SlidingSyncListOnceBuilt { - override fun updateList(list: SlidingSyncList): SlidingSyncList { - invitesSlidingSyncList.tryEmit(list) - return list - } - }) - - private val slidingSync = client - .slidingSync("ElementX") - // .homeserver("https://slidingsync.lab.matrix.org") - .withCommonExtensions() - .addList(visibleRoomsSlidingSyncListBuilder) - .addList(invitesSlidingSyncListBuilder) - .use { - it.build() - } - - private val slidingSyncObserverProxy = SlidingSyncObserverProxy(coroutineScope) private val rustRoomSummaryDataSource: RustRoomSummaryDataSource = RustRoomSummaryDataSource( - slidingSyncObserverProxy.updateSummaryFlow, - slidingSync, - visibleRoomsSlidingSyncList, + roomList, dispatchers, ) @@ -178,9 +103,7 @@ class RustMatrixClient constructor( private val rustInvitesDataSource: RustRoomSummaryDataSource = RustRoomSummaryDataSource( - slidingSyncObserverProxy.updateSummaryFlow, - slidingSync, - invitesSlidingSyncList, + roomList, dispatchers, ) @@ -199,25 +122,19 @@ class RustMatrixClient constructor( init { client.setDelegate(clientDelegate) - rustRoomSummaryDataSource.init() - rustInvitesDataSource.init() - slidingSync.setObserver(slidingSyncObserverProxy) - slidingSyncUpdateJob = slidingSyncObserverProxy.updateSummaryFlow - .onEach { onSlidingSyncUpdate() } - .launchIn(coroutineScope) + rustRoomSummaryDataSource.subscribeIfNeeded() + //rustInvitesDataSource.init() } override fun getRoom(roomId: RoomId): MatrixRoom? { - val slidingSyncRoom = slidingSync.getRoom(roomId.value) ?: return null - val fullRoom = slidingSyncRoom.fullRoom() ?: return null + val roomListItem = roomList.room(roomId.value) + val fullRoom = roomListItem.fullRoom() return RustMatrixRoom( sessionId = sessionId, - slidingSyncUpdateFlow = slidingSyncObserverProxy.updateSummaryFlow, - slidingSyncRoom = slidingSyncRoom, + roomListItem = roomListItem, innerRoom = fullRoom, coroutineScope = coroutineScope, coroutineDispatchers = dispatchers, - clock = clock, ) } @@ -261,9 +178,11 @@ class RustMatrixClient constructor( // Wait to receive the room back from the sync withTimeout(30_000L) { - slidingSyncObserverProxy.updateSummaryFlow.filter { roomId.value in it.rooms }.first() + roomSummaryDataSource.roomSummaries() + .filter { roomSummaries -> + roomSummaries.map { it.identifier() }.contains(roomId.value) + }.first() } - roomId } } @@ -301,7 +220,7 @@ class RustMatrixClient constructor( override fun startSync() { if (isSyncing.compareAndSet(false, true)) { - slidingSyncObserverToken = slidingSync.sync() + slidingSyncObserverToken = roomList.sync() } } @@ -314,16 +233,11 @@ class RustMatrixClient constructor( override fun close() { slidingSyncUpdateJob?.cancel() stopSync() - slidingSync.setObserver(null) rustRoomSummaryDataSource.close() rustInvitesDataSource.close() client.setDelegate(null) - visibleRoomsSlidingSyncListBuilder.destroy() - invitesSlidingSyncListBuilder.destroy() - visibleRoomsSlidingSyncList.resetReplayCache() - invitesSlidingSyncList.resetReplayCache() - slidingSync.destroy() verificationService.destroy() + roomList.destroy() client.destroy() } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomListFlows.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomListFlows.kt new file mode 100644 index 0000000000..e9d34e468d --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomListFlows.kt @@ -0,0 +1,48 @@ +package io.element.android.libraries.matrix.impl.room + +import io.element.android.libraries.matrix.impl.util.mxCallbackFlow +import kotlinx.coroutines.channels.trySendBlocking +import kotlinx.coroutines.flow.Flow +import org.matrix.rustcomponents.sdk.RoomList +import org.matrix.rustcomponents.sdk.RoomListEntriesListener +import org.matrix.rustcomponents.sdk.RoomListEntriesUpdate +import org.matrix.rustcomponents.sdk.RoomListEntry +import org.matrix.rustcomponents.sdk.RoomListState +import org.matrix.rustcomponents.sdk.RoomListStateListener +import org.matrix.rustcomponents.sdk.SlidingSyncListLoadingState +import org.matrix.rustcomponents.sdk.SlidingSyncListStateObserver + +fun RoomList.stateFlow(): Flow = + mxCallbackFlow { + val listener = object : RoomListStateListener { + override fun onUpdate(state: RoomListState) { + trySendBlocking(state) + } + } + state(listener) + } + +fun RoomList.loadingStateFlow(): Flow = + mxCallbackFlow { + val listener = object : SlidingSyncListStateObserver { + override fun didReceiveUpdate(newState: SlidingSyncListLoadingState) { + trySendBlocking(newState) + } + } + val result = entriesLoadingState(listener) + send(result.entriesLoadingState) + result.entriesLoadingStateStream + } + +fun RoomList.roomListEntriesUpdateFlow(onInitialList: suspend (List) -> Unit): Flow = + mxCallbackFlow { + val listener = object : RoomListEntriesListener { + override fun onUpdate(roomEntriesUpdate: RoomListEntriesUpdate) { + trySendBlocking(roomEntriesUpdate) + } + } + val result = entries(listener) + onInitialList(result.entries) + result.entriesStream + } + diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSummaryDetailsFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSummaryDetailsFactory.kt index 1f8be2fa21..40ae88bb9a 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSummaryDetailsFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSummaryDetailsFactory.kt @@ -20,27 +20,24 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.room.RoomSummaryDetails import io.element.android.libraries.matrix.impl.room.message.RoomMessageFactory import org.matrix.rustcomponents.sdk.Room -import org.matrix.rustcomponents.sdk.SlidingSyncRoom +import org.matrix.rustcomponents.sdk.RoomListItem class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory()) { - fun create(slidingSyncRoom: SlidingSyncRoom, room: Room?): RoomSummaryDetails { - val latestRoomMessage = slidingSyncRoom.latestRoomMessage()?.use { + fun create(roomListItem: RoomListItem, room: Room?): RoomSummaryDetails { + val latestRoomMessage = roomListItem.latestEvent()?.use { roomMessageFactory.create(it) } - return RoomSummaryDetails( - roomId = RoomId(slidingSyncRoom.roomId()), - name = slidingSyncRoom.name() ?: slidingSyncRoom.roomId(), + roomId = RoomId(roomListItem.id()), + name = roomListItem.name() ?: roomListItem.id(), canonicalAlias = room?.canonicalAlias(), isDirect = room?.isDirect() ?: false, avatarURLString = room?.avatarUrl(), - unreadNotificationCount = slidingSyncRoom.unreadNotifications().use { it.notificationCount().toInt() }, + unreadNotificationCount = roomListItem.unreadNotifications().use { it.notificationCount().toInt() }, lastMessage = latestRoomMessage, lastMessageTimestamp = latestRoomMessage?.originServerTs, inviter = room?.inviter()?.let(RoomMemberMapper::map), ) } - - } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt index 8452ef193b..dd33c99d47 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt @@ -34,30 +34,28 @@ import io.element.android.libraries.matrix.impl.media.map import io.element.android.libraries.matrix.impl.timeline.RustMatrixTimeline import io.element.android.services.toolbox.api.systemclock.SystemClock import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.Room +import org.matrix.rustcomponents.sdk.RoomListEntriesUpdate +import org.matrix.rustcomponents.sdk.RoomListItem import org.matrix.rustcomponents.sdk.RoomMember -import org.matrix.rustcomponents.sdk.SlidingSyncRoom -import org.matrix.rustcomponents.sdk.UpdateSummary import org.matrix.rustcomponents.sdk.genTransactionId import org.matrix.rustcomponents.sdk.messageEventContentFromMarkdown import java.io.File class RustMatrixRoom( override val sessionId: SessionId, - private val slidingSyncUpdateFlow: Flow, - private val slidingSyncRoom: SlidingSyncRoom, + private val roomListItem: RoomListItem, private val innerRoom: Room, private val coroutineScope: CoroutineScope, private val coroutineDispatchers: CoroutineDispatchers, - private val clock: SystemClock, ) : MatrixRoom { override val membersStateFlow: StateFlow @@ -69,21 +67,15 @@ class RustMatrixRoom( RustMatrixTimeline( matrixRoom = this, innerRoom = innerRoom, - slidingSyncRoom = slidingSyncRoom, + roomListItem = roomListItem, coroutineScope = coroutineScope, coroutineDispatchers = coroutineDispatchers ) } override fun syncUpdateFlow(): Flow { - return slidingSyncUpdateFlow - .filter { - it.rooms.contains(roomId.value) - } - .map { - clock.epochMillis() - } - .onStart { emit(clock.epochMillis()) } + //TODO branch this somehow... + return emptyFlow() } override fun timeline(): MatrixTimeline { @@ -92,14 +84,14 @@ class RustMatrixRoom( override fun close() { innerRoom.destroy() - slidingSyncRoom.destroy() + roomListItem.destroy() } override val roomId = RoomId(innerRoom.id()) override val name: String? get() { - return slidingSyncRoom.name() + return roomListItem.name() } override val bestName: String diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomSummaryDataSource.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomSummaryDataSource.kt index 34c0a9cb48..bf32155db8 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomSummaryDataSource.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomSummaryDataSource.kt @@ -19,36 +19,27 @@ package io.element.android.libraries.matrix.impl.room import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.api.room.RoomSummary import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource -import io.element.android.libraries.matrix.impl.sync.roomListDiff -import io.element.android.libraries.matrix.impl.sync.state import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext +import org.matrix.rustcomponents.sdk.RoomList +import org.matrix.rustcomponents.sdk.RoomListEntriesUpdate import org.matrix.rustcomponents.sdk.RoomListEntry -import org.matrix.rustcomponents.sdk.SlidingSync -import org.matrix.rustcomponents.sdk.SlidingSyncList -import org.matrix.rustcomponents.sdk.SlidingSyncListRoomsListDiff -import org.matrix.rustcomponents.sdk.SlidingSyncSelectiveModeBuilder +import org.matrix.rustcomponents.sdk.RoomListInput +import org.matrix.rustcomponents.sdk.RoomListRange import org.matrix.rustcomponents.sdk.SlidingSyncListLoadingState -import org.matrix.rustcomponents.sdk.UpdateSummary import timber.log.Timber import java.io.Closeable import java.util.UUID internal class RustRoomSummaryDataSource( - private val slidingSyncUpdateFlow: Flow, - private val slidingSync: SlidingSync, - private val slidingSyncListFlow: Flow, + private val roomList: RoomList, private val coroutineDispatchers: CoroutineDispatchers, private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory(), ) : RoomSummaryDataSource, Closeable { @@ -56,39 +47,24 @@ internal class RustRoomSummaryDataSource( private val coroutineScope = CoroutineScope(SupervisorJob() + coroutineDispatchers.io) private val roomSummaries = MutableStateFlow>(emptyList()) - private val state = MutableStateFlow(SlidingSyncListLoadingState.NOT_LOADED) + private val loadingState = MutableStateFlow(RoomSummaryDataSource.LoadingState.NotLoaded) - fun init() { + fun subscribeIfNeeded() { coroutineScope.launch { - val slidingSyncList = slidingSyncListFlow.first() - val summaries = slidingSyncList.currentRoomList().map(::buildSummaryForRoomListEntry) - updateRoomSummaries { - addAll(summaries) - } - - slidingSyncList.roomListDiff(this) - .onEach { diffs -> - updateRoomSummaries { - applyDiff(diffs) - } + roomList.roomListEntriesUpdateFlow { roomListEntries -> + val summaries = roomListEntries.map(::buildSummaryForRoomListEntry) + updateRoomSummaries { + addAll(summaries) } - .launchIn(this) - - slidingSyncList.state(this) - .onEach { slidingSyncState -> - Timber.v("New sliding sync state: $slidingSyncState") - state.value = slidingSyncState - }.launchIn(this) + }.onEach { + updateRoomSummaries { + applyUpdate(it) + } + }.launchIn(this) } - - slidingSyncUpdateFlow - .onEach { - didReceiveSyncUpdate(it) - }.launchIn(coroutineScope) } override fun close() { - runBlocking { slidingSyncListFlow.firstOrNull() }?.close() coroutineScope.cancel() } @@ -96,77 +72,64 @@ internal class RustRoomSummaryDataSource( return roomSummaries } + override fun loadingState(): StateFlow { + return loadingState + } + override fun setSlidingSyncRange(range: IntRange) { Timber.v("setVisibleRange=$range") coroutineScope.launch { - val slidingSyncMode = SlidingSyncSelectiveModeBuilder() - .addRange(range.first.toUInt(), range.last.toUInt()) - slidingSyncListFlow.first().setSyncMode(slidingSyncMode) + val ranges = listOf(RoomListRange(range.first.toUInt(), range.last.toUInt())) + roomList.applyInput( + RoomListInput.Viewport(ranges) + ) } } - private suspend fun didReceiveSyncUpdate(summary: UpdateSummary) { - Timber.v("UpdateRooms with identifiers: ${summary.rooms}") - if (state.value != SlidingSyncListLoadingState.FULLY_LOADED) { - return - } - updateRoomSummaries { - for (identifier in summary.rooms) { - val index = indexOfFirst { it.identifier() == identifier } - if (index == -1) { - continue - } - val updatedRoomSummary = buildRoomSummaryForIdentifier(identifier) - set(index, updatedRoomSummary) - } - } - } - - private fun MutableList.applyDiff(diff: SlidingSyncListRoomsListDiff) { + private fun MutableList.applyUpdate(update: RoomListEntriesUpdate) { fun MutableList.fillUntil(untilIndex: Int) { repeat((size - 1 until untilIndex).count()) { add(buildEmptyRoomSummary()) } } - Timber.v("ApplyDiff: $diff for list with size: $size") - when (diff) { - is SlidingSyncListRoomsListDiff.Append -> { - val roomSummaries = diff.values.map { + when (update) { + is RoomListEntriesUpdate.Append -> { + val roomSummaries = update.values.map { buildSummaryForRoomListEntry(it) } addAll(roomSummaries) } - is SlidingSyncListRoomsListDiff.PushBack -> { - val roomSummary = buildSummaryForRoomListEntry(diff.value) + is RoomListEntriesUpdate.PushBack -> { + val roomSummary = buildSummaryForRoomListEntry(update.value) add(roomSummary) } - is SlidingSyncListRoomsListDiff.PushFront -> { - val roomSummary = buildSummaryForRoomListEntry(diff.value) + is RoomListEntriesUpdate.PushFront -> { + val roomSummary = buildSummaryForRoomListEntry(update.value) add(0, roomSummary) } - is SlidingSyncListRoomsListDiff.Set -> { - fillUntil(diff.index.toInt()) - val roomSummary = buildSummaryForRoomListEntry(diff.value) - set(diff.index.toInt(), roomSummary) + is RoomListEntriesUpdate.Set -> { + fillUntil(update.index.toInt()) + val roomSummary = buildSummaryForRoomListEntry(update.value) + set(update.index.toInt(), roomSummary) } - is SlidingSyncListRoomsListDiff.Insert -> { - val roomSummary = buildSummaryForRoomListEntry(diff.value) - add(diff.index.toInt(), roomSummary) + is RoomListEntriesUpdate.Insert -> { + val roomSummary = buildSummaryForRoomListEntry(update.value) + add(update.index.toInt(), roomSummary) } - is SlidingSyncListRoomsListDiff.Remove -> { - removeAt(diff.index.toInt()) + is RoomListEntriesUpdate.Remove -> { + removeAt(update.index.toInt()) } - is SlidingSyncListRoomsListDiff.Reset -> { + is RoomListEntriesUpdate.Reset -> { clear() - addAll(diff.values.map { buildSummaryForRoomListEntry(it) }) + addAll(update.values.map { buildSummaryForRoomListEntry(it) }) } - SlidingSyncListRoomsListDiff.PopBack -> { + RoomListEntriesUpdate.PopBack -> { removeFirstOrNull() } - SlidingSyncListRoomsListDiff.PopFront -> { + RoomListEntriesUpdate.PopFront -> { removeLastOrNull() } - SlidingSyncListRoomsListDiff.Clear -> { + RoomListEntriesUpdate.Clear -> { clear() } } @@ -185,14 +148,13 @@ internal class RustRoomSummaryDataSource( } private fun buildRoomSummaryForIdentifier(identifier: String): RoomSummary { - val slidingSyncRoom = slidingSync.getRoom(identifier) ?: return RoomSummary.Empty(identifier) - val fullRoom = slidingSyncRoom.fullRoom() - val roomSummary = RoomSummary.Filled( - details = roomSummaryDetailsFactory.create(slidingSyncRoom, fullRoom) - ) - fullRoom?.destroy() - slidingSyncRoom.destroy() - return roomSummary + return roomList.room(identifier).use { roomListItem -> + roomListItem.fullRoom().use { fullRoom -> + RoomSummary.Filled( + details = roomSummaryDetailsFactory.create(roomListItem, fullRoom) + ) + } + } } private suspend fun updateRoomSummaries(block: MutableList.() -> Unit) = diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/SlidingSyncListFlows.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/SlidingSyncListFlows.kt deleted file mode 100644 index eb8019a79d..0000000000 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/SlidingSyncListFlows.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2023 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.element.android.libraries.matrix.impl.sync - -import io.element.android.libraries.matrix.impl.util.mxCallbackFlow -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.launch -import org.matrix.rustcomponents.sdk.SlidingSyncList -import org.matrix.rustcomponents.sdk.SlidingSyncListLoadingState -import org.matrix.rustcomponents.sdk.SlidingSyncListRoomListObserver -import org.matrix.rustcomponents.sdk.SlidingSyncListRoomsCountObserver -import org.matrix.rustcomponents.sdk.SlidingSyncListRoomsListDiff -import org.matrix.rustcomponents.sdk.SlidingSyncListStateObserver - -fun SlidingSyncList.roomListDiff(scope: CoroutineScope): Flow = - mxCallbackFlow { - val observer = object : SlidingSyncListRoomListObserver { - override fun didReceiveUpdate(diff: SlidingSyncListRoomsListDiff) { - scope.launch { - send(diff) - } - } - } - observeRoomList(observer) - } - -fun SlidingSyncList.state(scope: CoroutineScope): Flow = mxCallbackFlow { - val observer = object : SlidingSyncListStateObserver { - override fun didReceiveUpdate(newState: SlidingSyncListLoadingState) { - scope.launch { - send(newState) - } - } - } - observeState(observer) -} - -fun SlidingSyncList.roomsCount(scope: CoroutineScope): Flow = mxCallbackFlow { - val observer = object : SlidingSyncListRoomsCountObserver { - override fun didReceiveUpdate(count: UInt) { - scope.launch { - send(count) - } - } - } - observeRoomsCount(observer) -} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/SlidingSyncObserverProxy.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/SlidingSyncObserverProxy.kt deleted file mode 100644 index e37c6e0854..0000000000 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/sync/SlidingSyncObserverProxy.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.element.android.libraries.matrix.impl.sync - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.asSharedFlow -import kotlinx.coroutines.launch -import org.matrix.rustcomponents.sdk.SlidingSyncObserver -import org.matrix.rustcomponents.sdk.UpdateSummary - -// Sounds like a reasonable buffer size before it suspends emitting new items. -private const val BUFFER_SIZE = 64 - -class SlidingSyncObserverProxy( - private val coroutineScope: CoroutineScope, -) : SlidingSyncObserver { - - private val updateSummaryMutableFlow = - MutableSharedFlow(extraBufferCapacity = BUFFER_SIZE) - val updateSummaryFlow: SharedFlow = updateSummaryMutableFlow.asSharedFlow() - - override fun didReceiveSyncUpdate(summary: UpdateSummary) { - coroutineScope.launch { - updateSummaryMutableFlow.emit(summary) - } - } -} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineDiffProcessor.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineDiffProcessor.kt index 7d299519a5..d44f112f38 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineDiffProcessor.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineDiffProcessor.kt @@ -37,10 +37,10 @@ internal class MatrixTimelineDiffProcessor( private val timelineItemFactory: MatrixTimelineItemMapper, ) : TimelineListener { - override fun onUpdate(update: TimelineDiff) { + override fun onUpdate(diff: TimelineDiff) { coroutineScope.launch { updateTimelineItems { - applyDiff(update) + applyDiff(diff) } when (val firstItem = timelineItems.value.firstOrNull()) { is MatrixTimelineItem.Virtual -> updateBackPaginationState(firstItem.virtual) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt index 4b07d59970..980c427737 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustMatrixTimeline.kt @@ -38,6 +38,7 @@ import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.PaginationOptions import org.matrix.rustcomponents.sdk.RequiredState import org.matrix.rustcomponents.sdk.Room +import org.matrix.rustcomponents.sdk.RoomListItem import org.matrix.rustcomponents.sdk.RoomSubscription import org.matrix.rustcomponents.sdk.SlidingSyncRoom import org.matrix.rustcomponents.sdk.TimelineItem @@ -48,7 +49,7 @@ import java.util.concurrent.atomic.AtomicBoolean class RustMatrixTimeline( private val matrixRoom: MatrixRoom, private val innerRoom: Room, - private val slidingSyncRoom: SlidingSyncRoom, + private val roomListItem: RoomListItem, private val coroutineScope: CoroutineScope, private val coroutineDispatchers: CoroutineDispatchers, ) : MatrixTimeline { @@ -166,12 +167,12 @@ class RustMatrixTimeline( ), timelineLimit = null ) - slidingSyncRoom.subscribeToRoom(settings) - val result = slidingSyncRoom.addTimelineListener(timelineListener) + roomListItem.subscribe(settings) + val result = innerRoom.addTimelineListener(timelineListener) launch { fetchMembers() } - listenerTokens += result.taskHandle + listenerTokens += result.itemsStream result.items } }