Show every answer the portal remembers, and give SSH keys their missing half
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
pragma Singleton
|
||||
|
||||
// What this desktop remembers about what you opened.
|
||||
//
|
||||
// Two traces -- the recent-files list and the thumbnail cache -- both of them a
|
||||
// normal and useful part of a desktop rather than a problem. This measures them
|
||||
// when asked and clears them when asked, and does neither on its own.
|
||||
//
|
||||
// Nothing here measures on startup. Walking a thumbnail cache costs real time
|
||||
// on a machine that has browsed a large picture library, and a settings page
|
||||
// that has not been opened has no business spending it. `measured` says whether
|
||||
// there is an answer yet, so the card can show its own state honestly instead of
|
||||
// showing a confident zero.
|
||||
//
|
||||
// Trash is deliberately absent. It is measured and emptied by Disks, and one
|
||||
// trash implementation is the right number to have.
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property string helperPath: Quickshell.env("PANAMA_PRIVACY_HELPER")
|
||||
|| Quickshell.shellDir + "/scripts/panama-privacy"
|
||||
|
||||
// real rather than int: a thumbnail cache on a machine with a large picture
|
||||
// library goes past what a 32-bit int holds, and a byte count that wrapped
|
||||
// negative is worse than no byte count.
|
||||
property real recentsBytes: 0
|
||||
property int recentsEntries: 0
|
||||
property string recentsPath: ""
|
||||
property bool recentsPresent: false
|
||||
|
||||
property real thumbnailsBytes: 0
|
||||
property string thumbnailsPath: ""
|
||||
property bool thumbnailsPresent: false
|
||||
|
||||
// False when the walk ran out of time, which makes the byte count a floor
|
||||
// rather than an answer.
|
||||
property bool thumbnailsComplete: true
|
||||
|
||||
// Whether there is an answer at all yet. Distinct from thumbnailsComplete,
|
||||
// which is about the quality of an answer that exists.
|
||||
property bool measured: false
|
||||
|
||||
property string lastError: ""
|
||||
|
||||
readonly property bool busy: reader.running || mutation.running
|
||||
|
||||
function measure(): void {
|
||||
if (reader.running)
|
||||
return;
|
||||
reader.command = [root.helperPath, "traces"];
|
||||
reader.running = true;
|
||||
}
|
||||
|
||||
function absorb(text: string): void {
|
||||
try {
|
||||
const parsed = JSON.parse(text);
|
||||
const recents = parsed.recents ?? ({});
|
||||
const thumbnails = parsed.thumbnails ?? ({});
|
||||
root.recentsBytes = Number(recents.bytes ?? 0);
|
||||
root.recentsEntries = Number(recents.entries ?? 0);
|
||||
root.recentsPath = String(recents.path ?? "");
|
||||
root.recentsPresent = recents.present === true;
|
||||
root.thumbnailsBytes = Number(thumbnails.bytes ?? 0);
|
||||
root.thumbnailsPath = String(thumbnails.path ?? "");
|
||||
root.thumbnailsPresent = thumbnails.present === true;
|
||||
root.thumbnailsComplete = thumbnails.measured !== false;
|
||||
root.lastError = String(parsed.error ?? "");
|
||||
} catch (error) {
|
||||
root.lastError = "Could not read what the desktop has remembered.";
|
||||
console.warn("Traces: could not parse helper output:", error);
|
||||
}
|
||||
root.measured = true;
|
||||
}
|
||||
|
||||
function run(verb: string): void {
|
||||
if (mutation.running)
|
||||
return;
|
||||
root.lastError = "";
|
||||
mutation.command = [root.helperPath, verb];
|
||||
mutation.running = true;
|
||||
}
|
||||
|
||||
// The list is emptied, never deleted: GTK recreates the file the moment
|
||||
// anything opens a file anyway, and an empty valid document takes effect in
|
||||
// every running application immediately.
|
||||
function clearRecents(): void { root.run("clear-recents"); }
|
||||
|
||||
// The folder stays; what is inside it goes. The helper refuses to follow a
|
||||
// link out of it.
|
||||
function clearThumbnails(): void { root.run("clear-thumbnails"); }
|
||||
|
||||
Process {
|
||||
id: reader
|
||||
stdout: StdioCollector { onStreamFinished: root.absorb(this.text) }
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: if (this.text.trim() !== "") root.lastError = this.text.trim()
|
||||
}
|
||||
}
|
||||
|
||||
// Both clears answer with a freshly measured snapshot, so the card updates
|
||||
// without a second read.
|
||||
Process {
|
||||
id: mutation
|
||||
stdout: StdioCollector { onStreamFinished: root.absorb(this.text) }
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: if (this.text.trim() !== "") root.lastError = this.text.trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user