1414
1515use matrix_sdk:: { Client , Room , latest_events:: LocalLatestEventValue } ;
1616use matrix_sdk_base:: latest_event:: LatestEventValue as BaseLatestEventValue ;
17- use ruma:: { MilliSecondsSinceUnixEpoch , OwnedUserId } ;
17+ use ruma:: {
18+ MilliSecondsSinceUnixEpoch , OwnedUserId ,
19+ events:: {
20+ AnyMessageLikeEventContent , relation:: Replacement , room:: message:: RoomMessageEventContent ,
21+ } ,
22+ } ;
1823use tracing:: trace;
1924
2025use crate :: timeline:: {
21- Profile , TimelineDetails , TimelineItemContent , event_handler:: TimelineAction ,
26+ Profile , TimelineDetails , TimelineItemContent ,
27+ event_handler:: { HandleAggregationKind , TimelineAction } ,
2228 traits:: RoomDataProvider ,
2329} ;
2430
@@ -92,7 +98,7 @@ impl LatestEventValue {
9298 . map ( TimelineDetails :: Ready )
9399 . unwrap_or ( TimelineDetails :: Unavailable ) ;
94100
95- let Some ( TimelineAction :: AddItem { content } ) = TimelineAction :: from_event (
101+ match TimelineAction :: from_event (
96102 any_sync_timeline_event,
97103 & raw_any_sync_timeline_event,
98104 room,
@@ -102,11 +108,50 @@ impl LatestEventValue {
102108 None ,
103109 )
104110 . await
105- else {
106- return Self :: None ;
107- } ;
111+ {
112+ // Easy path: no aggregation, direct event.
113+ Some ( TimelineAction :: AddItem { content } ) => {
114+ Self :: Remote { timestamp, sender, is_own, profile, content }
115+ }
108116
109- Self :: Remote { timestamp, sender, is_own, profile, content }
117+ // Aggregated event.
118+ //
119+ // Only edits are supported for the moment.
120+ Some ( TimelineAction :: HandleAggregation {
121+ kind :
122+ HandleAggregationKind :: Edit { replacement : Replacement { new_content, .. } } ,
123+ ..
124+ } ) => {
125+ // Let's map the edit into a regular message.
126+ match TimelineAction :: from_content (
127+ AnyMessageLikeEventContent :: RoomMessage ( RoomMessageEventContent :: new (
128+ new_content. msgtype ,
129+ ) ) ,
130+ // We don't care about the `InReplyToDetails` in the context of a
131+ // `LatestEventValue`.
132+ None ,
133+ // We don't care about the thread information in the context of a
134+ // `LatestEventValue`.
135+ None ,
136+ None ,
137+ ) {
138+ // The expected case.
139+ TimelineAction :: AddItem { content } => {
140+ Self :: Remote { timestamp, sender, is_own, profile, content }
141+ }
142+
143+ // Supposedly unreachable, but let's pretend there is no
144+ // `LatestEventValue` if it happens.
145+ _ => {
146+ trace ! ( "latest event was an edit that failed to be un-aggregated" ) ;
147+
148+ Self :: None
149+ }
150+ }
151+ }
152+
153+ _ => Self :: None ,
154+ }
110155 }
111156 BaseLatestEventValue :: LocalIsSending ( LocalLatestEventValue {
112157 timestamp,
@@ -209,7 +254,9 @@ mod tests {
209254 assert_matches!( profile, TimelineDetails :: Unavailable ) ;
210255 assert_matches!(
211256 content,
212- TimelineItemContent :: MsgLike ( MsgLikeContent { kind: MsgLikeKind :: Message ( _) , .. } )
257+ TimelineItemContent :: MsgLike ( MsgLikeContent { kind: MsgLikeKind :: Message ( message) , .. } ) => {
258+ assert_eq!( message. body( ) , "raclette" ) ;
259+ }
213260 ) ;
214261 } )
215262 }
@@ -275,4 +322,38 @@ mod tests {
275322 assert!( is_sending. not( ) ) ;
276323 } )
277324 }
325+
326+ #[ async_test]
327+ async fn test_remote_edit ( ) {
328+ let server = MatrixMockServer :: new ( ) . await ;
329+ let client = server. client_builder ( ) . build ( ) . await ;
330+ let room = server. sync_room ( & client, JoinedRoomBuilder :: new ( room_id ! ( "!r0" ) ) ) . await ;
331+ let sender = user_id ! ( "@mnt_io:matrix.org" ) ;
332+ let event_factory = EventFactory :: new ( ) ;
333+
334+ let base_value = BaseLatestEventValue :: Remote ( RemoteLatestEventValue :: from_plaintext (
335+ event_factory
336+ . server_ts ( 42 )
337+ . sender ( sender)
338+ . text_msg ( "bonjour" )
339+ . event_id ( event_id ! ( "$ev1" ) )
340+ . edit ( event_id ! ( "$ev0" ) , RoomMessageEventContent :: text_plain ( "fondue" ) . into ( ) )
341+ . into_raw_sync ( ) ,
342+ ) ) ;
343+ let value =
344+ LatestEventValue :: from_base_latest_event_value ( base_value, & room, & client) . await ;
345+
346+ assert_matches ! ( value, LatestEventValue :: Remote { timestamp, sender: received_sender, is_own, profile, content } => {
347+ assert_eq!( u64 :: from( timestamp. get( ) ) , 42u64 ) ;
348+ assert_eq!( received_sender, sender) ;
349+ assert!( is_own. not( ) ) ;
350+ assert_matches!( profile, TimelineDetails :: Unavailable ) ;
351+ assert_matches!(
352+ content,
353+ TimelineItemContent :: MsgLike ( MsgLikeContent { kind: MsgLikeKind :: Message ( message) , .. } ) => {
354+ assert_eq!( message. body( ) , "fondue" ) ;
355+ }
356+ ) ;
357+ } )
358+ }
278359}
0 commit comments