events: Improve usability and docs of m.room.message reply constructors

This commit is contained in:
Jonas Platte 2021-11-18 22:51:58 +01:00
parent 24950b208e
commit 49e5d45ac9
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
2 changed files with 81 additions and 18 deletions

View File

@ -20,6 +20,8 @@ pub mod feedback;
mod relation_serde; mod relation_serde;
mod reply; mod reply;
pub use reply::ReplyBaseEvent;
/// The content of an `m.room.message` event. /// The content of an `m.room.message` event.
/// ///
/// This event is used when sending messages in a room. /// This event is used when sending messages in a room.
@ -81,20 +83,28 @@ impl RoomMessageEventContent {
} }
/// Creates a plain text reply to a message. /// Creates a plain text reply to a message.
pub fn text_reply_plain(reply: impl fmt::Display, original_message: &RoomMessageEvent) -> Self { pub fn text_reply_plain(
reply: impl fmt::Display,
original_message: &impl ReplyBaseEvent,
) -> Self {
let quoted = reply::get_plain_quote_fallback(original_message); let quoted = reply::get_plain_quote_fallback(original_message);
let body = format!("{}\n\n{}", quoted, reply); let body = format!("{}\n\n{}", quoted, reply);
Self { Self {
relates_to: Some(Relation::Reply { relates_to: Some(Relation::Reply {
in_reply_to: InReplyTo { event_id: original_message.event_id.clone() }, in_reply_to: InReplyTo { event_id: original_message.event_id().clone() },
}), }),
..Self::text_plain(body) ..Self::text_plain(body)
} }
} }
/// Creates a html text reply to a message. /// Creates a html text reply to a message.
///
/// Different from `text_reply_plain`, this constructor requires specifically a
/// [`RoomMessageEvent`] since it creates a permalink to the previous message, for which the
/// room ID is required. If you want to reply to a [`SyncRoomMessageEvent`], you have to convert
/// it first by calling [`.into_full_event()`][crate::SyncMessageEvent::into_full_event].
pub fn text_reply_html( pub fn text_reply_html(
reply: impl fmt::Display, reply: impl fmt::Display,
html_reply: impl fmt::Display, html_reply: impl fmt::Display,
@ -115,16 +125,21 @@ impl RoomMessageEventContent {
} }
/// Creates a plain text notice reply to a message. /// Creates a plain text notice reply to a message.
///
/// Different from `notice_reply_plain`, this constructor requires specifically a
/// [`RoomMessageEvent`] since it creates a permalink to the previous message, for which the
/// room ID is required. If you want to reply to a [`SyncRoomMessageEvent`], you have to convert
/// it first by calling [`.into_full_event()`][crate::SyncMessageEvent::into_full_event].
pub fn notice_reply_plain( pub fn notice_reply_plain(
reply: impl fmt::Display, reply: impl fmt::Display,
original_message: &RoomMessageEvent, original_message: &impl ReplyBaseEvent,
) -> Self { ) -> Self {
let quoted = reply::get_plain_quote_fallback(original_message); let quoted = reply::get_plain_quote_fallback(original_message);
let body = format!("{}\n\n{}", quoted, reply); let body = format!("{}\n\n{}", quoted, reply);
Self { Self {
relates_to: Some(Relation::Reply { relates_to: Some(Relation::Reply {
in_reply_to: InReplyTo { event_id: original_message.event_id.clone() }, in_reply_to: InReplyTo { event_id: original_message.event_id().clone() },
}), }),
..Self::notice_plain(body) ..Self::notice_plain(body)
} }

View File

@ -1,42 +1,90 @@
use indoc::formatdoc; use indoc::formatdoc;
use ruma_identifiers::{EventId, UserId};
use super::{FormattedBody, MessageType, RoomMessageEvent}; use super::{
FormattedBody, MessageType, RoomMessageEvent, RoomMessageEventContent, SyncRoomMessageEvent,
};
pub fn get_plain_quote_fallback(original_message: &RoomMessageEvent) -> String { /// An event that can be replied to.
match &original_message.content.msgtype { ///
/// This trait only exists to allow the plain-text `reply` constructors on `MessageEventContent` to
/// use either a [`RoomMessageEvent`] or a [`SyncRoomMessageEvent`] as the event being replied to.
pub trait ReplyBaseEvent {
#[doc(hidden)]
fn event_id(&self) -> &EventId;
#[doc(hidden)]
fn sender(&self) -> &UserId;
#[doc(hidden)]
fn content(&self) -> &RoomMessageEventContent;
}
impl ReplyBaseEvent for RoomMessageEvent {
fn event_id(&self) -> &EventId {
&self.event_id
}
fn sender(&self) -> &UserId {
&self.sender
}
fn content(&self) -> &RoomMessageEventContent {
&self.content
}
}
impl ReplyBaseEvent for SyncRoomMessageEvent {
fn event_id(&self) -> &EventId {
&self.event_id
}
fn sender(&self) -> &UserId {
&self.sender
}
fn content(&self) -> &RoomMessageEventContent {
&self.content
}
}
pub fn get_plain_quote_fallback(original_message: &impl ReplyBaseEvent) -> String {
let sender = original_message.sender();
match &original_message.content().msgtype {
MessageType::Audio(_) => { MessageType::Audio(_) => {
format!("> <{}> sent an audio file.", original_message.sender) format!("> <{}> sent an audio file.", sender)
} }
MessageType::Emote(content) => { MessageType::Emote(content) => {
format!("> * <{}> {}", original_message.sender, content.body) format!("> * <{}> {}", sender, content.body)
} }
MessageType::File(_) => { MessageType::File(_) => {
format!("> <{}> sent a file.", original_message.sender) format!("> <{}> sent a file.", sender)
} }
MessageType::Image(_) => { MessageType::Image(_) => {
format!("> <{}> sent an image.", original_message.sender) format!("> <{}> sent an image.", sender)
} }
MessageType::Location(content) => { MessageType::Location(content) => {
format!("> <{}> {}", original_message.sender, content.body) format!("> <{}> {}", sender, content.body)
} }
MessageType::Notice(content) => { MessageType::Notice(content) => {
format!("> <{}> {}", original_message.sender, content.body) format!("> <{}> {}", sender, content.body)
} }
MessageType::ServerNotice(content) => { MessageType::ServerNotice(content) => {
format!("> <{}> {}", original_message.sender, content.body) format!("> <{}> {}", sender, content.body)
} }
MessageType::Text(content) => { MessageType::Text(content) => {
format!("> <{}> {}", original_message.sender, content.body) format!("> <{}> {}", sender, content.body)
} }
MessageType::Video(_) => { MessageType::Video(_) => {
format!("> <{}> sent a video.", original_message.sender) format!("> <{}> sent a video.", sender)
} }
MessageType::_Custom(content) => { MessageType::_Custom(content) => {
format!("> <{}> {}", original_message.sender, content.body) format!("> <{}> {}", sender, content.body)
} }
#[cfg(feature = "unstable-pre-spec")] #[cfg(feature = "unstable-pre-spec")]
MessageType::VerificationRequest(content) => { MessageType::VerificationRequest(content) => {
format!("> <{}> {}", original_message.sender, content.body) format!("> <{}> {}", sender, content.body)
} }
} }
.replace('\n', "\n> ") .replace('\n', "\n> ")