refactor(ui): Timeline receives pagination events as VectorDiffs!

This patch allows the paginated events of a `Timeline` to be received
via `RoomEventCacheUpdate::UpdateTimelineEvents` as `VectorDiff`s.
This commit is contained in:
Ivan Enderlin
2024-12-17 17:30:44 +01:00
parent d8dd72fd9c
commit f1842ba5d0
4 changed files with 45 additions and 9 deletions

View File

@@ -124,7 +124,7 @@ pub(super) struct TimelineController<P: RoomDataProvider = Room> {
pub(crate) room_data_provider: P,
/// Settings applied to this timeline.
settings: TimelineSettings,
pub(super) settings: TimelineSettings,
}
#[derive(Clone)]

View File

@@ -77,12 +77,16 @@ impl super::Timeline {
let num_events = events.len();
trace!("Back-pagination succeeded with {num_events} events");
// TODO(hywan): Remove, and let spread events via
// `matrix_sdk::event_cache::RoomEventCacheUpdate` from
// `matrix_sdk::event_cache::RoomPagination::run_backwards`.
self.controller
.add_events_at(events.into_iter(), TimelineNewItemPosition::Start { origin: RemoteEventOrigin::Pagination })
.await;
// If `TimelineSettings::vectordiffs_as_inputs` is enabled,
// we don't need to add events manually: everything we need
// is to let the `EventCache` receive the events from this
// pagination, and emit its updates as `VectorDiff`s, which
// will be handled by the `Timeline` naturally.
if !self.controller.settings.vectordiffs_as_inputs {
self.controller
.add_events_at(events.into_iter(), TimelineNewItemPosition::Start { origin: RemoteEventOrigin::Pagination })
.await;
}
if num_events == 0 && !reached_start {
// As an exceptional contract: if there were no events in the response,

View File

@@ -28,7 +28,7 @@ use super::{
events::{Gap, RoomEvents},
RoomEventCacheInner,
},
BackPaginationOutcome, Result,
BackPaginationOutcome, EventsOrigin, Result, RoomEventCacheUpdate,
};
/// An API object to run pagination queries on a [`super::RoomEventCache`].
@@ -227,6 +227,15 @@ impl RoomPagination {
debug!("not storing previous batch token, because we deduplicated all new back-paginated events");
}
let sync_timeline_events_diffs = room_events.updates_as_vector_diffs();
if !sync_timeline_events_diffs.is_empty() {
let _ = self.inner.sender.send(RoomEventCacheUpdate::UpdateTimelineEvents {
diffs: sync_timeline_events_diffs,
origin: EventsOrigin::Sync,
});
}
BackPaginationOutcome { events, reached_start }
})
.await?;

View File

@@ -281,6 +281,9 @@ async fn test_backpaginate_once() {
assert_event_matches_msg(&events[1], "hello");
assert_eq!(events.len(), 2);
let next = room_stream.recv().now_or_never();
assert_matches!(next, Some(Ok(RoomEventCacheUpdate::UpdateTimelineEvents { .. })));
let next = room_stream.recv().now_or_never();
assert_matches!(next, None);
}
@@ -400,6 +403,14 @@ async fn test_backpaginate_many_times_with_many_iterations() {
assert_event_matches_msg(&events[3], "heyo");
assert_eq!(events.len(), 4);
// First iteration.
let next = room_stream.recv().now_or_never();
assert_matches!(next, Some(Ok(RoomEventCacheUpdate::UpdateTimelineEvents { .. })));
// Second iteration.
let next = room_stream.recv().now_or_never();
assert_matches!(next, Some(Ok(RoomEventCacheUpdate::UpdateTimelineEvents { .. })));
assert!(room_stream.is_empty());
}
@@ -523,6 +534,14 @@ async fn test_backpaginate_many_times_with_one_iteration() {
assert_event_matches_msg(&events[3], "heyo");
assert_eq!(events.len(), 4);
// First pagination.
let next = room_stream.recv().now_or_never();
assert_matches!(next, Some(Ok(RoomEventCacheUpdate::UpdateTimelineEvents { .. })));
// Second pagination.
let next = room_stream.recv().now_or_never();
assert_matches!(next, Some(Ok(RoomEventCacheUpdate::UpdateTimelineEvents { .. })));
assert!(room_stream.is_empty());
}
@@ -680,7 +699,7 @@ async fn test_backpaginating_without_token() {
let room = server.sync_joined_room(&client, room_id).await;
let (room_event_cache, _drop_handles) = room.event_cache().await.unwrap();
let (events, room_stream) = room_event_cache.subscribe().await.unwrap();
let (events, mut room_stream) = room_event_cache.subscribe().await.unwrap();
assert!(events.is_empty());
assert!(room_stream.is_empty());
@@ -712,6 +731,9 @@ async fn test_backpaginating_without_token() {
assert_event_matches_msg(&events[0], "hi");
assert_eq!(events.len(), 1);
let next = room_stream.recv().now_or_never();
assert_matches!(next, Some(Ok(RoomEventCacheUpdate::UpdateTimelineEvents { .. })));
assert!(room_stream.is_empty());
}
@@ -772,6 +794,7 @@ async fn test_limited_timeline_resets_pagination() {
server.sync_room(&client, JoinedRoomBuilder::new(room_id).set_timeline_limited()).await;
// We receive an update about the limited timeline.
assert_let_timeout!(Ok(RoomEventCacheUpdate::UpdateTimelineEvents { .. }) = room_stream.recv());
assert_let_timeout!(Ok(RoomEventCacheUpdate::Clear) = room_stream.recv());
// The paginator state is reset: status set to Initial, hasn't hit the timeline