summaryrefslogtreecommitdiff
path: root/modules/lock/Notification.qml
diff options
context:
space:
mode:
Diffstat (limited to 'modules/lock/Notification.qml')
-rw-r--r--modules/lock/Notification.qml220
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
+ }
+ }
+}