From 247f6d2188ce9157ccda25068f6318b9d2069bd5 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 24 Feb 2023 15:05:20 +0100 Subject: [PATCH] Update rust-sdk (from maven) --- .../messages/timeline/TimelinePresenter.kt | 15 ---- .../factories/TimelineItemsFactory.kt | 13 ---- gradle/libs.versions.toml | 1 + libraries/matrix/build.gradle.kts | 3 +- .../libraries/matrix/RustMatrixClient.kt | 4 +- .../matrix/room/RoomSummaryDataSource.kt | 38 +++++----- .../matrix/timeline/MatrixTimeline.kt | 7 -- .../matrix/timeline/RustMatrixTimeline.kt | 69 ++++++++++++------- .../libraries/matrix/util/CallbackFlow.kt | 7 +- ...{StoppableSpawnBag.kt => TaskHandleBag.kt} | 10 +-- samples/minimal/build.gradle.kts | 1 + .../android/samples/minimal/RoomListScreen.kt | 14 ++-- 12 files changed, 86 insertions(+), 96 deletions(-) rename libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/util/{StoppableSpawnBag.kt => TaskHandleBag.kt} (71%) diff --git a/features/messages/src/main/kotlin/io/element/android/features/messages/timeline/TimelinePresenter.kt b/features/messages/src/main/kotlin/io/element/android/features/messages/timeline/TimelinePresenter.kt index d1b9145586..aff82273b9 100644 --- a/features/messages/src/main/kotlin/io/element/android/features/messages/timeline/TimelinePresenter.kt +++ b/features/messages/src/main/kotlin/io/element/android/features/messages/timeline/TimelinePresenter.kt @@ -28,8 +28,6 @@ import io.element.android.features.messages.timeline.factories.TimelineItemsFact import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.core.EventId import io.element.android.libraries.matrix.room.MatrixRoom -import io.element.android.libraries.matrix.timeline.MatrixTimeline -import io.element.android.libraries.matrix.timeline.MatrixTimelineItem import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn @@ -47,17 +45,6 @@ class TimelinePresenter @Inject constructor( private val timeline = room.timeline() - private class TimelineCallback( - private val coroutineScope: CoroutineScope, - private val timelineItemsFactory: TimelineItemsFactory, - ) : MatrixTimeline.Callback { - override fun onPushedTimelineItem(timelineItem: MatrixTimelineItem) { - coroutineScope.launch { - timelineItemsFactory.pushItem(timelineItem) - } - } - } - @Composable override fun present(): TimelineState { val localCoroutineScope = rememberCoroutineScope() @@ -83,10 +70,8 @@ class TimelinePresenter @Inject constructor( } DisposableEffect(Unit) { - timeline.callback = TimelineCallback(localCoroutineScope, timelineItemsFactory) timeline.initialize() onDispose { - timeline.callback = null timeline.dispose() } } diff --git a/features/messages/src/main/kotlin/io/element/android/features/messages/timeline/factories/TimelineItemsFactory.kt b/features/messages/src/main/kotlin/io/element/android/features/messages/timeline/factories/TimelineItemsFactory.kt index d4c4701193..ff3318de5e 100644 --- a/features/messages/src/main/kotlin/io/element/android/features/messages/timeline/factories/TimelineItemsFactory.kt +++ b/features/messages/src/main/kotlin/io/element/android/features/messages/timeline/factories/TimelineItemsFactory.kt @@ -22,7 +22,6 @@ import io.element.android.features.messages.timeline.diff.MatrixTimelineItemsDif import io.element.android.features.messages.timeline.factories.event.TimelineItemEventFactory import io.element.android.features.messages.timeline.factories.virtual.TimelineItemVirtualFactory import io.element.android.features.messages.timeline.model.TimelineItem -import io.element.android.features.messages.timeline.util.invalidateLast import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.timeline.MatrixTimelineItem import kotlinx.coroutines.flow.MutableStateFlow @@ -61,18 +60,6 @@ class TimelineItemsFactory @Inject constructor( } } - suspend fun pushItem( - timelineItem: MatrixTimelineItem, - ) = withContext(dispatchers.computation) { - lock.withLock { - // Makes sure to invalidate last as we need to recompute some data (like groupPosition) - timelineItemsCache.invalidateLast() - timelineItemsCache.add(null) - matrixTimelineItems = matrixTimelineItems + timelineItem - buildAndEmitTimelineItemStates(matrixTimelineItems) - } - } - private suspend fun buildAndEmitTimelineItemStates(timelineItems: List) { val newTimelineItemStates = ArrayList() for (index in timelineItemsCache.indices.reversed()) { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 001825734c..13dea84636 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -117,6 +117,7 @@ jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = { module = "app.cash.molecule:molecule-runtime", version.ref = "molecule" } timber = "com.jakewharton.timber:timber:5.0.1" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.2" # Di inject = "javax.inject:javax.inject:1" diff --git a/libraries/matrix/build.gradle.kts b/libraries/matrix/build.gradle.kts index c331eab4ee..876e139c61 100644 --- a/libraries/matrix/build.gradle.kts +++ b/libraries/matrix/build.gradle.kts @@ -31,7 +31,8 @@ anvil { } dependencies { - api(projects.libraries.rustsdk) + //api(projects.libraries.rustsdk) + api(libs.matrix.sdk) implementation(projects.libraries.di) implementation(libs.dagger) implementation(projects.libraries.core) diff --git a/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/RustMatrixClient.kt b/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/RustMatrixClient.kt index 4e82840534..4d12f104a0 100644 --- a/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/RustMatrixClient.kt +++ b/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/RustMatrixClient.kt @@ -38,7 +38,7 @@ import org.matrix.rustcomponents.sdk.RequiredState import org.matrix.rustcomponents.sdk.SlidingSyncMode import org.matrix.rustcomponents.sdk.SlidingSyncRequestListFilters import org.matrix.rustcomponents.sdk.SlidingSyncViewBuilder -import org.matrix.rustcomponents.sdk.StoppableSpawn +import org.matrix.rustcomponents.sdk.TaskHandle import timber.log.Timber import java.io.File import java.util.concurrent.atomic.AtomicBoolean @@ -114,7 +114,7 @@ class RustMatrixClient constructor( dispatchers, ::onRestartSync ) - private var slidingSyncObserverToken: StoppableSpawn? = null + private var slidingSyncObserverToken: TaskHandle? = null private val mediaResolver = RustMediaResolver(this) private val isSyncing = AtomicBoolean(false) diff --git a/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/room/RoomSummaryDataSource.kt b/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/room/RoomSummaryDataSource.kt index 3a787899b9..7bbc70fdd0 100644 --- a/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/room/RoomSummaryDataSource.kt +++ b/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/room/RoomSummaryDataSource.kt @@ -37,7 +37,6 @@ import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomsListDiff import org.matrix.rustcomponents.sdk.UpdateSummary import timber.log.Timber import java.io.Closeable -import java.util.Collections import java.util.UUID interface RoomSummaryDataSource { @@ -128,30 +127,40 @@ internal class RustRoomSummaryDataSource( } Timber.v("ApplyDiff: $diff for list with size: $size") when (diff) { - is SlidingSyncViewRoomsListDiff.Push -> { + is SlidingSyncViewRoomsListDiff.Append -> { + val roomSummaries = diff.values.map { + buildSummaryForRoomListEntry(it) + } + addAll(roomSummaries) + } + is SlidingSyncViewRoomsListDiff.PushBack -> { val roomSummary = buildSummaryForRoomListEntry(diff.value) add(roomSummary) } - is SlidingSyncViewRoomsListDiff.UpdateAt -> { + is SlidingSyncViewRoomsListDiff.PushFront -> { + val roomSummary = buildSummaryForRoomListEntry(diff.value) + add(0, roomSummary) + } + is SlidingSyncViewRoomsListDiff.Set -> { fillUntil(diff.index.toInt()) val roomSummary = buildSummaryForRoomListEntry(diff.value) set(diff.index.toInt(), roomSummary) } - is SlidingSyncViewRoomsListDiff.InsertAt -> { + is SlidingSyncViewRoomsListDiff.Insert -> { val roomSummary = buildSummaryForRoomListEntry(diff.value) add(diff.index.toInt(), roomSummary) } - is SlidingSyncViewRoomsListDiff.Move -> { - Collections.swap(this, diff.oldIndex.toInt(), diff.newIndex.toInt()) - } - is SlidingSyncViewRoomsListDiff.RemoveAt -> { + is SlidingSyncViewRoomsListDiff.Remove -> { removeAt(diff.index.toInt()) } - is SlidingSyncViewRoomsListDiff.Replace -> { + is SlidingSyncViewRoomsListDiff.Reset -> { clear() addAll(diff.values.map { buildSummaryForRoomListEntry(it) }) } - SlidingSyncViewRoomsListDiff.Pop -> { + SlidingSyncViewRoomsListDiff.PopBack -> { + removeFirstOrNull() + } + SlidingSyncViewRoomsListDiff.PopFront -> { removeLastOrNull() } SlidingSyncViewRoomsListDiff.Clear -> { @@ -185,13 +194,4 @@ internal class RustRoomSummaryDataSource( block(mutableRoomSummaries) roomSummaries.value = mutableRoomSummaries } - - fun SlidingSyncViewRoomsListDiff.isInvalidation(): Boolean { - return when (this) { - is SlidingSyncViewRoomsListDiff.InsertAt -> this.value is RoomListEntry.Invalidated - is SlidingSyncViewRoomsListDiff.UpdateAt -> this.value is RoomListEntry.Invalidated - is SlidingSyncViewRoomsListDiff.Push -> this.value is RoomListEntry.Invalidated - else -> false - } - } } diff --git a/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/timeline/MatrixTimeline.kt b/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/timeline/MatrixTimeline.kt index a4c6a1cc81..83141b3f6f 100644 --- a/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/timeline/MatrixTimeline.kt +++ b/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/timeline/MatrixTimeline.kt @@ -21,16 +21,9 @@ import kotlinx.coroutines.flow.Flow import org.matrix.rustcomponents.sdk.TimelineListener interface MatrixTimeline { - var callback: Callback? - - interface Callback { - fun onUpdatedTimelineItem(timelineItem: MatrixTimelineItem) = Unit - fun onPushedTimelineItem(timelineItem: MatrixTimelineItem) = Unit - } fun timelineItems(): Flow> suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result - fun addListener(timelineListener: TimelineListener) fun initialize() fun dispose() diff --git a/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/timeline/RustMatrixTimeline.kt b/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/timeline/RustMatrixTimeline.kt index 6bc1a7b0b9..c1e13a1ea3 100644 --- a/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/timeline/RustMatrixTimeline.kt +++ b/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/timeline/RustMatrixTimeline.kt @@ -19,7 +19,7 @@ package io.element.android.libraries.matrix.timeline import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.core.EventId import io.element.android.libraries.matrix.room.RustMatrixRoom -import io.element.android.libraries.matrix.util.StoppableSpawnBag +import io.element.android.libraries.matrix.util.TaskHandleBag import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow @@ -32,9 +32,9 @@ import org.matrix.rustcomponents.sdk.Room import org.matrix.rustcomponents.sdk.SlidingSyncRoom import org.matrix.rustcomponents.sdk.TimelineChange import org.matrix.rustcomponents.sdk.TimelineDiff +import org.matrix.rustcomponents.sdk.TimelineItem import org.matrix.rustcomponents.sdk.TimelineListener import timber.log.Timber -import java.util.Collections class RustMatrixTimeline( private val matrixRoom: RustMatrixRoom, @@ -54,12 +54,10 @@ class RustMatrixTimeline( } } - override var callback: MatrixTimeline.Callback? = null - private val timelineItems: MutableStateFlow> = MutableStateFlow(emptyList()) - private val listenerTokens = StoppableSpawnBag() + private val listenerTokens = TaskHandleBag() @OptIn(FlowPreview::class) override fun timelineItems(): Flow> { @@ -68,37 +66,42 @@ class RustMatrixTimeline( private fun MutableList.applyDiff(diff: TimelineDiff) { when (diff.change()) { - TimelineChange.PUSH -> { - val item = diff.push()?.asMatrixTimelineItem() ?: return - callback?.onPushedTimelineItem(item) + TimelineChange.APPEND -> { + val items = diff.append()?.map { it.asMatrixTimelineItem() } ?: return + addAll(items) + } + TimelineChange.PUSH_BACK -> { + val item = diff.pushBack()?.asMatrixTimelineItem() ?: return add(item) } - TimelineChange.UPDATE_AT -> { - val updateAtData = diff.updateAt() ?: return + TimelineChange.PUSH_FRONT -> { + val item = diff.pushFront()?.asMatrixTimelineItem() ?: return + add(0, item) + } + TimelineChange.SET -> { + val updateAtData = diff.set() ?: return val item = updateAtData.item.asMatrixTimelineItem() - callback?.onUpdatedTimelineItem(item) set(updateAtData.index.toInt(), item) } - TimelineChange.INSERT_AT -> { - val insertAtData = diff.insertAt() ?: return + TimelineChange.INSERT -> { + val insertAtData = diff.insert() ?: return val item = insertAtData.item.asMatrixTimelineItem() add(insertAtData.index.toInt(), item) } - TimelineChange.MOVE -> { - val moveData = diff.move() ?: return - Collections.swap(this, moveData.oldIndex.toInt(), moveData.newIndex.toInt()) - } - TimelineChange.REMOVE_AT -> { - val removeAtData = diff.removeAt() ?: return + TimelineChange.REMOVE -> { + val removeAtData = diff.remove() ?: return removeAt(removeAtData.toInt()) } - TimelineChange.REPLACE -> { + TimelineChange.RESET -> { clear() - val items = diff.replace()?.map { it.asMatrixTimelineItem() } ?: return + val items = diff.reset()?.map { it.asMatrixTimelineItem() } ?: return addAll(items) } - TimelineChange.POP -> { - removeLast() + TimelineChange.POP_FRONT -> { + removeFirstOrNull() + } + TimelineChange.POP_BACK -> { + removeLastOrNull() } TimelineChange.CLEAR -> { clear() @@ -128,8 +131,12 @@ class RustMatrixTimeline( timelineItems.value = mutableTimelineItems } - override fun addListener(timelineListener: TimelineListener) { - listenerTokens += slidingSyncRoom.subscribeAndAddTimelineListener(timelineListener, null) + private suspend fun addListener(timelineListener: TimelineListener): Result> = withContext(coroutineDispatchers.computation) { + runCatching { + val result = slidingSyncRoom.subscribeAndAddTimelineListener(timelineListener, null) + listenerTokens += result.taskHandle + result.items + } } override fun initialize() { @@ -142,7 +149,17 @@ class RustMatrixTimeline( Timber.v("Success fetching members for room ${slidingSyncRoom.roomId()}") } } - addListener(innerTimelineListener) + coroutineScope.launch { + val result = addListener(innerTimelineListener) + result + .onSuccess { timelineItems -> + val matrixTimelineItems = timelineItems.map { it.asMatrixTimelineItem() } + updateTimelineItems { addAll(matrixTimelineItems) } + } + .onFailure { + Timber.e("Failed adding timeline listener on room with identifier: ${slidingSyncRoom.roomId()})") + } + } } override fun dispose() { diff --git a/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/util/CallbackFlow.kt b/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/util/CallbackFlow.kt index 3b82cc2489..9cf36f1db1 100644 --- a/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/util/CallbackFlow.kt +++ b/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/util/CallbackFlow.kt @@ -19,12 +19,13 @@ package io.element.android.libraries.matrix.util import kotlinx.coroutines.channels.ProducerScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.callbackFlow -import org.matrix.rustcomponents.sdk.StoppableSpawn +import org.matrix.rustcomponents.sdk.TaskHandle -internal fun mxCallbackFlow(block: suspend ProducerScope.() -> StoppableSpawn) = +internal fun mxCallbackFlow(block: suspend ProducerScope.() -> TaskHandle) = callbackFlow { - val token: StoppableSpawn = block(this) + val token: TaskHandle = block(this) awaitClose { token.cancel() + token.destroy() } } diff --git a/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/util/StoppableSpawnBag.kt b/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/util/TaskHandleBag.kt similarity index 71% rename from libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/util/StoppableSpawnBag.kt rename to libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/util/TaskHandleBag.kt index a84833c54d..f4f75d0e8e 100644 --- a/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/util/StoppableSpawnBag.kt +++ b/libraries/matrix/src/main/kotlin/io/element/android/libraries/matrix/util/TaskHandleBag.kt @@ -16,14 +16,14 @@ package io.element.android.libraries.matrix.util -import org.matrix.rustcomponents.sdk.StoppableSpawn +import org.matrix.rustcomponents.sdk.TaskHandle import java.util.concurrent.CopyOnWriteArraySet -class StoppableSpawnBag(private val tokens: MutableSet = CopyOnWriteArraySet()) : Set by tokens { +class TaskHandleBag(private val tokens: MutableSet = CopyOnWriteArraySet()) : Set by tokens { - operator fun plusAssign(stoppableSpawn: StoppableSpawn?) { - if (stoppableSpawn == null) return - tokens += stoppableSpawn + operator fun plusAssign(taskHandle: TaskHandle?) { + if (taskHandle == null) return + tokens += taskHandle } fun dispose() { diff --git a/samples/minimal/build.gradle.kts b/samples/minimal/build.gradle.kts index 79a05a89fd..9c88140f25 100644 --- a/samples/minimal/build.gradle.kts +++ b/samples/minimal/build.gradle.kts @@ -51,6 +51,7 @@ dependencies { implementation(projects.libraries.designsystem) implementation(projects.libraries.architecture) implementation(projects.libraries.core) + implementation(projects.libraries.dateformatter) implementation(projects.features.roomlist) implementation(projects.features.login) coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.2.2") diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt index 5d34d66c4b..78ebb2aa9c 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt @@ -18,17 +18,24 @@ package io.element.android.samples.minimal import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import io.element.android.features.roomlist.LastMessageFormatter import io.element.android.features.roomlist.RoomListPresenter import io.element.android.features.roomlist.RoomListView +import io.element.android.libraries.dateformatter.impl.DefaultLastMessageFormatter import io.element.android.libraries.matrix.MatrixClient import io.element.android.libraries.matrix.core.RoomId import kotlinx.coroutines.launch +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import java.util.Locale class RoomListScreen(private val matrixClient: MatrixClient) { + private val clock = Clock.System + private val locale = Locale.getDefault() + private val timeZone = TimeZone.currentSystemDefault() + private val presenter = RoomListPresenter(matrixClient, DefaultLastMessageFormatter(clock, locale, timeZone)) + @Composable fun Content(modifier: Modifier = Modifier) { fun onRoomClicked(roomId: RoomId) { @@ -43,9 +50,6 @@ class RoomListScreen(private val matrixClient: MatrixClient) { } } - val presenter = remember { - RoomListPresenter(matrixClient, LastMessageFormatter()) - } val state = presenter.present() RoomListView( state = state,