feat(dictation): ⌘D push-to-talk, stop button icon when recording

- ⌘D is now push-to-talk: hold to record, release to stop.
  AppShell dispatches keydown/keyup events; useComposerDictation
  starts on keydown and stops on keyup.
- Button click still toggles (click mic to start, click stop to end).
- Mic icon swaps to a filled stop square while recording.
- Shortcut description updated to reflect hold-to-talk behavior.
This commit is contained in:
klopez4212
2026-07-11 16:18:40 +01:00
parent ba958389e7
commit 1bcfcd4171
4 changed files with 37 additions and 10 deletions
+9 -1
View File
@@ -597,7 +597,7 @@ export function AppShell() {
if (key === "d" && !event.shiftKey) {
event.preventDefault();
window.dispatchEvent(new CustomEvent("buzz:toggle-dictation"));
window.dispatchEvent(new CustomEvent("buzz:dictation-key-down"));
return;
}
@@ -608,9 +608,17 @@ export function AppShell() {
}
}
function handleKeyUp(event: KeyboardEvent) {
if (event.key.toLowerCase() === "d") {
window.dispatchEvent(new CustomEvent("buzz:dictation-key-up"));
}
}
window.addEventListener("keydown", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);
return () => {
window.removeEventListener("keydown", handleKeyDown);
window.removeEventListener("keyup", handleKeyUp);
};
}, [
handleOpenBrowseChannels,
@@ -71,16 +71,31 @@ export function useComposerDictation({
}
}, [disabled, dictation.isRecording, dictation.cancelRecording]);
// ⌘D global shortcut — dispatched from AppShell's keydown handler.
// ⌘D push-to-talk — hold to record, release to stop.
// Dispatched from AppShell's keydown/keyup handlers.
useEffect(() => {
function handleToggle() {
dictation.toggleRecording();
function handleKeyDown() {
if (!dictation.isRecording && !dictation.isStarting) {
dictation.startRecording();
}
}
window.addEventListener("buzz:toggle-dictation", handleToggle);
function handleKeyUp() {
if (dictation.isRecording || dictation.isStarting) {
dictation.stopRecording();
}
}
window.addEventListener("buzz:dictation-key-down", handleKeyDown);
window.addEventListener("buzz:dictation-key-up", handleKeyUp);
return () => {
window.removeEventListener("buzz:toggle-dictation", handleToggle);
window.removeEventListener("buzz:dictation-key-down", handleKeyDown);
window.removeEventListener("buzz:dictation-key-up", handleKeyUp);
};
}, [dictation.toggleRecording]);
}, [
dictation.isRecording,
dictation.isStarting,
dictation.startRecording,
dictation.stopRecording,
]);
return dictation;
}
@@ -1,4 +1,4 @@
import { Mic } from "lucide-react";
import { Mic, Square } from "lucide-react";
import { Button } from "@/shared/ui/button";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/shared/ui/tooltip";
import { cn } from "@/shared/lib/cn";
@@ -51,7 +51,11 @@ export function DictationButton({
type="button"
variant={dictation.isRecording ? "default" : "ghost"}
>
<Mic />
{dictation.isRecording ? (
<Square className="h-3.5 w-3.5 fill-current" />
) : (
<Mic />
)}
</Button>
</TooltipTrigger>
<TooltipContent>
+1 -1
View File
@@ -184,7 +184,7 @@ export const KEYBOARD_SHORTCUTS: KeyboardShortcut[] = [
{
id: "voice-dictation",
label: "Voice Dictation",
description: "Start or stop voice dictation in the composer",
description: "Hold to dictate, release to stop (push-to-talk)",
keys: "⌘D",
keysWindows: "Ctrl+D",
category: "Messages",