diff --git a/crates/matrix-sdk-ui/src/timeline/traits.rs b/crates/matrix-sdk-ui/src/timeline/traits.rs index b4211c974..1b9d24fbf 100644 --- a/crates/matrix-sdk-ui/src/timeline/traits.rs +++ b/crates/matrix-sdk-ui/src/timeline/traits.rs @@ -232,23 +232,27 @@ impl RoomDataProvider for Room { event_id: &'a EventId, receipt_thread: ReceiptThread, ) -> IndexMap { - let mut result = match self - .load_event_receipts(ReceiptType::Read, receipt_thread.clone(), event_id) - .await - { - Ok(receipts) => receipts.into_iter().collect(), - Err(e) => { - error!(?event_id, ?receipt_thread, "Failed to get read receipts for event: {e}"); - IndexMap::new() - } - }; + if matches!(receipt_thread, ReceiptThread::Unthreaded | ReceiptThread::Main) { + // If the requested receipt thread is unthreaded or main, we maintain maximal + // compatibility with clients using either unthreaded or main-thread read + // receipts by allowing both here. - if receipt_thread == ReceiptThread::Unthreaded { - // Include the main thread receipts as well, to be maximally compatible with - // clients using either the unthreaded or main thread receipt type. - let main_thread_receipts = match self + // First, load the main receipts. + let mut result = match self .load_event_receipts(ReceiptType::Read, ReceiptThread::Main, event_id) .await + { + Ok(receipts) => receipts.into_iter().collect(), + Err(e) => { + error!(?event_id, "Failed to get main thread read receipts for event: {e}"); + IndexMap::new() + } + }; + + // Then, load the unthreaded receipts. + let unthreaded_receipts = match self + .load_event_receipts(ReceiptType::Read, ReceiptThread::Unthreaded, event_id) + .await { Ok(receipts) => receipts, Err(e) => { @@ -256,10 +260,32 @@ impl RoomDataProvider for Room { Vec::new() } }; - result.extend(main_thread_receipts); + + // Only insert unthreaded receipts that are more recent. Ideally we'd compare + // the receipted event position, but we don't have access to that + // here. + for (user_id, unthreaded_receipt) in unthreaded_receipts { + if let Some(main_receipt) = result.get(&user_id) { + if unthreaded_receipt.ts > main_receipt.ts { + result.insert(user_id, unthreaded_receipt); + } + } else { + result.insert(user_id, unthreaded_receipt); + } + } + + return result; } - result + // In all other cases, return what's requested, and only that (threaded + // receipts). + match self.load_event_receipts(ReceiptType::Read, receipt_thread.clone(), event_id).await { + Ok(receipts) => receipts.into_iter().collect(), + Err(e) => { + error!(?event_id, ?receipt_thread, "Failed to get read receipts for event: {e}"); + IndexMap::new() + } + } } async fn push_context(&self) -> Option {