[fractal/fractal-next] Use SyncRoomEvent instead of other types



commit 5a3c22a4034d4b07d2746e8a68e70024a7f2c5ac
Author: Julian Sparber <julian sparber net>
Date:   Tue Jul 20 09:13:19 2021 +0000

    Use SyncRoomEvent instead of other types

 src/session/content/item_row.rs    | 116 +++++++------
 src/session/content/message_row.rs |  42 +++--
 src/session/content/state_row.rs   |   4 +-
 src/session/room/event.rs          | 348 +++++++++++++++++++++----------------
 src/session/room/item.rs           |   8 +-
 src/session/room/room.rs           | 133 ++++++--------
 src/session/room/timeline.rs       |  65 +++----
 src/session/user.rs                |   4 +-
 8 files changed, 377 insertions(+), 343 deletions(-)
---
diff --git a/src/session/content/item_row.rs b/src/session/content/item_row.rs
index 4ae02192..1c70d0c0 100644
--- a/src/session/content/item_row.rs
+++ b/src/session/content/item_row.rs
@@ -1,21 +1,23 @@
 use adw::{prelude::*, subclass::prelude::*};
 use gettextrs::gettext;
-use gtk::{gio, glib, prelude::*, subclass::prelude::*};
+use gtk::{gio, glib, glib::clone, prelude::*, subclass::prelude::*};
 
 use crate::components::{ContextMenuBin, ContextMenuBinExt, ContextMenuBinImpl};
 use crate::session::content::{DividerRow, MessageRow, StateRow};
 use crate::session::event_source_dialog::EventSourceDialog;
-use crate::session::room::{Item, ItemType};
-use matrix_sdk::ruma::events::AnyRoomEvent;
+use crate::session::room::{Event, Item, ItemType};
+use matrix_sdk::ruma::events::AnySyncRoomEvent;
 
 mod imp {
     use super::*;
+    use glib::signal::SignalHandlerId;
     use std::cell::RefCell;
 
     #[derive(Debug, Default)]
     pub struct ItemRow {
         pub item: RefCell<Option<Item>>,
         pub menu_model: RefCell<Option<gio::MenuModel>>,
+        pub event_notify_handler: RefCell<Option<SignalHandlerId>>,
     }
 
     #[glib::object_subclass]
@@ -73,6 +75,16 @@ mod imp {
                 _ => unimplemented!(),
             }
         }
+
+        fn dispose(&self, _obj: &Self::Type) {
+            if let Some(ItemType::Event(event)) =
+                self.item.borrow().as_ref().map(|item| item.type_())
+            {
+                if let Some(handler) = self.event_notify_handler.borrow_mut().take() {
+                    event.disconnect(handler);
+                }
+            }
+        }
     }
 
     impl WidgetImpl for ItemRow {}
@@ -113,6 +125,13 @@ impl ItemRow {
     fn set_item(&self, item: Option<Item>) {
         let priv_ = imp::ItemRow::from_instance(&self);
 
+        if let Some(ItemType::Event(event)) = priv_.item.borrow().as_ref().map(|item| item.type_())
+        {
+            if let Some(handler) = priv_.event_notify_handler.borrow_mut().take() {
+                event.disconnect(handler);
+            }
+        }
+
         if let Some(ref item) = item {
             match item.type_() {
                 ItemType::Event(event) => {
@@ -126,57 +145,19 @@ impl ItemRow {
                         self.enable_gactions();
                     }
 
-                    match event.matrix_event() {
-                        AnyRoomEvent::Message(_message) => {
-                            let child = if let Some(Ok(child)) =
-                                self.child().map(|w| w.downcast::<MessageRow>())
-                            {
-                                child
-                            } else {
-                                let child = MessageRow::new();
-                                self.set_child(Some(&child));
-                                child
-                            };
-                            child.set_event(event.clone());
-                        }
-                        AnyRoomEvent::State(state) => {
-                            let child = if let Some(Ok(child)) =
-                                self.child().map(|w| w.downcast::<StateRow>())
-                            {
-                                child
-                            } else {
-                                let child = StateRow::new();
-                                self.set_child(Some(&child));
-                                child
-                            };
-
-                            child.update(&state);
-                        }
-                        AnyRoomEvent::RedactedMessage(_) => {
-                            let child = if let Some(Ok(child)) =
-                                self.child().map(|w| w.downcast::<MessageRow>())
-                            {
-                                child
-                            } else {
-                                let child = MessageRow::new();
-                                self.set_child(Some(&child));
-                                child
-                            };
-                            child.set_event(event.clone());
-                        }
-                        AnyRoomEvent::RedactedState(_) => {
-                            let child = if let Some(Ok(child)) =
-                                self.child().map(|w| w.downcast::<MessageRow>())
-                            {
-                                child
-                            } else {
-                                let child = MessageRow::new();
-                                self.set_child(Some(&child));
-                                child
-                            };
-                            child.set_event(event.clone());
-                        }
-                    }
+                    let event_notify_handler = event.connect_notify_local(
+                        Some("event"),
+                        clone!(@weak self as obj => move |event, _| {
+                            obj.set_event_widget(event);
+                        }),
+                    );
+
+                    priv_
+                        .event_notify_handler
+                        .borrow_mut()
+                        .replace(event_notify_handler);
+
+                    self.set_event_widget(event);
                 }
                 ItemType::DayDivider(date) => {
                     if self.context_menu().is_some() {
@@ -219,4 +200,31 @@ impl ItemRow {
         }
         priv_.item.replace(item);
     }
+
+    fn set_event_widget(&self, event: &Event) {
+        match event.matrix_event() {
+            Some(AnySyncRoomEvent::State(state)) => {
+                let child = if let Some(Ok(child)) = self.child().map(|w| w.downcast::<StateRow>())
+                {
+                    child
+                } else {
+                    let child = StateRow::new();
+                    self.set_child(Some(&child));
+                    child
+                };
+                child.update(&state);
+            }
+            _ => {
+                let child =
+                    if let Some(Ok(child)) = self.child().map(|w| w.downcast::<MessageRow>()) {
+                        child
+                    } else {
+                        let child = MessageRow::new();
+                        self.set_child(Some(&child));
+                        child
+                    };
+                child.set_event(event.clone());
+            }
+        }
+    }
 }
diff --git a/src/session/content/message_row.rs b/src/session/content/message_row.rs
index c1fc0d60..996c3b17 100644
--- a/src/session/content/message_row.rs
+++ b/src/session/content/message_row.rs
@@ -1,5 +1,6 @@
 use crate::components::Avatar;
 use adw::{prelude::*, subclass::prelude::*};
+use gettextrs::gettext;
 use gtk::{
     gio, glib, glib::clone, glib::signal::SignalHandlerId, prelude::*, subclass::prelude::*,
     CompositeTemplate,
@@ -12,7 +13,7 @@ use log::warn;
 use matrix_sdk::ruma::events::{
     room::message::{FormattedBody, MessageFormat, MessageType, Relation},
     room::redaction::RedactionEventContent,
-    AnyMessageEvent, AnyMessageEventContent, AnyRoomEvent,
+    AnyMessageEventContent, AnySyncMessageEvent, AnySyncRoomEvent,
 };
 use sourceview::prelude::*;
 
@@ -190,10 +191,10 @@ impl MessageRow {
         if let Some(replacement_event) = event.relates_to().iter().rev().find(|event| {
             let matrix_event = event.matrix_event();
             match matrix_event {
-                AnyRoomEvent::Message(AnyMessageEvent::RoomMessage(message)) => {
+                Some(AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage(message))) => {
                     message.content.relates_to.is_some()
                 }
-                AnyRoomEvent::Message(AnyMessageEvent::RoomRedaction(_)) => true,
+                Some(AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomRedaction(_))) => true,
                 _ => false,
             }
         }) {
@@ -207,24 +208,32 @@ impl MessageRow {
         }
     }
     /// Find the content we need to display
-    fn find_content(&self, event: &Event) -> AnyMessageEventContent {
+    fn find_content(&self, event: &Event) -> Option<AnyMessageEventContent> {
         match self.find_last_event(event).matrix_event() {
-            AnyRoomEvent::Message(message) => message.content(),
-            AnyRoomEvent::RedactedMessage(message) => {
+            Some(AnySyncRoomEvent::Message(message)) => Some(message.content()),
+            Some(AnySyncRoomEvent::RedactedMessage(message)) => {
                 if let Some(ref redaction_event) = message.unsigned().redacted_because {
-                    AnyMessageEventContent::RoomRedaction(redaction_event.content.clone())
+                    Some(AnyMessageEventContent::RoomRedaction(
+                        redaction_event.content.clone(),
+                    ))
                 } else {
-                    AnyMessageEventContent::RoomRedaction(RedactionEventContent::new())
+                    Some(AnyMessageEventContent::RoomRedaction(
+                        RedactionEventContent::new(),
+                    ))
                 }
             }
-            AnyRoomEvent::RedactedState(state) => {
+            Some(AnySyncRoomEvent::RedactedState(state)) => {
                 if let Some(ref redaction_event) = state.unsigned().redacted_because {
-                    AnyMessageEventContent::RoomRedaction(redaction_event.content.clone())
+                    Some(AnyMessageEventContent::RoomRedaction(
+                        redaction_event.content.clone(),
+                    ))
                 } else {
-                    AnyMessageEventContent::RoomRedaction(RedactionEventContent::new())
+                    Some(AnyMessageEventContent::RoomRedaction(
+                        RedactionEventContent::new(),
+                    ))
                 }
             }
-            _ => panic!("This event isn’t a room message event or redacted event"),
+            _ => None,
         }
     }
 
@@ -234,8 +243,9 @@ impl MessageRow {
 
         // TODO: create widgets for all event types
         // TODO: display reaction events from event.relates_to()
+
         match content {
-            AnyMessageEventContent::RoomMessage(message) => {
+            Some(AnyMessageEventContent::RoomMessage(message)) => {
                 let msgtype = if let Some(Relation::Replacement(replacement)) = message.relates_to {
                     replacement.new_content.msgtype
                 } else {
@@ -300,10 +310,10 @@ impl MessageRow {
                     }
                 }
             }
-            AnyMessageEventContent::RoomRedaction(_) => {
-                self.show_label_with_text("This message was removed.");
+            Some(AnyMessageEventContent::RoomRedaction(_)) => {
+                self.show_label_with_text(&gettext("This message was removed."))
             }
-            _ => warn!("Event not supported: {:?}", content),
+            _ => self.show_label_with_text(&gettext("Unsupported event")),
         }
     }
 
diff --git a/src/session/content/state_row.rs b/src/session/content/state_row.rs
index 4dd0f6c9..7f4b4aff 100644
--- a/src/session/content/state_row.rs
+++ b/src/session/content/state_row.rs
@@ -3,7 +3,7 @@ use gettextrs::gettext;
 use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate};
 use log::warn;
 use matrix_sdk::ruma::events::{
-    room::member::MembershipState, AnyStateEvent, AnyStateEventContent,
+    room::member::MembershipState, AnyStateEventContent, AnySyncStateEvent,
 };
 
 mod imp {
@@ -51,7 +51,7 @@ impl StateRow {
         glib::Object::new(&[]).expect("Failed to create StateRow")
     }
 
-    pub fn update(&self, state: &AnyStateEvent) {
+    pub fn update(&self, state: &AnySyncStateEvent) {
         let _priv_ = imp::StateRow::from_instance(self);
         // We may want to show more state events in the future
         // For a full list of state events see:
diff --git a/src/session/room/event.rs b/src/session/room/event.rs
index 2ab260ef..4dcfb7a0 100644
--- a/src/session/room/event.rs
+++ b/src/session/room/event.rs
@@ -1,20 +1,23 @@
 use gtk::{glib, glib::DateTime, prelude::*, subclass::prelude::*};
-use matrix_sdk::ruma::{
-    events::{
-        room::message::MessageType, room::message::Relation, AnyMessageEvent,
-        AnyMessageEventContent, AnyRedactedMessageEvent, AnyRedactedStateEvent, AnyRoomEvent,
-        AnyStateEvent,
+use matrix_sdk::{
+    deserialized_responses::SyncRoomEvent,
+    ruma::{
+        events::{
+            room::message::MessageType, room::message::Relation, AnyMessageEventContent,
+            AnyRedactedSyncMessageEvent, AnyRedactedSyncStateEvent, AnySyncMessageEvent,
+            AnySyncRoomEvent, AnySyncStateEvent,
+        },
+        identifiers::{EventId, UserId},
+        MilliSecondsSinceUnixEpoch,
     },
-    identifiers::{EventId, UserId},
 };
 
-use crate::fn_event;
-use crate::session::User;
-use std::cell::RefCell;
+use crate::session::{Room, User};
+use log::warn;
 
 #[derive(Clone, Debug, glib::GBoxed)]
-#[gboxed(type_name = "BoxedAnyRoomEvent")]
-pub struct BoxedAnyRoomEvent(AnyRoomEvent);
+#[gboxed(type_name = "BoxedSyncRoomEvent")]
+pub struct BoxedSyncRoomEvent(SyncRoomEvent);
 
 mod imp {
     use super::*;
@@ -24,11 +27,13 @@ mod imp {
 
     #[derive(Debug, Default)]
     pub struct Event {
-        pub event: OnceCell<RefCell<AnyRoomEvent>>,
-        pub source: RefCell<Option<String>>,
+        /// The deserialized matrix event
+        pub event: RefCell<Option<AnySyncRoomEvent>>,
+        /// The SDK event containing encryption information and the serialized event as `Raw`
+        pub pure_event: RefCell<Option<SyncRoomEvent>>,
         pub relates_to: RefCell<Vec<super::Event>>,
         pub show_header: Cell<bool>,
-        pub sender: OnceCell<User>,
+        pub room: OnceCell<Room>,
     }
 
     #[glib::object_subclass]
@@ -53,15 +58,15 @@ mod imp {
                         "event",
                         "event",
                         "The matrix event of this Event",
-                        BoxedAnyRoomEvent::static_type(),
-                        glib::ParamFlags::WRITABLE | glib::ParamFlags::CONSTRUCT,
+                        BoxedSyncRoomEvent::static_type(),
+                        glib::ParamFlags::WRITABLE,
                     ),
                     glib::ParamSpec::new_string(
                         "source",
                         "Source",
                         "The source (JSON) of this Event",
                         None,
-                        glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT | 
glib::ParamFlags::EXPLICIT_NOTIFY,
+                        glib::ParamFlags::READABLE | glib::ParamFlags::EXPLICIT_NOTIFY,
                     ),
                     glib::ParamSpec::new_boolean(
                         "show-header",
@@ -82,6 +87,13 @@ mod imp {
                         "Sender",
                         "The sender of this matrix event",
                         User::static_type(),
+                        glib::ParamFlags::READABLE,
+                    ),
+                    glib::ParamSpec::new_object(
+                        "room",
+                        "Room",
+                        "The room containing this event",
+                        Room::static_type(),
                         glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
                     ),
                     glib::ParamSpec::new_string(
@@ -106,22 +118,15 @@ mod imp {
         ) {
             match pspec.name() {
                 "event" => {
-                    let event = value.get::<BoxedAnyRoomEvent>().unwrap();
-                    obj.set_matrix_event(event.0);
-                }
-                "source" => {
-                    let source = value.get().unwrap();
-                    obj.set_source(source);
+                    let event = value.get::<BoxedSyncRoomEvent>().unwrap();
+                    obj.set_matrix_pure_event(event.0);
                 }
                 "show-header" => {
                     let show_header = value.get().unwrap();
                     let _ = obj.set_show_header(show_header);
                 }
-                "sender" => {
-                    let sender = value.get().unwrap();
-                    if let Some(sender) = sender {
-                        let _ = self.sender.set(sender).unwrap();
-                    }
+                "room" => {
+                    let _ = self.room.set(value.get().unwrap());
                 }
                 _ => unimplemented!(),
             }
@@ -130,7 +135,8 @@ mod imp {
         fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
             match pspec.name() {
                 "source" => obj.source().to_value(),
-                "sender" => self.sender.get().to_value(),
+                "sender" => obj.sender().to_value(),
+                "room" => self.room.get().unwrap().to_value(),
                 "show-header" => obj.show_header().to_value(),
                 "can-hide-header" => obj.can_hide_header().to_value(),
                 "time" => obj.time().to_value(),
@@ -149,68 +155,108 @@ glib::wrapper! {
 
 /// This is the GObject representation of a matrix room event
 impl Event {
-    pub fn new(event: &AnyRoomEvent, source: &String, sender: &User) -> Self {
-        let event = BoxedAnyRoomEvent(event.to_owned());
-        glib::Object::new(&[("event", &event), ("source", source), ("sender", sender)])
-            .expect("Failed to create Event")
+    pub fn new(event: SyncRoomEvent, room: &Room) -> Self {
+        let event = BoxedSyncRoomEvent(event);
+        glib::Object::new(&[("event", &event), ("room", room)]).expect("Failed to create Event")
     }
 
-    pub fn sender(&self) -> &User {
+    pub fn sender(&self) -> User {
         let priv_ = imp::Event::from_instance(&self);
-        priv_.sender.get().unwrap()
+        priv_
+            .room
+            .get()
+            .unwrap()
+            .member_by_id(&self.matrix_sender())
     }
 
-    pub fn matrix_event(&self) -> AnyRoomEvent {
+    /// Get the matrix event
+    ///
+    /// If the `SyncRoomEvent` couldn't be deserialized this is `None`
+    pub fn matrix_event(&self) -> Option<AnySyncRoomEvent> {
         let priv_ = imp::Event::from_instance(&self);
-        priv_.event.get().unwrap().borrow().clone()
+        priv_.event.borrow().clone()
     }
 
-    pub fn set_matrix_event(&self, event: AnyRoomEvent) {
+    pub fn matrix_pure_event(&self) -> SyncRoomEvent {
         let priv_ = imp::Event::from_instance(&self);
-        if let Some(value) = priv_.event.get() {
-            value.replace(event);
+        priv_.pure_event.borrow().clone().unwrap()
+    }
+
+    pub fn set_matrix_pure_event(&self, event: SyncRoomEvent) {
+        let priv_ = imp::Event::from_instance(&self);
+
+        if let Ok(deserialized) = event.event.deserialize() {
+            priv_.event.replace(Some(deserialized));
         } else {
-            priv_.event.set(RefCell::new(event)).unwrap();
+            warn!("Failed to deserialize event: {:?}", event);
         }
+
+        priv_.pure_event.replace(Some(event));
+
         self.notify("event");
     }
 
     pub fn matrix_sender(&self) -> UserId {
         let priv_ = imp::Event::from_instance(&self);
-        let event = &*priv_.event.get().unwrap().borrow();
-        fn_event!(event, sender).clone()
+
+        if let Some(event) = priv_.event.borrow().as_ref() {
+            event.sender().to_owned()
+        } else {
+            priv_
+                .pure_event
+                .borrow()
+                .as_ref()
+                .unwrap()
+                .event
+                .get_field::<UserId>("sender")
+                .unwrap()
+                .unwrap()
+        }
     }
 
     pub fn matrix_event_id(&self) -> EventId {
         let priv_ = imp::Event::from_instance(&self);
-        let event = &*priv_.event.get().unwrap().borrow();
-        fn_event!(event, event_id).clone()
-    }
 
-    pub fn source(&self) -> String {
-        let priv_ = imp::Event::from_instance(&self);
-        priv_.source.borrow().clone().unwrap_or("".into())
+        if let Some(event) = priv_.event.borrow().as_ref() {
+            event.event_id().to_owned()
+        } else {
+            priv_
+                .pure_event
+                .borrow()
+                .as_ref()
+                .unwrap()
+                .event
+                .get_field::<EventId>("event_id")
+                .unwrap()
+                .unwrap()
+        }
     }
 
-    pub fn set_source(&self, source: Option<String>) {
+    pub fn source(&self) -> String {
         let priv_ = imp::Event::from_instance(&self);
-
-        if Some(self.source()) == source {
-            return;
-        }
-
-        priv_.source.replace(source);
-        self.notify("source");
+        serde_json::to_string_pretty(priv_.pure_event.borrow().as_ref().unwrap().event.json())
+            .unwrap()
     }
 
     pub fn timestamp(&self) -> DateTime {
         let priv_ = imp::Event::from_instance(&self);
-        let event = &*priv_.event.get().unwrap().borrow();
-
-        let ts = fn_event!(event, origin_server_ts).clone();
 
-        // FIXME: we need to add `as_secs()` to `MilliSecondsSinceUnixEpoch`
-        DateTime::from_unix_utc(i64::from(ts.0) / 1000)
+        let ts = if let Some(event) = priv_.event.borrow().as_ref() {
+            event.origin_server_ts().as_secs()
+        } else {
+            priv_
+                .pure_event
+                .borrow()
+                .as_ref()
+                .unwrap()
+                .event
+                .get_field::<MilliSecondsSinceUnixEpoch>("origin_server_ts")
+                .unwrap()
+                .unwrap()
+                .as_secs()
+        };
+
+        DateTime::from_unix_utc(ts.into())
             .and_then(|t| t.to_local())
             .unwrap()
     }
@@ -234,9 +280,9 @@ impl Event {
     pub fn related_matrix_event(&self) -> Option<EventId> {
         let priv_ = imp::Event::from_instance(&self);
 
-        match *priv_.event.get().unwrap().borrow() {
-            AnyRoomEvent::Message(ref message) => match message {
-                AnyMessageEvent::RoomRedaction(event) => Some(event.redacts.clone()),
+        match priv_.event.borrow().as_ref()? {
+            AnySyncRoomEvent::Message(ref message) => match message {
+                AnySyncMessageEvent::RoomRedaction(event) => Some(event.redacts.clone()),
                 _ => match message.content() {
                     AnyMessageEventContent::Reaction(event) => Some(event.relates_to.event_id),
                     AnyMessageEventContent::RoomMessage(event) => match event.relates_to {
@@ -265,75 +311,79 @@ impl Event {
             return true;
         }
 
-        match &*priv_.event.get().unwrap().borrow() {
-            AnyRoomEvent::Message(message) => match message {
-                AnyMessageEvent::CallAnswer(_) => true,
-                AnyMessageEvent::CallInvite(_) => true,
-                AnyMessageEvent::CallHangup(_) => true,
-                AnyMessageEvent::CallCandidates(_) => true,
-                AnyMessageEvent::KeyVerificationReady(_) => true,
-                AnyMessageEvent::KeyVerificationStart(_) => true,
-                AnyMessageEvent::KeyVerificationCancel(_) => true,
-                AnyMessageEvent::KeyVerificationAccept(_) => true,
-                AnyMessageEvent::KeyVerificationKey(_) => true,
-                AnyMessageEvent::KeyVerificationMac(_) => true,
-                AnyMessageEvent::KeyVerificationDone(_) => true,
-                AnyMessageEvent::RoomEncrypted(_) => true,
-                AnyMessageEvent::RoomMessageFeedback(_) => true,
-                AnyMessageEvent::RoomRedaction(_) => true,
-                AnyMessageEvent::Sticker(_) => true,
-                _ => false,
-            },
-            AnyRoomEvent::State(state) => match state {
-                AnyStateEvent::PolicyRuleRoom(_) => true,
-                AnyStateEvent::PolicyRuleServer(_) => true,
-                AnyStateEvent::PolicyRuleUser(_) => true,
-                AnyStateEvent::RoomAliases(_) => true,
-                AnyStateEvent::RoomAvatar(_) => true,
-                AnyStateEvent::RoomCanonicalAlias(_) => true,
-                AnyStateEvent::RoomEncryption(_) => true,
-                AnyStateEvent::RoomJoinRules(_) => true,
-                AnyStateEvent::RoomName(_) => true,
-                AnyStateEvent::RoomPinnedEvents(_) => true,
-                AnyStateEvent::RoomPowerLevels(_) => true,
-                AnyStateEvent::RoomServerAcl(_) => true,
-                AnyStateEvent::RoomTopic(_) => true,
-                _ => false,
-            },
-            AnyRoomEvent::RedactedMessage(message) => match message {
-                AnyRedactedMessageEvent::CallAnswer(_) => true,
-                AnyRedactedMessageEvent::CallInvite(_) => true,
-                AnyRedactedMessageEvent::CallHangup(_) => true,
-                AnyRedactedMessageEvent::CallCandidates(_) => true,
-                AnyRedactedMessageEvent::KeyVerificationReady(_) => true,
-                AnyRedactedMessageEvent::KeyVerificationStart(_) => true,
-                AnyRedactedMessageEvent::KeyVerificationCancel(_) => true,
-                AnyRedactedMessageEvent::KeyVerificationAccept(_) => true,
-                AnyRedactedMessageEvent::KeyVerificationKey(_) => true,
-                AnyRedactedMessageEvent::KeyVerificationMac(_) => true,
-                AnyRedactedMessageEvent::KeyVerificationDone(_) => true,
-                AnyRedactedMessageEvent::RoomEncrypted(_) => true,
-                AnyRedactedMessageEvent::RoomMessageFeedback(_) => true,
-                AnyRedactedMessageEvent::RoomRedaction(_) => true,
-                AnyRedactedMessageEvent::Sticker(_) => true,
-                _ => false,
-            },
-            AnyRoomEvent::RedactedState(state) => match state {
-                AnyRedactedStateEvent::PolicyRuleRoom(_) => true,
-                AnyRedactedStateEvent::PolicyRuleServer(_) => true,
-                AnyRedactedStateEvent::PolicyRuleUser(_) => true,
-                AnyRedactedStateEvent::RoomAliases(_) => true,
-                AnyRedactedStateEvent::RoomAvatar(_) => true,
-                AnyRedactedStateEvent::RoomCanonicalAlias(_) => true,
-                AnyRedactedStateEvent::RoomEncryption(_) => true,
-                AnyRedactedStateEvent::RoomJoinRules(_) => true,
-                AnyRedactedStateEvent::RoomName(_) => true,
-                AnyRedactedStateEvent::RoomPinnedEvents(_) => true,
-                AnyRedactedStateEvent::RoomPowerLevels(_) => true,
-                AnyRedactedStateEvent::RoomServerAcl(_) => true,
-                AnyRedactedStateEvent::RoomTopic(_) => true,
-                _ => false,
-            },
+        if let Some(event) = priv_.event.borrow().as_ref() {
+            match event {
+                AnySyncRoomEvent::Message(message) => match message {
+                    AnySyncMessageEvent::CallAnswer(_) => true,
+                    AnySyncMessageEvent::CallInvite(_) => true,
+                    AnySyncMessageEvent::CallHangup(_) => true,
+                    AnySyncMessageEvent::CallCandidates(_) => true,
+                    AnySyncMessageEvent::KeyVerificationReady(_) => true,
+                    AnySyncMessageEvent::KeyVerificationStart(_) => true,
+                    AnySyncMessageEvent::KeyVerificationCancel(_) => true,
+                    AnySyncMessageEvent::KeyVerificationAccept(_) => true,
+                    AnySyncMessageEvent::KeyVerificationKey(_) => true,
+                    AnySyncMessageEvent::KeyVerificationMac(_) => true,
+                    AnySyncMessageEvent::KeyVerificationDone(_) => true,
+                    AnySyncMessageEvent::RoomEncrypted(_) => true,
+                    AnySyncMessageEvent::RoomMessageFeedback(_) => true,
+                    AnySyncMessageEvent::RoomRedaction(_) => true,
+                    AnySyncMessageEvent::Sticker(_) => true,
+                    _ => false,
+                },
+                AnySyncRoomEvent::State(state) => match state {
+                    AnySyncStateEvent::PolicyRuleRoom(_) => true,
+                    AnySyncStateEvent::PolicyRuleServer(_) => true,
+                    AnySyncStateEvent::PolicyRuleUser(_) => true,
+                    AnySyncStateEvent::RoomAliases(_) => true,
+                    AnySyncStateEvent::RoomAvatar(_) => true,
+                    AnySyncStateEvent::RoomCanonicalAlias(_) => true,
+                    AnySyncStateEvent::RoomEncryption(_) => true,
+                    AnySyncStateEvent::RoomJoinRules(_) => true,
+                    AnySyncStateEvent::RoomName(_) => true,
+                    AnySyncStateEvent::RoomPinnedEvents(_) => true,
+                    AnySyncStateEvent::RoomPowerLevels(_) => true,
+                    AnySyncStateEvent::RoomServerAcl(_) => true,
+                    AnySyncStateEvent::RoomTopic(_) => true,
+                    _ => false,
+                },
+                AnySyncRoomEvent::RedactedMessage(message) => match message {
+                    AnyRedactedSyncMessageEvent::CallAnswer(_) => true,
+                    AnyRedactedSyncMessageEvent::CallInvite(_) => true,
+                    AnyRedactedSyncMessageEvent::CallHangup(_) => true,
+                    AnyRedactedSyncMessageEvent::CallCandidates(_) => true,
+                    AnyRedactedSyncMessageEvent::KeyVerificationReady(_) => true,
+                    AnyRedactedSyncMessageEvent::KeyVerificationStart(_) => true,
+                    AnyRedactedSyncMessageEvent::KeyVerificationCancel(_) => true,
+                    AnyRedactedSyncMessageEvent::KeyVerificationAccept(_) => true,
+                    AnyRedactedSyncMessageEvent::KeyVerificationKey(_) => true,
+                    AnyRedactedSyncMessageEvent::KeyVerificationMac(_) => true,
+                    AnyRedactedSyncMessageEvent::KeyVerificationDone(_) => true,
+                    AnyRedactedSyncMessageEvent::RoomEncrypted(_) => true,
+                    AnyRedactedSyncMessageEvent::RoomMessageFeedback(_) => true,
+                    AnyRedactedSyncMessageEvent::RoomRedaction(_) => true,
+                    AnyRedactedSyncMessageEvent::Sticker(_) => true,
+                    _ => false,
+                },
+                AnySyncRoomEvent::RedactedState(state) => match state {
+                    AnyRedactedSyncStateEvent::PolicyRuleRoom(_) => true,
+                    AnyRedactedSyncStateEvent::PolicyRuleServer(_) => true,
+                    AnyRedactedSyncStateEvent::PolicyRuleUser(_) => true,
+                    AnyRedactedSyncStateEvent::RoomAliases(_) => true,
+                    AnyRedactedSyncStateEvent::RoomAvatar(_) => true,
+                    AnyRedactedSyncStateEvent::RoomCanonicalAlias(_) => true,
+                    AnyRedactedSyncStateEvent::RoomEncryption(_) => true,
+                    AnyRedactedSyncStateEvent::RoomJoinRules(_) => true,
+                    AnyRedactedSyncStateEvent::RoomName(_) => true,
+                    AnyRedactedSyncStateEvent::RoomPinnedEvents(_) => true,
+                    AnyRedactedSyncStateEvent::RoomPowerLevels(_) => true,
+                    AnyRedactedSyncStateEvent::RoomServerAcl(_) => true,
+                    AnyRedactedSyncStateEvent::RoomTopic(_) => true,
+                    _ => false,
+                },
+            }
+        } else {
+            false
         }
     }
 
@@ -353,23 +403,25 @@ impl Event {
     }
 
     pub fn can_hide_header(&self) -> bool {
-        let priv_ = imp::Event::from_instance(&self);
-
-        match &*priv_.event.get().unwrap().borrow() {
-            AnyRoomEvent::Message(ref message) => match message.content() {
-                AnyMessageEventContent::RoomMessage(message) => match message.msgtype {
-                    MessageType::Audio(_) => true,
-                    MessageType::File(_) => true,
-                    MessageType::Image(_) => true,
-                    MessageType::Location(_) => true,
-                    MessageType::Notice(_) => true,
-                    MessageType::Text(_) => true,
-                    MessageType::Video(_) => true,
+        if let Some(event) = self.matrix_event() {
+            match event {
+                AnySyncRoomEvent::Message(ref message) => match message.content() {
+                    AnyMessageEventContent::RoomMessage(message) => match message.msgtype {
+                        MessageType::Audio(_) => true,
+                        MessageType::File(_) => true,
+                        MessageType::Image(_) => true,
+                        MessageType::Location(_) => true,
+                        MessageType::Notice(_) => true,
+                        MessageType::Text(_) => true,
+                        MessageType::Video(_) => true,
+                        _ => false,
+                    },
                     _ => false,
                 },
                 _ => false,
-            },
-            _ => false,
+            }
+        } else {
+            false
         }
     }
 
diff --git a/src/session/room/item.rs b/src/session/room/item.rs
index 08b4d69b..dd695908 100644
--- a/src/session/room/item.rs
+++ b/src/session/room/item.rs
@@ -1,6 +1,6 @@
 use gtk::{glib, glib::DateTime, prelude::*, subclass::prelude::*};
 use matrix_sdk::ruma::{
-    events::AnyRoomEvent,
+    events::AnySyncRoomEvent,
     identifiers::{EventId, UserId},
 };
 
@@ -115,7 +115,7 @@ glib::wrapper! {
 }
 
 /// This represents any row inside the room history.
-/// This can be AnyRoomEvent, a day divider or new message divider.
+/// This can be AnySyncRoomEvent, a day divider or new message divider.
 impl Item {
     pub fn for_event(event: Event) -> Self {
         let type_ = BoxedItemType(ItemType::Event(event));
@@ -141,10 +141,10 @@ impl Item {
         }
     }
 
-    pub fn matrix_event(&self) -> Option<AnyRoomEvent> {
+    pub fn matrix_event(&self) -> Option<AnySyncRoomEvent> {
         let priv_ = imp::Item::from_instance(&self);
         if let ItemType::Event(event) = priv_.type_.get().unwrap() {
-            Some(event.matrix_event())
+            event.matrix_event()
         } else {
             None
         }
diff --git a/src/session/room/room.rs b/src/session/room/room.rs
index 78e91b7c..638e14f9 100644
--- a/src/session/room/room.rs
+++ b/src/session/room/room.rs
@@ -7,7 +7,6 @@ use matrix_sdk::{
     ruma::{
         api::client::r0::sync::sync_events::InvitedRoom,
         events::{
-            exports::serde::de::DeserializeOwned,
             room::{
                 member::{MemberEventContent, MembershipState},
                 message::{
@@ -16,8 +15,8 @@ use matrix_sdk::{
                 },
             },
             tag::TagName,
-            AnyMessageEvent, AnyRoomAccountDataEvent, AnyRoomEvent, AnyStateEvent,
-            AnyStrippedStateEvent, AnySyncRoomEvent, MessageEvent, StateEvent, Unsigned,
+            AnyRoomAccountDataEvent, AnyStrippedStateEvent, AnySyncMessageEvent, AnySyncRoomEvent,
+            AnySyncStateEvent, SyncMessageEvent, SyncStateEvent, Unsigned,
         },
         identifiers::{EventId, RoomId, UserId},
         serde::Raw,
@@ -26,13 +25,13 @@ use matrix_sdk::{
     uuid::Uuid,
     RoomMember,
 };
+use serde_json::value::RawValue;
 use std::cell::RefCell;
 use std::convert::TryFrom;
 
 use crate::components::{LabelWithWidgets, Pill};
-use crate::event_from_sync_event;
 use crate::session::{
-    room::{HighlightFlags, RoomType, Timeline},
+    room::{Event, HighlightFlags, RoomType, Timeline},
     Avatar, Session, User,
 };
 use crate::utils::do_async;
@@ -539,28 +538,30 @@ impl Room {
     }
 
     /// Add new events to the timeline
-    pub fn append_events<T: DeserializeOwned>(&self, batch: Vec<(AnyRoomEvent, Raw<T>)>) {
+    pub fn append_events(&self, batch: Vec<Event>) {
         let priv_ = imp::Room::from_instance(self);
 
         //FIXME: notify only when the count has changed
         self.notify_notification_count();
 
-        for (event, _) in batch.iter() {
-            match event {
-                AnyRoomEvent::State(AnyStateEvent::RoomMember(ref event)) => {
-                    self.update_member_for_member_event(event)
-                }
-                AnyRoomEvent::State(AnyStateEvent::RoomAvatar(event)) => {
-                    self.avatar().set_url(event.content.url.to_owned());
-                }
-                AnyRoomEvent::State(AnyStateEvent::RoomName(_)) => {
-                    // FIXME: this doesn't take into account changes in the calculated name
-                    self.load_display_name()
-                }
-                AnyRoomEvent::State(AnyStateEvent::RoomTopic(_)) => {
-                    self.notify("topic");
+        for event in &batch {
+            if let Some(event) = event.matrix_event() {
+                match event {
+                    AnySyncRoomEvent::State(AnySyncStateEvent::RoomMember(ref event)) => {
+                        self.update_member_for_member_event(event)
+                    }
+                    AnySyncRoomEvent::State(AnySyncStateEvent::RoomAvatar(event)) => {
+                        self.avatar().set_url(event.content.url.to_owned());
+                    }
+                    AnySyncRoomEvent::State(AnySyncStateEvent::RoomName(_)) => {
+                        // FIXME: this doesn't take into account changes in the calculated name
+                        self.load_display_name()
+                    }
+                    AnySyncRoomEvent::State(AnySyncStateEvent::RoomTopic(_)) => {
+                        self.notify("topic");
+                    }
+                    _ => {}
                 }
-                _ => {}
             }
         }
 
@@ -583,7 +584,7 @@ impl Room {
     }
 
     /// Updates a room member based on the room member state event
-    fn update_member_for_member_event(&self, event: &StateEvent<MemberEventContent>) {
+    fn update_member_for_member_event(&self, event: &SyncStateEvent<MemberEventContent>) {
         let priv_ = imp::Room::from_instance(self);
         let mut room_members = priv_.room_members.borrow_mut();
         let user_id = &event.sender;
@@ -636,49 +637,46 @@ impl Room {
     }
 
     pub fn send_text_message(&self, body: &str, markdown_enabled: bool) {
-        if let MatrixRoom::Joined(matrix_room) = self.matrix_room() {
-            let content = if let Some(body) = body.strip_prefix("/me ") {
-                let emote = if markdown_enabled {
-                    EmoteMessageEventContent::markdown(body)
-                } else {
-                    EmoteMessageEventContent::plain(body)
-                };
-                MessageEventContent::new(MessageType::Emote(emote))
+        let content = if let Some(body) = body.strip_prefix("/me ") {
+            let emote = if markdown_enabled {
+                EmoteMessageEventContent::markdown(body)
             } else {
-                let text = if markdown_enabled {
-                    TextMessageEventContent::markdown(body)
-                } else {
-                    TextMessageEventContent::plain(body)
-                };
-                MessageEventContent::new(MessageType::Text(text))
+                EmoteMessageEventContent::plain(body)
+            };
+            MessageEventContent::new(MessageType::Emote(emote))
+        } else {
+            let text = if markdown_enabled {
+                TextMessageEventContent::markdown(body)
+            } else {
+                TextMessageEventContent::plain(body)
             };
+            MessageEventContent::new(MessageType::Text(text))
+        };
 
-            let txn_id = Uuid::new_v4();
+        let txn_id = Uuid::new_v4();
 
-            let pending_event = AnyMessageEvent::RoomMessage(MessageEvent {
-                content,
-                event_id: EventId::try_from(format!("${}:fractal.gnome.org", txn_id)).unwrap(),
-                sender: self.session().user().user_id().clone(),
-                origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
-                room_id: matrix_room.room_id().clone(),
-                unsigned: Unsigned::default(),
-            });
+        let pending_event = AnySyncMessageEvent::RoomMessage(SyncMessageEvent {
+            content,
+            event_id: EventId::try_from(format!("${}:fractal.gnome.org", txn_id)).unwrap(),
+            sender: self.session().user().user_id().clone(),
+            origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
+            unsigned: Unsigned::default(),
+        });
 
-            self.send_message(txn_id, pending_event);
-        }
+        self.send_message(txn_id, pending_event);
     }
 
-    pub fn send_message(&self, txn_id: Uuid, event: AnyMessageEvent) {
+    pub fn send_message(&self, txn_id: Uuid, event: AnySyncMessageEvent) {
         let priv_ = imp::Room::from_instance(self);
         let content = event.content();
 
         if let MatrixRoom::Joined(matrix_room) = self.matrix_room() {
             let pending_id = event.event_id().clone();
-            priv_
-                .timeline
-                .get()
-                .unwrap()
-                .append_pending(AnyRoomEvent::Message(event));
+            let json = serde_json::to_string(&AnySyncRoomEvent::Message(event)).unwrap();
+            let raw_event: Raw<AnySyncRoomEvent> =
+                Raw::from_json(RawValue::from_string(json).unwrap());
+            let event = Event::new(raw_event.into(), self);
+            priv_.timeline.get().unwrap().append_pending(event);
 
             do_async(
                 glib::PRIORITY_DEFAULT_IDLE,
@@ -686,10 +684,7 @@ impl Room {
                 clone!(@weak self as obj => move |result| async move {
                     // FIXME: We should retry the request if it fails
                     match result {
-                            Ok(result) => {
-                                    let priv_ = imp::Room::from_instance(&obj);
-                                    priv_.timeline.get().unwrap().set_event_id_for_pending(pending_id, 
result.event_id)
-                            },
+                            Ok(result) => obj.timeline().set_event_id_for_pending(pending_id, 
result.event_id),
                             Err(error) => error!("Couldn’t send message: {}", error),
                     };
                 }),
@@ -760,22 +755,12 @@ impl Room {
     pub fn handle_left_response(&self, response_room: LeftRoom) {
         self.set_matrix_room(self.session().client().get_room(self.room_id()).unwrap());
 
-        let room_id = self.room_id();
-
         self.append_events(
             response_room
                 .timeline
                 .events
                 .into_iter()
-                .filter_map(|raw_event| {
-                    if let Ok(event) = raw_event.event.deserialize() {
-                        Some((event, raw_event.event))
-                    } else {
-                        error!("Couldn’t deserialize event: {:?}", raw_event);
-                        None
-                    }
-                })
-                .map(|(event, source)| (event_from_sync_event!(event, room_id), source))
+                .map(|event| Event::new(event, self))
                 .collect(),
         );
     }
@@ -792,22 +777,12 @@ impl Room {
             self.load_category();
         }
 
-        let room_id = self.room_id();
-
         self.append_events(
             response_room
                 .timeline
                 .events
                 .into_iter()
-                .filter_map(|raw_event| {
-                    if let Ok(event) = raw_event.event.deserialize() {
-                        Some((event, raw_event.event))
-                    } else {
-                        error!("Couldn’t deserialize event: {:?}", raw_event);
-                        None
-                    }
-                })
-                .map(|(event, source)| (event_from_sync_event!(event, room_id), source))
+                .map(|event| Event::new(event, self))
                 .collect(),
         );
     }
diff --git a/src/session/room/timeline.rs b/src/session/room/timeline.rs
index 9206dfea..43298ad8 100644
--- a/src/session/room/timeline.rs
+++ b/src/session/room/timeline.rs
@@ -1,12 +1,6 @@
 use gtk::{gio, glib, prelude::*, subclass::prelude::*};
-use matrix_sdk::ruma::{
-    events::{exports::serde::de::DeserializeOwned, AnyRoomEvent},
-    identifiers::EventId,
-    serde::Raw,
-};
-use serde_json::{to_string_pretty as to_json_string_pretty, to_value as to_json_value};
-
-use crate::fn_event;
+use matrix_sdk::ruma::identifiers::EventId;
+
 use crate::session::room::{Event, Item, Room};
 
 mod imp {
@@ -268,7 +262,7 @@ impl Timeline {
 
     /// Append the new events
     // TODO: This should be lazy, for inspiration see: 
https://blogs.gnome.org/ebassi/documentation/lazy-loading/
-    pub fn append<T: DeserializeOwned>(&self, batch: Vec<(AnyRoomEvent, Raw<T>)>) {
+    pub fn append(&self, batch: Vec<Event>) {
         let priv_ = imp::Timeline::from_instance(self);
 
         if batch.is_empty() {
@@ -286,24 +280,22 @@ impl Timeline {
 
             let mut pending_events = priv_.pending_events.borrow_mut();
 
-            for (event, raw) in batch.into_iter() {
-                let event_id = fn_event!(event, event_id).clone();
-                let user = self.room().member_by_id(fn_event!(event, sender));
-                let source = to_json_value(raw.into_json())
-                    .and_then(|v| to_json_string_pretty(&v))
-                    .unwrap();
+            for event in batch.into_iter() {
+                let event_id = event.matrix_event_id();
 
                 if let Some(pending_id) = pending_events.remove(&event_id) {
-                    if let Some(event_obj) = priv_.event_map.borrow_mut().remove(&pending_id) {
-                        event_obj.set_matrix_event(event);
-                        event_obj.set_source(Some(source));
-                        priv_.event_map.borrow_mut().insert(event_id, event_obj);
-                    }
+                    let mut event_map = priv_.event_map.borrow_mut();
+
+                    if let Some(pending_event) = event_map.remove(&pending_id) {
+                        pending_event.set_matrix_pure_event(event.matrix_pure_event());
+                        event_map.insert(event_id, pending_event);
+                    };
                     added -= 1;
                 } else {
-                    let event = Event::new(&event, &source, &user);
-
-                    priv_.event_map.borrow_mut().insert(event_id, event.clone());
+                    priv_
+                        .event_map
+                        .borrow_mut()
+                        .insert(event_id.to_owned(), event.clone());
                     if event.is_hidden_event() {
                         self.add_hidden_event(event);
                         added -= 1;
@@ -320,17 +312,18 @@ impl Timeline {
     }
 
     /// Append an event that wasn't yet fully sent and received via a sync
-    pub fn append_pending(&self, event: AnyRoomEvent) {
+    pub fn append_pending(&self, event: Event) {
         let priv_ = imp::Timeline::from_instance(self);
 
+        priv_
+            .event_map
+            .borrow_mut()
+            .insert(event.matrix_event_id(), event.clone());
+
         let index = {
             let mut list = priv_.list.borrow_mut();
             let index = list.len();
 
-            let user = self.room().member_by_id(fn_event!(event, sender));
-            let source = to_json_string_pretty(&event).unwrap();
-            let event = Event::new(&event, &source, &user);
-
             if event.is_hidden_event() {
                 self.add_hidden_event(event);
                 None
@@ -363,7 +356,7 @@ impl Timeline {
 
     /// Prepends a batch of events
     // TODO: This should be lazy, see: https://blogs.gnome.org/ebassi/documentation/lazy-loading/
-    pub fn prepend<T: DeserializeOwned>(&self, batch: Vec<(AnyRoomEvent, Raw<T>)>) {
+    pub fn prepend(&self, batch: Vec<Event>) {
         let priv_ = imp::Timeline::from_instance(self);
         let mut added = batch.len();
 
@@ -371,15 +364,11 @@ impl Timeline {
             // Extend the size of the list so that rust doesn't need to reallocate memory multiple times
             priv_.list.borrow_mut().reserve(added);
 
-            for (event, raw) in batch {
-                let user = self.room().member_by_id(fn_event!(event, sender));
-                let event_id = fn_event!(event, event_id).clone();
-                let source = to_json_value(raw.into_json())
-                    .and_then(|v| to_json_string_pretty(&v))
-                    .unwrap();
-                let event = Event::new(&event, &source, &user);
-
-                priv_.event_map.borrow_mut().insert(event_id, event.clone());
+            for event in batch {
+                priv_
+                    .event_map
+                    .borrow_mut()
+                    .insert(event.matrix_event_id(), event.clone());
 
                 if event.is_hidden_event() {
                     self.add_hidden_event(event);
diff --git a/src/session/user.rs b/src/session/user.rs
index 3e75d374..c5ecb3a8 100644
--- a/src/session/user.rs
+++ b/src/session/user.rs
@@ -3,7 +3,7 @@ use gtk::{glib, prelude::*, subclass::prelude::*};
 use crate::session::Session;
 use matrix_sdk::{
     ruma::{
-        events::{room::member::MemberEventContent, StateEvent, StrippedStateEvent},
+        events::{room::member::MemberEventContent, StrippedStateEvent, SyncStateEvent},
         identifiers::UserId,
     },
     RoomMember,
@@ -181,7 +181,7 @@ impl User {
     }
 
     /// Update the user based on the the room member state event
-    pub fn update_from_member_event(&self, event: &StateEvent<MemberEventContent>) {
+    pub fn update_from_member_event(&self, event: &SyncStateEvent<MemberEventContent>) {
         let changed = {
             let priv_ = imp::User::from_instance(&self);
             let user_id = priv_.user_id.get().unwrap();


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]