173 lines
5.2 KiB
QML
173 lines
5.2 KiB
QML
// One app's worth of notifications in the date menu, GNOME-style: a header
|
|
// carrying the app's identity and a clear button, over a collapsible stack of
|
|
// cards.
|
|
//
|
|
// The header is the disclosure control in its entirety — a 4px chevron is a
|
|
// poor click target, and GNOME lets you hit the whole row.
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Widgets
|
|
import qs.config
|
|
import qs.services
|
|
import qs.modules.notifications
|
|
import qs.modules.quicksettings
|
|
import qs.widgets
|
|
|
|
Column {
|
|
id: root
|
|
|
|
// One entry from Notifs.groups: { app, icon, desktopEntry, items }.
|
|
required property var group
|
|
|
|
property bool expanded: true
|
|
|
|
signal toggled
|
|
signal cleared
|
|
|
|
spacing: 4
|
|
|
|
// The app icon the notifications themselves declared, falling back to the
|
|
// desktop entry — same resolution order NotificationCard uses.
|
|
readonly property string iconSource: {
|
|
if (root.group.icon)
|
|
return Quickshell.iconPath(root.group.icon, true);
|
|
const entry = DesktopEntries.byId(root.group.desktopEntry);
|
|
return entry ? Quickshell.iconPath(entry.icon, true) : "";
|
|
}
|
|
|
|
Rectangle {
|
|
id: header
|
|
width: parent.width
|
|
height: 28
|
|
radius: Theme.cardRadius - 4
|
|
border.width: 0
|
|
color: headerMouse.containsMouse ? Theme.alpha(Theme.fg, 0.07) : "transparent"
|
|
|
|
Behavior on color {
|
|
ColorAnimation {
|
|
duration: headerMouse.containsMouse ? Theme.durFast : Theme.durNormal
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: headerMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: root.toggled()
|
|
}
|
|
|
|
Row {
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 6
|
|
anchors.right: clearButton.left
|
|
anchors.rightMargin: 6
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
spacing: 7
|
|
|
|
IconImage {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
implicitSize: 15
|
|
asynchronous: true
|
|
source: root.iconSource
|
|
visible: source !== ""
|
|
}
|
|
|
|
Text {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: root.group.app
|
|
color: Theme.fgDim
|
|
elide: Text.ElideRight
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
font.weight: Font.DemiBold
|
|
}
|
|
|
|
// A bare count next to a collapsed group is the only way to know
|
|
// how much is hidden, so it is always shown once there is more
|
|
// than one.
|
|
Rectangle {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: countLabel.implicitWidth + 12
|
|
height: 16
|
|
radius: Theme.pillRadius
|
|
border.width: 0
|
|
visible: root.group.items.length > 1
|
|
color: Theme.alpha(Theme.fg, 0.12)
|
|
|
|
Text {
|
|
id: countLabel
|
|
anchors.centerIn: parent
|
|
text: root.group.items.length
|
|
color: Theme.fgDim
|
|
font.family: Theme.fontFamily
|
|
font.features: Theme.tabularFigures
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
}
|
|
}
|
|
}
|
|
|
|
IconButton {
|
|
id: clearButton
|
|
anchors.right: chevron.left
|
|
anchors.rightMargin: 2
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
size: 22
|
|
iconSize: 12
|
|
tint: Theme.fgMuted
|
|
icon: "edit-clear-all-symbolic"
|
|
iconFallback: "window-close-symbolic"
|
|
onClicked: root.cleared()
|
|
}
|
|
|
|
ThemedIcon {
|
|
id: chevron
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 6
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
size: 12
|
|
icon: "pan-down-symbolic"
|
|
iconFallback: "go-down-symbolic"
|
|
tint: Theme.fgMuted
|
|
|
|
// Pointing down when open, right when closed — the standard
|
|
// disclosure direction, animated only on the click that caused it.
|
|
rotation: root.expanded ? 0 : -90
|
|
|
|
Behavior on rotation {
|
|
NumberAnimation {
|
|
duration: Theme.durNormal
|
|
easing.type: Easing.OutCubic
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Section animates its own height and hides itself at zero, which also
|
|
// collapses the spacing the parent Column would otherwise leave behind.
|
|
Section {
|
|
width: parent.width
|
|
expanded: root.expanded
|
|
|
|
Column {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
spacing: 4
|
|
|
|
Repeater {
|
|
model: root.group.items
|
|
|
|
NotificationCard {
|
|
required property var modelData
|
|
|
|
width: parent.width
|
|
compact: true
|
|
notification: modelData
|
|
onDismissed: Notifs.dismiss(modelData)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|