From b5b536ac8f9c63fec48a6fc252e5080de28f68d2 Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Thu, 18 Sep 2025 20:37:00 +1000 Subject: sidebar: add notifs --- modules/sidebar/NotifDock.qml | 208 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 modules/sidebar/NotifDock.qml (limited to 'modules/sidebar/NotifDock.qml') diff --git a/modules/sidebar/NotifDock.qml b/modules/sidebar/NotifDock.qml new file mode 100644 index 0000000..36b6665 --- /dev/null +++ b/modules/sidebar/NotifDock.qml @@ -0,0 +1,208 @@ +pragma ComponentBehavior: Bound + +import qs.components +import qs.components.controls +import qs.components.containers +import qs.components.effects +import qs.services +import qs.config +import Quickshell +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +Item { + id: root + + required property Props props + + anchors.fill: parent + anchors.margins: Appearance.padding.normal + + Component.onCompleted: Notifs.list.forEach(n => n.popup = false) + + StyledText { + id: title + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Appearance.padding.small + + text: Notifs.list.length > 0 ? qsTr("%1 notification%2").arg(Notifs.list.length).arg(Notifs.list.length === 1 ? "" : "s") : qsTr("Notifications") + color: Colours.palette.m3outline + font.pointSize: Appearance.font.size.normal + font.family: Appearance.font.family.mono + font.weight: 500 + elide: Text.ElideRight + } + + ClippingRectangle { + id: clipRect + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: title.bottom + anchors.bottom: parent.bottom + anchors.topMargin: Appearance.spacing.smaller + + radius: Appearance.rounding.small + color: "transparent" + + Loader { + anchors.centerIn: parent + asynchronous: true + active: opacity > 0 + opacity: Notifs.list.length > 0 ? 0 : 1 + + sourceComponent: ColumnLayout { + spacing: Appearance.spacing.large + + Image { + asynchronous: true + source: Qt.resolvedUrl(`${Quickshell.shellDir}/assets/dino.png`) + fillMode: Image.PreserveAspectFit + sourceSize.width: clipRect.width * 0.8 + + layer.enabled: true + layer.effect: Colouriser { + colorizationColor: Colours.palette.m3outlineVariant + brightness: 1 + } + } + + StyledText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("No Notifications") + color: Colours.palette.m3outlineVariant + font.pointSize: Appearance.font.size.large + font.family: Appearance.font.family.mono + font.weight: 500 + } + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.extraLarge + } + } + } + + StyledListView { + anchors.fill: parent + + spacing: Appearance.spacing.small + clip: true + + model: ScriptModel { + values: [...new Set(Notifs.list.map(notif => notif.appName))].reverse() + } + + delegate: NotifGroup { + props: root.props + } + + add: Transition { + Anim { + property: "opacity" + from: 0 + to: 1 + } + Anim { + property: "scale" + from: 0 + to: 1 + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + remove: Transition { + Anim { + property: "opacity" + to: 0 + } + Anim { + property: "scale" + to: 0.6 + } + } + + move: Transition { + Anim { + properties: "opacity,scale" + to: 1 + } + Anim { + property: "y" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + + displaced: Transition { + Anim { + properties: "opacity,scale" + to: 1 + } + Anim { + property: "y" + duration: Appearance.anim.durations.expressiveDefaultSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial + } + } + } + } + + Timer { + id: clearTimer + + repeat: true + interval: 50 + onTriggered: { + Notifs.list[0]?.notification.dismiss(); + if (Notifs.list.length === 0) + stop(); + } + } + + Loader { + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: Appearance.padding.normal + + scale: Notifs.list.length > 0 ? 1 : 0.5 + opacity: Notifs.list.length > 0 ? 1 : 0 + active: opacity > 0 + + sourceComponent: IconButton { + id: clearBtn + + icon: "clear_all" + radius: Appearance.rounding.normal + padding: Appearance.padding.normal + font.pointSize: Math.round(Appearance.font.size.large * 1.3) + onClicked: clearTimer.start() + + Elevation { + anchors.fill: parent + radius: parent.radius + z: -1 + level: clearBtn.stateLayer.containsMouse ? 4 : 3 + } + } + + Behavior on scale { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + easing.bezierCurve: Appearance.anim.curves.expressiveFastSpatial + } + } + + Behavior on opacity { + Anim { + duration: Appearance.anim.durations.expressiveFastSpatial + } + } + } +} -- cgit v1.2.3-freya