Files
quickshell/modules/notifications/NotificationManager.qml
T
2026-07-17 20:03:04 +00:00

130 lines
3.7 KiB
QML

import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Services.Notifications
import "../../config"
Item {
id: root
NotificationServer {
id: notificationServer
imageSupported: true
actionsSupported: true
bodyMarkupSupported: false
onNotification: (notification) => {
notification.tracked = true
root.onNotificationReceived(notification)
}
}
readonly property ObjectModel notifications: notificationServer.trackedNotifications
property int notificationCount: 0
property var lastNotification: null
property bool hasCritical: false
readonly property string soundDir: Config.configDir + "/assets/sounds"
property var _trackedIds: ({})
property var _dismissTimes: ({})
function onNotificationReceived(notification) {
_trackedIds[notification.id] = true
notificationCount = Object.keys(_trackedIds).length
lastNotification = notification
if (notification.urgency === NotificationUrgency.Critical)
hasCritical = true
playSound(notification.urgency)
scheduleDismiss(notification)
}
function playSound(urgency) {
var path
switch (urgency) {
case NotificationUrgency.Low:
path = soundDir + "/notification-low.oga"
break
case NotificationUrgency.Critical:
path = soundDir + "/notification-critical.oga"
break
default:
path = soundDir + "/notification-normal.oga"
break
}
soundProc.command = [
"sh", "-c",
"pw-play \"" + path + "\" 2>/dev/null || paplay \"" + path + "\" 2>/dev/null || ffplay -nodisp -autoexit \"" + path + "\" 2>/dev/null"
]
soundProc.running = true
}
function scheduleDismiss(notification) {
var timeout = notification.expireTimeout
if (timeout <= 0) {
if (notification.urgency === NotificationUrgency.Critical)
timeout = 60
else
timeout = 5
}
_dismissTimes[notification.id] = Date.now() / 1000 + timeout
if (!refreshTimer.running)
refreshTimer.running = true
}
function dismissNotification(notification) {
delete _trackedIds[notification.id]
delete _dismissTimes[notification.id]
notificationCount = Object.keys(_trackedIds).length
notification.tracked = false
refreshMetadata()
}
function refreshMetadata() {
hasCritical = false
lastNotification = null
for (var i = 0; i < notifications.count; i++) {
var n = notifications.get(i)
if (_trackedIds[n.id]) {
lastNotification = n
if (n.urgency === NotificationUrgency.Critical)
hasCritical = true
}
}
if (notificationCount === 0) {
hasCritical = false
lastNotification = null
}
}
Timer {
id: refreshTimer
interval: 1000
repeat: true
onTriggered: {
var now = Date.now() / 1000
for (var id in _dismissTimes) {
if (_dismissTimes[id] <= now) {
for (var i = 0; i < notifications.count; i++) {
var n = notifications.get(i)
if (n.id.toString() === id) {
dismissNotification(n)
break
}
}
}
}
if (Object.keys(_trackedIds).length === 0)
running = false
}
}
Process {
id: soundProc
running: false
}
}