sdk-ui: create TimelineState::replace_all which combines clear and add_remote_events_at in the same transaction

This commit is contained in:
Jorge Martín
2024-09-10 08:56:03 +02:00
committed by Jorge Martin Espinosa
parent a6f84d8513
commit 08df153ed9
3 changed files with 62 additions and 6 deletions
@@ -637,8 +637,6 @@ impl<P: RoomDataProvider> TimelineController<P> {
) {
let mut state = self.state.write().await;
state.clear();
let track_read_markers = self.settings.track_read_receipts;
if track_read_markers {
state.populate_initial_user_receipt(&self.room_data_provider, ReceiptType::Read).await;
@@ -647,9 +645,14 @@ impl<P: RoomDataProvider> TimelineController<P> {
.await;
}
if !events.is_empty() {
// Replace the events if either the current event list or the new one aren't
// empty.
// Previously we just had to check the new one wasn't empty because
// we did a clear operation before so the current one would always be empty, but
// now we may want to replace a populated timeline with an empty one.
if !state.items.is_empty() || !events.is_empty() {
state
.add_remote_events_at(
.replace_with_remove_events(
events,
TimelineEnd::Back,
origin,
@@ -63,7 +63,7 @@ use crate::{
pub(crate) enum TimelineEnd {
/// Event should be prepended to the front of the timeline.
Front,
/// Event should appended to the back of the timeline.
/// Event should be appended to the back of the timeline.
Back,
}
@@ -101,7 +101,7 @@ impl TimelineState {
}
}
/// Add the given remove events at the given end of the timeline.
/// Add the given remote events at the given end of the timeline.
///
/// Note: when the `position` is [`TimelineEnd::Front`], prepended events
/// should be ordered in *reverse* topological order, that is, `events[0]`
@@ -274,6 +274,27 @@ impl TimelineState {
txn.commit();
}
/// Replaces the existing events in the timeline with the given remote ones.
///
/// Note: when the `position` is [`TimelineEnd::Front`], prepended events
/// should be ordered in *reverse* topological order, that is, `events[0]`
/// is the most recent.
pub(super) async fn replace_with_remove_events<P: RoomDataProvider>(
&mut self,
events: Vec<SyncTimelineEvent>,
position: TimelineEnd,
origin: RemoteEventOrigin,
room_data_provider: &P,
settings: &TimelineSettings,
) -> HandleManyEventsResult {
let mut txn = self.transaction();
txn.clear();
let result =
txn.add_remote_events_at(events, position, origin, room_data_provider, settings).await;
txn.commit();
result
}
pub(super) fn transaction(&mut self) -> TimelineStateTransaction<'_> {
let items = self.items.transaction();
let meta = self.meta.clone();
@@ -15,6 +15,7 @@
use assert_matches::assert_matches;
use assert_matches2::assert_let;
use eyeball_im::VectorDiff;
use futures_util::StreamExt;
use matrix_sdk_test::{async_test, sync_timeline_event, ALICE, BOB, CAROL};
use ruma::{
events::{
@@ -505,3 +506,34 @@ async fn test_thread() {
assert_let!(TimelineDetails::Ready(replied_to_event) = &in_reply_to.event);
assert_eq!(replied_to_event.sender(), *ALICE);
}
#[async_test]
async fn test_replace_with_initial_events_when_batched() {
let timeline = TestTimeline::with_room_data_provider(TestRoomDataProvider::default())
.with_settings(TimelineSettings::default());
let f = &timeline.factory;
let ev = f.text_msg("hey").sender(*ALICE).into_sync();
timeline.controller.add_events_at(vec![ev], TimelineEnd::Back, RemoteEventOrigin::Sync).await;
let (items, mut stream) = timeline.controller.subscribe_batched().await;
assert_eq!(items.len(), 2);
assert!(items[0].is_day_divider());
assert_eq!(items[1].as_event().unwrap().content().as_message().unwrap().body(), "hey");
let ev = f.text_msg("yo").sender(*BOB).into_sync();
timeline.controller.replace_with_initial_remote_events(vec![ev], RemoteEventOrigin::Sync).await;
// Assert there are more than a single Clear diff in the next batch:
// Clear + PushBack (event) + PushFront (day divider)
let batched_diffs = stream.next().await.unwrap();
assert_eq!(batched_diffs.len(), 3);
assert_matches!(batched_diffs[0], VectorDiff::Clear);
assert_matches!(&batched_diffs[1], VectorDiff::PushBack { value } => {
assert!(value.as_event().is_some());
});
assert_matches!(&batched_diffs[2], VectorDiff::PushFront { value } => {
assert_matches!(value.as_virtual(), Some(VirtualTimelineItem::DayDivider(_)));
});
}