From 9d142fbaf3f0b355cf0ff219a803980cffca03bf Mon Sep 17 00:00:00 2001 From: Lemmy Date: Thu, 12 Mar 2026 11:00:50 -0400 Subject: [PATCH] refactor(notif): rename internals for clarity (popup vs history) --- Modules/Bar/Widgets/NotificationHistory.qml | 6 +- Modules/Notification/Notification.qml | 6 +- .../NotificationHistoryPanel.qml | 26 +- Services/Control/IPCService.qml | 12 +- Services/System/NotificationService.qml | 243 +++++++++--------- 5 files changed, 144 insertions(+), 149 deletions(-) diff --git a/Modules/Bar/Widgets/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml index e191e37c3..c7b82e7e2 100644 --- a/Modules/Bar/Widgets/NotificationHistory.qml +++ b/Modules/Bar/Widgets/NotificationHistory.qml @@ -43,7 +43,7 @@ NIconButton { function computeUnreadCount() { var since = NotificationService.lastSeenTs; var count = 0; - var model = NotificationService.historyList; + var model = NotificationService.historyModel; for (var i = 0; i < model.count; i++) { var item = model.get(i); var ts = item.timestamp instanceof Date ? item.timestamp.getTime() : item.timestamp; @@ -71,8 +71,8 @@ NIconButton { colorFg: Color.resolveColorKey(iconColorKey) border.color: Style.capsuleBorderColor border.width: Style.capsuleBorderWidth - visible: !((hideWhenZero && NotificationService.historyList.count === 0) || (hideWhenZeroUnread && count === 0)) - opacity: !((hideWhenZero && NotificationService.historyList.count === 0) || (hideWhenZeroUnread && count === 0)) ? 1.0 : 0.0 + visible: !((hideWhenZero && NotificationService.historyModel.count === 0) || (hideWhenZeroUnread && count === 0)) + opacity: !((hideWhenZero && NotificationService.historyModel.count === 0) || (hideWhenZeroUnread && count === 0)) ? 1.0 : 0.0 NPopupContextMenu { id: contextMenu diff --git a/Modules/Notification/Notification.qml b/Modules/Notification/Notification.qml index 0c56c7fe1..d971681ae 100644 --- a/Modules/Notification/Notification.qml +++ b/Modules/Notification/Notification.qml @@ -26,7 +26,7 @@ Variants { required property ShellScreen modelData - property ListModel notificationModel: NotificationService.activeList + property ListModel notificationModel: NotificationService.popupModel // Deferred activation to prevent re-entrant QML incubation crash. // Direct binding to notificationModel.count would activate the Loader @@ -177,7 +177,7 @@ Variants { } } catch (e) { // Service fallback if delegate is already invalid - NotificationService.dismissActiveNotification(notificationId); + NotificationService.dismissPopup(notificationId); } }; @@ -369,7 +369,7 @@ Variants { interval: Style.animationSlow repeat: false onTriggered: { - NotificationService.dismissActiveNotification(notificationId); + NotificationService.dismissPopup(notificationId); } } diff --git a/Modules/Panels/NotificationHistory/NotificationHistoryPanel.qml b/Modules/Panels/NotificationHistory/NotificationHistoryPanel.qml index 42ccc0b70..6117f45cb 100644 --- a/Modules/Panels/NotificationHistory/NotificationHistoryPanel.qml +++ b/Modules/Panels/NotificationHistory/NotificationHistoryPanel.qml @@ -95,7 +95,7 @@ SmartPanel { } function moveSelection(dir) { - var m = NotificationService.historyList; + var m = NotificationService.historyModel; if (!m || m.count === 0) return; @@ -139,7 +139,7 @@ SmartPanel { function moveAction(dir) { if (focusIndex === -1) return; - var item = NotificationService.historyList.get(focusIndex); + var item = NotificationService.historyModel.get(focusIndex); if (!item) return; @@ -162,7 +162,7 @@ SmartPanel { function activateSelection() { if (focusIndex === -1) return; - var item = NotificationService.historyList.get(focusIndex); + var item = NotificationService.historyModel.get(focusIndex); if (!item) return; @@ -189,7 +189,7 @@ SmartPanel { function removeSelection() { if (focusIndex === -1) return; - var item = NotificationService.historyList.get(focusIndex); + var item = NotificationService.historyModel.get(focusIndex); if (!item) return; @@ -237,7 +237,7 @@ SmartPanel { // Calculate content height based on header + tabs (if visible) + content property real calculatedHeight: { - if (NotificationService.historyList.count === 0) { + if (NotificationService.historyModel.count === 0) { return headerBox.implicitHeight + scrollView.implicitHeight + Style.margin2L + Style.marginM; } return headerBox.implicitHeight + scrollView.implicitHeight + Style.margin2L + Style.marginM; @@ -296,7 +296,7 @@ SmartPanel { } function recalcRangeCounts() { - var m = NotificationService.historyList; + var m = NotificationService.historyModel; if (!m || typeof m.count === "undefined" || m.count <= 0) { panelContent.rangeCounts = [0, 0, 0, 0]; return; @@ -328,7 +328,7 @@ SmartPanel { } function hasNotificationsInCurrentRange() { - var m = NotificationService.historyList; + var m = NotificationService.historyModel; if (!m || m.count === 0) { return false; } @@ -347,7 +347,7 @@ SmartPanel { } Connections { - target: NotificationService.historyList + target: NotificationService.historyModel function onCountChanged() { panelContent.recalcRangeCounts(); } @@ -433,7 +433,7 @@ SmartPanel { NTabBar { id: tabsBox Layout.fillWidth: true - visible: NotificationService.historyList.count > 0 && panelContent.groupByDate + visible: NotificationService.historyModel.count > 0 && panelContent.groupByDate currentIndex: panelContent.currentRange tabHeight: Style.toOdd(Style.baseWidgetSize * 0.8) spacing: Style.marginXS @@ -512,20 +512,20 @@ SmartPanel { NIcon { icon: "bell-off" - pointSize: (NotificationService.historyList.count === 0) ? 48 : Style.baseWidgetSize + pointSize: (NotificationService.historyModel.count === 0) ? 48 : Style.baseWidgetSize color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } NText { text: I18n.tr("notifications.panel.no-notifications") - pointSize: (NotificationService.historyList.count === 0) ? Style.fontSizeL : Style.fontSizeM + pointSize: (NotificationService.historyModel.count === 0) ? Style.fontSizeL : Style.fontSizeM color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } NText { - visible: NotificationService.historyList.count === 0 + visible: NotificationService.historyModel.count === 0 text: I18n.tr("notifications.panel.description") pointSize: Style.fontSizeS color: Color.mOnSurfaceVariant @@ -552,7 +552,7 @@ SmartPanel { spacing: Style.marginM Repeater { - model: NotificationService.historyList + model: NotificationService.historyModel delegate: Item { id: notificationDelegate diff --git a/Services/Control/IPCService.qml b/Services/Control/IPCService.qml index 91bad8c6d..7ec2b38eb 100644 --- a/Services/Control/IPCService.qml +++ b/Services/Control/IPCService.qml @@ -37,11 +37,11 @@ Singleton { Logger.w("IPC", "Argument to ipc call '" + funcName + "' must be a number"); return null; } - if (idx < 0 || idx >= NotificationService.activeList.count) { + if (idx < 0 || idx >= NotificationService.popupModel.count) { Logger.w("IPC", "Notification index out of range: " + idx); return null; } - return NotificationService.activeList.get(idx); + return NotificationService.popupModel.get(idx); } IpcHandler { @@ -191,7 +191,7 @@ Singleton { } function dismissOldest() { - NotificationService.dismissOldestActive(); + NotificationService.dismissOldestPopup(); } function removeOldestHistory() { @@ -199,7 +199,7 @@ Singleton { } function dismissAll() { - NotificationService.dismissAllActive(); + NotificationService.dismissAllPopups(); } function getHistory(): string { @@ -230,13 +230,13 @@ Singleton { var actions = JSON.parse(notif.actionsJson || "[]"); if (actions.length === 0) { - NotificationService.dismissActiveNotification(notif.id); + NotificationService.dismissPopup(notif.id); return false; } var actionId = actions.find(a => a.identifier === "default")?.identifier ?? actions[0].identifier; var result = NotificationService.invokeAction(notif.id, actionId); - NotificationService.dismissActiveNotification(notif.id); + NotificationService.dismissPopup(notif.id); return result; } diff --git a/Services/System/NotificationService.qml b/Services/System/NotificationService.qml index b68e6cfb2..3c7eb411f 100644 --- a/Services/System/NotificationService.qml +++ b/Services/System/NotificationService.qml @@ -17,7 +17,7 @@ Singleton { id: root // Configuration - property int maxVisible: 5 + property int maxPopups: 5 property int maxHistory: 100 property string historyFile: Quickshell.env("NOCTALIA_NOTIF_HISTORY_FILE") || (Settings.cacheDir + "notifications.json") @@ -27,11 +27,11 @@ Singleton { property bool doNotDisturb: false // Models - property ListModel activeList: ListModel {} - property ListModel historyList: ListModel {} + property ListModel popupModel: ListModel {} + property ListModel historyModel: ListModel {} // Internal state - property var activeNotifications: ({}) // Maps internal ID to {notification, watcher, metadata} + property var popupState: ({}) // Maps internal ID to {notification, watcher, cachedActions, metadata} property var quickshellIdToInternalId: ({}) // Rate limiting for notification sounds (minimum 100ms between sounds) @@ -167,19 +167,19 @@ Singleton { // Check if this is a replacement notification const existingInternalId = quickshellIdToInternalId[quickshellId]; - if (existingInternalId && activeNotifications[existingInternalId]) { - updateExistingNotification(existingInternalId, notification, data); + if (existingInternalId && popupState[existingInternalId]) { + updatePopup(existingInternalId, notification, data); return; } // Check for duplicate content const duplicateId = findDuplicateNotification(data); if (duplicateId) { - removeNotification(duplicateId); + removePopup(duplicateId); } // Add new notification - addNewNotification(quickshellId, notification, data); + addPopup(quickshellId, notification, data); playNotificationSound(data.urgency, notification.appName); } @@ -277,30 +277,30 @@ Singleton { return defaultSoundFile; } - function updateExistingNotification(internalId, notification, data) { - const index = findNotificationIndex(internalId); + function updatePopup(internalId, notification, data) { + const index = findPopupIndex(internalId); if (index < 0) return; - const existing = activeList.get(index); + const existing = popupModel.get(index); const oldTimestamp = existing.timestamp; const oldProgress = existing.progress; // Update properties (keeping original timestamp and progress) - activeList.setProperty(index, "summary", data.summary); - activeList.setProperty(index, "summaryMarkdown", data.summaryMarkdown); - activeList.setProperty(index, "body", data.body); - activeList.setProperty(index, "bodyMarkdown", data.bodyMarkdown); - activeList.setProperty(index, "appName", data.appName); - activeList.setProperty(index, "urgency", data.urgency); - activeList.setProperty(index, "expireTimeout", data.expireTimeout); - activeList.setProperty(index, "originalImage", data.originalImage); - activeList.setProperty(index, "cachedImage", data.cachedImage); - activeList.setProperty(index, "actionsJson", data.actionsJson); - activeList.setProperty(index, "timestamp", oldTimestamp); - activeList.setProperty(index, "progress", oldProgress); + popupModel.setProperty(index, "summary", data.summary); + popupModel.setProperty(index, "summaryMarkdown", data.summaryMarkdown); + popupModel.setProperty(index, "body", data.body); + popupModel.setProperty(index, "bodyMarkdown", data.bodyMarkdown); + popupModel.setProperty(index, "appName", data.appName); + popupModel.setProperty(index, "urgency", data.urgency); + popupModel.setProperty(index, "expireTimeout", data.expireTimeout); + popupModel.setProperty(index, "originalImage", data.originalImage); + popupModel.setProperty(index, "cachedImage", data.cachedImage); + popupModel.setProperty(index, "actionsJson", data.actionsJson); + popupModel.setProperty(index, "timestamp", oldTimestamp); + popupModel.setProperty(index, "progress", oldProgress); // Update stored notification object - const notifData = activeNotifications[internalId]; + const notifData = popupState[internalId]; notifData.notification = notification; // Deep copy actions to preserve them even if QML object clears list @@ -319,7 +319,7 @@ Singleton { notification.tracked = true; function onClosed() { - userDismissNotification(internalId); + dismissPopup(internalId); } notification.closed.connect(onClosed); notifData.onClosed = onClosed; @@ -329,7 +329,7 @@ Singleton { notifData.metadata.duration = calculateDuration(data); } - function addNewNotification(quickshellId, notification, data) { + function addPopup(quickshellId, notification, data) { // Map IDs quickshellIdToInternalId[quickshellId] = data.id; @@ -351,7 +351,7 @@ Singleton { } // Store notification data - activeNotifications[data.id] = { + popupState[data.id] = { "notification": notification, "watcher": watcher, "cachedActions": safeActions // Cache actions @@ -370,24 +370,24 @@ Singleton { notification.tracked = true; function onClosed() { - userDismissNotification(data.id); + dismissPopup(data.id); } notification.closed.connect(onClosed); - activeNotifications[data.id].onClosed = onClosed; + popupState[data.id].onClosed = onClosed; // Defer list insertion to prevent re-entrant QML incubation crash. // Direct insert triggers Repeater.modelUpdated synchronously, which // incubates delegates whose signal handlers can re-enter the V4 engine // and crash in QV4::Object::insertMember. Qt.callLater(() => { - activeList.insert(0, data); + popupModel.insert(0, data); // Remove overflow - while (activeList.count > maxVisible) { - const last = activeList.get(activeList.count - 1); + while (popupModel.count > maxPopups) { + const last = popupModel.get(popupModel.count - 1); // Overflow only removes from ACTIVE view, but keeps it for history - activeNotifications[last.id]?.notification?.dismiss(); // Visually dismiss - activeList.remove(activeList.count - 1); + popupState[last.id]?.notification?.dismiss(); // Visually dismiss + popupModel.remove(popupModel.count - 1); // DO NOT call cleanupNotification here, we want to keep it for history actions } }); @@ -396,8 +396,8 @@ Singleton { function findDuplicateNotification(data) { const contentId = getContentId(data.summary, data.body, data.appName); - for (var i = 0; i < activeList.count; i++) { - const existing = activeList.get(i); + for (var i = 0; i < popupModel.count; i++) { + const existing = popupModel.get(i); const existingContentId = getContentId(existing.summary, existing.body, existing.appName); if (existingContentId === contentId) { return existing.id; @@ -455,9 +455,9 @@ Singleton { }; } - function findNotificationIndex(internalId) { - for (var i = 0; i < activeList.count; i++) { - if (activeList.get(i).id === internalId) { + function findPopupIndex(internalId) { + for (var i = 0; i < popupModel.count; i++) { + if (popupModel.get(i).id === internalId) { return i; } } @@ -465,45 +465,45 @@ Singleton { } function updateNotificationFromObject(internalId) { - const notifData = activeNotifications[internalId]; + const notifData = popupState[internalId]; if (!notifData) return; - const index = findNotificationIndex(internalId); + const index = findPopupIndex(internalId); if (index < 0) return; const data = createData(notifData.notification); - const existing = activeList.get(index); + const existing = popupModel.get(index); // Update properties (keeping timestamp and progress) - activeList.setProperty(index, "summary", data.summary); - activeList.setProperty(index, "summaryMarkdown", data.summaryMarkdown); - activeList.setProperty(index, "body", data.body); - activeList.setProperty(index, "bodyMarkdown", data.bodyMarkdown); - activeList.setProperty(index, "appName", data.appName); - activeList.setProperty(index, "urgency", data.urgency); - activeList.setProperty(index, "expireTimeout", data.expireTimeout); - activeList.setProperty(index, "originalImage", data.originalImage); - activeList.setProperty(index, "cachedImage", data.cachedImage); - activeList.setProperty(index, "actionsJson", data.actionsJson); + popupModel.setProperty(index, "summary", data.summary); + popupModel.setProperty(index, "summaryMarkdown", data.summaryMarkdown); + popupModel.setProperty(index, "body", data.body); + popupModel.setProperty(index, "bodyMarkdown", data.bodyMarkdown); + popupModel.setProperty(index, "appName", data.appName); + popupModel.setProperty(index, "urgency", data.urgency); + popupModel.setProperty(index, "expireTimeout", data.expireTimeout); + popupModel.setProperty(index, "originalImage", data.originalImage); + popupModel.setProperty(index, "cachedImage", data.cachedImage); + popupModel.setProperty(index, "actionsJson", data.actionsJson); // Update metadata notifData.metadata.urgency = data.urgency; notifData.metadata.duration = calculateDuration(data); } - function removeNotification(id) { - const index = findNotificationIndex(id); + function removePopup(id) { + const index = findPopupIndex(id); if (index >= 0) { - activeList.remove(index); + popupModel.remove(index); } cleanupNotification(id); } function cleanupNotification(id) { - const notifData = activeNotifications[id]; + const notifData = popupState[id]; if (notifData) { notifData.watcher?.destroy(); - delete activeNotifications[id]; + delete popupState[id]; } // Clean up quickshell ID mapping @@ -519,7 +519,7 @@ Singleton { Timer { interval: 50 repeat: true - running: activeList.count > 0 + running: popupModel.count > 0 onTriggered: updateAllProgress() } @@ -527,9 +527,9 @@ Singleton { const now = Date.now(); const toRemove = []; - for (var i = 0; i < activeList.count; i++) { - const notif = activeList.get(i); - const notifData = activeNotifications[notif.id]; + for (var i = 0; i < popupModel.count; i++) { + const notif = popupModel.get(i); + const notifData = popupState[notif.id]; if (!notifData) continue; const meta = notifData.metadata; @@ -541,7 +541,7 @@ Singleton { if (progress <= 0) { toRemove.push(notif.id); } else if (Math.abs(notif.progress - progress) > 0.005) { - activeList.setProperty(i, "progress", progress); + popupModel.setProperty(i, "progress", progress); } } @@ -571,8 +571,8 @@ Singleton { } function updateImagePath(notificationId, path) { - updateModel(activeList, notificationId, "cachedImage", path); - updateModel(historyList, notificationId, "cachedImage", path); + updateModel(popupModel, notificationId, "cachedImage", path); + updateModel(historyModel, notificationId, "cachedImage", path); saveHistory(); } @@ -588,18 +588,18 @@ Singleton { // History management function addToHistory(data) { // Defer list insertion to prevent re-entrant QML incubation crash. - // See addNewNotification for full explanation. + // See addPopup for full explanation. Qt.callLater(() => { - historyList.insert(0, data); + historyModel.insert(0, data); - while (historyList.count > maxHistory) { - const old = historyList.get(historyList.count - 1); + while (historyModel.count > maxHistory) { + const old = historyModel.get(historyModel.count - 1); // Only delete cached images that are in our cache directory const cachedPath = old.cachedImage ? old.cachedImage.replace(/^file:\/\//, "") : ""; if (cachedPath && cachedPath.startsWith(ImageCacheService.notificationsDir)) { Quickshell.execDetached(["rm", "-f", cachedPath]); } - historyList.remove(historyList.count - 1); + historyModel.remove(historyModel.count - 1); } saveHistory(); }); @@ -635,8 +635,8 @@ Singleton { function performSaveHistory() { try { const items = []; - for (var i = 0; i < historyList.count; i++) { - const n = historyList.get(i); + for (var i = 0; i < historyModel.count; i++) { + const n = historyModel.get(i); const copy = Object.assign({}, n); copy.timestamp = n.timestamp.getTime(); items.push(copy); @@ -650,7 +650,7 @@ Singleton { function loadHistory() { try { - historyList.clear(); + historyModel.clear(); for (const item of adapter.notifications || []) { const time = new Date(item.timestamp); @@ -660,20 +660,20 @@ Singleton { cachedImage = item.originalImage || ""; } - historyList.append({ - "id": item.id || "", - "summary": item.summary || "", - "summaryMarkdown": processNotificationMarkdown(item.summary || ""), - "body": item.body || "", - "bodyMarkdown": processNotificationMarkdown(item.body || ""), - "appName": item.appName || "", - "urgency": item.urgency < 0 || item.urgency > 2 ? 1 : item.urgency, - "timestamp": time, - "originalImage": item.originalImage || "", - "cachedImage": cachedImage, - "actionsJson": item.actionsJson || "[]", - "originalId": item.originalId || 0 - }); + historyModel.append({ + "id": item.id || "", + "summary": item.summary || "", + "summaryMarkdown": processNotificationMarkdown(item.summary || ""), + "body": item.body || "", + "bodyMarkdown": processNotificationMarkdown(item.body || ""), + "appName": item.appName || "", + "urgency": item.urgency < 0 || item.urgency > 2 ? 1 : item.urgency, + "timestamp": time, + "originalImage": item.originalImage || "", + "cachedImage": cachedImage, + "actionsJson": item.actionsJson || "[]", + "originalId": item.originalId || 0 + }); } } catch (e) { Logger.e("Notifications", "Load failed:", e); @@ -870,7 +870,7 @@ Singleton { } function pauseTimeout(id) { - const notifData = activeNotifications[id]; + const notifData = popupState[id]; if (notifData && !notifData.metadata.paused) { notifData.metadata.paused = true; notifData.metadata.pauseTime = Date.now(); @@ -878,46 +878,41 @@ Singleton { } function resumeTimeout(id) { - const notifData = activeNotifications[id]; + const notifData = popupState[id]; if (notifData && notifData.metadata.paused) { notifData.metadata.timestamp += Date.now() - notifData.metadata.pauseTime; notifData.metadata.paused = false; } } - // Public API - function dismissActiveNotification(id) { - userDismissNotification(id); - } - - // User dismissed from active view (e.g. clicked close, or swipe) - // This behaves like "overflow" - removes from active list but KEEPS data for history - function userDismissNotification(id) { - const index = findNotificationIndex(id); + // Dismiss a popup notification (e.g. clicked close, swipe, or overflow). + // Removes from popup list but KEEPS data for history. + function dismissPopup(id) { + const index = findPopupIndex(id); if (index >= 0) { - activeList.remove(index); + popupModel.remove(index); } } - function dismissOldestActive() { - if (activeList.count > 0) { - const lastNotif = activeList.get(activeList.count - 1); - dismissActiveNotification(lastNotif.id); + function dismissOldestPopup() { + if (popupModel.count > 0) { + const lastNotif = popupModel.get(popupModel.count - 1); + dismissPopup(lastNotif.id); } } - function dismissAllActive() { - for (const id in activeNotifications) { - activeNotifications[id].notification?.dismiss(); - activeNotifications[id].watcher?.destroy(); + function dismissAllPopups() { + for (const id in popupState) { + popupState[id].notification?.dismiss(); + popupState[id].watcher?.destroy(); } - activeList.clear(); - activeNotifications = {}; + popupModel.clear(); + popupState = {}; quickshellIdToInternalId = {}; } function invokeActionAndSuppressClose(id, actionId) { - const notifData = activeNotifications[id]; + const notifData = popupState[id]; if (notifData && notifData.notification && notifData.onClosed) { try { notifData.notification.closed.disconnect(notifData.onClosed); @@ -929,7 +924,7 @@ Singleton { function invokeAction(id, actionId) { let invoked = false; - const notifData = activeNotifications[id]; + const notifData = popupState[id]; if (notifData && notifData.notification) { const actionsToUse = (notifData.notification.actions && notifData.notification.actions.length > 0) ? notifData.notification.actions : (notifData.cachedActions || []); @@ -966,9 +961,9 @@ Singleton { } } else if (!notifData) { Logger.w("NotificationService", "No active notification data for id=" + id + ", searching history for manual invoke"); - for (var i = 0; i < historyList.count; i++) { - if (historyList.get(i).id === id) { - const histEntry = historyList.get(i); + for (var i = 0; i < historyModel.count; i++) { + if (historyModel.get(i).id === id) { + const histEntry = historyModel.get(i); if (histEntry.originalId) { invoked = manualInvoke(histEntry.originalId, actionId); } @@ -983,8 +978,8 @@ Singleton { } // Clear actions after use - updateModel(activeList, id, "actionsJson", "[]"); - updateModel(historyList, id, "actionsJson", "[]"); + updateModel(popupModel, id, "actionsJson", "[]"); + updateModel(historyModel, id, "actionsJson", "[]"); saveHistory(); return true; @@ -1032,15 +1027,15 @@ Singleton { } function removeFromHistory(notificationId) { - for (var i = 0; i < historyList.count; i++) { - const notif = historyList.get(i); + for (var i = 0; i < historyModel.count; i++) { + const notif = historyModel.get(i); if (notif.id === notificationId) { // Only delete cached images that are in our cache directory const cachedPath = notif.cachedImage ? notif.cachedImage.replace(/^file:\/\//, "") : ""; if (cachedPath && cachedPath.startsWith(ImageCacheService.notificationsDir)) { Quickshell.execDetached(["rm", "-f", cachedPath]); } - historyList.remove(i); + historyModel.remove(i); saveHistory(); return true; } @@ -1049,14 +1044,14 @@ Singleton { } function removeOldestHistory() { - if (historyList.count > 0) { - const oldest = historyList.get(historyList.count - 1); + if (historyModel.count > 0) { + const oldest = historyModel.get(historyModel.count - 1); // Only delete cached images that are in our cache directory const cachedPath = oldest.cachedImage ? oldest.cachedImage.replace(/^file:\/\//, "") : ""; if (cachedPath && cachedPath.startsWith(ImageCacheService.notificationsDir)) { Quickshell.execDetached(["rm", "-f", cachedPath]); } - historyList.remove(historyList.count - 1); + historyModel.remove(historyModel.count - 1); saveHistory(); return true; } @@ -1070,14 +1065,14 @@ Singleton { Logger.e("Notifications", "Failed to clear cache directory:", e); } - historyList.clear(); + historyModel.clear(); saveHistory(); } function getHistorySnapshot() { const items = []; - for (var i = 0; i < historyList.count; i++) { - const entry = historyList.get(i); + for (var i = 0; i < historyModel.count; i++) { + const entry = historyModel.get(i); items.push({ "id": entry.id, "summary": entry.summary,