featui): Timeline::subscribe() supports lazy backwards pagination.

This patch updates the pagination mechanism of the `Timeline` to support
lazy backwards pagination.

`Timeline::paginate_backwards` already does different things whether the
timeline focus is live or focused. When it's live, the method will first
try to paginate backwards lazily, by adjusting the `count` value of the
`Skip` stream used by the `Timeline::subscribe` method. If there is not
enough items to provide, the greedy pagination will run.
This commit is contained in:
Ivan Enderlin
2025-01-29 15:40:58 +01:00
parent 51feda1042
commit 7e59ae99d0
3 changed files with 38 additions and 4 deletions

View File

@@ -410,7 +410,28 @@ impl<P: RoomDataProvider> TimelineController<P> {
}
}
/// Run a backward pagination (in focused mode) and append the results to
/// Run a lazy backwards pagination (in live mode).
///
/// It adjusts the `count` value of the `Skip` higher-order stream so that
/// more items are pushed front in the timeline.
///
/// If no more items are available (i.e. if the `count` is zero), this
/// method returns `Some(needs)` where `needs` is the number of events that
/// must be unlazily backwards paginated.
pub(super) async fn live_lazy_paginate_backwards(&self, num_events: u16) -> Option<usize> {
let state = self.state.read().await;
let (count, needs) = state
.meta
.subscriber_skip_count
.compute_next_when_paginating_backwards(num_events.into());
state.meta.subscriber_skip_count.update(count, &state.timeline_focus);
needs
}
/// Run a backwards pagination (in focused mode) and append the results to
/// the timeline.
///
/// Returns whether we hit the start of the timeline.
@@ -439,7 +460,7 @@ impl<P: RoomDataProvider> TimelineController<P> {
Ok(hit_end_of_timeline)
}
/// Run a forward pagination (in focused mode) and append the results to
/// Run a forwards pagination (in focused mode) and append the results to
/// the timeline.
///
/// Returns whether we hit the end of the timeline.

View File

@@ -58,7 +58,7 @@ pub(in crate::timeline) struct TimelineState {
pub meta: TimelineMetadata,
/// The kind of focus of this timeline.
pub(super) timeline_focus: TimelineFocusKind,
pub timeline_focus: TimelineFocusKind,
}
impl TimelineState {

View File

@@ -32,8 +32,21 @@ impl super::Timeline {
///
/// Returns whether we hit the start of the timeline.
#[instrument(skip_all, fields(room_id = ?self.room().room_id()))]
pub async fn paginate_backwards(&self, num_events: u16) -> Result<bool, Error> {
pub async fn paginate_backwards(&self, mut num_events: u16) -> Result<bool, Error> {
if self.controller.is_live().await {
match self.controller.live_lazy_paginate_backwards(num_events).await {
Some(needed_num_events) => {
num_events = needed_num_events.try_into().expect(
"failed to cast `needed_num_events` (`usize`) into `num_events` (`usize`)",
);
}
None => {
// TODO: returning `false` is not true everytime, we need a way to know if
// lazy-loading has reached the end of the timeline.
return Ok(false);
}
}
Ok(self.live_paginate_backwards(num_events).await?)
} else {
Ok(self.controller.focused_paginate_backwards(num_events).await?)