diff --git a/README.md b/README.md index bd5220a67..134553ec6 100644 --- a/README.md +++ b/README.md @@ -530,7 +530,9 @@ default, you must create it manually. "clearThreshold": 0.3, "defaultExpireTimeout": 5000, "expandThreshold": 20, - "expire": false + "expire": false, + "timeoutBar": false, + "timeoutCircle": false, }, "osd": { "enabled": true, diff --git a/config/NotifsConfig.qml b/config/NotifsConfig.qml index 25d8680e2..9e9ae5218 100644 --- a/config/NotifsConfig.qml +++ b/config/NotifsConfig.qml @@ -3,6 +3,8 @@ import Quickshell.Io JsonObject { property bool expire: true property int defaultExpireTimeout: 5000 + property bool timeoutBar: false + property bool timeoutCircle: false property real clearThreshold: 0.3 property int expandThreshold: 20 property bool actionOnClick: false diff --git a/modules/notifications/Content.qml b/modules/notifications/Content.qml index 2d4590e0e..8628d4126 100644 --- a/modules/notifications/Content.qml +++ b/modules/notifications/Content.qml @@ -25,7 +25,7 @@ Item { let height = (count - 1) * Appearance.spacing.smaller; for (let i = 0; i < count; i++) - height += list.itemAtIndex(i)?.nonAnimHeight ?? 0; + height += list.itemAtIndex(i)?.implicitHeight ?? 0; if (visibilities && panels) { if (visibilities.osd) { diff --git a/modules/notifications/Notification.qml b/modules/notifications/Notification.qml index 95507fcb5..39bcc9250 100644 --- a/modules/notifications/Notification.qml +++ b/modules/notifications/Notification.qml @@ -10,6 +10,7 @@ import Quickshell.Widgets import Quickshell.Services.Notifications import QtQuick import QtQuick.Layouts +import QtQuick.Shapes StyledRect { id: root @@ -23,7 +24,7 @@ StyledRect { color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondaryContainer : Colours.tPalette.m3surfaceContainer radius: Appearance.rounding.normal implicitWidth: Config.notifs.sizes.width - implicitHeight: inner.implicitHeight + implicitHeight: inner.implicitHeight + progressBar.implicitHeight x: Config.notifs.sizes.width Component.onCompleted: { @@ -311,12 +312,78 @@ StyledRect { font.pointSize: Appearance.font.size.small } + Loader { + active: Config.notifs.timeoutCircle + asynchronous: true + anchors.centerIn: closeBtn + + sourceComponent: Shape { + id: progressCircle + width: closeBtn.implicitWidth + Appearance.padding.small + height: closeBtn.implicitHeight + Appearance.padding.small + preferredRendererType: Shape.CurveRenderer + + ShapePath { + capStyle: ShapePath.FlatCap + fillColor: "transparent" + strokeWidth: Appearance.padding.small + strokeColor: Colours.palette.m3tertiary + + PathAngleArc { + centerX: progressCircle.width / 2 + centerY: progressCircle.height / 2 + radiusX: progressCircle.width / 2 - Appearance.padding.small / 2 + radiusY: progressCircle.height / 2 - Appearance.padding.small / 2 + + startAngle: -90 + + NumberAnimation on sweepAngle { + from: 360 + to: 0 + duration: Config.notifs.defaultExpireTimeout + running: root.modelData.timer.running + } + } + } + } + } + Item { - id: expandBtn + id: closeBtn anchors.right: parent.right anchors.top: parent.top + implicitWidth: closeIcon.height + implicitHeight: closeIcon.height + + StateLayer { + radius: Appearance.rounding.full + color: Colours.palette.m3onSurface + + function onClicked() { + root.modelData.notification.dismiss(); + } + } + + MaterialIcon { + id: closeIcon + + anchors.centerIn: parent + + animate: true + text: "close" + font.pointSize: Appearance.font.size.normal + } + } + + Item { + id: expandBtn + + anchors.right: closeBtn.left + anchors.top: parent.top + anchors.rightMargin: Appearance.spacing.small + implicitWidth: expandIcon.height implicitHeight: expandIcon.height @@ -437,6 +504,30 @@ StyledRect { } } + Loader { + id: progressBar + active: Config.notifs.timeoutBar + asynchronous: true + + anchors.right: parent.right + anchors.bottom: parent.bottom + + sourceComponent: StyledRect { + anchors.topMargin: Appearance.padding.small + + implicitHeight: Appearance.padding.small + + color: Colours.palette.m3tertiary + + NumberAnimation on implicitWidth { + from: root.width + to: 0 + duration: Config.notifs.defaultExpireTimeout + running: root.modelData.timer.running + } + } + } + component Action: StyledRect { id: action