mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-04 05:58:11 -04:00
sdk: Fill in replied-to event from timeline items when available
This commit is contained in:
committed by
Jonas Platte
parent
10d441f580
commit
848de833cc
@@ -15,7 +15,7 @@
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use chrono::{Datelike, Local, TimeZone};
|
||||
use eyeball_im::ObservableVector;
|
||||
use eyeball_im::{ObservableVector, Vector};
|
||||
use indexmap::{map::Entry, IndexMap, IndexSet};
|
||||
use matrix_sdk_base::deserialized_responses::EncryptionInfo;
|
||||
use ruma::{
|
||||
@@ -289,7 +289,7 @@ impl<'a> TimelineEventHandler<'a> {
|
||||
self.handle_room_message_edit(re);
|
||||
}
|
||||
AnyMessageLikeEventContent::RoomMessage(c) => {
|
||||
self.add(NewEventTimelineItem::message(c, relations));
|
||||
self.add(NewEventTimelineItem::message(c, relations, self.items));
|
||||
}
|
||||
AnyMessageLikeEventContent::RoomEncrypted(c) => self.handle_room_encrypted(c),
|
||||
AnyMessageLikeEventContent::Sticker(c) => {
|
||||
@@ -965,8 +965,10 @@ impl NewEventTimelineItem {
|
||||
fn message(
|
||||
c: RoomMessageEventContent,
|
||||
relations: BundledMessageLikeRelations<AnySyncMessageLikeEvent>,
|
||||
timeline_items: &Vector<Arc<TimelineItem>>,
|
||||
) -> Self {
|
||||
let content = TimelineItemContent::Message(Message::from_event(c, relations));
|
||||
let content =
|
||||
TimelineItemContent::Message(Message::from_event(c, relations, timeline_items));
|
||||
|
||||
Self::from_content(content)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::{fmt, ops::Deref, sync::Arc};
|
||||
|
||||
use imbl::{vector, Vector};
|
||||
use indexmap::IndexMap;
|
||||
use matrix_sdk_base::deserialized_responses::TimelineEvent;
|
||||
use ruma::{
|
||||
@@ -39,11 +40,13 @@ use ruma::{
|
||||
},
|
||||
OwnedDeviceId, OwnedEventId, OwnedMxcUri, OwnedTransactionId, OwnedUserId, UserId,
|
||||
};
|
||||
use tracing::error;
|
||||
use tracing::{debug, error};
|
||||
|
||||
use super::{Profile, TimelineDetails};
|
||||
use super::{EventTimelineItem, Profile, TimelineDetails};
|
||||
use crate::{
|
||||
room::timeline::{inner::RoomDataProvider, Error as TimelineError, DEFAULT_SANITIZER_MODE},
|
||||
room::timeline::{
|
||||
inner::RoomDataProvider, Error as TimelineError, TimelineItem, DEFAULT_SANITIZER_MODE,
|
||||
},
|
||||
Result,
|
||||
};
|
||||
|
||||
@@ -130,6 +133,7 @@ impl Message {
|
||||
pub(in crate::room::timeline) fn from_event(
|
||||
c: RoomMessageEventContent,
|
||||
relations: BundledMessageLikeRelations<AnySyncMessageLikeEvent>,
|
||||
timeline_items: &Vector<Arc<TimelineItem>>,
|
||||
) -> Self {
|
||||
let edited = relations.has_replacement();
|
||||
let edit = relations.replace.and_then(|r| match *r {
|
||||
@@ -150,7 +154,24 @@ impl Message {
|
||||
}
|
||||
});
|
||||
|
||||
let in_reply_to = c.relates_to.and_then(InReplyToDetails::from_relation);
|
||||
let in_reply_to = c.relates_to.and_then(|relation| match relation {
|
||||
message::Relation::Reply { in_reply_to } => {
|
||||
let event_id = in_reply_to.event_id;
|
||||
let event = timeline_items
|
||||
.iter()
|
||||
.filter_map(|it| it.as_event())
|
||||
.find(|it| it.event_id() == Some(&*event_id))
|
||||
.and_then(RepliedToEvent::from_timeline_item)
|
||||
.map(Box::new);
|
||||
|
||||
Some(InReplyToDetails {
|
||||
event_id,
|
||||
event: TimelineDetails::from_initial_value(event),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let msgtype = match edit {
|
||||
Some(mut e) => {
|
||||
// Edit's content is never supposed to contain the reply fallback.
|
||||
@@ -231,17 +252,6 @@ pub struct InReplyToDetails {
|
||||
pub event: TimelineDetails<Box<RepliedToEvent>>,
|
||||
}
|
||||
|
||||
impl InReplyToDetails {
|
||||
pub(in crate::room::timeline) fn from_relation<C>(relation: Relation<C>) -> Option<Self> {
|
||||
match relation {
|
||||
message::Relation::Reply { in_reply_to } => {
|
||||
Some(Self { event_id: in_reply_to.event_id, event: TimelineDetails::Unavailable })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An event that is replied to.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RepliedToEvent {
|
||||
@@ -266,6 +276,23 @@ impl RepliedToEvent {
|
||||
&self.sender_profile
|
||||
}
|
||||
|
||||
fn from_timeline_item(timeline_item: &EventTimelineItem) -> Option<Self> {
|
||||
let message = match &timeline_item.content {
|
||||
TimelineItemContent::Message(msg) => msg.to_owned(),
|
||||
// FIXME: Handle redacted messages
|
||||
_ => {
|
||||
debug!("Replied-to event is not a message, discarding");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
Some(Self {
|
||||
message,
|
||||
sender: timeline_item.sender.clone(),
|
||||
sender_profile: timeline_item.sender_profile.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(in crate::room::timeline) async fn try_from_timeline_event<P: RoomDataProvider>(
|
||||
timeline_event: TimelineEvent,
|
||||
room_data_provider: &P,
|
||||
@@ -281,7 +308,7 @@ impl RepliedToEvent {
|
||||
return Err(TimelineError::UnsupportedEvent.into());
|
||||
};
|
||||
|
||||
let message = Message::from_event(c, event.relations());
|
||||
let message = Message::from_event(c, event.relations(), &vector![]);
|
||||
let sender = event.sender().to_owned();
|
||||
let sender_profile =
|
||||
TimelineDetails::from_initial_value(room_data_provider.profile(&sender).await);
|
||||
|
||||
@@ -330,5 +330,6 @@ async fn reply() {
|
||||
|
||||
let in_reply_to = message.in_reply_to().unwrap();
|
||||
assert_eq!(in_reply_to.event_id, first_event_id);
|
||||
assert_matches!(in_reply_to.event, TimelineDetails::Unavailable);
|
||||
let replied_to_event = assert_matches!(&in_reply_to.event, TimelineDetails::Ready(msg) => msg);
|
||||
assert_eq!(replied_to_event.sender(), *ALICE);
|
||||
}
|
||||
|
||||
@@ -662,7 +662,7 @@ async fn in_reply_to_details() {
|
||||
assert_matches!(second_event.content(), TimelineItemContent::Message(message) => message);
|
||||
let in_reply_to = message.in_reply_to().unwrap();
|
||||
assert_eq!(in_reply_to.event_id, event_id!("$event1"));
|
||||
assert_matches!(in_reply_to.event, TimelineDetails::Unavailable);
|
||||
assert_matches!(in_reply_to.event, TimelineDetails::Ready(_));
|
||||
|
||||
// Fetch details locally first.
|
||||
timeline.fetch_event_details(second_event.event_id().unwrap()).await.unwrap();
|
||||
|
||||
Reference in New Issue
Block a user