Skip to content

Commit 306a9f7

Browse files
authored
Allow edit and reply to work also for events that have not yet been paginated (#3553)
Fixes #3538 The current implementation for send_reply and edit only work with timeline items that have already been paginated. However given the fact that by restoring drafts, we may restore a reply to an event for timeline where such event has not been paginated, sending such reply would fail (same for the edit event). So I reworked a bit the code here to use. only the event id, and reuse the existing timeline if available, otherwise we can fetch the event and synthethise the content and still be able to successfully send the event. This is the third part of the breakdown of the following PR: #3439
1 parent 2834fa1 commit 306a9f7

File tree

7 files changed

+589
-57
lines changed

7 files changed

+589
-57
lines changed

bindings/matrix-sdk-ffi/src/timeline/mod.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -454,10 +454,17 @@ impl Timeline {
454454
pub async fn send_reply(
455455
&self,
456456
msg: Arc<RoomMessageEventContentWithoutRelation>,
457-
reply_item: Arc<EventTimelineItem>,
457+
event_id: String,
458458
) -> Result<(), ClientError> {
459+
let event_id = EventId::parse(event_id)?;
460+
let replied_to_info = self
461+
.inner
462+
.replied_to_info_from_event_id(&event_id)
463+
.await
464+
.map_err(|err| anyhow::anyhow!(err))?;
465+
459466
self.inner
460-
.send_reply((*msg).clone(), &reply_item.0, ForwardThread::Yes)
467+
.send_reply((*msg).clone(), replied_to_info, ForwardThread::Yes)
461468
.await
462469
.map_err(|err| anyhow::anyhow!(err))?;
463470
Ok(())
@@ -466,10 +473,17 @@ impl Timeline {
466473
pub async fn edit(
467474
&self,
468475
new_content: Arc<RoomMessageEventContentWithoutRelation>,
469-
edit_item: Arc<EventTimelineItem>,
476+
event_id: String,
470477
) -> Result<(), ClientError> {
478+
let event_id = EventId::parse(event_id)?;
479+
let edit_info = self
480+
.inner
481+
.edit_info_from_event_id(&event_id)
482+
.await
483+
.map_err(|err| anyhow::anyhow!(err))?;
484+
471485
self.inner
472-
.edit((*new_content).clone(), &edit_item.0)
486+
.edit((*new_content).clone(), edit_info)
473487
.await
474488
.map_err(|err| anyhow::anyhow!(err))?;
475489
Ok(())

crates/matrix-sdk-ui/src/timeline/error.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ pub struct UnsupportedReplyItem(UnsupportedReplyItemInner);
8888
impl UnsupportedReplyItem {
8989
pub(super) const MISSING_EVENT_ID: Self = Self(UnsupportedReplyItemInner::MissingEventId);
9090
pub(super) const MISSING_JSON: Self = Self(UnsupportedReplyItemInner::MissingJson);
91+
pub(super) const MISSING_EVENT: Self = Self(UnsupportedReplyItemInner::MissingEvent);
92+
pub(super) const FAILED_TO_DESERIALIZE_EVENT: Self =
93+
Self(UnsupportedReplyItemInner::FailedToDeserializeEvent);
94+
pub(super) const STATE_EVENT: Self = Self(UnsupportedReplyItemInner::StateEvent);
9195
}
9296

9397
#[cfg(not(tarpaulin_include))]
@@ -103,6 +107,12 @@ enum UnsupportedReplyItemInner {
103107
MissingEventId,
104108
#[error("redacted events whose JSON form isn't available can't be replied")]
105109
MissingJson,
110+
#[error("event to reply to not found")]
111+
MissingEvent,
112+
#[error("failed to deserialize event to reply to")]
113+
FailedToDeserializeEvent,
114+
#[error("tried to reply to a state event")]
115+
StateEvent,
106116
}
107117

108118
#[derive(Error)]
@@ -114,6 +124,9 @@ impl UnsupportedEditItem {
114124
pub(super) const NOT_ROOM_MESSAGE: Self = Self(UnsupportedEditItemInner::NotRoomMessage);
115125
pub(super) const NOT_POLL_EVENT: Self = Self(UnsupportedEditItemInner::NotPollEvent);
116126
pub(super) const NOT_OWN_EVENT: Self = Self(UnsupportedEditItemInner::NotOwnEvent);
127+
pub(super) const MISSING_EVENT: Self = Self(UnsupportedEditItemInner::MissingEvent);
128+
pub(super) const FAILED_TO_DESERIALIZE_EVENT: Self =
129+
Self(UnsupportedEditItemInner::FailedToDeserializeEvent);
117130
}
118131

119132
#[cfg(not(tarpaulin_include))]
@@ -133,6 +146,10 @@ enum UnsupportedEditItemInner {
133146
NotPollEvent,
134147
#[error("tried to edit another user's event")]
135148
NotOwnEvent,
149+
#[error("event to edit not found")]
150+
MissingEvent,
151+
#[error("failed to deserialize event to edit")]
152+
FailedToDeserializeEvent,
136153
}
137154

138155
#[derive(Debug, Error)]

crates/matrix-sdk-ui/src/timeline/event_item/mod.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ pub(super) use self::{
4545
local::LocalEventTimelineItem,
4646
remote::{RemoteEventOrigin, RemoteEventTimelineItem},
4747
};
48+
use super::{EditInfo, RepliedToInfo, ReplyContent, UnsupportedEditItem, UnsupportedReplyItem};
4849

4950
/// An item in the timeline that represents at least one event.
5051
///
@@ -421,6 +422,47 @@ impl EventTimelineItem {
421422
kind,
422423
}
423424
}
425+
426+
/// Gives the information needed to reply to the event of the item.
427+
pub fn replied_to_info(&self) -> Result<RepliedToInfo, UnsupportedReplyItem> {
428+
let reply_content = match self.content() {
429+
TimelineItemContent::Message(msg) => ReplyContent::Message(msg.to_owned()),
430+
_ => {
431+
let Some(raw_event) = self.latest_json() else {
432+
return Err(UnsupportedReplyItem::MISSING_JSON);
433+
};
434+
435+
ReplyContent::Raw(raw_event.clone())
436+
}
437+
};
438+
439+
let Some(event_id) = self.event_id() else {
440+
return Err(UnsupportedReplyItem::MISSING_EVENT_ID);
441+
};
442+
443+
Ok(RepliedToInfo {
444+
event_id: event_id.to_owned(),
445+
sender: self.sender().to_owned(),
446+
timestamp: self.timestamp(),
447+
content: reply_content,
448+
})
449+
}
450+
451+
/// Gives the information needed to edit the event of the item.
452+
pub fn edit_info(&self) -> Result<EditInfo, UnsupportedEditItem> {
453+
if !self.is_own() {
454+
return Err(UnsupportedEditItem::NOT_OWN_EVENT);
455+
}
456+
// Early returns here must be in sync with
457+
// `EventTimelineItem::can_be_edited`
458+
let Some(event_id) = self.event_id() else {
459+
return Err(UnsupportedEditItem::MISSING_EVENT_ID);
460+
};
461+
let TimelineItemContent::Message(original_content) = self.content() else {
462+
return Err(UnsupportedEditItem::NOT_ROOM_MESSAGE);
463+
};
464+
Ok(EditInfo { event_id: event_id.to_owned(), original_message: original_content.clone() })
465+
}
424466
}
425467

426468
impl From<LocalEventTimelineItem> for EventTimelineItemKind {

0 commit comments

Comments
 (0)