mirror of
https://github.com/youwen5/iamb.git
synced 2025-06-20 05:39:52 -07:00
Support editing messages (#4)
This commit is contained in:
parent
69125e3fc4
commit
8966644f6e
6 changed files with 195 additions and 37 deletions
|
@ -74,7 +74,7 @@ two other TUI clients and Element Web:
|
||||||
| New user registration | ❌ | ❌ | ❌ | ✔️ |
|
| New user registration | ❌ | ❌ | ❌ | ✔️ |
|
||||||
| VOIP | ❌ | ❌ | ❌ | ✔️ |
|
| VOIP | ❌ | ❌ | ❌ | ✔️ |
|
||||||
| Reactions | ❌ ([#2]) | ✔️ | ❌ | ✔️ |
|
| Reactions | ❌ ([#2]) | ✔️ | ❌ | ✔️ |
|
||||||
| Message editing | ❌ ([#4]) | ✔️ | ❌ | ✔️ |
|
| Message editing | ✔️ | ✔️ | ❌ | ✔️ |
|
||||||
| Room upgrades | ❌ | ✔️ | ❌ | ✔️ |
|
| Room upgrades | ❌ | ✔️ | ❌ | ✔️ |
|
||||||
| Localisations | ❌ | 1 | ❌ | 44 |
|
| Localisations | ❌ | 1 | ❌ | 44 |
|
||||||
| SSO Support | ❌ | ✔️ | ✔️ | ✔️ |
|
| SSO Support | ❌ | ✔️ | ✔️ | ✔️ |
|
||||||
|
|
93
src/base.rs
93
src/base.rs
|
@ -8,7 +8,20 @@ use tracing::warn;
|
||||||
|
|
||||||
use matrix_sdk::{
|
use matrix_sdk::{
|
||||||
encryption::verification::SasVerification,
|
encryption::verification::SasVerification,
|
||||||
ruma::{OwnedRoomId, OwnedUserId, RoomId},
|
ruma::{
|
||||||
|
events::room::message::{
|
||||||
|
OriginalRoomMessageEvent,
|
||||||
|
Relation,
|
||||||
|
Replacement,
|
||||||
|
RoomMessageEvent,
|
||||||
|
RoomMessageEventContent,
|
||||||
|
},
|
||||||
|
EventId,
|
||||||
|
OwnedEventId,
|
||||||
|
OwnedRoomId,
|
||||||
|
OwnedUserId,
|
||||||
|
RoomId,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use modalkit::{
|
use modalkit::{
|
||||||
|
@ -41,7 +54,7 @@ use modalkit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
message::{Message, Messages},
|
message::{Message, MessageEvent, MessageKey, MessageTimeStamp, Messages},
|
||||||
worker::Requester,
|
worker::Requester,
|
||||||
ApplicationSettings,
|
ApplicationSettings,
|
||||||
};
|
};
|
||||||
|
@ -61,9 +74,22 @@ pub enum VerifyAction {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum MessageAction {
|
pub enum MessageAction {
|
||||||
|
/// Cance the current reply or edit.
|
||||||
Cancel,
|
Cancel,
|
||||||
|
|
||||||
|
/// Download an attachment to the given path.
|
||||||
|
///
|
||||||
|
/// The [bool] argument controls whether to overwrite any already existing file at the
|
||||||
|
/// destination path.
|
||||||
Download(Option<String>, bool),
|
Download(Option<String>, bool),
|
||||||
|
|
||||||
|
/// Edit a sent message.
|
||||||
|
Edit,
|
||||||
|
|
||||||
|
/// Redact a message.
|
||||||
Redact(Option<String>),
|
Redact(Option<String>),
|
||||||
|
|
||||||
|
/// Reply to a message.
|
||||||
Reply,
|
Reply,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,13 +277,72 @@ pub enum RoomFetchStatus {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct RoomInfo {
|
pub struct RoomInfo {
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
|
|
||||||
|
pub keys: HashMap<OwnedEventId, MessageKey>,
|
||||||
pub messages: Messages,
|
pub messages: Messages,
|
||||||
|
|
||||||
pub fetch_id: RoomFetchStatus,
|
pub fetch_id: RoomFetchStatus,
|
||||||
pub fetch_last: Option<Instant>,
|
pub fetch_last: Option<Instant>,
|
||||||
pub users_typing: Option<(Instant, Vec<OwnedUserId>)>,
|
pub users_typing: Option<(Instant, Vec<OwnedUserId>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoomInfo {
|
impl RoomInfo {
|
||||||
|
pub fn get_event(&self, event_id: &EventId) -> Option<&Message> {
|
||||||
|
self.messages.get(self.keys.get(event_id)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_edit(&mut self, msg: Replacement) {
|
||||||
|
let event_id = msg.event_id;
|
||||||
|
let new_content = msg.new_content;
|
||||||
|
|
||||||
|
let key = if let Some(k) = self.keys.get(&event_id) {
|
||||||
|
k
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let msg = if let Some(msg) = self.messages.get_mut(key) {
|
||||||
|
msg
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
match &mut msg.event {
|
||||||
|
MessageEvent::Original(orig) => {
|
||||||
|
orig.content = *new_content;
|
||||||
|
},
|
||||||
|
MessageEvent::Local(content) => {
|
||||||
|
*content = new_content;
|
||||||
|
},
|
||||||
|
MessageEvent::Redacted(_) => {
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_message(&mut self, msg: RoomMessageEvent) {
|
||||||
|
let event_id = msg.event_id().to_owned();
|
||||||
|
let key = (msg.origin_server_ts().into(), event_id.clone());
|
||||||
|
|
||||||
|
self.keys.insert(event_id.clone(), key.clone());
|
||||||
|
self.messages.insert(key, msg.into());
|
||||||
|
|
||||||
|
// Remove any echo.
|
||||||
|
let key = (MessageTimeStamp::LocalEcho, event_id);
|
||||||
|
let _ = self.messages.remove(&key);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, msg: RoomMessageEvent) {
|
||||||
|
match msg {
|
||||||
|
RoomMessageEvent::Original(OriginalRoomMessageEvent {
|
||||||
|
content:
|
||||||
|
RoomMessageEventContent { relates_to: Some(Relation::Replacement(repl)), .. },
|
||||||
|
..
|
||||||
|
}) => self.insert_edit(repl),
|
||||||
|
_ => self.insert_message(msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn recently_fetched(&self) -> bool {
|
fn recently_fetched(&self) -> bool {
|
||||||
self.fetch_last.map_or(false, |i| i.elapsed() < ROOM_FETCH_DEBOUNCE)
|
self.fetch_last.map_or(false, |i| i.elapsed() < ROOM_FETCH_DEBOUNCE)
|
||||||
}
|
}
|
||||||
|
@ -388,9 +473,7 @@ impl ChatStore {
|
||||||
match res {
|
match res {
|
||||||
Ok((fetch_id, msgs)) => {
|
Ok((fetch_id, msgs)) => {
|
||||||
for msg in msgs.into_iter() {
|
for msg in msgs.into_iter() {
|
||||||
let key = (msg.origin_server_ts().into(), msg.event_id().to_owned());
|
info.insert(msg);
|
||||||
|
|
||||||
info.messages.insert(key, Message::from(msg));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info.fetch_id =
|
info.fetch_id =
|
||||||
|
|
|
@ -144,6 +144,17 @@ fn iamb_cancel(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
||||||
return Ok(step);
|
return Ok(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn iamb_edit(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
||||||
|
if !desc.arg.text.is_empty() {
|
||||||
|
return Result::Err(CommandError::InvalidArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ract = IambAction::from(MessageAction::Edit);
|
||||||
|
let step = CommandStep::Continue(ract.into(), ctx.context.take());
|
||||||
|
|
||||||
|
return Ok(step);
|
||||||
|
}
|
||||||
|
|
||||||
fn iamb_redact(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
fn iamb_redact(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
|
||||||
let args = desc.arg.strings()?;
|
let args = desc.arg.strings()?;
|
||||||
|
|
||||||
|
@ -269,6 +280,7 @@ fn add_iamb_commands(cmds: &mut ProgramCommands) {
|
||||||
cmds.add_command(ProgramCommand { names: vec!["cancel".into()], f: iamb_cancel });
|
cmds.add_command(ProgramCommand { names: vec!["cancel".into()], f: iamb_cancel });
|
||||||
cmds.add_command(ProgramCommand { names: vec!["dms".into()], f: iamb_dms });
|
cmds.add_command(ProgramCommand { names: vec!["dms".into()], f: iamb_dms });
|
||||||
cmds.add_command(ProgramCommand { names: vec!["download".into()], f: iamb_download });
|
cmds.add_command(ProgramCommand { names: vec!["download".into()], f: iamb_download });
|
||||||
|
cmds.add_command(ProgramCommand { names: vec!["edit".into()], f: iamb_edit });
|
||||||
cmds.add_command(ProgramCommand { names: vec!["invite".into()], f: iamb_invite });
|
cmds.add_command(ProgramCommand { names: vec!["invite".into()], f: iamb_invite });
|
||||||
cmds.add_command(ProgramCommand { names: vec!["join".into()], f: iamb_join });
|
cmds.add_command(ProgramCommand { names: vec!["join".into()], f: iamb_join });
|
||||||
cmds.add_command(ProgramCommand { names: vec!["members".into()], f: iamb_members });
|
cmds.add_command(ProgramCommand { names: vec!["members".into()], f: iamb_members });
|
||||||
|
|
15
src/tests.rs
15
src/tests.rs
|
@ -111,6 +111,18 @@ pub fn mock_message5() -> Message {
|
||||||
mock_room1_message(content, TEST_USER2.clone(), MSG4_KEY.clone())
|
mock_room1_message(content, TEST_USER2.clone(), MSG4_KEY.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mock_keys() -> HashMap<OwnedEventId, MessageKey> {
|
||||||
|
let mut keys = HashMap::new();
|
||||||
|
|
||||||
|
keys.insert(MSG1_EVID.clone(), MSG1_KEY.clone());
|
||||||
|
keys.insert(MSG2_EVID.clone(), MSG2_KEY.clone());
|
||||||
|
keys.insert(MSG3_EVID.clone(), MSG3_KEY.clone());
|
||||||
|
keys.insert(MSG4_EVID.clone(), MSG4_KEY.clone());
|
||||||
|
keys.insert(MSG5_EVID.clone(), MSG5_KEY.clone());
|
||||||
|
|
||||||
|
keys
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mock_messages() -> Messages {
|
pub fn mock_messages() -> Messages {
|
||||||
let mut messages = BTreeMap::new();
|
let mut messages = BTreeMap::new();
|
||||||
|
|
||||||
|
@ -126,7 +138,10 @@ pub fn mock_messages() -> Messages {
|
||||||
pub fn mock_room() -> RoomInfo {
|
pub fn mock_room() -> RoomInfo {
|
||||||
RoomInfo {
|
RoomInfo {
|
||||||
name: Some("Watercooler Discussion".into()),
|
name: Some("Watercooler Discussion".into()),
|
||||||
|
|
||||||
|
keys: mock_keys(),
|
||||||
messages: mock_messages(),
|
messages: mock_messages(),
|
||||||
|
|
||||||
fetch_id: RoomFetchStatus::NotStarted,
|
fetch_id: RoomFetchStatus::NotStarted,
|
||||||
fetch_last: None,
|
fetch_last: None,
|
||||||
users_typing: None,
|
users_typing: None,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use matrix_sdk::{
|
use matrix_sdk::{
|
||||||
|
@ -11,6 +12,8 @@ use matrix_sdk::{
|
||||||
events::room::message::{
|
events::room::message::{
|
||||||
MessageType,
|
MessageType,
|
||||||
OriginalRoomMessageEvent,
|
OriginalRoomMessageEvent,
|
||||||
|
Relation,
|
||||||
|
Replacement,
|
||||||
RoomMessageEventContent,
|
RoomMessageEventContent,
|
||||||
TextMessageEventContent,
|
TextMessageEventContent,
|
||||||
},
|
},
|
||||||
|
@ -82,6 +85,7 @@ pub struct ChatState {
|
||||||
focus: RoomFocus,
|
focus: RoomFocus,
|
||||||
|
|
||||||
reply_to: Option<MessageKey>,
|
reply_to: Option<MessageKey>,
|
||||||
|
editing: Option<MessageKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChatState {
|
impl ChatState {
|
||||||
|
@ -104,6 +108,7 @@ impl ChatState {
|
||||||
focus: RoomFocus::MessageBar,
|
focus: RoomFocus::MessageBar,
|
||||||
|
|
||||||
reply_to: None,
|
reply_to: None,
|
||||||
|
editing: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +125,7 @@ impl ChatState {
|
||||||
|
|
||||||
fn reset(&mut self) -> EditRope {
|
fn reset(&mut self) -> EditRope {
|
||||||
self.reply_to = None;
|
self.reply_to = None;
|
||||||
|
self.editing = None;
|
||||||
self.tbox.reset()
|
self.tbox.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +151,7 @@ impl ChatState {
|
||||||
match act {
|
match act {
|
||||||
MessageAction::Cancel => {
|
MessageAction::Cancel => {
|
||||||
self.reply_to = None;
|
self.reply_to = None;
|
||||||
|
self.editing = None;
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
},
|
},
|
||||||
|
@ -224,6 +231,40 @@ impl ChatState {
|
||||||
|
|
||||||
Err(IambError::NoAttachment.into())
|
Err(IambError::NoAttachment.into())
|
||||||
},
|
},
|
||||||
|
MessageAction::Edit => {
|
||||||
|
if msg.sender != settings.profile.user_id {
|
||||||
|
let msg = "Cannot edit messages sent by someone else";
|
||||||
|
let err = UIError::Failure(msg.into());
|
||||||
|
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ev = match &msg.event {
|
||||||
|
MessageEvent::Original(ev) => &ev.content,
|
||||||
|
MessageEvent::Local(ev) => ev.deref(),
|
||||||
|
_ => {
|
||||||
|
let msg = "Cannot edit a redacted message";
|
||||||
|
let err = UIError::Failure(msg.into());
|
||||||
|
|
||||||
|
return Err(err);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let text = match &ev.msgtype {
|
||||||
|
MessageType::Text(msg) => msg.body.as_str(),
|
||||||
|
_ => {
|
||||||
|
let msg = "Cannot edit a non-text message";
|
||||||
|
let err = UIError::Failure(msg.into());
|
||||||
|
|
||||||
|
return Err(err);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
self.tbox.set_text(text);
|
||||||
|
self.editing = self.scrollback.get_key(info);
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
},
|
||||||
MessageAction::Redact(reason) => {
|
MessageAction::Redact(reason) => {
|
||||||
let room = store
|
let room = store
|
||||||
.application
|
.application
|
||||||
|
@ -273,6 +314,7 @@ impl ChatState {
|
||||||
.get_joined_room(self.id())
|
.get_joined_room(self.id())
|
||||||
.ok_or(IambError::NotJoined)?;
|
.ok_or(IambError::NotJoined)?;
|
||||||
let info = store.application.rooms.entry(self.id().to_owned()).or_default();
|
let info = store.application.rooms.entry(self.id().to_owned()).or_default();
|
||||||
|
let mut show_echo = true;
|
||||||
|
|
||||||
let (event_id, msg) = match act {
|
let (event_id, msg) = match act {
|
||||||
SendAction::Submit => {
|
SendAction::Submit => {
|
||||||
|
@ -287,7 +329,14 @@ impl ChatState {
|
||||||
|
|
||||||
let mut msg = RoomMessageEventContent::new(msg);
|
let mut msg = RoomMessageEventContent::new(msg);
|
||||||
|
|
||||||
if let Some(m) = self.get_reply_to(info) {
|
if let Some((_, event_id)) = &self.editing {
|
||||||
|
msg.relates_to = Some(Relation::Replacement(Replacement::new(
|
||||||
|
event_id.clone(),
|
||||||
|
Box::new(msg.clone()),
|
||||||
|
)));
|
||||||
|
|
||||||
|
show_echo = false;
|
||||||
|
} else if let Some(m) = self.get_reply_to(info) {
|
||||||
// XXX: Switch to RoomMessageEventContent::reply() once it's stable?
|
// XXX: Switch to RoomMessageEventContent::reply() once it's stable?
|
||||||
msg = msg.make_reply_to(m);
|
msg = msg.make_reply_to(m);
|
||||||
}
|
}
|
||||||
|
@ -327,11 +376,13 @@ impl ChatState {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let user = store.application.settings.profile.user_id.clone();
|
if show_echo {
|
||||||
let key = (MessageTimeStamp::LocalEcho, event_id);
|
let user = store.application.settings.profile.user_id.clone();
|
||||||
let msg = MessageEvent::Local(msg.into());
|
let key = (MessageTimeStamp::LocalEcho, event_id);
|
||||||
let msg = Message::new(msg, user, MessageTimeStamp::LocalEcho);
|
let msg = MessageEvent::Local(msg.into());
|
||||||
info.messages.insert(key, msg);
|
let msg = Message::new(msg, user, MessageTimeStamp::LocalEcho);
|
||||||
|
info.messages.insert(key, msg);
|
||||||
|
}
|
||||||
|
|
||||||
// Jump to the end of the scrollback to show the message.
|
// Jump to the end of the scrollback to show the message.
|
||||||
self.scrollback.goto_latest();
|
self.scrollback.goto_latest();
|
||||||
|
@ -413,6 +464,7 @@ impl WindowOps<IambInfo> for ChatState {
|
||||||
focus: self.focus,
|
focus: self.focus,
|
||||||
|
|
||||||
reply_to: None,
|
reply_to: None,
|
||||||
|
editing: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,14 +653,20 @@ impl<'a> StatefulWidget for Chat<'a> {
|
||||||
let scrollback = Scrollback::new(self.store).focus(scrollback_focused);
|
let scrollback = Scrollback::new(self.store).focus(scrollback_focused);
|
||||||
scrollback.render(scrollarea, buf, &mut state.scrollback);
|
scrollback.render(scrollarea, buf, &mut state.scrollback);
|
||||||
|
|
||||||
let desc_spans = state.reply_to.as_ref().and_then(|k| {
|
let desc_spans = match (&state.editing, &state.reply_to) {
|
||||||
let room = self.store.application.rooms.get(state.id())?;
|
(None, None) => None,
|
||||||
let msg = room.messages.get(k)?;
|
(Some(_), _) => Some(Spans::from("Editing message")),
|
||||||
let user = self.store.application.settings.get_user_span(msg.sender.as_ref());
|
(_, Some(_)) => {
|
||||||
let spans = Spans(vec![Span::from("Replying to "), user]);
|
state.reply_to.as_ref().and_then(|k| {
|
||||||
|
let room = self.store.application.rooms.get(state.id())?;
|
||||||
|
let msg = room.messages.get(k)?;
|
||||||
|
let user = self.store.application.settings.get_user_span(msg.sender.as_ref());
|
||||||
|
let spans = Spans(vec![Span::from("Replying to "), user]);
|
||||||
|
|
||||||
spans.into()
|
spans.into()
|
||||||
});
|
})
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(desc_spans) = desc_spans {
|
if let Some(desc_spans) = desc_spans {
|
||||||
Paragraph::new(desc_spans).render(descarea, buf);
|
Paragraph::new(desc_spans).render(descarea, buf);
|
||||||
|
|
|
@ -58,7 +58,7 @@ use modalkit::editing::action::{EditInfo, InfoMessage, UIError};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
base::{AsyncProgramStore, IambError, IambResult, SetRoomField, VerifyAction},
|
base::{AsyncProgramStore, IambError, IambResult, SetRoomField, VerifyAction},
|
||||||
message::{Message, MessageFetchResult, MessageTimeStamp},
|
message::MessageFetchResult,
|
||||||
ApplicationSettings,
|
ApplicationSettings,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -536,15 +536,7 @@ impl ClientWorker {
|
||||||
let mut locked = store.lock().await;
|
let mut locked = store.lock().await;
|
||||||
let mut info = locked.application.get_room_info(room_id.to_owned());
|
let mut info = locked.application.get_room_info(room_id.to_owned());
|
||||||
info.name = room_name;
|
info.name = room_name;
|
||||||
|
info.insert(ev.into_full_event(room_id.to_owned()));
|
||||||
let event_id = ev.event_id().to_owned();
|
|
||||||
let key = (ev.origin_server_ts().into(), event_id.clone());
|
|
||||||
let msg = Message::from(ev.into_full_event(room_id.to_owned()));
|
|
||||||
info.messages.insert(key, msg);
|
|
||||||
|
|
||||||
// Remove the echo.
|
|
||||||
let key = (MessageTimeStamp::LocalEcho, event_id);
|
|
||||||
let _ = info.messages.remove(&key);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -561,17 +553,15 @@ impl ClientWorker {
|
||||||
let mut locked = store.lock().await;
|
let mut locked = store.lock().await;
|
||||||
let info = locked.application.get_room_info(room_id.to_owned());
|
let info = locked.application.get_room_info(room_id.to_owned());
|
||||||
|
|
||||||
// XXX: need to store a mapping of EventId -> MessageKey somewhere
|
let key = if let Some(k) = info.keys.get(&ev.redacts) {
|
||||||
// to avoid having to iterate over the messages here.
|
k
|
||||||
for ((_, id), msg) in info.messages.iter_mut().rev() {
|
} else {
|
||||||
if id != &ev.redacts {
|
return;
|
||||||
continue;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
if let Some(msg) = info.messages.get_mut(key) {
|
||||||
let ev = SyncRoomRedactionEvent::Original(ev);
|
let ev = SyncRoomRedactionEvent::Original(ev);
|
||||||
msg.event.redact(ev, room_version);
|
msg.event.redact(ev, room_version);
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue