Skip to content

Commit

Permalink
Raven notification cleanup (#362)
Browse files Browse the repository at this point in the history
* raven: Cleanup notifications group code

Signed-off-by: Evan Maddock <maddock.evan@vivaldi.net>

* raven: Make NotificationWidget a subclass of ListBoxRow

Signed-off-by: Evan Maddock <maddock.evan@vivaldi.net>

---------

Signed-off-by: Evan Maddock <maddock.evan@vivaldi.net>
Co-authored-by: Joshua Strobl <JoshStrobl@users.noreply.github.com>
  • Loading branch information
EbonJaeger and JoshStrobl committed May 13, 2023
1 parent 5e47b16 commit 1186d47
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 109 deletions.
35 changes: 17 additions & 18 deletions src/raven/notification_widget.vala
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,36 @@
* (at your option) any later version.
*/

public class NotificationWidget : Gtk.Box {
public class NotificationWidget : Gtk.ListBoxRow {
public Budgie.Notification notification { get; construct; }

private Gtk.Box? header = null;
private Gtk.Button? dismiss_button = null;
private Gtk.Label? label_title = null;
private Gtk.Label? label_body = null;
private Gtk.Label? label_timestamp = null;

public signal void closed_individually();

public NotificationWidget(Budgie.Notification notification) {
Object(orientation: Gtk.Orientation.VERTICAL, spacing: 4, notification: notification);
Object(notification: notification);
}

construct {
expand = false;
margin_bottom = 4;
get_style_context().add_class("notification-clone");
var box = new Gtk.Box(Gtk.Orientation.VERTICAL, 4) {
expand = false,
margin_bottom = 4,
};
box.get_style_context().add_class("notification-clone");

header = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0); // Create our Notification header
var header = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0); // Create our Notification header

dismiss_button = new Gtk.Button.from_icon_name("window-close-symbolic", Gtk.IconSize.MENU);
var dismiss_button = new Gtk.Button.from_icon_name("window-close-symbolic", Gtk.IconSize.MENU);
dismiss_button.get_style_context().add_class("flat");
dismiss_button.get_style_context().add_class("image-button");

label_title = new Gtk.Label(notification.summary) {
var label_title = new Gtk.Label(notification.summary) {
ellipsize = Pango.EllipsizeMode.END,
halign = Gtk.Align.START,
justify = Gtk.Justification.LEFT,
use_markup = true
};

Gtk.Label label_body = null;
if (notification.body != "") { // If there is body content
label_body = new Gtk.Label(notification.body) {
halign = Gtk.Align.START,
Expand All @@ -60,7 +57,7 @@ public class NotificationWidget : Gtk.Box {
string clock_format = gnome_settings.get_string("clock-format");
clock_format = (clock_format == "12h") ? date.format("%l:%M %p") : date.format("%H:%M");

label_timestamp = new Gtk.Label(clock_format) {
var label_timestamp = new Gtk.Label(clock_format) {
halign = Gtk.Align.START,
justify = Gtk.Justification.LEFT
};
Expand All @@ -72,14 +69,16 @@ public class NotificationWidget : Gtk.Box {
header.pack_start(label_title, false, false, 0); // Expand the label
header.pack_end(dismiss_button, false, false, 0);

pack_start(header); // Add our header
pack_end(label_timestamp);
box.pack_start(header); // Add our header
box.pack_end(label_timestamp);

if (label_body != null) {
pack_end(label_body);
box.pack_end(label_body);
}

dismiss_button.clicked.connect(Dismiss);

add(box);
}

/**
Expand Down
189 changes: 99 additions & 90 deletions src/raven/notifications_group.vala
Original file line number Diff line number Diff line change
Expand Up @@ -14,77 +14,92 @@ namespace Budgie {
* NotificationGroup is a group of notifications.
*/
public class NotificationGroup : Gtk.Box {
public int? count = 0;
private HashTable<uint32, NotificationWidget>? notifications = null;
private Gtk.ListBox? list = null;
private Gtk.Box? header = null;
private Gtk.Image? app_image = null;
private Gtk.Label? app_label = null;
private string? app_name;
private Gtk.Button? dismiss_button = null;
private uint? tokeep;
private HashTable<uint32, NotificationWidget> notifications;

private Gtk.Label name_label;
private Gtk.Button dismiss_button;
private Gtk.ListBox noti_box;

public string app_name { get; construct; }
public string app_icon { get; construct; }
public uint tokeep { get; construct set; }
public NotificationSort noti_sort_mode { get; construct set; default = NEW_OLD; }
public int noti_count { get; private set; default = 0; }

/* Signals */

/**
* Signals
*/
public signal void dismissed_group(string app_name);
public signal void dismissed_notification(uint32 id);

public NotificationGroup(string c_app_icon, string c_app_name, NotificationSort sort_mode, uint keep) {
Object(orientation: Gtk.Orientation.VERTICAL, spacing: 4);
construct {
can_focus = false; // Disable focus to prevent scroll on click
focus_on_click = false;
tokeep = keep;

get_style_context().add_class("raven-notifications-group");

// Intentially omit _end because it messes with alignment of dismiss buttons
margin = 4;

app_name = c_app_name;

if (("budgie" in c_app_name) && ("caffeine" in c_app_icon)) { // Caffeine Notification
app_name = _("Caffeine Mode");
}

notifications = new HashTable<uint32, NotificationWidget>(direct_hash, direct_equal);
list = new Gtk.ListBox();
list.can_focus = false; // Disable focus to prevent scroll on click
list.focus_on_click = false;
list.set_selection_mode(Gtk.SelectionMode.NONE);
set_sort_mode(sort_mode);

noti_box = new Gtk.ListBox() {
can_focus = false,
focus_on_click = false,
selection_mode = Gtk.SelectionMode.NONE,
};
noti_box.set_sort_func(sort_notifications);

/**
* Header creation
*/
header = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0); // Create our Notification header
var header = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0); // Create our Notification header
header.get_style_context().add_class("raven-notifications-group-header");

app_image = new Gtk.Image.from_icon_name(c_app_icon, Gtk.IconSize.DND);
app_image.halign = Gtk.Align.START;
app_image.margin_end = 5;
app_image.set_pixel_size(32); // Really ensure it's 32x32

app_label = new Gtk.Label(app_name);
app_label.ellipsize = Pango.EllipsizeMode.END;
app_label.halign = Gtk.Align.START;
app_label.justify = Gtk.Justification.LEFT;
app_label.use_markup = true;

dismiss_button = new Gtk.Button.from_icon_name("list-remove-all-symbolic", Gtk.IconSize.MENU);
var app_image = new Gtk.Image.from_icon_name(app_icon, Gtk.IconSize.DND) {
halign = Gtk.Align.START,
margin_end = 5,
pixel_size = 32, // Really ensure it's 32x32
};

name_label = new Gtk.Label(app_name) {
ellipsize = Pango.EllipsizeMode.END,
halign = Gtk.Align.START,
justify = Gtk.Justification.LEFT,
use_markup = true,
};

dismiss_button = new Gtk.Button.from_icon_name("list-remove-all-symbolic", Gtk.IconSize.MENU) {
valign = Gtk.Align.CENTER,
halign = Gtk.Align.END,
};
dismiss_button.get_style_context().add_class("flat");
dismiss_button.get_style_context().add_class("image-button");
dismiss_button.valign = Gtk.Align.CENTER;
dismiss_button.halign = Gtk.Align.END;

dismiss_button.clicked.connect(dismiss_all);

header.pack_start(app_image, false, false, 0);
header.pack_start(app_label, false, false, 0);
header.pack_start(name_label, false, false, 0);
header.pack_end(dismiss_button, false, false, 0);

pack_start(header);
pack_start(list);
pack_start(noti_box);
}

public NotificationGroup(string c_app_icon, string c_app_name, NotificationSort sort_mode, uint keep) {
var name = c_app_name;

if (("budgie" in name) && ("caffeine" in c_app_icon)) { // Caffeine Notification
name = _("Caffeine Mode");
}

Object(
app_name: name,
app_icon: c_app_icon,
tokeep: keep,
noti_sort_mode: sort_mode,
orientation: Gtk.Orientation.VERTICAL,
spacing: 4
);
}

/**
Expand All @@ -97,9 +112,9 @@ namespace Budgie {

var widget = new NotificationWidget(notification);
notifications.insert(id, widget);
list.prepend(widget);
noti_box.prepend(widget);

list.invalidate_sort();
noti_box.invalidate_sort();
update_count();

widget.closed_individually.connect(() => { // When this notification is closed
Expand All @@ -113,10 +128,8 @@ namespace Budgie {
* dismiss_all is responsible for dismissing all notifications
*/
public void dismiss_all() {
notifications.foreach_remove((id, notification) => {
var parent = notification.get_parent();
list.remove(parent);
parent.destroy();
notifications.foreach_remove((id, widget) => {
widget.destroy();
dismissed_notification(id);
return true;
});
Expand All @@ -129,17 +142,18 @@ namespace Budgie {
* remove_notification is responsible for removing a notification (if it exists) and updating our counter
*/
public void remove_notification(uint32 id) {
var notification = notifications.lookup(id); // Get our notification
var widget = notifications.lookup(id); // Get our notification

if (notification != null) { // If this notification exists
if (widget != null) { // If this notification exists
notifications.remove(id);
var parent = notification.get_parent();
list.remove(parent);
list.invalidate_sort();
parent.destroy();

widget.destroy();

noti_box.invalidate_sort();
update_count(); // Update our counter
dismissed_notification(id); // Notify anything listening
if (count == 0) { // This was the last notification

if (noti_count == 0) { // This was the last notification
dismissed_group(app_name); // Dismiss the group
}
}
Expand All @@ -149,25 +163,29 @@ namespace Budgie {
* too many notifications will choke raven and the desktop, so let's set a limit;
* keep the latest n-notifications of current group, delete older ones
*/
public void limit_notifications () {
public void limit_notifications() {
GLib.List<uint32> currnotifs = notifications.get_keys();

currnotifs.sort((a, b) => {
return (int) (a > b) - (int) (a < b);
});

uint n_currnotifs = currnotifs.length();

/**
* no need to reduce if the current number of notifications is below our threshold
* and we shouldn't attempt to set a negative uint
*/
if (n_currnotifs <= tokeep) return;
uint n_remove = n_currnotifs - tokeep;
int count = 0;

foreach (uint n in currnotifs) {
if (count < n_remove) {
remove_notification(n);
} else {
if (count >= n_remove) {
break;
}

remove_notification(n);
count++;
}
}
Expand All @@ -183,45 +201,36 @@ namespace Budgie {
/**
* update_count updates our notifications count for this group
*/
public void update_count() {
count = (int) notifications.length;
if (count > tokeep) {
private void update_count() {
noti_count = (int) notifications.length;

if (noti_count > tokeep) {
limit_notifications();
}
app_label.set_markup("<b>%s (%i)</b>".printf(app_name, count));

name_label.set_markup("<b>%s (%i)</b>".printf(app_name, noti_count));
}

/**
* Set the sort mode for this notification group.
*/
public void set_sort_mode(NotificationSort sort_mode) {
switch (sort_mode) {
case OLD_NEW:
list.set_sort_func(sort_old_to_new);
break;
private int sort_notifications(Gtk.ListBoxRow a, Gtk.ListBoxRow b) {
var noti_a = a as NotificationWidget;
var noti_b = b as NotificationWidget;

switch (noti_sort_mode) {
case NEW_OLD:
default:
list.set_sort_func(sort_new_to_old);
break;
return (int) (noti_b.notification.timestamp - noti_a.notification.timestamp);
case OLD_NEW:
return (int) (noti_a.notification.timestamp - noti_b.notification.timestamp);
}

list.invalidate_sort();
}

private int sort_new_to_old(Gtk.ListBoxRow a, Gtk.ListBoxRow b) {
var noti_a = a.get_child() as NotificationWidget;
var noti_b = b.get_child() as NotificationWidget;

// Sort notifications from new -> old, descending
return (int)(noti_b.notification.timestamp - noti_a.notification.timestamp);
return 0;
}

private int sort_old_to_new(Gtk.ListBoxRow a, Gtk.ListBoxRow b) {
var noti_a = a.get_child() as NotificationWidget;
var noti_b = b.get_child() as NotificationWidget;

// Sort notifications from old -> new, descending
return (int)(noti_a.notification.timestamp - noti_b.notification.timestamp);
/**
* Set the sort mode for this notification group.
*/
public void set_sort_mode(NotificationSort sort_mode) {
noti_sort_mode = sort_mode;
noti_box.invalidate_sort();
}
}
}
2 changes: 1 addition & 1 deletion src/raven/notifications_view.vala
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ namespace Budgie {

if (notification_groups.length != 0) {
notification_groups.foreach((app_name, notification_group) => { // For each notifications list
len += notification_group.count; // Add this notification group count
len += notification_group.noti_count; // Add this notification group count
});
}

Expand Down

0 comments on commit 1186d47

Please sign in to comment.