Quickly branch pagination

This commit is contained in:
ganfra
2022-11-07 18:41:28 +01:00
parent da8b307339
commit bff815e2c5
6 changed files with 91 additions and 47 deletions

View File

@@ -8,11 +8,12 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
@@ -33,7 +34,14 @@ fun MessagesScreen(roomId: String) {
val roomTitle by viewModel.collectAsState(MessagesViewState::roomName)
val roomAvatar by viewModel.collectAsState(MessagesViewState::roomAvatar)
val timelineItems by viewModel.collectAsState(MessagesViewState::timelineItems)
MessagesContent(roomTitle, roomAvatar, timelineItems().orEmpty())
val hasMoreToLoad by viewModel.collectAsState(MessagesViewState::hasMoreToLoad)
MessagesContent(
roomTitle = roomTitle,
roomAvatar = roomAvatar,
timelineItems = timelineItems().orEmpty(),
hasMoreToLoad = hasMoreToLoad,
onReachedLoadMore = viewModel::loadMore
)
}
@Composable
@@ -41,6 +49,8 @@ fun MessagesContent(
roomTitle: String?,
roomAvatar: AvatarData?,
timelineItems: List<MatrixTimelineItem>,
hasMoreToLoad: Boolean,
onReachedLoadMore: () -> Unit,
) {
LogCompositions(tag = "MessagesScreen", msg = "Content")
val lazyListState = rememberLazyListState()
@@ -61,7 +71,9 @@ fun MessagesContent(
TimelineItems(
padding = padding,
lazyListState = lazyListState,
timelineItems = timelineItems
timelineItems = timelineItems,
hasMoreToLoad = hasMoreToLoad,
onReachedLoadMore = onReachedLoadMore,
)
}
)
@@ -71,7 +83,9 @@ fun MessagesContent(
fun TimelineItems(
padding: PaddingValues,
lazyListState: LazyListState,
timelineItems: List<MatrixTimelineItem>
timelineItems: List<MatrixTimelineItem>,
hasMoreToLoad: Boolean,
onReachedLoadMore: () -> Unit,
) {
LazyColumn(
modifier = Modifier
@@ -82,12 +96,18 @@ fun TimelineItems(
verticalArrangement = Arrangement.Bottom,
reverseLayout = true
) {
items(timelineItems) { timelineItem ->
itemsIndexed(timelineItems) { index, timelineItem ->
TimelineItemRow(timelineItem = timelineItem)
}
if (hasMoreToLoad) {
item {
MessagesLoadingMoreIndicator(onReachedLoadMore)
}
}
}
}
@Composable
fun TimelineItemRow(
timelineItem: MatrixTimelineItem
@@ -124,7 +144,7 @@ fun TimelineItemRow(
}
@Composable
internal fun MessagesLoadingMoreIndicator() {
internal fun MessagesLoadingMoreIndicator(onReachedLoadMore: () -> Unit) {
Box(
Modifier
.fillMaxWidth()
@@ -133,6 +153,10 @@ internal fun MessagesLoadingMoreIndicator() {
contentAlignment = Alignment.Center,
) {
CircularProgressIndicator(strokeWidth = 2.dp, color = MaterialTheme.colorScheme.primary)
LaunchedEffect(Unit) {
onReachedLoadMore()
}
}
}

View File

@@ -9,13 +9,17 @@ import io.element.android.x.features.messages.model.MessagesViewState
import io.element.android.x.matrix.MatrixClient
import io.element.android.x.matrix.MatrixInstance
import io.element.android.x.matrix.room.MatrixRoom
import io.element.android.x.matrix.timeline.MatrixTimeline
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import org.matrix.rustcomponents.sdk.mediaSourceFromUrl
private const val PAGINATION_COUNT = 50
class MessagesViewModel(
private val client: MatrixClient,
private val room: MatrixRoom,
private val timeline: MatrixTimeline,
private val initialState: MessagesViewState
) :
MavericksViewModel<MessagesViewState>(initialState) {
@@ -29,7 +33,7 @@ class MessagesViewModel(
val matrix = MatrixInstance.getInstance()
val client = matrix.activeClient()
val room = client.getRoom(state.roomId) ?: return null
return MessagesViewModel(client, room, state)
return MessagesViewModel(client, room, room.timeline(), state)
}
}
@@ -39,7 +43,18 @@ class MessagesViewModel(
handleInit()
}
fun loadMore(){
viewModelScope.launch {
timeline.paginateBackwards(PAGINATION_COUNT)
setState { copy(hasMoreToLoad = timeline.hasMoreToLoad) }
}
}
private fun handleInit() {
setState {
copy(hasMoreToLoad = timeline.hasMoreToLoad)
}
room.syncUpdateFlow()
.onEach {
val avatarData =
@@ -51,7 +66,7 @@ class MessagesViewModel(
}
}.launchIn(viewModelScope)
room.timeline().timelineItems()
timeline.timelineItems()
.execute {
copy(timelineItems = it)
}

View File

@@ -10,10 +10,15 @@ data class MessagesViewState(
val roomId: String,
val roomName: String? = null,
val roomAvatar: AvatarData? = null,
val timelineItems: Async<List<MatrixTimelineItem>> = Uninitialized
val timelineItems: Async<List<MatrixTimelineItem>> = Uninitialized,
val hasMoreToLoad: Boolean = false,
) : MavericksState {
@Suppress("unused")
constructor(roomId: String) : this(roomId = roomId, roomName = null, roomAvatar = null)
constructor(roomId: String) : this(
roomId = roomId,
roomName = null,
roomAvatar = null
)
}

View File

@@ -0,0 +1,2 @@
package io.element.android.x.core.data.flow

View File

@@ -3,10 +3,13 @@ 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.timeline.MatrixTimeline
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.*
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 slidingSyncUpdateFlow: Flow<UpdateSummary>,
@@ -15,7 +18,6 @@ class MatrixRoom(
private val coroutineDispatchers: CoroutineDispatchers,
) {
private val paginationOutcome = MutableStateFlow(PaginationOutcome(true))
fun syncUpdateFlow(): Flow<Unit> {
return slidingSyncUpdateFlow
.filter {
@@ -26,11 +28,7 @@ class MatrixRoom(
}
fun timeline(): MatrixTimeline {
return MatrixTimeline(this)
}
internal fun timelineDiff(): Flow<TimelineDiff> {
return room.timelineDiff()
return MatrixTimeline(this, room, coroutineDispatchers)
}
val roomId = RoomId(room.id())
@@ -55,18 +53,5 @@ class MatrixRoom(
return room.avatarUrl()
}
fun addTimelineListener(timelineListener: TimelineListener) {
room.addTimelineListener(timelineListener)
}
suspend fun paginateBackwards(count: Int): Result<Unit> = withContext(coroutineDispatchers.io) {
if (!paginationOutcome.value.moreMessages) {
return@withContext Result.failure(IllegalStateException("no more message"))
}
runCatching {
paginationOutcome.value = room.paginateBackwards(count.toUShort())
}
}
}

View File

@@ -1,17 +1,20 @@
package io.element.android.x.matrix.timeline
import io.element.android.x.core.data.CoroutineDispatchers
import io.element.android.x.matrix.core.EventId
import io.element.android.x.matrix.room.MatrixRoom
import io.element.android.x.matrix.room.timelineDiff
import kotlinx.coroutines.flow.*
import org.matrix.rustcomponents.sdk.TimelineChange
import org.matrix.rustcomponents.sdk.TimelineDiff
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.*
import timber.log.Timber
import java.util.*
class MatrixTimeline(
private val room: MatrixRoom,
private val matrixRoom: MatrixRoom,
private val room: Room,
private val coroutineDispatchers: CoroutineDispatchers,
) {
interface Callback {
fun onUpdatedTimelineItem(eventId: EventId)
fun onStartedBackPaginating()
@@ -20,6 +23,7 @@ class MatrixTimeline(
var callback: Callback? = null
private val paginationOutcome = MutableStateFlow(PaginationOutcome(true))
private val timelineItems: MutableStateFlow<List<MatrixTimelineItem>> =
MutableStateFlow(emptyList())
@@ -30,6 +34,12 @@ class MatrixTimeline(
}
}
val hasMoreToLoad: Boolean
get() {
return paginationOutcome.value.moreMessages
}
private fun diffFlow(): Flow<Unit> {
return room.timelineDiff()
.onEach { timelineDiff ->
@@ -78,28 +88,31 @@ class MatrixTimeline(
}
}
suspend fun paginateBackwards(count: Int): Result<Unit> = withContext(coroutineDispatchers.io) {
if (!paginationOutcome.value.moreMessages) {
return@withContext Result.failure(IllegalStateException("no more message"))
}
runCatching {
paginationOutcome.value = room.paginateBackwards(count.toUShort())
}
}
private fun updateTimelineItems(block: MutableList<MatrixTimelineItem>.() -> Unit) {
val mutableTimelineItems = timelineItems.value.toMutableList()
block(mutableTimelineItems)
timelineItems.value = mutableTimelineItems
}
suspend fun processItemAppearance(itemId: String) {
fun addListener(timelineListener: TimelineListener) {
room.addTimelineListener(timelineListener)
}
suspend fun processItemDisappearance(itemId: String) {
}
suspend fun paginateBackwards(count: Int): Result<Unit> {
return room.paginateBackwards(count)
fun dispose(){
room.removeTimeline()
}
suspend fun sendMessage(message: String): Result<Unit> {
return Result.success(Unit)
}
}