Krolyxon
Commit 071f97f

Branches

Refs →

aurora.configquickshellauroraNotifs.qml

71 lines · 2.5 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: true
14 property string soundFile: Quickshell.env("HOME") + "/.config/quickshell/aurora/sounds/Blow.aiff"
15 property real soundVolume: 0.7
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 var ms = n.urgency === NotificationUrgency.Critical ? 12000
43 : (n.expireTimeout > 0 ? n.expireTimeout * 1000 : 5000)
44 var next = popups.concat([{ n: n, until: Date.now() + ms }])
45 popups = next.slice(-4)
46 n.closed.connect(function () { root.dropPopup(n) })
47 }
48
49 NotificationServer {
50 id: server
51 keepOnReload: true
52 actionsSupported: true
53 bodyMarkupSupported: true
54 imageSupported: true
55 onNotification: n => {
56 n.tracked = true
57 if (!root.dnd || n.urgency === NotificationUrgency.Critical) root.push(n)
58 }
59 }
60
61 Timer {
62 interval: 500
63 running: root.popups.length > 0
64 repeat: true
65 onTriggered: {
66 var now = Date.now()
67 var keep = root.popups.filter(function (p) { return p.until > now })
68 if (keep.length !== root.popups.length) root.popups = keep
69 }
70 }
71}