import QtQuick import qs.config import qs.services SettingsPage { title: "Sound" lede: "Live PipeWire output, input, and device selection." SettingsCard { title: "Output" subtitle: AudioDevices.current(true)?.description ?? "No output device" SoundDeviceList { width: parent.width output: true } AudioBalance { width: parent.width node: AudioDevices.current(true) } } SettingsCard { title: "Input" subtitle: AudioDevices.current(false)?.description ?? "No input device" SoundDeviceList { width: parent.width output: false } } // Beside Input on purpose: dictation listens through whichever device that // card selects, and putting the two together is what makes that obvious. SettingsCard { title: "Dictation" subtitle: Dictation.ready ? "Hold Super+D, speak, and release. The words are typed where the cursor is." : "Speech to text, on the GPU. Hold Super+D once it is set up. The one-time setup below 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: "Applications" subtitle: "Control each application currently playing through PipeWire." ApplicationMixer { width: parent.width } } SettingsCard { title: "Sound feedback" subtitle: "Use the same event preferences as GTK and GNOME applications." SettingRow { label: "Event sounds" detail: "Play alerts and interface event sounds" controlWidth: 42 SettingsToggle { anchors.fill: parent checked: SoundFeedback.eventSounds enabled: !SoundFeedback.busy onToggled: checked => SoundFeedback.setEventSounds(checked) } } SettingRow { label: "Input feedback" detail: "Play sounds for supported typing and input events" controlWidth: 42 divider: false SettingsToggle { anchors.fill: parent checked: SoundFeedback.inputFeedback enabled: !SoundFeedback.busy onToggled: checked => SoundFeedback.setInputFeedback(checked) } } } SettingsCard { title: "Advanced sound" ActionRow { label: "Device profiles" detail: "Open Fedora's complete device profile panel" divider: false action: "Open panel" onTriggered: SystemSettings.openGnomePanel("sound") } } }