notifications: timeout, prevent some warnings when dismissing notif

This commit is contained in:
end-4
2025-05-26 09:37:57 +02:00
parent ce9993071c
commit ea41ee4241
3 changed files with 106 additions and 37 deletions
@@ -21,7 +21,7 @@ import Quickshell.Services.Notifications
Item { // Notification group area
id: root
property var notificationGroup
property var notifications: notificationGroup.notifications
property var notifications: notificationGroup?.notifications ?? []
property int notificationCount: notifications.length
property bool multipleNotifications: notificationCount > 1
property bool expanded: false
@@ -60,7 +60,9 @@ Item { // Notification group area
}
onFinished: () => {
root.notifications.forEach((notif) => {
Notifications.discardNotification(notif.id);
Qt.callLater(() => {
Notifications.discardNotification(notif.id);
});
});
}
}
@@ -153,16 +155,16 @@ Item { // Notification group area
NotificationAppIcon { // Icons
Layout.alignment: Qt.AlignTop
Layout.fillWidth: false
image: root.multipleNotifications ? "" : notificationGroup.notifications[0].image
appIcon: notificationGroup.appIcon
summary: notificationGroup.notifications[root.notificationCount - 1].summary
image: root?.multipleNotifications ? "" : notificationGroup?.notifications[0]?.image ?? ""
appIcon: notificationGroup?.appIcon
summary: notificationGroup?.notifications[root.notificationCount - 1]?.summary
}
ColumnLayout { // Content
Layout.fillWidth: true
spacing: expanded ?
((root.multipleNotifications &&
notificationGroup.notifications[root.notificationCount - 1].image != "") ? 35 :
notificationGroup?.notifications[root.notificationCount - 1].image != "") ? 35 :
5) : 0
Behavior on spacing {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
@@ -176,9 +178,9 @@ Item { // Notification group area
StyledText {
id: appName
text: topRow.showAppName ?
notificationGroup.appName :
notificationGroup.notifications[0].summary
text: (topRow.showAppName ?
notificationGroup?.appName :
notificationGroup?.notifications[0]?.summary) || ""
font.pixelSize: topRow.showAppName ?
topRow.fontSize :
Appearance.font.pixelSize.small
@@ -188,7 +190,7 @@ Item { // Notification group area
}
StyledText {
id: timeText
text: " • " + NotificationUtils.getFriendlyNotifTimeString(notificationGroup.time)
text: " • " + NotificationUtils.getFriendlyNotifTimeString(notificationGroup?.time)
font.pixelSize: topRow.fontSize
color: Appearance.colors.colSubtext
Layout.alignment: Qt.AlignRight
@@ -60,6 +60,7 @@ function findSuitableMaterialSymbol(summary = "") {
* @returns { string }
*/
const getFriendlyNotifTimeString = (timestamp) => {
if (!timestamp) return '';
const messageTime = new Date(timestamp);
const now = new Date();
const oneMinuteAgo = new Date(now.getTime() - 60000);
+93 -27
View File
@@ -11,11 +11,67 @@ import Qt.labs.platform
Singleton {
id: root
component Notif: QtObject {
required property int id
property Notification notification
property list<var> actions: notification?.actions.map((action) => ({
"identifier": action.identifier,
"text": action.text,
})) ?? []
property bool popup: false
property string appIcon: notification?.appIcon ?? ""
property string appName: notification?.appName ?? ""
property string body: notification?.body ?? ""
property string image: notification?.image ?? ""
property string summary: notification?.summary ?? ""
property double time
property string urgency: notification?.urgency.toString() ?? "normal"
property Timer timer
}
function notifToJSON(notif) {
return {
"id": notif.id,
"actions": notif.actions,
"appIcon": notif.appIcon,
"appName": notif.appName,
"body": notif.body,
"image": notif.image,
"summary": notif.summary,
"time": notif.time,
"urgency": notif.urgency,
}
}
function notifToString(notif) {
return JSON.stringify(notifToJSON(notif), null, 2);
}
component NotifTimer: Timer {
required property int id
interval: 5000
running: true
onTriggered: () => {
root.timeoutNotification(id);
destroy()
}
}
property var filePath: `${XdgDirectories.cache}/notifications/notifications.json`
property var list: []
property var popupList: []
property list<Notif> list: []
property var popupList: list.filter((notif) => notif.popup);
property bool popupInhibited: GlobalStates?.sidebarRightOpen ?? false
property var latestTimeForApp: ({})
Component {
id: notifComponent
Notif {}
}
Component {
id: notifTimerComponent
NotifTimer {}
}
function stringifyList(list) {
return JSON.stringify(list.map((notif) => notifToJSON(notif)), null, 2);
}
onListChanged: {
// Update latest time for each app
@@ -85,29 +141,25 @@ Singleton {
onNotification: (notification) => {
notification.tracked = true
const newNotifObject = {
const newNotifObject = notifComponent.createObject(root, {
"id": notification.id + root.idOffset,
"actions": notification.actions.map((action) => {
return {
"identifier": action.identifier,
"text": action.text,
}
}),
"appIcon": notification.appIcon,
"appName": notification.appName,
"body": notification.body,
"image": notification.image,
"summary": notification.summary,
"notification": notification,
"time": Date.now(),
"urgency": notification.urgency.toString(),
}
});
root.list = [...root.list, newNotifObject];
// console.log(root.popupInhibited)
// Popup
if (!root.popupInhibited) {
root.popupList = [...root.popupList, newNotifObject];
newNotifObject.popup = true;
newNotifObject.timer = notifTimerComponent.createObject(root, {
"id": newNotifObject.id,
"interval": notification.expireTimeout < 0 ? 5000 : notification.expireTimeout,
});
}
root.notify(newNotifObject);
notifFileView.setText(JSON.stringify(root.list, null, 2))
// console.log(notifToString(newNotifObject));
notifFileView.setText(stringifyList(root.list));
}
}
@@ -116,20 +168,19 @@ Singleton {
const notifServerIndex = notifServer.trackedNotifications.values.findIndex((notif) => notif.id + root.idOffset === id);
if (index !== -1) {
root.list.splice(index, 1);
notifFileView.setText(JSON.stringify(root.list, null, 2))
notifFileView.setText(stringifyList(root.list));
triggerListChange()
}
if (notifServerIndex !== -1) {
notifServer.trackedNotifications.values[notifServerIndex].dismiss()
}
root.popupList = root.popupList.filter((notif) => notif.id !== id);
root.discard(id);
}
function discardAllNotifications() {
root.list = []
triggerListChange()
notifFileView.setText(JSON.stringify(root.list, null, 2))
notifFileView.setText(stringifyList(root.list));
notifServer.trackedNotifications.values.forEach((notif) => {
notif.dismiss()
})
@@ -138,15 +189,18 @@ Singleton {
function timeoutNotification(id) {
const index = root.list.findIndex((notif) => notif.id === id);
root.popupList = root.popupList.filter((notif) => notif.id !== id);
if (root.list[index] != null)
root.list[index].popup = false;
root.timeout(id);
}
function timeoutAll() {
root.list.forEach((notif) => {
root.popupList.forEach((notif) => {
root.timeout(notif.id);
})
root.popupList = []
root.popupList.forEach((notif) => {
notif.popup = false;
});
}
function attemptInvokeAction(id, notifIdentifier) {
@@ -177,7 +231,19 @@ Singleton {
path: filePath
onLoaded: {
const fileContents = notifFileView.text()
root.list = JSON.parse(fileContents)
root.list = JSON.parse(fileContents).map((notif) => {
return notifComponent.createObject(root, {
"id": notif.id,
"actions": notif.actions,
"appIcon": notif.appIcon,
"appName": notif.appName,
"body": notif.body,
"image": notif.image,
"summary": notif.summary,
"time": notif.time,
"urgency": notif.urgency,
});
});
// Find largest id
let maxId = 0
root.list.forEach((notif) => {
@@ -192,7 +258,7 @@ Singleton {
if(error == FileViewError.FileNotFound) {
console.log("[Notifications] File not found, creating new file.")
root.list = []
notifFileView.setText(JSON.stringify(root.list))
notifFileView.setText(stringifyList(root.list));
} else {
console.log("[Notifications] Error loading file: " + error)
}