Start filling MatrixRoom class and use it in MessagesScreen

This commit is contained in:
ganfra 2022-11-04 17:56:14 +01:00
parent d04d847521
commit 11b74c0279
11 changed files with 202 additions and 74 deletions

View file

@ -12,10 +12,10 @@ import org.matrix.rustcomponents.sdk.AuthenticationService
import org.matrix.rustcomponents.sdk.Client
import org.matrix.rustcomponents.sdk.ClientBuilder
import java.io.File
import java.util.Optional
import java.util.*
class Matrix(
coroutineScope: CoroutineScope,
private val coroutineScope: CoroutineScope,
context: Context,
) {
private val coroutineDispatchers = CoroutineDispatchers(
@ -44,10 +44,14 @@ class Matrix(
return isLoggedIn
}
fun matrixClient(): Flow<Optional<MatrixClient>> {
fun client(): Flow<Optional<MatrixClient>> {
return matrixClient
}
fun activeClient(): MatrixClient {
return matrixClient.value.get()
}
suspend fun restoreSession() = withContext(coroutineDispatchers.io) {
sessionStore.getStoredData()
?.let { sessionData ->
@ -80,6 +84,7 @@ class Matrix(
return MatrixClient(
client = client,
sessionStore = sessionStore,
coroutineScope = coroutineScope,
dispatchers = coroutineDispatchers
).also {
matrixClient.value = Optional.of(it)

View file

@ -2,9 +2,14 @@ package io.element.android.x.matrix
import io.element.android.x.core.data.CoroutineDispatchers
import io.element.android.x.matrix.core.UserId
import io.element.android.x.matrix.room.MatrixRoom
import io.element.android.x.matrix.room.RoomSummaryDataSource
import io.element.android.x.matrix.room.RoomSummaryDetailsFactory
import io.element.android.x.matrix.room.RustRoomSummaryDataSource
import io.element.android.x.matrix.room.message.RoomMessageFactory
import io.element.android.x.matrix.session.SessionStore
import io.element.android.x.matrix.sync.SlidingSyncObserverProxy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.*
import timber.log.Timber
@ -13,6 +18,7 @@ import java.io.Closeable
class MatrixClient internal constructor(
private val client: Client,
private val sessionStore: SessionStore,
private val coroutineScope: CoroutineScope,
private val dispatchers: CoroutineDispatchers,
) : Closeable {
@ -30,19 +36,15 @@ class MatrixClient internal constructor(
}
}
private val slidingSyncObserver = object : SlidingSyncObserver {
override fun didReceiveSyncUpdate(summary: UpdateSummary) {
Timber.v("didReceiveSyncUpdate=$summary on Thread: ${Thread.currentThread()}")
roomSummaryDataSource.updateRoomsWithIdentifiers(summary.rooms)
}
}
private val slidingSyncView = SlidingSyncViewBuilder()
.timelineLimit(limit = 1u)
.requiredState(requiredState = listOf(
RequiredState(key = "m.room.avatar", value = ""),
RequiredState(key = "m.room.encryption", value = ""),
))
.requiredState(
requiredState = listOf(
RequiredState(key = "m.room.avatar", value = ""),
RequiredState(key = "m.room.name", value = ""),
RequiredState(key = "m.room.encryption", value = ""),
)
)
.name(name = "HomeScreenView")
.syncMode(mode = SlidingSyncMode.FULL_SYNC)
.build()
@ -54,15 +56,28 @@ class MatrixClient internal constructor(
.addView(slidingSyncView)
.build()
private val slidingSyncObserverProxy = SlidingSyncObserverProxy(coroutineScope)
private val roomSummaryDataSource: RustRoomSummaryDataSource =
RustRoomSummaryDataSource(slidingSync, slidingSyncView, dispatchers)
RustRoomSummaryDataSource(slidingSyncObserverProxy.updateSummaryFlow, slidingSync, slidingSyncView, dispatchers)
private var slidingSyncObserverToken: StoppableSpawn? = null
init {
client.setDelegate(clientDelegate)
}
fun getRoom(roomId: String): MatrixRoom? {
val slidingSyncRoom = slidingSync.getRoom(roomId) ?: return null
val room = slidingSyncRoom.fullRoom() ?: return null
return MatrixRoom(
slidingSyncUpdateFlow = slidingSyncObserverProxy.updateSummaryFlow,
slidingSyncRoom = slidingSyncRoom,
room = room
)
}
fun startSync() {
slidingSync.setObserver(slidingSyncObserver)
roomSummaryDataSource.startSync()
slidingSync.setObserver(slidingSyncObserverProxy)
slidingSyncObserverToken = slidingSync.sync()
}
@ -113,7 +128,8 @@ class MatrixClient internal constructor(
): Result<ByteArray> =
withContext(dispatchers.io) {
runCatching {
client.getMediaThumbnail(source, width.toULong(), height.toULong()).toUByteArray().toByteArray()
client.getMediaThumbnail(source, width.toULong(), height.toULong()).toUByteArray()
.toByteArray()
}
}

View file

@ -1,11 +1,50 @@
package io.element.android.x.matrix.room
import io.element.android.x.matrix.core.RoomId
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.SlidingSyncRoom
import org.matrix.rustcomponents.sdk.UpdateSummary
class MatrixRoom(private val room: Room) {
class MatrixRoom(
private val slidingSyncUpdateFlow: Flow<UpdateSummary>,
private val slidingSyncRoom: SlidingSyncRoom,
private val room: Room,
) {
fun syncUpdateFlow(): Flow<Unit> {
return slidingSyncUpdateFlow
.filter {
it.rooms.contains(room.id())
}
.map { }
.onStart { emit(Unit) }
}
val roomId = RoomId(room.id())
val name: String?
get() {
return slidingSyncRoom.name()
}
val displayName: String
get() {
return room.displayName()
}
val topic: String?
get() {
return room.topic()
}
val avatarUrl: String?
get() {
return room.avatarUrl()
}
}

View file

@ -1,7 +1,6 @@
package io.element.android.x.matrix.room
import io.element.android.x.core.data.CoroutineDispatchers
import io.element.android.x.matrix.core.RoomId
import io.element.android.x.matrix.room.message.RoomMessageFactory
import io.element.android.x.matrix.sync.roomListDiff
import io.element.android.x.matrix.sync.state
@ -20,10 +19,11 @@ interface RoomSummaryDataSource {
}
internal class RustRoomSummaryDataSource(
private val slidingSyncUpdateFlow: Flow<UpdateSummary>,
private val slidingSync: SlidingSync,
private val slidingSyncView: SlidingSyncView,
private val coroutineDispatchers: CoroutineDispatchers,
private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory(),
private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory()
) : RoomSummaryDataSource, Closeable {
private val coroutineScope = CoroutineScope(SupervisorJob() + coroutineDispatchers.io)
@ -31,7 +31,8 @@ internal class RustRoomSummaryDataSource(
private val roomSummaries = MutableStateFlow<List<RoomSummary>>(emptyList())
private val state = MutableStateFlow(SlidingSyncState.COLD)
init {
fun startSync(){
slidingSyncView.roomListDiff()
.onEach { diff ->
updateRoomSummaries {
@ -44,6 +45,11 @@ internal class RustRoomSummaryDataSource(
Timber.v("New sliding sync state: $slidingSyncState")
state.value = slidingSyncState
}.launchIn(coroutineScope)
slidingSyncUpdateFlow
.onEach {
didReceiveSyncUpdate(it)
}.launchIn(coroutineScope)
}
fun stopSync() {
@ -58,13 +64,13 @@ internal class RustRoomSummaryDataSource(
return roomSummaries.sample(100)
}
internal fun updateRoomsWithIdentifiers(identifiers: List<String>) {
Timber.v("UpdateRooms with identifiers: $identifiers")
private fun didReceiveSyncUpdate(summary: UpdateSummary) {
Timber.v("UpdateRooms with identifiers: ${summary.rooms}")
if (state.value != SlidingSyncState.LIVE) {
return
}
updateRoomSummaries {
for (identifier in identifiers) {
for (identifier in summary.rooms) {
val index = indexOfFirst { it.identifier() == identifier }
if (index == -1) {
continue
@ -78,7 +84,7 @@ internal class RustRoomSummaryDataSource(
private fun MutableList<RoomSummary>.applyDiff(diff: SlidingSyncViewRoomsListDiff) {
fun MutableList<RoomSummary>.fillUntil(untilIndex: Int) {
repeat((size-1 until untilIndex).count()) {
repeat((size - 1 until untilIndex).count()) {
add(buildEmptyRoomSummary())
}
}
@ -89,7 +95,7 @@ internal class RustRoomSummaryDataSource(
add(roomSummary)
}
is SlidingSyncViewRoomsListDiff.UpdateAt -> {
fillUntil(diff.index.toInt())
//fillUntil(diff.index.toInt())
val roomSummary = buildSummaryForRoomListEntry(diff.value)
set(diff.index.toInt(), roomSummary)
}
@ -124,24 +130,8 @@ internal class RustRoomSummaryDataSource(
private fun buildRoomSummaryForIdentifier(identifier: String): RoomSummary {
val room = slidingSync.getRoom(identifier) ?: return RoomSummary.Empty(identifier)
val latestRoomMessage = room.latestRoomMessage()?.let {
roomMessageFactory.create(it)
}
val computedLastMessage = when {
latestRoomMessage == null -> null
room.isDm() == true -> latestRoomMessage.body
else -> "${latestRoomMessage.sender.value}: ${latestRoomMessage.body}"
}
return RoomSummary.Filled(
details = RoomSummaryDetails(
roomId = RoomId(identifier),
name = room.name() ?: identifier,
isDirect = room.isDm() ?: false,
avatarURLString = room.fullRoom()?.avatarUrl(),
unreadNotificationCount = room.unreadNotifications().notificationCount().toInt(),
lastMessage = computedLastMessage,
lastMessageTimestamp = latestRoomMessage?.originServerTs
)
details = roomSummaryDetailsFactory.create(room, room.fullRoom())
)
}

View file

@ -0,0 +1,30 @@
package io.element.android.x.matrix.room
import io.element.android.x.matrix.core.RoomId
import io.element.android.x.matrix.room.message.RoomMessageFactory
import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.SlidingSyncRoom
class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory()) {
fun create(slidingSyncRoom: SlidingSyncRoom, room: Room?): RoomSummaryDetails{
val latestRoomMessage = slidingSyncRoom.latestRoomMessage()?.let {
roomMessageFactory.create(it)
}
val computedLastMessage = when {
latestRoomMessage == null -> null
slidingSyncRoom.isDm() == true -> latestRoomMessage.body
else -> "${latestRoomMessage.sender.value}: ${latestRoomMessage.body}"
}
return RoomSummaryDetails(
roomId = RoomId(slidingSyncRoom.roomId()),
name = slidingSyncRoom.name() ?: slidingSyncRoom.roomId(),
isDirect = slidingSyncRoom.isDm() ?: false,
avatarURLString = room?.avatarUrl(),
unreadNotificationCount = slidingSyncRoom.unreadNotifications().notificationCount().toInt(),
lastMessage = computedLastMessage,
lastMessageTimestamp = latestRoomMessage?.originServerTs
)
}
}

View file

@ -5,7 +5,6 @@ import io.element.android.x.matrix.core.UserId
import org.matrix.rustcomponents.sdk.EventTimelineItem
class RoomMessageFactory {
fun create(eventTimelineItem: EventTimelineItem?): RoomMessage? {
eventTimelineItem ?: return null
return RoomMessage(

View file

@ -0,0 +1,20 @@
package io.element.android.x.matrix.sync
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import org.matrix.rustcomponents.sdk.SlidingSyncObserver
import org.matrix.rustcomponents.sdk.UpdateSummary
class SlidingSyncObserverProxy(private val coroutineScope: CoroutineScope) : SlidingSyncObserver {
private val updateSummaryMutableFlow = MutableSharedFlow<UpdateSummary>()
val updateSummaryFlow: Flow<UpdateSummary> = updateSummaryMutableFlow
override fun didReceiveSyncUpdate(summary: UpdateSummary) {
coroutineScope.launch {
updateSummaryMutableFlow.emit(summary)
}
}
}