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 } } }