aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/assistant/Card.qml
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-19 11:20:12 +0200
committerDanilo M. <danix@danix.xyz>2026-10-19 11:20:12 +0200
commitc1fc2001219eb9aa349439b3007b57e1ced25335 (patch)
tree900e3fbc9da3a58d8f4e08f68040dd080c75ef84 /desktop/assistant/Card.qml
parent5ce0cdf77d19e74d85de8674e88b25db213e8534 (diff)
downloadquickshell-c1fc2001219eb9aa349439b3007b57e1ced25335.tar.gz
quickshell-c1fc2001219eb9aa349439b3007b57e1ced25335.zip
assistant: a mic button asks by voice
Each recording is a pw-record Process of its own, made from a Component like the Do row's runs, so a stopped recording's late exit cannot be read as the next one's. Stopping sets running to false (SIGTERM), which lets pw-record write the WAV header; the audio ask goes out from the process's exit, not from the click. Recording stops itself at 59 s: the daemon refuses over 60 s by file size, and the stop lands a little after the tick. Escape cancels a recording before it does anything else, and closing the card or losing the daemon cancels it too. A pw-record that ends on its own says "recording failed". Checked: a scratch harness saw transcribing, thinking, idle for a 2 s recording; by hand, every case in the spec passed with no pw-record left behind, a desktop shell reload mid-recording included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop/assistant/Card.qml')
-rw-r--r--desktop/assistant/Card.qml24
1 files changed, 23 insertions, 1 deletions
diff --git a/desktop/assistant/Card.qml b/desktop/assistant/Card.qml
index 4c76e64..d8826fa 100644
--- a/desktop/assistant/Card.qml
+++ b/desktop/assistant/Card.qml
@@ -431,10 +431,30 @@ Rectangle {
}
}
+ // nf-fa-microphone, checked in Inconsolata Nerd Font. Every state,
+ // entry included: SUPER+Home opens the card and the mic is one click away.
+ Button {
+ id: mic
+ anchors { bottom: parent.bottom; left: attach.right; leftMargin: attach.visible ? 8 : 0 }
+ height: box.height
+ icon: ""
+ text: card.canvas.recording
+ ? `${Math.floor(card.canvas.micSecs / 60)}:${String(card.canvas.micSecs % 60).padStart(2, "0")}`
+ : ""
+ danger: card.canvas.recording
+ enabled: card.canvas.connected && (card.canvas.recording
+ || (!card.canvas.busy && !card.canvas.opRunning && !card.canvas.blocked))
+ onClicked: {
+ if (card.canvas.recording) card.canvas.endRecording(true);
+ else card.canvas.record();
+ input.forceActiveFocus();
+ }
+ }
+
Rectangle {
id: box
anchors {
- bottom: parent.bottom; left: attach.right; leftMargin: attach.visible ? 8 : 0
+ bottom: parent.bottom; left: mic.right; leftMargin: 8
right: history.left; rightMargin: 8
}
// Grows with the text up to six lines, then scrolls.
@@ -483,6 +503,8 @@ Rectangle {
visible: input.text === ""
elide: Text.ElideRight
text: !card.canvas.connected ? "assistant not running"
+ : card.canvas.recording ? "Listening… click the mic to send"
+ : card.canvas.state === "transcribing" ? "Transcribing…"
: card.mode === "entry" ? "How can I help you?"
: card.canvas.staged.length ? `Ask about ${card.canvas.staged[0].name}…`
: "Message the assistant"