Skip to content

feat(mobile): hardware keyboard send and recent chats on the app icon - #2380

Merged
DoodleBears merged 9 commits into
mainfrom
claude/ios-qol-pull-to-compose-t1kgmy
Oct 20, 2026
Merged

DoodleBears merged 9 commits into
mainfrom
claude/ios-qol-pull-to-compose-t1kgmy

Conversation

@DoodleBears

@DoodleBears DoodleBears commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Vain · project thread

Before: with a hardware keyboard (iPad, or an Android phone with a keyboard paired), sending meant tapping the send button on screen, and on Android Enter only added a new line. Long-pressing the app icon showed only the system items.

After:

  1. Hardware keyboard send. On iPhone and iPad, ⌘↩ sends the draft, and it shows as "Send" in the overlay you get by holding ⌘. On Android, Enter sends, Shift+Enter adds a new line, and Ctrl+Enter also sends. In the full-screen draft editor, plain Enter adds a new line, and only ⌘↩ or Ctrl+Enter sends. The on-screen keyboard works as before. Nothing sends while the draft is empty or dictation is running.
  2. Recent chats on the app icon. Long-pressing the app icon lists the three chats you opened most recently, newest first. These are Home Screen quick actions on iOS and app shortcuts on Android. Tapping one opens that chat on its Host, including when the app was closed.

These are the next native QoL items Vain approved after #2364. Share-to-Bot comes in its own PR.

How:

  • (1) A new local Expo module, modules/hardware-send, wraps the composer field.
    • On iOS, the view returns a UIKeyCommand for ⌘↩ from keyCommands. UIKit collects key commands along the responder chain, so the shortcut works only while the field inside is focused.
    • On Android, the view intercepts dispatchKeyEvent before the focused EditText gets it. It ignores events that come from the on-screen keyboard or from a virtual device.
    • Builds without the module fall back to a plain View.
  • (2) expo-quick-actions (6.0.2) sets the dynamic shortcut items.
    • The conversation screen records each chat it opens through a mount ref callback. It keeps the list in SecureStore, next to the saved Hosts, and calls setItems only when the list changes.
    • The tab shell routes a tapped shortcut. It opens only in-app paths, and it waits until the saved Host has loaded, the same way push routing waits.
    • Under the UIScene life cycle, Expo forwards a launch shortcut as a performActionFor event before any JS listener exists. The library filled initial only from launchOptions, so a cold-start shortcut was dropped. A small pnpm patch keeps the first unobserved shortcut as initial.
  • This PR also carries a one-line fix for red main: release-notes-view.tsx now gets its tooltip from the shared ds/tooltip wrapper (from fix(release): upgrade in place when DSH refuses an installed deepseekbot, and simplify the update notice #2382 against feat(client): show panel header action tooltips instantly #2386). The fix does nothing once main has it.

Screenshots (iOS Simulator)

Light Dark
<img src="https://raw.githubusercontent.com/BotHarness/DeepSeekBot/2d2f47c5999aa414af684c09daa6f928f7ffa8bb/.github/pr-screenshots/2380-hardware-send/2380-quick-actions-light.png" width="240"> <img src="https://raw.githubusercontent.com/BotHarness/DeepSeekBot/2d2f47c5999aa414af684c09daa6f928f7ffa8bb/.github/pr-screenshots/2380-hardware-send/2380-quick-actions-dark.png" width="240">

Notes

  • Needs a native rebuild. Both items add native code, so an OTA update alone does not install them.
  • Android shortcuts have no custom icon for now, so the launcher shows the app's own badge.
  • Verification:
    • pnpm lint, pnpm format:check, root and mobile tsc, and the mobile vitest suite pass.
    • New tests cover the recent-chat list, shortcut routing (including waiting at cold start), and the Android key rules (HardwareSendTest, run by the Android native module job).
    • On the iOS Simulator, the shortcut list and a warm tap pass.
    • Merged at Vain's call before the remaining device checks: the cold-start re-check on the patched build, ⌘↩, and Android hardware Enter. Those results will follow in the thread.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TYsJ1DZQ7Vd8sKVs6MMhdF

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsJ1DZQ7Vd8sKVs6MMhdF
@coderabbitai

coderabbitai Bot commented Oct 20, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

claude and others added 6 commits October 20, 2026 08:26
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsJ1DZQ7Vd8sKVs6MMhdF
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsJ1DZQ7Vd8sKVs6MMhdF
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A shortcut tapped while the app was closed fired before the navigator and
Host session were ready, so the app stayed on Chats. Hold it until the
saved Host has loaded, as push routing does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsJ1DZQ7Vd8sKVs6MMhdF
main is red: #2382 added a direct primitives Tooltip import after #2386
required every tooltip to use ds/tooltip. No-ops once main carries the
same fix.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsJ1DZQ7Vd8sKVs6MMhdF

Copy link
Copy Markdown
Contributor Author

test (shard 1) failed on 97cbd80 in packages/client/test/header-tooltips.test.tsx. The cause isn't in this PR. On main, #2382 added a direct primitives Tooltip import in release-notes-view.tsx after #2386 had required every tooltip to go through ds/tooltip, so main fails the same test. No fix PR existed, so 81a1084 merges main and moves that import onto the shared wrapper. That change does nothing once main has the same fix.


Generated by Claude Code

DoodleBears and others added 2 commits October 20, 2026 19:20
…2380

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Under the scene life cycle Expo forwards the launch shortcut as a
performActionFor event before any JS listener exists, and
expo-quick-actions only read launchOptions, so QuickActions.initial was
empty and the app stayed on Chats. Patch it to keep the first unobserved
shortcut as the initial action.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsJ1DZQ7Vd8sKVs6MMhdF
@DoodleBears
DoodleBears marked this pull request as ready for review October 20, 2026 10:40
@DoodleBears
DoodleBears merged commit d220792 into main Oct 20, 2026
13 checks passed
DoodleBears added a commit that referenced this pull request Oct 20, 2026
…nshots

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor Author

Android phone result: FAIL on hardware Enter with the default IME; shortcuts PASS (Xiaomi, Android 16 / HyperOS 3, isolated QA Host, deepseek-v4.1-flash), release build of main

Screenshots: 2380-android-keyboard/phone (commit 2b8b398)

Scene Files
Hardware keyboard in composer / full-screen draft kb-composer-enter-light.png, kb-draft-ctrlenter-light.png, kb-draft-wetype-pinyin-light.png
On-screen keyboard Enter still adds a line onscreen-enter-light.png
App icon long-press lists recent chats app-icon-shortcuts-{light,dark}.png
Shortcut opens the chat, cold start included shortcut-opens-{mira,nova}-*.png, coldstart-opens-mira-light.png

Finding 1 (blocking for the feature): with the phone's default IME (WeChat keyboard / WeType), a physical keyboard's Enter and Ctrl+Enter only insert a newline in both the composer and the full-screen draft. The IME consumes the key and re-emits it as its own event, so the native check treats it as an on-screen key and lets it through. Tested with a temporary HID keyboard (removed afterwards); other IMEs not tried.

Finding 2: the shortcuts use the default Android placeholder icon, not the Bot avatar.

Shortcut order (Mira, Nova, QA Lounge) matched recency, and both warm and cold start open the right chat.


Generated by Claude Code

DoodleBears added a commit that referenced this pull request Oct 21, 2026
…#2401 (#2422)

* fix(mobile): Android hardware Enter with WeType, attachment ✕, flick-up and shortcut icons

- Treat an input-method Enter that echoes a hardware Enter as that key, so
  Enter and Ctrl+Enter send with WeType and similar input methods.
- Stop the hidden measuring text in the composer from taking taps meant for
  the attachment ✕ and the mention list.
- Lower the Android flick-up speed to 0.3 dp/ms.
- Use the launcher icon for Android app shortcuts, which cannot draw SF Symbols.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsJ1DZQ7Vd8sKVs6MMhdF

* docs(changes): link #2422

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsJ1DZQ7Vd8sKVs6MMhdF

* fix(ci): keep the recent-chats test out of the root typecheck

recent-chats.ts now imports react-native, whose timer globals clash with
Node's in the root program, like the other excluded mobile tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsJ1DZQ7Vd8sKVs6MMhdF

* fix(mobile): show shared image thumbnails and hide the keyboard on Send to

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsJ1DZQ7Vd8sKVs6MMhdF

* fix(mobile): send when an input method types the newline for a hardware Enter

WeType on HyperOS types a newline into the field instead of sending the Enter
key again. The view now watches the focused field and turns a newline typed
within 500 ms of a sending hardware Enter into a send. Also recheck the
clipboard once Android gives the window focus back, and name shared files
that arrive as bare media ids after their type.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsJ1DZQ7Vd8sKVs6MMhdF

* fix(mobile): keep the keyboard down while Send to is open

Android can bring the keyboard back for the chat underneath after the share
sheet opens. Hide it again whenever it shows or the app becomes active.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsJ1DZQ7Vd8sKVs6MMhdF

---------

Co-authored-by: Claude <noreply@anthropic.com>
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