[fractal/fractal-next] session: Add dialog to view an Event's source



commit 3b538164ef5b504c7acc0b342ea5b2324428a0f0
Author: Kévin Commaille <zecakeh tedomum fr>
Date:   Fri May 28 11:26:16 2021 +0200

    session: Add dialog to view an Event's source

 data/resources/resources.gresource.xml   |   1 +
 data/resources/style.css                 |  10 ++-
 data/resources/ui/event-source-dialog.ui |  51 ++++++++++++++
 po/POTFILES.in                           |   1 +
 src/meson.build                          |   1 +
 src/session/content/item_row.rs          |   1 +
 src/session/event_source_dialog.rs       | 114 +++++++++++++++++++++++++++++++
 src/session/mod.rs                       |   1 +
 8 files changed, 178 insertions(+), 2 deletions(-)
---
diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml
index 3355c92b..b38a6083 100644
--- a/data/resources/resources.gresource.xml
+++ b/data/resources/resources.gresource.xml
@@ -11,6 +11,7 @@
     <file compressed="true" preprocess="xml-stripblanks" 
alias="content-state-row.ui">ui/content-state-row.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" 
alias="content-markdown-popover.ui">ui/content-markdown-popover.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" 
alias="content-invite.ui">ui/content-invite.ui</file>
+    <file compressed="true" preprocess="xml-stripblanks" 
alias="event-source-dialog.ui">ui/event-source-dialog.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" alias="login.ui">ui/login.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" alias="session.ui">ui/session.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" alias="sidebar.ui">ui/sidebar.ui</file>
diff --git a/data/resources/style.css b/data/resources/style.css
index 8eedf99e..a92cde49 100644
--- a/data/resources/style.css
+++ b/data/resources/style.css
@@ -25,8 +25,8 @@
 
 /* Session */
 .session-loading-spinner {
- min-width: 32px;
- min-height: 32px;
+  min-width: 32px;
+  min-height: 32px;
 }
 
 headerbar.flat {
@@ -158,3 +158,9 @@ headerbar.flat {
   border-radius: 9999px;
   padding-left: 24px;
 }
+
+/* Event Source Dialog */
+.event-source-dialog .sourceview {
+  background-color: @theme_base_color;
+  padding: 6px;
+}
diff --git a/data/resources/ui/event-source-dialog.ui b/data/resources/ui/event-source-dialog.ui
new file mode 100644
index 00000000..dcd304c4
--- /dev/null
+++ b/data/resources/ui/event-source-dialog.ui
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="EventSourceDialog" parent="AdwWindow">
+    <property name="modal">True</property>
+    <property name="title" translatable="yes">Event Source</property>
+    <property name="destroy-with-parent">True</property>
+    <property name="default-width">500</property>
+    <property name="default-height">300</property>
+    <child>
+      <object class="GtkBox">
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkHeaderBar">
+            <child type="start">
+              <object class="GtkButton">
+                <property name="icon-name">edit-copy-symbolic</property>
+                <property name="focus-on-click">False</property>
+                <property name="action-name">event-source-dialog.copy</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkScrolledWindow">
+            <style>
+              <class name="event-source-dialog"/>
+            </style>
+            <property name="child">
+              <object class="GtkSourceView" id="source_view">
+                <property name="can_focus">False</property>
+                <property name="editable">False</property>
+                <property name="hexpand">True</property>
+                <property name="vexpand">True</property>
+                <property name="wrap_mode">word-char</property>
+                <property name="buffer">
+                  <object class="GtkSourceBuffer">
+                    <binding name="text">
+                      <lookup name="source">
+                        <lookup name="event">EventSourceDialog</lookup>
+                      </lookup>
+                    </binding>
+                  </object>
+                </property>
+              </object>
+            </property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 93ff03cc..2d43d112 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -15,6 +15,7 @@ data/resources/ui/content-room-history.ui
 data/resources/ui/content-state-row.ui
 data/resources/ui/content.ui
 data/resources/ui/context-menu-bin.ui
+data/resources/ui/event-source-dialog.ui
 data/resources/ui/login.ui
 data/resources/ui/in-app-notification.ui
 data/resources/ui/session.ui
diff --git a/src/meson.build b/src/meson.build
index e149e2bc..bfd51e20 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -33,6 +33,7 @@ sources = files(
   'login.rs',
   'secret.rs',
   'utils.rs',
+  'session/event_source_dialog.rs',
   'session/user.rs',
   'session/mod.rs',
   'session/categories/categories.rs',
diff --git a/src/session/content/item_row.rs b/src/session/content/item_row.rs
index b728d29c..030c5a27 100644
--- a/src/session/content/item_row.rs
+++ b/src/session/content/item_row.rs
@@ -4,6 +4,7 @@ use gtk::{gio, glib, 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::events::AnyRoomEvent;
 
diff --git a/src/session/event_source_dialog.rs b/src/session/event_source_dialog.rs
new file mode 100644
index 00000000..fe7d5f1f
--- /dev/null
+++ b/src/session/event_source_dialog.rs
@@ -0,0 +1,114 @@
+use crate::session::room::Event;
+use adw::subclass::prelude::*;
+use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate};
+use sourceview::prelude::*;
+
+mod imp {
+    use super::*;
+    use glib::subclass::InitializingObject;
+    use once_cell::unsync::OnceCell;
+
+    #[derive(Debug, Default, CompositeTemplate)]
+    #[template(resource = "/org/gnome/FractalNext/event-source-dialog.ui")]
+    pub struct EventSourceDialog {
+        pub event: OnceCell<Event>,
+        #[template_child]
+        pub source_view: TemplateChild<sourceview::View>,
+    }
+
+    #[glib::object_subclass]
+    impl ObjectSubclass for EventSourceDialog {
+        const NAME: &'static str = "EventSourceDialog";
+        type Type = super::EventSourceDialog;
+        type ParentType = adw::Window;
+
+        fn class_init(klass: &mut Self::Class) {
+            Self::bind_template(klass);
+            klass.install_action("event-source-dialog.copy", None, move |widget, _, _| {
+                widget.copy_to_clipboard();
+            });
+        }
+
+        fn instance_init(obj: &InitializingObject<Self>) {
+            obj.init_template();
+        }
+    }
+
+    impl ObjectImpl for EventSourceDialog {
+        fn properties() -> &'static [glib::ParamSpec] {
+            use once_cell::sync::Lazy;
+            static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+                vec![glib::ParamSpec::new_object(
+                    "event",
+                    "Event",
+                    "The event that is displayed in the Dialog",
+                    Event::static_type(),
+                    glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
+                )]
+            });
+
+            PROPERTIES.as_ref()
+        }
+
+        fn set_property(
+            &self,
+            _obj: &Self::Type,
+            _id: usize,
+            value: &glib::Value,
+            pspec: &glib::ParamSpec,
+        ) {
+            match pspec.name() {
+                "event" => {
+                    let event = value.get().unwrap();
+                    let _ = self.event.set(event);
+                }
+                _ => unimplemented!(),
+            }
+        }
+
+        fn property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+            match pspec.name() {
+                "event" => self.event.get().to_value(),
+                _ => unimplemented!(),
+            }
+        }
+
+        fn constructed(&self, obj: &Self::Type) {
+            let buffer = self
+                .source_view
+                .buffer()
+                .downcast::<sourceview::Buffer>()
+                .unwrap();
+
+            let md_lang = sourceview::LanguageManager::default().and_then(|lm| lm.language("json"));
+            buffer.set_language(md_lang.as_ref());
+
+            self.parent_constructed(obj);
+        }
+    }
+
+    impl WidgetImpl for EventSourceDialog {}
+    impl WindowImpl for EventSourceDialog {}
+    impl AdwWindowImpl for EventSourceDialog {}
+}
+
+glib::wrapper! {
+    pub struct EventSourceDialog(ObjectSubclass<imp::EventSourceDialog>)
+        @extends gtk::Widget, gtk::Window, adw::Window, @implements gtk::Accessible;
+}
+
+impl EventSourceDialog {
+    pub fn new(window: &gtk::Window, event: &Event) -> Self {
+        glib::Object::new(&[("transient-for", window), ("event", event)])
+            .expect("Failed to create EventSourceDialog")
+    }
+
+    pub fn copy_to_clipboard(&self) {
+        let priv_ = imp::EventSourceDialog::from_instance(self);
+
+        let clipboard = self.clipboard();
+        let buffer = priv_.source_view.buffer();
+        let (start_iter, end_iter) = buffer.bounds();
+        clipboard.set_text(buffer.text(&start_iter, &end_iter, true).as_ref());
+    }
+}
diff --git a/src/session/mod.rs b/src/session/mod.rs
index abf65411..4a183df4 100644
--- a/src/session/mod.rs
+++ b/src/session/mod.rs
@@ -1,5 +1,6 @@
 mod categories;
 mod content;
+mod event_source_dialog;
 mod room;
 mod room_list;
 mod sidebar;


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