Files
quickdots/notifications/NotificationCard.qml
2026-04-24 02:14:35 +00:00

192 lines
6.3 KiB
QML

import QtQuick
import QtQuick.Layouts
import Quickshell.Services.Notifications
Item {
id: root
property string toastId: ""
property string appName: ""
property string summary: ""
property string body: ""
property int urgency: NotificationUrgency.Normal
property string timeStr: ""
property int timeout: 5000
property var t
property var urgencyColor: function(u) { return "#ffffff" }
property var urgencyIcon: function(u) { return "" }
signal dismissed(string toastId)
width: parent ? parent.width : 350
height: toastCard.height
property real progressVal: 1.0
Timer {
interval: root.timeout
running: root.timeout > 0
repeat: false
onTriggered: root.dismissed(root.toastId)
}
NumberAnimation on progressVal {
from: 1.0; to: 0.0
duration: root.timeout
running: root.urgency === NotificationUrgency.Low && root.timeout > 0
}
opacity: 0
scale: 0.90
Component.onCompleted: {
entranceOp.start()
entranceSc.start()
}
NumberAnimation {
id: entranceOp; target: root
property: "opacity"; from: 0; to: 1
duration: 240; easing.type: Easing.OutCubic
}
NumberAnimation {
id: entranceSc; target: root
property: "scale"; from: 0.90; to: 1.0
duration: 240; easing.type: Easing.OutBack
}
Rectangle {
id: toastCard
width: parent.width
height: toastContent.implicitHeight + (root.urgency === NotificationUrgency.Low ? 30 : 24)
radius: 16
color: cardHover.hovered ? root.t.notifToastBgHover : root.t.notifToastBg
border.color: root.urgency === NotificationUrgency.Critical
? root.t.notifUrgencyCritical
: (cardHover.hovered ? root.t.notifBorderActive : root.t.notifToastBorder)
border.width: 1
layer.enabled: true
Behavior on color { ColorAnimation { duration: 150; easing.type: Easing.OutCubic } }
Behavior on border.color { ColorAnimation { duration: 150 } }
HoverHandler { id: cardHover }
TapHandler { onTapped: root.dismissed(root.toastId) }
Rectangle {
width: 4
height: Math.max(16, toastCard.height - 24)
radius: 2
anchors {
left: parent.left
leftMargin: 10
verticalCenter: parent.verticalCenter
}
color: root.urgencyColor(root.urgency)
}
ColumnLayout {
id: toastContent
anchors {
left: parent.left
right: parent.right
top: parent.top
leftMargin: 24
rightMargin: 12
topMargin: 12
}
spacing: 4
RowLayout {
Layout.fillWidth: true
spacing: 6
Text {
text: root.urgencyIcon(root.urgency)
color: root.urgencyColor(root.urgency)
font.pixelSize: 12
Layout.alignment: Qt.AlignVCenter
}
Text {
text: root.appName
color: root.t.notifToastAppName
font.pixelSize: 11
font.bold: true
font.capitalization: Font.AllUppercase
Layout.fillWidth: true
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
Text {
text: root.timeStr
color: root.t.notifToastDim
font.pixelSize: 10
verticalAlignment: Text.AlignVCenter
}
Rectangle {
Layout.alignment: Qt.AlignVCenter
width: 20; height: 20; radius: 10
color: closeHover.hovered ? root.t.notifHistoryHover : "transparent"
Behavior on color { ColorAnimation { duration: 100 } }
Text {
anchors.centerIn: parent
text: "✕"
color: closeHover.hovered ? root.t.notifToastText : root.t.notifToastDim
font.pixelSize: 10
}
HoverHandler { id: closeHover; cursorShape: Qt.PointingHandCursor }
TapHandler { onTapped: root.dismissed(root.toastId) }
}
}
Text {
text: root.summary
color: root.t.notifToastText
font.pixelSize: 14
font.bold: true
Layout.fillWidth: true
elide: Text.ElideRight
textFormat: Text.PlainText
visible: root.summary !== ""
}
Text {
text: root.body
color: root.t.notifToastDim
font.pixelSize: 12
Layout.fillWidth: true
wrapMode: Text.WordWrap
maximumLineCount: 3
elide: Text.ElideRight
textFormat: Text.PlainText
visible: root.body !== ""
Layout.bottomMargin: root.urgency === NotificationUrgency.Low ? 6 : 0
lineHeight: 1.15
}
}
Item {
visible: root.urgency === NotificationUrgency.Low && root.timeout > 0
anchors {
left: parent.left; right: parent.right; bottom: parent.bottom
margins: 10; bottomMargin: 10
}
height: 4
Rectangle {
anchors.fill: parent
radius: 2
color: root.t.notifProgressBg
}
Rectangle {
width: parent.width * root.progressVal
height: parent.height
radius: 2
color: root.t.notifProgressFill
}
}
}
}