qml format

This commit is contained in:
quadbyte 2025-08-10 17:04:51 -04:00
parent 9418d94f6d
commit eda4bc8a6a
4 changed files with 159 additions and 161 deletions

View file

@ -25,17 +25,17 @@ PanelWindow {
WlrLayershell.exclusionMode: ExclusionMode.Ignore WlrLayershell.exclusionMode: ExclusionMode.Ignore
// Use the notification service // Use the notification service
property var notificationService: NotificationService { } property var notificationService: NotificationService {}
// Access the notification model from the service // Access the notification model from the service
property ListModel notificationModel: notificationService.notificationModel property ListModel notificationModel: notificationService.notificationModel
// Track notifications being removed for animation // Track notifications being removed for animation
property var removingNotifications: ({}) property var removingNotifications: ({})
// Connect to animation signal from service // Connect to animation signal from service
Component.onCompleted: { Component.onCompleted: {
notificationService.animateAndRemove.connect(function(notification, index) { notificationService.animateAndRemove.connect(function (notification, index) {
// Find the delegate and trigger its animation // Find the delegate and trigger its animation
if (notificationStack.children && notificationStack.children[index]) { if (notificationStack.children && notificationStack.children[index]) {
let delegate = notificationStack.children[index] let delegate = notificationStack.children[index]
@ -46,8 +46,6 @@ PanelWindow {
}) })
} }
// Main notification container // Main notification container
Column { Column {
id: notificationStack id: notificationStack
@ -57,8 +55,6 @@ PanelWindow {
width: 360 * scaling width: 360 * scaling
visible: true visible: true
// Multiple notifications display // Multiple notifications display
Repeater { Repeater {
model: notificationModel model: notificationModel
@ -70,29 +66,29 @@ PanelWindow {
radius: Style.radiusMedium * scaling radius: Style.radiusMedium * scaling
border.color: Colors.backgroundTertiary border.color: Colors.backgroundTertiary
border.width: Math.min(1, Style.borderThin * scaling) border.width: Math.min(1, Style.borderThin * scaling)
// Animation properties // Animation properties
property real scaleValue: 0.8 property real scaleValue: 0.8
property real opacityValue: 0.0 property real opacityValue: 0.0
property bool isRemoving: false property bool isRemoving: false
// Scale and fade-in animation // Scale and fade-in animation
scale: scaleValue scale: scaleValue
opacity: opacityValue opacity: opacityValue
// Animate in when the item is created // Animate in when the item is created
Component.onCompleted: { Component.onCompleted: {
scaleValue = 1.0 scaleValue = 1.0
opacityValue = 1.0 opacityValue = 1.0
} }
// Animate out when being removed // Animate out when being removed
function animateOut() { function animateOut() {
isRemoving = true isRemoving = true
scaleValue = 0.8 scaleValue = 0.8
opacityValue = 0.0 opacityValue = 0.0
} }
// Timer for delayed removal after animation // Timer for delayed removal after animation
Timer { Timer {
id: removalTimer id: removalTimer
@ -102,7 +98,7 @@ PanelWindow {
notificationService.forceRemoveNotification(model.rawNotification) notificationService.forceRemoveNotification(model.rawNotification)
} }
} }
// Check if this notification is being removed // Check if this notification is being removed
onIsRemovingChanged: { onIsRemovingChanged: {
if (isRemoving) { if (isRemoving) {
@ -110,7 +106,7 @@ PanelWindow {
removalTimer.start() removalTimer.start()
} }
} }
// Animation behaviors // Animation behaviors
Behavior on scale { Behavior on scale {
NumberAnimation { NumberAnimation {
@ -118,22 +114,20 @@ PanelWindow {
easing.type: Easing.OutBack easing.type: Easing.OutBack
} }
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {
duration: Style.animationNormal duration: Style.animationNormal
easing.type: Easing.OutQuad easing.type: Easing.OutQuad
} }
} }
Column { Column {
id: contentColumn id: contentColumn
anchors.fill: parent anchors.fill: parent
anchors.margins: Style.marginMedium * scaling anchors.margins: Style.marginMedium * scaling
spacing: Style.marginSmall * scaling spacing: Style.marginSmall * scaling
RowLayout { RowLayout {
spacing: Style.marginSmall * scaling spacing: Style.marginSmall * scaling
NText { NText {
@ -142,19 +136,22 @@ PanelWindow {
font.pointSize: Style.fontSizeSmall font.pointSize: Style.fontSizeSmall
} }
Rectangle { Rectangle {
width: 6 * scaling; height: 6 * scaling; radius: 3 * scaling width: 6 * scaling
color: (model.urgency === NotificationUrgency.Critical) ? Colors.error : height: 6 * scaling
(model.urgency === NotificationUrgency.Low) ? Colors.textSecondary : Colors.accentPrimary radius: 3 * scaling
color: (model.urgency === NotificationUrgency.Critical) ? Colors.error : (model.urgency === NotificationUrgency.Low) ? Colors.textSecondary : Colors.accentPrimary
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
} }
Item { Layout.fillWidth: true } Item {
Layout.fillWidth: true
}
NText { NText {
text: notificationService.formatTimestamp(model.timestamp) text: notificationService.formatTimestamp(model.timestamp)
color: Colors.textSecondary color: Colors.textSecondary
font.pointSize: Style.fontSizeSmall font.pointSize: Style.fontSizeSmall
} }
} }
NText { NText {
text: model.summary || "No summary" text: model.summary || "No summary"
font.pointSize: Style.fontSizeLarge font.pointSize: Style.fontSizeLarge
@ -165,7 +162,7 @@ PanelWindow {
maximumLineCount: 3 maximumLineCount: 3
elide: Text.ElideRight elide: Text.ElideRight
} }
NText { NText {
text: model.body || "" text: model.body || ""
font.pointSize: Style.fontSizeSmall font.pointSize: Style.fontSizeSmall
@ -176,13 +173,13 @@ PanelWindow {
elide: Text.ElideRight elide: Text.ElideRight
} }
} }
NIconButton { NIconButton {
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
anchors.margins: Style.marginSmall * scaling anchors.margins: Style.marginSmall * scaling
icon: "close" icon: "close"
onClicked: function() { onClicked: function () {
animateOut() animateOut()
} }
} }

View file

@ -22,7 +22,9 @@ NBox {
anchors.margins: Style.marginMedium * scaling anchors.margins: Style.marginMedium * scaling
spacing: Style.marginMedium * scaling spacing: Style.marginMedium * scaling
Item { height: Style.marginLarge * scaling } Item {
height: Style.marginLarge * scaling
}
Text { Text {
text: "music_note" text: "music_note"
@ -38,6 +40,8 @@ NBox {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
Item { height: Style.marginLarge * scaling } Item {
height: Style.marginLarge * scaling
}
} }
} }

View file

@ -46,9 +46,9 @@ NBox {
color: Colors.backgroundTertiary color: Colors.backgroundTertiary
} }
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
spacing: Style.marginMedium * scaling spacing: Style.marginMedium * scaling
Repeater { Repeater {
model: 5 model: 5
delegate: ColumnLayout { delegate: ColumnLayout {

View file

@ -2,138 +2,135 @@ import QtQuick
import qs.Services import qs.Services
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
QtObject { QtObject {
id: root id: root
// Notification server instance // Notification server instance
property NotificationServer server: NotificationServer { property NotificationServer server: NotificationServer {
id: notificationServer id: notificationServer
// Server capabilities // Server capabilities
keepOnReload: false keepOnReload: false
imageSupported: true imageSupported: true
actionsSupported: true actionsSupported: true
actionIconsSupported: true actionIconsSupported: true
bodyMarkupSupported: true bodyMarkupSupported: true
bodySupported: true bodySupported: true
persistenceSupported: true persistenceSupported: true
inlineReplySupported: true inlineReplySupported: true
bodyHyperlinksSupported: true bodyHyperlinksSupported: true
bodyImagesSupported: true bodyImagesSupported: true
// Signal when notification is received // Signal when notification is received
onNotification: function(notification) { onNotification: function (notification) {
// Track the notification // Track the notification
notification.tracked = true notification.tracked = true
// Connect to closed signal for cleanup // Connect to closed signal for cleanup
notification.closed.connect(function() { notification.closed.connect(function () {
root.removeNotification(notification) root.removeNotification(notification)
}) })
// Add to our model // Add to our model
root.addNotification(notification) root.addNotification(notification)
}
} }
}
// List model to hold notifications
property ListModel notificationModel: ListModel { } // List model to hold notifications
property ListModel notificationModel: ListModel {}
// Maximum visible notifications
property int maxVisible: 5 // Maximum visible notifications
property int maxVisible: 5
// Auto-hide timer
property Timer hideTimer: Timer { // Auto-hide timer
interval: 5000 // 5 seconds property Timer hideTimer: Timer {
repeat: true interval: 5000 // 5 seconds
running: notificationModel.count > 0 repeat: true
running: notificationModel.count > 0
onTriggered: {
if (notificationModel.count === 0) { onTriggered: {
return if (notificationModel.count === 0) {
} return
}
// Always remove the oldest notification (last in the list)
let oldestNotification = notificationModel.get(notificationModel.count - 1).rawNotification // Always remove the oldest notification (last in the list)
if (oldestNotification && !oldestNotification.transient) { let oldestNotification = notificationModel.get(notificationModel.count - 1).rawNotification
// Trigger animation signal instead of direct dismiss if (oldestNotification && !oldestNotification.transient) {
animateAndRemove(oldestNotification, notificationModel.count - 1) // Trigger animation signal instead of direct dismiss
} animateAndRemove(oldestNotification, notificationModel.count - 1)
} }
} }
}
// Function to add notification to model
function addNotification(notification) { // Function to add notification to model
notificationModel.insert(0, { function addNotification(notification) {
rawNotification: notification, notificationModel.insert(0, {
summary: notification.summary, "rawNotification": notification,
body: notification.body, "summary": notification.summary,
appName: notification.appName, "body": notification.body,
urgency: notification.urgency, "appName": notification.appName,
timestamp: new Date() "urgency": notification.urgency,
}) "timestamp": new Date()
})
// Remove oldest notifications if we exceed maxVisible
while (notificationModel.count > maxVisible) { // Remove oldest notifications if we exceed maxVisible
let oldestNotification = notificationModel.get(notificationModel.count - 1).rawNotification while (notificationModel.count > maxVisible) {
if (oldestNotification) { let oldestNotification = notificationModel.get(notificationModel.count - 1).rawNotification
oldestNotification.dismiss() if (oldestNotification) {
} oldestNotification.dismiss()
notificationModel.remove(notificationModel.count - 1) }
} notificationModel.remove(notificationModel.count - 1)
} }
}
// Signal to trigger animation before removal
signal animateAndRemove(var notification, int index) // Signal to trigger animation before removal
signal animateAndRemove(var notification, int index)
// Function to remove notification from model
function removeNotification(notification) { // Function to remove notification from model
for (let i = 0; i < notificationModel.count; i++) { function removeNotification(notification) {
if (notificationModel.get(i).rawNotification === notification) { for (var i = 0; i < notificationModel.count; i++) {
// Emit signal to trigger animation first if (notificationModel.get(i).rawNotification === notification) {
animateAndRemove(notification, i) // Emit signal to trigger animation first
break animateAndRemove(notification, i)
} break
} }
} }
}
// Function to actually remove notification after animation
function forceRemoveNotification(notification) { // Function to actually remove notification after animation
for (let i = 0; i < notificationModel.count; i++) { function forceRemoveNotification(notification) {
if (notificationModel.get(i).rawNotification === notification) { for (var i = 0; i < notificationModel.count; i++) {
notificationModel.remove(i) if (notificationModel.get(i).rawNotification === notification) {
break notificationModel.remove(i)
} break
} }
} }
}
// Function to format timestamp
function formatTimestamp(timestamp) { // Function to format timestamp
if (!timestamp) return "" function formatTimestamp(timestamp) {
if (!timestamp)
const now = new Date() return ""
const diff = now - timestamp
const now = new Date()
// Less than 1 minute const diff = now - timestamp
if (diff < 60000) {
return "now" // Less than 1 minute
} if (diff < 60000) {
// Less than 1 hour return "now"
else if (diff < 3600000) { } // Less than 1 hour
const minutes = Math.floor(diff / 60000) else if (diff < 3600000) {
return `${minutes}m ago` const minutes = Math.floor(diff / 60000)
} return `${minutes}m ago`
// Less than 24 hours } // Less than 24 hours
else if (diff < 86400000) { else if (diff < 86400000) {
const hours = Math.floor(diff / 3600000) const hours = Math.floor(diff / 3600000)
return `${hours}h ago` return `${hours}h ago`
} } // More than 24 hours
// More than 24 hours else {
else { const days = Math.floor(diff / 86400000)
const days = Math.floor(diff / 86400000) return `${days}d ago`
return `${days}d ago`
}
} }
} }
}