Use the shared floating panel for dictation - #7658
ComputelessComputer wants to merge 1 commit into
Conversation
Add optional live words, microphone activity, and cancel/finish controls across desktop platforms. Preserve destination focus and keep preview failures from interrupting recordings. ANLG-382.
There was a problem hiding this comment.
7 issues found across 260 files
Not reviewed (too large): apps/desktop/src/i18n/locales/af/messages.ts (~2 lines), apps/desktop/src/i18n/locales/am/messages.ts (~2 lines), apps/desktop/src/i18n/locales/ar/messages.ts (~2 lines), apps/desktop/src/i18n/locales/as/messages.ts (~2 lines), apps/desktop/src/i18n/locales/az/messages.ts (~2 lines), apps/desktop/src/i18n/locales/ba/messages.ts (~2 lines), apps/desktop/src/i18n/locales/be/messages.ts (~2 lines), apps/desktop/src/i18n/locales/bg/messages.ts (~2 lines), apps/desktop/src/i18n/locales/bn/messages.ts (~2 lines), apps/desktop/src/i18n/locales/bo/messages.ts (~2 lines), and 40 more - if these are generated or fixture files, add them to ignored paths to exclude them from future reviews.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/desktop/src/meeting-float/overlay/dictation.tsx">
<violation number="1" location="apps/desktop/src/meeting-float/overlay/dictation.tsx:27">
P2: During live preview, `aria-atomic="true"` makes every partial update re-announce the entire accumulated transcript, causing repeated speech and a growing screen-reader queue. Set this live region to non-atomic or isolate the changing partial text in its own live region.</violation>
</file>
<file name="plugins/dictation/src/recorder.rs">
<violation number="1" location="plugins/dictation/src/recorder.rs:204">
P2: When the preview consumer falls behind capture, the 32-item queue fills and `Preview::send` returns `false` even though the connection is still healthy. This branch permanently drops live preview and reports `previewUnavailable`; distinguish queue-full from closed/fatal errors and disable preview only for the latter.</violation>
</file>
<file name="apps/desktop/src/meeting-float/window-panel.ts">
<violation number="1" location="apps/desktop/src/meeting-float/window-panel.ts:218">
P2: When the post-update `floatingBarShow()` call fails for dictation, this branch returns without logging `shown.error`, unlike the earlier show path. Log the native error before returning so panel-open timeouts can be diagnosed.</violation>
</file>
<file name="apps/desktop/src/dictation/lifecycle.tsx">
<violation number="1" location="apps/desktop/src/dictation/lifecycle.tsx:159">
P1: When cloud live preview is enabled, `auth.getSessionForRequest()` runs before `captureTarget()`, so token-refresh latency can capture a newly focused field instead of the shortcut's original destination. Capture the target before awaiting preview-session authentication.</violation>
</file>
<file name="plugins/dictation/src/preview.rs">
<violation number="1" location="plugins/dictation/src/preview.rs:92">
P2: When a configured realtime provider is omitted from this match, live preview always reports unavailable even though batch transcription supports that provider. Dispatch every supported realtime provider or use a shared adapter registry.</violation>
</file>
<file name="plugins/windows/swift-lib/src/FloatingBarManager.swift">
<violation number="1" location="plugins/windows/swift-lib/src/FloatingBarManager.swift:319">
P2: After the initializer errors are fixed, `layout(matching:)` still cannot identify a compact dictation frame because it has no `isDictation: true` candidates. When dictation ends, `resize` falls through to the inverted expanded fallback, which can move the panel to the wrong anchor; enumerate both dictation values.</violation>
</file>
<file name="plugins/windows/swift-lib/src/FloatingBarView.swift">
<violation number="1" location="plugins/windows/swift-lib/src/FloatingBarView.swift:37">
P2: When a compact dictation bar is dragged and then expanded or finished, the panel shifts by 33 points because its preserved anchor omits the cancel button width. Pass `layout.isDictation` to the manager’s compact control-width calculation so the anchor matches the rendered controls.</violation>
</file>
Note: This PR contains a large number of files. cubic selects up to 200 of the highest-priority eligible files for this review, so some files may not have been reviewed.
Re-trigger cubic
| ); | ||
| const previewSession = | ||
| livePreview && isCloudModel | ||
| ? await auth.getSessionForRequest().catch(() => null) |
There was a problem hiding this comment.
P1: When cloud live preview is enabled, auth.getSessionForRequest() runs before captureTarget(), so token-refresh latency can capture a newly focused field instead of the shortcut's original destination. Capture the target before awaiting preview-session authentication.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/dictation/lifecycle.tsx, line 159:
<comment>When cloud live preview is enabled, `auth.getSessionForRequest()` runs before `captureTarget()`, so token-refresh latency can capture a newly focused field instead of the shortcut's original destination. Capture the target before awaiting preview-session authentication.</comment>
<file context>
@@ -119,15 +154,70 @@ function ActiveDictation({
);
+ const previewSession =
+ livePreview && isCloudModel
+ ? await auth.getSessionForRequest().catch(() => null)
+ : null;
+ const apiKey = isCloudModel
</file context>
| className="px-1 text-[15px] leading-6 break-words whitespace-pre-wrap" | ||
| style={{ color: colorScheme === "dark" ? "white" : "rgb(31, 28, 26)" }} | ||
| aria-live="polite" | ||
| aria-atomic="true" |
There was a problem hiding this comment.
P2: During live preview, aria-atomic="true" makes every partial update re-announce the entire accumulated transcript, causing repeated speech and a growing screen-reader queue. Set this live region to non-atomic or isolate the changing partial text in its own live region.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/meeting-float/overlay/dictation.tsx, line 27:
<comment>During live preview, `aria-atomic="true"` makes every partial update re-announce the entire accumulated transcript, causing repeated speech and a growing screen-reader queue. Set this live region to non-atomic or isolate the changing partial text in its own live region.</comment>
<file context>
@@ -0,0 +1,40 @@
+ className="px-1 text-[15px] leading-6 break-words whitespace-pre-wrap"
+ style={{ color: colorScheme === "dark" ? "white" : "rgb(31, 28, 26)" }}
+ aria-live="polite"
+ aria-atomic="true"
+ >
+ {dictation.text || dictation.partial ? (
</file context>
| if let Some(updates) = &updates { | ||
| let rms = (samples.iter().map(|s| f64::from(*s).powi(2)).sum::<f64>() / samples.len().max(1) as f64).sqrt(); | ||
| let _ = updates.send(RecordingUpdate::Amplitude { amplitude: (rms * 8.0).clamp(0.0, 1.0) }); | ||
| if preview.as_ref().is_some_and(|preview| !preview.send(&samples)) { |
There was a problem hiding this comment.
P2: When the preview consumer falls behind capture, the 32-item queue fills and Preview::send returns false even though the connection is still healthy. This branch permanently drops live preview and reports previewUnavailable; distinguish queue-full from closed/fatal errors and disable preview only for the latter.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At plugins/dictation/src/recorder.rs, line 204:
<comment>When the preview consumer falls behind capture, the 32-item queue fills and `Preview::send` returns `false` even though the connection is still healthy. This branch permanently drops live preview and reports `previewUnavailable`; distinguish queue-full from closed/fatal errors and disable preview only for the latter.</comment>
<file context>
@@ -179,6 +198,14 @@ async fn record_to_file(
+ if let Some(updates) = &updates {
+ let rms = (samples.iter().map(|s| f64::from(*s).powi(2)).sum::<f64>() / samples.len().max(1) as f64).sqrt();
+ let _ = updates.send(RecordingUpdate::Amplitude { amplitude: (rms * 8.0).clamp(0.0, 1.0) });
+ if preview.as_ref().is_some_and(|preview| !preview.send(&samples)) {
+ preview = None;
+ let _ = updates.send(RecordingUpdate::PreviewUnavailable);
</file context>
| await hideFloatingMeetingPanel(); | ||
| return false; | ||
| } | ||
| if (shown.status === "error") return false; |
There was a problem hiding this comment.
P2: When the post-update floatingBarShow() call fails for dictation, this branch returns without logging shown.error, unlike the earlier show path. Log the native error before returning so panel-open timeouts can be diagnosed.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/meeting-float/window-panel.ts, line 218:
<comment>When the post-update `floatingBarShow()` call fails for dictation, this branch returns without logging `shown.error`, unlike the earlier show path. Log the native error before returning so panel-open timeouts can be diagnosed.</comment>
<file context>
@@ -205,6 +209,15 @@ export async function showFloatingMeetingWindow(
+ await hideFloatingMeetingPanel();
+ return false;
+ }
+ if (shown.status === "error") return false;
+ }
+
</file context>
| if (shown.status === "error") return false; | |
| if (shown.status === "error") { | |
| console.error("Failed to show floating meeting panel:", shown.error); | |
| return false; | |
| } |
| "elevenlabs" => listen::<ElevenLabsAdapter>(config, receiver, updates).await, | ||
| "gladia" => listen::<GladiaAdapter>(config, receiver, updates).await, | ||
| "meta" => listen::<MetaAdapter>(config, receiver, updates).await, | ||
| _ => Err(()), |
There was a problem hiding this comment.
P2: When a configured realtime provider is omitted from this match, live preview always reports unavailable even though batch transcription supports that provider. Dispatch every supported realtime provider or use a shared adapter registry.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At plugins/dictation/src/preview.rs, line 92:
<comment>When a configured realtime provider is omitted from this match, live preview always reports unavailable even though batch transcription supports that provider. Dispatch every supported realtime provider or use a shared adapter registry.</comment>
<file context>
@@ -0,0 +1,318 @@
+ "elevenlabs" => listen::<ElevenLabsAdapter>(config, receiver, updates).await,
+ "gladia" => listen::<GladiaAdapter>(config, receiver, updates).await,
+ "meta" => listen::<MetaAdapter>(config, receiver, updates).await,
+ _ => Err(()),
+ }
+}
</file context>
| private struct FloatingBarWindowLayout { | ||
| let isExpanded: Bool | ||
| let showsExpand: Bool | ||
| let isDictation: Bool |
There was a problem hiding this comment.
P2: After the initializer errors are fixed, layout(matching:) still cannot identify a compact dictation frame because it has no isDictation: true candidates. When dictation ends, resize falls through to the inverted expanded fallback, which can move the panel to the wrong anchor; enumerate both dictation values.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At plugins/windows/swift-lib/src/FloatingBarManager.swift, line 319:
<comment>After the initializer errors are fixed, `layout(matching:)` still cannot identify a compact dictation frame because it has no `isDictation: true` candidates. When dictation ends, `resize` falls through to the inverted expanded fallback, which can move the panel to the wrong anchor; enumerate both dictation values.</comment>
<file context>
@@ -308,4 +316,11 @@ final class FloatingBarManager {
private struct FloatingBarWindowLayout {
let isExpanded: Bool
let showsExpand: Bool
+ let isDictation: Bool
+}
+
</file context>
| static func compactControlsWidth(showsExpand: Bool, isDictation: Bool = false) -> CGFloat { | ||
| let recordingControls = | ||
| showsExpand ? compactStopWidth + compactGap + compactIconSize : compactSoloStopWidth | ||
| return recordingControls + (isDictation ? compactIconSize + compactGap : 0) |
There was a problem hiding this comment.
P2: When a compact dictation bar is dragged and then expanded or finished, the panel shifts by 33 points because its preserved anchor omits the cancel button width. Pass layout.isDictation to the manager’s compact control-width calculation so the anchor matches the rendered controls.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At plugins/windows/swift-lib/src/FloatingBarView.swift, line 37:
<comment>When a compact dictation bar is dragged and then expanded or finished, the panel shifts by 33 points because its preserved anchor omits the cancel button width. Pass `layout.isDictation` to the manager’s compact control-width calculation so the anchor matches the rendered controls.</comment>
<file context>
@@ -31,29 +31,27 @@ enum FloatingBarLayout {
+ static func compactControlsWidth(showsExpand: Bool, isDictation: Bool = false) -> CGFloat {
+ let recordingControls =
+ showsExpand ? compactStopWidth + compactGap + compactIconSize : compactSoloStopWidth
+ return recordingControls + (isDictation ? compactIconSize + compactGap : 0)
}
</file context>
Add optional live words, microphone activity, and cancel/finish controls across desktop platforms. Preserve destination focus and keep preview failures from interrupting recordings. ANLG-382.
Summary by cubic
Implements ANLG-382 by moving dictation into the shared floating panel instead of a dedicated dictation window, so the destination field keeps focus on all desktop platforms. Adds an optional live transcript preview, and dictation keeps recording normally if the preview connection can't be set up.
Details
Written for commit 0eb151b. Summary will update on new commits.