Compare commits

..

3 commits

6 changed files with 95 additions and 16 deletions

View file

@ -21,7 +21,8 @@ QtObject {
}) })
property var notifications: ({ property var notifications: ({
enable: true, enable: true,
timeout: 3000 timeout: 3000,
maxPopups: 4
}) })
property var mpris: ({ property var mpris: ({
enable: true enable: true

View file

@ -58,12 +58,42 @@ M.PopupPanel {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor 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 // Separator
Rectangle { Rectangle {
width: menuWindow.panelWidth - 16 width: menuWindow.panelWidth - 16
@ -82,10 +112,23 @@ M.PopupPanel {
required property int index required property int index
width: menuWindow.panelWidth width: menuWindow.panelWidth
height: notifContent.height + 12 height: _targetHeight * _heightScale
opacity: 0 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 { NumberAnimation {
id: fadeIn id: fadeIn
target: notifItem target: notifItem
@ -93,8 +136,6 @@ M.PopupPanel {
to: 1 to: 1
duration: 150 duration: 150
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
// Stagger by index
Component.onCompleted: fadeIn.from = 0
} }
Rectangle { Rectangle {
@ -242,14 +283,34 @@ M.PopupPanel {
} }
} }
NumberAnimation { SequentialAnimation {
id: _dismissAnim id: _dismissAnim
target: notifItem ParallelAnimation {
property: "opacity" NumberAnimation {
to: 0 target: notifItem
duration: 150 property: "x"
easing.type: Easing.InCubic to: menuWindow.panelWidth
onFinished: M.NotifService.dismiss(notifItem.modelData.id) 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 { MouseArea {

View file

@ -34,7 +34,7 @@ PanelWindow {
property var _knownIds: ({}) property var _knownIds: ({})
Repeater { Repeater {
model: M.NotifService.popups.slice(0, 4) model: M.NotifService.popups.slice(0, M.Modules.notifications.maxPopups || 4)
delegate: Item { delegate: Item {
id: popupItem id: popupItem

View file

@ -83,6 +83,15 @@ QtObject {
root.list = [data, ...root.list]; 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 // Auto-expire popup
if (data.popup) { if (data.popup) {
const timeout = notif.expireTimeout > 0 ? notif.expireTimeout : (M.Modules.notifications.timeout || 3000); const timeout = notif.expireTimeout > 0 ? notif.expireTimeout : (M.Modules.notifications.timeout || 3000);

View file

@ -98,6 +98,11 @@ in
default = 3000; default = 3000;
description = "Notification popup timeout in milliseconds."; description = "Notification popup timeout in milliseconds.";
}; };
maxPopups = lib.mkOption {
type = lib.types.int;
default = 4;
description = "Maximum number of notification popups shown simultaneously.";
};
}; };
bluetooth = moduleOpt "bluetooth" (intervalOpt 5000); bluetooth = moduleOpt "bluetooth" (intervalOpt 5000);
network = moduleOpt "network" (intervalOpt 5000); network = moduleOpt "network" (intervalOpt 5000);

View file

@ -19,8 +19,11 @@ ShellRoot {
screen: scope.modelData screen: scope.modelData
} }
NotifPopup { LazyLoader {
screen: scope.modelData active: (Modules.notifications.maxPopups ?? 4) > 0
NotifPopup {
screen: scope.modelData
}
} }
LazyLoader { LazyLoader {