From 54a62679574db230fd72a5c7819d5f7715cf17c0 Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Sun, 12 Jan 2025 23:00:18 +1100 Subject: notification popups --- modules/notifpopups.tsx | 163 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 modules/notifpopups.tsx (limited to 'modules/notifpopups.tsx') diff --git a/modules/notifpopups.tsx b/modules/notifpopups.tsx new file mode 100644 index 0000000..a9a898c --- /dev/null +++ b/modules/notifpopups.tsx @@ -0,0 +1,163 @@ +import { GLib, register, timeout } from "astal"; +import { Astal, Gtk, Widget } from "astal/gtk3"; +import AstalNotifd from "gi://AstalNotifd"; + +const urgencyToString = (urgency: AstalNotifd.Urgency) => { + switch (urgency) { + case AstalNotifd.Urgency.LOW: + return "low"; + case AstalNotifd.Urgency.NORMAL: + return "normal"; + case AstalNotifd.Urgency.CRITICAL: + return "critical"; + } +}; + +const getTime = (time: number) => { + const messageTime = GLib.DateTime.new_from_unix_local(time); + const todayDay = GLib.DateTime.new_now_local().get_day_of_year(); + if (messageTime.get_day_of_year() === todayDay) { + const aMinuteAgo = GLib.DateTime.new_now_local().add_seconds(-60); + return aMinuteAgo !== null && messageTime.compare(aMinuteAgo) > 0 ? "Now" : messageTime.format("%H:%M"); + } else if (messageTime.get_day_of_year() === todayDay - 1) return "Yesterday"; + return messageTime.format("%d/%m"); +}; + +const Icon = ({ icon }: { icon: string }) => { + if (GLib.file_test(icon, GLib.FileTest.EXISTS)) + return ( + + ); + if (Astal.Icon.lookup_icon(icon)) return ; + return null; +}; + +@register() +class NotifPopup extends Widget.Box { + readonly #revealer; + #destroyed = false; + + constructor({ notification }: { notification: AstalNotifd.Notification }) { + super(); + + this.#revealer = ( + + + + + {(notification.appIcon || notification.desktopEntry) && ( + + )} + + + ) as Widget.Revealer; + this.add(this.#revealer); + + // Init animation + const width = this.get_preferred_width()[1]; + this.css = `margin-left: ${width}px; margin-right: -${width}px;`; + timeout(1, () => { + this.css = `transition: 150ms cubic-bezier(0.05, 0.9, 0.1, 1.1); margin-left: 0; margin-right: 0;`; + }); + + // Close popup after timeout + // timeout( + // notification.expireTimeout > 0 + // ? notification.expireTimeout + // : notification.urgency === AstalNotifd.Urgency.CRITICAL + // ? 10000 + // : 5000, + // () => this.destroyWithAnims() + // ); + } + + destroyWithAnims() { + if (this.#destroyed) return; + this.#destroyed = true; + + const animTime = 120; + const animMargin = this.get_allocated_width(); + this.css = `transition: ${animTime}ms cubic-bezier(0.85, 0, 0.15, 1); + margin-left: ${animMargin}px; margin-right: -${animMargin}px;`; + timeout(animTime, () => { + this.#revealer.revealChild = false; + timeout(this.#revealer.transitionDuration, () => this.destroy()); + }); + } +} + +export default () => ( + + { + const notifd = AstalNotifd.get_default(); + const map = new Map(); + self.hook(notifd, "notified", (self, id) => { + const notification = notifd.get_notification(id); + const popup = () as NotifPopup; + map.set(notification.id, popup); + self.add( + event.button === Astal.MouseButton.MIDDLE && notification.dismiss()} + // Close on hover lost + onHoverLost={() => popup.destroyWithAnims()} + > + {popup} + + ); + }); + self.hook(notifd, "resolved", (_, id) => { + const popup = map.get(id); + if (popup) { + popup.destroyWithAnims(); + map.delete(id); + } + }); + + // Change input region to child region so can click through empty space + self.connect("size-allocate", () => self.get_window()?.set_child_input_shapes()); + }} + /> + +); -- cgit v1.2.3-freya