This commit is contained in:
Your Name
2026-07-17 20:03:04 +00:00
parent 880ee3974f
commit d4c5dfc135
4 changed files with 52 additions and 71 deletions
+4 -4
View File
@@ -1,7 +1,6 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import Quickshell.Widgets
import "../../config" import "../../config"
Rectangle { Rectangle {
@@ -78,13 +77,14 @@ Rectangle {
height: 28 height: 28
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
IconImage { Image {
id: notifIcon id: notifIcon
anchors.fill: parent anchors.fill: parent
icon: notification.appIcon source: notification.appIcon ? "file://" + notification.appIcon : ""
sourceSize.width: 28 sourceSize.width: 28
sourceSize.height: 28 sourceSize.height: 28
visible: notification.appIcon !== "" asynchronous: true
visible: status === Image.Ready
} }
Text { Text {
@@ -1,7 +1,6 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import Quickshell.Widgets
import "../../config" import "../../config"
MouseArea { MouseArea {
@@ -44,13 +43,15 @@ MouseArea {
height: Config.iconSize(indicator.height) height: Config.iconSize(indicator.height)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
IconImage { Image {
id: notifIcon id: notifIcon
anchors.fill: parent anchors.fill: parent
icon: manager.lastNotification ? manager.lastNotification.appIcon : "" source: (manager.lastNotification && manager.lastNotification.appIcon)
? "file://" + manager.lastNotification.appIcon : ""
sourceSize.width: Config.iconSize(indicator.height) sourceSize.width: Config.iconSize(indicator.height)
sourceSize.height: Config.iconSize(indicator.height) sourceSize.height: Config.iconSize(indicator.height)
visible: manager.lastNotification && manager.lastNotification.appIcon !== "" asynchronous: true
visible: status === Image.Ready
} }
Text { Text {
@@ -159,9 +160,7 @@ MouseArea {
radius: Config.small_radius radius: Config.small_radius
color: Qt.alpha(Colors.surfaceContainerHighest, 0.5) color: Qt.alpha(Colors.surfaceContainerHighest, 0.5)
required property var model property var notif: modelData
property var notif: model.object
Row { Row {
anchors { anchors {
+41 -59
View File
@@ -1,6 +1,6 @@
import QtQuick import QtQuick
import QtMultimedia
import Quickshell import Quickshell
import Quickshell.Io
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import "../../config" import "../../config"
@@ -9,6 +9,7 @@ Item {
NotificationServer { NotificationServer {
id: notificationServer id: notificationServer
imageSupported: true imageSupported: true
actionsSupported: true actionsSupported: true
bodyMarkupSupported: false bodyMarkupSupported: false
@@ -19,18 +20,20 @@ Item {
} }
} }
property ObjectModel notifications: ObjectModel {} readonly property ObjectModel notifications: notificationServer.trackedNotifications
property int notificationCount: 0 property int notificationCount: 0
property var lastNotification: null property var lastNotification: null
property bool hasCritical: false property bool hasCritical: false
readonly property string soundDir: Config.configDir + "/assets/sounds" readonly property string soundDir: Config.configDir + "/assets/sounds"
property var _trackedIds: ({})
property var _dismissTimes: ({}) property var _dismissTimes: ({})
function onNotificationReceived(notification) { function onNotificationReceived(notification) {
notifications.append(notification) _trackedIds[notification.id] = true
notificationCount = notifications.count notificationCount = Object.keys(_trackedIds).length
lastNotification = notification lastNotification = notification
if (notification.urgency === NotificationUrgency.Critical) if (notification.urgency === NotificationUrgency.Critical)
hasCritical = true hasCritical = true
@@ -41,26 +44,22 @@ Item {
function playSound(urgency) { function playSound(urgency) {
var path var path
var vol
switch (urgency) { switch (urgency) {
case NotificationUrgency.Low: case NotificationUrgency.Low:
path = soundDir + "/notification-low.oga" path = soundDir + "/notification-low.oga"
vol = 0.35
break break
case NotificationUrgency.Critical: case NotificationUrgency.Critical:
path = soundDir + "/notification-critical.oga" path = soundDir + "/notification-critical.oga"
vol = 1.0
break break
default: default:
path = soundDir + "/notification-normal.oga" path = soundDir + "/notification-normal.oga"
vol = 0.7
break break
} }
soundProc.command = [
if (player.hasAudio) player.stop() "sh", "-c",
player.source = "file://" + path "pw-play \"" + path + "\" 2>/dev/null || paplay \"" + path + "\" 2>/dev/null || ffplay -nodisp -autoexit \"" + path + "\" 2>/dev/null"
audioOutput.volume = vol ]
player.play() soundProc.running = true
} }
function scheduleDismiss(notification) { function scheduleDismiss(notification) {
@@ -77,44 +76,27 @@ Item {
} }
function dismissNotification(notification) { 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++) { for (var i = 0; i < notifications.count; i++) {
if (notifications.get(i).id === notification.id) { var n = notifications.get(i)
notifications.remove(i) if (_trackedIds[n.id]) {
break lastNotification = n
if (n.urgency === NotificationUrgency.Critical)
hasCritical = true
} }
} }
notificationCount = notifications.count
delete _dismissTimes[notification.id]
if (notificationCount === 0) { if (notificationCount === 0) {
hasCritical = false hasCritical = false
lastNotification = null 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)
} }
} }
@@ -124,24 +106,24 @@ Item {
repeat: true repeat: true
onTriggered: { onTriggered: {
var now = Date.now() / 1000 var now = Date.now() / 1000
var toDismiss = [] for (var id in _dismissTimes) {
for (var i = 0; i < notifications.count; i++) { if (_dismissTimes[id] <= now) {
var n = notifications.get(i) for (var i = 0; i < notifications.count; i++) {
var t = _dismissTimes[n.id] var n = notifications.get(i)
if (t !== undefined && now >= t) if (n.id.toString() === id) {
toDismiss.push(n) dismissNotification(n)
break
}
}
}
} }
for (var j = 0; j < toDismiss.length; j++) if (Object.keys(_trackedIds).length === 0)
dismissNotification(toDismiss[j])
if (notifications.count === 0)
running = false running = false
} }
} }
MediaPlayer { Process {
id: player id: soundProc
audioOutput: AudioOutput { running: false
id: audioOutput
}
} }
} }
+1 -1
View File
@@ -62,7 +62,7 @@ Variants {
delegate: NotificationCard { delegate: NotificationCard {
width: contentColumn.width width: contentColumn.width
notification: model.object notification: modelData
manager: root.manager manager: root.manager
} }
} }