sdk: Fill in replied-to event from timeline items when available

This commit is contained in:
Jonas Platte
2023-05-04 16:00:54 +02:00
committed by Jonas Platte
parent 10d441f580
commit 848de833cc
4 changed files with 51 additions and 21 deletions

View File

@@ -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)
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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();