Start filling MatrixRoom class and use it in MessagesScreen
This commit is contained in:
parent
d04d847521
commit
11b74c0279
11 changed files with 202 additions and 74 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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())
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue