mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 13:32:50 -05:00
notifications: add image persistence
This commit is contained in:
@@ -103,7 +103,7 @@ Variants {
|
||||
}
|
||||
pluginService: (liveInstanceData.widgetType !== "desktopClock" && liveInstanceData.widgetType !== "systemMonitor") ? PluginService : null
|
||||
screen: screenDelegate.screen
|
||||
visible: shouldBeVisible
|
||||
widgetEnabled: shouldBeVisible
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,6 +362,7 @@ PanelWindow {
|
||||
id: iconContainer
|
||||
|
||||
readonly property bool hasNotificationImage: notificationData && notificationData.image && notificationData.image !== ""
|
||||
readonly property bool needsImagePersist: hasNotificationImage && notificationData.image.startsWith("image://qsimage/") && !notificationData.persistedImagePath
|
||||
|
||||
width: 63
|
||||
height: 63
|
||||
@@ -391,6 +392,22 @@ PanelWindow {
|
||||
const appName = notificationData?.appName || "?";
|
||||
return appName.charAt(0).toUpperCase();
|
||||
}
|
||||
|
||||
onImageStatusChanged: {
|
||||
if (imageStatus === Image.Ready && needsImagePersist) {
|
||||
const cachePath = NotificationService.getImageCachePath(notificationData);
|
||||
saveImageToFile(cachePath);
|
||||
}
|
||||
}
|
||||
|
||||
onImageSaved: filePath => {
|
||||
if (!notificationData)
|
||||
return;
|
||||
notificationData.persistedImagePath = filePath;
|
||||
const wrapperId = notificationData.notification?.id?.toString() || "";
|
||||
if (wrapperId)
|
||||
NotificationService.updateHistoryImage(wrapperId, filePath);
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
||||
@@ -17,6 +17,7 @@ Item {
|
||||
property var pluginService: null
|
||||
property string instanceId: ""
|
||||
property var instanceData: null
|
||||
property bool widgetEnabled: true
|
||||
|
||||
readonly property bool isBuiltin: pluginId === "desktopClock" || pluginId === "systemMonitor"
|
||||
readonly property var activeComponent: isBuiltin ? builtinComponent : PluginService.pluginDesktopComponents[pluginId] ?? null
|
||||
@@ -202,7 +203,7 @@ Item {
|
||||
PanelWindow {
|
||||
id: widgetWindow
|
||||
screen: root.screen
|
||||
visible: root.visible && root.activeComponent !== null
|
||||
visible: root.widgetEnabled && root.activeComponent !== null
|
||||
color: "transparent"
|
||||
|
||||
WlrLayershell.namespace: "quickshell:desktop-widget:" + root.pluginId + (root.instanceId ? ":" + root.instanceId : "")
|
||||
|
||||
@@ -17,6 +17,7 @@ Singleton {
|
||||
|
||||
property var historyList: []
|
||||
readonly property string historyFile: Paths.strip(Paths.cache) + "/notification_history.json"
|
||||
readonly property string imageCacheDir: Paths.strip(Paths.cache) + "/notification_images"
|
||||
property bool historyLoaded: false
|
||||
|
||||
property list<NotifWrapper> notificationQueue: []
|
||||
@@ -46,6 +47,7 @@ Singleton {
|
||||
Component.onCompleted: {
|
||||
_recomputeGroups();
|
||||
Quickshell.execDetached(["mkdir", "-p", Paths.strip(Paths.cache)]);
|
||||
Quickshell.execDetached(["mkdir", "-p", imageCacheDir]);
|
||||
}
|
||||
|
||||
FileView {
|
||||
@@ -72,10 +74,46 @@ Singleton {
|
||||
onTriggered: root.performSaveHistory()
|
||||
}
|
||||
|
||||
function getImageCachePath(wrapper) {
|
||||
const ts = wrapper.time ? wrapper.time.getTime() : Date.now();
|
||||
const id = wrapper.notification?.id?.toString() || "0";
|
||||
return imageCacheDir + "/notif_" + ts + "_" + id + ".png";
|
||||
}
|
||||
|
||||
function updateHistoryImage(wrapperId, imagePath) {
|
||||
const idx = historyList.findIndex(n => n.id === wrapperId);
|
||||
if (idx < 0)
|
||||
return;
|
||||
const item = historyList[idx];
|
||||
const updated = {
|
||||
id: item.id,
|
||||
summary: item.summary,
|
||||
body: item.body,
|
||||
htmlBody: item.htmlBody,
|
||||
appName: item.appName,
|
||||
appIcon: item.appIcon,
|
||||
image: "file://" + imagePath,
|
||||
urgency: item.urgency,
|
||||
timestamp: item.timestamp,
|
||||
desktopEntry: item.desktopEntry
|
||||
};
|
||||
const newList = historyList.slice();
|
||||
newList[idx] = updated;
|
||||
historyList = newList;
|
||||
saveHistory();
|
||||
}
|
||||
|
||||
function addToHistory(wrapper) {
|
||||
if (!wrapper)
|
||||
return;
|
||||
const urg = typeof wrapper.urgency === "number" ? wrapper.urgency : 1;
|
||||
const imageUrl = wrapper.image || "";
|
||||
let persistableImage = "";
|
||||
if (wrapper.persistedImagePath) {
|
||||
persistableImage = "file://" + wrapper.persistedImagePath;
|
||||
} else if (imageUrl && !imageUrl.startsWith("image://qsimage/")) {
|
||||
persistableImage = imageUrl;
|
||||
}
|
||||
const data = {
|
||||
id: wrapper.notification?.id?.toString() || Date.now().toString(),
|
||||
summary: wrapper.summary || "",
|
||||
@@ -83,7 +121,7 @@ Singleton {
|
||||
htmlBody: wrapper.htmlBody || wrapper.body || "",
|
||||
appName: wrapper.appName || "",
|
||||
appIcon: wrapper.appIcon || "",
|
||||
image: wrapper.cleanImage || "",
|
||||
image: persistableImage,
|
||||
urgency: urg,
|
||||
timestamp: wrapper.time.getTime(),
|
||||
desktopEntry: wrapper.desktopEntry || ""
|
||||
@@ -148,9 +186,19 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function _deleteCachedImage(imagePath) {
|
||||
if (!imagePath || !imagePath.startsWith("file://"))
|
||||
return;
|
||||
const filePath = imagePath.replace("file://", "");
|
||||
if (filePath.startsWith(imageCacheDir)) {
|
||||
Quickshell.execDetached(["rm", "-f", filePath]);
|
||||
}
|
||||
}
|
||||
|
||||
function removeFromHistory(notificationId) {
|
||||
const idx = historyList.findIndex(n => n.id === notificationId);
|
||||
if (idx >= 0) {
|
||||
_deleteCachedImage(historyList[idx].image);
|
||||
historyList = historyList.filter((_, i) => i !== idx);
|
||||
saveHistory();
|
||||
return true;
|
||||
@@ -159,6 +207,9 @@ Singleton {
|
||||
}
|
||||
|
||||
function clearHistory() {
|
||||
for (const item of historyList) {
|
||||
_deleteCachedImage(item.image);
|
||||
}
|
||||
historyList = [];
|
||||
saveHistory();
|
||||
}
|
||||
@@ -268,15 +319,22 @@ Singleton {
|
||||
|
||||
const now = Date.now();
|
||||
const maxAgeMs = maxAgeDays * 24 * 60 * 60 * 1000;
|
||||
const toRemove = historyList.filter(item => (now - item.timestamp) > maxAgeMs);
|
||||
const pruned = historyList.filter(item => (now - item.timestamp) <= maxAgeMs);
|
||||
|
||||
if (pruned.length !== historyList.length) {
|
||||
for (const item of toRemove) {
|
||||
_deleteCachedImage(item.image);
|
||||
}
|
||||
historyList = pruned;
|
||||
saveHistory();
|
||||
}
|
||||
}
|
||||
|
||||
function deleteHistory() {
|
||||
for (const item of historyList) {
|
||||
_deleteCachedImage(item.image);
|
||||
}
|
||||
historyList = [];
|
||||
historyAdapter.notifications = [];
|
||||
historyFileView.writeAdapter();
|
||||
@@ -461,6 +519,7 @@ Singleton {
|
||||
property bool removedByLimit: false
|
||||
property bool isPersistent: true
|
||||
property int seq: 0
|
||||
property string persistedImagePath: ""
|
||||
|
||||
onPopupChanged: {
|
||||
if (!popup) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
@@ -13,6 +12,19 @@ Rectangle {
|
||||
property bool hasImage: imageSource !== ""
|
||||
property alias imageStatus: internalImage.status
|
||||
|
||||
signal imageSaved(string filePath)
|
||||
|
||||
function saveImageToFile(filePath) {
|
||||
if (internalImage.status !== Image.Ready)
|
||||
return false;
|
||||
internalImage.grabToImage(function (result) {
|
||||
if (result && result.saveToFile(filePath)) {
|
||||
root.imageSaved(filePath);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
radius: width / 2
|
||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
||||
border.color: "transparent"
|
||||
@@ -67,7 +79,6 @@ Rectangle {
|
||||
visible: (internalImage.status !== Image.Ready || root.imageSource === "") && root.fallbackIcon !== ""
|
||||
}
|
||||
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
visible: root.imageSource === "" && root.fallbackIcon === "" && root.fallbackText !== ""
|
||||
|
||||
Reference in New Issue
Block a user