Merge pull request #731 from vector-im/feature/fga/timeline_back_pagination
Feature/fga/timeline back pagination
This commit is contained in:
commit
a2a5d251d1
8 changed files with 43 additions and 69 deletions
|
|
@ -59,21 +59,16 @@ class TimelinePresenter @Inject constructor(
|
|||
var lastReadMarkerIndex by rememberSaveable { mutableStateOf(Int.MAX_VALUE) }
|
||||
var lastReadMarkerId by rememberSaveable { mutableStateOf<EventId?>(null) }
|
||||
|
||||
val timelineItems = timelineItemsFactory
|
||||
.flow()
|
||||
.collectAsState()
|
||||
|
||||
val paginationState = timeline
|
||||
.paginationState()
|
||||
.collectAsState()
|
||||
val timelineItems by timelineItemsFactory.collectItemsAsState()
|
||||
val paginationState by timeline.paginationState.collectAsState()
|
||||
|
||||
fun handleEvents(event: TimelineEvents) {
|
||||
when (event) {
|
||||
TimelineEvents.LoadMore -> localCoroutineScope.loadMore(paginationState.value)
|
||||
TimelineEvents.LoadMore -> localCoroutineScope.loadMore(paginationState)
|
||||
is TimelineEvents.SetHighlightedEvent -> highlightedEventId.value = event.eventId
|
||||
is TimelineEvents.OnScrollFinished -> {
|
||||
// Get last valid EventId seen by the user, as the first index might refer to a Virtual item
|
||||
val eventId = getLastEventIdBeforeOrAt(event.firstIndex, timelineItems.value) ?: return
|
||||
val eventId = getLastEventIdBeforeOrAt(event.firstIndex, timelineItems) ?: return
|
||||
if (event.firstIndex <= lastReadMarkerIndex && eventId != lastReadMarkerId) {
|
||||
lastReadMarkerIndex = event.firstIndex
|
||||
lastReadMarkerId = eventId
|
||||
|
|
@ -85,11 +80,11 @@ class TimelinePresenter @Inject constructor(
|
|||
|
||||
LaunchedEffect(Unit) {
|
||||
timeline
|
||||
.timelineItems()
|
||||
.timelineItems
|
||||
.onEach(timelineItemsFactory::replaceWith)
|
||||
.onEach { timelineItems ->
|
||||
if (timelineItems.isEmpty()) {
|
||||
loadMore(paginationState.value)
|
||||
loadMore(paginationState)
|
||||
}
|
||||
}
|
||||
.launchIn(this)
|
||||
|
|
@ -97,8 +92,8 @@ class TimelinePresenter @Inject constructor(
|
|||
|
||||
return TimelineState(
|
||||
highlightedEventId = highlightedEventId.value,
|
||||
paginationState = paginationState.value,
|
||||
timelineItems = timelineItems.value,
|
||||
paginationState = paginationState,
|
||||
timelineItems = timelineItems,
|
||||
eventSink = ::handleEvents
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
|
|
@ -62,7 +61,6 @@ import io.element.android.libraries.designsystem.theme.components.Icon
|
|||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
|
|
@ -123,8 +121,7 @@ fun TimelineView(
|
|||
|
||||
TimelineScrollHelper(
|
||||
lazyListState = lazyListState,
|
||||
timelineItems = state.timelineItems,
|
||||
onLoadMore = ::onReachedLoadMore
|
||||
timelineItems = state.timelineItems
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -222,7 +219,6 @@ fun TimelineItemRow(
|
|||
internal fun BoxScope.TimelineScrollHelper(
|
||||
lazyListState: LazyListState,
|
||||
timelineItems: ImmutableList<TimelineItem>,
|
||||
onLoadMore: () -> Unit = {},
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val firstVisibleItemIndex by remember { derivedStateOf { lazyListState.firstVisibleItemIndex } }
|
||||
|
|
@ -236,24 +232,6 @@ internal fun BoxScope.TimelineScrollHelper(
|
|||
}
|
||||
}
|
||||
|
||||
// Handle load more preloading
|
||||
val loadMore by remember {
|
||||
derivedStateOf {
|
||||
val layoutInfo = lazyListState.layoutInfo
|
||||
val totalItemsNumber = layoutInfo.totalItemsCount
|
||||
val lastVisibleItemIndex = (layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0) + 1
|
||||
lastVisibleItemIndex > (totalItemsNumber - 30)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(loadMore) {
|
||||
snapshotFlow { loadMore }
|
||||
.distinctUntilChanged()
|
||||
.collect {
|
||||
onLoadMore()
|
||||
}
|
||||
}
|
||||
|
||||
// Jump to bottom button
|
||||
if (firstVisibleItemIndex > 2) {
|
||||
FloatingActionButton(
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
package io.element.android.features.messages.impl.timeline.factories
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import io.element.android.features.messages.impl.timeline.diff.CacheInvalidator
|
||||
import io.element.android.features.messages.impl.timeline.diff.MatrixTimelineItemsDiffCallback
|
||||
|
|
@ -27,11 +30,8 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
|||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -55,7 +55,10 @@ class TimelineItemsFactory @Inject constructor(
|
|||
private val lock = Mutex()
|
||||
private val cacheInvalidator = CacheInvalidator(timelineItemsCache)
|
||||
|
||||
fun flow(): StateFlow<ImmutableList<TimelineItem>> = timelineItems.asStateFlow()
|
||||
@Composable
|
||||
fun collectItemsAsState(): State<ImmutableList<TimelineItem>> {
|
||||
return timelineItems.collectAsState()
|
||||
}
|
||||
|
||||
suspend fun replaceWith(
|
||||
timelineItems: List<MatrixTimelineItem>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue