Sitelet https://github.com/Ameyanagi/aibo/pull/14
Skip to content

Hand the caret back after errors, and make the panel yield the stage - #14

Merged
Ameyanagi merged 1 commit into
mainfrom
panel-focus-fixes
Aug 2, 2026
Merged

Ameyanagi merged 1 commit into
mainfrom
panel-focus-fixes

Conversation

@Ameyanagi

Copy link
Copy Markdown
Owner

Four small behavioral fixes to how the panel treats focus and work in progress (all in aibo-ui/src/app.rs):

Caret returns after errors

UiEvent::Failed, ContextFailed, and DictationFailed each ended a run with focus left nowhere, so the next keystroke went into the void until the input was clicked. The success twins already refocused (StreamEvent::Done, DictationEnded); the failure paths now do the same. The blocking no-provider error still routes focus to settings.

Hotkey summons instead of dismissing

Pressing the panel hotkey while the panel was visible but another app held the keyboard hid the panel and discarded its session — the opposite of "get me back to aibo". A new panel_focused flag (tracked from Focused/Unfocused window events, set optimistically on show) lets the toggle tell the two intents apart. Dismissal stays one press away once the panel has focus.

Settings can't open behind the panel

The panel floats AlwaysOnTop; the settings window doesn't, so settings always landed behind aibo and couldn't be raised. Opening settings now hides the panel (non-destructive — the hotkey resumes the same conversation). Regression test included.

⌥⇧Space appends to the open conversation

The capture hotkey discarded the session even when the panel was open with typed text. It now takes the attach-menu path (region_capture_keeps_session): panel hides for clean pixels, capture re-presents it with the crop attached beside the composer text. Crop-then-ask still starts fresh from a closed panel, and a cancelled crop brings the conversation back.

Verified with CI's gates: cargo fmt --check, cargo clippy --workspace --all-features --all-targets --locked -- -D warnings -A unsafe-code, cargo test (298 passed).

Four fixes to how the panel treats focus and the user's work in progress,
all in the update loop:

* A failed run now returns the caret to the composer, the same way
  StreamEvent::Done always has. UiEvent::Failed, ContextFailed and
  DictationFailed each ended a run with focus left nowhere — the pattern
  was consistently "the success path refocuses, the failure path forgot"
  (DictationEnded focuses; DictationFailed did not).

* The toggle hotkey pressed while the panel is visible but another app
  holds the keyboard now summons aibo — activate, focus window, focus
  composer — instead of hiding a panel the user was trying to get back
  to and destroying the session it displayed. A new panel_focused flag
  tracks the window server's Focused/Unfocused answers, optimistically
  set on show so a quick double-press still means open-then-dismiss.

* Opening settings hides the panel. The panel floats AlwaysOnTop and
  the settings window does not, so with both on screen settings could
  only ever open behind aibo, unreachable. Nothing is lost: hide_panel
  never cancels a run and the hotkey resumes the conversation.

* The capture hotkey pressed while the panel is open joins the
  conversation in progress, exactly like the attach menu's screenshot
  row: composer text, transcript and attachments survive and the crop
  lands beside them. Discarding the session there was an implicit
  destructive gesture. Crop-then-ask still starts fresh from a closed
  panel, and a cancelled crop now brings the conversation back instead
  of leaving it destroyed and hidden.
Copilot AI review requested due to automatic review settings August 2, 2026 06:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts focus and session-handling behaviors in the UI panel to better preserve in-progress work and ensure the user can immediately continue typing after interruptions or failures.

Changes:

  • Track whether the panel window is actually focused (panel_focused) to make the toggle hotkey “summon” the panel (rather than dismiss) when another app currently has keyboard focus.
  • Return input focus to the composer after failure-ending events (UiEvent::Failed, ContextFailed, DictationFailed) to avoid “dead” keystrokes after errors.
  • Hide the always-on-top panel when opening settings so the settings window is reachable; adds a regression test.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/aibo-ui/src/app.rs
Comment on lines +1434 to +1438
let step_aside = if state.panel_visible {
state.hide_panel()
} else {
Task::none()
};
@Ameyanagi
Ameyanagi merged commit 5f61c62 into main Aug 2, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants