From 7e59ae99d0de08e72a956dfd29f68e942de9a8ed Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 29 Jan 2025 15:40:58 +0100 Subject: [PATCH] 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. --- .../src/timeline/controller/mod.rs | 25 +++++++++++++++++-- .../src/timeline/controller/state.rs | 2 +- .../matrix-sdk-ui/src/timeline/pagination.rs | 15 ++++++++++- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/crates/matrix-sdk-ui/src/timeline/controller/mod.rs b/crates/matrix-sdk-ui/src/timeline/controller/mod.rs index b7e55537e..78ebec3d1 100644 --- a/crates/matrix-sdk-ui/src/timeline/controller/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/controller/mod.rs @@ -410,7 +410,28 @@ impl TimelineController

{ } } - /// 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 { + 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 TimelineController

{ 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. diff --git a/crates/matrix-sdk-ui/src/timeline/controller/state.rs b/crates/matrix-sdk-ui/src/timeline/controller/state.rs index be78978ae..e00002ab4 100644 --- a/crates/matrix-sdk-ui/src/timeline/controller/state.rs +++ b/crates/matrix-sdk-ui/src/timeline/controller/state.rs @@ -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 { diff --git a/crates/matrix-sdk-ui/src/timeline/pagination.rs b/crates/matrix-sdk-ui/src/timeline/pagination.rs index 4c79f5a4b..273183650 100644 --- a/crates/matrix-sdk-ui/src/timeline/pagination.rs +++ b/crates/matrix-sdk-ui/src/timeline/pagination.rs @@ -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 { + pub async fn paginate_backwards(&self, mut num_events: u16) -> Result { 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?)