166 lines
5.0 KiB
Rust
166 lines
5.0 KiB
Rust
use std::ops::Deref;
|
|
|
|
use gtk::{glib, prelude::*, subclass::prelude::*};
|
|
use matrix_sdk::deserialized_responses::TimelineEvent;
|
|
use ruma::{
|
|
events::{
|
|
room::message::{MessageType, OriginalSyncRoomMessageEvent, Relation},
|
|
AnySyncMessageLikeEvent, AnyTimelineEvent, SyncMessageLikeEvent,
|
|
},
|
|
OwnedEventId,
|
|
};
|
|
|
|
use crate::{session::model::Room, utils::matrix::get_media_content};
|
|
|
|
/// The types of events that can be displayer in the history viewers.
|
|
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, glib::Enum)]
|
|
#[enum_type(name = "HistoryViewerEventType")]
|
|
pub enum HistoryViewerEventType {
|
|
#[default]
|
|
File,
|
|
Media,
|
|
Audio,
|
|
}
|
|
|
|
impl HistoryViewerEventType {
|
|
fn with_msgtype(msgtype: &MessageType) -> Option<Self> {
|
|
let event_type = match msgtype {
|
|
MessageType::Audio(_) => Self::Audio,
|
|
MessageType::File(_) => Self::File,
|
|
MessageType::Image(_) => Self::Media,
|
|
MessageType::Video(_) => Self::Media,
|
|
_ => return None,
|
|
};
|
|
|
|
Some(event_type)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, glib::Boxed)]
|
|
#[boxed_type(name = "BoxedSyncRoomMessageEvent")]
|
|
pub struct BoxedSyncRoomMessageEvent(pub OriginalSyncRoomMessageEvent);
|
|
|
|
impl Deref for BoxedSyncRoomMessageEvent {
|
|
type Target = OriginalSyncRoomMessageEvent;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
mod imp {
|
|
use std::cell::{Cell, OnceCell};
|
|
|
|
use super::*;
|
|
|
|
#[derive(Debug, Default, glib::Properties)]
|
|
#[properties(wrapper_type = super::HistoryViewerEvent)]
|
|
pub struct HistoryViewerEvent {
|
|
/// The room containing this event.
|
|
#[property(get, construct_only)]
|
|
pub room: glib::WeakRef<Room>,
|
|
/// The Matrix event.
|
|
#[property(construct_only)]
|
|
pub matrix_event: OnceCell<BoxedSyncRoomMessageEvent>,
|
|
/// The type of the event.
|
|
#[property(get, construct_only, builder(HistoryViewerEventType::default()))]
|
|
pub event_type: Cell<HistoryViewerEventType>,
|
|
}
|
|
|
|
#[glib::object_subclass]
|
|
impl ObjectSubclass for HistoryViewerEvent {
|
|
const NAME: &'static str = "HistoryViewerEvent";
|
|
type Type = super::HistoryViewerEvent;
|
|
}
|
|
|
|
#[glib::derived_properties]
|
|
impl ObjectImpl for HistoryViewerEvent {}
|
|
}
|
|
|
|
glib::wrapper! {
|
|
/// An event in the history viewer's timeline.
|
|
pub struct HistoryViewerEvent(ObjectSubclass<imp::HistoryViewerEvent>);
|
|
}
|
|
|
|
impl HistoryViewerEvent {
|
|
/// Constructs a new `HistoryViewerEvent` with the given event, if it is
|
|
/// viewable in one of the history viewers.
|
|
pub fn try_new(room: &Room, event: TimelineEvent) -> Option<Self> {
|
|
let Ok(AnyTimelineEvent::MessageLike(message_like_event)) = event.event.deserialize()
|
|
else {
|
|
return None;
|
|
};
|
|
let AnySyncMessageLikeEvent::RoomMessage(SyncMessageLikeEvent::Original(mut message_event)) =
|
|
message_like_event.into()
|
|
else {
|
|
return None;
|
|
};
|
|
|
|
// Filter out edits, they should be bundled with the original event.
|
|
if matches!(
|
|
message_event.content.relates_to,
|
|
Some(Relation::Replacement(_))
|
|
) {
|
|
return None;
|
|
}
|
|
|
|
// Apply bundled edit.
|
|
if let Some(Relation::Replacement(replacement)) = message_event
|
|
.unsigned
|
|
.relations
|
|
.replace
|
|
.as_ref()
|
|
.and_then(|e| e.content.relates_to.as_ref())
|
|
{
|
|
message_event
|
|
.content
|
|
.apply_replacement(replacement.new_content.clone());
|
|
}
|
|
|
|
let event_type = HistoryViewerEventType::with_msgtype(&message_event.content.msgtype)?;
|
|
|
|
let obj: Self = glib::Object::builder()
|
|
.property("room", room)
|
|
.property("matrix-event", BoxedSyncRoomMessageEvent(message_event))
|
|
.property("event-type", event_type)
|
|
.build();
|
|
|
|
Some(obj)
|
|
}
|
|
|
|
/// The Matrix event.
|
|
fn matrix_event(&self) -> &OriginalSyncRoomMessageEvent {
|
|
self.imp().matrix_event.get().unwrap()
|
|
}
|
|
|
|
/// The event ID of the inner event.
|
|
pub fn event_id(&self) -> OwnedEventId {
|
|
self.matrix_event().event_id.clone()
|
|
}
|
|
|
|
/// The message content of the inner event.
|
|
pub fn message_content(&self) -> MessageType {
|
|
self.matrix_event().content.msgtype.clone()
|
|
}
|
|
|
|
/// Get the binary content of this event.
|
|
///
|
|
/// Returns `Ok((filename, binary_content))` on success.
|
|
pub async fn get_file_content(&self) -> Result<(String, Vec<u8>), matrix_sdk::Error> {
|
|
let Some(room) = self.room() else {
|
|
return Err(matrix_sdk::Error::UnknownError(
|
|
"Failed to upgrade Room".into(),
|
|
));
|
|
};
|
|
let Some(session) = room.session() else {
|
|
return Err(matrix_sdk::Error::UnknownError(
|
|
"Failed to upgrade Session".into(),
|
|
));
|
|
};
|
|
let client = session.client();
|
|
let message_content = self.message_content();
|
|
|
|
get_media_content(client, message_content).await
|
|
}
|
|
}
|