improved code by removing redundancies and done some optimizations

This commit is contained in:
SomeElse
2026-05-05 03:58:40 +00:00
parent 8f25ee5caf
commit 046a36fbec
13 changed files with 441 additions and 663 deletions

View File

@@ -5,8 +5,7 @@ import Quickshell
import Quickshell.Wayland
import Quickshell.Services.Notifications
import "../../config" as Cfg
import "../../notifications" as Notif
import "../../config" as Cfg
Rectangle {
id: root
@@ -37,6 +36,287 @@ Rectangle {
Behavior on border.color { ColorAnimation { duration: 150 } }
Behavior on width { NumberAnimation { duration: 200; easing.type: Easing.OutCubic } }
component NotificationCard: Item {
id: toastRoot
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
property bool slideFromRight: false
property real slideX: slideFromRight ? (width + 20) : -(width + 20)
transform: Translate { id: slideTranslate; x: toastRoot.slideX }
Component.onCompleted: entranceSlide.start()
NumberAnimation {
id: entranceSlide
target: slideTranslate; property: "x"
from: toastRoot.slideX; to: 0
duration: 300; easing.type: Easing.OutCubic
}
function triggerDismiss() {
if (exitSlide.running) return
autoTimer.stop()
exitSlide.start()
}
NumberAnimation {
id: exitSlide
target: slideTranslate; property: "x"
to: toastRoot.slideX
duration: 220; easing.type: Easing.InCubic
onStopped: toastRoot.dismissed(toastRoot.toastId)
}
Timer {
id: autoTimer
interval: toastRoot.timeout
running: toastRoot.timeout > 0
repeat: false
onTriggered: toastRoot.triggerDismiss()
}
NumberAnimation on progressVal {
from: 1.0; to: 0.0
duration: toastRoot.timeout
running: toastRoot.urgency === NotificationUrgency.Low && toastRoot.timeout > 0
}
Rectangle {
id: toastCard
width: parent.width
height: toastContent.implicitHeight + (toastRoot.urgency === NotificationUrgency.Low ? 30 : 24)
radius: 16
color: cardHover.hovered ? toastRoot.t.notifToastBgHover : toastRoot.t.notifToastBg
border.color: toastRoot.urgency === NotificationUrgency.Critical
? toastRoot.t.notifUrgencyCritical
: (cardHover.hovered ? toastRoot.t.notifBorderActive : toastRoot.t.notifToastBorder)
border.width: Cfg.Config.popupBorderWidth
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: toastRoot.triggerDismiss() }
Rectangle {
width: 4
height: Math.max(16, toastCard.height - 24)
radius: 2
anchors {
left: parent.left
leftMargin: 10
verticalCenter: parent.verticalCenter
}
color: toastRoot.urgencyColor(toastRoot.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: toastRoot.urgencyIcon(toastRoot.urgency)
color: toastRoot.urgencyColor(toastRoot.urgency)
font.pixelSize: 12
Layout.alignment: Qt.AlignVCenter
}
Text {
text: toastRoot.appName
color: toastRoot.t.notifToastAppName
font.pixelSize: 11
font.bold: true
font.capitalization: Font.AllUppercase
Layout.fillWidth: true
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
Text {
text: toastRoot.timeStr
color: toastRoot.t.notifToastDim
font.pixelSize: 10
verticalAlignment: Text.AlignVCenter
}
Rectangle {
Layout.alignment: Qt.AlignVCenter
width: 20; height: 20; radius: 10
color: closeHover.hovered ? toastRoot.t.notifHistoryHover : "transparent"
Behavior on color { ColorAnimation { duration: 100 } }
Text {
anchors.centerIn: parent
text: "✕"
color: closeHover.hovered ? toastRoot.t.notifToastText : toastRoot.t.notifToastDim
font.pixelSize: 10
}
HoverHandler { id: closeHover; cursorShape: Qt.PointingHandCursor }
TapHandler { onTapped: toastRoot.triggerDismiss() }
}
}
Text {
text: toastRoot.summary
color: toastRoot.t.notifToastText
font.pixelSize: 14
font.bold: true
Layout.fillWidth: true
elide: Text.ElideRight
textFormat: Text.PlainText
visible: toastRoot.summary !== ""
}
Text {
text: toastRoot.body
color: toastRoot.t.notifToastDim
font.pixelSize: 12
Layout.fillWidth: true
wrapMode: Text.WordWrap
maximumLineCount: 3
elide: Text.ElideRight
textFormat: Text.PlainText
visible: toastRoot.body !== ""
Layout.bottomMargin: toastRoot.urgency === NotificationUrgency.Low ? 6 : 0
lineHeight: 1.15
}
}
Item {
visible: toastRoot.urgency === NotificationUrgency.Low && toastRoot.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: toastRoot.t.notifProgressBg
}
Rectangle {
width: parent.width * toastRoot.progressVal
height: parent.height
radius: 2
color: toastRoot.t.notifProgressFill
}
}
}
}
component HistoryCard: Rectangle {
id: histRoot
property int itemIndex: 0
property string appName: ""
property string summary: ""
property string body: ""
property int urgency: 0
property string timeStr: ""
property var t
property var urgencyColor: function(u) { return "#ffffff" }
property var urgencyIcon: function(u) { return "" }
signal dismissed(int itemIndex)
height: histItemContent.implicitHeight + 24
radius: 12
clip: true
color: histItemHover.hovered ? histRoot.t.notifHistoryHover : "transparent"
Behavior on color { ColorAnimation { duration: 150; easing.type: Easing.OutCubic } }
HoverHandler { id: histItemHover }
SequentialAnimation {
id: dismissAnim
ParallelAnimation {
NumberAnimation { target: histRoot; property: "opacity"; to: 0; duration: 150; easing.type: Easing.OutCubic }
NumberAnimation { target: histRoot; property: "scale"; to: 0.95; duration: 150; easing.type: Easing.OutCubic }
}
NumberAnimation { target: histRoot; property: "height"; to: 0; duration: 150; easing.type: Easing.InOutQuad }
ScriptAction { script: histRoot.dismissed(histRoot.itemIndex) }
}
Rectangle {
width: 3
height: Math.max(12, histRoot.height - 24)
radius: 1.5
anchors { left: parent.left; leftMargin: 10; verticalCenter: parent.verticalCenter }
color: histRoot.urgencyColor(histRoot.urgency)
}
Rectangle {
anchors { right: parent.right; top: parent.top; margins: 8 }
width: 22; height: 22; radius: 11
color: histCloseHover.hovered ? histRoot.t.notifHistoryHover : "transparent"
opacity: histItemHover.hovered ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 150 } }
Behavior on color { ColorAnimation { duration: 150 } }
Text { anchors.centerIn: parent; text: "✕"; color: histRoot.t.notifToastText; font.pixelSize: 10 }
HoverHandler { id: histCloseHover; cursorShape: Qt.PointingHandCursor }
TapHandler { onTapped: dismissAnim.start() }
}
ColumnLayout {
id: histItemContent
anchors { left: parent.left; right: parent.right; top: parent.top; leftMargin: 24; rightMargin: 36; topMargin: 12 }
spacing: 4
RowLayout {
Layout.fillWidth: true; spacing: 5
Text { text: histRoot.urgencyIcon(histRoot.urgency); color: histRoot.urgencyColor(histRoot.urgency); font.pixelSize: 11; Layout.alignment: Qt.AlignVCenter }
Text {
text: histRoot.appName; color: histRoot.t.notifToastAppName; font.pixelSize: 11; font.bold: true
font.capitalization: Font.AllUppercase; Layout.fillWidth: true; elide: Text.ElideRight; verticalAlignment: Text.AlignVCenter
}
Text { text: histRoot.timeStr; color: histRoot.t.notifToastDim; font.pixelSize: 11; verticalAlignment: Text.AlignVCenter }
}
Text {
text: histRoot.summary; color: histRoot.t.notifToastText; font.pixelSize: 13; font.bold: true
Layout.fillWidth: true; elide: Text.ElideRight; textFormat: Text.PlainText; visible: histRoot.summary !== ""
}
Text {
text: histRoot.body; color: histRoot.t.notifToastDim; font.pixelSize: 12; Layout.fillWidth: true
wrapMode: Text.WordWrap; maximumLineCount: 2; elide: Text.ElideRight; textFormat: Text.PlainText; visible: histRoot.body !== ""; lineHeight: 1.15
}
}
}
HoverHandler { id: hoverHandler; cursorShape: Qt.PointingHandCursor; onHoveredChanged: if (hovered) bellRingAnim.start() }
TapHandler {
onTapped: {
@@ -135,39 +415,31 @@ Rectangle {
onNotification: function(notif) {
notif.tracked = true
bellRingAnim.start()
var timeStr = new Date().toLocaleTimeString(Qt.locale(), "HH:mm")
var toastId = notif.id + "_" + Date.now()
const timeStr = new Date().toLocaleTimeString(Qt.locale(), "HH:mm")
const toastId = notif.id + "_" + Date.now()
const appName = notif.appName || "Unknown"
const summary = notif.summary || ""
const body = notif.body || ""
const urgency = notif.urgency
notifHistory.insert(0, {
nid: notif.id,
appName: notif.appName || "Unknown",
summary: notif.summary || "",
body: notif.body || "",
urgency: notif.urgency,
timeStr: timeStr
nid: notif.id,
appName, summary, body, urgency, timeStr
})
while (notifHistory.count > Cfg.Config.notificationHistorySize)
notifHistory.remove(notifHistory.count - 1)
var cfgTimeout = notif.urgency === NotificationUrgency.Critical
var cfgTimeout = urgency === NotificationUrgency.Critical
? Cfg.Config.notifTimeoutCritical
: (notif.urgency === NotificationUrgency.Low
: (urgency === NotificationUrgency.Low
? Cfg.Config.notifTimeoutLow
: Cfg.Config.notifTimeoutNormal)
var finalTimeout = (notif.expireTimeout > 0) ? notif.expireTimeout : cfgTimeout
var toastEntry = {
toastId: toastId,
nid: notif.id,
appName: notif.appName || "Unknown",
summary: notif.summary || "",
body: notif.body || "",
urgency: notif.urgency,
timeStr: timeStr,
timeout: finalTimeout
}
if (!root.doNotDisturb) {
var toastEntry = { toastId, nid: notif.id, appName, summary, body, urgency, timeStr, timeout: finalTimeout }
if (toastLayer.atBottom) activeToasts.append(toastEntry)
else activeToasts.insert(0, toastEntry)
if (!root.historyOpen) root.unreadCount++
@@ -197,7 +469,6 @@ Rectangle {
readonly property bool shareEdge: (root.isTop && !atBottom) || (!root.isTop && atBottom)
readonly property int edgeGap: shareEdge ? root.barMargin + root.barHeight + 10 : root.barMargin + 10
// Extra clearance so cards don't overlap the frame border stroke
readonly property int toastPad: root.barMargin + Cfg.Config.frameBorderWidth + Cfg.Config.notifToastEdgePad
Column {
@@ -209,7 +480,7 @@ Rectangle {
Repeater {
model: activeToasts
Notif.NotificationCard {
NotificationCard {
width: toastCol.width
toastId: model.toastId
appName: model.appName
@@ -286,11 +557,11 @@ Rectangle {
transform: Translate {
y: historyPopup.popupOpen ? 0 : (root.isTop ? -historyCard.height : historyCard.height)
Behavior on y {
NumberAnimation {
duration: Cfg.Config.popupAnimDuration;
easing.type: Easing.OutExpo
Behavior on y {
NumberAnimation {
duration: Cfg.Config.popupAnimDuration;
easing.type: Easing.OutExpo
}
enabled: historyPopup.visible
}
@@ -319,7 +590,6 @@ Rectangle {
Layout.fillWidth: true; Layout.alignment: Qt.AlignVCenter
}
// ── Do Not Disturb toggle ─────────────────────────────
Rectangle {
Layout.alignment: Qt.AlignVCenter
width: dndRow.implicitWidth + 16
@@ -426,7 +696,7 @@ Rectangle {
Repeater {
model: notifHistory
Notif.HistoryCard {
HistoryCard {
width: histCol.width - 10; x: 2; itemIndex: index
appName: model.appName; summary: model.summary; body: model.body; urgency: model.urgency; timeStr: model.timeStr
t: root.t; urgencyColor: root.urgencyColor; urgencyIcon: root.urgencyIcon
@@ -439,4 +709,3 @@ Rectangle {
}
}
}