import QtQuick import QtMultimedia import Quickshell 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) } } property ObjectModel notifications: ObjectModel {} property int notificationCount: 0 property var lastNotification: null property bool hasCritical: false readonly property string soundDir: Config.configDir + "/assets/sounds" property var _dismissTimes: ({}) function onNotificationReceived(notification) { notifications.append(notification) notificationCount = notifications.count lastNotification = notification if (notification.urgency === NotificationUrgency.Critical) hasCritical = true playSound(notification.urgency) scheduleDismiss(notification) } function playSound(urgency) { var path var vol switch (urgency) { case NotificationUrgency.Low: path = soundDir + "/notification-low.oga" vol = 0.35 break case NotificationUrgency.Critical: path = soundDir + "/notification-critical.oga" vol = 1.0 break default: path = soundDir + "/notification-normal.oga" vol = 0.7 break } if (player.hasAudio) player.stop() player.source = "file://" + path audioOutput.volume = vol player.play() } 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) { for (var i = 0; i < notifications.count; i++) { if (notifications.get(i).id === notification.id) { notifications.remove(i) break } } notificationCount = notifications.count delete _dismissTimes[notification.id] if (notificationCount === 0) { hasCritical = false lastNotification = null } else { lastNotification = notifications.get(0) hasCritical = false for (var j = 0; j < notifications.count; j++) { if (notifications.get(j).urgency === NotificationUrgency.Critical) { hasCritical = true break } } } notification.tracked = false } function dismissById(nid) { for (var i = 0; i < notifications.count; i++) { var n = notifications.get(i) if (n.id === nid) { dismissNotification(n) return } } } function dismissAll() { while (notifications.count > 0) { var n = notifications.get(0) dismissNotification(n) } } Timer { id: refreshTimer interval: 1000 repeat: true onTriggered: { var now = Date.now() / 1000 var toDismiss = [] for (var i = 0; i < notifications.count; i++) { var n = notifications.get(i) var t = _dismissTimes[n.id] if (t !== undefined && now >= t) toDismiss.push(n) } for (var j = 0; j < toDismiss.length; j++) dismissNotification(toDismiss[j]) if (notifications.count === 0) running = false } } MediaPlayer { id: player audioOutput: AudioOutput { id: audioOutput } } }