Browse Source

Start filling MatrixRoom class and use it in MessagesScreen

feature/bma/flipper
ganfra 2 years ago
parent
commit
11b74c0279
  1. 21
      features/messages/src/main/java/io/element/android/x/features/messages/MessagesScreen.kt
  2. 61
      features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt
  3. 5
      features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesViewState.kt
  4. 2
      features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListViewModel.kt
  5. 11
      libraries/matrix/src/main/java/io/element/android/x/matrix/Matrix.kt
  6. 44
      libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixClient.kt
  7. 41
      libraries/matrix/src/main/java/io/element/android/x/matrix/room/MatrixRoom.kt
  8. 40
      libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDataSource.kt
  9. 30
      libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDetailsFactory.kt
  10. 1
      libraries/matrix/src/main/java/io/element/android/x/matrix/room/message/RoomMessageFactory.kt
  11. 20
      libraries/matrix/src/main/java/io/element/android/x/matrix/sync/SlidingSyncObserverProxy.kt

21
features/messages/src/main/java/io/element/android/x/features/messages/MessagesScreen.kt

@ -2,6 +2,7 @@
package io.element.android.x.features.messages package io.element.android.x.features.messages
import Avatar
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.* import androidx.compose.material3.*
@ -12,18 +13,23 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
import com.airbnb.mvrx.compose.collectAsState import com.airbnb.mvrx.compose.collectAsState
import com.airbnb.mvrx.compose.mavericksViewModel import com.airbnb.mvrx.compose.mavericksViewModel
import io.element.android.x.core.data.LogCompositions import io.element.android.x.core.data.LogCompositions
import io.element.android.x.designsystem.components.avatar.AvatarData
import io.element.android.x.features.messages.model.MessagesViewState import io.element.android.x.features.messages.model.MessagesViewState
@Composable @Composable
fun MessagesScreen(roomId: String) { fun MessagesScreen(roomId: String) {
val viewModel: MessagesViewModel = mavericksViewModel(argsFactory = { roomId }) val viewModel: MessagesViewModel = mavericksViewModel(argsFactory = { roomId })
LogCompositions(tag = "MessagesScreen", msg = "Root") LogCompositions(tag = "MessagesScreen", msg = "Root")
val roomTitle by viewModel.collectAsState(prop1 = MessagesViewState::roomTitle) val roomTitle by viewModel.collectAsState(MessagesViewState::roomName)
MessagesContent(roomTitle) val roomAvatar by viewModel.collectAsState(MessagesViewState::roomAvatar)
MessagesContent(roomTitle, roomAvatar)
} }
@Composable @Composable
fun MessagesContent(roomTitle: String) { fun MessagesContent(
roomTitle: String?,
roomAvatar: AvatarData?
) {
val appBarState = rememberTopAppBarState() val appBarState = rememberTopAppBarState()
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(appBarState) val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(appBarState)
LogCompositions(tag = "RoomListScreen", msg = "Content") LogCompositions(tag = "RoomListScreen", msg = "Content")
@ -31,7 +37,14 @@ fun MessagesContent(roomTitle: String) {
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { Text(text = roomTitle) } navigationIcon = {
if (roomAvatar != null) {
IconButton(onClick = {}) {
Avatar(roomAvatar)
}
}
},
title = { Text(text = roomTitle ?: "") }
) )
}, },
content = { padding -> content = { padding ->

61
features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt

@ -1,48 +1,69 @@
package io.element.android.x.features.messages package io.element.android.x.features.messages
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.MavericksViewModel import com.airbnb.mvrx.MavericksViewModel
import com.airbnb.mvrx.Success import com.airbnb.mvrx.MavericksViewModelFactory
import io.element.android.x.core.data.parallelMap import com.airbnb.mvrx.ViewModelContext
import io.element.android.x.designsystem.components.avatar.AvatarData import io.element.android.x.designsystem.components.avatar.AvatarData
import io.element.android.x.designsystem.components.avatar.AvatarSize import io.element.android.x.designsystem.components.avatar.AvatarSize
import io.element.android.x.features.messages.model.MessagesViewState import io.element.android.x.features.messages.model.MessagesViewState
import io.element.android.x.matrix.MatrixClient import io.element.android.x.matrix.MatrixClient
import io.element.android.x.matrix.MatrixInstance import io.element.android.x.matrix.MatrixInstance
import io.element.android.x.matrix.room.RoomSummary import io.element.android.x.matrix.room.MatrixRoom
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.matrix.rustcomponents.sdk.mediaSourceFromUrl import org.matrix.rustcomponents.sdk.mediaSourceFromUrl
class MessagesViewModel(initialState: MessagesViewState) : class MessagesViewModel(
private val client: MatrixClient,
private val room: MatrixRoom,
private val initialState: MessagesViewState
) :
MavericksViewModel<MessagesViewState>(initialState) { MavericksViewModel<MessagesViewState>(initialState) {
private val matrix = MatrixInstance.getInstance() companion object : MavericksViewModelFactory<MessagesViewModel, MessagesViewState> {
override fun create(
viewModelContext: ViewModelContext,
state: MessagesViewState
): MessagesViewModel? {
val matrix = MatrixInstance.getInstance()
val client = matrix.activeClient()
val room = client.getRoom(state.roomId) ?: return null
return MessagesViewModel(client, room, state)
}
}
init { init {
handleInit() handleInit()
} }
private fun handleInit() { private fun handleInit() {
viewModelScope.launch { room.syncUpdateFlow()
.onEach {
val avatarData =
} loadAvatarData(room.name ?: room.roomId.value, room.avatarUrl, AvatarSize.SMALL)
setState {
copy(
roomName = room.name, roomAvatar = avatarData,
)
}
}.launchIn(viewModelScope)
} }
private suspend fun loadAvatarData( private suspend fun loadAvatarData(
client: MatrixClient,
name: String, name: String,
url: String?, url: String?,
size: AvatarSize = AvatarSize.MEDIUM size: AvatarSize = AvatarSize.MEDIUM
): AvatarData { ): AvatarData {
val mediaContent = url?.let { val mediaContent = url?.let {
val mediaSource = mediaSourceFromUrl(it) val mediaSource = mediaSourceFromUrl(it)
client.loadMediaThumbnailForSource(mediaSource, size.value.toLong(), size.value.toLong()) client.loadMediaThumbnailForSource(
mediaSource,
size.value.toLong(),
size.value.toLong()
)
} }
return mediaContent?.fold( return mediaContent?.fold(
{ it }, { it },
@ -52,10 +73,6 @@ class MessagesViewModel(initialState: MessagesViewState) :
} }
} }
private suspend fun getClient(): MatrixClient {
return matrix.matrixClient().first().get()
}
override fun onCleared() { override fun onCleared() {
super.onCleared() super.onCleared()
} }

5
features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesViewState.kt

@ -2,15 +2,14 @@ package io.element.android.x.features.messages.model
import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.MavericksState
import io.element.android.x.designsystem.components.avatar.AvatarData import io.element.android.x.designsystem.components.avatar.AvatarData
import io.element.android.x.matrix.core.RoomId
data class MessagesViewState( data class MessagesViewState(
val roomId: String, val roomId: String,
val roomTitle: String = "", val roomName: String? = null,
val roomAvatar: AvatarData? = null val roomAvatar: AvatarData? = null
) : MavericksState { ) : MavericksState {
@Suppress("unused") @Suppress("unused")
constructor(roomId: String) : this(roomId = roomId, roomTitle = "", roomAvatar = null) constructor(roomId: String) : this(roomId = roomId, roomName = null, roomAvatar = null)
} }

2
features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListViewModel.kt

@ -131,7 +131,7 @@ class RoomListViewModel(initialState: RoomListViewState) :
} }
private suspend fun getClient(): MatrixClient { private suspend fun getClient(): MatrixClient {
return matrix.matrixClient().first().get() return matrix.client().first().get()
} }
override fun onCleared() { override fun onCleared() {

11
libraries/matrix/src/main/java/io/element/android/x/matrix/Matrix.kt

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

44
libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixClient.kt

@ -2,9 +2,14 @@ package io.element.android.x.matrix
import io.element.android.x.core.data.CoroutineDispatchers import io.element.android.x.core.data.CoroutineDispatchers
import io.element.android.x.matrix.core.UserId 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.RoomSummaryDataSource
import io.element.android.x.matrix.room.RoomSummaryDetailsFactory
import io.element.android.x.matrix.room.RustRoomSummaryDataSource 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.session.SessionStore
import io.element.android.x.matrix.sync.SlidingSyncObserverProxy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.* import org.matrix.rustcomponents.sdk.*
import timber.log.Timber import timber.log.Timber
@ -13,6 +18,7 @@ import java.io.Closeable
class MatrixClient internal constructor( class MatrixClient internal constructor(
private val client: Client, private val client: Client,
private val sessionStore: SessionStore, private val sessionStore: SessionStore,
private val coroutineScope: CoroutineScope,
private val dispatchers: CoroutineDispatchers, private val dispatchers: CoroutineDispatchers,
) : Closeable { ) : 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() private val slidingSyncView = SlidingSyncViewBuilder()
.timelineLimit(limit = 1u) .timelineLimit(limit = 1u)
.requiredState(requiredState = listOf( .requiredState(
RequiredState(key = "m.room.avatar", value = ""), requiredState = listOf(
RequiredState(key = "m.room.encryption", value = ""), RequiredState(key = "m.room.avatar", value = ""),
)) RequiredState(key = "m.room.name", value = ""),
RequiredState(key = "m.room.encryption", value = ""),
)
)
.name(name = "HomeScreenView") .name(name = "HomeScreenView")
.syncMode(mode = SlidingSyncMode.FULL_SYNC) .syncMode(mode = SlidingSyncMode.FULL_SYNC)
.build() .build()
@ -54,15 +56,28 @@ class MatrixClient internal constructor(
.addView(slidingSyncView) .addView(slidingSyncView)
.build() .build()
private val slidingSyncObserverProxy = SlidingSyncObserverProxy(coroutineScope)
private val roomSummaryDataSource: RustRoomSummaryDataSource = private val roomSummaryDataSource: RustRoomSummaryDataSource =
RustRoomSummaryDataSource(slidingSync, slidingSyncView, dispatchers) RustRoomSummaryDataSource(slidingSyncObserverProxy.updateSummaryFlow, slidingSync, slidingSyncView, dispatchers)
private var slidingSyncObserverToken: StoppableSpawn? = null private var slidingSyncObserverToken: StoppableSpawn? = null
init { init {
client.setDelegate(clientDelegate) 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() { fun startSync() {
slidingSync.setObserver(slidingSyncObserver) roomSummaryDataSource.startSync()
slidingSync.setObserver(slidingSyncObserverProxy)
slidingSyncObserverToken = slidingSync.sync() slidingSyncObserverToken = slidingSync.sync()
} }
@ -113,7 +128,8 @@ class MatrixClient internal constructor(
): Result<ByteArray> = ): Result<ByteArray> =
withContext(dispatchers.io) { withContext(dispatchers.io) {
runCatching { runCatching {
client.getMediaThumbnail(source, width.toULong(), height.toULong()).toUByteArray().toByteArray() client.getMediaThumbnail(source, width.toULong(), height.toULong()).toUByteArray()
.toByteArray()
} }
} }

41
libraries/matrix/src/main/java/io/element/android/x/matrix/room/MatrixRoom.kt

@ -1,11 +1,50 @@
package io.element.android.x.matrix.room package io.element.android.x.matrix.room
import io.element.android.x.matrix.core.RoomId 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.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 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()
}
} }

40
libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDataSource.kt

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

30
libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDetailsFactory.kt

@ -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
)
}
}

1
libraries/matrix/src/main/java/io/element/android/x/matrix/room/message/RoomMessageFactory.kt

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

20
libraries/matrix/src/main/java/io/element/android/x/matrix/sync/SlidingSyncObserverProxy.kt

@ -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…
Cancel
Save