Make Applications a real app manager, and clean up storage without the racket
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -18,6 +18,16 @@ Singleton {
|
||||
property var luaAutostartEntries: []
|
||||
property string lastError: ""
|
||||
|
||||
// One file type at a time: the escape hatch for when a role's family is too
|
||||
// broad, which is a real case -- SVG belongs in an editor while every other
|
||||
// image belongs in a viewer. Kept separate from the role state because it is
|
||||
// a search, not a setting: it is whatever was last asked for and nothing is
|
||||
// remembered between visits.
|
||||
property var typeMatches: []
|
||||
property string typeQuery: ""
|
||||
property bool typeSearchTruncated: false
|
||||
readonly property bool searchingTypes: typeSearch.running
|
||||
|
||||
// For the UI, which wants one answer to "is anything happening".
|
||||
//
|
||||
// Guards inside this file do NOT use it. `busy` is a binding, and a binding
|
||||
@@ -56,15 +66,48 @@ Singleton {
|
||||
Process {
|
||||
id: mutationProcess
|
||||
|
||||
// A set-type write changes the answer the open search is showing, so
|
||||
// the search is re-run rather than left displaying the old handler.
|
||||
property string repeatQuery: ""
|
||||
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
if (exitCode !== 0) {
|
||||
mutationProcess.repeatQuery = ""
|
||||
root.lastError = "That application setting could not be changed."
|
||||
return;
|
||||
}
|
||||
if (mutationProcess.repeatQuery !== "") {
|
||||
const query = mutationProcess.repeatQuery;
|
||||
mutationProcess.repeatQuery = "";
|
||||
root.searchTypes(query);
|
||||
}
|
||||
root.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: typeSearch
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
try {
|
||||
const payload = JSON.parse(this.text);
|
||||
root.typeMatches = Array.isArray(payload.types) ? payload.types : [];
|
||||
root.typeSearchTruncated = payload.truncated === true;
|
||||
} catch (error) {
|
||||
root.typeMatches = [];
|
||||
root.lastError = "File types returned an unreadable response."
|
||||
}
|
||||
}
|
||||
}
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
if (exitCode !== 0) {
|
||||
root.typeMatches = [];
|
||||
root.lastError = "File types could not be searched."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applySnapshot(text: string): void {
|
||||
try {
|
||||
const payload = JSON.parse(text);
|
||||
@@ -135,6 +178,47 @@ Singleton {
|
||||
mutationProcess.exec([root.helper, "remove-autostart", desktopId]);
|
||||
}
|
||||
|
||||
// Searching is over the type name and its file extensions -- "svg", "heic",
|
||||
// ".mkv". Matching the human descriptions would mean reading the whole
|
||||
// shared-mime-info database, some thousands of small files, per keystroke.
|
||||
function searchTypes(query: string): void {
|
||||
const trimmed = String(query ?? "").trim();
|
||||
root.typeQuery = trimmed;
|
||||
if (trimmed.length < 2) {
|
||||
root.typeMatches = [];
|
||||
root.typeSearchTruncated = false;
|
||||
return;
|
||||
}
|
||||
if (typeSearch.running)
|
||||
return;
|
||||
typeSearch.exec([root.helper, "search-types", trimmed]);
|
||||
}
|
||||
|
||||
function clearTypeSearch(): void {
|
||||
root.typeQuery = "";
|
||||
root.typeMatches = [];
|
||||
root.typeSearchTruncated = false;
|
||||
}
|
||||
|
||||
// One type, one application: the override that leaves the rest of the
|
||||
// family where it is. The helper validates the type against what this
|
||||
// system knows and the application against what is installed.
|
||||
function setType(mime: string, desktopId: string): void {
|
||||
if (mutationProcess.running)
|
||||
return;
|
||||
if (!/^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*$/.test(mime)) {
|
||||
root.lastError = "Choose a file type from the list."
|
||||
return;
|
||||
}
|
||||
if (!root.knownDesktopId(desktopId)) {
|
||||
root.lastError = "Choose an application from the available list."
|
||||
return;
|
||||
}
|
||||
root.lastError = "";
|
||||
mutationProcess.repeatQuery = root.typeQuery;
|
||||
mutationProcess.exec([root.helper, "set-type", mime, desktopId]);
|
||||
}
|
||||
|
||||
function addAutostart(desktopId: string): void {
|
||||
if (mutationProcess.running)
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user