[gnome-boxes/toast-revolution: 8/9] notifications, toasts: Replace in-app notifications with Toasts




commit 23af1e74b16b1ae48a9539f2d9fd577c0391d8b8
Author: Felipe Borges <felipeborges gnome org>
Date:   Thu Jan 20 20:04:53 2022 +0100

    notifications, toasts: Replace in-app notifications with Toasts
    
    Boxes.Toast and Boxes.ToastOverlay are our custom Toast implementation.
    We should migrate away from this once we migrate from libhandy to
    libadwaita.
    
    Fixes #95

 data/ui/app-window.ui                  |  8 +---
 data/ui/assistant/vm-assistant.ui      | 44 +++++++++--------
 data/ui/toast.ui                       |  2 +
 src/app-window.vala                    | 24 +++++-----
 src/app.vala                           | 16 ++++---
 src/assistant/vm-assistant.vala        |  4 +-
 src/downloads-hub.vala                 |  2 +-
 src/libvirt-machine.vala               | 18 +++----
 src/machine.vala                       | 38 +++++++++++----
 src/meson.build                        |  2 -
 src/notification.vala                  | 84 ---------------------------------
 src/notificationbar.vala               | 86 ----------------------------------
 src/preferences/snapshot-list-row.vala | 20 +++-----
 src/preferences/snapshots-page.vala    |  4 +-
 src/ui/toast-overlay.vala              |  6 +++
 src/ui/toast.vala                      |  5 ++
 src/unattended-installer.vala          |  2 +-
 src/vm-importer.vala                   |  5 +-
 18 files changed, 111 insertions(+), 259 deletions(-)
---
diff --git a/data/ui/app-window.ui b/data/ui/app-window.ui
index 3e1a85a6..796b9228 100644
--- a/data/ui/app-window.ui
+++ b/data/ui/app-window.ui
@@ -32,15 +32,9 @@
         </child>
 
         <child>
-          <object class="GtkOverlay" id="notification_overlay">
+          <object class="BoxesToastOverlay" id="toast_overlay">
             <property name="visible">True</property>
 
-            <child type="overlay">
-              <object class="BoxesNotificationbar" id="_notificationbar">
-                <property name="visible">True</property>
-              </object>
-            </child>
-
             <child>
               <object class="GtkStack" id="below_bin">
                 <property name="visible">True</property>
diff --git a/data/ui/assistant/vm-assistant.ui b/data/ui/assistant/vm-assistant.ui
index 579468e5..f178e100 100644
--- a/data/ui/assistant/vm-assistant.ui
+++ b/data/ui/assistant/vm-assistant.ui
@@ -14,27 +14,33 @@
         <property name="orientation">vertical</property>
 
         <child>
-          <object class="GtkStack" id="pages">
+          <object class="BoxesToastOverlay" id="toast_overlay">
             <property name="visible">True</property>
-            <signal name="notify::visible-child" handler="update_titlebar"/>
-            <child>
-              <object class="BoxesAssistantIndexPage" id="index_page">
-                <signal name="done" handler="do_preparation"/>
-              </object>
-            </child>
-            <child>
-              <object class="BoxesAssistantPreparationPage" id="preparation_page">
-                <signal name="done" handler="do_setup"/>
-              </object>
-            </child>
-            <child>
-              <object class="BoxesAssistantSetupPage" id="setup_page">
-                <signal name="done" handler="do_review"/>
-              </object>
-            </child>
+
             <child>
-              <object class="BoxesAssistantReviewPage" id="review_page">
-                <signal name="done" handler="do_create"/>
+              <object class="GtkStack" id="pages">
+                <property name="visible">True</property>
+                <signal name="notify::visible-child" handler="update_titlebar"/>
+                <child>
+                  <object class="BoxesAssistantIndexPage" id="index_page">
+                    <signal name="done" handler="do_preparation"/>
+                  </object>
+                </child>
+                <child>
+                  <object class="BoxesAssistantPreparationPage" id="preparation_page">
+                    <signal name="done" handler="do_setup"/>
+                  </object>
+                </child>
+                <child>
+                  <object class="BoxesAssistantSetupPage" id="setup_page">
+                    <signal name="done" handler="do_review"/>
+                  </object>
+                </child>
+                <child>
+                  <object class="BoxesAssistantReviewPage" id="review_page">
+                    <signal name="done" handler="do_create"/>
+                  </object>
+                </child>
               </object>
             </child>
           </object>
diff --git a/data/ui/toast.ui b/data/ui/toast.ui
index 44a5976c..73f2f957 100644
--- a/data/ui/toast.ui
+++ b/data/ui/toast.ui
@@ -3,7 +3,9 @@
   <template class="BoxesToast" parent="GtkBox">
     <property name="visible">True</property>
     <property name="can_focus">True</property>
+    <property name="halign">center</property>
     <property name="valign">end</property>
+    <property name="margin">20</property>
     <style>
       <class name="app-notification"/>
       <class name="boxes-toast"/>
diff --git a/src/app-window.vala b/src/app-window.vala
index cd012fa6..482081c0 100644
--- a/src/app-window.vala
+++ b/src/app-window.vala
@@ -56,17 +56,13 @@
     }
     private bool maximized { get { return WindowState.MAXIMIZED in get_window ().get_state (); } }
 
-    public Notificationbar notificationbar {
-        get {
-            return _notificationbar;
-        }
-    }
-
     [GtkChild]
     public unowned Searchbar searchbar;
     [GtkChild]
     public unowned Topbar topbar;
     [GtkChild]
+    public unowned Boxes.ToastOverlay toast_overlay;
+    [GtkChild]
     public unowned DisplayPage display_page;
     [GtkChild]
     public unowned Hdy.StatusPage empty_boxes;
@@ -99,9 +95,6 @@
         set { settings.set_boolean ("first-run", value); }
     }
 
-    [GtkChild]
-    private unowned Notificationbar _notificationbar;
-
     private uint configure_id;
     public const uint configure_id_timeout = 100;  // 100ms
 
@@ -155,7 +148,6 @@ public void setup_ui () {
         list_view.setup_ui (this);
         searchbar.setup_ui (this);
         troubleshoot_view.setup_ui (this);
-        notificationbar.searchbar = searchbar;
 
         group = new Gtk.WindowGroup ();
         group.add_window (this);
@@ -163,6 +155,14 @@ public void setup_ui () {
         App.app.call_when_ready (on_app_ready);
     }
 
+    public void display_toast (Boxes.Toast toast) {
+        toast_overlay.display_toast (toast);
+    }
+
+    public void dismiss_toast () {
+        toast_overlay.dismiss ();
+    }
+
     private void on_app_ready () {
         notify["ui-state"].connect (ui_state_changed);
         notify["view-type"].connect (ui_state_changed);
@@ -302,8 +302,8 @@ public void connect_to (Machine machine) {
         // Track machine status in toolbar
         status_bind = machine.bind_property ("status", topbar, "status", BindingFlags.SYNC_CREATE);
 
-        got_error_id = machine.got_error.connect ( (message) => {
-            notificationbar.display_error (message);
+        got_error_id = machine.got_error.connect ((message) => {
+            display_toast (new Boxes.Toast (message));
         });
 
         if (ui_state != UIState.CREDS)
diff --git a/src/app.vala b/src/app.vala
index 84e1e060..03dac7b5 100644
--- a/src/app.vala
+++ b/src/app.vala
@@ -299,9 +299,8 @@ public override void shutdown () {
             this.hold ();
         }
 
-        foreach (var window in windows) {
-            window.notificationbar.dismiss_all ();
-        }
+        main_window.dismiss_toast ();
+
         async_launcher.await_all ();
         suspend_machines ();
     }
@@ -578,7 +577,7 @@ public void delete_machines_undoable (owned List<CollectionItem> items,
         foreach (var item in items)
             collection.remove_item (item);
 
-        Notification.OKFunc undo = () => {
+        Toast.OKFunc undo = () => {
             debug ("Box deletion cancelled by user. Re-adding to view");
             foreach (var item in items) {
                 var machine = item as Machine;
@@ -588,7 +587,7 @@ public void delete_machines_undoable (owned List<CollectionItem> items,
                 undo_notify_callback ();
         };
 
-        Notification.DismissFunc really_remove = () => {
+        Toast.DismissFunc really_remove = () => {
             debug ("User did not cancel deletion. Deleting now...");
             foreach (var item in items) {
                 if (!(item is Machine))
@@ -600,7 +599,12 @@ public void delete_machines_undoable (owned List<CollectionItem> items,
             }
         };
 
-        main_window.notificationbar.display_for_action (msg, _("_Undo"), (owned) undo, (owned) 
really_remove);
+        main_window.display_toast (new Boxes.Toast () {
+            message = msg,
+            action = _("Undo"),
+            undo_func = (owned) undo,
+            dismiss_func = (owned) really_remove,
+        });
     }
 
     public AppWindow add_new_window () {
diff --git a/src/assistant/vm-assistant.vala b/src/assistant/vm-assistant.vala
index 73f474b9..61f17095 100644
--- a/src/assistant/vm-assistant.vala
+++ b/src/assistant/vm-assistant.vala
@@ -3,6 +3,8 @@
 
 [GtkTemplate (ui = "/org/gnome/Boxes/ui/assistant/vm-assistant.ui")]
 private class Boxes.VMAssistant : Gtk.Dialog {
+    [GtkChild]
+    private unowned Boxes.ToastOverlay toast_overlay;
     [GtkChild]
     private unowned Stack pages;
     [GtkChild]
@@ -58,7 +60,7 @@ private async void prepare_for_path (string path) {
             debug("Failed to analyze installer image: %s", error.message);
 
             var msg = _("Failed to analyze installer media. Corrupted or incomplete media?");
-            App.app.main_window.notificationbar.display_error (msg);
+            toast_overlay.display_toast (new Boxes.Toast (msg));
         }
     }
 
diff --git a/src/downloads-hub.vala b/src/downloads-hub.vala
index 7faac266..df05631c 100644
--- a/src/downloads-hub.vala
+++ b/src/downloads-hub.vala
@@ -183,7 +183,7 @@ private async void download (string url, string filename) {
             local_file = yield Downloader.fetch_media (url, filename, progress, cancellable);
         } catch (IOError.CANCELLED cancel_error) { // We did this, so ignore!
         } catch (GLib.Error error) {
-            App.app.main_window.notificationbar.display_error (_("Failed to download"));
+            App.app.main_window.display_toast (new Boxes.Toast (_("Failed to download: %s").printf 
(error.message)));
 
             warning (error.message);
             return;
diff --git a/src/libvirt-machine.vala b/src/libvirt-machine.vala
index fae61071..642c60a0 100644
--- a/src/libvirt-machine.vala
+++ b/src/libvirt-machine.vala
@@ -510,7 +510,6 @@ public override void restart () {
 
         stay_on_display = true;
         ulong state_id = 0;
-        Boxes.Notification notification = null;
         debug ("Rebooting '%s'..", name);
 
         state_id = notify["state"].connect (() => {
@@ -530,26 +529,21 @@ public override void restart () {
                     Source.remove (shutdown_timeout);
                     shutdown_timeout = 0;
                 }
-                if (notification != null) {
-                    notification.dismiss ();
-                    notification = null;
-                }
             }
         });
 
         shutdown_timeout = Timeout.add_seconds (5, () => {
             // Seems guest ignored ACPI shutdown, lets force shutdown with user's consent
-            Notification.OKFunc really_force_shutdown = () => {
-                notification = null;
+            Toast.OKFunc really_force_shutdown = () => {
                 force_shutdown ();
             };
 
             var message = _("Restart of “%s” is taking too long. Force it to shutdown?").printf (name);
-            notification = window.notificationbar.display_for_action (message,
-                                                                       _("_Shutdown"),
-                                                                       (owned) really_force_shutdown,
-                                                                       null,
-                                                                       -1);
+            window.display_toast (new Boxes.Toast () {
+                message = message,
+                action = _("Shutdown"),
+                undo_func = (owned) really_force_shutdown
+            });
             shutdown_timeout = 0;
 
             return false;
diff --git a/src/machine.vala b/src/machine.vala
index f8b81d07..de495b88 100644
--- a/src/machine.vala
+++ b/src/machine.vala
@@ -203,8 +203,10 @@ protected void show_display () {
                     if (!stay_on_display && window.current_item == this)
                         window.set_state (Boxes.UIState.COLLECTION);
 
-                    if (failed)
-                        window.notificationbar.display_error (_("Connection to “%s” failed").printf (name));
+                    if (failed) {
+                        string message = _("Connection to “%s” failed").printf (name);
+                        window.display_toast (new Boxes.Toast (message));
+                    }
                 }
 
                 load_screenshot ();
@@ -584,12 +586,20 @@ private async void try_connect_display (ConnectFlags flags = ConnectFlags.NONE)
         try {
             yield connect_display (flags);
         } catch (Boxes.Error.RESTORE_FAILED e) {
-            var message = _("“%s” could not be restored from disk\nTry without saved state?").printf (name);
-            var notification = window.notificationbar.display_for_action (message, _("Restart"), () => {
+            Toast.OKFunc restart_func = () => {
                 try_connect_display.begin (flags | Machine.ConnectFlags.IGNORE_SAVED_STATE);
-            });
-            notification.dismissed.connect (() => {
+            };
+            Toast.DismissFunc dismiss_func = () => {
                 window.set_state (UIState.COLLECTION);
+            };
+
+            // Translators: The first %s is the name of the box, the second is the reason of the error
+            var message = _("“%s” could not be restored from disk: %s").printf (name, e.message);
+            window.display_toast (new Boxes.Toast () {
+                message = message,
+                action = _("Restart"),
+                undo_func = (owned) restart_func,
+                dismiss_func = (owned) dismiss_func
             });
         } catch (Boxes.Error.START_FAILED e) {
             warning ("Failed to start %s: %s", name, e.message);
@@ -597,7 +607,7 @@ private async void try_connect_display (ConnectFlags flags = ConnectFlags.NONE)
 
             var msg = _("Failed to start “%s”").printf (name);
             if (this is LibvirtMachine) {
-                Notification.OKFunc troubleshoot = () => {
+                Toast.OKFunc troubleshoot = () => {
                     window.current_item = this;
 
                     var preferences = new PreferencesWindow () {
@@ -608,14 +618,22 @@ private async void try_connect_display (ConnectFlags flags = ConnectFlags.NONE)
                     preferences.show_troubleshoot_logs ();
                 };
 
-                window.notificationbar.display_for_action (msg, _("Troubleshooting Log"), (owned) 
troubleshoot, null);
+                window.display_toast (new Boxes.Toast () {
+                    message = msg,
+                    action = _("Troubleshooting Log"),
+                    undo_func = (owned) troubleshoot
+                });
             } else {
-                window.notificationbar.display_error (msg);
+                window.display_toast (new Boxes.Toast (msg));
             }
         } catch (GLib.Error e) {
             warning ("Failed to connect to %s: %s", name, e.message);
             window.set_state (UIState.COLLECTION);
-            window.notificationbar.display_error (_("Connection to “%s” failed").printf (name));
+
+            // Translators: the first %s is the name of the box, the second is the reason of the error.
+            var message = _("Connection to “%s” failed: %s").printf (name, e.message);
+
+            window.display_toast (new Boxes.Toast (message));
         }
     }
 
diff --git a/src/meson.build b/src/meson.build
index 26e1b5dc..e4b913da 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -68,8 +68,6 @@ vala_sources = [
   'machine.vala',
   'main.vala',
   'media-manager.vala',
-  'notification.vala',
-  'notificationbar.vala',
   'os-database.vala',
   'portals.vala',
   'search.vala',
diff --git a/src/preferences/snapshot-list-row.vala b/src/preferences/snapshot-list-row.vala
index 407e1a55..3d9b6931 100644
--- a/src/preferences/snapshot-list-row.vala
+++ b/src/preferences/snapshot-list-row.vala
@@ -45,9 +45,7 @@ public SnapshotListRow (GVir.DomainSnapshot snapshot,
         } catch (GLib.Error e) {
             critical (e.message);
 
-            display_toast (new Boxes.Toast () {
-                message = e.message
-            });
+            display_toast (new Boxes.Toast (e.message));
         }
     }
 
@@ -75,10 +73,8 @@ private void on_save_name_button_clicked () {
         } catch (GLib.Error e) {
             warning ("Failed to rename snapshot to %s: %s", name, e.message);
 
-            display_toast (new Boxes.Toast () {
-                // Translators: %s is the reason why Boxes failed to rename the snapshot.
-                message = _("Failed to rename snapshot: %s").printf (e.message)
-            });
+            // Translators: %s is the reason why Boxes failed to rename the snapshot.
+            display_toast (new Boxes.Toast (_("Failed to rename snapshot: %s").printf (e.message)));
         }
     }
 
@@ -115,10 +111,8 @@ private void on_revert_button_clicked () {
             } catch (GLib.Error e) {
                 warning (e.message);
 
-                display_toast (new Boxes.Toast () {
-                    // Translators: %s is the reason why Boxes failed to apply the snapshot.
-                    message = _("Failed to revert to snapshot: %s").printf (e.message)
-                });
+                // Translators: %s is the reason why Boxes failed to apply the snapshot.
+                display_toast (new Boxes.Toast (_("Failed to revert to snapshot: %s").printf (e.message)));
             }
             activity_message = null;
         });
@@ -141,12 +135,12 @@ private void on_delete_button_clicked () {
         var row = this;
         parent_container.remove (this);
 
-        Notification.OKFunc undo = () => {
+        Toast.OKFunc undo = () => {
             parent_container.add (this);
             row = null;
         };
 
-        Notification.DismissFunc really_remove = () => {
+        Toast.DismissFunc really_remove = () => {
             this.snapshot.delete_async.begin (0, null, (obj, res) =>{
                 try {
                     this.snapshot.delete_async.end (res);
diff --git a/src/preferences/snapshots-page.vala b/src/preferences/snapshots-page.vala
index 9f0438fe..10060cdd 100644
--- a/src/preferences/snapshots-page.vala
+++ b/src/preferences/snapshots-page.vala
@@ -139,9 +139,7 @@ private async void create_snapshot () {
             var msg = _("Failed to create snapshot of %s").printf (machine.name);
             warning (e.message);
 
-            toast_overlay.display_toast (new Boxes.Toast () {
-                message = msg
-            });
+            toast_overlay.display_toast (new Boxes.Toast (msg));
         }
         this.activity = null;
 
diff --git a/src/ui/toast-overlay.vala b/src/ui/toast-overlay.vala
index 0e2f9bd7..e9750524 100644
--- a/src/ui/toast-overlay.vala
+++ b/src/ui/toast-overlay.vala
@@ -21,4 +21,10 @@ public void display_toast (Boxes.Toast toast) {
         this.toast = toast;
     }
 
+    public void dismiss () {
+        if (toast != null) {
+            toast.dismiss ();
+            _toast = null;
+        }
+    }
 }
diff --git a/src/ui/toast.vala b/src/ui/toast.vala
index e5029631..186b3552 100644
--- a/src/ui/toast.vala
+++ b/src/ui/toast.vala
@@ -32,6 +32,11 @@
     public OKFunc? undo_func;
     public DismissFunc? dismiss_func;
 
+    public Toast (string? message = null) {
+        if (message != null)
+            this.message = message;
+    }
+
     public void dismiss () {
         if (dismiss_func != null)
             dismiss_func ();
diff --git a/src/unattended-installer.vala b/src/unattended-installer.vala
index b544d138..c176a50b 100644
--- a/src/unattended-installer.vala
+++ b/src/unattended-installer.vala
@@ -205,7 +205,7 @@ public override async void prepare_for_installation (string vm_name, Cancellable
             // if it wants to retry a non-automatic install or to just abort the box creation..
             setup_box.express_install = false;
             var msg = _("An error occurred during installation preparation. Express Install disabled.");
-            App.app.main_window.notificationbar.display_error (msg);
+            App.app.main_window.display_toast (new Boxes.Toast (msg));
             debug ("Disabling unattended installation: %s", error.message);
         }
     }
diff --git a/src/vm-importer.vala b/src/vm-importer.vala
index e152ea16..73a1b172 100644
--- a/src/vm-importer.vala
+++ b/src/vm-importer.vala
@@ -61,8 +61,9 @@ private async void import_vm (LibvirtMachine machine) {
                      machine.name,
                      source_media.device_file,
                      error.message);
-            var ui_message = _("Box import from file “%s” failed.").printf (source_media.device_file);
-            App.app.main_window.notificationbar.display_error (ui_message);
+            // Translators: the first %s is a path, the second is the reason of the failure.
+            var message = _("Box import from file “%s” failed: %s").printf (source_media.device_file, 
error.message);
+            App.app.main_window.display_toast (new Boxes.Toast (message));
             machine.delete ();
 
             return;


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