Skip to content

fix(mobile): Android composer picker scrolls past the first four rows - #15856

Merged
shivamhwp merged 6 commits into
mainfrom
t3code/android-file-picker-scroll
Oct 7, 2026
Merged

shivamhwp merged 6 commits into
mainfrom
t3code/android-file-picker-scroll

Conversation

@shivamhwp

@shivamhwp shivamhwp commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

On Android, the composer pickers in an open thread (@ files, $ skills, / commands, #) showed four rows and wouldn't scroll, so anything past the fourth result was unreachable. Taps worked. Swipes went to the chat behind the picker instead.

The picker hung above the composer with absolute bottom-full, outside its parent's bounds. Android only sends drags to views inside their parent's bounds, so the picker's list never got the swipe.

On Android the picker now renders into ComposerPopoverHost, a full-size layer inside the composer's KeyboardStickyView. That layer covers the picker, so Android delivers its swipes, and it moves with the keyboard, so the picker stays right above the composer without any keyboard timing. The anchor re-measures the composer's resting position with measureLayout against the host after each composer render, and when the composer or the host resizes. iOS keeps the old wrapper.

Testing

Xiaomi POCO M3 Pro, Android 13, dev build of this branch on current main. Same steps in both videos: type $, swipe up three times inside the skills list, swipe down twice, close the keyboard, swipe once more.

Before: the list stays on babysit-pr, the chat behind it scrolls After: the list scrolls to test-t3-app and back, and still scrolls with the keyboard closed
Before: skills list does not scroll After: skills list scrolls
Full video Full video

The before video runs the old wrapper on the same build. I confirmed which code was live from the view tree each time: the old wrapper squeezes the list into a 22px strip inside the composer, and the fix gives it its full height. Mobile typecheck and lint on the changed files pass. iOS isn't tested since that path is unchanged.

A pending question card or a failed-creation card replaces the composer with display: "none". The picker now lives outside the composer, so the host also hides it on that same condition. I checked this on the phone with a temporary, uncommitted timer that flips that state while the picker is open:

Without the host check: the composer hides, the picker stays floating With it: the picker hides with the composer
Picker floating with composer hidden Picker hidden with composer

Closes #15658

🤖 Generated with Claude Code

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Oct 5, 2026
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Oct 5, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This Android fix introduces new popover hosting, coordinate measurement, and composer-layout behavior across multiple production components. An unresolved Medium-severity finding concerns stale picker visibility and interaction when the composer is hidden, so the change needs human review.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

@shivamhwp shivamhwp changed the title fix(mobile): Android composer picker scrolls again fix(mobile): Android composer picker scrolls past the first four rows Oct 5, 2026
@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 4.9 KiB 4.9 KiB 0 B (0.0%) 6.8 KiB ✅
Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 20.8 KiB 20.8 KiB 0 B (0.0%) 29.3 KiB ✅
Codex Live turn messages 1 1 0 (0.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB −41 B (−0.8%) 6.8 KiB ✅
Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB −41 B (−3.3%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 21.2 KiB 21.2 KiB −41 B (−0.2%) 29.3 KiB ✅
Claude Live turn messages 2 1 −1 (−50.0%) 8 ✅

Baseline: 250e052 · PR result: 3bebf4b · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@juliusmarminge juliusmarminge added the macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews label Oct 5, 2026
@macroscopeapp
macroscopeapp Bot dismissed their stale review October 5, 2026 02:51

Dismissing prior approval to re-evaluate b85d6d1

macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Oct 5, 2026
@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: pingdotgg/t3code/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a40c9059-195f-4d10-9cc8-95c0bb7eb842
📥 Commits

Reviewing files that changed from the base of the PR and between d7c8378 and bd654f7.

📒 Files selected for processing (3)
  • apps/mobile/src/features/threads/ComposerPopoverAnchor.android.tsx
  • apps/mobile/src/features/threads/ComposerPopoverHost.tsx
  • apps/mobile/src/features/threads/ThreadDetailScreen.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 5 remain after this review.


📝 Walkthrough

Walkthrough

The change adds a host for composer popover content and an anchor for positioning it. ThreadDetailScreen provides the host, and ThreadComposer uses the anchor for ComposerCommandPopover. On Android, the anchor measures its position relative to the host and updates the popover position.

Changes

Composer popover hosting and anchoring

Layer / File(s) Summary
:--- :---
Host context and screen wiring
apps/mobile/src/features/threads/ComposerPopoverHost.tsx, apps/mobile/src/features/threads/ThreadDetailScreen.tsx
ComposerPopoverHost provides a host view, content setter, and layout version through context. ThreadDetailScreen wraps its existing floating composer overlay in the host.
Anchor positioning
apps/mobile/src/features/threads/ComposerPopoverAnchor.tsx, apps/mobile/src/features/threads/ComposerPopoverAnchor.android.tsx
The shared anchor renders children above the composer. On Android, it measures its position relative to the host, updates host content with the measured position, and clears that content on unmount.
ThreadComposer integration
apps/mobile/src/features/threads/ThreadComposer.tsx
ThreadComposer wraps ComposerCommandPopover in ComposerPopoverAnchor instead of an absolute bottom-aligned View.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to bd654

No actionable issue remains before merge under normal checks. Android gesture delivery has not been independently verified at runtime.

Security Architecture Review

Security architecture risk: ⚪ Minimal · up to bd654

The change relocates the Android picker without changing command-selection permissions or thread binding. Each screen owns its picker state, and closing the picker clears the hosted content. No material security risk was identified in this change.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The introduced mutable projection is scoped to a host instance in the thread screen. The current topology has one anchor under each host, so separate screen instances do not share the projection slot.

Trust Boundaries and Controls

  • observed — Picker visibility and selection remain controlled by ThreadComposer’s existing menu. Its menu retains owner, environment, and current-thread inputs; ThreadDetailScreen continues passing the same thread/environment props. The host relocation does not add a command handler or permission bypass in this flow.

Resilience and Maintainability Implications

  • inferred — Closing or unmounting the anchor clears hosted content. A late measurement callback updates only the originating anchor’s local state and cannot directly republish into the host after unmount. The setter has no owner token, but the inspected single-writer topology does not exercise competing-owner cleanup.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Issue #15658 requires the Android picker in an open thread to scroll beyond the visible rows. ThreadComposer now uses ComposerPopoverAnchor; on Android, the anchor renders the picker in `ComposerP…
Out of Scope Changes check ✅ Passed The host, anchor, and ThreadDetailScreen wrapper support the Android picker fix in issue #15658. The shared picker includes the @, $, /, and # entries identified in the issue. The iOS fallba…
Title check ✅ Passed The title clearly and concisely describes the Android composer picker scrolling fix.
Description check ✅ Passed The description clearly explains the problem, implementation, affected pickers, verification steps, test environment, screenshots, recordings, and limitations. It links issue #15658, but it does not e…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@macroscopeapp
macroscopeapp Bot dismissed their stale review October 5, 2026 03:07

Dismissing prior approval to re-evaluate 9e603f9

@github-actions github-actions Bot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Oct 5, 2026
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Oct 5, 2026
@macroscopeapp
macroscopeapp Bot dismissed their stale review October 5, 2026 03:11

Dismissing prior approval to re-evaluate 80e96b6

macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Oct 5, 2026
@macroscopeapp
macroscopeapp Bot dismissed their stale review October 5, 2026 03:41

Dismissing prior approval to re-evaluate d7c8378

@shivamhwp
shivamhwp force-pushed the t3code/android-file-picker-scroll branch from d7c8378 to bd654f7 Compare October 5, 2026 03:55
shivamhwp and others added 5 commits October 7, 2026 08:30
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e keyboard settles

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

The overlay portal sat outside the keyboard transform, so the picker had to be
re-measured on keyboard events and landed in the wrong place. Render it into a
full-size host inside the composer's KeyboardStickyView instead, which moves
with the keyboard and still covers the picker so Android delivers its scrolls.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@shivamhwp
shivamhwp force-pushed the t3code/android-file-picker-scroll branch from bd654f7 to 375a54d Compare October 7, 2026 08:35
// re-project after every render.
useEffect(() => {
measure();
host?.setContent(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium threads/ComposerPopoverAnchor.android.tsx:40

When ThreadDetailScreen hides the composer with display: "none", an already-open picker remains visible and interactive over the questionnaire or failure UI. This effect keeps setting the picker on ComposerPopoverHost, which is outside the hidden subtree; clear or suppress the host content when the composer is hidden.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/mobile/src/features/threads/ComposerPopoverAnchor.android.tsx around line 40:

When `ThreadDetailScreen` hides the composer with `display: "none"`, an already-open picker remains visible and interactive over the questionnaire or failure UI. This effect keeps setting the picker on `ComposerPopoverHost`, which is outside the hidden subtree; clear or suppress the host content when the composer is hidden.

A pending question or a failed creation hides the composer with display none.
The picker now lives outside the composer's subtree, so it stayed on screen.
The host hides its popovers on the same condition.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@shivamhwp
shivamhwp merged commit 8a92ebe into main Oct 7, 2026
30 checks passed
@shivamhwp
shivamhwp deleted the t3code/android-file-picker-scroll branch October 7, 2026 20:34
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Oct 8, 2026
## What's Changed
* feat(models): add Claude Haiku 5.5 and retire Sonnet 5 and Opus 5 to legacy by @juliusmarminge in pingdotgg/t3code#16903
* fix(web): iPhone Duo folds animate, center on the hinge, and keep the phone's orientation by @gabrielelpidio in pingdotgg/t3code#16885
* fix(server): Claude 5-series models always run 1M context by @juliusmarminge in pingdotgg/t3code#16908
* fix(desktop): setup prompts name a t3 that runs on desktop installs by @juliusmarminge in pingdotgg/t3code#16676
* feat(desktop): install the t3 command from Settings by @juliusmarminge in pingdotgg/t3code#16683
* fix(web): show live names in thread-read activity by @Bil0000 in pingdotgg/t3code#13140
* feat(mobile): adopt v5 navigation and native iPad columns by @juliusmarminge in pingdotgg/t3code#16733
* fix(mobile): Android composer picker scrolls past the first four rows by @shivamhwp in pingdotgg/t3code#15856
* fix(desktop): sign-in and captchas work again in desktop browser tabs by @juliusmarminge in pingdotgg/t3code#16939
* fix(server): missing project folders no longer log favicon warnings by @yordis in pingdotgg/t3code#16757
* fix(server): unload Codex threads left idle on the shared app-server by @RhysSullivan in pingdotgg/t3code#16917
* fix(web): fast typing no longer scrambles text when type-to-focus kicks in by @otavio in pingdotgg/t3code#14595
* fix(web): simplify workspace card rows by @Bil0000 in pingdotgg/t3code#16823
* fix(web): Copy MCP URL shows up for environments reached over plain http by @SunkenInTime in pingdotgg/t3code#16909
* fix(web): C#, Java, PHP and 11 other languages get file icons by @juliusmarminge in pingdotgg/t3code#16974
* feat(clients): live row shows the agent's latest thought by @t3dotgg in pingdotgg/t3code#16284
* feat(web): block-level Markdown in the rich text composer by @chrisdeeming in pingdotgg/t3code#14677
* fix(web): center project monograms in settled rows by @Aforno in pingdotgg/t3code#16841
* fix(web): cancelling a new citation no longer leaves a stray space by @Aforno in pingdotgg/t3code#16828
* fix(settings): provider updates show live progress instead of a bare spinner by @shivamhwp in pingdotgg/t3code#16958
* feat(web): find in diffs with Cmd+F by @juliusmarminge in pingdotgg/t3code#14623
* refactor(server): GitHub services are named for the API they call, not gh by @juliusmarminge in pingdotgg/t3code#16967
* refactor(server): GitHub GraphQL batches use variables and share one pager by @juliusmarminge in pingdotgg/t3code#16960
* refactor(server): GitHub source control reads GitHubApi directly by @juliusmarminge in pingdotgg/t3code#16982
* refactor(server): GitHub rate limits read the response headers by @juliusmarminge in pingdotgg/t3code#16986

## New Contributors
* @RhysSullivan made their first contribution in pingdotgg/t3code#16917
* @Aforno made their first contribution in pingdotgg/t3code#16841

**Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261007.2787...v0.0.46-nightly.20261008.2801

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261008.2801
github-actions Bot added a commit to davidvanderklay/t3code-flake that referenced this pull request Oct 8, 2026
## What's Changed
* feat(models): add Claude Haiku 5.5 and retire Sonnet 5 and Opus 5 to legacy by @juliusmarminge in pingdotgg/t3code#16903
* fix(web): iPhone Duo folds animate, center on the hinge, and keep the phone's orientation by @gabrielelpidio in pingdotgg/t3code#16885
* fix(server): Claude 5-series models always run 1M context by @juliusmarminge in pingdotgg/t3code#16908
* fix(desktop): setup prompts name a t3 that runs on desktop installs by @juliusmarminge in pingdotgg/t3code#16676
* feat(desktop): install the t3 command from Settings by @juliusmarminge in pingdotgg/t3code#16683
* fix(web): show live names in thread-read activity by @Bil0000 in pingdotgg/t3code#13140
* feat(mobile): adopt v5 navigation and native iPad columns by @juliusmarminge in pingdotgg/t3code#16733
* fix(mobile): Android composer picker scrolls past the first four rows by @shivamhwp in pingdotgg/t3code#15856
* fix(desktop): sign-in and captchas work again in desktop browser tabs by @juliusmarminge in pingdotgg/t3code#16939
* fix(server): missing project folders no longer log favicon warnings by @yordis in pingdotgg/t3code#16757
* fix(server): unload Codex threads left idle on the shared app-server by @RhysSullivan in pingdotgg/t3code#16917
* fix(web): fast typing no longer scrambles text when type-to-focus kicks in by @otavio in pingdotgg/t3code#14595
* fix(web): simplify workspace card rows by @Bil0000 in pingdotgg/t3code#16823
* fix(web): Copy MCP URL shows up for environments reached over plain http by @SunkenInTime in pingdotgg/t3code#16909
* fix(web): C#, Java, PHP and 11 other languages get file icons by @juliusmarminge in pingdotgg/t3code#16974
* feat(clients): live row shows the agent's latest thought by @t3dotgg in pingdotgg/t3code#16284
* feat(web): block-level Markdown in the rich text composer by @chrisdeeming in pingdotgg/t3code#14677
* fix(web): center project monograms in settled rows by @Aforno in pingdotgg/t3code#16841
* fix(web): cancelling a new citation no longer leaves a stray space by @Aforno in pingdotgg/t3code#16828
* fix(settings): provider updates show live progress instead of a bare spinner by @shivamhwp in pingdotgg/t3code#16958
* feat(web): find in diffs with Cmd+F by @juliusmarminge in pingdotgg/t3code#14623
* refactor(server): GitHub services are named for the API they call, not gh by @juliusmarminge in pingdotgg/t3code#16967
* refactor(server): GitHub GraphQL batches use variables and share one pager by @juliusmarminge in pingdotgg/t3code#16960
* refactor(server): GitHub source control reads GitHubApi directly by @juliusmarminge in pingdotgg/t3code#16982
* refactor(server): GitHub rate limits read the response headers by @juliusmarminge in pingdotgg/t3code#16986

## New Contributors
* @RhysSullivan made their first contribution in pingdotgg/t3code#16917
* @Aforno made their first contribution in pingdotgg/t3code#16841

**Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261007.2787...v0.0.46-nightly.20261008.2801

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261008.2801
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Android: composer @ picker cannot be scrolled, so results past the fourth are unreachable

2 participants