From ed05e9af2515c3c1c09becae5b405fc5074aa5e9 Mon Sep 17 00:00:00 2001
From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>
Date: Thu, 16 Jan 2025 18:47:23 +1100
Subject: notifications: make popup window
---
src/modules/bar.tsx | 77 +++++++++++++++++++++------------------
src/modules/notifications.tsx | 84 +++++++++++++++++++++++++------------------
src/modules/notifpopups.tsx | 10 +++++-
src/widgets/notification.tsx | 11 ++++--
src/widgets/popupwindow.ts | 5 +--
5 files changed, 112 insertions(+), 75 deletions(-)
(limited to 'src')
diff --git a/src/modules/bar.tsx b/src/modules/bar.tsx
index b56d94a..aeb6e42 100644
--- a/src/modules/bar.tsx
+++ b/src/modules/bar.tsx
@@ -15,6 +15,7 @@ import { getAppCategoryIcon } from "../utils/icons";
import { ellipsize } from "../utils/strings";
import { osIcon } from "../utils/system";
import { setupCustomTooltip } from "../utils/widgets";
+import type PopupWindow from "../widgets/popupwindow";
const hyprland = AstalHyprland.get_default();
@@ -385,11 +386,19 @@ const PkgUpdates = () => (
);
-const Notifications = () => {
+const Unread = () => {
const unreadCount = Variable(0);
return (
- {
+ if (event.button === Astal.MouseButton.PRIMARY) {
+ const popup = App.get_window("notifications") as PopupWindow | null;
+ if (popup) {
+ if (popup.visible) popup.hide();
+ else popup.popup_at_widget(self, event);
+ }
+ } else if (event.button === Astal.MouseButton.SECONDARY) unreadCount.set(0);
+ }}
setup={self =>
setupCustomTooltip(
self,
@@ -397,39 +406,37 @@ const Notifications = () => {
)
}
>
-
-
+
);
};
@@ -491,7 +498,7 @@ export default ({ monitor }: { monitor: Monitor }) => (
-
+
diff --git a/src/modules/notifications.tsx b/src/modules/notifications.tsx
index 66188a1..ea98ada 100644
--- a/src/modules/notifications.tsx
+++ b/src/modules/notifications.tsx
@@ -1,6 +1,8 @@
-import { Gtk } from "astal/gtk3";
+import { bind } from "astal";
+import { Astal, Gtk } from "astal/gtk3";
import AstalNotifd from "gi://AstalNotifd";
-import { PopupWindow, setupChildClickthrough } from "../utils/widgets";
+import Notification from "../widgets/notification";
+import PopupWindow from "../widgets/popupwindow";
const List = () => (
(
className="list"
setup={self => {
const notifd = AstalNotifd.get_default();
- const map = new Map();
- self.hook(notifd, "notified", (self, id) => {
- const notification = notifd.get_notification(id);
+ const map = new Map();
- const popup = () as NotifPopup;
- popup.connect("destroy", () => map.get(notification.id) === popup && map.delete(notification.id));
+ const addNotification = (notification: AstalNotifd.Notification) => {
+ const notif = () as Notification;
+ notif.connect("destroy", () => map.get(notification.id) === notif && map.delete(notification.id));
map.get(notification.id)?.destroyWithAnims();
- map.set(notification.id, popup);
+ map.set(notification.id, notif);
- self.add(
+ self.pack_end(
event.button === Astal.MouseButton.MIDDLE && notification.dismiss()}
- // Close on hover lost
- onHoverLost={() => popup.destroyWithAnims()}
>
- {popup}
-
+ {notif}
+ ,
+ false,
+ false,
+ 0
);
+ };
- // 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());
+ notifd
+ .get_notifications()
+ .sort((a, b) => a.time - b.time)
+ .forEach(addNotification);
- // Change input region to child region so can click through empty space
- setupChildClickthrough(self);
+ self.hook(notifd, "notified", (_, id) => addNotification(notifd.get_notification(id)));
+ self.hook(notifd, "resolved", (_, id) => map.get(id)?.destroyWithAnims());
}}
/>
);
-export default class Notifications extends PopupWindow {
- constructor() {
- super({
- name: "notifications",
- child: (
-
-
-
- ),
- });
-
- setupChildClickthrough(self);
- }
-}
+export default () => (
+
+
+
+ `${n.length} notification${n.length === 1 ? "" : "s"}`
+ )}
+ />
+
+
+
+
+
+
+
+);
diff --git a/src/modules/notifpopups.tsx b/src/modules/notifpopups.tsx
index 5da3092..9e34549 100644
--- a/src/modules/notifpopups.tsx
+++ b/src/modules/notifpopups.tsx
@@ -1,4 +1,4 @@
-import { Astal, Gtk } from "astal/gtk3";
+import { App, Astal, Gtk } from "astal/gtk3";
import AstalNotifd from "gi://AstalNotifd";
import { notifpopups as config } from "../../config";
import { setupChildClickthrough } from "../utils/widgets";
@@ -16,7 +16,11 @@ export default () => (
setup={self => {
const notifd = AstalNotifd.get_default();
const map = new Map();
+ let notifsOpen = false;
+
self.hook(notifd, "notified", (self, id) => {
+ if (notifsOpen) return;
+
const notification = notifd.get_notification(id);
const popup = () as Notification;
@@ -41,6 +45,10 @@ export default () => (
});
self.hook(notifd, "resolved", (_, id) => map.get(id)?.destroyWithAnims());
+ self.hook(App, "window-toggled", (_, window) => {
+ if (window.name === "notifications") notifsOpen = window.visible;
+ });
+
// Change input region to child region so can click through empty space
setupChildClickthrough(self);
}}
diff --git a/src/widgets/notification.tsx b/src/widgets/notification.tsx
index 0bef5ca..adac831 100644
--- a/src/widgets/notification.tsx
+++ b/src/widgets/notification.tsx
@@ -57,12 +57,16 @@ export default class Notification extends Widget.Box {
#destroyed = false;
constructor({ notification, popup }: { notification: AstalNotifd.Notification; popup?: boolean }) {
- super();
+ super({ className: "notification" });
this.#revealer = (
-
+
-
+
@@ -101,6 +105,7 @@ export default class Notification extends Widget.Box {
const width = this.get_preferred_width()[1];
this.css = `margin-left: ${width}px; margin-right: -${width}px;`;
timeout(1, () => {
+ this.#revealer.revealChild = true;
this.css = `transition: 300ms cubic-bezier(0.05, 0.9, 0.1, 1.1); margin-left: 0; margin-right: 0;`;
});
diff --git a/src/widgets/popupwindow.ts b/src/widgets/popupwindow.ts
index 67aa0ff..9f5192e 100644
--- a/src/widgets/popupwindow.ts
+++ b/src/widgets/popupwindow.ts
@@ -28,10 +28,11 @@ export default class PopupWindow extends Widget.Window {
});
}
- popup_at_widget(widget: JSX.Element, event: Gdk.Event) {
+ popup_at_widget(widget: JSX.Element, event: Gdk.Event | Astal.ClickEvent) {
const { width, height } = widget.get_allocation();
- const [_, x, y] = event.get_coords();
+ const [_, x, y] = event instanceof Gdk.Event ? event.get_coords() : [null, event.x, event.y];
const { x: cx, y: cy } = AstalHyprland.get_default().get_cursor_position();
+ this.anchor = Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT;
this.marginLeft = cx + ((width - this.get_preferred_width()[1]) / 2 - x);
this.marginTop = cy + (height - y);
this.show();
--
cgit v1.2.3-freya