From 9358f8fe6e6d03cba679e48d23de1ea6edbec521 Mon Sep 17 00:00:00 2001 From: Damocles Date: Mon, 13 Apr 2026 15:35:12 +0200 Subject: [PATCH 1/3] notifications: disableable popups, configurable max popup count --- modules/Modules.qml | 4 +++- modules/NotifPopup.qml | 2 +- modules/NotifService.qml | 9 +++++++++ nix/hm-module.nix | 10 ++++++++++ shell.qml | 7 +++++-- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/modules/Modules.qml b/modules/Modules.qml index c385754..3be68c1 100644 --- a/modules/Modules.qml +++ b/modules/Modules.qml @@ -21,7 +21,9 @@ QtObject { }) property var notifications: ({ enable: true, - timeout: 3000 + timeout: 3000, + popups: true, + maxPopups: 4 }) property var mpris: ({ enable: true diff --git a/modules/NotifPopup.qml b/modules/NotifPopup.qml index 09db576..0720c85 100644 --- a/modules/NotifPopup.qml +++ b/modules/NotifPopup.qml @@ -34,7 +34,7 @@ PanelWindow { property var _knownIds: ({}) Repeater { - model: M.NotifService.popups.slice(0, 4) + model: M.NotifService.popups.slice(0, M.Modules.notifications.maxPopups || 4) delegate: Item { id: popupItem diff --git a/modules/NotifService.qml b/modules/NotifService.qml index 5e408fb..130dbd7 100644 --- a/modules/NotifService.qml +++ b/modules/NotifService.qml @@ -83,6 +83,15 @@ QtObject { root.list = [data, ...root.list]; + // Dismiss excess popups (keep in history, just hide popup) + const max = M.Modules.notifications.maxPopups || 4; + const currentPopups = root.list.filter(n => n.popup && !n.closed); + if (currentPopups.length > max) { + for (let i = max; i < currentPopups.length; i++) + currentPopups[i].popup = false; + root._changed(); + } + // Auto-expire popup if (data.popup) { const timeout = notif.expireTimeout > 0 ? notif.expireTimeout : (M.Modules.notifications.timeout || 3000); diff --git a/nix/hm-module.nix b/nix/hm-module.nix index e7487bb..a62a401 100644 --- a/nix/hm-module.nix +++ b/nix/hm-module.nix @@ -98,6 +98,16 @@ in default = 3000; description = "Notification popup timeout in milliseconds."; }; + popups = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Show notification popups."; + }; + maxPopups = lib.mkOption { + type = lib.types.int; + default = 4; + description = "Maximum number of notification popups shown simultaneously."; + }; }; bluetooth = moduleOpt "bluetooth" (intervalOpt 5000); network = moduleOpt "network" (intervalOpt 5000); diff --git a/shell.qml b/shell.qml index e4c4f64..7467ef3 100644 --- a/shell.qml +++ b/shell.qml @@ -19,8 +19,11 @@ ShellRoot { screen: scope.modelData } - NotifPopup { - screen: scope.modelData + LazyLoader { + active: Modules.notifications.popups + NotifPopup { + screen: scope.modelData + } } LazyLoader { From a6d95ffdaf0b5f82e6309311baec1e49172994eb Mon Sep 17 00:00:00 2001 From: Damocles Date: Mon, 13 Apr 2026 15:36:54 +0200 Subject: [PATCH 2/3] notifications: derive popup enabled from maxPopups > 0 --- modules/Modules.qml | 1 - nix/hm-module.nix | 5 ----- shell.qml | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/modules/Modules.qml b/modules/Modules.qml index 3be68c1..3b5f0e9 100644 --- a/modules/Modules.qml +++ b/modules/Modules.qml @@ -22,7 +22,6 @@ QtObject { property var notifications: ({ enable: true, timeout: 3000, - popups: true, maxPopups: 4 }) property var mpris: ({ diff --git a/nix/hm-module.nix b/nix/hm-module.nix index a62a401..35a68e4 100644 --- a/nix/hm-module.nix +++ b/nix/hm-module.nix @@ -98,11 +98,6 @@ in default = 3000; description = "Notification popup timeout in milliseconds."; }; - popups = lib.mkOption { - type = lib.types.bool; - default = true; - description = "Show notification popups."; - }; maxPopups = lib.mkOption { type = lib.types.int; default = 4; diff --git a/shell.qml b/shell.qml index 7467ef3..3fc3674 100644 --- a/shell.qml +++ b/shell.qml @@ -20,7 +20,7 @@ ShellRoot { } LazyLoader { - active: Modules.notifications.popups + active: (Modules.notifications.maxPopups ?? 4) > 0 NotifPopup { screen: scope.modelData } From f65bd90bfd07c0322462c6230c5f624275cbffbf Mon Sep 17 00:00:00 2001 From: Damocles Date: Mon, 13 Apr 2026 15:41:57 +0200 Subject: [PATCH 3/3] notification center: swipe-right dismiss, cascading clear-all --- modules/NotifCenter.qml | 85 +++++++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 12 deletions(-) diff --git a/modules/NotifCenter.qml b/modules/NotifCenter.qml index 2507d56..1c1e5eb 100644 --- a/modules/NotifCenter.qml +++ b/modules/NotifCenter.qml @@ -58,12 +58,42 @@ M.PopupPanel { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor - onClicked: M.NotifService.dismissAll() + onClicked: menuWindow._cascadeDismiss() } } } } + property var _delegates: [] + + function _cascadeDismiss() { + const dels = _delegates.filter(d => d && d.modelData && !d.modelData.closed); + for (let i = 0; i < dels.length; i++) { + const d = dels[i]; + const delay = i * 60; + Qt.callLater(() => { + _cascadeTimer.createObject(menuWindow, { + _target: d, + _delay: delay + }); + }); + } + } + + property Component _cascadeTimer: Component { + Timer { + property var _target + property int _delay + interval: _delay + running: true + onTriggered: { + if (_target && _target._dismissAnim) + _target._dismissAnim.start(); + destroy(); + } + } + } + // Separator Rectangle { width: menuWindow.panelWidth - 16 @@ -82,10 +112,23 @@ M.PopupPanel { required property int index width: menuWindow.panelWidth - height: notifContent.height + 12 + height: _targetHeight * _heightScale opacity: 0 + clip: true + + readonly property real _targetHeight: notifContent.height + 12 + property real _heightScale: 1 + + Component.onCompleted: { + menuWindow._delegates.push(notifItem); + fadeIn.start(); + } + Component.onDestruction: { + const idx = menuWindow._delegates.indexOf(notifItem); + if (idx >= 0) + menuWindow._delegates.splice(idx, 1); + } - Component.onCompleted: fadeIn.start() NumberAnimation { id: fadeIn target: notifItem @@ -93,8 +136,6 @@ M.PopupPanel { to: 1 duration: 150 easing.type: Easing.OutCubic - // Stagger by index - Component.onCompleted: fadeIn.from = 0 } Rectangle { @@ -242,14 +283,34 @@ M.PopupPanel { } } - NumberAnimation { + SequentialAnimation { id: _dismissAnim - target: notifItem - property: "opacity" - to: 0 - duration: 150 - easing.type: Easing.InCubic - onFinished: M.NotifService.dismiss(notifItem.modelData.id) + ParallelAnimation { + NumberAnimation { + target: notifItem + property: "x" + to: menuWindow.panelWidth + duration: 200 + easing.type: Easing.InCubic + } + NumberAnimation { + target: notifItem + property: "opacity" + to: 0 + duration: 200 + easing.type: Easing.InCubic + } + } + NumberAnimation { + target: notifItem + property: "_heightScale" + to: 0 + duration: 150 + easing.type: Easing.OutCubic + } + ScriptAction { + script: M.NotifService.dismiss(notifItem.modelData.id) + } } MouseArea {