diff --git a/ags/scripts/notifications.ts b/ags/scripts/notifications.ts index 9010117..4aac42c 100644 --- a/ags/scripts/notifications.ts +++ b/ags/scripts/notifications.ts @@ -1,6 +1,11 @@ -import { GObject, property, register, signal, timeout } from "astal"; +import { AstalIO, GObject, property, register, signal, timeout } from "astal"; import AstalNotifd from "gi://AstalNotifd"; +export const + NOTIFICATION_TIMEOUT_URGENT: number = 0, + NOTIFICATION_TIMEOUT_NORMAL: number = 4000, + NOTIFICATION_TIMEOUT_LOW: number = 2000; + @register({ GTypeName: "Notifications" }) class Notifications extends GObject.Object { private static instance: (Notifications|null) = null; @@ -29,6 +34,9 @@ class Notifications extends GObject.Object { @signal(Number) declare historyRemoved: (id: number) => void; + @signal(Number) + declare notificationReplaced: (id: number) => void; + constructor() { super(); @@ -36,13 +44,33 @@ class Notifications extends GObject.Object { this.#connections = [ AstalNotifd.get_default().connect("notified", (notifd, id, _replaced) => { const notification = notifd.get_notification(id); - const notifTimeout = 4000; + const notifTimeout = notification.urgency === AstalNotifd.Urgency.LOW ? + NOTIFICATION_TIMEOUT_LOW + : (notification.urgency === AstalNotifd.Urgency.CRITICAL ? + NOTIFICATION_TIMEOUT_URGENT + : NOTIFICATION_TIMEOUT_NORMAL); this.addNotification(notification, () => { - if(notification.urgency !== AstalNotifd.Urgency.CRITICAL) - timeout(notifTimeout, () => { + if(notification.urgency !== AstalNotifd.Urgency.CRITICAL || + (notification.urgency === AstalNotifd.Urgency.CRITICAL && + NOTIFICATION_TIMEOUT_URGENT > 0)) { + + let notifTimer: AstalIO.Time; + let replacedConnectionId: number; + const removeFun = () => { // Funny name haha lmao remove fun :skull: this.removeNotification(id); + replacedConnectionId && this.disconnect(replacedConnectionId); + } + + replacedConnectionId = this.connect("notification-replaced", (_, id: number) => { + if(notification.id === id) { + notifTimer.cancel(); + notifTimer = timeout(notifTimeout, removeFun); + } }); + + notifTimer = timeout(notifTimeout, removeFun); + } }); }), AstalNotifd.get_default().connect("resolved", (notifd, id, _reason) => { @@ -51,7 +79,8 @@ class Notifications extends GObject.Object { }) ]; - this.vfunc_dispose = () => { + this.run_dispose = () => { + super.run_dispose(); this.#connections.map((id: number) => AstalNotifd.get_default().disconnect(id)); }; @@ -84,6 +113,10 @@ class Notifications extends GObject.Object { private addNotification(notif: AstalNotifd.Notification, onAdded?: (notif: AstalNotifd.Notification) => void): void { const newArray = this.#notifications.reverse().filter((item) => item.id !== notif.id); + if(newArray !== this.notifications) { + this.emit("notification-replaced", notif.id); + } + newArray.push(notif); this.#notifications = newArray.reverse(); this.notify("notifications"); @@ -98,6 +131,14 @@ class Notifications extends GObject.Object { this.notify("notifications"); this.emit("notification-removed", notifId); } + + connect(signal: string, callback: (...args: any[]) => void): number { + return super.connect(signal, callback); + } + + disconnect(id: number) { + super.disconnect(id); + } } export { Notifications }; diff --git a/ags/style/_float-notifications.scss b/ags/style/_float-notifications.scss index 91c6195..6f789bb 100644 --- a/ags/style/_float-notifications.scss +++ b/ags/style/_float-notifications.scss @@ -7,19 +7,8 @@ top: 6px; }; - & revealer { - padding: 6px; - - & > .notification { - box-shadow: 0 0 4px .5px colors.$bg-translucent; - } - - &:first-child { - margin-top: 0; - } - - &:last-child { - margin-bottom: 0; - } + & > .notification { + margin: 6px; + box-shadow: 0 0 4px .5px colors.$bg-translucent; } } diff --git a/ags/widget/Notification.ts b/ags/widget/Notification.ts index aa7a9af..c1b2c5c 100644 --- a/ags/widget/Notification.ts +++ b/ags/widget/Notification.ts @@ -92,6 +92,7 @@ export function NotificationWidget(notification: AstalNotifd.Notification|number className: "body", useMarkup: true, halign: Gtk.Align.START, + xalign: 0, truncate: false, wrap: true, wrapMode: Pango.WrapMode.WORD, diff --git a/ags/window/FloatingNotifications.ts b/ags/window/FloatingNotifications.ts index d032bad..b62f865 100644 --- a/ags/window/FloatingNotifications.ts +++ b/ags/window/FloatingNotifications.ts @@ -3,11 +3,8 @@ import AstalNotifd from "gi://AstalNotifd"; import { bind } from "astal/binding"; import { Notifications } from "../scripts/notifications"; import { NotificationWidget } from "../widget/Notification"; -import { timeout } from "astal"; -import { VarMap } from "../scripts/varmap"; const connections: Array = []; -const notifWidgets = new VarMap(); export const FloatingNotifications: Widget.Window = new Widget.Window({ namespace: "floating-notifications", @@ -20,30 +17,11 @@ export const FloatingNotifications: Widget.Window = new Widget.Window({ exclusivity: Astal.Exclusivity.NORMAL, setup: (window) => { connections.push( - Notifications.getDefault().connect("notification-added", (_, notif: AstalNotifd.Notification) => { + Notifications.getDefault().connect("notification-added", (_, _notif: AstalNotifd.Notification) => { !window.is_visible() && window.show(); - - notifWidgets.set(notif.id, new Widget.Revealer({ - revealChild: false, - transitionDuration: 320, - transitionType: Gtk.RevealerTransitionType.SLIDE_RIGHT, - child: NotificationWidget(notif, - () => Notifications.getDefault().removeNotification(notif.id)), - } as Widget.RevealerProps)); - - notifWidgets.getValue(notif.id)!.revealChild = true; }), - - Notifications.getDefault().connect("notification-removed", (_, id: number) => { - notifWidgets.getValue(id)!.revealChild = false; - timeout( - (notifWidgets.getValue(id)?.get_transition_duration() || 0) + 50, - () => { - notifWidgets.delete(id); - Notifications.getDefault().notifications.length === 0 && - window.is_visible() && window.hide(); - } - ); + Notifications.getDefault().connect("notification-removed", (_: Notifications, _id: number) => { + window.is_visible() && _.notifications.length === 0 && window.hide() }) ); }, @@ -53,6 +31,11 @@ export const FloatingNotifications: Widget.Window = new Widget.Window({ orientation: Gtk.Orientation.VERTICAL, homogeneous: false, visible: bind(Notifications.getDefault(), "notifications").as(notifs => notifs.length > 0), - children: bind(notifWidgets).as((map) => [...map.values()].map((revealer) => revealer)) + children: bind(Notifications.getDefault(), "notifications").as((notifs) => + notifs.map((item) => + NotificationWidget(item, + () => Notifications.getDefault().removeNotification(item)) + ) + ), } as Widget.BoxProps) } as Widget.WindowProps);