Update rust-sdk (from maven)

This commit is contained in:
ganfra 2023-02-24 15:05:20 +01:00
parent 8d4d8e96bd
commit 247f6d2188
12 changed files with 86 additions and 96 deletions

View file

@ -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.architecture.Presenter
import io.element.android.libraries.matrix.core.EventId import io.element.android.libraries.matrix.core.EventId
import io.element.android.libraries.matrix.room.MatrixRoom 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.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@ -47,17 +45,6 @@ class TimelinePresenter @Inject constructor(
private val timeline = room.timeline() 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 @Composable
override fun present(): TimelineState { override fun present(): TimelineState {
val localCoroutineScope = rememberCoroutineScope() val localCoroutineScope = rememberCoroutineScope()
@ -83,10 +70,8 @@ class TimelinePresenter @Inject constructor(
} }
DisposableEffect(Unit) { DisposableEffect(Unit) {
timeline.callback = TimelineCallback(localCoroutineScope, timelineItemsFactory)
timeline.initialize() timeline.initialize()
onDispose { onDispose {
timeline.callback = null
timeline.dispose() timeline.dispose()
} }
} }

View file

@ -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.event.TimelineItemEventFactory
import io.element.android.features.messages.timeline.factories.virtual.TimelineItemVirtualFactory 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.model.TimelineItem
import io.element.android.features.messages.timeline.util.invalidateLast
import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.timeline.MatrixTimelineItem
import kotlinx.coroutines.flow.MutableStateFlow 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<MatrixTimelineItem>) { private suspend fun buildAndEmitTimelineItemStates(timelineItems: List<MatrixTimelineItem>) {
val newTimelineItemStates = ArrayList<TimelineItem>() val newTimelineItemStates = ArrayList<TimelineItem>()
for (index in timelineItemsCache.indices.reversed()) { for (index in timelineItemsCache.indices.reversed()) {

View file

@ -117,6 +117,7 @@ jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
molecule-runtime = { module = "app.cash.molecule:molecule-runtime", version.ref = "molecule" } molecule-runtime = { module = "app.cash.molecule:molecule-runtime", version.ref = "molecule" }
timber = "com.jakewharton.timber:timber:5.0.1" timber = "com.jakewharton.timber:timber:5.0.1"
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.2"
# Di # Di
inject = "javax.inject:javax.inject:1" inject = "javax.inject:javax.inject:1"

View file

@ -31,7 +31,8 @@ anvil {
} }
dependencies { dependencies {
api(projects.libraries.rustsdk) //api(projects.libraries.rustsdk)
api(libs.matrix.sdk)
implementation(projects.libraries.di) implementation(projects.libraries.di)
implementation(libs.dagger) implementation(libs.dagger)
implementation(projects.libraries.core) implementation(projects.libraries.core)

View file

@ -38,7 +38,7 @@ import org.matrix.rustcomponents.sdk.RequiredState
import org.matrix.rustcomponents.sdk.SlidingSyncMode import org.matrix.rustcomponents.sdk.SlidingSyncMode
import org.matrix.rustcomponents.sdk.SlidingSyncRequestListFilters import org.matrix.rustcomponents.sdk.SlidingSyncRequestListFilters
import org.matrix.rustcomponents.sdk.SlidingSyncViewBuilder import org.matrix.rustcomponents.sdk.SlidingSyncViewBuilder
import org.matrix.rustcomponents.sdk.StoppableSpawn import org.matrix.rustcomponents.sdk.TaskHandle
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
@ -114,7 +114,7 @@ class RustMatrixClient constructor(
dispatchers, dispatchers,
::onRestartSync ::onRestartSync
) )
private var slidingSyncObserverToken: StoppableSpawn? = null private var slidingSyncObserverToken: TaskHandle? = null
private val mediaResolver = RustMediaResolver(this) private val mediaResolver = RustMediaResolver(this)
private val isSyncing = AtomicBoolean(false) private val isSyncing = AtomicBoolean(false)

View file

@ -37,7 +37,6 @@ import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomsListDiff
import org.matrix.rustcomponents.sdk.UpdateSummary import org.matrix.rustcomponents.sdk.UpdateSummary
import timber.log.Timber import timber.log.Timber
import java.io.Closeable import java.io.Closeable
import java.util.Collections
import java.util.UUID import java.util.UUID
interface RoomSummaryDataSource { interface RoomSummaryDataSource {
@ -128,30 +127,40 @@ internal class RustRoomSummaryDataSource(
} }
Timber.v("ApplyDiff: $diff for list with size: $size") Timber.v("ApplyDiff: $diff for list with size: $size")
when (diff) { 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) val roomSummary = buildSummaryForRoomListEntry(diff.value)
add(roomSummary) add(roomSummary)
} }
is SlidingSyncViewRoomsListDiff.UpdateAt -> { is SlidingSyncViewRoomsListDiff.PushFront -> {
val roomSummary = buildSummaryForRoomListEntry(diff.value)
add(0, roomSummary)
}
is SlidingSyncViewRoomsListDiff.Set -> {
fillUntil(diff.index.toInt()) fillUntil(diff.index.toInt())
val roomSummary = buildSummaryForRoomListEntry(diff.value) val roomSummary = buildSummaryForRoomListEntry(diff.value)
set(diff.index.toInt(), roomSummary) set(diff.index.toInt(), roomSummary)
} }
is SlidingSyncViewRoomsListDiff.InsertAt -> { is SlidingSyncViewRoomsListDiff.Insert -> {
val roomSummary = buildSummaryForRoomListEntry(diff.value) val roomSummary = buildSummaryForRoomListEntry(diff.value)
add(diff.index.toInt(), roomSummary) add(diff.index.toInt(), roomSummary)
} }
is SlidingSyncViewRoomsListDiff.Move -> { is SlidingSyncViewRoomsListDiff.Remove -> {
Collections.swap(this, diff.oldIndex.toInt(), diff.newIndex.toInt())
}
is SlidingSyncViewRoomsListDiff.RemoveAt -> {
removeAt(diff.index.toInt()) removeAt(diff.index.toInt())
} }
is SlidingSyncViewRoomsListDiff.Replace -> { is SlidingSyncViewRoomsListDiff.Reset -> {
clear() clear()
addAll(diff.values.map { buildSummaryForRoomListEntry(it) }) addAll(diff.values.map { buildSummaryForRoomListEntry(it) })
} }
SlidingSyncViewRoomsListDiff.Pop -> { SlidingSyncViewRoomsListDiff.PopBack -> {
removeFirstOrNull()
}
SlidingSyncViewRoomsListDiff.PopFront -> {
removeLastOrNull() removeLastOrNull()
} }
SlidingSyncViewRoomsListDiff.Clear -> { SlidingSyncViewRoomsListDiff.Clear -> {
@ -185,13 +194,4 @@ internal class RustRoomSummaryDataSource(
block(mutableRoomSummaries) block(mutableRoomSummaries)
roomSummaries.value = 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
}
}
} }

View file

@ -21,16 +21,9 @@ import kotlinx.coroutines.flow.Flow
import org.matrix.rustcomponents.sdk.TimelineListener import org.matrix.rustcomponents.sdk.TimelineListener
interface MatrixTimeline { interface MatrixTimeline {
var callback: Callback?
interface Callback {
fun onUpdatedTimelineItem(timelineItem: MatrixTimelineItem) = Unit
fun onPushedTimelineItem(timelineItem: MatrixTimelineItem) = Unit
}
fun timelineItems(): Flow<List<MatrixTimelineItem>> fun timelineItems(): Flow<List<MatrixTimelineItem>>
suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result<Unit> suspend fun paginateBackwards(requestSize: Int, untilNumberOfItems: Int): Result<Unit>
fun addListener(timelineListener: TimelineListener)
fun initialize() fun initialize()
fun dispose() fun dispose()

View file

@ -19,7 +19,7 @@ package io.element.android.libraries.matrix.timeline
import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.core.EventId import io.element.android.libraries.matrix.core.EventId
import io.element.android.libraries.matrix.room.RustMatrixRoom 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.CoroutineScope
import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow 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.SlidingSyncRoom
import org.matrix.rustcomponents.sdk.TimelineChange import org.matrix.rustcomponents.sdk.TimelineChange
import org.matrix.rustcomponents.sdk.TimelineDiff import org.matrix.rustcomponents.sdk.TimelineDiff
import org.matrix.rustcomponents.sdk.TimelineItem
import org.matrix.rustcomponents.sdk.TimelineListener import org.matrix.rustcomponents.sdk.TimelineListener
import timber.log.Timber import timber.log.Timber
import java.util.Collections
class RustMatrixTimeline( class RustMatrixTimeline(
private val matrixRoom: RustMatrixRoom, private val matrixRoom: RustMatrixRoom,
@ -54,12 +54,10 @@ class RustMatrixTimeline(
} }
} }
override var callback: MatrixTimeline.Callback? = null
private val timelineItems: MutableStateFlow<List<MatrixTimelineItem>> = private val timelineItems: MutableStateFlow<List<MatrixTimelineItem>> =
MutableStateFlow(emptyList()) MutableStateFlow(emptyList())
private val listenerTokens = StoppableSpawnBag() private val listenerTokens = TaskHandleBag()
@OptIn(FlowPreview::class) @OptIn(FlowPreview::class)
override fun timelineItems(): Flow<List<MatrixTimelineItem>> { override fun timelineItems(): Flow<List<MatrixTimelineItem>> {
@ -68,37 +66,42 @@ class RustMatrixTimeline(
private fun MutableList<MatrixTimelineItem>.applyDiff(diff: TimelineDiff) { private fun MutableList<MatrixTimelineItem>.applyDiff(diff: TimelineDiff) {
when (diff.change()) { when (diff.change()) {
TimelineChange.PUSH -> { TimelineChange.APPEND -> {
val item = diff.push()?.asMatrixTimelineItem() ?: return val items = diff.append()?.map { it.asMatrixTimelineItem() } ?: return
callback?.onPushedTimelineItem(item) addAll(items)
}
TimelineChange.PUSH_BACK -> {
val item = diff.pushBack()?.asMatrixTimelineItem() ?: return
add(item) add(item)
} }
TimelineChange.UPDATE_AT -> { TimelineChange.PUSH_FRONT -> {
val updateAtData = diff.updateAt() ?: return val item = diff.pushFront()?.asMatrixTimelineItem() ?: return
add(0, item)
}
TimelineChange.SET -> {
val updateAtData = diff.set() ?: return
val item = updateAtData.item.asMatrixTimelineItem() val item = updateAtData.item.asMatrixTimelineItem()
callback?.onUpdatedTimelineItem(item)
set(updateAtData.index.toInt(), item) set(updateAtData.index.toInt(), item)
} }
TimelineChange.INSERT_AT -> { TimelineChange.INSERT -> {
val insertAtData = diff.insertAt() ?: return val insertAtData = diff.insert() ?: return
val item = insertAtData.item.asMatrixTimelineItem() val item = insertAtData.item.asMatrixTimelineItem()
add(insertAtData.index.toInt(), item) add(insertAtData.index.toInt(), item)
} }
TimelineChange.MOVE -> { TimelineChange.REMOVE -> {
val moveData = diff.move() ?: return val removeAtData = diff.remove() ?: return
Collections.swap(this, moveData.oldIndex.toInt(), moveData.newIndex.toInt())
}
TimelineChange.REMOVE_AT -> {
val removeAtData = diff.removeAt() ?: return
removeAt(removeAtData.toInt()) removeAt(removeAtData.toInt())
} }
TimelineChange.REPLACE -> { TimelineChange.RESET -> {
clear() clear()
val items = diff.replace()?.map { it.asMatrixTimelineItem() } ?: return val items = diff.reset()?.map { it.asMatrixTimelineItem() } ?: return
addAll(items) addAll(items)
} }
TimelineChange.POP -> { TimelineChange.POP_FRONT -> {
removeLast() removeFirstOrNull()
}
TimelineChange.POP_BACK -> {
removeLastOrNull()
} }
TimelineChange.CLEAR -> { TimelineChange.CLEAR -> {
clear() clear()
@ -128,8 +131,12 @@ class RustMatrixTimeline(
timelineItems.value = mutableTimelineItems timelineItems.value = mutableTimelineItems
} }
override fun addListener(timelineListener: TimelineListener) { private suspend fun addListener(timelineListener: TimelineListener): Result<List<TimelineItem>> = withContext(coroutineDispatchers.computation) {
listenerTokens += slidingSyncRoom.subscribeAndAddTimelineListener(timelineListener, null) runCatching {
val result = slidingSyncRoom.subscribeAndAddTimelineListener(timelineListener, null)
listenerTokens += result.taskHandle
result.items
}
} }
override fun initialize() { override fun initialize() {
@ -142,7 +149,17 @@ class RustMatrixTimeline(
Timber.v("Success fetching members for room ${slidingSyncRoom.roomId()}") 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() { override fun dispose() {

View file

@ -19,12 +19,13 @@ package io.element.android.libraries.matrix.util
import kotlinx.coroutines.channels.ProducerScope import kotlinx.coroutines.channels.ProducerScope
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import org.matrix.rustcomponents.sdk.StoppableSpawn import org.matrix.rustcomponents.sdk.TaskHandle
internal fun <T> mxCallbackFlow(block: suspend ProducerScope<T>.() -> StoppableSpawn) = internal fun <T> mxCallbackFlow(block: suspend ProducerScope<T>.() -> TaskHandle) =
callbackFlow { callbackFlow {
val token: StoppableSpawn = block(this) val token: TaskHandle = block(this)
awaitClose { awaitClose {
token.cancel() token.cancel()
token.destroy()
} }
} }

View file

@ -16,14 +16,14 @@
package io.element.android.libraries.matrix.util package io.element.android.libraries.matrix.util
import org.matrix.rustcomponents.sdk.StoppableSpawn import org.matrix.rustcomponents.sdk.TaskHandle
import java.util.concurrent.CopyOnWriteArraySet import java.util.concurrent.CopyOnWriteArraySet
class StoppableSpawnBag(private val tokens: MutableSet<StoppableSpawn> = CopyOnWriteArraySet()) : Set<StoppableSpawn> by tokens { class TaskHandleBag(private val tokens: MutableSet<TaskHandle> = CopyOnWriteArraySet()) : Set<TaskHandle> by tokens {
operator fun plusAssign(stoppableSpawn: StoppableSpawn?) { operator fun plusAssign(taskHandle: TaskHandle?) {
if (stoppableSpawn == null) return if (taskHandle == null) return
tokens += stoppableSpawn tokens += taskHandle
} }
fun dispose() { fun dispose() {

View file

@ -51,6 +51,7 @@ dependencies {
implementation(projects.libraries.designsystem) implementation(projects.libraries.designsystem)
implementation(projects.libraries.architecture) implementation(projects.libraries.architecture)
implementation(projects.libraries.core) implementation(projects.libraries.core)
implementation(projects.libraries.dateformatter)
implementation(projects.features.roomlist) implementation(projects.features.roomlist)
implementation(projects.features.login) implementation(projects.features.login)
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.2.2") coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.2.2")

View file

@ -18,17 +18,24 @@ package io.element.android.samples.minimal
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier 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.RoomListPresenter
import io.element.android.features.roomlist.RoomListView 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.MatrixClient
import io.element.android.libraries.matrix.core.RoomId import io.element.android.libraries.matrix.core.RoomId
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.datetime.Clock
import kotlinx.datetime.TimeZone
import java.util.Locale
class RoomListScreen(private val matrixClient: MatrixClient) { 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 @Composable
fun Content(modifier: Modifier = Modifier) { fun Content(modifier: Modifier = Modifier) {
fun onRoomClicked(roomId: RoomId) { fun onRoomClicked(roomId: RoomId) {
@ -43,9 +50,6 @@ class RoomListScreen(private val matrixClient: MatrixClient) {
} }
} }
val presenter = remember {
RoomListPresenter(matrixClient, LastMessageFormatter())
}
val state = presenter.present() val state = presenter.present()
RoomListView( RoomListView(
state = state, state = state,