dotfiles/home/ags/files/notifications/NotificationPopups.tsx

66 lines
2.5 KiB
TypeScript

import app from "ags/gtk4/app"
import { Astal, Gtk } from "ags/gtk4"
import AstalNotifd from "gi://AstalNotifd"
import Notification from "./Notification"
import { createBinding, For, createState, onCleanup } from "ags"
export default function NotificationPopups() {
const monitors = createBinding(app, "monitors")
const notifd = AstalNotifd.get_default()
const [notifications, setNotifications] = createState(
new Array<AstalNotifd.Notification>(),
)
const notifiedHandler = notifd.connect("notified", (_, id, replaced) => {
const notification = notifd.get_notification(id)
if (replaced && notifications.get().some(n => n.id === id)) {
setNotifications((ns) => ns.map((n) => (n.id === id ? notification : n)))
} else {
setNotifications((ns) => [notification, ...ns])
}
})
const resolvedHandler = notifd.connect("resolved", (_, id) => {
setNotifications((ns) => ns.filter((n) => n.id !== id))
})
// technically, we don't need to cleanup because in this example this is a root component
// and this cleanup function is only called when the program exits, but exiting will cleanup either way
// but it's here to remind you that you should not forget to cleanup signal connections
onCleanup(() => {
notifd.disconnect(notifiedHandler)
notifd.disconnect(resolvedHandler)
})
return (
<For each={monitors} cleanup={(win) => (win as Gtk.Window).destroy()}>
{(monitor) => (
<window
class="NotificationPopups"
gdkmonitor={monitor}
visible={notifications((ns) => ns.length > 0)}
anchor={Astal.WindowAnchor.TOP | Astal.WindowAnchor.RIGHT}
>
<box orientation={Gtk.Orientation.VERTICAL}>
<For each={notifications}>
{(notification) => (
<Notification
notification={notification}
onHoverLost={() =>
setNotifications((ns) =>
ns.filter((n) => n.id !== notification.id),
)
}
/>
)}
</For>
</box>
</window>
)}
</For>
)
}