From dc8d1f2f85b91fcd2fd2d4064af239426b9025d1 Mon Sep 17 00:00:00 2001 From: Joshua Strobl Date: Thu, 24 May 2018 00:10:45 +0300 Subject: [PATCH] Implement broader Raven DND support and tweak Clear Notifications. Implements a dnd_enabled state in RavenIFace, as well as appropriate functionality for setting, fetching, and being updated on DND state changes. This is utilized by our Notifications / Raven Applet, which will now update the icon based on the DND state (defaults to not being in DND mode). Additionally, tweaked the icon for enabling / disabling DND to being notification-alert-symbolic, to be consistent with the applet, and disabled being notification-disabled-symbolic. This commit also tweaks the behavior of showing the Clear Notifications button, which will now only show if there are actual notifications to clear. Added a .vscode workspace configuration to enforce spaces for Vala. --- .vscode/settings.json | 7 +++ .../notifications/NotificationsApplet.vala | 30 +++++++++++++ src/raven/notifications_view.vala | 44 +++++++++---------- src/raven/raven.vala | 23 ++++++++++ 4 files changed, 80 insertions(+), 24 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..c336b7fbb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "editor.detectIndentation": true, + "[vala]": { + "editor.insertSpaces": true, + "editor.tabSize": 4 + } +} \ No newline at end of file diff --git a/src/applets/notifications/NotificationsApplet.vala b/src/applets/notifications/NotificationsApplet.vala index 58ac60c15..fe63a6d46 100644 --- a/src/applets/notifications/NotificationsApplet.vala +++ b/src/applets/notifications/NotificationsApplet.vala @@ -23,6 +23,8 @@ public const string RAVEN_DBUS_OBJECT_PATH = "/org/budgie_desktop/Raven"; [DBus (name="org.budgie_desktop.Raven")] public interface RavenRemote : Object { + public signal void DoNotDisturbChanged(bool active); + public abstract async bool GetDoNotDisturbState() throws Error; public abstract async void ToggleNotificationsView() throws Error; public signal void NotificationsChanged(); public abstract async uint GetNotificationCount() throws Error; @@ -41,15 +43,22 @@ public class NotificationsApplet : Budgie.Applet { try { raven_proxy = Bus.get_proxy.end(res); + raven_proxy.DoNotDisturbChanged.connect(on_dnd_changed); raven_proxy.NotificationsChanged.connect(on_notifications_changed); raven_proxy.UnreadNotifications.connect(on_notifications_unread); raven_proxy.ReadNotifications.connect(on_notifications_read); raven_proxy.GetNotificationCount.begin(on_get_count); + raven_proxy.GetDoNotDisturbState.begin(on_get_dnd_state); } catch (Error e) { warning("Failed to gain Raven proxy: %s", e.message); } } + void on_dnd_changed(bool active) + { + set_dnd_state(active); + } + void on_notifications_read() { this.icon.get_style_context().remove_class("alert"); @@ -80,6 +89,25 @@ public class NotificationsApplet : Budgie.Applet } } + void on_get_dnd_state(GLib.Object? o, AsyncResult? res) + { + bool active = true; // Default to true + + try { + active = raven_proxy.GetDoNotDisturbState.end(res); + } catch (Error e) { + warning("Failed to get Do Not Disturb state: %s", e.message); + return; + } + + set_dnd_state(active); // Set the DND state + } + + void set_dnd_state(bool enabled) + { + this.icon.set_from_icon_name(((!enabled) ? "notification-alert-symbolic" : "notification-disabled-symbolic"), Gtk.IconSize.MENU); // Set applet icon based on the DND state + } + void on_notifications_changed() { raven_proxy.GetNotificationCount.begin(on_get_count); @@ -94,11 +122,13 @@ public class NotificationsApplet : Budgie.Applet if (button.button != 1) { return Gdk.EVENT_PROPAGATE; } + try { raven_proxy.ToggleNotificationsView(); } catch (Error e) { message("Failed to toggle Raven: %s", e.message); } + return Gdk.EVENT_STOP; } diff --git a/src/raven/notifications_view.vala b/src/raven/notifications_view.vala index 98002948e..173b27d04 100644 --- a/src/raven/notifications_view.vala +++ b/src/raven/notifications_view.vala @@ -513,11 +513,12 @@ public class NotificationsView : Gtk.Box private Settings settings = new GLib.Settings("com.solus-project.budgie-panel"); private HeaderWidget? header = null; - private Gtk.ListBox? listbox; + private Gtk.ListBox? listbox; + private Gtk.Button clear_notifications_button; private Gtk.Button button_mute; - private bool mute_control = false; - private Gtk.Image image_notifications_enabled = new Gtk.Image.from_icon_name("mail-send-receive-symbolic", Gtk.IconSize.MENU); - private Gtk.Image image_notifications_disabled = new Gtk.Image.from_icon_name("image-red-eye-symbolic", Gtk.IconSize.MENU); + private bool dnd_enabled = false; + private Gtk.Image image_notifications_enabled = new Gtk.Image.from_icon_name("notification-alert-symbolic", Gtk.IconSize.MENU); + private Gtk.Image image_notifications_disabled = new Gtk.Image.from_icon_name("notification-disabled-symbolic", Gtk.IconSize.MENU); private GLib.Queue stack = null; @@ -588,10 +589,11 @@ public class NotificationsView : Gtk.Box text = _("1 unread notification"); } else { text = _("No unread notifications"); - } + } Raven.get_instance().set_notification_count(len); header.text = text; + clear_notifications_button.set_visible((len >= 1)); // Only show clear notifications button if we actually have notifications } public uint32 Notify(string app_name, uint32 replaces_id, string app_icon, @@ -609,10 +611,10 @@ public class NotificationsView : Gtk.Box int32 expire = expire_timeout; - if (mute_control) { + if (dnd_enabled) { /* Don't show the notification */ expire = 0; - /* Prevent pure derpery. */ + /* Prevent pure derpery. */ } else if (expire_timeout < 4000 || expire_timeout > 20000) { expire = 4000; } @@ -706,13 +708,9 @@ public class NotificationsView : Gtk.Box [DBus (visible = false)] void do_not_disturb_toggle() { - if (mute_control) { - button_mute.set_image(image_notifications_enabled); - mute_control = false; - } else { - button_mute.set_image(image_notifications_disabled); - mute_control = true; - } + dnd_enabled = !dnd_enabled; // Invert value, so if DND was enabled, set to disabled, otherwise set to enabled + button_mute.set_image(!dnd_enabled ? image_notifications_enabled : image_notifications_disabled); + Raven.get_instance().set_dnd_state(dnd_enabled); } @@ -721,25 +719,23 @@ public class NotificationsView : Gtk.Box { Object(orientation: Gtk.Orientation.VERTICAL, spacing: 0); - var img = new Gtk.Image.from_icon_name("list-remove-all-symbolic", Gtk.IconSize.MENU); - img.margin_top = 4; - - var btn = new Gtk.Button.from_icon_name("list-remove-all-symbolic", Gtk.IconSize.MENU); - btn.relief = Gtk.ReliefStyle.NONE; + clear_notifications_button = new Gtk.Button.from_icon_name("list-remove-all-symbolic", Gtk.IconSize.MENU); + clear_notifications_button.relief = Gtk.ReliefStyle.NONE; + clear_notifications_button.no_show_all = true; button_mute = new Gtk.Button(); button_mute.set_image(image_notifications_enabled); button_mute.relief = Gtk.ReliefStyle.NONE; - var controlButtons = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0); - controlButtons.pack_start(btn, false, false, 0); - controlButtons.pack_start(button_mute, false, false, 0); + var control_buttons = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0); + control_buttons.pack_start(clear_notifications_button, false, false, 0); + control_buttons.pack_start(button_mute, false, false, 0); - header = new HeaderWidget(_("No new notifications"), "notification-alert-symbolic", false, null, controlButtons); + header = new HeaderWidget(_("No new notifications"), "notification-alert-symbolic", false, null, control_buttons); header.margin_top = 6; + clear_notifications_button.clicked.connect(this.clear_all); button_mute.clicked.connect(this.do_not_disturb_toggle); - btn.clicked.connect(this.clear_all); pack_start(header, false, false, 0); diff --git a/src/raven/raven.vala b/src/raven/raven.vala index f9346acaf..b5a3b33af 100644 --- a/src/raven/raven.vala +++ b/src/raven/raven.vala @@ -20,6 +20,9 @@ public class RavenIface { private Raven? parent = null; + [DBus (visible = false)] + private bool dnd_enabled = false; + [DBus (visible = false)] public uint notifications = 0; @@ -96,6 +99,7 @@ public class RavenIface } } + public signal void NotificationsChanged(); public uint GetNotificationCount() { @@ -109,6 +113,20 @@ public class RavenIface { return "1"; } + + /** + * Do Not Disturb Functionality + */ + public signal void DoNotDisturbChanged(bool active); + + public bool GetDoNotDisturbState() { + return this.dnd_enabled; + } + + public void SetDoNotDisturb(bool enable) { + this.dnd_enabled = enable; + this.DoNotDisturbChanged(this.dnd_enabled); + } } public class Raven : Gtk.Window @@ -218,6 +236,11 @@ public class Raven : Gtk.Window return Raven._instance; } + public void set_dnd_state(bool active) + { + this.iface.SetDoNotDisturb(active); // Set the active state of our RavenIFace DND + } + public void set_notification_count(uint count) { if (this.n_count != count && this.iface != null) {