Skip to content

Fix iOS keyboard focus after photo picker - #9287

Merged
azooz2003-bit merged 3 commits into
mainfrom
feat-ios-photo-picker-focus
Aug 1, 2026
Merged

azooz2003-bit merged 3 commits into
mainfrom
feat-ios-photo-picker-focus

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jul 31, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes the workspace-detail terminal getting stuck with a hidden keyboard after cancelling the attachment photo picker.

The composer now releases both SwiftUI field focus and the terminal input proxy before presenting the system picker. Terminal, composer, and chrome dismissal share one responder-release path.

Regression coverage reproduces the exact sequence and asserts that the first terminal tap restores both proxy focus and the software keyboard.

Verification in progress:

  • iOS UI regression, red on test-only commit d0e352d
  • iOS UI regression, green run dispatched for fix commit 640e87a
  • tagged macOS and iOS builds, isolated simulator, and iPhone preflight

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Fixes the iOS keyboard staying hidden after cancelling the photo picker. The composer now clears field focus and the surface releases its responder before presenting, so a terminal tap reliably brings the keyboard back.

  • Bug Fixes
    • CmuxMobileShellUI: Composer clears @FocusState, gates picker via presentPhotoPicker(), and calls prepareForModalPresentation so GhosttySurfaceRepresentable can release the surface responder first.
    • CmuxMobileTerminal: Added resignCurrentInput() and routed existing paths through it to keep first-responder and keyboard state in sync.
    • cmuxUITests: Regression test ensures a terminal tap re-opens the keyboard after cancelling the photo picker.

Written for commit fa97d5f. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes

    • Improved keyboard and input focus handling when opening or dismissing the photo picker.
    • Ensured terminal input can be restored reliably after cancelling the photo picker.
    • Prevented keyboard state inconsistencies during modal transitions.
  • Tests

    • Added regression coverage for photo-picker cancellation and keyboard restoration.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The changes add a modal-preparation step before the composer's photo picker opens. GhosttySurfaceView gains a resignCurrentInput() method that releases whichever input control owns the keyboard. TerminalComposerView uses a new closure to call this before presenting the picker. A UI test validates keyboard state through cancellation and restoration.

Changes

Composer keyboard resignation before modal presentation

Layer / File(s) Summary
Shared input resignation on GhosttySurfaceView
Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView.swift
Adds public resignCurrentInput(), which resigns the terminal proxy or ends editing in the composer container and clears the active-input reference. Existing keyboard-toggle and chrome-hiding code paths now call this shared method.
TerminalComposerView modal preparation before photo picker
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalComposerView.swift
Adds prepareForModalPresentation property and init parameter. New presentPhotoPicker() method clears field focus, calls the preparation closure, then presents the picker. The attach button now calls presentPhotoPicker() instead of setting isPickerPresented directly.
Wiring modal preparation closure to surface input resignation
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/GhosttySurfaceRepresentable.swift
makeComposerController passes separate closures for height remeasurement and modal preparation, with modal preparation resigning the surface's current input responder.
UI regression test for photo picker cancellation
ios/cmuxUITests/cmuxUITests.swift
Adds a Composer.attachButton accessibility identifier and a test verifying keyboard dismissal on picker cancellation and restoration on subsequent terminal tap.

Estimated code review effort: 2 (Simple) | ~12 minutes

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant TerminalComposerView
    participant GhosttySurfaceRepresentable
    participant GhosttySurfaceView

    User->>TerminalComposerView: Tap attach button
    TerminalComposerView->>TerminalComposerView: presentPhotoPicker()
    TerminalComposerView->>TerminalComposerView: Clear field focus
    TerminalComposerView->>GhosttySurfaceRepresentable: prepareForModalPresentation()
    GhosttySurfaceRepresentable->>GhosttySurfaceView: resignCurrentInput()
    GhosttySurfaceView->>GhosttySurfaceView: Resign terminal proxy or composer container
    TerminalComposerView->>User: Present photo picker
    User->>TerminalComposerView: Cancel picker
    User->>GhosttySurfaceView: Tap terminal
    GhosttySurfaceView->>GhosttySurfaceView: Restore proxy responder and keyboard
Loading

Possibly related issues

  • manaflow-ai/cmux-dev-artifacts#7091: This PR adds the testTerminalTapRestoresKeyboardAfterCancellingPhotoPicker UI test that the issue describes.
🚥 Pre-merge checks | ✅ 4 | ❌ 21

❌ Failed checks (1 warning, 20 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the bug and implementation, but it omits the required Demo Video, Review Trigger, and Checklist sections, and testing remains incomplete. Add the required template sections, provide a demo video, complete and report testing, and confirm checklist and review-bot requirements.
Cmux Swift Actor Isolation ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Swift Blocking Runtime ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Browser Automation Off-Main ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Expensive Synchronous Load ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Cache Substitution Correctness ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux No Hacky Sleeps ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Algorithmic Complexity ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Swift Concurrency ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Swift @Concurrent ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Swift Package Boundaries ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Swiftpm Lockfiles ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Swift Logging ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux User-Facing Error Privacy ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Full Internationalization ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Swiftui State Layout ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Architecture Rethink ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Swift Auxiliary Window Close Shortcuts ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux Source Artifacts ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux No Test Or Debug Seam In Production Source ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Cmux No Ambient Global State ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the iOS keyboard-focus fix after photo-picker use, which matches the primary change.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-ios-photo-picker-focus

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@azooz2003-bit
azooz2003-bit merged commit b2db1c4 into main Aug 1, 2026
6 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.

1 participant