notifications: destroy wrapper object when quickshell's notif is destroyed (#1465)

This commit is contained in:
end-4
2025-07-18 16:09:35 +07:00
parent 40f2e0b6a7
commit bab166baea
3 changed files with 30 additions and 17 deletions
@@ -53,7 +53,7 @@ Item { // Notification group area
onFinished: () => { onFinished: () => {
root.notifications.forEach((notif) => { root.notifications.forEach((notif) => {
Qt.callLater(() => { Qt.callLater(() => {
Notifications.discardNotification(notif.id); Notifications.discardNotification(notif.notificationId);
}); });
}); });
} }
@@ -70,7 +70,7 @@ Item { // Notification item area
easing.bezierCurve: Appearance.animation.elementMove.bezierCurve easing.bezierCurve: Appearance.animation.elementMove.bezierCurve
} }
onFinished: () => { onFinished: () => {
Notifications.discardNotification(notificationObject.id); Notifications.discardNotification(notificationObject.notificationId);
} }
} }
@@ -269,7 +269,7 @@ Item { // Notification item area
buttonText: modelData.text buttonText: modelData.text
urgency: notificationObject.urgency urgency: notificationObject.urgency
onClicked: { onClicked: {
Notifications.attemptInvokeAction(notificationObject.id, modelData.identifier); Notifications.attemptInvokeAction(notificationObject.notificationId, modelData.identifier);
} }
} }
} }
@@ -17,7 +17,8 @@ import Quickshell.Services.Notifications
Singleton { Singleton {
id: root id: root
component Notif: QtObject { component Notif: QtObject {
required property int id id: wrapper
required property int notificationId // Could just be `id` but it conflicts with the default prop in QtObject
property Notification notification property Notification notification
property list<var> actions: notification?.actions.map((action) => ({ property list<var> actions: notification?.actions.map((action) => ({
"identifier": action.identifier, "identifier": action.identifier,
@@ -32,11 +33,19 @@ Singleton {
property double time property double time
property string urgency: notification?.urgency.toString() ?? "normal" property string urgency: notification?.urgency.toString() ?? "normal"
property Timer timer property Timer timer
readonly property Connections conn: Connections {
target: wrapper.notification.Component
function onDestruction(): void {
wrapper.destroy();
}
}
} }
function notifToJSON(notif) { function notifToJSON(notif) {
return { return {
"id": notif.id, "notificationId": notif.notificationId,
"actions": notif.actions, "actions": notif.actions,
"appIcon": notif.appIcon, "appIcon": notif.appIcon,
"appName": notif.appName, "appName": notif.appName,
@@ -52,11 +61,11 @@ Singleton {
} }
component NotifTimer: Timer { component NotifTimer: Timer {
required property int id required property int notificationId
interval: 5000 interval: 5000
running: true running: true
onTriggered: () => { onTriggered: () => {
root.timeoutNotification(id); root.timeoutNotification(notificationId);
destroy() destroy()
} }
} }
@@ -130,7 +139,7 @@ Singleton {
property int idOffset property int idOffset
signal initDone(); signal initDone();
signal notify(notification: var); signal notify(notification: var);
signal discard(id: var); signal discard(id: int);
signal discardAll(); signal discardAll();
signal timeout(id: var); signal timeout(id: var);
@@ -149,7 +158,7 @@ Singleton {
onNotification: (notification) => { onNotification: (notification) => {
notification.tracked = true notification.tracked = true
const newNotifObject = notifComponent.createObject(root, { const newNotifObject = notifComponent.createObject(root, {
"id": notification.id + root.idOffset, "notificationId": notification.id + root.idOffset,
"notification": notification, "notification": notification,
"time": Date.now(), "time": Date.now(),
}); });
@@ -159,7 +168,7 @@ Singleton {
if (!root.popupInhibited) { if (!root.popupInhibited) {
newNotifObject.popup = true; newNotifObject.popup = true;
newNotifObject.timer = notifTimerComponent.createObject(root, { newNotifObject.timer = notifTimerComponent.createObject(root, {
"id": newNotifObject.id, "notificationId": newNotifObject.notificationId,
"interval": notification.expireTimeout < 0 ? 5000 : notification.expireTimeout, "interval": notification.expireTimeout < 0 ? 5000 : notification.expireTimeout,
}); });
} }
@@ -171,7 +180,8 @@ Singleton {
} }
function discardNotification(id) { function discardNotification(id) {
const index = root.list.findIndex((notif) => notif.id === id); console.log("[Notifications] Discarding notification with ID: " + id);
const index = root.list.findIndex((notif) => notif.notificationId === id);
const notifServerIndex = notifServer.trackedNotifications.values.findIndex((notif) => notif.id + root.idOffset === id); const notifServerIndex = notifServer.trackedNotifications.values.findIndex((notif) => notif.id + root.idOffset === id);
if (index !== -1) { if (index !== -1) {
root.list.splice(index, 1); root.list.splice(index, 1);
@@ -181,7 +191,7 @@ Singleton {
if (notifServerIndex !== -1) { if (notifServerIndex !== -1) {
notifServer.trackedNotifications.values[notifServerIndex].dismiss() notifServer.trackedNotifications.values[notifServerIndex].dismiss()
} }
root.discard(id); root.discard(id); // Emit signal
} }
function discardAllNotifications() { function discardAllNotifications() {
@@ -195,7 +205,7 @@ Singleton {
} }
function timeoutNotification(id) { function timeoutNotification(id) {
const index = root.list.findIndex((notif) => notif.id === id); const index = root.list.findIndex((notif) => notif.notificationId === id);
if (root.list[index] != null) if (root.list[index] != null)
root.list[index].popup = false; root.list[index].popup = false;
root.timeout(id); root.timeout(id);
@@ -203,7 +213,7 @@ Singleton {
function timeoutAll() { function timeoutAll() {
root.popupList.forEach((notif) => { root.popupList.forEach((notif) => {
root.timeout(notif.id); root.timeout(notif.notificationId);
}) })
root.popupList.forEach((notif) => { root.popupList.forEach((notif) => {
notif.popup = false; notif.popup = false;
@@ -211,10 +221,13 @@ Singleton {
} }
function attemptInvokeAction(id, notifIdentifier) { function attemptInvokeAction(id, notifIdentifier) {
console.log("[Notifications] Attempting to invoke action with identifier: " + notifIdentifier + " for notification ID: " + id);
const notifServerIndex = notifServer.trackedNotifications.values.findIndex((notif) => notif.id + root.idOffset === id); const notifServerIndex = notifServer.trackedNotifications.values.findIndex((notif) => notif.id + root.idOffset === id);
console.log("Notification server index: " + notifServerIndex);
if (notifServerIndex !== -1) { if (notifServerIndex !== -1) {
const notifServerNotif = notifServer.trackedNotifications.values[notifServerIndex]; const notifServerNotif = notifServer.trackedNotifications.values[notifServerIndex];
const action = notifServerNotif.actions.find((action) => action.identifier === notifIdentifier); const action = notifServerNotif.actions.find((action) => action.identifier === notifIdentifier);
console.log("Action found: " + JSON.stringify(action));
action.invoke() action.invoke()
} }
else { else {
@@ -242,7 +255,7 @@ Singleton {
const fileContents = notifFileView.text() const fileContents = notifFileView.text()
root.list = JSON.parse(fileContents).map((notif) => { root.list = JSON.parse(fileContents).map((notif) => {
return notifComponent.createObject(root, { return notifComponent.createObject(root, {
"id": notif.id, "notificationId": notif.notificationId,
"actions": [], // Notification actions are meaningless if they're not tracked by the server or the sender is dead "actions": [], // Notification actions are meaningless if they're not tracked by the server or the sender is dead
"appIcon": notif.appIcon, "appIcon": notif.appIcon,
"appName": notif.appName, "appName": notif.appName,
@@ -253,10 +266,10 @@ Singleton {
"urgency": notif.urgency, "urgency": notif.urgency,
}); });
}); });
// Find largest id // Find largest notificationId
let maxId = 0 let maxId = 0
root.list.forEach((notif) => { root.list.forEach((notif) => {
maxId = Math.max(maxId, notif.id) maxId = Math.max(maxId, notif.notificationId)
}) })
console.log("[Notifications] File loaded") console.log("[Notifications] File loaded")