diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-06-25 20:52:15 +1000 |
|---|---|---|
| committer | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-06-25 20:52:15 +1000 |
| commit | d7d4d86da2952e44642c65502aaaefaa69c6d948 (patch) | |
| tree | 28ae984386060dcf81394932fe365c63de4793c5 /modules/lock/Notification.qml | |
| parent | internal: move notif icon guessing to utils (diff) | |
| download | caelestia-shell-d7d4d86da2952e44642c65502aaaefaa69c6d948.tar.gz caelestia-shell-d7d4d86da2952e44642c65502aaaefaa69c6d948.tar.bz2 caelestia-shell-d7d4d86da2952e44642c65502aaaefaa69c6d948.zip | |
lock: add notifs and status
Diffstat (limited to 'modules/lock/Notification.qml')
| -rw-r--r-- | modules/lock/Notification.qml | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/modules/lock/Notification.qml b/modules/lock/Notification.qml new file mode 100644 index 0000000..1d3e1c7 --- /dev/null +++ b/modules/lock/Notification.qml @@ -0,0 +1,220 @@ +pragma ComponentBehavior: Bound + +import "root:/widgets" +import "root:/services" +import "root:/config" +import "root:/utils" +import Quickshell +import Quickshell.Widgets +import Quickshell.Services.Notifications +import QtQuick +import QtQuick.Layouts + +StyledRect { + id: root + + required property Notifs.Notif modelData + readonly property bool hasImage: modelData.image.length > 0 + readonly property bool hasAppIcon: modelData.appIcon.length > 0 + readonly property int nonAnimHeight: Math.max(image.height, details.implicitHeight) + Appearance.padding.normal * 2 + + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3secondaryContainer : Colours.palette.m3surfaceContainer + radius: Appearance.rounding.normal + implicitWidth: Config.notifs.sizes.width + + Component.onCompleted: implicitHeight = Qt.binding(() => nonAnimHeight) + + Behavior on implicitHeight { + NumberAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } + + Behavior on x { + NumberAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.emphasizedDecel + } + } + + RetainableLock { + object: root.modelData.notification + locked: true + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: pressed ? Qt.ClosedHandCursor : undefined + acceptedButtons: Qt.LeftButton | Qt.MiddleButton + preventStealing: true + + onEntered: root.modelData.timer.stop() + onExited: root.modelData.timer.start() + + drag.target: parent + drag.axis: Drag.XAxis + + onPressed: event => { + if (event.button === Qt.MiddleButton) + root.modelData.notification.dismiss(); + } + onReleased: event => { + if (Math.abs(root.x) < Config.notifs.sizes.width * Config.notifs.clearThreshold) + root.x = 0; + else + root.modelData.notification.dismiss(); // TODO: change back to popup when notif dock impled + } + } + + Loader { + id: image + + active: root.hasImage + asynchronous: true + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Appearance.padding.normal + + width: Config.notifs.sizes.image + height: Config.notifs.sizes.image + visible: root.hasImage || root.hasAppIcon + + sourceComponent: ClippingRectangle { + radius: Appearance.rounding.full + implicitWidth: Config.notifs.sizes.image + implicitHeight: Config.notifs.sizes.image + + Image { + anchors.fill: parent + source: Qt.resolvedUrl(root.modelData.image) + fillMode: Image.PreserveAspectCrop + cache: false + asynchronous: true + } + } + } + + Loader { + id: appIcon + + active: root.hasAppIcon || !root.hasImage + asynchronous: true + + anchors.horizontalCenter: root.hasImage ? undefined : image.horizontalCenter + anchors.verticalCenter: root.hasImage ? undefined : image.verticalCenter + anchors.right: root.hasImage ? image.right : undefined + anchors.bottom: root.hasImage ? image.bottom : undefined + + sourceComponent: StyledRect { + radius: Appearance.rounding.full + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3error : root.modelData.urgency === NotificationUrgency.Low ? Colours.palette.m3surfaceContainerHighest : Colours.palette.m3tertiaryContainer + implicitWidth: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image + implicitHeight: root.hasImage ? Config.notifs.sizes.badge : Config.notifs.sizes.image + + Loader { + id: icon + + active: root.hasAppIcon + asynchronous: true + + anchors.centerIn: parent + visible: !root.modelData.appIcon.endsWith("symbolic") + + width: Math.round(parent.width * 0.6) + height: Math.round(parent.width * 0.6) + + sourceComponent: IconImage { + implicitSize: Math.round(parent.width * 0.6) + source: Quickshell.iconPath(root.modelData.appIcon) + asynchronous: true + } + } + + Loader { + active: root.modelData.appIcon.endsWith("symbolic") + asynchronous: true + anchors.fill: icon + + sourceComponent: Colouriser { + source: icon + colorizationColor: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : root.modelData.urgency === NotificationUrgency.Low ? Colours.palette.m3onSurface : Colours.palette.m3onTertiaryContainer + } + } + + Loader { + active: !root.hasAppIcon + asynchronous: true + anchors.centerIn: parent + anchors.horizontalCenterOffset: -Appearance.font.size.large * 0.02 + anchors.verticalCenterOffset: Appearance.font.size.large * 0.02 + + sourceComponent: MaterialIcon { + text: Icons.getNotifIcon(root.modelData.summary.toLowerCase(), root.modelData.urgency) + + color: root.modelData.urgency === NotificationUrgency.Critical ? Colours.palette.m3onError : root.modelData.urgency === NotificationUrgency.Low ? Colours.palette.m3onSurface : Colours.palette.m3onTertiaryContainer + font.pointSize: Appearance.font.size.large + font.variableAxes: ({ + opsz: Appearance.font.size.large + }) + } + } + } + } + + ColumnLayout { + id: details + + anchors.verticalCenter: parent.verticalCenter + anchors.left: image.right + anchors.right: parent.right + anchors.leftMargin: Appearance.spacing.smaller + anchors.rightMargin: Appearance.padding.larger + + spacing: 0 + + RowLayout { + Layout.fillWidth: true + + spacing: Appearance.spacing.small + + StyledText { + Layout.fillWidth: true + Layout.maximumWidth: implicitWidth + + animate: true + text: root.modelData.summary + elide: Text.ElideRight + maximumLineCount: 1 + } + + StyledText { + text: "•" + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + } + + StyledText { + animate: true + text: root.modelData.timeStr + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + } + } + + StyledText { + Layout.fillWidth: true + + animate: true + text: root.modelData.body + color: Colours.palette.m3onSurfaceVariant + font.pointSize: Appearance.font.size.small + elide: Text.ElideRight + maximumLineCount: 1 + } + } +} |