Files
DeltaruneQuickshell/Shell/Notifications/NotificationGroup.qml
2026-03-02 19:28:15 +02:00

180 lines
6.1 KiB
QML

import QtQuick
Item {
id: root
property NotificationTheme theme
property var groupData: null
property bool expanded: false
property bool peekEnabled: false
signal closeFinished(int notificationId, string reason)
signal expandRequested(string groupKey, bool expanded)
readonly property var entries: groupData && groupData.notifications ? groupData.notifications : []
readonly property int entryCount: entries.length
readonly property bool showCompressedStack: !expanded && entryCount > 1
readonly property int visiblePeekCount: showCompressedStack && peekEnabled ? Math.min(theme ? theme.stackPeekCount : 2, Math.max(0, entryCount - 1)) : 0
width: theme ? theme.stackWidth : 420
implicitHeight: {
if (expanded)
return expandedColumn.implicitHeight;
const base = newestCard.implicitHeight;
const step = theme ? theme.stackPeekStep : 18;
return base + visiblePeekCount * step;
}
height: implicitHeight
Item {
id: compressedStack
visible: !root.expanded
width: parent.width
height: parent.height
Repeater {
model: root.visiblePeekCount
NotificationCard {
property int peekIndex: index
theme: root.theme
notificationId: root.entries[peekIndex + 1].notificationId
notifObject: root.entries[peekIndex + 1].notifObject
notifVersion: root.entries[peekIndex + 1].notifVersion
createdAtMs: root.entries[peekIndex + 1].createdAt
peekMode: true
interactive: false
width: root.width
y: Math.max(0, newestCard.implicitHeight - (theme ? theme.stackPeekHeight : 36) + (theme ? theme.stackPeekStep : 18) * (peekIndex + 1))
z: 10 - peekIndex
onCloseFinished: function (closedNotificationId, reason) {
root.closeFinished(closedNotificationId, reason);
}
}
}
NotificationCard {
id: newestCard
theme: root.theme
notificationId: root.entryCount > 0 ? root.entries[0].notificationId : -1
notifObject: root.entryCount > 0 ? root.entries[0].notifObject : null
notifVersion: root.entryCount > 0 ? root.entries[0].notifVersion : 0
createdAtMs: root.entryCount > 0 ? root.entries[0].createdAt : Date.now()
interactive: root.entryCount <= 1
width: root.width
y: 0
z: 20
onCloseFinished: function (closedNotificationId, reason) {
root.closeFinished(closedNotificationId, reason);
}
}
Rectangle {
visible: root.entryCount > 1 && root.peekEnabled
width: 82
height: 18
x: root.width - width - 18
y: newestCard.implicitHeight + 1
color: theme ? theme.panelBackground : "#000000"
border.width: 2
border.color: theme ? theme.panelBorder : "#ffffff"
radius: 0
antialiasing: false
z: 25
Text {
anchors.centerIn: parent
text: "+" + String(Math.max(0, root.entryCount - 1))
color: theme ? theme.panelText : "#ffffff"
font.family: theme ? theme.fontFamily : "8bitoperator JVE"
font.pixelSize: 14
font.letterSpacing: theme ? theme.fontLetterSpacing : 1
renderType: Text.NativeRendering
font.hintingPreference: Font.PreferNoHinting
smooth: false
antialiasing: false
}
}
TapHandler {
enabled: root.entryCount > 1
acceptedButtons: Qt.LeftButton
onTapped: root.expandRequested(root.groupData.groupKey, true)
}
TapHandler {
enabled: root.entryCount > 1
acceptedButtons: Qt.RightButton
onTapped: {
if (root.entryCount > 0)
root.closeFinished(root.entries[0].notificationId, "dismiss");
}
}
}
Column {
id: expandedColumn
visible: root.expanded
width: parent.width
spacing: 0
Repeater {
model: root.entries
NotificationCard {
theme: root.theme
notificationId: modelData.notificationId
notifObject: modelData.notifObject
notifVersion: modelData.notifVersion
createdAtMs: modelData.createdAt
width: root.width
forceExpanded: true
onCloseFinished: function (closedNotificationId, reason) {
root.closeFinished(closedNotificationId, reason);
}
}
}
Rectangle {
visible: root.entryCount > 1
width: parent.width
height: theme ? theme.actionHeight : 34
color: theme ? theme.panelBackground : "#000000"
border.width: theme ? theme.actionBorderWidth : 2
border.color: theme ? theme.panelBorder : "#ffffff"
radius: 0
antialiasing: false
Text {
anchors.centerIn: parent
text: "Collapse"
color: theme ? theme.panelText : "#ffffff"
font.family: theme ? theme.fontFamily : "8bitoperator JVE"
font.pixelSize: 18
font.letterSpacing: theme ? theme.fontLetterSpacing : 1
renderType: Text.NativeRendering
font.hintingPreference: Font.PreferNoHinting
smooth: false
antialiasing: false
}
TapHandler {
acceptedButtons: Qt.LeftButton
onTapped: root.expandRequested(root.groupData.groupKey, false)
}
}
}
Behavior on implicitHeight {
NumberAnimation {
duration: theme ? theme.expandMs : 120
easing.type: Easing.InOutCubic
}
}
}