Fold thirty-one settings pages into fifteen categories with tabs
The sidebar was a flat scan of thirty-one rows; now it reads like a settings app. Multi-subject categories (Input, Network & Sharing, Applications, Users & Accounts, Privacy & Security, System) carry an Appearance-style tab strip above the page, drawn by the shell so the leaf pages themselves are untouched. The taxonomy lives in one new file, services/SettingsRoutes.qml; the sidebar, the strip, route validation, search breadcrumbs, and both generators derive from it. ShellState.settingsPage still holds leaf ids, so every deep link, IPC call, and search result keeps working — and now lands on the exact tab. Dictation moves out of Sound onto its own page under Input, with a handoff back to Sound for the microphone. The strip scrolls when System's nine tabs outgrow a tiled window. All 161 contracts pass. Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
|
||||
// Dictation is an input method, so it lives under Input beside the keyboard —
|
||||
// but it listens through whichever device the Sound page selects, so the
|
||||
// microphone card below hands off there rather than duplicating the picker.
|
||||
SettingsPage {
|
||||
title: "Dictation"
|
||||
lede: Dictation.ready
|
||||
? "Hold Super+D, speak, and release. The words are typed where the cursor is."
|
||||
: "Speech to text, on the GPU, once the one-time setup below has run."
|
||||
|
||||
SettingsCard {
|
||||
title: "Dictation"
|
||||
subtitle: Dictation.ready
|
||||
? "Hold Super+D, speak, and release. The words are typed where the cursor is."
|
||||
: "The one-time setup fetches a speech server and a ~490 MB model — neither ships with Panama, because both are large and want the network."
|
||||
|
||||
// Status of the two pieces, read from the machine rather than guessed.
|
||||
TextRow {
|
||||
label: "Speech server"
|
||||
detail: Dictation.serverReady
|
||||
? "Running"
|
||||
: (Dictation.imageBuilt ? "Ready — starts on the first dictation" : "Not set up yet")
|
||||
value: Dictation.imageBuilt ? "Ready" : "Missing"
|
||||
}
|
||||
|
||||
TextRow {
|
||||
label: "Speech model"
|
||||
detail: Dictation.modelInstalled
|
||||
? "Kept across rebuilds of the server"
|
||||
: "About 490 MB, downloaded once"
|
||||
value: Dictation.modelInstalled ? Math.round(Dictation.modelBytes / 1048576) + " MB" : "Missing"
|
||||
}
|
||||
|
||||
// ONE action that actually works: panama-dictate setup pulls the
|
||||
// server image and downloads the model together. This card used to
|
||||
// offer a Download button wired to a command the helper does not have,
|
||||
// and told you to build a "panama app whisper-vulkan" that does not
|
||||
// exist -- so nothing here did anything. It does now.
|
||||
ActionRow {
|
||||
visible: !Dictation.ready || Dictation.downloading
|
||||
label: "Set up dictation"
|
||||
detail: {
|
||||
if (!Dictation.downloading)
|
||||
return "Fetches the speech server and the model. Runs once, keeps both.";
|
||||
if (Dictation.phase === "pulling")
|
||||
return "Fetching the speech server…";
|
||||
if (Dictation.downloadTotalBytes > 0)
|
||||
return "Downloading model — " + Math.round(Dictation.downloadFraction * 100)
|
||||
+ "% of " + Math.round(Dictation.downloadTotalBytes / 1048576) + " MB";
|
||||
return "Setting up…";
|
||||
}
|
||||
action: Dictation.downloading ? "Working…" : "Set up"
|
||||
enabled: !Dictation.downloading
|
||||
onTriggered: Dictation.setup()
|
||||
divider: !Dictation.typingAvailable || Dictation.lastError !== ""
|
||||
}
|
||||
|
||||
TextRow {
|
||||
visible: !Dictation.typingAvailable
|
||||
label: "Typing"
|
||||
detail: "wtype is missing, so dictated text would go to the clipboard instead of being typed."
|
||||
value: "Missing"
|
||||
divider: Dictation.lastError !== ""
|
||||
}
|
||||
|
||||
TextRow {
|
||||
visible: Dictation.lastError !== ""
|
||||
label: "Problem"
|
||||
detail: Dictation.lastError
|
||||
value: ""
|
||||
divider: false
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Microphone"
|
||||
subtitle: AudioDevices.current(false)?.description ?? "No input device"
|
||||
|
||||
ActionRow {
|
||||
label: "Input device"
|
||||
detail: "Dictation listens through the input device selected in Sound"
|
||||
divider: false
|
||||
action: "Open Sound"
|
||||
onTriggered: ShellState.openSettings("sound")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user