Skip to content

feat(app): Mobile Touch Optimization#18767

Open
noahbentusi wants to merge 80 commits intoanomalyco:betafrom
noahbentusi:yjh/dev
Open

feat(app): Mobile Touch Optimization#18767
noahbentusi wants to merge 80 commits intoanomalyco:betafrom
noahbentusi:yjh/dev

Conversation

@noahbentusi
Copy link
Copy Markdown

@noahbentusi noahbentusi commented Mar 23, 2026

Issue for this PR

Closes #

Type of change

  • New feature
  • Bug fix
  • Refactor / code improvement
  • Documentation

What does this PR do?

This PR optimizes the OpenCode App for mobile/touch devices while preserving the existing desktop experience. It addresses 5 key pain points for mobile users:

  1. Toolbar Overflow - Hidden toolbar buttons are now accessible via an overflow menu on narrow screens
  2. Mobile Panel Fullscreen - Side panels (file tree, review) display fullscreen on mobile instead of split view
  3. Selection Comment - Touch and mouse users can select code and add comments via a floating "+" button
  4. Long-Press File Menu - Touch users can long-press files to add them to the conversation context
  5. Markdown Render Toggle - Markdown files can switch between rendered and source views

The changes include:

  • Toolbar overflow menu with "⋯" button for hidden options on screens < 768px
  • Mobile fullscreen panel layout for file tree and review panels
  • Floating selection toolbar with "+" button for adding comments to selected code
  • Long-press context menu for file items to add to conversation
  • Markdown render/source toggle functionality
  • Back to chat navigation button on mobile toolbar

These improvements enhance mobile usability by making touch interactions more intuitive and preserving the desktop experience for larger screens.

How did you verify your code works?

All features tested on mobile viewport (720×1920):

  • Overflow menu shows hidden toolbar options
  • Back to chat button returns to chat view
  • File tree panel opens fullscreen
  • Clicking file shows content in panel
  • Selecting code shows "+" button
  • Clicking "+" opens comment dialog
  • Long-press/right-click on file shows context menu
  • Desktop mode (>768px) remains unaffected

Screenshots / recordings

Mobile toolbar with overflow menu and back button visible. File tree in fullscreen mode with file content displayed.

图片 图片 图片 图片 图片 图片

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

MakonnenMak and others added 30 commits February 20, 2026 13:20
…t and message rendering

When the client clock is ahead of the server, user message IDs (generated
client-side) sort after assistant message IDs (generated server-side).
This broke the prompt loop exit check and the UI message pairing logic.

- Extract shouldExitLoop() into a pure function that uses parentID matching
  instead of relying on ID ordering
- Extract findAssistantMessages() with forward+backward scan to handle
  messages sorted out of expected order due to clock skew
- Remove debug console.log statements added during investigation
- Add tests for both extracted functions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…t-loop-exit

# Conflicts:
#	packages/ui/src/components/session-turn.tsx
…t-loop-exit

# Conflicts:
#	packages/ui/src/components/session-turn.tsx
…lers

Use Node's createServer for MCP OAuth callback and Codex plugin OAuth
servers instead of Bun.serve, making them work under Node.js.
Use npm-install:${pkg} instead of a global npm-install lock so
concurrent installs of different packages can run in parallel.
When the lockfile exists but .bin is empty or absent, add() would
read the lockfile via loadVirtual() and return early without calling
reify(). Delete the lockfile before calling add() so it proceeds
with a full install.
Replace tsx dependency with explicit 'node' invocation for the
compiled ESLint server. Remove all BUN_BE_BUN env var references
which are no longer needed after the Bun-to-Node migration.
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Npm.which now returns undefined instead of throwing when binary not found.
Update all callers to check for undefined and return early.
Avoid explicit union types by using a resolved variable pattern.
This restores the SIGHUP handler that was previously reverted. The handler ensures the process exits on terminal hangup (eg. closing the terminal tab), preventing long-running commands like `serve` from becoming orphaned processes.
- Replace manual subscription Map with PubSub.unbounded per instance
- Per-type PubSubs + wildcard PubSub, cleaned up via addFinalizer
- InstanceDisposed published before PubSub shutdown so subscribers see it
- Add makeRuntime to run-service.ts (single runtime with runPromise + runFork)
- Legacy facade preserved: publish/subscribe/subscribeAll same signatures
- subscribe/subscribeAll fork stream consumer fibers, return interrupt function
- Extract Format.file() for explicit formatting, remove event-driven subscription
- Inline Format.file() calls in write/edit/apply_patch tools
- Drop Bus.once (zero callers)
- Keep makeRunPromise as deprecated wrapper for existing services
- Replace manual subscription Map with PubSub.unbounded per instance
- Per-type PubSubs + wildcard PubSub, cleaned up via addFinalizer
- InstanceDisposed published before PubSub shutdown so subscribers see it
- Replace makeRunPromise with makeRuntime (single runtime with runPromise + runFork)
- Update all 19 services to use makeRuntime destructuring
- Legacy facade preserved: publish/subscribe/subscribeAll same signatures
- subscribe/subscribeAll fork stream consumer fibers, return interrupt function
- Extract Format.file() for explicit formatting, remove event-driven subscription
- Inline Format.file() calls in write/edit/apply_patch tools
- Drop Bus.once (zero callers)
- Add runCallback to makeRuntime (returns interrupt function directly)
- Simplify forkStream to use runCallback instead of runFork + Fiber.interrupt
- Add 6 bus tests covering publish/subscribe, unsubscribe, subscribeAll,
  and InstanceDisposed delivery on instance disposal
- Plugin: use bus.subscribeAll() Stream + forkScoped instead of callback facade
- Vcs: use bus.subscribe() Stream + forkScoped instead of acquireRelease callback
- Status: use bus.publish() Effect directly instead of Effect.promise wrapper
- Rewrite Vcs test to use facade functions (shared memoMap ensures singleton Bus)
- Add Bus integration tests for subscribe cleanup and instance disposal
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.

5 participants