pragma Singleton pragma ComponentBehavior: Bound import Quickshell import Quickshell.Io import QtQuick import ZShell.Models import ZShell.Internal import ZShell.Config import qs.Components import qs.Services import qs.Helpers import qs.Paths Searcher { id: root property string actualCurrent: WallpaperPath.currentWallpaperPath property alias crops: adapter.monitorCrops readonly property string current: showPreview ? previewPath : actualCurrent readonly property string currentThumbnail: thumbnailFor(current) readonly property bool currentIsVideo: isVideoPath(current) property alias monitorCrops: monitorCrops property bool pendingPreviewClear property bool previewColorLock property string previewPath property bool recentlyChanged property bool showPreview: false function getCategoryFor(w: WallpaperEntry): string { let category = w.parentDir.slice(Paths.wallsdir.length + 1); if (category.includes("/")) category = category.slice(0, category.indexOf("/")); return category; } readonly property var videoExts: ["mp4", "mkv", "webm", "avi", "mov", "wmv", "flv", "m4v", "mpg", "mpeg", "3gp", "ogv", "ts", "vob"] function isVideoPath(path: string): bool { if (!path) return false; const dot = path.lastIndexOf("."); if (dot < 0) return false; return videoExts.includes(path.slice(dot + 1).toLowerCase()); } function thumbnailFor(path: string): string { if (!path) return ""; for (const entry of root.list) { if (entry.path === path) return entry.thumbnailPath || path; } return path; } function getCrop(screen: string): var { return root.crops[screen]; } function preview(path: string): void { previewPath = path; showPreview = true; if (Config.colors.schemeGen) previewColorsProc.running = true; } function setCrop(screen: string, rect: rect, zoom: real): void { if (zoom <= 0) zoom = 1.0; else if (zoom > 5.0) zoom = 5.0; root.crops[screen] = { x: rect.x, y: rect.y, width: rect.width, height: rect.height, zoom: zoom }; } function setWallpaper(path: string): void { actualCurrent = path; WallpaperPath.currentWallpaperPath = path; Quickshell.screens.forEach(n => setCrop(n.name, Qt.rect(0, 0, 1, 1), 1.0)); Quickshell.execDetached(["zshell-cli", "wallpaper", "lockscreen", "--input-image", `${root.actualCurrent}`, "--output-path", `${Paths.state}/lockscreen_bg.png`, "--blur-amount", `${Config.lock.blurAmount}`]); if (Config.colors.schemeGen) Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${root.actualCurrent}`, "--scheme", `${Config.colors.schemeType}`, "--mode", `${Config.colors.mode}`]); } function stopPreview(): void { showPreview = false; if (previewColorLock) pendingPreviewClear = true; else Colors.showPreview = false; } extraOpts: useFuzzy ? ({}) : ({ forward: false }) key: "relativePath" list: wallpapers.entries useFuzzy: true onPreviewColorLockChanged: { if (!previewColorLock && pendingPreviewClear) Colors.showPreview = false; } IpcHandler { function set(path: string): void { root.setWallpaper(path); } target: "wallpaper" } FileView { id: monitorCrops path: `${Paths.state}/wallpaper-crops.json` watchChanges: true onAdapterUpdated: cropWriteDelay.restart() onFileChanged: reload() JsonAdapter { id: adapter property var monitorCrops: ({}) } } Timer { id: cropWriteDelay interval: 100 repeat: false running: false onTriggered: monitorCrops.writeAdapter() } WallpaperDb { id: wallpapers dbPath: `${Paths.state}/wallpapers.sqlite` cacheSize: wallpaper.largestBufferSize requireHardwareCodec: true path: Config.general.wallpaperPath } Process { id: previewColorsProc command: ["zshell-cli", "scheme", "generate", "-p", "-i", root.previewPath] stdout: StdioCollector { onStreamFinished: { Colors.load(text, true); Colors.showPreview = true; } } } WallpaperService { id: wallpaper dbPath: wallpapers.dbPath path: root.current } Connections { target: wallpapers function onCacheStored(path: string): void { if (path === root.current) wallpaper.invalidateCache(); } } Variants { model: Quickshell.screens WallpaperObject { readonly property var crops: root.getCrop(modelData.name) required property var modelData cropHeight: crops?.height ?? 1.0 cropWidth: crops?.width ?? 1.0 cropX: crops?.x ?? 0.0 cropY: crops?.y ?? 0.0 screen: modelData.name service: wallpaper zoom: crops?.zoom ?? 1.0 Behavior on cropHeight { Anim {} } Behavior on cropWidth { Anim {} } Behavior on cropX { Anim {} } Behavior on cropY { Anim {} } } } }