summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/dms/Widgets/CachingImage.qml
diff options
context:
space:
mode:
authorNippy <nippy@rp1.hu>2026-05-08 19:50:49 +0200
committerNippy <nippy@rp1.hu>2026-05-08 19:50:49 +0200
commit3462bcc46ecf74f576ea4397f16492c16bd75b10 (patch)
treec5ab7aef4498647e057bda8d49c11e5f9dda74c9 /raveos-hyprland-theme/theme-data/dms/Widgets/CachingImage.qml
parent56616f693b4f263cbf0d47da43b67424efa6022d (diff)
downloadRaveOS-PKGBUILD-3462bcc46ecf74f576ea4397f16492c16bd75b10.tar.gz
RaveOS-PKGBUILD-3462bcc46ecf74f576ea4397f16492c16bd75b10.zip
raveos update
Diffstat (limited to 'raveos-hyprland-theme/theme-data/dms/Widgets/CachingImage.qml')
-rw-r--r--raveos-hyprland-theme/theme-data/dms/Widgets/CachingImage.qml102
1 files changed, 102 insertions, 0 deletions
diff --git a/raveos-hyprland-theme/theme-data/dms/Widgets/CachingImage.qml b/raveos-hyprland-theme/theme-data/dms/Widgets/CachingImage.qml
new file mode 100644
index 0000000..5ffec09
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/dms/Widgets/CachingImage.qml
@@ -0,0 +1,102 @@
+import QtQuick
+import qs.Common
+
+Item {
+ id: root
+
+ property string imagePath: ""
+ property int maxCacheSize: 512
+ property int status: isAnimated ? animatedImg.status : staticImg.status
+ property int fillMode: Image.PreserveAspectCrop
+
+ readonly property bool isRemoteUrl: imagePath.startsWith("http://") || imagePath.startsWith("https://")
+ readonly property bool isAnimated: {
+ if (!imagePath)
+ return false;
+ const lower = imagePath.toLowerCase();
+ return lower.endsWith(".gif") || lower.endsWith(".webp");
+ }
+ readonly property string normalizedPath: {
+ if (!imagePath)
+ return "";
+ if (isRemoteUrl)
+ return imagePath;
+ if (imagePath.startsWith("file://"))
+ return imagePath.substring(7);
+ return imagePath;
+ }
+
+ function djb2Hash(str) {
+ if (!str)
+ return "";
+ let hash = 5381;
+ for (let i = 0; i < str.length; i++) {
+ hash = ((hash << 5) + hash) + str.charCodeAt(i);
+ hash = hash & 0x7FFFFFFF;
+ }
+ return hash.toString(16).padStart(8, '0');
+ }
+
+ readonly property string imageHash: normalizedPath ? djb2Hash(normalizedPath) : ""
+ readonly property string cachePath: imageHash && !isRemoteUrl && !isAnimated ? `${Paths.stringify(Paths.imagecache)}/${imageHash}@${maxCacheSize}x${maxCacheSize}.png` : ""
+ readonly property string encodedImagePath: {
+ if (!normalizedPath)
+ return "";
+ if (isRemoteUrl)
+ return normalizedPath;
+ return "file://" + normalizedPath.split('/').map(s => encodeURIComponent(s)).join('/');
+ }
+
+ AnimatedImage {
+ id: animatedImg
+ anchors.fill: parent
+ visible: root.isAnimated
+ asynchronous: true
+ fillMode: root.fillMode
+ source: root.isAnimated ? root.imagePath : ""
+ playing: visible && status === AnimatedImage.Ready
+ }
+
+ Image {
+ id: staticImg
+ anchors.fill: parent
+ visible: !root.isAnimated
+ asynchronous: true
+ fillMode: root.fillMode
+ sourceSize.width: root.maxCacheSize
+ sourceSize.height: root.maxCacheSize
+ smooth: true
+
+ onStatusChanged: {
+ if (source == root.cachePath && status === Image.Error) {
+ source = root.encodedImagePath;
+ return;
+ }
+ if (root.isRemoteUrl || source != root.encodedImagePath || status !== Image.Ready || !root.cachePath)
+ return;
+ Paths.mkdir(Paths.imagecache);
+ const grabPath = root.cachePath;
+ if (visible && width > 0 && height > 0 && Window.window?.visible) {
+ grabToImage(res => res.saveToFile(grabPath));
+ }
+ }
+ }
+
+ onImagePathChanged: {
+ if (!imagePath) {
+ staticImg.source = "";
+ return;
+ }
+ if (isAnimated)
+ return;
+ if (isRemoteUrl) {
+ staticImg.source = imagePath;
+ return;
+ }
+ Paths.mkdir(Paths.imagecache);
+ const hash = djb2Hash(normalizedPath);
+ const cPath = hash ? `${Paths.stringify(Paths.imagecache)}/${hash}@${maxCacheSize}x${maxCacheSize}.png` : "";
+ const encoded = "file://" + normalizedPath.split('/').map(s => encodeURIComponent(s)).join('/');
+ staticImg.source = cPath || encoded;
+ }
+}