Skip to content
Open
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
3 changes: 3 additions & 0 deletions crates/matrix-sdk-ui/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.

### Features

- Utilize the cache and include common relations when focusing a timeline on an event without
requestion context.
([#5858](https://github.com/matrix-org/matrix-rust-sdk/pull/5858))
- [**breaking**] The `LatestEventValue::Local` type gains 2 new fields: `sender`
and `profile`.
([#5885](https://github.com/matrix-org/matrix-rust-sdk/pull/5885))
Expand Down
54 changes: 42 additions & 12 deletions crates/matrix-sdk-ui/src/timeline/controller/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use imbl::Vector;
#[cfg(test)]
use matrix_sdk::Result;
use matrix_sdk::{
config::RequestConfig,
deserialized_responses::TimelineEvent,
event_cache::{DecryptionRetryRequest, RoomEventCache, RoomPaginationStatus},
paginators::{PaginationResult, PaginationToken, Paginator},
Expand All @@ -40,7 +41,7 @@ use ruma::{
poll::unstable_start::UnstablePollStartEventContent,
reaction::ReactionEventContent,
receipt::{Receipt, ReceiptThread, ReceiptType},
relation::Annotation,
relation::{Annotation, RelationType},
room::message::{MessageType, Relation},
},
room_version_rules::RoomVersionRules,
Expand Down Expand Up @@ -467,16 +468,46 @@ impl<P: RoomDataProvider> TimelineController<P> {

let event_paginator = Paginator::new(self.room_data_provider.clone());

// Start a /context request so we can know if the event is in a thread or not,
// and know which kind of pagination we'll be using then.
let start_from_result = event_paginator
.start_from(event_id, (*num_context_events).into())
.await
.map_err(PaginationError::Paginator)?;
let load_events_with_context = || async {
// Start a /context request to load the focussed event and surrounding events.
event_paginator
.start_from(event_id, (*num_context_events).into())
.await
.map(|r| r.events)
.map_err(PaginationError::Paginator)
};

let events = if *num_context_events == 0 {
// If no context is requested, try to load the event from the cache first and
// include common relations such as reactions and edits.
let request_config = Some(RequestConfig::default().retry_limit(3));
let relations_filter =
Some(vec![RelationType::Annotation, RelationType::Replacement]);

// Load the event from the cache or, failing that, the server.
match self
.room_data_provider
.load_event_with_relations(event_id, request_config, relations_filter)
.await
{
Ok((event, related_events)) => {
let mut events = vec![event];
events.extend(related_events);
events
}
Err(err) => {
error!("error when loading focussed event: {err}");
// Fall back to load the focussed event using /context.
load_events_with_context().await?
}
}
} else {
// Start a /context request to load the focussed event and surrounding events.
load_events_with_context().await?
};

// Find the target event, and see if it's part of a thread.
let thread_root_event_id = start_from_result
.events
let thread_root_event_id = events
.iter()
.find(
|event| {
Expand All @@ -492,7 +523,7 @@ impl<P: RoomDataProvider> TimelineController<P> {
// Look if the thread root event is part of the /context response. This
// allows us to spare some backwards pagination with
// /relations.
let includes_root_event = start_from_result.events.iter().any(|event| {
let includes_root_event = events.iter().any(|event| {
if let Some(id) = event.event_id() { id == root_id } else { false }
});

Expand All @@ -515,8 +546,7 @@ impl<P: RoomDataProvider> TimelineController<P> {
},
});

let has_events = !start_from_result.events.is_empty();
let events = start_from_result.events;
let has_events = !events.is_empty();

match paginator.get().expect("Paginator was not instantiated") {
AnyPaginator::Unthreaded { .. } => {
Expand Down
55 changes: 53 additions & 2 deletions crates/matrix-sdk-ui/tests/integration/timeline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,57 @@ async fn test_timeline_is_threaded() {
assert!(timeline.is_threaded());
}

{
// An event-focused timeline, focused on a non-thread event, isn't threaded when
// no context is requested.
let f = EventFactory::new();
let event = f
.text_msg("hello world")
.event_id(event_id!("$target"))
.room(room_id)
.sender(&ALICE)
.into_event();
server.mock_room_event().match_event_id().ok(event).mock_once().mount().await;

let timeline = TimelineBuilder::new(&room)
.with_focus(TimelineFocus::Event {
target: owned_event_id!("$target"),
num_context_events: 0,
hide_threaded_events: true,
})
.build()
.await
.unwrap();
assert!(timeline.is_threaded().not());
}

{
// But an event-focused timeline, focused on an in-thread event, is threaded
// when no context is requested \o/
let f = EventFactory::new();
let thread_root = event_id!("$thread_root");
let event = f
.text_msg("hey to you too")
.event_id(event_id!("$thetarget"))
.in_thread(thread_root, thread_root)
.room(room_id)
.sender(&ALICE)
.into_event();

server.mock_room_event().match_event_id().ok(event).mock_once().mount().await;

let timeline = TimelineBuilder::new(&room)
.with_focus(TimelineFocus::Event {
target: owned_event_id!("$thetarget"),
num_context_events: 0,
hide_threaded_events: true,
})
.build()
.await
.unwrap();
assert!(timeline.is_threaded());
}

{
// An event-focused timeline, focused on a non-thread event, isn't threaded.
let f = EventFactory::new();
Expand All @@ -116,7 +167,7 @@ async fn test_timeline_is_threaded() {
let timeline = TimelineBuilder::new(&room)
.with_focus(TimelineFocus::Event {
target: owned_event_id!("$target"),
num_context_events: 0,
num_context_events: 2,
hide_threaded_events: true,
})
.build()
Expand Down Expand Up @@ -147,7 +198,7 @@ async fn test_timeline_is_threaded() {
let timeline = TimelineBuilder::new(&room)
.with_focus(TimelineFocus::Event {
target: owned_event_id!("$target"),
num_context_events: 0,
num_context_events: 2,
hide_threaded_events: true,
})
.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1848,7 +1848,7 @@ async fn test_permalink_doesnt_listen_to_thread_sync() {
let timeline = TimelineBuilder::new(&room)
.with_focus(TimelineFocus::Event {
target: owned_event_id!("$target"),
num_context_events: 0,
num_context_events: 2,
hide_threaded_events: true,
})
.build()
Expand Down
Loading