Skip to content

Polish mobile timeline navigation - #5874

Merged
klopez4212 merged 8 commits into
mainfrom
kennylopez-mobile-timeline-navigation
Aug 18, 2026
Merged

Polish mobile timeline navigation#5874
klopez4212 merged 8 commits into
mainfrom
kennylopez-mobile-timeline-navigation

Conversation

@klopez4212

@klopez4212 klopez4212 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add sticky date headers that crossfade with in-timeline dates
  • replace the Latest pill with a centered down-arrow control
  • animate the control out from its bottom-center anchor
2AF1BB3F-B295-4084-8A65-90AED60B58B5

Validation

  • bin/just mobile-check
  • bin/just mobile-test (1,359 tests)
  • Android debug and signed iOS release builds

@klopez4212
klopez4212 marked this pull request as ready for review August 14, 2026 15:25
@klopez4212
klopez4212 requested a review from a team as a code owner August 14, 2026 15:25

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 859f538e91

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread mobile/lib/features/channels/channel_detail_page/message_list.dart

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b06a626b30

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread mobile/ios/Runner/JumpToLatestGlassButton.swift

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b8b892201e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread mobile/lib/features/channels/channel_detail_page/message_list.dart

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Blocking at exact head bd47a715a80c23bf07f212289561b790caafa657:

The PR's own regression test keeps follow mode off while a tall newest message stays visible fails deterministically, both in just mobile-test (+1360 -1) and alone:

. ./bin/activate-hermit
cd mobile
flutter test test/features/channels/channel_detail_page_test.dart \
  --plain-name 'keeps follow mode off while a tall newest message stays visible'

After the user detaches a tall newest row and a live message arrives, item 0 is no longer at the reversed-list boundary, but channel-jump-to-latest remains absent (channel_detail_page_test.dart:2853-2863). The visibility decision at message_list.dart:370-395 depends on distanceFromLatest; that value is refreshed only by a depth-0 ScrollNotification at lines 617-627, not by the post-insert positions transition. Consequently the newly unseen message can have no jump affordance.

Please recompute the post-insert tail state from settled positions/layout (or otherwise remove the stale-metric dependency), retain this regression row, and rerun the full Mobile package gate.

Other exact-head evidence: just mobile-check passes; iOS 26.5 simulator debug build/install/launch of the new Swift platform views was independently confirmed. GitHub Mobile is green, but does not override the deterministic local failure of a test added by this PR.

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: kenny lopez <klopez4212@gmail.com>
Signed-off-by: kenny lopez <klopez4212@gmail.com>
@klopez4212
klopez4212 force-pushed the kennylopez-mobile-timeline-navigation branch from bd47a71 to 6fe81cf Compare August 14, 2026 18:14
Co-authored-by: Kenny Lopez <klopez4212@gmail.com>
Signed-off-by: Kenny Lopez <klopez4212@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fbd9f56f49

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread mobile/lib/features/channels/jump_to_latest_button.dart Outdated
Comment thread mobile/lib/features/channels/channel_detail_page/message_list.dart

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Verdict: COMMENT — prior blocker resolved; native acceptance remains unproven

Reviewed: 69107dc3bfecbb80cc5f5b8bb6a7647ad054ce57..fbd9f56f494e2b54f9a2fb5f327a770e201b3f7a (live PR head rechecked immediately before submission)

Risk: high. This changes virtualized timeline tail/follow state and introduces iOS platform views for user-visible navigation controls.

The deterministic blocker from my review at bd47a715... is resolved at this head: keeps follow mode off while a tall newest message stays visible now passes, and the full Mobile package suite is green.

I am not converting that into native sign-off. The remaining contract is sensitive to layout-only state changes: updateJumpToLatestVisibility reads composerBottomInset when calculating visible page height (mobile/lib/features/channels/channel_detail_page/message_list.dart:406-430), while its positions-listener effect is keyed at :461-519; the explicit dock/keyboard layout effect at :528-534 only realigns when following latest. Placement itself is declarative (:863-895), but the requested detached journey still needs to prove visibility and alignment across multiline composer, queued attachment, keyboard, and channel typing changes without a timeline scroll.

Validation at exact clean head:

  • bin/just mobile-check — PASS; 410 files unchanged, analyze clean.
  • bin/just mobile-test — PASS; 1,422/1,422 tests.
  • GitHub Mobile and DCO checks — PASS at this head.
  • iPhone 17 Pro / iOS 26.5 native attempt: Xcode build and Flutter launch succeeded. Initial detached geometry was sane (Latest Rect(177,714,225,762), dock top 778, 16 pt gap; semantic label Jump to latest message). The journey then failed in both usable attempts because SpringBoard's badge-notification permission sheet covered Buzz and the fixture could not locate the composer. Those recordings prove launch/blocker only, not the requested transitions.

Accessibility residual: Flutter labels the wrapping semantic button (jump_to_latest_button.dart:47-67) while the native UIButton carries the same label (mobile/ios/Runner/JumpToLatestGlassButton.swift:81-88). The captured Flutter semantics showed one label but no actionable semantics; an AX/VoiceOver run is still needed to rule out duplicate or non-actionable exposure at the platform boundary.

Residual risk / next evidence: rerun the detached journey with notification permission pre-seeded or reliably suppressed, and capture the multiline + attachment + keyboard + typing transitions plus AX/VoiceOver semantics. The current source suspicion is not enough to claim a visible defect, but the blocked native run is also not acceptance evidence. Dungeon rule: an obscured control does not become verified merely because CI is cheerful.

Signed-off-by: kenny lopez <klopez4212@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e0f5e5dd0d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

),
),
),
if (!showUnreadNavigation)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep the divider visible when suppressing the sticky header

When the oldest-unread control is present and the user scrolls far enough for a day divider to become sticky, updateStickyDateHeader still publishes that day's timestamp, causing DayDivider to fade its label to zero opacity, but this condition removes the corresponding sticky header from the tree. The timeline therefore displays no date label until the unread control is dismissed; avoid marking the divider sticky while the header is suppressed, or keep an equivalent date surface visible.

Useful? React with 👍 / 👎.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

A Team re-review — prior blocker resolved

Reviewed current head e0f5e5dd0ddddccd3edef3e758c7df20e04e343f, including the delta from the prior reviewed merge head fbd9f56f494e2b54f9a2fb5f327a770e201b3f7a.

The blocking stale-inset closure is fixed: mobile/lib/features/channels/channel_detail_page/message_list.dart:516-519 now includes composerBottomInset in the positions-listener effect dependencies, so multiline drafts, attachments, and other composer-height changes recompute detached/latest visibility without waiting for an unrelated scroll event.

The remainder of the delta only converts the iOS glass widgets to Riverpod-aware hook widgets and updates their focused tests. git diff --check fbd9f56f...e0f5e5dd passes in a clean exact-head worktree. Current CI is green, including Mobile.

No new material defect found in the reviewed delta. Native iOS keyboard/animation acceptance remains residual risk; it was not rerun locally in this re-review.

@jedwards27 jedwards27 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

A Team exact-head review complete at e0f5e5d. Independent product/security and validation/integration lanes found no blocker. Focused timeline tests, full Mobile checks/tests, exact-head Android CI build, and iOS compile/XCTest passed. Residual acceptance risk: no exact-head interactive VoiceOver/TalkBack + IME/attachment journey; older recordings were not counted.

@brow

brow commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

🤖 Review note at e0f5e5dd0ddddccd3edef3e758c7df20e04e343f. Approving. One real residual and one test gap, neither blocking, both measured rather than read.

The residual: the new sticky date header is not wired into the one state where it is suppressed.

In message_list.dart the item builder passes stickyDayTimestamp to DayDivider unconditionally, while the StickyDateHeader itself sits behind if (!showUnreadNavigation). So while the oldest-unread control is on screen, a day divider that scrolls past the sticky threshold still gets told it is the sticky day, DayDivider._buildOpacity fades its label to zero, and there is no capsule in the tree to take its place. The user sees no date.

Measured on a 400x600 viewport, 3 days by 40 messages, sweeping the scroll alignment in 201 steps of roughly 3 logical pixels:

arm positions with no visible date
this head, unread control up 123 of 201
this head, no unread control 0 of 201
merge base 69107dc3bf, unread control up 109 of 201

The base column is the reason this is a note and not a blocker. The merge base already had no date at 109 of those positions, because it has no sticky mechanism at all, and this PR takes the ordinary case to zero. The genuine regression is the residue, about 14 of 201 sampled positions, of which the sub-case where a divider is physically on screen at zero opacity is a contiguous band of roughly 18 to 21 logical pixels of scroll. It clears when the scroll offset leaves the band or when the unread control goes away, so it does not need a dismissal to recover.

Codex thread 3791837261 describes that narrow mechanism accurately. Its stated consequence, no date until the unread control is dismissed, is right in kind and overstated in duration. It is still unanswered, and it is the only unresolved thread here.

The test gap, which is the part worth more than the residual.

No test in mobile/test pins the interaction between the unread control and any date surface. Two type-preserving mutants that delete the wiring entirely both survive the full 131 test channel_detail_page_test.dart: publishing a null active timestamp from updateStickyDateHeader, and forcing the sticky header to always render. day_divider_test.dart drives the widget with its own ValueNotifier, so it cannot see the message_list wiring either. Whatever you do about the residual above, the suite as it stands cannot tell you whether it worked.

Two smaller notes, no action needed:

  1. Several new rows pin implementation constants rather than the visible contract: the 180 ms and 160 ms switcher durations, the exact curves, surface.withValues(alpha: 0.72), border alpha 0.08, the 120 ms divider opacity duration and Curves.easeOutCubic, and a raw scale.value < 0.1. These will fail on a restyle that keeps the behaviour correct.
  2. StickyDateGlassHeader.swift and JumpToLatestGlassButton.swift have no RunnerTests coverage, and the Mobile CI job runs flutter test rather than RunnerTests, so the iOS 26 glass path, the pre-26 blur fallback, and the native teardown are unverified by CI and by us. Stating the bound, not asking for the tests in this PR.

I am deliberately not proposing a fix shape. We measured one candidate and it closes the narrow mechanism only while leaving the larger sub-case, so it is not a safe thing to hand over as a direction.

@klopez4212
klopez4212 merged commit 417eea2 into main Aug 18, 2026
24 checks passed
@klopez4212
klopez4212 deleted the kennylopez-mobile-timeline-navigation branch August 18, 2026 17:57
sandro-sq added a commit that referenced this pull request Aug 18, 2026
* origin/main: (78 commits)
  Polish mobile timeline navigation (#5874)
  chore(release): release Buzz Desktop version 0.5.17 (#6234)
  fix(prompt): simplify pickup follow-through (#6186)
  fix(mcp): scope todo usage (#6216)
  fix(desktop): bound remote agent mention authorization (#6224)
  fix: bump h2 for RUSTSEC-2026-0258 (#6222)
  fix(desktop): bind presence retry timers (#6213)
  ci: make file-size policy a first-class gate (#6187)
  fix(desktop): eliminate mounted-view CPU burn — compositor-safe shimmer, observer append fast path, poll-tick disk reads (#6198)
  chore(release): release Buzz Desktop version 0.5.16 (#6191)
  fix(desktop): restore release agent mentions (#6182)
  test(desktop): cover exact workflow batch limit (#6168)
  chore(release): release Buzz Desktop version 0.5.15 (#6173)
  Preserve managed agent mentions during relay errors (#6167)
  fix(workflows): preserve multi-channel listing semantics (#6009)
  Remove Startup Recovery section in base prompt (#6161)
  fix(desktop): align preview sidebar row styling (#6163)
  fix(desktop): repair dropped team membership links at boot and on edit (#5904)
  fix(cli): keep project replacement timestamps at or after wall clock (#5666)
  Remove GitHub security advisory commitment (#6144)
  ...

Signed-off-by: Alessandro Joabar <sandro@squareup.com>
tlongwell-block pushed a commit that referenced this pull request Aug 18, 2026
Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Signed-off-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>

* origin/main:
  Polish mobile timeline navigation (#5874)
  chore(release): release Buzz Desktop version 0.5.17 (#6234)
  fix(prompt): simplify pickup follow-through (#6186)
  fix(mcp): scope todo usage (#6216)
  fix(desktop): bound remote agent mention authorization (#6224)
  fix: bump h2 for RUSTSEC-2026-0258 (#6222)

Signed-off-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
wpfleger96 pushed a commit that referenced this pull request Aug 18, 2026
…c-agent-commit-identity

* origin/main:
  Polish mobile timeline navigation (#5874)
  chore(release): release Buzz Desktop version 0.5.17 (#6234)
  fix(prompt): simplify pickup follow-through (#6186)
  fix(mcp): scope todo usage (#6216)
  fix(desktop): bound remote agent mention authorization (#6224)
  fix: bump h2 for RUSTSEC-2026-0258 (#6222)
  fix(desktop): bind presence retry timers (#6213)
  ci: make file-size policy a first-class gate (#6187)
  fix(desktop): eliminate mounted-view CPU burn — compositor-safe shimmer, observer append fast path, poll-tick disk reads (#6198)
  chore(release): release Buzz Desktop version 0.5.16 (#6191)
  fix(desktop): restore release agent mentions (#6182)
  test(desktop): cover exact workflow batch limit (#6168)
  chore(release): release Buzz Desktop version 0.5.15 (#6173)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
mfethe1 pushed a commit to mfethe1/buzz that referenced this pull request Aug 18, 2026
Resolves a semantic conflict git could not see. Main renamed the
`welcomeKickoff` test fixture `bumble` -> `pollen` (block#5874's neighbourhood),
and this branch had added three assertions that still referenced `bumble`.
Neither side touched the other's lines, so the merge was textually clean and
GitHub reported MERGEABLE -- but the merged file defines `pollen` and reads
`bumble`, and the suite dies with `ReferenceError: bumble is not defined` at
welcomeKickoff.test.mjs:49.

Nothing had ever built this combination: as a fork PR it runs DCO and nothing
else, and the branch alone is self-consistent, so the break existed only in the
merge result.

The three added references now use `pollen`. The `"builtin:bumble"` runtime id
on line 34 is unchanged -- that is the harness identifier, not the fixture.

Verified in this worktree on x86_64-pc-windows-msvc:
- `pnpm test`: the welcomeKickoff ReferenceError is gone. The one remaining
  failure is `focused polling pauses on blur`, which passes 5/5 in isolation
  and lives in a file this branch does not touch.
- `pnpm check` (biome + file-size ratchet + px-text + pubkey guards): exit 0.

Signed-off-by: Michael Feth <michael@jira-flow.com>
jedwards27 pushed a commit to jedwards27/buzz that referenced this pull request Aug 18, 2026
* origin/main: (43 commits)
  perf(desktop): parallelize relay agent directory rebuild (block#6258)
  Refine the mobile emoji picker (block#5853)
  fix(desktop): exclude archived agents from nest, order regeneration (block#5905)
  Add font size and conversation density preferences (block#5644)
  fix(desktop): emit camelCase config-write payload fields (block#6062)
  fix(desktop): downscale large avatars for agent-share PNG body (block#6260)
  fix(desktop): preserve early relay auth challenges (block#3320)
  Polish mobile message actions (block#5873)
  Refine mobile pairing confirmation (block#6018)
  chore(scripts): add buzz-adopt-prod-agents.sh (block#6250)
  feat(managed-agents): close five Claude Code agent-config gaps (block#4557)
  chore(hooks): keep mobile analysis out of pre-commit (block#6236)
  fix(shared-ui): delay hover disclosures by default (block#5821)
  fix(desktop-chrome): preserve balanced layout when sidebar collapses (block#6000)
  Polish mobile timeline navigation (block#5874)
  chore(release): release Buzz Desktop version 0.5.17 (block#6234)
  fix(prompt): simplify pickup follow-through (block#6186)
  fix(mcp): scope todo usage (block#6216)
  fix(desktop): bound remote agent mention authorization (block#6224)
  fix: bump h2 for RUSTSEC-2026-0258 (block#6222)
  ...

Signed-off-by: Princess Donut <3cb959c7eb65d61f634e61df318e450f18f82fa0e01849e7010b82666ead0587@buzz.block.builderlab.xyz>

# Conflicts:
#	desktop/src/main.tsx
#	mobile/ios/Podfile.lock
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.

3 participants