matrix_sdk_ui/timeline/event_item/content/msg_like.rs
1// Copyright 2024 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use as_variant::as_variant;
16use ruma::OwnedEventId;
17
18use super::{EmbeddedEvent, EncryptedMessage, InReplyToDetails, Message, PollState, Sticker};
19use crate::timeline::{ReactionsByKeyBySender, TimelineDetails};
20
21#[derive(Clone, Debug)]
22pub enum MsgLikeKind {
23 /// An `m.room.message` event or extensible event, including edits.
24 Message(Message),
25
26 /// An `m.sticker` event.
27 Sticker(Sticker),
28
29 /// An `m.poll.start` event.
30 Poll(PollState),
31
32 /// A redacted message.
33 Redacted,
34
35 /// An `m.room.encrypted` event that could not be decrypted.
36 UnableToDecrypt(EncryptedMessage),
37}
38
39#[derive(Clone, Debug)]
40pub struct ThreadSummary {
41 pub latest_event: TimelineDetails<Box<EmbeddedEvent>>,
42
43 /// The number of events in the thread, except for the thread root.
44 ///
45 /// This can be zero if all the events in the thread have been redacted.
46 ///
47 /// Note: this doesn't interact with the timeline filter; so opening a
48 /// thread-focused timeline with the same timeline filter may result in
49 /// *fewer* events than this number.
50 pub num_replies: u32,
51}
52
53/// A special kind of [`super::TimelineItemContent`] that groups together
54/// different room message types with their respective reactions and thread
55/// information.
56#[derive(Clone, Debug)]
57pub struct MsgLikeContent {
58 pub kind: MsgLikeKind,
59 pub reactions: ReactionsByKeyBySender,
60 /// The event this message is replying to, if any.
61 pub in_reply_to: Option<InReplyToDetails>,
62 /// Event ID of the thread root, if this is a message in a thread.
63 pub thread_root: Option<OwnedEventId>,
64 /// Information about the thread this message is the root of, if any.
65 pub thread_summary: Option<ThreadSummary>,
66}
67
68impl MsgLikeContent {
69 #[cfg(not(tarpaulin_include))] // debug-logging functionality
70 pub(crate) fn debug_string(&self) -> &'static str {
71 match self.kind {
72 MsgLikeKind::Message(_) => "a message",
73 MsgLikeKind::Sticker(_) => "a sticker",
74 MsgLikeKind::Poll(_) => "a poll",
75 MsgLikeKind::Redacted => "a redacted message",
76 MsgLikeKind::UnableToDecrypt(_) => "an encrypted message we couldn't decrypt",
77 }
78 }
79
80 pub fn redacted() -> Self {
81 Self {
82 kind: MsgLikeKind::Redacted,
83 reactions: Default::default(),
84 thread_root: None,
85 in_reply_to: None,
86 thread_summary: None,
87 }
88 }
89
90 pub fn unable_to_decrypt(encrypted_message: EncryptedMessage) -> Self {
91 Self {
92 kind: MsgLikeKind::UnableToDecrypt(encrypted_message),
93 reactions: Default::default(),
94 thread_root: None,
95 in_reply_to: None,
96 thread_summary: None,
97 }
98 }
99
100 /// Whether this item is part of a thread.
101 pub fn is_threaded(&self) -> bool {
102 self.thread_root.is_some()
103 }
104
105 pub fn with_in_reply_to(&self, in_reply_to: InReplyToDetails) -> Self {
106 Self { in_reply_to: Some(in_reply_to), ..self.clone() }
107 }
108
109 pub fn with_kind(&self, kind: MsgLikeKind) -> Self {
110 Self { kind, ..self.clone() }
111 }
112
113 /// If `kind` is of the [`MsgLikeKind`][MsgLikeKind::Message] variant,
114 /// return the inner [`Message`].
115 pub fn as_message(&self) -> Option<Message> {
116 as_variant!(&self.kind, MsgLikeKind::Message(message) => message.clone())
117 }
118}