diff --git a/bindings/matrix-sdk-ffi/src/timeline.rs b/bindings/matrix-sdk-ffi/src/timeline.rs index 12f444f38..962eb30e8 100644 --- a/bindings/matrix-sdk-ffi/src/timeline.rs +++ b/bindings/matrix-sdk-ffi/src/timeline.rs @@ -305,7 +305,7 @@ impl EventTimelineItem { } pub fn raw(&self) -> Option { - self.0.raw().map(|r| r.json().get().to_owned()) + self.0.original_json().map(|r| r.json().get().to_owned()) } pub fn local_send_state(&self) -> Option { diff --git a/crates/matrix-sdk/src/room/timeline/event_handler.rs b/crates/matrix-sdk/src/room/timeline/event_handler.rs index 0ad194b45..df547eee3 100644 --- a/crates/matrix-sdk/src/room/timeline/event_handler.rs +++ b/crates/matrix-sdk/src/room/timeline/event_handler.rs @@ -381,14 +381,19 @@ impl<'a> TimelineEventHandler<'a> { } }; - let content = TimelineItemContent::Message(Message { + let new_content = TimelineItemContent::Message(Message { msgtype: replacement.new_content, in_reply_to: msg.in_reply_to.clone(), edited: true, }); + let edit_json = match &self.flow { + Flow::Local { .. } => None, + Flow::Remote { raw_event, .. } => Some(raw_event.clone()), + }; + trace!("Applying edit"); - Some(event_item.with_content(content)) + Some(event_item.apply_edit(new_content, edit_json)) }); } diff --git a/crates/matrix-sdk/src/room/timeline/event_item/mod.rs b/crates/matrix-sdk/src/room/timeline/event_item/mod.rs index 662a71180..303d68ff3 100644 --- a/crates/matrix-sdk/src/room/timeline/event_item/mod.rs +++ b/crates/matrix-sdk/src/room/timeline/event_item/mod.rs @@ -169,18 +169,24 @@ impl EventTimelineItem { /// /// Returns `None` if this event hasn't been echoed back by the server /// yet. - pub fn raw(&self) -> Option<&Raw> { + pub fn original_json(&self) -> Option<&Raw> { match self { Self::Local(_local_event) => None, - Self::Remote(remote_event) => Some(remote_event.raw()), + Self::Remote(remote_event) => Some(remote_event.original_json()), } } - /// Clone the current event item, and update its `content`. - pub(super) fn with_content(&self, content: TimelineItemContent) -> Self { + /// Clone the current event item, and apply an edit to it. + pub(super) fn apply_edit( + &self, + new_content: TimelineItemContent, + edit_json: Option>, + ) -> Self { match self { - Self::Local(local_event) => Self::Local(local_event.with_content(content)), - Self::Remote(remote_event) => Self::Remote(remote_event.with_content(content)), + Self::Local(local_event) => Self::Local(local_event.with_content(new_content)), + Self::Remote(remote_event) => { + Self::Remote(remote_event.apply_edit(new_content, edit_json)) + } } } diff --git a/crates/matrix-sdk/src/room/timeline/event_item/remote.rs b/crates/matrix-sdk/src/room/timeline/event_item/remote.rs index e824a44ff..966406574 100644 --- a/crates/matrix-sdk/src/room/timeline/event_item/remote.rs +++ b/crates/matrix-sdk/src/room/timeline/event_item/remote.rs @@ -36,8 +36,13 @@ pub struct RemoteEventTimelineItem { is_own: bool, /// Encryption information. encryption_info: Option, - // FIXME: Expose the raw JSON of aggregated events somehow - raw: Raw, + /// JSON of the original event. + /// + /// If the message is edited, this *won't* change, instead + /// `latest_edit_json` will be updated. + original_json: Raw, + /// JSON of the latest edit to this item. + latest_edit_json: Option>, /// Whether the item should be highlighted in the timeline. is_highlighted: bool, } @@ -54,7 +59,7 @@ impl RemoteEventTimelineItem { read_receipts: IndexMap, is_own: bool, encryption_info: Option, - raw: Raw, + original_json: Raw, is_highlighted: bool, ) -> Self { Self { @@ -67,7 +72,8 @@ impl RemoteEventTimelineItem { read_receipts, is_own, encryption_info, - raw, + original_json, + latest_edit_json: None, is_highlighted, } } @@ -125,8 +131,13 @@ impl RemoteEventTimelineItem { } /// Get the raw JSON representation of the primary event. - pub fn raw(&self) -> &Raw { - &self.raw + pub fn original_json(&self) -> &Raw { + &self.original_json + } + + /// Get the raw JSON representation of the latest edit, if any. + pub fn latest_edit_json(&self) -> Option<&Raw> { + self.latest_edit_json.as_ref() } /// Whether the event should be highlighted in the timeline. @@ -159,8 +170,15 @@ impl RemoteEventTimelineItem { } /// Clone the current event item, and update its `content`. - pub(in crate::room::timeline) fn with_content(&self, content: TimelineItemContent) -> Self { - Self { content, ..self.clone() } + pub(in crate::room::timeline) fn apply_edit( + &self, + content: TimelineItemContent, + edit_json: Option>, + ) -> Self { + // If the edit is local (is not a full event yet), `edit_json` will be + // `None`, in that case retain the existing value of `latest_edit_json` + let latest_edit_json = edit_json.or_else(|| self.latest_edit_json.clone()); + Self { content, latest_edit_json, ..self.clone() } } /// Clone the current event item, and update its `sender_profile`. diff --git a/crates/matrix-sdk/src/room/timeline/inner.rs b/crates/matrix-sdk/src/room/timeline/inner.rs index 78079fca2..66d354447 100644 --- a/crates/matrix-sdk/src/room/timeline/inner.rs +++ b/crates/matrix-sdk/src/room/timeline/inner.rs @@ -395,7 +395,7 @@ impl TimelineInner

{ tracing::Span::current().record("event_id", debug(remote_event.event_id())); - let raw = remote_event.raw().cast_ref(); + let raw = remote_event.original_json().cast_ref(); match olm_machine.decrypt_room_event(raw, room_id).await { Ok(event) => { trace!("Successfully decrypted event that previously failed to decrypt"); @@ -694,12 +694,11 @@ async fn fetch_replied_to_event( return details; }; - let event_item = item - .with_content(TimelineItemContent::Message(message.with_in_reply_to(InReplyToDetails { - event_id: in_reply_to.to_owned(), - details: TimelineDetails::Pending, - }))) - .into(); + let reply = message.with_in_reply_to(InReplyToDetails { + event_id: in_reply_to.to_owned(), + details: TimelineDetails::Pending, + }); + let event_item = item.apply_edit(TimelineItemContent::Message(reply), None).into(); state.items.set(index, Arc::new(TimelineItem::Event(event_item))); // Don't hold the state lock while the network request is made diff --git a/crates/matrix-sdk/tests/integration/room/timeline/mod.rs b/crates/matrix-sdk/tests/integration/room/timeline/mod.rs index d32a14e09..1a93e8c5a 100644 --- a/crates/matrix-sdk/tests/integration/room/timeline/mod.rs +++ b/crates/matrix-sdk/tests/integration/room/timeline/mod.rs @@ -130,7 +130,7 @@ async fn edit() { assert_eq!(item.timestamp(), MilliSecondsSinceUnixEpoch(uint!(152038280))); assert!(item.event_id().is_some()); assert!(!item.is_own()); - assert!(item.raw().is_some()); + assert!(item.original_json().is_some()); let msg = assert_matches!(item.content(), TimelineItemContent::Message(msg) => msg); assert_matches!(msg.msgtype(), MessageType::Text(_));