diff --git a/.config/quickshell/modules/common/widgets/NotificationAppIcon.qml b/.config/quickshell/modules/common/widgets/NotificationAppIcon.qml index 5a218d8f9..371093b25 100644 --- a/.config/quickshell/modules/common/widgets/NotificationAppIcon.qml +++ b/.config/quickshell/modules/common/widgets/NotificationAppIcon.qml @@ -14,7 +14,8 @@ Rectangle { // App icon property var summary: "" property var urgency: NotificationUrgency.Normal property var image: "" - property real size: 45 + property real scale: 1 + property real size: 45 * scale property real materialIconScale: 0.57 property real appIconScale: 0.7 property real smallAppIconScale: 0.49 diff --git a/.config/quickshell/modules/common/widgets/NotificationGroup.qml b/.config/quickshell/modules/common/widgets/NotificationGroup.qml index 7b1381dd3..14f29920e 100644 --- a/.config/quickshell/modules/common/widgets/NotificationGroup.qml +++ b/.config/quickshell/modules/common/widgets/NotificationGroup.qml @@ -152,14 +152,17 @@ Item { // Notification group area NotificationAppIcon { // Icons Layout.alignment: Qt.AlignTop Layout.fillWidth: false - + image: root.multipleNotifications ? "" : notificationGroup.notifications[0].image appIcon: notificationGroup.appIcon summary: notificationGroup.notifications[root.notificationCount - 1].summary } ColumnLayout { // Content Layout.fillWidth: true - spacing: expanded ? 5 : 0 + spacing: expanded ? + ((root.multipleNotifications && + notificationGroup.notifications[root.notificationCount - 1].image != "") ? 35 : + 5) : 0 Behavior on spacing { animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) } diff --git a/.config/quickshell/modules/common/widgets/NotificationItem.qml b/.config/quickshell/modules/common/widgets/NotificationItem.qml index ada5a95ff..fca48a542 100644 --- a/.config/quickshell/modules/common/widgets/NotificationItem.qml +++ b/.config/quickshell/modules/common/widgets/NotificationItem.qml @@ -23,7 +23,7 @@ Item { // Notification item area property real padding: 8 property real dragConfirmThreshold: 70 // Drag further to discard notification - property real dismissOvershoot: 20 // Account for gaps and bouncy animations + property real dismissOvershoot: notificationIcon.implicitWidth + 20 // Account for gaps and bouncy animations property var qmlParent: root?.parent?.parent // There's something between this and the parent ListView property var parentDragIndex: qmlParent?.dragIndex ?? -1 property var parentDragDistance: qmlParent?.dragDistance ?? 0 @@ -89,6 +89,21 @@ Item { // Notification item area } } + NotificationAppIcon { // App icon + id: notificationIcon + opacity: (!onlyNotification && notificationObject.image != "" && expanded) ? 1 : 0 + visible: opacity > 0 + + Behavior on opacity { + animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) + } + + image: notificationObject.image + anchors.right: background.left + anchors.top: background.top + anchors.rightMargin: 10 + } + Rectangle { // Background of notification item id: background width: parent.width diff --git a/.config/quickshell/services/Notifications.qml b/.config/quickshell/services/Notifications.qml index 81161dab5..67b2351e5 100644 --- a/.config/quickshell/services/Notifications.qml +++ b/.config/quickshell/services/Notifications.qml @@ -15,9 +15,22 @@ Singleton { property var list: [] property var popupList: [] property bool popupInhibited: GlobalStates?.sidebarRightOpen ?? false - // Quickshell's notification IDs starts at 1 on each run, while saved notifications - // can already contain higher IDs. This is for avoiding id collisions - property int idOffset + property var latestTimeForApp: ({}) + + onListChanged: { + // Update latest time for each app + root.list.forEach((notif) => { + if (!root.latestTimeForApp[notif.appName] || notif.time > root.latestTimeForApp[notif.appName]) { + root.latestTimeForApp[notif.appName] = Math.max(root.latestTimeForApp[notif.appName] || 0, notif.time); + } + }); + // Remove apps that no longer have notifications + Object.keys(root.latestTimeForApp).forEach((appName) => { + if (!root.list.some((notif) => notif.appName === appName)) { + delete root.latestTimeForApp[appName]; + } + }); + } function appNameListForGroups(groups) { return Object.keys(groups).sort((a, b) => { @@ -39,7 +52,7 @@ Singleton { } groups[notif.appName].notifications.push(notif); // Always set to the latest time in the group - groups[notif.appName].time = notif.time; + groups[notif.appName].time = latestTimeForApp[notif.appName] || notif.time; }); return groups; } @@ -49,6 +62,9 @@ Singleton { property var appNameList: appNameListForGroups(root.groupsByAppName) property var popupAppNameList: appNameListForGroups(root.popupGroupsByAppName) + // Quickshell's notification IDs starts at 1 on each run, while saved notifications + // can already contain higher IDs. This is for avoiding id collisions + property int idOffset signal initDone(); signal notify(notification: var); signal discard(id: var); @@ -87,7 +103,9 @@ Singleton { } root.list = [...root.list, newNotifObject]; // console.log(root.popupInhibited) - if (!root.popupInhibited) root.popupList = [...root.popupList, newNotifObject]; + if (!root.popupInhibited) { + root.popupList = [...root.popupList, newNotifObject]; + } root.notify(newNotifObject); notifFileView.setText(JSON.stringify(root.list, null, 2)) }