From d1cbfafb2ef694f571930bc87812d25f59b93ec3 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Wed, 29 Nov 2023 13:48:04 +0100 Subject: [PATCH] Added back notification logic Notifications are now separated into their own group depending on their provided name --- src/constants.vala.in | 1 + src/controlCenter/controlCenter.vala | 184 +++++++++++++------ src/notificationGroup/notificationGroup.vala | 81 +++++--- 3 files changed, 191 insertions(+), 75 deletions(-) diff --git a/src/constants.vala.in b/src/constants.vala.in index 28cfa2ca..31779bc1 100644 --- a/src/constants.vala.in +++ b/src/constants.vala.in @@ -1,4 +1,5 @@ public class Constants { public const string VERSION = @VERSION@; public const string VERSIONNUM = @VERSION_NUM@; + public const uint ANIMATION_DURATION = 400; } diff --git a/src/controlCenter/controlCenter.vala b/src/controlCenter/controlCenter.vala index 1bcfce04..ee379ae8 100644 --- a/src/controlCenter/controlCenter.vala +++ b/src/controlCenter/controlCenter.vala @@ -15,7 +15,14 @@ namespace SwayNotificationCenter { [GtkChild] unowned Gtk.Box box; - NotificationGroup noti_group; + unowned NotificationGroup ? expanded_group = null; + private double fade_animation_progress = 1.0; + private Animation ? notification_fade_animation; + + HashTable noti_groups_id = + new HashTable (direct_hash, direct_equal); + HashTable noti_groups_name = + new HashTable (str_hash, str_equal); const string STACK_NOTIFICATIONS_PAGE = "notifications-list"; const string STACK_PLACEHOLDER_PAGE = "notifications-placeholder"; @@ -29,7 +36,6 @@ namespace SwayNotificationCenter { private uint list_position = 0; - private double last_upper = 0; private bool list_reverse = false; private Gtk.Align list_align = Gtk.Align.START; @@ -58,8 +64,6 @@ namespace SwayNotificationCenter { GtkLayerShell.set_anchor (this, GtkLayerShell.Edge.BOTTOM, true); } - viewport.size_allocate.connect (size_alloc); - this.map.connect (() => { set_anchor (); // Wait until the layer has attached @@ -234,6 +238,58 @@ namespace SwayNotificationCenter { }); add_widgets (); + + notification_fade_animation = new Animation (this, Constants.ANIMATION_DURATION, + Animation.ease_in_out_cubic, + animation_value_cb, + animation_done_cb); + list_box.draw.connect (list_box_draw_cb); + } + + void animation_value_cb (double progress) { + this.fade_animation_progress = progress; + + this.queue_draw (); + } + + void animation_done_cb () { + notification_fade_animation.dispose (); + } + + void animate (double to) { + notification_fade_animation.stop (); + notification_fade_animation.start (fade_animation_progress, to); + } + + /// Fade non-expanded groups when one group is expanded + private bool list_box_draw_cb (Cairo.Context cr) { + Cairo.Pattern fade_gradient = new Cairo.Pattern.linear (0, 0, 0, 1); + fade_gradient.add_color_stop_rgba (0, 1, 1, 1, 1 - fade_animation_progress - 0.5); + + foreach (unowned Gtk.Widget widget in list_box.get_children ()) { + Gtk.Allocation alloc; + widget.get_allocated_size (out alloc, null); + + cr.save (); + cr.translate (0, alloc.y); + + cr.push_group (); + widget.draw (cr); + + cr.scale (alloc.width, alloc.height); + if (widget != expanded_group) { + cr.set_source (fade_gradient); + cr.rectangle (0, 0, alloc.width, alloc.height); + cr.set_operator (Cairo.Operator.DEST_OUT); + cr.fill (); + } + + cr.pop_group_to_source (); + cr.paint (); + + cr.restore (); + } + return true; } /** Adds all custom widgets. Removes previous widgets */ @@ -361,13 +417,13 @@ namespace SwayNotificationCenter { list_box.set_valign (list_align); list_box.set_sort_func ((w1, w2) => { - var a = (Notification) w1; - var b = (Notification) w2; - if (a == null || b == null) return 0; + var a_time = ((NotificationGroup) w1).get_time (); + var b_time = ((NotificationGroup) w2).get_time (); + if (a_time < 0 || b_time < 0)return 0; // Sort the list in reverse if needed - if (a.param.time == b.param.time) return 0; + if (a_time == b_time)return 0; int val = list_reverse ? 1 : -1; - return a.param.time > b.param.time ? val : val * -1; + return a_time > b_time ? val : val * -1; }); // Always set the size request in all events. @@ -375,15 +431,6 @@ namespace SwayNotificationCenter { ConfigModel.instance.control_center_height); } - private void size_alloc () { - var adj = viewport.vadjustment; - double upper = adj.get_upper (); - if (last_upper < upper) { - scroll_to_start (list_reverse); - } - last_upper = upper; - } - private void scroll_to_start (bool reverse) { Gtk.ScrollType scroll_type = Gtk.ScrollType.START; if (reverse) { @@ -393,20 +440,26 @@ namespace SwayNotificationCenter { } public uint notification_count () { - return list_box.get_children ().length (); + uint count = 0; + foreach (unowned Gtk.Widget widget in list_box.get_children ()) { + if (widget is NotificationGroup) { + count += ((NotificationGroup) widget).get_num_notifications (); + } + } + return count; } public void close_all_notifications () { foreach (var w in list_box.get_children ()) { - Notification noti = (Notification) w; - if (noti != null) noti.close_notification (false); + NotificationGroup group = (NotificationGroup) w; + if (group != null)group.close_all_notifications (); } try { swaync_daemon.subscribe_v2 (notification_count (), - swaync_daemon.get_dnd (), - get_visibility (), - swaync_daemon.inhibited); + swaync_daemon.get_dnd (), + get_visibility (), + swaync_daemon.inhibited); } catch (Error e) { stderr.printf (e.message + "\n"); } @@ -439,14 +492,14 @@ namespace SwayNotificationCenter { list_box.grab_focus (); navigate_list (list_position); foreach (var w in list_box.get_children ()) { - var noti = (Notification) w; - if (noti != null) noti.set_time (); + var group = (NotificationGroup) w; + if (group != null)group.update_time (); } } swaync_daemon.subscribe_v2 (notification_count (), - noti_daemon.dnd, - this.visible, - swaync_daemon.inhibited); + noti_daemon.dnd, + this.visible, + swaync_daemon.inhibited); } public bool toggle_visibility () { @@ -465,20 +518,9 @@ namespace SwayNotificationCenter { } public void close_notification (uint32 id, bool dismiss) { - // foreach (var w in list_box.get_children ()) { - // var noti = (Notification) w; - // if (noti != null && noti.param.applied_id == id) { - // if (!dismiss) { - // noti.remove_noti_timeout (); - // noti.destroy (); - // } else { - // noti.close_notification (false); - // list_box.remove (w); - // } - // break; - // } - // } - foreach (var w in noti_group.get_notifications ()) { + unowned NotificationGroup group = null; + if (!noti_groups_id.lookup_extended (id, null, out group))return; + foreach (var w in group.get_notifications ()) { var noti = (Notification) w; if (noti != null && noti.param.applied_id == id) { if (!dismiss) { @@ -486,15 +528,26 @@ namespace SwayNotificationCenter { noti.destroy (); } else { noti.close_notification (false); - noti_group.remove_notification (noti); + group.remove_notification (noti); } + noti_groups_id.remove (id); break; } } + if (group.is_empty ()) { + noti_groups_name.remove (group.app_name); + if (expanded_group == group) { + expanded_group = null; + animate (1); + } + group.destroy (); + } } public void replace_notification (uint32 id, NotifyParams new_params) { - foreach (var w in list_box.get_children ()) { + unowned NotificationGroup group = null; + if (!noti_groups_id.lookup_extended (id, null, out group))return; + foreach (var w in group.get_notifications ()) { var noti = (Notification) w; if (noti != null && noti.param.applied_id == id) { noti.replace_notification (new_params); @@ -520,16 +573,36 @@ namespace SwayNotificationCenter { }); noti.set_time (); - if (noti_group == null) { - list_box.add (noti_group = new NotificationGroup(param.app_name)); + NotificationGroup group; + // TODO: Use desktop-entry if exists instead + if (!noti_groups_name.lookup_extended (param.app_name, null, out group)) { + group = new NotificationGroup (param.app_name); + // Collapse other groups on expand + group.on_expand_change.connect ((expanded) => { + if (!expanded) { + animate (1); + return; + } + expanded_group = group; + animate (0); + foreach (unowned Gtk.Widget child in list_box.get_children ()) { + NotificationGroup g = (NotificationGroup) child; + if (g != null && g != group)g.set_expanded (false); + } + }); + noti_groups_name.set (param.app_name, group); + list_box.add (group); } - noti_group.add_notification (noti); + noti_groups_id.set (param.applied_id, group); + + group.add_notification (noti); + list_box.invalidate_sort (); scroll_to_start (list_reverse); try { swaync_daemon.subscribe_v2 (notification_count (), - swaync_daemon.get_dnd (), - get_visibility (), - swaync_daemon.inhibited); + swaync_daemon.get_dnd (), + get_visibility (), + swaync_daemon.inhibited); } catch (Error e) { stderr.printf (e.message + "\n"); } @@ -546,8 +619,13 @@ namespace SwayNotificationCenter { /** Forces each notification EventBox to reload its style_context #27 */ private void reload_notifications_style () { foreach (var c in list_box.get_children ()) { - Notification noti = (Notification) c; - if (noti != null) noti.reload_style_context (); + NotificationGroup group = (NotificationGroup) c; + if (group != null) { + group.forall ((widget) => { + Notification noti = (Notification) c; + noti.reload_style_context (); + }); + } } } } diff --git a/src/notificationGroup/notificationGroup.vala b/src/notificationGroup/notificationGroup.vala index d3a61801..51e018c2 100644 --- a/src/notificationGroup/notificationGroup.vala +++ b/src/notificationGroup/notificationGroup.vala @@ -1,6 +1,6 @@ namespace SwayNotificationCenter { public class NotificationGroup : Gtk.ListBoxRow { - const uint ANIMATION_DURATION = 400; + public string app_name; private ExpandableGroup group; private Gtk.Revealer revealer = new Gtk.Revealer (); @@ -9,14 +9,17 @@ namespace SwayNotificationCenter { private bool gesture_down = false; private bool gesture_in = false; + public signal void on_expand_change (bool state); + public NotificationGroup (string app_name) { + this.app_name = app_name; get_style_context ().add_class ("notification-group"); Gtk.Box box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); revealer.set_transition_type (Gtk.RevealerTransitionType.SLIDE_UP); revealer.set_reveal_child (false); - revealer.set_transition_duration (ANIMATION_DURATION); + revealer.set_transition_duration (Constants.ANIMATION_DURATION); // Add top controls Gtk.Box controls_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 4); @@ -29,7 +32,9 @@ namespace SwayNotificationCenter { collapse_button.set_halign (Gtk.Align.END); collapse_button.set_valign (Gtk.Align.CENTER); collapse_button.clicked.connect (() => { - group.set_expanded (false); + set_expanded (false); + on_expand_change (false); + group.set_sensitive (single_notification () || group.is_expanded); }); Gtk.Label app_label = new Gtk.Label (app_name); app_label.xalign = 0; @@ -43,7 +48,7 @@ namespace SwayNotificationCenter { set_activatable (false); - group = new ExpandableGroup (ANIMATION_DURATION, (state) => { + group = new ExpandableGroup (Constants.ANIMATION_DURATION, (state) => { revealer.set_reveal_child (state); }); box.add (group); @@ -52,7 +57,7 @@ namespace SwayNotificationCenter { show_all (); /* - * Handling of bank window presses (pressing outside of ControlCenter) + * Handling of group presses */ gesture = new Gtk.GestureMultiPress (this); gesture.set_touch_only (false); @@ -68,9 +73,12 @@ namespace SwayNotificationCenter { if (!gesture_down) return; gesture_down = false; if (gesture_in) { - if (!group.is_expanded) { + bool single_noti = single_notification (); + if (!group.is_expanded && !single_noti) { group.set_expanded (true); + on_expand_change (true); } + group.set_sensitive (single_noti || group.is_expanded); } Gdk.EventSequence ? sequence = gesture.get_current_sequence (); @@ -99,16 +107,59 @@ namespace SwayNotificationCenter { }); } + /// Returns if there's more than one notification + private bool single_notification () { + unowned Gtk.Widget ? widget = group.widgets.nth_data (1); + return widget == null; + } + + public void set_expanded (bool state) { + group.set_expanded (state); + } + public void add_notification (Notification noti) { group.add (noti); + if (!single_notification ()) { + group.set_sensitive (false); + } } public void remove_notification (Notification noti) { group.remove (noti); + if (single_notification ()) { + set_expanded (false); + } } public List get_notifications () { - return group.get_notifications (); + return group.widgets.copy (); + } + + public int64 get_time () { + if (group.widgets.is_empty ()) return -1; + return ((Notification) group.widgets.last ().data).param.time; + } + + public uint get_num_notifications () { + return group.widgets.length (); + } + + public bool is_empty () { + return group.widgets.is_empty (); + } + + public void close_all_notifications () { + foreach (unowned Gtk.Widget widget in group.widgets) { + var noti = (Notification) widget; + if (noti != null) noti.close_notification (false); + } + } + + public void update_time () { + foreach (unowned Gtk.Widget widget in group.widgets) { + var noti = (Notification) widget; + if (noti != null) noti.set_time (); + } } } @@ -128,7 +179,7 @@ namespace SwayNotificationCenter { private unowned on_expand_change change_cb; - private List widgets = new List(); + public List widgets = new List(); public delegate void on_expand_change (bool state); @@ -148,18 +199,9 @@ namespace SwayNotificationCenter { set_expanded (false); } - public List get_notifications () { - return widgets.copy (); - } - - public uint get_num_notifications () { - return widgets.length (); - } - public void set_expanded (bool value) { if (is_expanded == value) return; is_expanded = value; - set_sensitive (is_expanded); animate (is_expanded ? 1 : 0); @@ -429,8 +471,3 @@ namespace SwayNotificationCenter { } } } - - - - -