[fractal] window: Add a global paste action to paste media



commit 89b89024c93478bf37ecd2f8af5a5457213a51f4
Author: Marco Melorio <marco melorio protonmail com>
Date:   Sun Apr 17 01:56:23 2022 +0200

    window: Add a global paste action to paste media
    
    Now it's possible to paste an image even when the message entry is not focused.

 data/resources/ui/session.ui            | 10 +++++-----
 src/session/content/mod.rs              | 13 +++++++++++++
 src/session/content/room_history/mod.rs |  6 ++++++
 src/session/mod.rs                      | 18 +++++++++++-------
 src/window.rs                           | 25 ++++++++++++++++++++++++-
 5 files changed, 59 insertions(+), 13 deletions(-)
---
diff --git a/data/resources/ui/session.ui b/data/resources/ui/session.ui
index b67b69a56..f32f0348a 100644
--- a/data/resources/ui/session.ui
+++ b/data/resources/ui/session.ui
@@ -3,14 +3,14 @@
   <template class="Session" parent="AdwBin">
     <property name="child">
       <object class="GtkStack" id="stack">
-        <property name="visible-child">content</property>
+        <property name="visible-child">leaflet</property>
         <property name="transition-type">crossfade</property>
         <child>
-          <object class="AdwLeaflet" id="content">
+          <object class="AdwLeaflet" id="leaflet">
             <property name="fold-threshold-policy">minimum</property>
             <child>
               <object class="Sidebar" id="sidebar">
-                <property name="compact" bind-source="content" bind-property="folded" 
bind-flags="sync-create"/>
+                <property name="compact" bind-source="leaflet" bind-property="folded" 
bind-flags="sync-create"/>
                 <property name="user" bind-source="Session" bind-property="user" bind-flags="sync-create"/>
                 <property name="item-list" bind-source="Session" bind-property="item-list" 
bind-flags="sync-create"/>
               </object>
@@ -24,8 +24,8 @@
               </object>
             </child>
             <child>
-              <object class="Content">
-                <property name="compact" bind-source="content" bind-property="folded" 
bind-flags="sync-create"/>
+              <object class="Content" id="content">
+                <property name="compact" bind-source="leaflet" bind-property="folded" 
bind-flags="sync-create"/>
                 <property name="item" bind-source="sidebar" bind-property="selected-item" 
bind-flags="sync-create | bidirectional"/>
                 <property name="session">Session</property>
               </object>
diff --git a/src/session/content/mod.rs b/src/session/content/mod.rs
index 940a831cd..6b4fdb0b1 100644
--- a/src/session/content/mod.rs
+++ b/src/session/content/mod.rs
@@ -169,6 +169,19 @@ impl Content {
         glib::Object::new(&[("session", session)]).expect("Failed to create Content")
     }
 
+    pub fn handle_paste_action(&self) {
+        let priv_ = self.imp();
+        if priv_
+            .stack
+            .visible_child()
+            .as_ref()
+            .map(|c| c == priv_.room_history.upcast_ref::<gtk::Widget>())
+            .unwrap_or_default()
+        {
+            priv_.room_history.handle_paste_action();
+        }
+    }
+
     pub fn session(&self) -> Option<Session> {
         self.imp()
             .session
diff --git a/src/session/content/room_history/mod.rs b/src/session/content/room_history/mod.rs
index d74d28b8c..b5ea0bdc3 100644
--- a/src/session/content/room_history/mod.rs
+++ b/src/session/content/room_history/mod.rs
@@ -440,6 +440,12 @@ impl RoomHistory {
         }
     }
 
+    pub fn handle_paste_action(&self) {
+        spawn!(glib::clone!(@weak self as obj => async move {
+            obj.read_clipboard().await;
+        }));
+    }
+
     pub fn new() -> Self {
         glib::Object::new(&[]).expect("Failed to create RoomHistory")
     }
diff --git a/src/session/mod.rs b/src/session/mod.rs
index 2b8e61e96..02ec32b73 100644
--- a/src/session/mod.rs
+++ b/src/session/mod.rs
@@ -101,10 +101,12 @@ mod imp {
         #[template_child]
         pub stack: TemplateChild<gtk::Stack>,
         #[template_child]
-        pub content: TemplateChild<adw::Leaflet>,
+        pub leaflet: TemplateChild<adw::Leaflet>,
         #[template_child]
         pub sidebar: TemplateChild<Sidebar>,
         #[template_child]
+        pub content: TemplateChild<Content>,
+        #[template_child]
         pub media_viewer: TemplateChild<MediaViewer>,
         pub client: RefCell<Option<Client>>,
         pub item_list: OnceCell<ItemList>,
@@ -186,8 +188,6 @@ mod imp {
         }
 
         fn instance_init(obj: &InitializingObject<Self>) {
-            Sidebar::static_type();
-            Content::static_type();
             obj.init_template();
         }
     }
@@ -249,9 +249,9 @@ mod imp {
                     let priv_ = obj.imp();
 
                     if priv_.sidebar.selected_item().is_none() {
-                        priv_.content.navigate(adw::NavigationDirection::Back);
+                        priv_.leaflet.navigate(adw::NavigationDirection::Back);
                     } else {
-                        priv_.content.navigate(adw::NavigationDirection::Forward);
+                        priv_.leaflet.navigate(adw::NavigationDirection::Forward);
                     }
                 }),
             );
@@ -559,7 +559,7 @@ impl Session {
 
                     let handle = spawn_tokio!(async move { encryption.bootstrap_cross_signing(None).await });
                     if handle.await.is_ok() {
-                        priv_.stack.set_visible_child(&*priv_.content);
+                        priv_.stack.set_visible_child(&*priv_.leaflet);
                         if let Some(window) = obj.parent_window() {
                             window.switch_to_sessions_page();
                         }
@@ -771,6 +771,10 @@ impl Session {
         );
     }
 
+    pub fn handle_paste_action(&self) {
+        self.imp().content.handle_paste_action();
+    }
+
     async fn cleanup_session(&self) {
         let priv_ = self.imp();
         let info = priv_.info.get().unwrap();
@@ -806,7 +810,7 @@ impl Session {
         spawn!(clone!(@weak self as obj => async move {
             obj.has_cross_signing_keys().await;
         }));
-        priv_.stack.set_visible_child(&*priv_.content);
+        priv_.stack.set_visible_child(&*priv_.leaflet);
         priv_.logout_on_dispose.set(false);
         if let Some(window) = self.parent_window() {
             window.switch_to_sessions_page();
diff --git a/src/window.rs b/src/window.rs
index 3f911e4bc..b32cb8458 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -1,7 +1,7 @@
 use adw::subclass::prelude::AdwApplicationWindowImpl;
 use gettextrs::gettext;
 use glib::signal::Inhibit;
-use gtk::{self, gio, glib, glib::clone, prelude::*, subclass::prelude::*, CompositeTemplate};
+use gtk::{self, gdk, gio, glib, glib::clone, prelude::*, subclass::prelude::*, CompositeTemplate};
 use log::warn;
 
 use crate::{
@@ -48,6 +48,29 @@ mod imp {
             Toast::static_type();
             InAppNotification::static_type();
             Self::bind_template(klass);
+
+            klass.add_binding_action(
+                gdk::Key::v,
+                gdk::ModifierType::CONTROL_MASK,
+                "win.paste",
+                None,
+            );
+            klass.add_binding_action(
+                gdk::Key::Insert,
+                gdk::ModifierType::SHIFT_MASK,
+                "win.paste",
+                None,
+            );
+            klass.install_action("win.paste", None, move |widget, _, _| {
+                if let Some(session) = widget
+                    .imp()
+                    .sessions
+                    .visible_child()
+                    .and_then(|c| c.downcast::<Session>().ok())
+                {
+                    session.handle_paste_action();
+                }
+            });
         }
 
         fn instance_init(obj: &InitializingObject<Self>) {


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