pragma Singleton // Carrying settings to another machine. // // Distinct from SettingsBackup, which snapshots this machine so it can be put // back exactly as it was. This produces something meant to travel: the // preferences that describe taste rather than hardware. // // The helper exports by allow-list from the preference schema, so a key added // later that happens to hold a token cannot leak into a file somebody emails to // themselves, and validates everything again on arrival. import Quickshell import Quickshell.Io import QtQuick Singleton { id: root readonly property string helperPath: Quickshell.shellDir + "/scripts/panama-settings-sync" // Where an export lands by default. Somewhere a person will find it again. readonly property string defaultPath: (Quickshell.env("HOME") ?? "") + "/panama-settings.json" property string lastError: "" property string lastAction: "" property int carried: 0 property int applied: 0 // What an import would do, one setting per row, with both values already // rendered as text by the helper. Capped for display; changeCount is how // many there really are, so the page can say what it is not showing. property var changes: [] property int changeCount: 0 property var skipped: [] property string exportedFrom: "" property bool previewed: false readonly property bool busy: worker.running function run(action: string, path: string): void { if (worker.running) return; root.lastError = ""; root.lastAction = action; worker.command = [root.helperPath, action, path]; worker.running = true; } function exportTo(path: string): void { root.run("export", path); } function preview(path: string): void { root.run("preview", path); } function importFrom(path: string): void { root.run("import", path); } function absorb(text: string): void { try { const parsed = JSON.parse(text); root.lastError = String(parsed.error ?? ""); root.carried = Number(parsed.carried ?? 0); root.applied = Number(parsed.applied ?? 0); root.changes = Array.isArray(parsed.changes) ? parsed.changes : []; root.changeCount = Number(parsed.changeCount ?? root.changes.length); root.skipped = Array.isArray(parsed.skipped) ? parsed.skipped : []; root.exportedFrom = String(parsed.exportedFrom ?? ""); root.previewed = root.lastAction === "preview" && root.lastError === ""; } catch (error) { root.lastError = "Could not read the result."; console.warn("SettingsSync: could not parse helper output:", error); } } Process { id: worker stdout: StdioCollector { onStreamFinished: root.absorb(this.text) } stderr: StdioCollector { onStreamFinished: if (this.text.trim() !== "") root.lastError = this.text.trim() } } }