Compare commits
3 commits
ce62d8f9cd
...
f65bd90bfd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f65bd90bfd | ||
|
|
a6d95ffdaf | ||
|
|
9358f8fe6e |
6 changed files with 95 additions and 16 deletions
|
|
@ -21,7 +21,8 @@ QtObject {
|
|||
})
|
||||
property var notifications: ({
|
||||
enable: true,
|
||||
timeout: 3000
|
||||
timeout: 3000,
|
||||
maxPopups: 4
|
||||
})
|
||||
property var mpris: ({
|
||||
enable: true
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -98,6 +98,11 @@ in
|
|||
default = 3000;
|
||||
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);
|
||||
network = moduleOpt "network" (intervalOpt 5000);
|
||||
|
|
|
|||
|
|
@ -19,8 +19,11 @@ ShellRoot {
|
|||
screen: scope.modelData
|
||||
}
|
||||
|
||||
NotifPopup {
|
||||
screen: scope.modelData
|
||||
LazyLoader {
|
||||
active: (Modules.notifications.maxPopups ?? 4) > 0
|
||||
NotifPopup {
|
||||
screen: scope.modelData
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue