diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-01-16 16:35:37 +1100 |
|---|---|---|
| committer | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-01-16 16:35:37 +1100 |
| commit | 02fd2e97f2c8a53bf2344e6fa8b14769cb15ee38 (patch) | |
| tree | 5e2a56becf6ba6961995e541ce9688224f704773 /modules/notifpopups.tsx | |
| parent | popupwindow: switch to class (diff) | |
| download | caelestia-shell-02fd2e97f2c8a53bf2344e6fa8b14769cb15ee38.tar.gz caelestia-shell-02fd2e97f2c8a53bf2344e6fa8b14769cb15ee38.tar.bz2 caelestia-shell-02fd2e97f2c8a53bf2344e6fa8b14769cb15ee38.zip | |
refactor: move ts to src
Also move popupwindow to own file
Diffstat (limited to 'modules/notifpopups.tsx')
| -rw-r--r-- | modules/notifpopups.tsx | 177 |
1 files changed, 0 insertions, 177 deletions
diff --git a/modules/notifpopups.tsx b/modules/notifpopups.tsx deleted file mode 100644 index c3441a9..0000000 --- a/modules/notifpopups.tsx +++ /dev/null @@ -1,177 +0,0 @@ -import { GLib, register, timeout } from "astal"; -import { Astal, Gtk, Widget } from "astal/gtk3"; -import AstalNotifd from "gi://AstalNotifd"; -import { notifpopups as config } from "../config"; -import { desktopEntrySubs } from "../utils/icons"; -import { setupChildClickthrough } from "../utils/widgets"; - -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 AppIcon = ({ appIcon, desktopEntry }: { appIcon: string; desktopEntry: string }) => { - // Try app icon - let icon = Astal.Icon.lookup_icon(appIcon) && appIcon; - // Try desktop entry - if (!icon) { - if (desktopEntrySubs.hasOwnProperty(desktopEntry)) icon = desktopEntrySubs[desktopEntry]; - else if (Astal.Icon.lookup_icon(desktopEntry)) icon = desktopEntry; - } - return icon ? <icon className="app-icon" icon={icon} /> : null; -}; - -const Image = ({ icon }: { icon: string }) => { - if (GLib.file_test(icon, GLib.FileTest.EXISTS)) - return ( - <box - valign={Gtk.Align.START} - className="image" - css={` - background-image: url("${icon}"); - `} - /> - ); - if (Astal.Icon.lookup_icon(icon)) return <icon valign={Gtk.Align.START} className="image" icon={icon} />; - return null; -}; - -@register() -class NotifPopup extends Widget.Box { - readonly #revealer; - #destroyed = false; - - constructor({ notification }: { notification: AstalNotifd.Notification }) { - super(); - - this.#revealer = ( - <revealer revealChild transitionType={Gtk.RevealerTransitionType.SLIDE_DOWN} transitionDuration={150}> - <box className="wrapper"> - <box vertical className={`popup ${urgencyToString(notification.urgency)}`}> - <box className="header"> - <AppIcon appIcon={notification.appIcon} desktopEntry={notification.appName} /> - <label className="app-name" label={notification.appName ?? "Unknown"} /> - <box hexpand /> - <label - className="time" - label={getTime(notification.time)!} - setup={self => - timeout(60000, () => !this.#destroyed && (self.label = getTime(notification.time)!)) - } - /> - </box> - <box hexpand className="separator" /> - <box className="content"> - {notification.image && <Image icon={notification.image} />} - <box vertical> - <label className="summary" xalign={0} label={notification.summary} truncate /> - <label className="body" xalign={0} label={notification.body} wrap useMarkup /> - </box> - </box> - <box className="actions"> - <button hexpand cursor="pointer" onClicked={() => notification.dismiss()} label="Close" /> - {notification.actions.map(a => ( - <button hexpand cursor="pointer" onClicked={() => notification.invoke(a.id)}> - {notification.actionIcons ? <icon icon={a.label} /> : a.label} - </button> - ))} - </box> - </box> - </box> - </revealer> - ) 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: 300ms cubic-bezier(0.05, 0.9, 0.1, 1.1); margin-left: 0; margin-right: 0;`; - }); - - // Close popup after timeout if transient or expire enabled in config - if (config.expire || notification.transient) - 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 () => ( - <window - namespace="caelestia-notifpopups" - anchor={Astal.WindowAnchor.TOP | Astal.WindowAnchor.RIGHT | Astal.WindowAnchor.BOTTOM} - > - <box - vertical - valign={Gtk.Align.START} - className="notifpopups" - setup={self => { - const notifd = AstalNotifd.get_default(); - const map = new Map<number, NotifPopup>(); - self.hook(notifd, "notified", (self, id) => { - const notification = notifd.get_notification(id); - - const popup = (<NotifPopup notification={notification} />) as NotifPopup; - popup.connect("destroy", () => map.get(notification.id) === popup && map.delete(notification.id)); - map.get(notification.id)?.destroyWithAnims(); - map.set(notification.id, popup); - - self.add( - <eventbox - // Dismiss on middle click - onClick={(_, event) => event.button === Astal.MouseButton.MIDDLE && notification.dismiss()} - // Close on hover lost - onHoverLost={() => popup.destroyWithAnims()} - > - {popup} - </eventbox> - ); - - // Limit number of popups - if (config.maxPopups > 0 && self.children.length > config.maxPopups) - map.values().next().value?.destroyWithAnims(); - }); - self.hook(notifd, "resolved", (_, id) => map.get(id)?.destroyWithAnims()); - - // Change input region to child region so can click through empty space - setupChildClickthrough(self); - }} - /> - </window> -); |