Skip to content

Commit 8f129eb

Browse files
committed
Try improved version using snapshotFlow, which seems more performant, as well as an extended threshold (-40 items)
1 parent d15b227 commit 8f129eb

File tree

1 file changed

+42
-11
lines changed
  • features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline

1 file changed

+42
-11
lines changed

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import androidx.compose.runtime.remember
3636
import androidx.compose.runtime.rememberCoroutineScope
3737
import androidx.compose.runtime.rememberUpdatedState
3838
import androidx.compose.runtime.setValue
39+
import androidx.compose.runtime.snapshotFlow
3940
import androidx.compose.ui.Alignment
4041
import androidx.compose.ui.Modifier
4142
import androidx.compose.ui.draw.rotate
@@ -72,6 +73,10 @@ import io.element.android.libraries.matrix.api.core.EventId
7273
import io.element.android.libraries.matrix.api.core.UserId
7374
import io.element.android.libraries.matrix.api.timeline.Timeline
7475
import io.element.android.libraries.ui.strings.CommonStrings
76+
import kotlinx.coroutines.ExperimentalCoroutinesApi
77+
import kotlinx.coroutines.flow.collectLatest
78+
import kotlinx.coroutines.flow.combine
79+
import kotlinx.coroutines.flow.distinctUntilChanged
7580
import kotlinx.coroutines.launch
7681
import timber.log.Timber
7782

@@ -177,17 +182,8 @@ fun TimelineView(
177182
onClearFocusRequestState = ::clearFocusRequestState
178183
)
179184

180-
val isCloseToStartOfLoadedTimeline by remember {
181-
derivedStateOf {
182-
lazyListState.firstVisibleItemIndex + lazyListState.layoutInfo.visibleItemsInfo.size >= lazyListState.layoutInfo.totalItemsCount - 10
183-
}
184-
}
185-
LaunchedEffect(isCloseToStartOfLoadedTimeline) {
186-
// Only back paginate when we're close to the start of the loaded timeline items and the user is actively scrolling
187-
if (lazyListState.isScrollInProgress && isCloseToStartOfLoadedTimeline) {
188-
Timber.d("Prefetching pagination with ${lazyListState.layoutInfo.totalItemsCount} items")
189-
state.eventSink(TimelineEvents.LoadMore(Timeline.PaginationDirection.BACKWARDS))
190-
}
185+
TimelinePrefetchingHelper(lazyListState = lazyListState) {
186+
state.eventSink(TimelineEvents.LoadMore(Timeline.PaginationDirection.BACKWARDS))
191187
}
192188

193189
TimelineScrollHelper(
@@ -218,6 +214,41 @@ private fun MessageShieldDialog(state: TimelineState) {
218214
)
219215
}
220216

217+
@OptIn(ExperimentalCoroutinesApi::class)
218+
@Composable
219+
private fun TimelinePrefetchingHelper(
220+
lazyListState: LazyListState,
221+
prefetch: () -> Unit,
222+
) {
223+
// We're using snapshot flows for these because using `LaunchedEffect` with `derivedState` doesn't seem to be responsive enough
224+
val firstVisibleItemIndexFlow = snapshotFlow {
225+
lazyListState.firstVisibleItemIndex
226+
}
227+
val layoutInfoFlow = snapshotFlow {
228+
lazyListState.layoutInfo
229+
}
230+
val isScrollingFlow = snapshotFlow {
231+
lazyListState.isScrollInProgress
232+
}
233+
234+
LaunchedEffect(Unit) {
235+
val isCloseToStartOfLoadedTimelineFlow = combine(layoutInfoFlow, firstVisibleItemIndexFlow) { layoutInfo, firstVisibleItemIndex ->
236+
firstVisibleItemIndex + layoutInfo.visibleItemsInfo.size >= layoutInfo.totalItemsCount - 40
237+
}
238+
239+
combine(isCloseToStartOfLoadedTimelineFlow, isScrollingFlow) { needsPrefetch, isScrolling ->
240+
needsPrefetch && isScrolling
241+
}
242+
.distinctUntilChanged()
243+
.collectLatest { needsPrefetch ->
244+
if (needsPrefetch) {
245+
Timber.d("Prefetching pagination with ${lazyListState.layoutInfo.totalItemsCount} items")
246+
prefetch()
247+
}
248+
}
249+
}
250+
}
251+
221252
@Composable
222253
private fun BoxScope.TimelineScrollHelper(
223254
hasAnyEvent: Boolean,

0 commit comments

Comments
 (0)