From d4001f79001c99bb08b66d9cee758803f20fdc47 Mon Sep 17 00:00:00 2001 From: Damocles Date: Wed, 29 Apr 2026 17:58:26 +0200 Subject: [PATCH] notifications: centralize icon resolution in NotifItem.resolvedIcon, fix lock pill grouping and missing fallbacks --- shell/applets/NotifApplet.qml | 16 +++++----------- shell/lock/LockNotifPills.qml | 16 +++++----------- shell/modules/NotifCard.qml | 11 +---------- shell/services/NotifItem.qml | 12 ++++++++++++ 4 files changed, 23 insertions(+), 32 deletions(-) diff --git a/shell/applets/NotifApplet.qml b/shell/applets/NotifApplet.qml index 0864da5..5280810 100644 --- a/shell/applets/NotifApplet.qml +++ b/shell/applets/NotifApplet.qml @@ -1,5 +1,4 @@ import QtQuick -import Quickshell import "../services" as S import "../modules" as M @@ -76,12 +75,14 @@ Column { if (!map[key]) map[key] = { appName: key, - appIcon: n.appIcon, + resolvedIcon: "", notifs: [], maxUrgency: 0, maxTime: 0 }; map[key].notifs.push(n); + if (!map[key].resolvedIcon && n.resolvedIcon) + map[key].resolvedIcon = n.resolvedIcon; if (n.urgency > map[key].maxUrgency) map[key].maxUrgency = n.urgency; if (n.time > map[key].maxTime) @@ -101,7 +102,7 @@ Column { arr.push({ type: "header", appName: g.appName, - appIcon: g.appIcon, + resolvedIcon: g.resolvedIcon, count: g.notifs.length, collapsed: collapsed, summaries: g.notifs.map(n => n.summary || "") @@ -299,14 +300,7 @@ Column { anchors.topMargin: (28 - height) / 2 width: S.Theme.fontSize + 2 height: S.Theme.fontSize + 2 - source: { - if (notifDelegate._type !== "header") - return ""; - const ic = notifDelegate.modelData.appIcon; - if (!ic) - return ""; - return (ic.startsWith("/") || ic.startsWith("file://")) ? ic : Quickshell.iconPath(ic, "dialog-information"); - } + source: notifDelegate._type === "header" ? (notifDelegate.modelData.resolvedIcon || "") : "" visible: status === Image.Ready fillMode: Image.PreserveAspectFit sourceSize: Qt.size(S.Theme.fontSize + 2, S.Theme.fontSize + 2) diff --git a/shell/lock/LockNotifPills.qml b/shell/lock/LockNotifPills.qml index 35cf4ad..82025bd 100644 --- a/shell/lock/LockNotifPills.qml +++ b/shell/lock/LockNotifPills.qml @@ -1,5 +1,4 @@ import QtQuick -import Quickshell import "../services" as S Row { @@ -12,13 +11,15 @@ Row { const notifs = S.NotifService.list.filter(n => n.state !== "dismissed"); const groups = {}; for (const n of notifs) { - const key = n.appIcon || n.appName || "unknown"; + const key = n.appName || "unknown"; if (!groups[key]) groups[key] = { - icon: n.appIcon, + resolvedIcon: "", name: n.appName, count: 0 }; + if (!groups[key].resolvedIcon && n.resolvedIcon) + groups[key].resolvedIcon = n.resolvedIcon; groups[key].count++; } return Object.values(groups); @@ -62,14 +63,7 @@ Row { anchors.verticalCenter: parent.verticalCenter width: 14 height: 14 - source: { - const icon = _pill.modelData.icon; - if (!icon) - return ""; - if (icon.startsWith("/")) - return icon; - return Quickshell.iconPath(icon) ?? ""; - } + source: _pill.modelData.resolvedIcon || "" sourceSize: Qt.size(14, 14) visible: source !== "" } diff --git a/shell/modules/NotifCard.qml b/shell/modules/NotifCard.qml index df988b7..10e7630 100644 --- a/shell/modules/NotifCard.qml +++ b/shell/modules/NotifCard.qml @@ -1,5 +1,4 @@ import QtQuick -import Quickshell import Quickshell.Services.Notifications import "." as M import "../services" as S @@ -87,15 +86,7 @@ Item { anchors.topMargin: 8 width: root.iconSize height: root.iconSize - source: { - const img = root.notif?.image; - if (img) - return img; - const ic = root.notif?.appIcon; - if (!ic) - return ""; - return (ic.startsWith("/") || ic.startsWith("file://")) ? ic : Quickshell.iconPath(ic, "dialog-information"); - } + source: root.notif?.resolvedIcon ?? "" visible: status === Image.Ready fillMode: Image.PreserveAspectFit sourceSize: Qt.size(root.iconSize, root.iconSize) diff --git a/shell/services/NotifItem.qml b/shell/services/NotifItem.qml index 488f48a..191170e 100644 --- a/shell/services/NotifItem.qml +++ b/shell/services/NotifItem.qml @@ -1,4 +1,5 @@ import QtQuick +import Quickshell import Quickshell.Services.Notifications import "." as S @@ -20,6 +21,17 @@ QtObject { property var actions: [] property real time: Date.now() + // Resolved icon URL - checks image first, then resolves appIcon via XDG lookup + readonly property string resolvedIcon: { + if (image) + return image; + if (!appIcon) + return ""; + if (appIcon.startsWith("/") || appIcon.startsWith("file://")) + return appIcon; + return Quickshell.iconPath(appIcon, "dialog-information"); + } + // Expire timer — owned by this item, not dynamically created readonly property Timer _expireTimer: Timer { running: false