mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-01 20:47:18 -04:00
feat(timeline): forward the TimelineEvent::thread_summary to timeline items
Right now, we're not passing the latest event yet, but we could improve that later!
This commit is contained in:
@@ -392,6 +392,15 @@ impl ThreadSummaryStatus {
|
||||
fn is_unknown(&self) -> bool {
|
||||
matches!(self, ThreadSummaryStatus::Unknown)
|
||||
}
|
||||
|
||||
/// Transforms the [`ThreadSummaryStatus`] into an optional thread summary,
|
||||
/// for cases where we don't care about distinguishing unknown and none.
|
||||
pub fn summary(&self) -> Option<&ThreadSummary> {
|
||||
match self {
|
||||
ThreadSummaryStatus::Unknown | ThreadSummaryStatus::None => None,
|
||||
ThreadSummaryStatus::Some(thread_summary) => Some(thread_summary),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a Matrix room event that has been returned from `/sync`,
|
||||
|
||||
@@ -37,7 +37,7 @@ use super::{
|
||||
};
|
||||
use crate::timeline::{
|
||||
event_handler::{FailedToParseEvent, RemovedItem, TimelineAction},
|
||||
VirtualTimelineItem,
|
||||
ThreadSummary, TimelineDetails, VirtualTimelineItem,
|
||||
};
|
||||
|
||||
pub(in crate::timeline) struct TimelineStateTransaction<'a> {
|
||||
@@ -205,6 +205,7 @@ impl<'a> TimelineStateTransaction<'a> {
|
||||
room_data_provider,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
&self.items,
|
||||
&mut self.meta,
|
||||
)
|
||||
@@ -555,7 +556,12 @@ impl<'a> TimelineStateTransaction<'a> {
|
||||
date_divider_adjuster: &mut DateDividerAdjuster,
|
||||
) -> RemovedItem {
|
||||
// TODO: do something with the thread summary!
|
||||
let TimelineEvent { push_actions, kind, thread_summary: _thread_summary } = event;
|
||||
let TimelineEvent { push_actions, kind, thread_summary } = event;
|
||||
|
||||
let thread_summary = thread_summary.summary().map(|_common_summary| {
|
||||
// TODO: later, fill the latest event in the thread summary!
|
||||
ThreadSummary { latest_event: TimelineDetails::Unavailable }
|
||||
});
|
||||
|
||||
let encryption_info = kind.encryption_info().cloned();
|
||||
|
||||
@@ -584,6 +590,7 @@ impl<'a> TimelineStateTransaction<'a> {
|
||||
event,
|
||||
&raw,
|
||||
room_data_provider,
|
||||
thread_summary,
|
||||
utd_info,
|
||||
bundled_edit_encryption_info,
|
||||
&self.items,
|
||||
|
||||
@@ -57,7 +57,8 @@ use super::{
|
||||
},
|
||||
traits::RoomDataProvider,
|
||||
EncryptedMessage, EventTimelineItem, InReplyToDetails, MsgLikeContent, MsgLikeKind, OtherState,
|
||||
ReactionStatus, RepliedToEvent, Sticker, TimelineDetails, TimelineItem, TimelineItemContent,
|
||||
ReactionStatus, RepliedToEvent, Sticker, ThreadSummary, TimelineDetails, TimelineItem,
|
||||
TimelineItemContent,
|
||||
};
|
||||
use crate::timeline::controller::aggregations::PendingEdit;
|
||||
|
||||
@@ -151,6 +152,7 @@ pub(super) struct RemoteEventContext<'a> {
|
||||
raw_event: &'a Raw<AnySyncTimelineEvent>,
|
||||
relations: BundledMessageLikeRelations<AnySyncMessageLikeEvent>,
|
||||
bundled_edit_encryption_info: Option<Arc<EncryptionInfo>>,
|
||||
thread_summary: Option<ThreadSummary>,
|
||||
}
|
||||
|
||||
/// An action that we want to cause on the timeline.
|
||||
@@ -194,6 +196,7 @@ impl TimelineAction {
|
||||
event: AnySyncTimelineEvent,
|
||||
raw_event: &Raw<AnySyncTimelineEvent>,
|
||||
room_data_provider: &P,
|
||||
thread_summary: Option<ThreadSummary>,
|
||||
unable_to_decrypt_info: Option<UnableToDecryptInfo>,
|
||||
bundled_edit_encryption_info: Option<Arc<EncryptionInfo>>,
|
||||
timeline_items: &Vector<Arc<TimelineItem>>,
|
||||
@@ -257,6 +260,7 @@ impl TimelineAction {
|
||||
raw_event,
|
||||
relations: ev.relations(),
|
||||
bundled_edit_encryption_info,
|
||||
thread_summary,
|
||||
}),
|
||||
timeline_items,
|
||||
meta,
|
||||
@@ -272,6 +276,7 @@ impl TimelineAction {
|
||||
raw_event,
|
||||
relations: ev.relations(),
|
||||
bundled_edit_encryption_info,
|
||||
thread_summary,
|
||||
}),
|
||||
timeline_items,
|
||||
meta,
|
||||
@@ -371,7 +376,7 @@ impl TimelineAction {
|
||||
timeline_items,
|
||||
);
|
||||
|
||||
if let Some(event_id) = remote_ctx.map(|ctx| ctx.event_id) {
|
||||
if let Some(event_id) = remote_ctx.as_ref().map(|ctx| ctx.event_id) {
|
||||
Self::mark_response(meta, event_id, in_reply_to.as_ref());
|
||||
}
|
||||
|
||||
@@ -380,7 +385,7 @@ impl TimelineAction {
|
||||
reactions: Default::default(),
|
||||
thread_root,
|
||||
in_reply_to,
|
||||
thread_summary: None,
|
||||
thread_summary: remote_ctx.and_then(|ctx| ctx.thread_summary),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -391,7 +396,7 @@ impl TimelineAction {
|
||||
Self::extract_reply_and_thread_root(c.relates_to.clone(), timeline_items);
|
||||
|
||||
// Record the bundled edit in the aggregations set, if any.
|
||||
if let Some(ctx) = remote_ctx {
|
||||
let thread_summary = if let Some(ctx) = remote_ctx {
|
||||
if let Some(new_content) = extract_poll_edit_content(ctx.relations) {
|
||||
// It is replacing the current event.
|
||||
if let Some(edit_event_id) =
|
||||
@@ -417,7 +422,11 @@ impl TimelineAction {
|
||||
}
|
||||
|
||||
Self::mark_response(meta, ctx.event_id, in_reply_to.as_ref());
|
||||
}
|
||||
|
||||
ctx.thread_summary
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let poll_state = PollState::new(c);
|
||||
|
||||
@@ -427,7 +436,7 @@ impl TimelineAction {
|
||||
reactions: Default::default(),
|
||||
thread_root,
|
||||
in_reply_to,
|
||||
thread_summary: None,
|
||||
thread_summary,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -439,7 +448,7 @@ impl TimelineAction {
|
||||
);
|
||||
|
||||
// Record the bundled edit in the aggregations set, if any.
|
||||
if let Some(ctx) = remote_ctx {
|
||||
let thread_summary = if let Some(ctx) = remote_ctx {
|
||||
if let Some(new_content) = extract_room_msg_edit_content(ctx.relations) {
|
||||
// It is replacing the current event.
|
||||
if let Some(edit_event_id) =
|
||||
@@ -465,7 +474,11 @@ impl TimelineAction {
|
||||
}
|
||||
|
||||
Self::mark_response(meta, ctx.event_id, in_reply_to.as_ref());
|
||||
}
|
||||
|
||||
ctx.thread_summary
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Self::AddItem {
|
||||
content: TimelineItemContent::message(
|
||||
@@ -474,7 +487,7 @@ impl TimelineAction {
|
||||
Default::default(),
|
||||
thread_root,
|
||||
in_reply_to,
|
||||
None,
|
||||
thread_summary,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,11 +121,15 @@ impl RepliedToEvent {
|
||||
|
||||
debug!(event_type = %event.event_type(), "got deserialized event");
|
||||
|
||||
// We don't need to fill the thread information of an embedded reply.
|
||||
let thread_summary = None;
|
||||
|
||||
let sender = event.sender().to_owned();
|
||||
let action = TimelineAction::from_event(
|
||||
event,
|
||||
&raw_event,
|
||||
room_data_provider,
|
||||
thread_summary,
|
||||
unable_to_decrypt_info,
|
||||
bundled_edit_encryption_info,
|
||||
timeline_items,
|
||||
|
||||
@@ -693,7 +693,7 @@ impl<T> TimelineDetails<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_unavailable(&self) -> bool {
|
||||
pub fn is_unavailable(&self) -> bool {
|
||||
matches!(self, Self::Unavailable)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,19 @@
|
||||
use assert_matches2::assert_let;
|
||||
use eyeball_im::VectorDiff;
|
||||
use futures_util::StreamExt as _;
|
||||
use matrix_sdk::test_utils::mocks::{MatrixMockServer, RoomRelationsResponseTemplate};
|
||||
use matrix_sdk_test::{async_test, event_factory::EventFactory};
|
||||
use matrix_sdk_ui::timeline::{TimelineBuilder, TimelineFocus};
|
||||
use ruma::{event_id, events::AnyTimelineEvent, owned_event_id, room_id, serde::Raw, user_id};
|
||||
use matrix_sdk::{
|
||||
assert_let_timeout,
|
||||
test_utils::mocks::{MatrixMockServer, RoomRelationsResponseTemplate},
|
||||
};
|
||||
use matrix_sdk_test::{async_test, event_factory::EventFactory, JoinedRoomBuilder, ALICE};
|
||||
use matrix_sdk_ui::timeline::{RoomExt as _, TimelineBuilder, TimelineFocus};
|
||||
use ruma::{
|
||||
event_id,
|
||||
events::{relation::BundledThread, AnyTimelineEvent, BundledMessageLikeRelations},
|
||||
owned_event_id, room_id,
|
||||
serde::Raw,
|
||||
uint, user_id,
|
||||
};
|
||||
use stream_assert::assert_pending;
|
||||
|
||||
#[async_test]
|
||||
@@ -151,8 +160,6 @@ async fn test_thread_backpagination() {
|
||||
// events and the thread root
|
||||
assert_eq!(timeline_updates.len(), 5);
|
||||
|
||||
println!("Stefan: {timeline_updates:?}");
|
||||
|
||||
// Check the timeline diffs
|
||||
assert_let!(VectorDiff::PushFront { value } = &timeline_updates[0]);
|
||||
assert_eq!(value.as_event().unwrap().event_id().unwrap(), event_id!("$2"));
|
||||
@@ -193,3 +200,50 @@ async fn test_thread_backpagination() {
|
||||
"Threaded event 4"
|
||||
);
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
async fn test_thread_summary() {
|
||||
// A sync event that includes a bundled thread summary receives a
|
||||
// `ThreadSummary` in the associated timeline content.
|
||||
let server = MatrixMockServer::new().await;
|
||||
let client = server.client_builder().build().await;
|
||||
|
||||
let room_id = room_id!("!a:b.c");
|
||||
let room = server.sync_joined_room(&client, room_id).await;
|
||||
|
||||
let timeline = room.timeline().await.unwrap();
|
||||
|
||||
let (initial_items, mut stream) = timeline.subscribe().await;
|
||||
assert!(initial_items.is_empty());
|
||||
|
||||
let f = EventFactory::new().room(room_id).sender(&ALICE);
|
||||
let thread_event_id = event_id!("$thread_root");
|
||||
let latest_event_id = event_id!("$latest_event");
|
||||
|
||||
let latest_thread_event = f.text_msg("the last one!").event_id(latest_event_id).into_raw();
|
||||
|
||||
let mut relations = BundledMessageLikeRelations::new();
|
||||
relations.thread = Some(Box::new(BundledThread::new(latest_thread_event, uint!(42), false)));
|
||||
|
||||
let event = f
|
||||
.text_msg("thready thread mcthreadface")
|
||||
.bundled_relations(relations)
|
||||
.event_id(thread_event_id);
|
||||
|
||||
server.sync_room(&client, JoinedRoomBuilder::new(room_id).add_timeline_event(event)).await;
|
||||
|
||||
assert_let_timeout!(Some(timeline_updates) = stream.next());
|
||||
// Message + day divider.
|
||||
assert_eq!(timeline_updates.len(), 2);
|
||||
|
||||
// Check the timeline diffs.
|
||||
assert_let!(VectorDiff::PushBack { value } = &timeline_updates[0]);
|
||||
let event_item = value.as_event().unwrap();
|
||||
assert_eq!(event_item.event_id().unwrap(), thread_event_id);
|
||||
assert_let!(Some(summary) = event_item.content().thread_summary());
|
||||
// Soon™, Stefan, soon™.
|
||||
assert!(summary.latest_event.is_unavailable());
|
||||
|
||||
assert_let!(VectorDiff::PushFront { value } = &timeline_updates[1]);
|
||||
assert!(value.is_date_divider());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user