diff options
| -rw-r--r-- | desktop/Prefs.qml | 13 | ||||
| -rw-r--r-- | desktop/companion/Admired.qml | 101 |
2 files changed, 113 insertions, 1 deletions
diff --git a/desktop/Prefs.qml b/desktop/Prefs.qml index 6340b91..03ac980 100644 --- a/desktop/Prefs.qml +++ b/desktop/Prefs.qml @@ -56,6 +56,16 @@ Singleton { root.write(Object.assign({}, root.doc, { companion: on })); } + // The companion's wallpaper list, "" for the default in + // companion/Admired.qml. + property string companionBlushFile: "" + function setCompanionBlushFile(p) { + p = p.trim(); + if (p === root.companionBlushFile) return; + root.companionBlushFile = p; + root.write(Object.assign({}, root.doc, { companionBlushFile: p })); + } + // The settings window's sidebar width, dragged by its edge. readonly property int sidebarMin: 160 readonly property int sidebarMax: 420 @@ -115,6 +125,7 @@ Singleton { root.settingsSidebar = typeof w === "number" && w >= root.sidebarMin && w <= root.sidebarMax ? Math.round(w) : 200; root.companion = parsed.companion !== false; + root.companionBlushFile = typeof parsed.companionBlushFile === "string" ? parsed.companionBlushFile : ""; root.ready = true; } @@ -130,6 +141,6 @@ Singleton { onFileChanged: reload() onLoaded: root.reparse() // Missing file: the defaults, and nothing written. - onLoadFailed: { root.doc = {}; root.pinnedIp = ""; root.presets = null; root.settingsSidebar = 200; root.assistantModel = ""; root.companion = true; root.ready = true; } + onLoadFailed: { root.doc = {}; root.pinnedIp = ""; root.presets = null; root.settingsSidebar = 200; root.assistantModel = ""; root.companion = true; root.companionBlushFile = ""; root.ready = true; } } } diff --git a/desktop/companion/Admired.qml b/desktop/companion/Admired.qml new file mode 100644 index 0000000..eee76d1 --- /dev/null +++ b/desktop/companion/Admired.qml @@ -0,0 +1,101 @@ +// Copyright (C) 2026 Danilo M. <danix@danix.xyz> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +pragma Singleton + +import Quickshell +import Quickshell.Io +import QtQuick +import ".." +import "ListFile.js" as LF + +// The wallpapers the companion blushes at, and what wallp has on each +// monitor. The companion reads both; the wallpaper picker toggles entries. +// What is on each monitor is read from wallp's own files here rather than +// through the appearance module's Wallpapers, which scans every wallpaper +// on creation, and the companion runs all session. +Singleton { + id: root + + readonly property string home: Quickshell.env("HOME") + readonly property string defaultPath: + (Quickshell.env("XDG_CONFIG_HOME") || root.home + "/.config") + "/keystone/companion-blush.txt" + readonly property string path: + Prefs.companionBlushFile !== "" ? Prefs.companionBlushFile.replace(/^~(?=\/|$)/, root.home) : root.defaultPath + + property string listText: "" + readonly property var paths: LF.parse(root.listText) + function listed(p) { return p !== "" && root.paths.indexOf(p) >= 0; } + + // The wallpaper on a monitor, by connector name; "" for one wallp does + // not set. + property var outputs: ({}) + property string wallH: "" + property string wallV: "" + function on(monitor) { + const w = root.outputs[monitor]; + return w === "H" ? root.wallH : w === "V" ? root.wallV : ""; + } + + // ponytail: a list file created by hand after start may not be watched + // until a restart (the watch is on a path that did not exist); the + // heart writes through the process below, which sets listText itself. + FileView { + path: root.path + watchChanges: true + printErrors: false + onFileChanged: reload() + onLoaded: root.listText = text() + onLoadFailed: root.listText = "" + } + FileView { + path: root.home + "/.config/wallp/wallp.conf" + watchChanges: true + printErrors: false + onFileChanged: reload() + onLoaded: root.outputs = LF.outputs(text()) + } + FileView { + path: root.home + "/.config/wallp/wall_h" + watchChanges: true + printErrors: false + onFileChanged: reload() + onLoaded: root.wallH = text().trim() + } + FileView { + path: root.home + "/.config/wallp/wall_v" + watchChanges: true + printErrors: false + onFileChanged: reload() + onLoaded: root.wallV = text().trim() + } + + // Through cat rather than FileView.setText, because the list can become + // empty and setText("") on a path the view has not loaded writes no + // file (AGENTS.md). + function toggle(p) { + writer.data = LF.toggle(root.listText, p); + root.listText = writer.data; + writer.command = ["sh", "-c", 'mkdir -p "$(dirname "$1")" && cat > "$1"', "sh", root.path]; + writer.stdinEnabled = true; + writer.running = false; + writer.running = true; + } + Process { + id: writer + property string data: "" + onStarted: { + writer.write(writer.data); + writer.stdinEnabled = false; + } + onExited: code => { if (code !== 0) console.warn("Admired: writing", root.path, "failed"); } + } +} |
