From 93bc4d935c0361e3320b5fecc76d4a895e18d32f Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 13 Dec 2025 23:07:26 +0100 Subject: [PATCH] waffles: notif center: drag to dismiss --- .../modules/common/widgets/StyledListView.qml | 2 +- .../ii/modules/waffle/looks/WListView.qml | 16 ++++- .../NotificationPaneContent.qml | 3 +- .../WNotificationDismissAnim.qml | 32 ++++++++++ .../notificationCenter/WNotificationGroup.qml | 59 +++++++++++++++---- .../WSingleNotification.qml | 40 +++++++++++-- 6 files changed, 132 insertions(+), 20 deletions(-) create mode 100644 dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationDismissAnim.qml diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledListView.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledListView.qml index 26518cfb1..4267e7bcd 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledListView.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledListView.qml @@ -100,7 +100,7 @@ ListView { to: 1, }), ] : [] - } + } move: Transition { animations: root.animateMovement ? [ diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WListView.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WListView.qml index e2ea3cda3..a46a03fe5 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WListView.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WListView.qml @@ -7,6 +7,20 @@ ListView { id: root boundsBehavior: Flickable.DragOverBounds - + ScrollBar.vertical: WScrollBar {} + + displaced: Transition { + animations: [Looks.transition.enter.createObject(this, { + property: "y" + })] + } + + remove: Transition { + ParallelAnimation { + NumberAnimation { property: "opacity"; to: 0; duration: 1000 } + NumberAnimation { properties: "x,y"; to: 100; duration: 1000 } + } + } + } diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationPaneContent.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationPaneContent.qml index 368829865..5e9582bf1 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationPaneContent.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationPaneContent.qml @@ -53,10 +53,9 @@ BodyRectangle { } } - StyledListView { + WListView { Layout.fillWidth: true Layout.fillHeight: true - animateAppearance: false clip: true model: Notifications.appNameList diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationDismissAnim.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationDismissAnim.qml new file mode 100644 index 000000000..8d3972c40 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationDismissAnim.qml @@ -0,0 +1,32 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.modules.common +import qs.modules.common.widgets +import qs.modules.common.functions +import qs.modules.waffle.looks + +SequentialAnimation { + id: root + + required property var target + + PropertyAction { + target: root.target + property: "ListView.delayRemove" + value: true + } + NumberAnimation { + target: root.target + property: "x" + to: root.target.width + duration: 250 + easing.type: Easing.BezierSpline + easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn + } + PropertyAction { + target: root.target + property: "ListView.delayRemove" + value: false + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml index 658bc03ae..88c44136e 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml @@ -1,3 +1,4 @@ +pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts import Quickshell @@ -18,10 +19,44 @@ MouseArea { implicitWidth: contentLayout.implicitWidth implicitHeight: contentLayout.implicitHeight + function dismissAll() { + root.notifications.forEach(notif => { + Qt.callLater(() => { + Notifications.discardNotification(notif.notificationId); + }); + }); + removeAnimation.start(); + } + + WNotificationDismissAnim { + id: removeAnimation + target: root + } + + property real dragDismissThreshold: 100 + drag { + axis: Drag.XAxis + target: contentLayout + minimumX: 0 + onActiveChanged: { + if (drag.active) + return; + if (contentLayout.x > root.dragDismissThreshold) { + root.dismissAll(); + } else { + contentLayout.x = 0; + } + } + } + ColumnLayout { id: contentLayout - anchors.fill: parent spacing: 4 + width: root.width + + Behavior on x { + animation: Looks.transition.enter.createObject(this) + } GroupHeader { id: notifHeader @@ -29,7 +64,9 @@ MouseArea { Layout.margins: 11 } - ListView { + WListView { + Layout.leftMargin: -Math.min(35, contentLayout.x) + Layout.rightMargin: -Layout.leftMargin Layout.fillWidth: true implicitWidth: notifHeader.implicitWidth implicitHeight: contentHeight @@ -40,14 +77,20 @@ MouseArea { objectProp: "notificationId" } delegate: WSingleNotification { + id: singleNotif required property int index required property var modelData + width: ListView.view.width notification: modelData + groupExpandControlMessage: { - if (root.notifications.length <= 1) return ""; - if (!root.expanded) return Translation.tr("+%1 notifications").arg(root.notifications.length - 1); - if (index === root.notifications.length - 1) return Translation.tr("See fewer"); + if (root.notifications.length <= 1) + return ""; + if (!root.expanded) + return Translation.tr("+%1 notifications").arg(root.notifications.length - 1); + if (index === root.notifications.length - 1) + return Translation.tr("See fewer"); return ""; } onGroupExpandToggle: { @@ -94,11 +137,7 @@ MouseArea { Layout.rightMargin: 3 icon.name: "dismiss" onClicked: { - root.notifications.forEach(notif => { - Qt.callLater(() => { - Notifications.discardNotification(notif.notificationId); - }); - }); + root.dismissAll(); } } } diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml index 895ab6892..350e7b0ab 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml @@ -18,6 +18,18 @@ MouseArea { signal groupExpandToggle hoverEnabled: true + function dismiss() { + Qt.callLater(() => { + Notifications.discardNotification(root.notification?.notificationId); + }); + removeAnimation.start(); + } + + WNotificationDismissAnim { + id: removeAnimation + target: root + } + implicitHeight: contentItem.implicitHeight implicitWidth: contentItem.implicitWidth @@ -25,9 +37,25 @@ MouseArea { animation: Looks.transition.enter.createObject(this) } + property real dragDismissThreshold: 100 + drag { + axis: Drag.XAxis + target: contentItem + minimumX: 0 + onActiveChanged: { + if (drag.active) + return; + if (contentItem.x > root.dragDismissThreshold) { + root.dismiss(); + } else { + contentItem.x = 0; + } + } + } + Rectangle { id: contentItem - anchors.fill: parent + width: parent.width color: Looks.colors.bgPanelBody radius: Looks.radius.medium property real padding: 12 @@ -36,6 +64,10 @@ MouseArea { border.width: 1 border.color: ColorUtils.applyAlpha(Looks.colors.ambientShadow, 0.1) + Behavior on x { + animation: Looks.transition.enter.createObject(this) + } + ColumnLayout { id: notificationContent anchors.fill: parent @@ -128,11 +160,7 @@ MouseArea { opacity: root.containsMouse ? 1 : 0 icon.name: "dismiss" implicitSize: 12 - onClicked: { - Qt.callLater(() => { - Notifications.discardNotification(root.notification?.notificationId); - }); - } + onClicked: root.dismiss() } }