fix(app): keep dictation shortcuts responsive (#2268)

The composer mirrored dictation state in a second ref that could remain stale after the recording surface changed. Route shortcut decisions through the dictation lifecycle's synchronous state so finishing or rejecting a recording cannot leave Command-D latched.
This commit is contained in:
Mohamed Boudra
2026-07-20 19:32:50 +02:00
committed by GitHub
parent b3b1283d3b
commit 2ead7e7719
5 changed files with 122 additions and 77 deletions
@@ -4,12 +4,40 @@ import {
resolveComposerSurfacePresentation,
runAlternateSendAction,
runDefaultSendAction,
runMessageInputKeyboardAction,
stopRealtimeVoice,
} from "./state";
const connected = { isConnected: true } as never;
const disconnected = { isConnected: false } as never;
function createDictationKeyboard({ startsRecording }: { startsRecording: boolean }) {
let isRecording = false;
const actions: string[] = [];
return {
actions,
pressDictationShortcut: () =>
runMessageInputKeyboardAction("dictation-toggle", {
focusInput: () => undefined,
isDictationRecording: () => isRecording,
markTranscriptForSend: () => actions.push("send transcript"),
startDictation: () => {
actions.push("start");
isRecording = startsRecording;
},
confirmDictation: () => {
actions.push("confirm");
isRecording = false;
},
cancelDictation: () => undefined,
toggleRealtimeVoice: () => undefined,
isRealtimeVoiceActive: false,
toggleRealtimeVoiceMute: () => undefined,
}),
};
}
describe("composer surface presentation", () => {
it("shows only the input when no voice overlay is active", () => {
expect(resolveComposerSurfacePresentation(false)).toEqual({
@@ -114,6 +142,27 @@ describe("computeCanStartDictation", () => {
});
});
describe("dictation keyboard behavior", () => {
it("starts dictation again after the previous dictation finishes", () => {
const keyboard = createDictationKeyboard({ startsRecording: true });
keyboard.pressDictationShortcut();
keyboard.pressDictationShortcut();
keyboard.pressDictationShortcut();
expect(keyboard.actions).toEqual(["start", "send transcript", "confirm", "start"]);
});
it("can retry when starting dictation does not enter the recording state", () => {
const keyboard = createDictationKeyboard({ startsRecording: false });
keyboard.pressDictationShortcut();
keyboard.pressDictationShortcut();
expect(keyboard.actions).toEqual(["start", "start"]);
});
});
describe("composer send behavior", () => {
function actions() {
const calls: string[] = [];