[fractal] timeline: Remove event when it should be hidden after decryption



commit 0b8d78c7e38e8beb62974f74b16a266fd420358d
Author: Kévin Commaille <zecakeh tedomum fr>
Date:   Thu Sep 15 15:24:38 2022 +0200

    timeline: Remove event when it should be hidden after decryption

 src/session/room/event/supported_event.rs | 29 ++++++++++++++++++----
 src/session/room/timeline/mod.rs          | 41 +++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+), 5 deletions(-)
---
diff --git a/src/session/room/event/supported_event.rs b/src/session/room/event/supported_event.rs
index 367f55f74..ec329cec8 100644
--- a/src/session/room/event/supported_event.rs
+++ b/src/session/room/event/supported_event.rs
@@ -1,5 +1,5 @@
 use gtk::{glib, glib::clone, prelude::*, subclass::prelude::*};
-use log::debug;
+use log::{debug, error};
 use matrix_sdk::{
     deserialized_responses::SyncTimelineEvent,
     media::MediaEventContent,
@@ -25,7 +25,7 @@ use crate::{
     prelude::*,
     session::room::{
         timeline::{TimelineItem, TimelineItemImpl},
-        Member, ReactionList, Room,
+        Member, ReactionList, Room, UnsupportedEvent,
     },
     spawn, spawn_tokio,
     utils::{filename_for_mime, media_type_uid},
@@ -192,6 +192,9 @@ impl SupportedEvent {
 
     /// Set the deserialized Matrix event of this `SupportedEvent`.
     fn set_matrix_event(&self, matrix_event: AnySyncTimelineEvent) {
+        let was_hidden = self.is_hidden_event();
+        let event_id = matrix_event.event_id().to_owned();
+
         if let AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomEncrypted(
             SyncMessageLikeEvent::Original(_),
         )) = matrix_event
@@ -202,6 +205,13 @@ impl SupportedEvent {
         }
 
         self.imp().matrix_event.replace(Some(matrix_event));
+
+        // Remove the event from the timeline if is should now be hidden.
+        let is_hidden = self.is_hidden_event();
+        if !was_hidden && is_hidden {
+            self.room().timeline().remove_event(&event_id);
+        }
+
         self.notify("activatable");
     }
 
@@ -227,9 +237,18 @@ impl SupportedEvent {
                     self.room().disconnect(keys_handle);
                 }
                 let pure_event = SyncTimelineEvent::from(decrypted);
-                let matrix_event = pure_event.event.deserialize().unwrap();
-                self.set_pure_event(pure_event);
-                self.set_matrix_event(matrix_event);
+                if let Ok(matrix_event) = pure_event.event.deserialize() {
+                    self.set_pure_event(pure_event);
+                    self.set_matrix_event(matrix_event);
+                } else {
+                    error!("Couldn’t deserialize event: {:?}", pure_event.event);
+
+                    // Remove this event from the timeline.
+                    let room = self.room();
+                    let new_event = UnsupportedEvent::new(pure_event, &room);
+                    room.timeline()
+                        .replace_supported_event(self.event_id(), new_event);
+                }
             }
             Err(error) => {
                 let room_name = room.display_name();
diff --git a/src/session/room/timeline/mod.rs b/src/session/room/timeline/mod.rs
index f95ab67f8..c57414c00 100644
--- a/src/session/room/timeline/mod.rs
+++ b/src/session/room/timeline/mod.rs
@@ -746,6 +746,21 @@ impl Timeline {
         self.imp().event_map.borrow().get(event_id).cloned()
     }
 
+    /// Get the position of the event with the given id in this `Timeline`.
+    pub fn find_event_position(&self, event_id: &EventId) -> Option<usize> {
+        self.imp()
+            .list
+            .borrow()
+            .iter()
+            .enumerate()
+            .find_map(|(pos, item)| {
+                item.downcast_ref::<Event>()
+                    .and_then(|event| event.event_id())
+                    .filter(|item_event_id| item_event_id == event_id)
+                    .map(|_| pos)
+            })
+    }
+
     /// Fetch the event with the given id.
     ///
     /// If the event can't be found locally, a request will be made to the
@@ -865,6 +880,32 @@ impl Timeline {
         self.imp().list.borrow_mut().pop_front();
         self.upcast_ref::<gio::ListModel>().items_changed(0, 1, 0);
     }
+
+    /// Remove the given event from the timeline.
+    ///
+    /// This should be used when the source of an `Event` changes and it should
+    /// be hidden now.
+    pub fn remove_event(&self, event_id: &EventId) {
+        if let Some(index) = self.find_event_position(event_id) {
+            self.imp().list.borrow_mut().remove(index);
+
+            self.items_changed(index as u32, 1, 0);
+        }
+    }
+
+    /// Replace the supported event with the given ID with the given unsupported
+    /// event in this timeline.
+    ///
+    /// This should be used when the source of a `SupportedEvent` changes, and
+    /// the new source fails to deserialize.
+    pub fn replace_supported_event(&self, event_id: OwnedEventId, event: UnsupportedEvent) {
+        self.remove_event(&event_id);
+
+        self.imp()
+            .event_map
+            .borrow_mut()
+            .insert(event_id, event.upcast());
+    }
 }
 
 async fn handle_forward_stream(


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