fix(mobile): retain resting scroll offsets through Duo inset changes#22978

merged2
duo/safe-areas
duo/reflow
opened3d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 3d ago

A fresh PR could open underneath its header because its initial inset was zero before the column was measured. Resting lists now follow their top inset until the reader scrolls away. This layer also captures thread position around width changes.

Fresh PR positioning was verified on the folded Duo after a cold launch. The resting-offset, thread-follow and PR-tab suites passed together: 40 tests.

The thread portion is the first step. #23147 completes the anchoring, and the two should land together. Unfolding still shows brief row overlap with both; #23147 lists what remains.

Fresh PR opens below its header

Implemented with Claude Opus 5.5 in Claude Code; integrated and reviewed with GPT-6.1 in Codex.

Motion verification

Fresh, real-time 30 fps recordings from the exact commits labeled in the videos, using fingerprint-matched debug native clients. Black cards mark cuts between displays.

Before

Before — PR 22978

After

After — PR 22978

This is intermediate progress, not seamless reflow: the AFTER recording still shows earlier messages briefly flashing, overlapping rows during unfolding, and a delayed return to the reader’s line. The anchoring in #23147 is not included.

Restack

Restacked onto main a12d6ed942 on 2026-10-21. The commits are unchanged apart from lockfile peer strings, and PullRequestRouteScreen keeping main's new listRefs list ref. The recordings above show the pre-restack commits they name.

Checks

All checks passed
Synced from GitHub

Thread transfer impact

⚠️ The latest CI run did not produce a thread transfer result for 84df3e9.

This comment will update automatically after the next completed run.

Synced from GitHub

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — This PR changes scrolling behavior across several mobile screens and adds timing-sensitive feed reflow restoration around LegendList measurement, including deferred and imperative scroll operations. The added tests cover the pure anchoring and offset logic, but the production interaction paths remain sufficiently complex to merit focused review.

No code changes detected at 84df3e9. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Review in Change Stack →

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Team
  • Run ID: 1080f473-b43a-4dab-afbc-23ebe9fe356d
📥 Commits

Reviewing files that changed from the base of the PR and between 26a1604154b086a2dae6713060011e7e0165cf5d and 84df3e96d5f0fa65e3f873f5a8a6aab1d50566ac.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Team
  • Run ID: 4d038f8c-5527-4d7d-98f3-1c8218859279
📥 Commits

Reviewing files that changed from the base of the PR and between 8b4d3a4790bcae76f8ac7db24666d3dea0f8ff0e and 26a1604154b086a2dae6713060011e7e0165cf5d.

📒 Files selected for processing: 10
  • apps/mobile/src/features/home/HomeScreen.tsx
  • apps/mobile/src/features/pull-requests/PullRequestReviewersScreen.tsx
  • apps/mobile/src/features/pull-requests/PullRequestRouteScreen.tsx
  • apps/mobile/src/features/pull-requests/PullRequestsScreen.tsx
  • apps/mobile/src/features/threads/ThreadFeed.tsx
  • apps/mobile/src/features/threads/thread-feed-live-follow.test.ts
  • apps/mobile/src/features/threads/thread-feed-live-follow.ts
  • apps/mobile/src/native/useRestingTopOffset.test.tsx
  • apps/mobile/src/native/useRestingTopOffset.ts
  • apps/mobile/vite.config.ts

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

📝 Walkthrough

The mobile app adds a hook for maintaining resting top offsets in scroll views. The thread feed also captures and restores its end or visible-row position when viewport width changes cause rows to remeasure.

Changes: Resting top offset

Layer / File(s)Summary
Offset hook and validation
apps/mobile/src/native/useRestingTopOffset.ts, apps/mobile/src/native/useRestingTopOffset.test.tsx, apps/mobile/vite.config.ts
The hook manages a held top offset and forwards scroll events. Tests cover inset changes, scrolling, and restored positions.
Scroll-view adoption
apps/mobile/src/features/home/HomeScreen.tsx, apps/mobile/src/features/pull-requests/PullRequestReviewersScreen.tsx, apps/mobile/src/features/pull-requests/PullRequestRouteScreen.tsx, apps/mobile/src/features/pull-requests/PullRequestsScreen.tsx
Home and pull-request scroll views use the hook instead of fixed top-inset content offsets. The pull-request list no longer sets an initial scroll offset.

Thread-feed reflow

Layer / File(s)Summary
Reflow anchors and scroll resolution
apps/mobile/src/features/threads/thread-feed-live-follow.ts, apps/mobile/src/features/threads/thread-feed-live-follow.test.ts
New helpers represent end or visible-row anchors and calculate corrected offsets. Tests cover end-following, proportional row positions, and unavailable anchors.
Feed reflow and restoration
apps/mobile/src/features/threads/ThreadFeed.tsx
ThreadFeed captures anchors during width changes and restores them after a settling delay. User interaction and thread state changes cancel restoration.

Priority: ➖ Normal

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

Change: Bug fix

Sequence Diagram(s)

mermaid
1sequenceDiagram
2 participant ThreadFeed
3 participant resolveThreadFeedReflowAnchor
4 participant FeedList
5 participant resolveThreadFeedReflowScroll
6 ThreadFeed->>resolveThreadFeedReflowAnchor: Capture end or visible-row anchor
7 ThreadFeed->>FeedList: Update viewport width and remeasure rows
8 ThreadFeed->>resolveThreadFeedReflowScroll: Resolve anchor after settling delay
9 resolveThreadFeedReflowScroll-->>ThreadFeed: Return corrected scroll offset
10 ThreadFeed->>FeedList: Restore anchored position

Possibly related issues

  • pingdotgg/t3code#12372: The issue concerns restoring the thread viewport after content changes, which overlaps with this PR’s width-driven row remeasurement and position restoration.

Suggested reviewers: maria-rcks, t3dotgg

Merge Risk: ⚪ Minimal · up to 26a16

No actionable merge-blocking issue was identified in this change; it is ready for normal checks.

Pre-merge checks: Passed 3 · Failed 1

Failed Failed checks: 1 warning

Check nameStatusExplanationResolution
Description checkWarningThe description explains the problem, implementation, verification results, known limitations, recordings, and restack details. It does not provide the required section structure or the required scope…Organize the description under Problem, Change, Scope and approval, and Verification headings. Add the triaged bug or discussion link with explicit maintainer approval, or explain why this focused fix qualifies for an exemption. Keep the ex…
Passed Passed checks: 3 passed
Check nameStatusExplanation
Title checkPassedThe title clearly and concisely describes the main mobile change: preserving resting scroll offsets during Duo inset changes.
Linked Issues checkPassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkPassedCheck skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description explains the problem, implementation, verification results, known limitations, recordings, and restack details. It does not provide the required section structure or the required scope and approval evidence, such as a triaged issue or explicit maintainer approval.

Resolution

Organize the description under Problem, Change, Scope and approval, and Verification headings. Add the triaged bug or discussion link with explicit maintainer approval, or explain why this focused fix qualifies for an exemption. Keep the existing test results, observed limitations, screenshots, and recordings in the Verification section.

✨ Finishing Touches: 💡 1
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

Added 2 commits

  • fix(mobile): the thread feed keeps its place when its width changes84df3e9
  • fix(mobile): a fresh pull request opens below the header on the folded iPhone Duoe0152b4