fix(widget): hide dictation pill when idle, show only when activated - #83
Conversation
Addresses pre-existing pill-mode UX where the idle "Ready" state was always visible on screen — cluttering the desktop for users who only invoke dictation via the global shortcut (Cmd+Shift+Space) or tray menu. User direction during the PR #51 review session: "dont show it if not activated". Widget now appears only when activated by the global shortcut or the tray "Start Dictation" menu item. Two surgical edits to frontend/src-tauri/src/lib.rs: 1. pill_mode_setup branch (~lines 384-406): drop win.show() and win.set_focus() on the widget window. Keep the top-center pre-positioning so the first show (via shortcut or tray) appears at the right location without a frame-jump on first show. Update the surrounding comment to document the new hidden-until-activated contract. 2. Tray "Start Dictation" handler (~lines 331-343): show + position + focus the widget BEFORE emitting tray-dictate. Previously the start branch only emitted the event, so triggering dictation from the tray menu recorded silently with no visible UI. The inline position+show+focus block mirrors the global-shortcut handler at lines 184-199; helper extraction was rejected to keep the diff minimal (see plan risks: "Keep the diff minimal"). The global shortcut handler (lines 184-199) and CaptureWidget.jsx auto-hide-on-done logic are unchanged — both were already correct. Trade-off vs the original "looks-launch-failed" first-run concern is accepted: the tray icon + "OmniVoice Dictation" tooltip (lib.rs:289) provide sufficient signal that the app is running. Idle on-screen pill is not required for that. Verified: cargo check --manifest-path frontend/src-tauri/Cargo.toml exits 0 with no warnings on our crate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Companion to commit 001d975 (the lib.rs behavior change). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR adds planning documentation and implements widget visibility behavior changes in the Tauri-based dictation system: the pill widget is pre-positioned but remains hidden during pill-mode initialization, and the tray "dictate" menu handler now positions, shows, and focuses the widget before emitting events. ChangesDictation pill widget idle/activation behavior
Sequence DiagramsequenceDiagram
participant PillInit as Pill-mode Init
participant TrayMenu as Tray Menu
participant WidgetWindow as Widget Window
participant EventEmit as Event Emitter
PillInit->>WidgetWindow: Position widget at top-center (y=60)
PillInit->>WidgetWindow: Log: pill-mode widget pre-positioned
PillInit->>WidgetWindow: Keep hidden (no show/focus)
TrayMenu->>WidgetWindow: Check if widget is visible
alt Widget not visible
TrayMenu->>WidgetWindow: Position at top-center (y=60 or center)
TrayMenu->>WidgetWindow: Show widget
TrayMenu->>WidgetWindow: Focus widget
TrayMenu->>EventEmit: Emit tray-dictate
else Widget already visible
TrayMenu->>EventEmit: Emit tray-dictate-stop
else Widget not found
TrayMenu->>WidgetWindow: Log warning: widget window missing
end
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes The PR primarily updates planning documentation (365 lines) with clear, structured specification and introduces a focused implementation change in one file (38 lines modified) affecting two code paths: pill-mode widget initialization and tray menu event handler. The logic is straightforward positioning and visibility state management without complex branching or edge-case handling beyond the documented scenarios. Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
.planning/quick/260518-lp7-hide-dictation-pill-widget-when-idle-sho/260518-lp7-PLAN.md (1)
147-178: ⚡ Quick winAdd a language tag to the fenced commit block.
The fenced block is missing a language identifier, which triggers MD040 and can cause docs-lint noise/failures.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.planning/quick/260518-lp7-hide-dictation-pill-widget-when-idle-sho/260518-lp7-PLAN.md around lines 147 - 178, The fenced commit block lacks a language tag which triggers MD040; update the triple-backtick fence that wraps the git commit (the block starting with git commit -m "$(cat <<'EOF' ... EOF )") to include a shell language identifier (e.g., ```sh or ```bash) so the block is linted correctly and MD040 warnings are resolved..planning/quick/260518-lp7-hide-dictation-pill-widget-when-idle-sho/260518-lp7-SUMMARY.md (1)
71-76: ⚡ Quick winSpecify fence languages for command/output blocks.
These fenced blocks are untyped and trigger MD040 warnings; please annotate them (e.g.,
bashfor commands,textfor output).Also applies to: 80-87, 91-95, 101-114
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.planning/quick/260518-lp7-hide-dictation-pill-widget-when-idle-sho/260518-lp7-SUMMARY.md around lines 71 - 76, The fenced code blocks showing the cargo command and its output are missing language annotations (e.g., the block containing "$ cargo check --manifest-path frontend/src-tauri/Cargo.toml 2>&1 | tail -3" and its result); update those fences to include appropriate languages (use ```bash for the command lines and ```text or ```output for the command output) and apply the same fix to the other untyped fences noted (around the sections corresponding to the ranges shown: 80-87, 91-95, 101-114) so MD040 warnings are resolved.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/src-tauri/src/lib.rs`:
- Around line 356-360: The current fallback emits "tray-dictate" even when the
widget window is missing (in the block that logs "Tray dictate: widget window
not found — emitting tray-dictate without visible UI"), which restarts
dictation; instead stop emitting that event when the window is absent. Modify
the code path around the log and the call to app.emit("tray-dictate", ()) so
that if the widget window lookup fails you only log the warning and return/abort
the tray-start flow (do not call app.emit), ensuring functions that handle
"tray-dictate" (and any dictation start logic) are not invoked when the widget
window is not found.
---
Nitpick comments:
In
@.planning/quick/260518-lp7-hide-dictation-pill-widget-when-idle-sho/260518-lp7-PLAN.md:
- Around line 147-178: The fenced commit block lacks a language tag which
triggers MD040; update the triple-backtick fence that wraps the git commit (the
block starting with git commit -m "$(cat <<'EOF' ... EOF )") to include a shell
language identifier (e.g., ```sh or ```bash) so the block is linted correctly
and MD040 warnings are resolved.
In
@.planning/quick/260518-lp7-hide-dictation-pill-widget-when-idle-sho/260518-lp7-SUMMARY.md:
- Around line 71-76: The fenced code blocks showing the cargo command and its
output are missing language annotations (e.g., the block containing "$ cargo
check --manifest-path frontend/src-tauri/Cargo.toml 2>&1 | tail -3" and its
result); update those fences to include appropriate languages (use ```bash for
the command lines and ```text or ```output for the command output) and apply the
same fix to the other untyped fences noted (around the sections corresponding to
the ranges shown: 80-87, 91-95, 101-114) so MD040 warnings are resolved.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: ea5d4252-cf55-4391-b4e3-26927fb4de6d
📒 Files selected for processing (4)
.planning/STATE.md.planning/quick/260518-lp7-hide-dictation-pill-widget-when-idle-sho/260518-lp7-PLAN.md.planning/quick/260518-lp7-hide-dictation-pill-widget-when-idle-sho/260518-lp7-SUMMARY.mdfrontend/src-tauri/src/lib.rs
| log::warn!( | ||
| "Tray dictate: widget window not found — \ | ||
| emitting tray-dictate without visible UI" | ||
| ); | ||
| let _ = app.emit("tray-dictate", ()); |
There was a problem hiding this comment.
Don’t start dictation when the widget window is missing.
This fallback still emits tray-dictate, which can reintroduce silent recording in the exact tray-start path this PR is trying to fix.
Suggested fix
} else {
log::warn!(
"Tray dictate: widget window not found — \
- emitting tray-dictate without visible UI"
+ refusing to start dictation without visible UI"
);
- let _ = app.emit("tray-dictate", ());
+ // Intentionally do not emit tray-dictate here.
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| log::warn!( | |
| "Tray dictate: widget window not found — \ | |
| emitting tray-dictate without visible UI" | |
| ); | |
| let _ = app.emit("tray-dictate", ()); | |
| log::warn!( | |
| "Tray dictate: widget window not found — \ | |
| refusing to start dictation without visible UI" | |
| ); | |
| // Intentionally do not emit tray-dictate here. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/src-tauri/src/lib.rs` around lines 356 - 360, The current fallback
emits "tray-dictate" even when the widget window is missing (in the block that
logs "Tray dictate: widget window not found — emitting tray-dictate without
visible UI"), which restarts dictation; instead stop emitting that event when
the window is absent. Modify the code path around the log and the call to
app.emit("tray-dictate", ()) so that if the widget window lookup fails you only
log the warning and return/abort the tray-start flow (do not call app.emit),
ensuring functions that handle "tray-dictate" (and any dictation start logic)
are not invoked when the widget window is not found.
Summary
tray-dictate, mirroring the global-shortcut handler — without this, starting dictation from the tray would record silently.Why
User reported during the v0.3.x stabilization review session that the idle "Ready" pill state should not be visible. Widget should appear only when actively used (recording / transcribing).
Trade-off acknowledged
The original code intentionally auto-showed the widget on launch to avoid a "looks-launch-failed" first-run experience (relevant when a user hasn't granted Accessibility permission for the global shortcut). That trade-off is accepted here because:
done(CaptureWidget.jsx:128-149) was already implemented — this PR aligns launch behavior with the rest of the state machineScope
frontend/src-tauri/src/lib.rswin.show()+win.set_focus()), traydictatehandler (add position+show+focus before emit)Untouched: global-shortcut handler (already shows widget correctly), CaptureWidget.jsx (auto-hide on done already works), tauri.conf.json (widget
visible: false, create: falseis correct).Test plan
cargo check --manifest-path frontend/src-tauri/Cargo.toml→ exit 0 (~49s)bun desktopin pill mode → widget should NOT appear on launch, only tray icon visibleOut of scope
The
open_studiotray handler still doesCommand::new(exe).spawn() + app.exit(0)which produces a blank dev window inbun desktopmode (tracked separately as a known-issue). Production users on bundled installers don't hit it. Fix coming in a follow-up PR.🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes