Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions benchmarks/benches/timeline.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use matrix_sdk::test_utils::mocks::MatrixMockServer;
use matrix_sdk_test::{JoinedRoomBuilder, StateTestEvent, event_factory::EventFactory};
use matrix_sdk_ui::timeline::TimelineBuilder;
use matrix_sdk_ui::timeline::{TimelineBuilder, TimelineReadReceiptTracking};
use ruma::{
EventId, events::room::message::RoomMessageEventContentWithoutRelation, owned_room_id,
owned_user_id,
Expand Down Expand Up @@ -103,7 +103,7 @@ pub fn create_timeline_with_initial_events(c: &mut Criterion) {
|b| {
b.to_async(&runtime).iter(|| async {
let timeline = TimelineBuilder::new(&room)
.track_read_marker_and_receipts()
.track_read_marker_and_receipts(TimelineReadReceiptTracking::AllEvents)
.build()
.await
.expect("Could not create timeline");
Expand Down
3 changes: 3 additions & 0 deletions bindings/matrix-sdk-ffi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ All notable changes to this project will be documented in this file.

### Breaking changes

- `TimelineConfiguration::track_read_receipts`'s type is now an enum to allow tracking to be enabled for all events
(like before) or only for message-like events (which prevents read receipts from being placed on state events).
([#5900](https://github.com/matrix-org/matrix-rust-sdk/pull/5900))
- `Client::reset_server_info()` has been split into `reset_supported_versions()`
and `reset_well_known()`.
([#5910](https://github.com/matrix-org/matrix-rust-sdk/pull/5910))
Expand Down
7 changes: 2 additions & 5 deletions bindings/matrix-sdk-ffi/src/room/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,8 @@ impl Room {

builder = builder
.with_focus(configuration.focus.try_into()?)
.with_date_divider_mode(configuration.date_divider_mode.into());

if configuration.track_read_receipts {
builder = builder.track_read_marker_and_receipts();
}
.with_date_divider_mode(configuration.date_divider_mode.into())
.track_read_marker_and_receipts(configuration.track_read_receipts);

match configuration.filter {
TimelineFilter::All => {
Expand Down
9 changes: 6 additions & 3 deletions bindings/matrix-sdk-ffi/src/timeline/configuration.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::sync::Arc;

use matrix_sdk_ui::timeline::event_type_filter::TimelineEventTypeFilter as InnerTimelineEventTypeFilter;
use matrix_sdk_ui::timeline::{
event_type_filter::TimelineEventTypeFilter as InnerTimelineEventTypeFilter,
TimelineReadReceiptTracking,
};
use ruma::{
events::{AnySyncTimelineEvent, TimelineEventType},
EventId,
Expand Down Expand Up @@ -173,11 +176,11 @@ pub struct TimelineConfiguration {
pub date_divider_mode: DateDividerMode,

/// Should the read receipts and read markers be tracked for the timeline
/// items in this instance?
/// items in this instance and on which event types?
///
/// As this has a non negligible performance impact, make sure to enable it
/// only when you need it.
pub track_read_receipts: bool,
pub track_read_receipts: TimelineReadReceiptTracking,

/// Whether this timeline instance should report UTDs through the client's
/// delegate.
Expand Down
7 changes: 7 additions & 0 deletions crates/matrix-sdk-ui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ All notable changes to this project will be documented in this file.

## [Unreleased] - ReleaseDate

### Features

- [**breaking**] `TimelineBuilder::track_read_marker_and_receipts` now takes a parameter to allow tracking to be enabled
for all events (like before) or only for message-like events (which prevents read receipts from being placed on state
events).
([#5900](https://github.com/matrix-org/matrix-rust-sdk/pull/5900))

## [0.15.0] - 2025-11-27

### Features
Expand Down
13 changes: 7 additions & 6 deletions crates/matrix-sdk-ui/src/timeline/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use super::{
};
use crate::{
timeline::{
TimelineReadReceiptTracking,
controller::spawn_crypto_tasks,
tasks::{
pinned_events_task, room_event_cache_updates_task, room_send_queue_update_task,
Expand Down Expand Up @@ -91,17 +92,17 @@ impl TimelineBuilder {
self
}

/// Chose when to insert the date separators, either in between each day
/// Choose when to insert the date separators, either in between each day
/// or each month.
pub fn with_date_divider_mode(mut self, mode: DateDividerMode) -> Self {
self.settings.date_divider_mode = mode;
self
}

/// Enable tracking of the fully-read marker and the read receipts on the
/// timeline.
pub fn track_read_marker_and_receipts(mut self) -> Self {
self.settings.track_read_receipts = true;
/// Choose whether to enable tracking of the fully-read marker and the read
/// receipts and on which event types.
pub fn track_read_marker_and_receipts(mut self, tracking: TimelineReadReceiptTracking) -> Self {
self.settings.track_read_receipts = tracking;
self
}

Expand Down Expand Up @@ -154,7 +155,7 @@ impl TimelineBuilder {
skip(self),
fields(
room_id = ?self.room.room_id(),
track_read_receipts = self.settings.track_read_receipts,
track_read_receipts = ?self.settings.track_read_receipts,
)
)]
pub async fn build(self) -> Result<Timeline, Error> {
Expand Down
12 changes: 11 additions & 1 deletion crates/matrix-sdk-ui/src/timeline/controller/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,9 @@ pub(in crate::timeline) struct EventMeta {
/// Whether the event is among the timeline items.
pub visible: bool,

/// Whether the event can show read receipts.
pub can_show_read_receipts: bool,

/// Foundation for the mapping between remote events to timeline items.
///
/// Let's explain it. The events represent the first set and are stored in
Expand Down Expand Up @@ -587,8 +590,15 @@ impl EventMeta {
pub fn new(
event_id: OwnedEventId,
visible: bool,
can_show_read_receipts: bool,
thread_root_id: Option<OwnedEventId>,
) -> Self {
Self { event_id, thread_root_id, visible, timeline_item_index: None }
Self {
event_id,
thread_root_id,
visible,
can_show_read_receipts,
timeline_item_index: None,
}
}
}
16 changes: 9 additions & 7 deletions crates/matrix-sdk-ui/src/timeline/controller/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ pub(super) use self::{
use super::{
DateDividerMode, EmbeddedEvent, Error, EventSendState, EventTimelineItem, InReplyToDetails,
MediaUploadProgress, PaginationError, Profile, TimelineDetails, TimelineEventItemId,
TimelineFocus, TimelineItem, TimelineItemContent, TimelineItemKind, VirtualTimelineItem,
TimelineFocus, TimelineItem, TimelineItemContent, TimelineItemKind,
TimelineReadReceiptTracking, VirtualTimelineItem,
algorithms::{rfind_event_by_id, rfind_event_item},
event_item::{ReactionStatus, RemoteEventOrigin},
item::TimelineUniqueId,
Expand Down Expand Up @@ -265,8 +266,9 @@ pub(super) struct TimelineController<P: RoomDataProvider = Room> {

#[derive(Clone)]
pub(super) struct TimelineSettings {
/// Should the read receipts and read markers be handled?
pub(super) track_read_receipts: bool,
/// Should the read receipts and read markers be handled and on which event
/// types?
pub(super) track_read_receipts: TimelineReadReceiptTracking,

/// Event filter that controls what's rendered as a timeline item (and thus
/// what can carry read receipts).
Expand All @@ -292,7 +294,7 @@ impl fmt::Debug for TimelineSettings {
impl Default for TimelineSettings {
fn default() -> Self {
Self {
track_read_receipts: false,
track_read_receipts: TimelineReadReceiptTracking::Disabled,
event_filter: Arc::new(default_event_filter),
add_failed_to_parse: true,
date_divider_mode: DateDividerMode::Daily,
Expand Down Expand Up @@ -981,8 +983,8 @@ impl<P: RoomDataProvider> TimelineController<P> {
{
let mut state = self.state.write().await;

let track_read_markers = self.settings.track_read_receipts;
if track_read_markers {
let track_read_markers = &self.settings.track_read_receipts;
if track_read_markers.is_enabled() {
state.populate_initial_user_receipt(&self.room_data_provider, ReceiptType::Read).await;
state
.populate_initial_user_receipt(&self.room_data_provider, ReceiptType::ReadPrivate)
Expand All @@ -1006,7 +1008,7 @@ impl<P: RoomDataProvider> TimelineController<P> {
.await;
}

if track_read_markers {
if track_read_markers.is_enabled() {
if let Some(fully_read_event_id) =
self.room_data_provider.load_fully_read_marker().await
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,7 @@ mod observable_items_tests {
thread_root_id: None,
timeline_item_index: None,
visible: false,
can_show_read_receipts: false,
}
}

Expand Down Expand Up @@ -2065,6 +2066,7 @@ mod all_remote_events_tests {
thread_root_id: None,
timeline_item_index,
visible: false,
can_show_read_receipts: false,
}
}

Expand Down
37 changes: 26 additions & 11 deletions crates/matrix-sdk-ui/src/timeline/controller/read_receipts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,13 @@ impl ReadReceipts {
old_receipt_pos = Some(pos);
}

// The receipt should appear on the first event that is visible.
if old_receipt_pos.is_some() && old_item_event_id.is_none() && event.visible {
// The receipt should appear on the first visible event that can show read
// receipts.
if old_receipt_pos.is_some()
&& old_item_event_id.is_none()
&& event.visible
&& event.can_show_read_receipts
{
old_item_pos = event.timeline_item_index;
old_item_event_id = Some(event.event_id.clone());
}
Expand All @@ -141,8 +146,13 @@ impl ReadReceipts {
new_receipt_pos = Some(pos);
}

// The receipt should appear on the first event that is visible.
if new_receipt_pos.is_some() && new_item_event_id.is_none() && event.visible {
// The receipt should appear on the first visible event that can show read
// receipts.
if new_receipt_pos.is_some()
&& new_item_event_id.is_none()
&& event.visible
&& event.can_show_read_receipts
{
new_item_pos = event.timeline_item_index;
new_item_event_id = Some(event.event_id.clone());
}
Expand Down Expand Up @@ -316,11 +326,16 @@ impl ReadReceipts {
}
}

// Include receipts for all the following non-visible events.
// Include receipts from all the following events that are hidden or can't show
// read receipts.
let mut hidden = Vec::new();
for hidden_event_meta in events_iter.take_while(|meta| !meta.visible) {
if let Some(event_receipts) = self.get_event_receipts(&hidden_event_meta.event_id) {
trace!(%hidden_event_meta.event_id, "found receipts on hidden event");
for hidden_receipt_event_meta in
events_iter.take_while(|meta| !meta.visible || !meta.can_show_read_receipts)
{
if let Some(event_receipts) =
self.get_event_receipts(&hidden_receipt_event_meta.event_id)
{
trace!(%hidden_receipt_event_meta.event_id, "found receipts on hidden event");
hidden.extend(event_receipts.clone());
}
}
Expand Down Expand Up @@ -659,8 +674,8 @@ impl<P: RoomDataProvider> TimelineStateTransaction<'_, P> {
.skip_while(|meta| meta.event_id != event_id)
// Go past the event item.
.skip(1)
// Find the first visible item.
.find(|meta| meta.visible)
// Find the first visible item that can show read receipts.
.find(|meta| meta.visible && meta.can_show_read_receipts)
else {
trace!("Couldn't find any previous visible event, exiting");
return;
Expand Down Expand Up @@ -806,7 +821,7 @@ impl<P: RoomDataProvider> TimelineState<P> {
.iter()
.rev()
.skip_while(|ev| ev.event_id != *latest_receipt_id)
.find(|ev| ev.visible)
.find(|ev| ev.visible && ev.can_show_read_receipts)
.map(|ev| ev.event_id.clone())
}
}
Expand Down
Loading
Loading