fractal/session/view/content/room_details/history_viewer/
event.rs1use gtk::{glib, prelude::*, subclass::prelude::*};
2use matrix_sdk::deserialized_responses::TimelineEvent;
3use ruma::{
4 events::{
5 room::message::{MessageType, OriginalSyncRoomMessageEvent, Relation},
6 AnySyncMessageLikeEvent, AnySyncTimelineEvent, SyncMessageLikeEvent,
7 },
8 OwnedEventId,
9};
10
11use crate::{
12 session::model::Room,
13 utils::matrix::{MediaMessage, VisualMediaMessage},
14};
15
16#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, glib::Enum)]
18#[enum_type(name = "HistoryViewerEventType")]
19pub enum HistoryViewerEventType {
20 #[default]
22 File,
23 Media,
25 Audio,
27}
28
29impl HistoryViewerEventType {
30 fn with_msgtype(msgtype: &MessageType) -> Option<Self> {
31 let event_type = match msgtype {
32 MessageType::Audio(_) => Self::Audio,
33 MessageType::File(_) => Self::File,
34 MessageType::Image(_) | MessageType::Video(_) => Self::Media,
35 _ => return None,
36 };
37
38 Some(event_type)
39 }
40}
41
42mod imp {
43 use std::cell::{Cell, OnceCell};
44
45 use super::*;
46
47 #[derive(Debug, Default, glib::Properties)]
48 #[properties(wrapper_type = super::HistoryViewerEvent)]
49 pub struct HistoryViewerEvent {
50 #[property(get, construct_only)]
52 room: glib::WeakRef<Room>,
53 matrix_event: OnceCell<OriginalSyncRoomMessageEvent>,
55 #[property(get, construct_only, builder(HistoryViewerEventType::default()))]
57 event_type: Cell<HistoryViewerEventType>,
58 }
59
60 #[glib::object_subclass]
61 impl ObjectSubclass for HistoryViewerEvent {
62 const NAME: &'static str = "HistoryViewerEvent";
63 type Type = super::HistoryViewerEvent;
64 }
65
66 #[glib::derived_properties]
67 impl ObjectImpl for HistoryViewerEvent {}
68
69 impl HistoryViewerEvent {
70 pub(super) fn set_matrix_event(&self, event: OriginalSyncRoomMessageEvent) {
72 self.matrix_event
73 .set(event)
74 .expect("Matrix event should be uninitialized");
75 }
76
77 pub(super) fn matrix_event(&self) -> &OriginalSyncRoomMessageEvent {
79 self.matrix_event
80 .get()
81 .expect("Matrix event should be initialized")
82 }
83 }
84}
85
86glib::wrapper! {
87 pub struct HistoryViewerEvent(ObjectSubclass<imp::HistoryViewerEvent>);
89}
90
91impl HistoryViewerEvent {
92 pub fn try_new(room: &Room, event: &TimelineEvent) -> Option<Self> {
95 let Ok(AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage(
96 SyncMessageLikeEvent::Original(mut message_event),
97 ))) = event.raw().deserialize()
98 else {
99 return None;
100 };
101
102 if matches!(
104 message_event.content.relates_to,
105 Some(Relation::Replacement(_))
106 ) {
107 return None;
108 }
109
110 if let Some(Relation::Replacement(replacement)) = message_event
112 .unsigned
113 .relations
114 .replace
115 .as_ref()
116 .and_then(|e| e.content.relates_to.as_ref())
117 {
118 message_event
119 .content
120 .apply_replacement(replacement.new_content.clone());
121 }
122
123 let event_type = HistoryViewerEventType::with_msgtype(&message_event.content.msgtype)?;
124
125 let obj = glib::Object::builder::<Self>()
126 .property("room", room)
127 .property("event-type", event_type)
128 .build();
129 obj.imp().set_matrix_event(message_event);
130
131 Some(obj)
132 }
133
134 pub(crate) fn matrix_event(&self) -> &OriginalSyncRoomMessageEvent {
136 self.imp().matrix_event()
137 }
138
139 pub(crate) fn event_id(&self) -> OwnedEventId {
141 self.matrix_event().event_id.clone()
142 }
143
144 pub(crate) fn media_message(&self) -> MediaMessage {
146 MediaMessage::from_message(&self.matrix_event().content.msgtype)
147 .expect("HistoryViewerEvents are all media messages")
148 }
149
150 pub(crate) fn visual_media_message(&self) -> Option<VisualMediaMessage> {
152 VisualMediaMessage::from_message(&self.matrix_event().content.msgtype)
153 }
154
155 pub(crate) async fn get_file_content(&self) -> Result<Vec<u8>, matrix_sdk::Error> {
157 let Some(room) = self.room() else {
158 return Err(matrix_sdk::Error::UnknownError(
159 "Could not upgrade Room".into(),
160 ));
161 };
162 let Some(session) = room.session() else {
163 return Err(matrix_sdk::Error::UnknownError(
164 "Could not upgrade Session".into(),
165 ));
166 };
167
168 let client = session.client();
169 self.media_message().into_content(&client).await
170 }
171}