forked from Shinonome/dots-hyprland
notifications: timeout, prevent some warnings when dismissing notif
This commit is contained in:
@@ -21,7 +21,7 @@ import Quickshell.Services.Notifications
|
|||||||
Item { // Notification group area
|
Item { // Notification group area
|
||||||
id: root
|
id: root
|
||||||
property var notificationGroup
|
property var notificationGroup
|
||||||
property var notifications: notificationGroup.notifications
|
property var notifications: notificationGroup?.notifications ?? []
|
||||||
property int notificationCount: notifications.length
|
property int notificationCount: notifications.length
|
||||||
property bool multipleNotifications: notificationCount > 1
|
property bool multipleNotifications: notificationCount > 1
|
||||||
property bool expanded: false
|
property bool expanded: false
|
||||||
@@ -60,7 +60,9 @@ Item { // Notification group area
|
|||||||
}
|
}
|
||||||
onFinished: () => {
|
onFinished: () => {
|
||||||
root.notifications.forEach((notif) => {
|
root.notifications.forEach((notif) => {
|
||||||
Notifications.discardNotification(notif.id);
|
Qt.callLater(() => {
|
||||||
|
Notifications.discardNotification(notif.id);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,16 +155,16 @@ Item { // Notification group area
|
|||||||
NotificationAppIcon { // Icons
|
NotificationAppIcon { // Icons
|
||||||
Layout.alignment: Qt.AlignTop
|
Layout.alignment: Qt.AlignTop
|
||||||
Layout.fillWidth: false
|
Layout.fillWidth: false
|
||||||
image: root.multipleNotifications ? "" : notificationGroup.notifications[0].image
|
image: root?.multipleNotifications ? "" : notificationGroup?.notifications[0]?.image ?? ""
|
||||||
appIcon: notificationGroup.appIcon
|
appIcon: notificationGroup?.appIcon
|
||||||
summary: notificationGroup.notifications[root.notificationCount - 1].summary
|
summary: notificationGroup?.notifications[root.notificationCount - 1]?.summary
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout { // Content
|
ColumnLayout { // Content
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: expanded ?
|
spacing: expanded ?
|
||||||
((root.multipleNotifications &&
|
((root.multipleNotifications &&
|
||||||
notificationGroup.notifications[root.notificationCount - 1].image != "") ? 35 :
|
notificationGroup?.notifications[root.notificationCount - 1].image != "") ? 35 :
|
||||||
5) : 0
|
5) : 0
|
||||||
Behavior on spacing {
|
Behavior on spacing {
|
||||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||||
@@ -176,9 +178,9 @@ Item { // Notification group area
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: appName
|
id: appName
|
||||||
text: topRow.showAppName ?
|
text: (topRow.showAppName ?
|
||||||
notificationGroup.appName :
|
notificationGroup?.appName :
|
||||||
notificationGroup.notifications[0].summary
|
notificationGroup?.notifications[0]?.summary) || ""
|
||||||
font.pixelSize: topRow.showAppName ?
|
font.pixelSize: topRow.showAppName ?
|
||||||
topRow.fontSize :
|
topRow.fontSize :
|
||||||
Appearance.font.pixelSize.small
|
Appearance.font.pixelSize.small
|
||||||
@@ -188,7 +190,7 @@ Item { // Notification group area
|
|||||||
}
|
}
|
||||||
StyledText {
|
StyledText {
|
||||||
id: timeText
|
id: timeText
|
||||||
text: " • " + NotificationUtils.getFriendlyNotifTimeString(notificationGroup.time)
|
text: " • " + NotificationUtils.getFriendlyNotifTimeString(notificationGroup?.time)
|
||||||
font.pixelSize: topRow.fontSize
|
font.pixelSize: topRow.fontSize
|
||||||
color: Appearance.colors.colSubtext
|
color: Appearance.colors.colSubtext
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ function findSuitableMaterialSymbol(summary = "") {
|
|||||||
* @returns { string }
|
* @returns { string }
|
||||||
*/
|
*/
|
||||||
const getFriendlyNotifTimeString = (timestamp) => {
|
const getFriendlyNotifTimeString = (timestamp) => {
|
||||||
|
if (!timestamp) return '';
|
||||||
const messageTime = new Date(timestamp);
|
const messageTime = new Date(timestamp);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const oneMinuteAgo = new Date(now.getTime() - 60000);
|
const oneMinuteAgo = new Date(now.getTime() - 60000);
|
||||||
|
|||||||
@@ -11,11 +11,67 @@ import Qt.labs.platform
|
|||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
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 filePath: `${XdgDirectories.cache}/notifications/notifications.json`
|
||||||
property var list: []
|
property list<Notif> list: []
|
||||||
property var popupList: []
|
property var popupList: list.filter((notif) => notif.popup);
|
||||||
property bool popupInhibited: GlobalStates?.sidebarRightOpen ?? false
|
property bool popupInhibited: GlobalStates?.sidebarRightOpen ?? false
|
||||||
property var latestTimeForApp: ({})
|
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: {
|
onListChanged: {
|
||||||
// Update latest time for each app
|
// Update latest time for each app
|
||||||
@@ -85,29 +141,25 @@ Singleton {
|
|||||||
|
|
||||||
onNotification: (notification) => {
|
onNotification: (notification) => {
|
||||||
notification.tracked = true
|
notification.tracked = true
|
||||||
const newNotifObject = {
|
const newNotifObject = notifComponent.createObject(root, {
|
||||||
"id": notification.id + root.idOffset,
|
"id": notification.id + root.idOffset,
|
||||||
"actions": notification.actions.map((action) => {
|
"notification": notification,
|
||||||
return {
|
|
||||||
"identifier": action.identifier,
|
|
||||||
"text": action.text,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
"appIcon": notification.appIcon,
|
|
||||||
"appName": notification.appName,
|
|
||||||
"body": notification.body,
|
|
||||||
"image": notification.image,
|
|
||||||
"summary": notification.summary,
|
|
||||||
"time": Date.now(),
|
"time": Date.now(),
|
||||||
"urgency": notification.urgency.toString(),
|
});
|
||||||
}
|
|
||||||
root.list = [...root.list, newNotifObject];
|
root.list = [...root.list, newNotifObject];
|
||||||
// console.log(root.popupInhibited)
|
|
||||||
|
// Popup
|
||||||
if (!root.popupInhibited) {
|
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);
|
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);
|
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);
|
||||||
notifFileView.setText(JSON.stringify(root.list, null, 2))
|
notifFileView.setText(stringifyList(root.list));
|
||||||
triggerListChange()
|
triggerListChange()
|
||||||
}
|
}
|
||||||
if (notifServerIndex !== -1) {
|
if (notifServerIndex !== -1) {
|
||||||
notifServer.trackedNotifications.values[notifServerIndex].dismiss()
|
notifServer.trackedNotifications.values[notifServerIndex].dismiss()
|
||||||
}
|
}
|
||||||
root.popupList = root.popupList.filter((notif) => notif.id !== id);
|
|
||||||
root.discard(id);
|
root.discard(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function discardAllNotifications() {
|
function discardAllNotifications() {
|
||||||
root.list = []
|
root.list = []
|
||||||
triggerListChange()
|
triggerListChange()
|
||||||
notifFileView.setText(JSON.stringify(root.list, null, 2))
|
notifFileView.setText(stringifyList(root.list));
|
||||||
notifServer.trackedNotifications.values.forEach((notif) => {
|
notifServer.trackedNotifications.values.forEach((notif) => {
|
||||||
notif.dismiss()
|
notif.dismiss()
|
||||||
})
|
})
|
||||||
@@ -138,15 +189,18 @@ Singleton {
|
|||||||
|
|
||||||
function timeoutNotification(id) {
|
function timeoutNotification(id) {
|
||||||
const index = root.list.findIndex((notif) => notif.id === 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);
|
root.timeout(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function timeoutAll() {
|
function timeoutAll() {
|
||||||
root.list.forEach((notif) => {
|
root.popupList.forEach((notif) => {
|
||||||
root.timeout(notif.id);
|
root.timeout(notif.id);
|
||||||
})
|
})
|
||||||
root.popupList = []
|
root.popupList.forEach((notif) => {
|
||||||
|
notif.popup = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function attemptInvokeAction(id, notifIdentifier) {
|
function attemptInvokeAction(id, notifIdentifier) {
|
||||||
@@ -177,7 +231,19 @@ Singleton {
|
|||||||
path: filePath
|
path: filePath
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
const fileContents = notifFileView.text()
|
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
|
// Find largest id
|
||||||
let maxId = 0
|
let maxId = 0
|
||||||
root.list.forEach((notif) => {
|
root.list.forEach((notif) => {
|
||||||
@@ -192,7 +258,7 @@ Singleton {
|
|||||||
if(error == FileViewError.FileNotFound) {
|
if(error == FileViewError.FileNotFound) {
|
||||||
console.log("[Notifications] File not found, creating new file.")
|
console.log("[Notifications] File not found, creating new file.")
|
||||||
root.list = []
|
root.list = []
|
||||||
notifFileView.setText(JSON.stringify(root.list))
|
notifFileView.setText(stringifyList(root.list));
|
||||||
} else {
|
} else {
|
||||||
console.log("[Notifications] Error loading file: " + error)
|
console.log("[Notifications] Error loading file: " + error)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user