Skip to content

Commit 7af3bbf

Browse files
committed
chore(ui): make latest_user_read_receipt rely on the timeline for finding the latest user receipt
- also update the tests accordingly as they now need to insert timeline events and take into consideration that own receipts are not displayed
1 parent 8fb6356 commit 7af3bbf

File tree

3 files changed

+183
-127
lines changed

3 files changed

+183
-127
lines changed

crates/matrix-sdk-ui/src/timeline/controller/mod.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,13 +1225,16 @@ impl<P: RoomDataProvider, D: Decryptor> TimelineController<P, D> {
12251225
&self,
12261226
user_id: &UserId,
12271227
) -> Option<(OwnedEventId, Receipt)> {
1228-
let receipt_thread = self.focus.receipt_thread();
1229-
1230-
self.state
1231-
.read()
1232-
.await
1233-
.latest_user_read_receipt(user_id, receipt_thread, &self.room_data_provider)
1234-
.await
1228+
self.items().await.iter().rev().find_map(|item| {
1229+
if let Some(event) = item.as_event()
1230+
&& let Some(event_id) = event.event_id()
1231+
&& let Some(receipt) = event.read_receipts().get(user_id)
1232+
{
1233+
Some((event_id.to_owned(), receipt.clone()))
1234+
} else {
1235+
None
1236+
}
1237+
})
12351238
}
12361239

12371240
/// Get the ID of the timeline event with the latest read receipt for the

crates/matrix-sdk-ui/src/timeline/tests/read_receipts.rs

Lines changed: 140 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -516,22 +516,32 @@ async fn test_initial_public_unthreaded_receipt() {
516516

517517
// Add initial unthreaded public receipt.
518518
let mut initial_user_receipts = ReadReceiptMap::new();
519-
initial_user_receipts
519+
let unthreaded_read_receipts = initial_user_receipts
520520
.entry(ReceiptType::Read)
521521
.or_default()
522522
.entry(ReceiptThread::Unthreaded)
523-
.or_default()
524-
.insert(
525-
ALICE.to_owned(),
526-
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
527-
);
523+
.or_default();
524+
unthreaded_read_receipts.insert(
525+
ALICE.to_owned(),
526+
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
527+
);
528+
unthreaded_read_receipts.insert(
529+
BOB.to_owned(),
530+
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
531+
);
528532

529533
let timeline = TestTimelineBuilder::new()
530534
.provider(TestRoomDataProvider::default().with_initial_user_receipts(initial_user_receipts))
531535
.settings(TimelineSettings { track_read_receipts: true, ..Default::default() })
532536
.build();
533537

534-
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*ALICE).await.unwrap();
538+
timeline
539+
.handle_live_event(timeline.factory.text_msg("A").sender(*ALICE).event_id(&event_id))
540+
.await;
541+
542+
// The current user should not see their own read receipt.
543+
assert!(timeline.controller.latest_user_read_receipt(*ALICE).await.is_none());
544+
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*BOB).await.unwrap();
535545
assert_eq!(receipt_event_id, event_id);
536546
}
537547

@@ -541,22 +551,32 @@ async fn test_initial_public_main_thread_receipt() {
541551

542552
// Add initial public receipt on the main thread.
543553
let mut initial_user_receipts = ReadReceiptMap::new();
544-
initial_user_receipts
554+
let main_thread_receipts = initial_user_receipts
545555
.entry(ReceiptType::Read)
546556
.or_default()
547557
.entry(ReceiptThread::Main)
548-
.or_default()
549-
.insert(
550-
ALICE.to_owned(),
551-
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
552-
);
558+
.or_default();
559+
main_thread_receipts.insert(
560+
ALICE.to_owned(),
561+
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
562+
);
563+
main_thread_receipts.insert(
564+
BOB.to_owned(),
565+
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
566+
);
553567

554568
let timeline = TestTimelineBuilder::new()
555569
.provider(TestRoomDataProvider::default().with_initial_user_receipts(initial_user_receipts))
556570
.settings(TimelineSettings { track_read_receipts: true, ..Default::default() })
557571
.build();
558572

559-
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*ALICE).await.unwrap();
573+
timeline
574+
.handle_live_event(timeline.factory.text_msg("A").sender(*ALICE).event_id(&event_id))
575+
.await;
576+
577+
// The current user should not see their own read receipt.
578+
assert!(timeline.controller.latest_user_read_receipt(*ALICE).await.is_none());
579+
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*BOB).await.unwrap();
560580
assert_eq!(receipt_event_id, event_id);
561581
}
562582

@@ -567,23 +587,33 @@ async fn test_initial_public_unthreaded_receipt_main_threaded_timeline() {
567587
// Add an initial unthreaded public receipt and expect it to be considered on a
568588
// main threaded timeline.
569589
let mut initial_user_receipts = ReadReceiptMap::new();
570-
initial_user_receipts
590+
let unthreaded_receipts = initial_user_receipts
571591
.entry(ReceiptType::Read)
572592
.or_default()
573593
.entry(ReceiptThread::Unthreaded)
574-
.or_default()
575-
.insert(
576-
ALICE.to_owned(),
577-
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
578-
);
594+
.or_default();
595+
unthreaded_receipts.insert(
596+
ALICE.to_owned(),
597+
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
598+
);
599+
unthreaded_receipts.insert(
600+
BOB.to_owned(),
601+
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
602+
);
579603

580604
let timeline = TestTimelineBuilder::new()
581605
.focus(TimelineFocus::Live { hide_threaded_events: true })
582606
.provider(TestRoomDataProvider::default().with_initial_user_receipts(initial_user_receipts))
583607
.settings(TimelineSettings { track_read_receipts: true, ..Default::default() })
584608
.build();
585609

586-
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*ALICE).await.unwrap();
610+
timeline
611+
.handle_live_event(timeline.factory.text_msg("A").sender(*ALICE).event_id(&event_id))
612+
.await;
613+
614+
// The current user should not see their own read receipt.
615+
assert!(timeline.controller.latest_user_read_receipt(*ALICE).await.is_none());
616+
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*BOB).await.unwrap();
587617
assert_eq!(receipt_event_id, event_id);
588618
}
589619

@@ -593,22 +623,32 @@ async fn test_initial_private_unthreaded_receipt() {
593623

594624
// Add initial unthreaded private receipt.
595625
let mut initial_user_receipts = ReadReceiptMap::new();
596-
initial_user_receipts
626+
let unthreaded_receipts = initial_user_receipts
597627
.entry(ReceiptType::ReadPrivate)
598628
.or_default()
599629
.entry(ReceiptThread::Unthreaded)
600-
.or_default()
601-
.insert(
602-
ALICE.to_owned(),
603-
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
604-
);
630+
.or_default();
631+
unthreaded_receipts.insert(
632+
ALICE.to_owned(),
633+
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
634+
);
635+
unthreaded_receipts.insert(
636+
BOB.to_owned(),
637+
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
638+
);
605639

606640
let timeline = TestTimelineBuilder::new()
607641
.provider(TestRoomDataProvider::default().with_initial_user_receipts(initial_user_receipts))
608642
.settings(TimelineSettings { track_read_receipts: true, ..Default::default() })
609643
.build();
610644

611-
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*ALICE).await.unwrap();
645+
timeline
646+
.handle_live_event(timeline.factory.text_msg("A").sender(*ALICE).event_id(&event_id))
647+
.await;
648+
649+
// The current user should not see their own read receipt.
650+
assert!(timeline.controller.latest_user_read_receipt(*ALICE).await.is_none());
651+
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*BOB).await.unwrap();
612652
assert_eq!(receipt_event_id, event_id);
613653
}
614654

@@ -618,22 +658,32 @@ async fn test_initial_private_main_thread_receipt() {
618658

619659
// Add initial private receipt on the main thread.
620660
let mut initial_user_receipts = ReadReceiptMap::new();
621-
initial_user_receipts
661+
let main_thread_receipts = initial_user_receipts
622662
.entry(ReceiptType::ReadPrivate)
623663
.or_default()
624664
.entry(ReceiptThread::Main)
625-
.or_default()
626-
.insert(
627-
ALICE.to_owned(),
628-
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
629-
);
665+
.or_default();
666+
main_thread_receipts.insert(
667+
ALICE.to_owned(),
668+
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
669+
);
670+
main_thread_receipts.insert(
671+
BOB.to_owned(),
672+
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
673+
);
630674

631675
let timeline = TestTimelineBuilder::new()
632676
.provider(TestRoomDataProvider::default().with_initial_user_receipts(initial_user_receipts))
633677
.settings(TimelineSettings { track_read_receipts: true, ..Default::default() })
634678
.build();
635679

636-
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*ALICE).await.unwrap();
680+
timeline
681+
.handle_live_event(timeline.factory.text_msg("A").sender(*ALICE).event_id(&event_id))
682+
.await;
683+
684+
// The current user should not see their own read receipt.
685+
assert!(timeline.controller.latest_user_read_receipt(*ALICE).await.is_none());
686+
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*BOB).await.unwrap();
637687
assert_eq!(receipt_event_id, event_id);
638688
}
639689

@@ -644,23 +694,33 @@ async fn test_initial_private_unthreaded_receipt_main_threaded_timeline() {
644694
// Add an initial unthreaded private receipt and expect it to be considered on a
645695
// main threaded timeline.
646696
let mut initial_user_receipts = ReadReceiptMap::new();
647-
initial_user_receipts
697+
let unthreaded_receipts = initial_user_receipts
648698
.entry(ReceiptType::ReadPrivate)
649699
.or_default()
650700
.entry(ReceiptThread::Unthreaded)
651-
.or_default()
652-
.insert(
653-
ALICE.to_owned(),
654-
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
655-
);
701+
.or_default();
702+
unthreaded_receipts.insert(
703+
ALICE.to_owned(),
704+
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
705+
);
706+
unthreaded_receipts.insert(
707+
BOB.to_owned(),
708+
(event_id.clone(), Receipt::new(ruma::MilliSecondsSinceUnixEpoch(uint!(10)))),
709+
);
656710

657711
let timeline = TestTimelineBuilder::new()
658712
.focus(TimelineFocus::Live { hide_threaded_events: true })
659713
.provider(TestRoomDataProvider::default().with_initial_user_receipts(initial_user_receipts))
660714
.settings(TimelineSettings { track_read_receipts: true, ..Default::default() })
661715
.build();
662716

663-
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*ALICE).await.unwrap();
717+
timeline
718+
.handle_live_event(timeline.factory.text_msg("A").sender(*ALICE).event_id(&event_id))
719+
.await;
720+
721+
// The current user should not see their own read receipt.
722+
assert!(timeline.controller.latest_user_read_receipt(*ALICE).await.is_none());
723+
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*BOB).await.unwrap();
664724
assert_eq!(receipt_event_id, event_id);
665725
}
666726

@@ -754,13 +814,10 @@ async fn test_implicit_read_receipt_before_explicit_read_receipt() {
754814
.settings(TimelineSettings { track_read_receipts: true, ..Default::default() })
755815
.build();
756816

757-
// Check that the receipts are at the correct place.
758-
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*ALICE).await.unwrap();
759-
assert_eq!(receipt_event_id, carol_event_id);
760-
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*BOB).await.unwrap();
761-
assert_eq!(receipt_event_id, carol_event_id);
762-
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*CAROL).await.unwrap();
763-
assert_eq!(receipt_event_id, carol_event_id);
817+
// Receipts should be empty before any events.
818+
assert!(timeline.controller.latest_user_read_receipt(*ALICE).await.is_none());
819+
assert!(timeline.controller.latest_user_read_receipt(*BOB).await.is_none());
820+
assert!(timeline.controller.latest_user_read_receipt(*CAROL).await.is_none());
764821

765822
// Add the events.
766823
timeline
@@ -797,9 +854,9 @@ async fn test_implicit_read_receipt_before_explicit_read_receipt() {
797854
)
798855
.await;
799856

800-
// The receipts shouldn't have moved.
801-
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*ALICE).await.unwrap();
802-
assert_eq!(receipt_event_id, carol_event_id);
857+
// The receipts shouldn't have moved. The current user should not see their
858+
// own read receipt.
859+
assert!(timeline.controller.latest_user_read_receipt(*ALICE).await.is_none());
803860
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*BOB).await.unwrap();
804861
assert_eq!(receipt_event_id, carol_event_id);
805862
let (receipt_event_id, _) = timeline.controller.latest_user_read_receipt(*CAROL).await.unwrap();
@@ -812,7 +869,7 @@ async fn test_threaded_latest_user_read_receipt() {
812869
let receipt_thread = ReceiptThread::Thread(thread_root.clone());
813870

814871
let timeline = TestTimelineBuilder::new()
815-
.focus(TimelineFocus::Thread { root_event_id: thread_root })
872+
.focus(TimelineFocus::Thread { root_event_id: thread_root.clone() })
816873
.settings(TimelineSettings { track_read_receipts: true, ..Default::default() })
817874
.build();
818875

@@ -824,57 +881,60 @@ async fn test_threaded_latest_user_read_receipt() {
824881
let f = &timeline.factory;
825882

826883
timeline
827-
.handle_live_event(f.text_msg("hi I'm Bob.").sender(*ALICE).event_id(event_id!("$1")))
828-
.await;
829-
830-
timeline
831-
.handle_live_event(f.text_msg("hi Alice, I'm Bob.").sender(*BOB).event_id(event_id!("$2")))
884+
.handle_live_event(
885+
f.text_msg("hi Alice, I'm Bob.")
886+
.sender(*BOB)
887+
.event_id(event_id!("$1"))
888+
.in_thread(&thread_root, event_id!("$1")),
889+
)
832890
.await;
833891

834892
// Implicit receipts are taken into account.
835-
let (receipt_event_id, receipt) =
836-
timeline.controller.latest_user_read_receipt(*ALICE).await.unwrap();
837-
assert_eq!(receipt_event_id, event_id!("$1"));
838-
assert_eq!(receipt.thread, receipt_thread);
839-
840893
let (receipt_event_id, receipt) =
841894
timeline.controller.latest_user_read_receipt(*BOB).await.unwrap();
842-
assert_eq!(receipt_event_id, event_id!("$2"));
895+
assert_eq!(receipt_event_id, event_id!("$1"));
843896
assert_eq!(receipt.thread, receipt_thread);
844897

845898
timeline
846-
.handle_live_event(f.text_msg("nice to meet you!").sender(*ALICE).event_id(event_id!("$3")))
899+
.handle_live_event(
900+
f.text_msg("hi Bob, I'm Alice.")
901+
.sender(*ALICE)
902+
.event_id(event_id!("$2"))
903+
.in_thread(&thread_root, event_id!("$2")),
904+
)
847905
.await;
848906

849-
// Alice's latest read receipt is updated.
850-
let (receipt_event_id, receipt) =
851-
timeline.controller.latest_user_read_receipt(*ALICE).await.unwrap();
852-
assert_eq!(receipt_event_id, event_id!("$3"));
853-
assert_eq!(receipt.thread, receipt_thread);
854-
855-
// But Bob's isn't.
907+
// Bob's latest read receipt is still at the first event.
856908
let (receipt_event_id, receipt) =
857909
timeline.controller.latest_user_read_receipt(*BOB).await.unwrap();
858-
assert_eq!(receipt_event_id, event_id!("$2"));
910+
assert_eq!(receipt_event_id, event_id!("$1"));
859911
assert_eq!(receipt.thread, receipt_thread);
860912

861-
// Bob sees Alice's message.
913+
// Bob doesn't see Alice's message yet but sends a new message.
914+
timeline
915+
.handle_live_event(
916+
f.text_msg("nice to meet you, Alice!")
917+
.sender(*BOB)
918+
.event_id(event_id!("$3"))
919+
.in_thread(&thread_root, event_id!("$3")),
920+
)
921+
.await;
922+
923+
// Bob sees Alice's message
862924
timeline
863925
.handle_read_receipts([(
864-
owned_event_id!("$3"),
926+
owned_event_id!("$2"),
865927
ReceiptType::Read,
866928
BOB.to_owned(),
867929
receipt_thread.clone(),
868930
)])
869931
.await;
870932

871933
// Alice's latest read receipt is at the same position.
872-
let (receipt_event_id, receipt) =
873-
timeline.controller.latest_user_read_receipt(*ALICE).await.unwrap();
874-
assert_eq!(receipt_event_id, event_id!("$3"));
875-
assert_eq!(receipt.thread, receipt_thread);
934+
assert!(timeline.controller.latest_user_read_receipt(*ALICE).await.is_none());
876935

877-
// But Bob's has moved!
936+
// But Bob's has moved to the latest event as implicit read receipts are
937+
// considered yet again.
878938
let (receipt_event_id, receipt) =
879939
timeline.controller.latest_user_read_receipt(*BOB).await.unwrap();
880940
assert_eq!(receipt_event_id, event_id!("$3"));

0 commit comments

Comments
 (0)