mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2026-08-15 18:43:59 +00:00
Switched to qmlformat.
This commit is contained in:
@@ -5,10 +5,10 @@ import QtQuick.Window
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Services.Notifications
|
||||
import "../../Helpers/sha256.js" as Checksum
|
||||
import qs.Commons
|
||||
import qs.Services.Power
|
||||
import qs.Services.UI
|
||||
import "../../Helpers/sha256.js" as Checksum
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
@@ -50,28 +50,30 @@ Singleton {
|
||||
antialiasing: true
|
||||
|
||||
onStatusChanged: {
|
||||
if (imageQueue.length === 0)
|
||||
return
|
||||
const req = imageQueue[0]
|
||||
if (imageQueue.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const req = imageQueue[0];
|
||||
|
||||
if (status === Image.Ready) {
|
||||
Quickshell.execDetached(["mkdir", "-p", Settings.cacheDirImagesNotifications])
|
||||
Quickshell.execDetached(["mkdir", "-p", Settings.cacheDirImagesNotifications]);
|
||||
grabToImage(result => {
|
||||
if (result.saveToFile(req.dest))
|
||||
updateImagePath(req.imageId, req.dest)
|
||||
processNextImage()
|
||||
})
|
||||
updateImagePath(req.imageId, req.dest);
|
||||
processNextImage();
|
||||
});
|
||||
} else if (status === Image.Error) {
|
||||
processNextImage()
|
||||
processNextImage();
|
||||
}
|
||||
}
|
||||
|
||||
function processNextImage() {
|
||||
imageQueue.shift()
|
||||
imageQueue.shift();
|
||||
if (imageQueue.length > 0) {
|
||||
source = imageQueue[0].src
|
||||
source = imageQueue[0].src;
|
||||
} else {
|
||||
source = ""
|
||||
source = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,53 +100,53 @@ Singleton {
|
||||
target: targetNotification
|
||||
|
||||
function onSummaryChanged() {
|
||||
updateNotificationFromObject(targetDataId)
|
||||
updateNotificationFromObject(targetDataId);
|
||||
}
|
||||
function onBodyChanged() {
|
||||
updateNotificationFromObject(targetDataId)
|
||||
updateNotificationFromObject(targetDataId);
|
||||
}
|
||||
function onAppNameChanged() {
|
||||
updateNotificationFromObject(targetDataId)
|
||||
updateNotificationFromObject(targetDataId);
|
||||
}
|
||||
function onUrgencyChanged() {
|
||||
updateNotificationFromObject(targetDataId)
|
||||
updateNotificationFromObject(targetDataId);
|
||||
}
|
||||
function onAppIconChanged() {
|
||||
updateNotificationFromObject(targetDataId)
|
||||
updateNotificationFromObject(targetDataId);
|
||||
}
|
||||
function onImageChanged() {
|
||||
updateNotificationFromObject(targetDataId)
|
||||
updateNotificationFromObject(targetDataId);
|
||||
}
|
||||
function onActionsChanged() {
|
||||
updateNotificationFromObject(targetDataId)
|
||||
updateNotificationFromObject(targetDataId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateNotificationServer() {
|
||||
if (notificationServerLoader) {
|
||||
notificationServerLoader.destroy()
|
||||
notificationServerLoader = null
|
||||
notificationServerLoader.destroy();
|
||||
notificationServerLoader = null;
|
||||
}
|
||||
|
||||
if (Settings.isLoaded && Settings.data.notifications.enabled !== false) {
|
||||
notificationServerLoader = notificationServerComponent.createObject(root)
|
||||
notificationServerLoader = notificationServerComponent.createObject(root);
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (Settings.isLoaded) {
|
||||
updateNotificationServer()
|
||||
updateNotificationServer();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Settings
|
||||
function onSettingsLoaded() {
|
||||
updateNotificationServer()
|
||||
updateNotificationServer();
|
||||
}
|
||||
function onSettingsSaved() {
|
||||
updateNotificationServer()
|
||||
updateNotificationServer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,76 +156,75 @@ Singleton {
|
||||
"summary": summary || "",
|
||||
"body": body || "",
|
||||
"app": appName || ""
|
||||
}))
|
||||
}));
|
||||
}
|
||||
|
||||
// Main handler
|
||||
function handleNotification(notification) {
|
||||
const quickshellId = notification.id
|
||||
const data = createData(notification)
|
||||
addToHistory(data)
|
||||
const quickshellId = notification.id;
|
||||
const data = createData(notification);
|
||||
addToHistory(data);
|
||||
|
||||
if (root.doNotDisturb || PowerProfileService.noctaliaPerformanceMode)
|
||||
return
|
||||
return;
|
||||
|
||||
// Check if this is a replacement notification
|
||||
const existingInternalId = quickshellIdToInternalId[quickshellId]
|
||||
const existingInternalId = quickshellIdToInternalId[quickshellId];
|
||||
if (existingInternalId && activeNotifications[existingInternalId]) {
|
||||
updateExistingNotification(existingInternalId, notification, data)
|
||||
return
|
||||
updateExistingNotification(existingInternalId, notification, data);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for duplicate content
|
||||
const duplicateId = findDuplicateNotification(data)
|
||||
const duplicateId = findDuplicateNotification(data);
|
||||
if (duplicateId) {
|
||||
removeNotification(duplicateId)
|
||||
removeNotification(duplicateId);
|
||||
}
|
||||
|
||||
// Add new notification
|
||||
addNewNotification(quickshellId, notification, data)
|
||||
addNewNotification(quickshellId, notification, data);
|
||||
}
|
||||
|
||||
function updateExistingNotification(internalId, notification, data) {
|
||||
const index = findNotificationIndex(internalId)
|
||||
const index = findNotificationIndex(internalId);
|
||||
if (index < 0)
|
||||
return
|
||||
|
||||
const existing = activeList.get(index)
|
||||
const oldTimestamp = existing.timestamp
|
||||
const oldProgress = existing.progress
|
||||
return;
|
||||
const existing = activeList.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, "body", data.body)
|
||||
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)
|
||||
activeList.setProperty(index, "summary", data.summary);
|
||||
activeList.setProperty(index, "body", data.body);
|
||||
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);
|
||||
|
||||
// Update stored notification object
|
||||
const notifData = activeNotifications[internalId]
|
||||
notifData.notification = notification
|
||||
notification.tracked = true
|
||||
notification.closed.connect(() => removeNotification(internalId))
|
||||
const notifData = activeNotifications[internalId];
|
||||
notifData.notification = notification;
|
||||
notification.tracked = true;
|
||||
notification.closed.connect(() => removeNotification(internalId));
|
||||
|
||||
// Update metadata
|
||||
notifData.metadata.urgency = data.urgency
|
||||
notifData.metadata.duration = calculateDuration(data)
|
||||
notifData.metadata.urgency = data.urgency;
|
||||
notifData.metadata.duration = calculateDuration(data);
|
||||
}
|
||||
|
||||
function addNewNotification(quickshellId, notification, data) {
|
||||
// Map IDs
|
||||
quickshellIdToInternalId[quickshellId] = data.id
|
||||
quickshellIdToInternalId[quickshellId] = data.id;
|
||||
|
||||
// Create watcher
|
||||
const watcher = notificationWatcherComponent.createObject(root, {
|
||||
"targetNotification": notification,
|
||||
"targetDataId": data.id
|
||||
})
|
||||
});
|
||||
|
||||
// Store notification data
|
||||
activeNotifications[data.id] = {
|
||||
@@ -236,61 +237,61 @@ Singleton {
|
||||
"paused": false,
|
||||
"pauseTime": 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
notification.tracked = true
|
||||
notification.closed.connect(() => removeNotification(data.id))
|
||||
notification.tracked = true;
|
||||
notification.closed.connect(() => removeNotification(data.id));
|
||||
|
||||
// Add to list
|
||||
activeList.insert(0, data)
|
||||
activeList.insert(0, data);
|
||||
|
||||
// Remove overflow
|
||||
while (activeList.count > maxVisible) {
|
||||
const last = activeList.get(activeList.count - 1)
|
||||
activeNotifications[last.id]?.notification?.dismiss()
|
||||
activeList.remove(activeList.count - 1)
|
||||
cleanupNotification(last.id)
|
||||
const last = activeList.get(activeList.count - 1);
|
||||
activeNotifications[last.id]?.notification?.dismiss();
|
||||
activeList.remove(activeList.count - 1);
|
||||
cleanupNotification(last.id);
|
||||
}
|
||||
}
|
||||
|
||||
function findDuplicateNotification(data) {
|
||||
const contentId = getContentId(data.summary, data.body, data.appName)
|
||||
const contentId = getContentId(data.summary, data.body, data.appName);
|
||||
|
||||
for (var i = 0; i < activeList.count; i++) {
|
||||
const existing = activeList.get(i)
|
||||
const existingContentId = getContentId(existing.summary, existing.body, existing.appName)
|
||||
const existing = activeList.get(i);
|
||||
const existingContentId = getContentId(existing.summary, existing.body, existing.appName);
|
||||
if (existingContentId === contentId) {
|
||||
return existing.id
|
||||
return existing.id;
|
||||
}
|
||||
}
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
function calculateDuration(data) {
|
||||
const durations = [Settings.data.notifications?.lowUrgencyDuration * 1000 || 3000, Settings.data.notifications?.normalUrgencyDuration * 1000 || 8000, Settings.data.notifications?.criticalUrgencyDuration * 1000 || 15000]
|
||||
const durations = [Settings.data.notifications?.lowUrgencyDuration * 1000 || 3000, Settings.data.notifications?.normalUrgencyDuration * 1000 || 8000, Settings.data.notifications?.criticalUrgencyDuration * 1000 || 15000];
|
||||
|
||||
if (Settings.data.notifications?.respectExpireTimeout) {
|
||||
if (data.expireTimeout === 0)
|
||||
return -1 // Never expire
|
||||
return -1; // Never expire
|
||||
if (data.expireTimeout > 0)
|
||||
return data.expireTimeout
|
||||
return data.expireTimeout;
|
||||
}
|
||||
|
||||
return durations[data.urgency]
|
||||
return durations[data.urgency];
|
||||
}
|
||||
|
||||
function createData(n) {
|
||||
const time = new Date()
|
||||
const time = new Date();
|
||||
const id = Checksum.sha256(JSON.stringify({
|
||||
"summary": n.summary,
|
||||
"body": n.body,
|
||||
"app": n.appName,
|
||||
"time": time.getTime()
|
||||
}))
|
||||
}));
|
||||
|
||||
const image = n.image || getIcon(n.appIcon)
|
||||
const imageId = generateImageId(n, image)
|
||||
queueImage(image, imageId)
|
||||
const image = n.image || getIcon(n.appIcon);
|
||||
const imageId = generateImageId(n, image);
|
||||
queueImage(image, imageId);
|
||||
|
||||
return {
|
||||
"id": id,
|
||||
@@ -307,65 +308,63 @@ Singleton {
|
||||
"text": a.text || "Action",
|
||||
"identifier": a.identifier || ""
|
||||
})))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function findNotificationIndex(internalId) {
|
||||
for (var i = 0; i < activeList.count; i++) {
|
||||
if (activeList.get(i).id === internalId) {
|
||||
return i
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
function updateNotificationFromObject(internalId) {
|
||||
const notifData = activeNotifications[internalId]
|
||||
const notifData = activeNotifications[internalId];
|
||||
if (!notifData)
|
||||
return
|
||||
|
||||
const index = findNotificationIndex(internalId)
|
||||
return;
|
||||
const index = findNotificationIndex(internalId);
|
||||
if (index < 0)
|
||||
return
|
||||
|
||||
const data = createData(notifData.notification)
|
||||
const existing = activeList.get(index)
|
||||
return;
|
||||
const data = createData(notifData.notification);
|
||||
const existing = activeList.get(index);
|
||||
|
||||
// Update properties (keeping timestamp and progress)
|
||||
activeList.setProperty(index, "summary", data.summary)
|
||||
activeList.setProperty(index, "body", data.body)
|
||||
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, "summary", data.summary);
|
||||
activeList.setProperty(index, "body", data.body);
|
||||
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);
|
||||
|
||||
// Update metadata
|
||||
notifData.metadata.urgency = data.urgency
|
||||
notifData.metadata.duration = calculateDuration(data)
|
||||
notifData.metadata.urgency = data.urgency;
|
||||
notifData.metadata.duration = calculateDuration(data);
|
||||
}
|
||||
|
||||
function removeNotification(id) {
|
||||
const index = findNotificationIndex(id)
|
||||
const index = findNotificationIndex(id);
|
||||
if (index >= 0) {
|
||||
activeList.remove(index)
|
||||
activeList.remove(index);
|
||||
}
|
||||
cleanupNotification(id)
|
||||
cleanupNotification(id);
|
||||
}
|
||||
|
||||
function cleanupNotification(id) {
|
||||
const notifData = activeNotifications[id]
|
||||
const notifData = activeNotifications[id];
|
||||
if (notifData) {
|
||||
notifData.watcher?.destroy()
|
||||
delete activeNotifications[id]
|
||||
notifData.watcher?.destroy();
|
||||
delete activeNotifications[id];
|
||||
}
|
||||
|
||||
// Clean up quickshell ID mapping
|
||||
for (const qsId in quickshellIdToInternalId) {
|
||||
if (quickshellIdToInternalId[qsId] === id) {
|
||||
delete quickshellIdToInternalId[qsId]
|
||||
break
|
||||
delete quickshellIdToInternalId[qsId];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,83 +378,80 @@ Singleton {
|
||||
}
|
||||
|
||||
function updateAllProgress() {
|
||||
const now = Date.now()
|
||||
const toRemove = []
|
||||
const now = Date.now();
|
||||
const toRemove = [];
|
||||
|
||||
for (var i = 0; i < activeList.count; i++) {
|
||||
const notif = activeList.get(i)
|
||||
const notifData = activeNotifications[notif.id]
|
||||
const notif = activeList.get(i);
|
||||
const notifData = activeNotifications[notif.id];
|
||||
if (!notifData)
|
||||
continue
|
||||
|
||||
const meta = notifData.metadata
|
||||
continue;
|
||||
const meta = notifData.metadata;
|
||||
if (meta.duration === -1 || meta.paused)
|
||||
continue
|
||||
|
||||
const elapsed = now - meta.timestamp
|
||||
const progress = Math.max(1.0 - (elapsed / meta.duration), 0.0)
|
||||
continue;
|
||||
const elapsed = now - meta.timestamp;
|
||||
const progress = Math.max(1.0 - (elapsed / meta.duration), 0.0);
|
||||
|
||||
if (progress <= 0) {
|
||||
toRemove.push(notif.id)
|
||||
toRemove.push(notif.id);
|
||||
} else if (Math.abs(notif.progress - progress) > 0.005) {
|
||||
activeList.setProperty(i, "progress", progress)
|
||||
activeList.setProperty(i, "progress", progress);
|
||||
}
|
||||
}
|
||||
|
||||
if (toRemove.length > 0) {
|
||||
animateAndRemove(toRemove[0])
|
||||
animateAndRemove(toRemove[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Image handling
|
||||
function queueImage(path, imageId) {
|
||||
if (!path || !path.startsWith("image://") || !imageId)
|
||||
return
|
||||
|
||||
const dest = Settings.cacheDirImagesNotifications + imageId + ".png"
|
||||
return;
|
||||
const dest = Settings.cacheDirImagesNotifications + imageId + ".png";
|
||||
|
||||
for (const req of imageQueue) {
|
||||
if (req.imageId === imageId)
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
imageQueue.push({
|
||||
"src": path,
|
||||
"dest": dest,
|
||||
"imageId": imageId
|
||||
})
|
||||
});
|
||||
|
||||
if (imageQueue.length === 1)
|
||||
cacher.source = path
|
||||
cacher.source = path;
|
||||
}
|
||||
|
||||
function updateImagePath(id, path) {
|
||||
updateModel(activeList, id, "cachedImage", path)
|
||||
updateModel(historyList, id, "cachedImage", path)
|
||||
saveHistory()
|
||||
updateModel(activeList, id, "cachedImage", path);
|
||||
updateModel(historyList, id, "cachedImage", path);
|
||||
saveHistory();
|
||||
}
|
||||
|
||||
function updateModel(model, id, prop, value) {
|
||||
for (var i = 0; i < model.count; i++) {
|
||||
if (model.get(i).id === id) {
|
||||
model.setProperty(i, prop, value)
|
||||
break
|
||||
model.setProperty(i, prop, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// History management
|
||||
function addToHistory(data) {
|
||||
historyList.insert(0, data)
|
||||
historyList.insert(0, data);
|
||||
|
||||
while (historyList.count > maxHistory) {
|
||||
const old = historyList.get(historyList.count - 1)
|
||||
const old = historyList.get(historyList.count - 1);
|
||||
if (old.cachedImage && !old.cachedImage.startsWith("image://")) {
|
||||
Quickshell.execDetached(["rm", "-f", old.cachedImage])
|
||||
Quickshell.execDetached(["rm", "-f", old.cachedImage]);
|
||||
}
|
||||
historyList.remove(historyList.count - 1)
|
||||
historyList.remove(historyList.count - 1);
|
||||
}
|
||||
saveHistory()
|
||||
saveHistory();
|
||||
}
|
||||
|
||||
// Persistence - History
|
||||
@@ -466,7 +462,7 @@ Singleton {
|
||||
onLoaded: loadHistory()
|
||||
onLoadFailed: error => {
|
||||
if (error === 2)
|
||||
writeAdapter()
|
||||
writeAdapter();
|
||||
}
|
||||
|
||||
JsonAdapter {
|
||||
@@ -483,7 +479,7 @@ Singleton {
|
||||
onLoaded: loadState()
|
||||
onLoadFailed: error => {
|
||||
if (error === 2)
|
||||
writeAdapter()
|
||||
writeAdapter();
|
||||
}
|
||||
|
||||
JsonAdapter {
|
||||
@@ -499,36 +495,36 @@ Singleton {
|
||||
}
|
||||
|
||||
function saveHistory() {
|
||||
saveTimer.restart()
|
||||
saveTimer.restart();
|
||||
}
|
||||
|
||||
function performSaveHistory() {
|
||||
try {
|
||||
const items = []
|
||||
const items = [];
|
||||
for (var i = 0; i < historyList.count; i++) {
|
||||
const n = historyList.get(i)
|
||||
const copy = Object.assign({}, n)
|
||||
copy.timestamp = n.timestamp.getTime()
|
||||
items.push(copy)
|
||||
const n = historyList.get(i);
|
||||
const copy = Object.assign({}, n);
|
||||
copy.timestamp = n.timestamp.getTime();
|
||||
items.push(copy);
|
||||
}
|
||||
adapter.notifications = items
|
||||
historyFileView.writeAdapter()
|
||||
adapter.notifications = items;
|
||||
historyFileView.writeAdapter();
|
||||
} catch (e) {
|
||||
Logger.e("Notifications", "Save history failed:", e)
|
||||
Logger.e("Notifications", "Save history failed:", e);
|
||||
}
|
||||
}
|
||||
|
||||
function loadHistory() {
|
||||
try {
|
||||
historyList.clear()
|
||||
historyList.clear();
|
||||
for (const item of adapter.notifications || []) {
|
||||
const time = new Date(item.timestamp)
|
||||
const time = new Date(item.timestamp);
|
||||
|
||||
let cachedImage = item.cachedImage || ""
|
||||
let cachedImage = item.cachedImage || "";
|
||||
if (item.originalImage && item.originalImage.startsWith("image://") && !cachedImage) {
|
||||
const imageId = generateImageId(item, item.originalImage)
|
||||
const imageId = generateImageId(item, item.originalImage);
|
||||
if (imageId) {
|
||||
cachedImage = Settings.cacheDirImagesNotifications + imageId + ".png"
|
||||
cachedImage = Settings.cacheDirImagesNotifications + imageId + ".png";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,196 +537,196 @@ Singleton {
|
||||
"timestamp": time,
|
||||
"originalImage": item.originalImage || "",
|
||||
"cachedImage": cachedImage
|
||||
})
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.e("Notifications", "Load failed:", e)
|
||||
Logger.e("Notifications", "Load failed:", e);
|
||||
}
|
||||
}
|
||||
|
||||
function loadState() {
|
||||
try {
|
||||
root.lastSeenTs = stateAdapter.lastSeenTs || 0
|
||||
root.lastSeenTs = stateAdapter.lastSeenTs || 0;
|
||||
|
||||
if (root.lastSeenTs === 0 && Settings.data.notifications && Settings.data.notifications.lastSeenTs) {
|
||||
root.lastSeenTs = Settings.data.notifications.lastSeenTs
|
||||
saveState()
|
||||
Logger.i("Notifications", "Migrated lastSeenTs from settings to state file")
|
||||
root.lastSeenTs = Settings.data.notifications.lastSeenTs;
|
||||
saveState();
|
||||
Logger.i("Notifications", "Migrated lastSeenTs from settings to state file");
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.e("Notifications", "Load state failed:", e)
|
||||
Logger.e("Notifications", "Load state failed:", e);
|
||||
}
|
||||
}
|
||||
|
||||
function saveState() {
|
||||
try {
|
||||
stateAdapter.lastSeenTs = root.lastSeenTs
|
||||
stateFileView.writeAdapter()
|
||||
stateAdapter.lastSeenTs = root.lastSeenTs;
|
||||
stateFileView.writeAdapter();
|
||||
} catch (e) {
|
||||
Logger.e("Notifications", "Save state failed:", e)
|
||||
Logger.e("Notifications", "Save state failed:", e);
|
||||
}
|
||||
}
|
||||
|
||||
function updateLastSeenTs() {
|
||||
root.lastSeenTs = Time.timestamp * 1000
|
||||
saveState()
|
||||
root.lastSeenTs = Time.timestamp * 1000;
|
||||
saveState();
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
function getAppName(name) {
|
||||
if (!name || name.trim() === "")
|
||||
return "Unknown"
|
||||
name = name.trim()
|
||||
return "Unknown";
|
||||
name = name.trim();
|
||||
|
||||
if (name.includes(".") && (name.startsWith("com.") || name.startsWith("org.") || name.startsWith("io.") || name.startsWith("net."))) {
|
||||
const parts = name.split(".")
|
||||
let appPart = parts[parts.length - 1]
|
||||
const parts = name.split(".");
|
||||
let appPart = parts[parts.length - 1];
|
||||
|
||||
if (!appPart || appPart === "app" || appPart === "desktop") {
|
||||
appPart = parts[parts.length - 2] || parts[0]
|
||||
appPart = parts[parts.length - 2] || parts[0];
|
||||
}
|
||||
|
||||
if (appPart)
|
||||
name = appPart
|
||||
name = appPart;
|
||||
}
|
||||
|
||||
if (name.includes(".")) {
|
||||
const parts = name.split(".")
|
||||
let displayName = parts[parts.length - 1]
|
||||
const parts = name.split(".");
|
||||
let displayName = parts[parts.length - 1];
|
||||
|
||||
if (!displayName || /^\d+$/.test(displayName)) {
|
||||
displayName = parts[parts.length - 2] || parts[0]
|
||||
displayName = parts[parts.length - 2] || parts[0];
|
||||
}
|
||||
|
||||
if (displayName) {
|
||||
displayName = displayName.charAt(0).toUpperCase() + displayName.slice(1)
|
||||
displayName = displayName.replace(/([a-z])([A-Z])/g, '$1 $2')
|
||||
displayName = displayName.replace(/app$/i, '').trim()
|
||||
displayName = displayName.replace(/desktop$/i, '').trim()
|
||||
displayName = displayName.replace(/flatpak$/i, '').trim()
|
||||
displayName = displayName.charAt(0).toUpperCase() + displayName.slice(1);
|
||||
displayName = displayName.replace(/([a-z])([A-Z])/g, '$1 $2');
|
||||
displayName = displayName.replace(/app$/i, '').trim();
|
||||
displayName = displayName.replace(/desktop$/i, '').trim();
|
||||
displayName = displayName.replace(/flatpak$/i, '').trim();
|
||||
|
||||
if (!displayName) {
|
||||
displayName = parts[parts.length - 1].charAt(0).toUpperCase() + parts[parts.length - 1].slice(1)
|
||||
displayName = parts[parts.length - 1].charAt(0).toUpperCase() + parts[parts.length - 1].slice(1);
|
||||
}
|
||||
}
|
||||
|
||||
return displayName || name
|
||||
return displayName || name;
|
||||
}
|
||||
|
||||
let displayName = name.charAt(0).toUpperCase() + name.slice(1)
|
||||
displayName = displayName.replace(/([a-z])([A-Z])/g, '$1 $2')
|
||||
displayName = displayName.replace(/app$/i, '').trim()
|
||||
displayName = displayName.replace(/desktop$/i, '').trim()
|
||||
let displayName = name.charAt(0).toUpperCase() + name.slice(1);
|
||||
displayName = displayName.replace(/([a-z])([A-Z])/g, '$1 $2');
|
||||
displayName = displayName.replace(/app$/i, '').trim();
|
||||
displayName = displayName.replace(/desktop$/i, '').trim();
|
||||
|
||||
return displayName || name
|
||||
return displayName || name;
|
||||
}
|
||||
|
||||
function getIcon(icon) {
|
||||
if (!icon)
|
||||
return ""
|
||||
return "";
|
||||
if (icon.startsWith("/") || icon.startsWith("file://"))
|
||||
return icon
|
||||
return ThemeIcons.iconFromName(icon)
|
||||
return icon;
|
||||
return ThemeIcons.iconFromName(icon);
|
||||
}
|
||||
|
||||
function stripTags(text) {
|
||||
return text.replace(/<[^>]*>?/gm, '')
|
||||
return text.replace(/<[^>]*>?/gm, '');
|
||||
}
|
||||
|
||||
function generateImageId(notification, image) {
|
||||
if (image && image.startsWith("image://")) {
|
||||
if (image.startsWith("image://qsimage/")) {
|
||||
const key = (notification.appName || "") + "|" + (notification.summary || "")
|
||||
return Checksum.sha256(key)
|
||||
const key = (notification.appName || "") + "|" + (notification.summary || "");
|
||||
return Checksum.sha256(key);
|
||||
}
|
||||
return Checksum.sha256(image)
|
||||
return Checksum.sha256(image);
|
||||
}
|
||||
return ""
|
||||
return "";
|
||||
}
|
||||
|
||||
function pauseTimeout(id) {
|
||||
const notifData = activeNotifications[id]
|
||||
const notifData = activeNotifications[id];
|
||||
if (notifData && !notifData.metadata.paused) {
|
||||
notifData.metadata.paused = true
|
||||
notifData.metadata.pauseTime = Date.now()
|
||||
notifData.metadata.paused = true;
|
||||
notifData.metadata.pauseTime = Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
function resumeTimeout(id) {
|
||||
const notifData = activeNotifications[id]
|
||||
const notifData = activeNotifications[id];
|
||||
if (notifData && notifData.metadata.paused) {
|
||||
notifData.metadata.timestamp += Date.now() - notifData.metadata.pauseTime
|
||||
notifData.metadata.paused = false
|
||||
notifData.metadata.timestamp += Date.now() - notifData.metadata.pauseTime;
|
||||
notifData.metadata.paused = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Public API
|
||||
function dismissActiveNotification(id) {
|
||||
activeNotifications[id]?.notification?.dismiss()
|
||||
removeNotification(id)
|
||||
activeNotifications[id]?.notification?.dismiss();
|
||||
removeNotification(id);
|
||||
}
|
||||
|
||||
function dismissOldestActive() {
|
||||
if (activeList.count > 0) {
|
||||
const lastNotif = activeList.get(activeList.count - 1)
|
||||
dismissActiveNotification(lastNotif.id)
|
||||
const lastNotif = activeList.get(activeList.count - 1);
|
||||
dismissActiveNotification(lastNotif.id);
|
||||
}
|
||||
}
|
||||
|
||||
function dismissAllActive() {
|
||||
for (const id in activeNotifications) {
|
||||
activeNotifications[id].notification?.dismiss()
|
||||
activeNotifications[id].watcher?.destroy()
|
||||
activeNotifications[id].notification?.dismiss();
|
||||
activeNotifications[id].watcher?.destroy();
|
||||
}
|
||||
activeList.clear()
|
||||
activeNotifications = {}
|
||||
quickshellIdToInternalId = {}
|
||||
activeList.clear();
|
||||
activeNotifications = {};
|
||||
quickshellIdToInternalId = {};
|
||||
}
|
||||
|
||||
function invokeAction(id, actionId) {
|
||||
const notifData = activeNotifications[id]
|
||||
const notifData = activeNotifications[id];
|
||||
if (!notifData?.notification?.actions)
|
||||
return false
|
||||
return false;
|
||||
|
||||
for (const action of notifData.notification.actions) {
|
||||
if (action.identifier === actionId && action.invoke) {
|
||||
action.invoke()
|
||||
return true
|
||||
action.invoke();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
function removeFromHistory(notificationId) {
|
||||
for (var i = 0; i < historyList.count; i++) {
|
||||
const notif = historyList.get(i)
|
||||
const notif = historyList.get(i);
|
||||
if (notif.id === notificationId) {
|
||||
if (notif.cachedImage && !notif.cachedImage.startsWith("image://")) {
|
||||
Quickshell.execDetached(["rm", "-f", notif.cachedImage])
|
||||
Quickshell.execDetached(["rm", "-f", notif.cachedImage]);
|
||||
}
|
||||
historyList.remove(i)
|
||||
saveHistory()
|
||||
return true
|
||||
historyList.remove(i);
|
||||
saveHistory();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
function clearHistory() {
|
||||
try {
|
||||
Quickshell.execDetached(["sh", "-c", `rm -rf "${Settings.cacheDirImagesNotifications}"*`])
|
||||
Quickshell.execDetached(["sh", "-c", `rm -rf "${Settings.cacheDirImagesNotifications}"*`]);
|
||||
} catch (e) {
|
||||
Logger.e("Notifications", "Failed to clear cache directory:", e)
|
||||
Logger.e("Notifications", "Failed to clear cache directory:", e);
|
||||
}
|
||||
|
||||
historyList.clear()
|
||||
saveHistory()
|
||||
historyList.clear();
|
||||
saveHistory();
|
||||
}
|
||||
|
||||
// Signals
|
||||
signal animateAndRemove(string notificationId)
|
||||
|
||||
onDoNotDisturbChanged: {
|
||||
ToastService.showNotice(doNotDisturb ? I18n.tr("toast.do-not-disturb.enabled") : I18n.tr("toast.do-not-disturb.disabled"), doNotDisturb ? I18n.tr("toast.do-not-disturb.enabled-desc") : I18n.tr("toast.do-not-disturb.disabled-desc"), doNotDisturb ? "bell-off" : "bell")
|
||||
ToastService.showNotice(doNotDisturb ? I18n.tr("toast.do-not-disturb.enabled") : I18n.tr("toast.do-not-disturb.disabled"), doNotDisturb ? I18n.tr("toast.do-not-disturb.enabled-desc") : I18n.tr("toast.do-not-disturb.disabled-desc"), doNotDisturb ? "bell-off" : "bell");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user