MatrixRoom API refinement (#719)

- `syncUpdateFlow` becomes a `val` and always returns the same instance of the underlying `StateFlow` instead of different `Flow` instances to allow consumers not to remember the `Flow` and not to specify an unneeded initial value.
- `timeline` becomes a `val` as it already always returns the same instance.
- Amends calling code accordingly
- Removes a few unneeded `val`s in `RustMatrixClient
- Fixes a small bug in `MessagesPresenter` that allowed to sometime show a newly created room's name as "Empty room" (changes `LaunchedEffect(syncUpdateFlow)` to `LaunchedEffect(syncUpdateFlow.value)`)
This commit is contained in:
Marco Romano 2023-06-29 10:48:55 +02:00 committed by GitHub
parent 79f7537c0b
commit b504dbe5f0
8 changed files with 23 additions and 34 deletions

View file

@ -99,7 +99,7 @@ class MessagesPresenter @AssistedInject constructor(
val customReactionState = customReactionPresenter.present() val customReactionState = customReactionPresenter.present()
val retryState = retrySendMenuPresenter.present() val retryState = retrySendMenuPresenter.present()
val syncUpdateFlow = room.syncUpdateFlow().collectAsState(0L) val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
val userHasPermissionToSendMessage by room.canSendEventAsState(type = MessageEventType.ROOM_MESSAGE, updateKey = syncUpdateFlow.value) val userHasPermissionToSendMessage by room.canSendEventAsState(type = MessageEventType.ROOM_MESSAGE, updateKey = syncUpdateFlow.value)
val roomName: MutableState<String?> = rememberSaveable { val roomName: MutableState<String?> = rememberSaveable {
mutableStateOf(null) mutableStateOf(null)
@ -112,7 +112,7 @@ class MessagesPresenter @AssistedInject constructor(
val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState() val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState()
LaunchedEffect(syncUpdateFlow) { LaunchedEffect(syncUpdateFlow.value) {
roomAvatar.value = roomAvatar.value =
AvatarData( AvatarData(
id = room.roomId.value, id = room.roomId.value,

View file

@ -43,7 +43,7 @@ class TimelinePresenter @Inject constructor(
room: MatrixRoom, room: MatrixRoom,
) : Presenter<TimelineState> { ) : Presenter<TimelineState> {
private val timeline = room.timeline() private val timeline = room.timeline
@Composable @Composable
override fun present(): TimelineState { override fun present(): TimelineState {

View file

@ -52,7 +52,7 @@ class RoomDetailsEditPresenter @Inject constructor(
@Composable @Composable
override fun present(): RoomDetailsEditState { override fun present(): RoomDetailsEditState {
val roomSyncUpdateFlow = room.syncUpdateFlow().collectAsState(0L) val roomSyncUpdateFlow = room.syncUpdateFlow.collectAsState()
// Since there is no way to obtain the new avatar uri after uploading a new avatar, // Since there is no way to obtain the new avatar uri after uploading a new avatar,
// just erase the local value when the room field has changed // just erase the local value when the room field has changed

View file

@ -58,9 +58,9 @@ interface MatrixRoom : Closeable {
*/ */
suspend fun updateMembers(): Result<Unit> suspend fun updateMembers(): Result<Unit>
fun syncUpdateFlow(): Flow<Long> val syncUpdateFlow: StateFlow<Long>
fun timeline(): MatrixTimeline val timeline: MatrixTimeline
fun open(): Result<Unit> fun open(): Result<Unit>

View file

@ -73,10 +73,10 @@ import org.matrix.rustcomponents.sdk.RoomVisibility as RustRoomVisibility
class RustMatrixClient constructor( class RustMatrixClient constructor(
private val client: Client, private val client: Client,
private val sessionStore: SessionStore, private val sessionStore: SessionStore,
private val appCoroutineScope: CoroutineScope, appCoroutineScope: CoroutineScope,
private val dispatchers: CoroutineDispatchers, private val dispatchers: CoroutineDispatchers,
private val baseDirectory: File, private val baseDirectory: File,
private val baseCacheDirectory: File, baseCacheDirectory: File,
private val clock: SystemClock, private val clock: SystemClock,
) : MatrixClient { ) : MatrixClient {

View file

@ -44,6 +44,7 @@ import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -71,15 +72,10 @@ class RustMatrixRoom(
override val roomId = RoomId(innerRoom.id()) override val roomId = RoomId(innerRoom.id())
private val roomCoroutineScope = sessionCoroutineScope.childScope(coroutineDispatchers.main, "RoomScope-$roomId") private val roomCoroutineScope = sessionCoroutineScope.childScope(coroutineDispatchers.main, "RoomScope-$roomId")
private val _membersStateFlow = MutableStateFlow<MatrixRoomMembersState>(MatrixRoomMembersState.Unknown)
override val membersStateFlow: StateFlow<MatrixRoomMembersState>
get() = _membersStateFlow
private var _membersStateFlow = MutableStateFlow<MatrixRoomMembersState>(MatrixRoomMembersState.Unknown)
private val isInit = MutableStateFlow(false) private val isInit = MutableStateFlow(false)
private val syncUpdateFlow = MutableStateFlow(systemClock.epochMillis()) private val _syncUpdateFlow = MutableStateFlow(0L)
private val _timeline by lazy {
private val timeline by lazy {
RustMatrixTimeline( RustMatrixTimeline(
matrixRoom = this, matrixRoom = this,
innerRoom = innerRoom, innerRoom = innerRoom,
@ -88,13 +84,11 @@ class RustMatrixRoom(
) )
} }
override fun syncUpdateFlow(): Flow<Long> { override val membersStateFlow: StateFlow<MatrixRoomMembersState> = _membersStateFlow.asStateFlow()
return syncUpdateFlow
}
override fun timeline(): MatrixTimeline { override val syncUpdateFlow: StateFlow<Long> = _syncUpdateFlow.asStateFlow()
return timeline
} override val timeline: MatrixTimeline = _timeline
override fun open(): Result<Unit> { override fun open(): Result<Unit> {
if (isInit.value) return Result.failure(IllegalStateException("Listener already registered")) if (isInit.value) return Result.failure(IllegalStateException("Listener already registered"))
@ -110,10 +104,10 @@ class RustMatrixRoom(
roomListItem.subscribe(settings) roomListItem.subscribe(settings)
roomCoroutineScope.launch(coroutineDispatchers.computation) { roomCoroutineScope.launch(coroutineDispatchers.computation) {
innerRoom.timelineDiffFlow { initialList -> innerRoom.timelineDiffFlow { initialList ->
timeline.postItems(initialList) _timeline.postItems(initialList)
}.onEach { }.onEach {
syncUpdateFlow.value = systemClock.epochMillis() _syncUpdateFlow.value = systemClock.epochMillis()
timeline.postDiff(it) _timeline.postDiff(it)
}.launchIn(this) }.launchIn(this)
fetchMembers() fetchMembers()
} }

View file

@ -34,9 +34,8 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
import io.element.android.tests.testutils.simulateLongTask import io.element.android.tests.testutils.simulateLongTask
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.StateFlow
import java.io.File import java.io.File
class FakeMatrixRoom( class FakeMatrixRoom(
@ -126,13 +125,9 @@ class FakeMatrixRoom(
updateMembersResult updateMembersResult
} }
override fun syncUpdateFlow(): Flow<Long> { override val syncUpdateFlow: StateFlow<Long> = MutableStateFlow(0L)
return emptyFlow()
}
override fun timeline(): MatrixTimeline { override val timeline: MatrixTimeline = matrixTimeline
return matrixTimeline
}
override fun open(): Result<Unit> { override fun open(): Result<Unit> {
return Result.success(Unit) return Result.success(Unit)

View file

@ -82,7 +82,7 @@ class RoomListScreen(
withContext(coroutineDispatchers.io) { withContext(coroutineDispatchers.io) {
matrixClient.getRoom(roomId)!!.use { room -> matrixClient.getRoom(roomId)!!.use { room ->
room.open() room.open()
val timeline = room.timeline() val timeline = room.timeline
timeline.apply { timeline.apply {
// TODO This doesn't work reliably as initialize is asynchronous, and the timeline can't be used until it's finished // TODO This doesn't work reliably as initialize is asynchronous, and the timeline can't be used until it's finished
paginateBackwards(20, 50) paginateBackwards(20, 50)