Krolyxon
Commit 8fda16f

Branches

Refs →

aurora.configquickshellauroraNotifs.qml

72 lines · 2.6 KB · QML

1pragma Singleton
2import QtQuick
3import Quickshell
4import Quickshell.Services.Notifications
5
6// Native notification daemon: toasts + history + do-not-disturb.
7// Stop dunst/mako first, only one daemon can own org.freedesktop.Notifications.
8Singleton {
9 id: root
10 property bool dnd: false
11
12 // sound played on every toast (silenced by do-not-disturb, except critical ones)
13 property bool soundEnabled: Settings.notifSound
14 property string soundFile: Quickshell.env("HOME") + "/.config/quickshell/aurora/sounds/Blow.aiff"
15 property real soundVolume: Settings.notifVolume
16 property var popups: [] // [{n, until}]
17 readonly property var model: server.trackedNotifications
18 readonly property int count: server.trackedNotifications.values.length
19
20 function history() { // newest first
21 var l = server.trackedNotifications.values, out = []
22 for (var i = l.length - 1; i >= 0; i--) out.push(l[i])
23 return out
24 }
25 function clearAll() {
26 var l = server.trackedNotifications.values, all = []
27 for (var i = 0; i < l.length; i++) all.push(l[i])
28 for (var j = 0; j < all.length; j++) all[j].dismiss()
29 popups = []
30 }
31 function dropPopup(n) {
32 popups = popups.filter(function (p) { return p.n !== n })
33 }
34 function playSound() {
35 if (!soundEnabled) return
36 Quickshell.execDetached(["sh", "-c",
37 '[ -f "$1" ] || exit 0; pw-play --volume="$2" "$1" 2>/dev/null || paplay "$1" 2>/dev/null',
38 "sh", soundFile, String(soundVolume)])
39 }
40 function push(n) {
41 playSound()
42 // expireTimeout is already in ms; apps asking for less than 15s get less, never more
43 var ms = (n.urgency !== NotificationUrgency.Critical && n.expireTimeout > 0)
44 ? Math.min(n.expireTimeout, 15000) : 15000
45 var next = popups.concat([{ n: n, until: Date.now() + ms }])
46 popups = next.slice(-4)
47 n.closed.connect(function () { root.dropPopup(n) })
48 }
49
50 NotificationServer {
51 id: server
52 keepOnReload: true
53 actionsSupported: true
54 bodyMarkupSupported: true
55 imageSupported: true
56 onNotification: n => {
57 n.tracked = true
58 if (!root.dnd || n.urgency === NotificationUrgency.Critical) root.push(n)
59 }
60 }
61
62 Timer {
63 interval: 500
64 running: root.popups.length > 0
65 repeat: true
66 onTriggered: {
67 var now = Date.now()
68 var keep = root.popups.filter(function (p) { return p.until > now })
69 if (keep.length !== root.popups.length) root.popups = keep
70 }
71 }
72}