pragma Singleton pragma ComponentBehavior: Bound import Quickshell import Quickshell.Io import Quickshell.Services.Notifications import ZShell.Services import qs.Components import qs.Helpers import qs.Paths import qs.Services import ZShell.Config Singleton { id: root readonly property var appCooldownMap: new Map() property alias dnd: props.dnd property alias list: store.rows readonly property list notClosed: store.rows.filter(n => !n.closed) readonly property list popups: store.rows.filter(n => n.popup) function shouldThrottle(appName: string): bool { if (props.dnd || ShellState.anySidebarOpen()) return false; const key = (appName || "unknown").trim().toLowerCase(); const cooldownSec = Config.notifs.appNotifCooldown; const cooldownMs = Math.max(0, cooldownSec * 1000); if (cooldownMs <= 0) return true; const now = Date.now(); const until = appCooldownMap.get(key) ?? 0; if (now < until) return false; appCooldownMap.set(key, now + cooldownMs); return true; } PersistentProperties { id: props property bool dnd reloadableId: "notifs" } NotificationStore { id: store path: `${Paths.state}/notifs.sqlite` } NotificationServer { id: server actionsSupported: true bodyHyperlinksSupported: true bodyImagesSupported: true bodyMarkupSupported: true imageSupported: true keepOnReload: true persistenceSupported: true onNotification: notif => { notif.tracked = true; store.insert(notif, root.shouldThrottle(notif.appName)); } } CustomShortcut { description: "Clear all notifications" name: "clearnotifs" onPressed: store.clear() } IpcHandler { function clear(): void { store.clear(); } function disableDnd(): void { props.dnd = false; } function enableDnd(): void { props.dnd = true; } function isDndEnabled(): bool { return props.dnd; } function toggleDnd(): void { props.dnd = !props.dnd; } target: "notifs" } }