Skip to content

cmux-next iPhone: reply thread line, single Chief push, swipe actions close before the sidebar - #24202

Merged
azooz2003-bit merged 13 commits into
feat-cmux-nextfrom
feat-cmux-next-ios-ui-fixes
Oct 22, 2026
Merged

azooz2003-bit merged 13 commits into
feat-cmux-nextfrom
feat-cmux-next-ios-ui-fixes

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes three user-reported UI bugs in the cmux-next iPhone app, plus the Feed swipe-button style.

1. Reply quote thread line (CmuxConversation)

Cause. MessageCellLayout started the thread line beside the quote at its vertical middle (min(quoteBodyLeading - 4, x + 14), then a curve into the avatar column at x = margin + 16). In a 1:1 chat that put a hook outside the quote's leading edge, through the quote's tail and down into a second curve under it, which is the stray "hook" in the user's screenshot.

Fix. The line's geometry moves into CmuxConversationGeometry/ConversationReplyThread (shared, unit-tested). As in Messages, the line drops from under the quoted bubble's tail (or, in a group, from the avatar column beside an incoming quote). For a reply on the other side it turns toward the reply in a short curve level with the reply's middle and ends short of it. For a reply on the same side it is a straight line that stops above the reply (or the replier's avatar). The row now keeps room for the quote's tail. The quote bubble itself is unchanged: an outlined bubble with its tail, in the colors the iMessage team measured.

Compared with Messages screenshots (How-To Geek, Gadget Hacks; Messages' line drops from under the quoted bubble and curls toward the reply), in both directions and in both modes:

iMessage reference, before, after (light)
iMessage reference, before, after (dark)
Both reply directions, before and after (light)
Both reply directions, before and after (dark)

Packages/iOS/CmuxConversation stays byte-identical to feat-imsg-parity-gui; the same commits land there too (linked below). The macOS surface (CmuxConversationMacUI) has its own thread layout in MacConversationRows and does not share this code; it already drops the line from under the quote.

2. Opening a Chief pushes twice

Cause. With the Cloud Chief ready and a Mac linked, Home pins the Cloud Chief and the Mac Chief side by side in one List row. Both pins were NavigationLink(value:). List treats the row as one cell, and a tap there activates every link in it, so the stack pushed the Cloud Chief and then the Mac Chief over it. That matches the user's recording: a push, then a second push about a second later. A minimal SwiftUI app reproduces it (two links in one List row, one tap gives depth 2):

Two-pin repro: NavigationLink pins (top) vs button pins (bottom)
Videos: before, after

Fix. The pins are plain buttons that push their own route through Home's open handler. Update: #24170 (Home parity) landed first and rebuilt Home with button rows and tiles, which carries the same fix, so after the merge this PR's ConversationsHome.swift matches the base. This PR keeps ChiefPinPushTests as the regression guard (it passes on the merged head).

3. Swipe actions vs the hamburger drawer

Cause. The drawer's pan began for any rightward pan on a tab root, including one over a row whose trailing actions were open (Workspaces, Home, Settings > Devices and the other Lists). The Feed's custom rows already closed first.

Fix. As in Mail and Messages, while a row's actions are open, a rightward swipe closes them and never opens the drawer; the next one does. RowSwipeActions (CmuxMobileDesign) tells the drawer about open rows. List rows are read at touch-down, because UIKit starts closing the row as the finger lands. An open row is a cell slid off the leading edge its siblings share (SwiftUI's List slides the layout attributes with it, and UIKit leaves its actions view in place after closing). Feed rows report their open state and name their pan, and the drawer waits for that pan.

Home before: the drawer opens over open actions
Home after: first swipe closes, second opens the drawer
Workspaces before
Workspaces after
Videos: Home before, Home after, Workspaces before, Workspaces after, Feed before, Feed after

Feed swipe buttons. The Feed drew its own full-height rectangles. It now uses RowSwipeActionButton, the same tinted capsules with captions that List's swipe actions draw on Workspaces and Home (measured on iOS 26.5: 66 x 50 pt, 12 pt apart, 10 pt from the edge). Its actions, haptic, full swipe and close-first rule are unchanged. The swipe row is not in CmuxTabsKit, so feat-cmux-next-tabs-kit needs no change.

Feed before, Feed after, Workspaces for comparison

Tests (red on base, green on head)

Bug Command (fleet: mini-cmux8s for the iOS simulator, mini-cmux11s and mini-cmux8s for swift test) Base Head
1 swift test --filter ConversationReplyThreadTests (Packages/iOS/CmuxConversation) 6 tests, 13 issues at d4111bf 6 pass; all 255 CmuxConversationGeometryTests pass
2 cmux_mobile_kit-test-ios.sh CmuxMobileChiefTests/ChiefPinPushTests fails: one tap pushed 2 Chiefs (stack depth 3) at 61c4994 passes; all CmuxMobileChiefTests pass (68)
3 cmux_mobile_kit-test-ios.sh CmuxMobileShellTests/RowSwipeActionsDrawerTests 4 of 5 failed at 6533d5b passes (7 tests)

Observed / Not run

  • Observed: before and after on an iOS 26.5 iPhone 17 Pro simulator (Demo builds of the base and the head, mock data, light and dark): the reply line in both directions, Home and Workspaces swipe-then-right-swipe, Feed swipe and buttons, and the two-pin repro app.
  • Not run: the Chief flows against a hidden Mac rig over the real link. The double push needs the Cloud Chief ready and a Mac linked at once, which the rig account has no Cloud Chief for; the cause and fix are shown with the minimal repro and the unit test instead. No real-phone check (not requested).
  • Not run: macOS conversation UI (unchanged code).

Changelog

  • Fixed: iPhone Chief reply quotes draw their thread line from under the quoted bubble, as in Messages.
  • Fixed: Opening a Chief on Home no longer pushes it twice.
  • Fixed: With a row's swipe actions open, a rightward swipe closes them instead of opening the sidebar.
  • Changed: Feed swipe actions use the same rounded buttons as the other lists.

No capture: native iPhone UI; simulator captures above (cmux-ci capture drives the Mac app).

🤖 Generated with Claude Code

azooz2003-bit and others added 11 commits October 21, 2026 19:43
… beside the quote)

The thread line's geometry moves into CmuxConversationGeometry
(ConversationReplyThread) unchanged; the new tests describe Messages' line,
which drops from under the quote, and fail on the current geometry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The inline reply's thread line started beside the quote at its middle: a
hook stuck out of the quote's leading side and the line crossed the quote's
tail, then ran under the quote toward a reply far on the other side.

Messages drops the line from under the quoted bubble (its tail, or a group's
avatar column) and turns it toward a reply on the other side in a short
curve level with the reply's middle; a reply on the quote's own side gets a
straight line that stops above it (a group reply: above its avatar). A
quote of an outgoing message threads down the trailing side. The row keeps
room for the quote's tail below it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the Cloud Chief ready and a Mac linked, Home pins the Cloud Chief
and the Mac Chief side by side in one List row. Both pins were
NavigationLinks, and List treats the row as one cell: a tap there
activated both links, so the stack pushed the Cloud Chief and then the
Mac Chief over it (the user's recording: a push, then a second push a
moment later). The pins are plain buttons now that push their own route
through Home's open handler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ver open row actions

Adds the shared RowSwipeActions registry, the List swipe-action button
style the Feed will share, and the drawer's mayOpen(at:) seam; the drawer
does not consult open rows yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e drawer opens

As in Mail and Messages: while a row's swipe actions are open, a
rightward swipe closes them and never opens the team drawer; the drawer
opens only when no row actions are open. Covers every list: List rows
(Workspaces, Home, Settings > Devices, artifacts, checkpoints) are found
slid open in the view tree, and the Feed's own rows report open state
through RowSwipeActions and name their pan so the drawer waits for it.

The Feed's swipe actions now use the same buttons as List's swipe
actions on Workspaces and Home (RowSwipeActionButton): tinted capsules
with their titles under them, inset from the row's edge, instead of
full-height rectangles. Same actions, haptic and full swipe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s the drawer shut

UIKit leaves its List swipe actions view in the hierarchy at full width
after the row closes, so counting it kept every later rightward swipe
from opening the drawer (found live on the iOS 26.5 simulator). An open
row is a cell slid off its laid-out place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… sibling cells

Live on the iOS 26.5 simulator the drawer still opened over an open
Home row: UIKit starts closing the row as the finger lands, before the
drawer's pan asks to begin, and SwiftUI's List slides the open cell's
layout attributes with it. The drawer now notes at touch-down whether a
List row is open, and an open row is the cell off the leading edge its
siblings share (or left of the content, for a lone row).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rd the reply

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Chief answers the workspace request inline (an incoming reply quoting an
outgoing message), and the user's thanks quotes Chief (the user's
reported case), so demo builds show both reply quote directions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ext-ios-ui-fixes

# Conflicts:
#	cmux-next-ios/CmuxMobileKit/Sources/CmuxMobileChief/ConversationsHome.swift
@cursor

cursor Bot commented Oct 22, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review ed327ff: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr24202 -f ref=feat-cmux-next-ios-ui-fixes -f platform=macos -f backend_mode=local

red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on f61b6a1 to compare; do not merge until green; see lane-rules

@blacksmith-sh

blacksmith-sh Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Found 11 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmph_4h4qe8/summary-fail.json (live):/summary-fail.json (live): View Logs
/tmp/tmpw_0wrn1f/summary-missing.json (live):/summary-missing.json (live): View Logs
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows/
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows
View Logs
[new_workspaces] the window draws no frames/[new_workspaces] the window draws no frames View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
View Logs
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs
convention violations found (ERROR lines above)./
convention violations found (ERROR lines above).
View Logs
nightly cmux-tui resolve/nightly cmux-tui resolve View Logs
test_every_submodule_free_checkout_on_an_owned_runner_resets_submodules (main.Reuse
dWorkspaceSubmodules.test_every_submodule_free_checkout_on_an_owned_runner_resets_submo
dules)/
test_every_submodule_free_checkout_on_an_owned_runner_resets_submodules (main.Reuse
dWorkspaceSubmodules.test_every_submodule_free_checkout_on_an_owned_runner_resets_submo
dules)
View Logs
test_every_submodule_free_checkout_on_an_owned_runner_resets_submodules (main.Reuse
dWorkspaceSubmodules.test_every_submodule_free_checkout_on_an_owned_runner_resets_submo
dules) (job='web-bundles')/
test_every_submodule_free_checkout_on_an_owned_runner_resets_submodules (main.Reuse
dWorkspaceSubmodules.test_every_submodule_free_checkout_on_an_owned_runner_resets_submo
dules) (job='web-bundles')
View Logs

...and 1 more test failures. View all on Blacksmith

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@teamleaderleo

Copy link
Copy Markdown
Collaborator

Bead cx-py54o created for this PR by the cmux coordinator.

…e drawer

- A reply on the quote's own side keeps room for a visible straight line
  (it was a dot), and the line meets the reply's first piece of content
  (a photo or file above the caption), never runs through it.
- A Feed row closes when it leaves the screen, so no open row outlives
  its registration; registration keys are per Feed screen; the full-swipe
  threshold stays past an open row's reveal; buttons fit short rows.
- Open-row detection counts only vertical lists (no grids, pagers or
  carousels) and only leftward slides; the touch-down probe walks the tree
  only where the drawer could open.
- A Chief pin's open handler is required.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
azooz2003-bit added a commit that referenced this pull request Oct 22, 2026
…ame-side reply keeps room for its line

The line ends in a short level run toward a reply on the other side. A
reply on the quote's own side keeps room for a visible straight line, and
the line meets the reply's first piece of content (a photo or file above
the caption). Same commits as #24202.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

Review (correctness-first subagent): findings and resolution

Reviewed 19c065e (read-only). No blockers. Fixed in 3145bc8 unless noted.

  1. Major. A same-side reply got a 1 pt dot, not a line. The row reserved only the tail and a 6 pt space. Fixed: the row keeps ConversationReplyThread.minimumStraightRun (12 pt) for a straight line. The test now uses the real row spacing and checks for a line at least 10 pt long.
  2. Major. The line aimed at primary, the last photo or link card, so it could run through photos above a caption. Fixed: it meets the reply's topmost content (photos, files, bubble, emoji, audio, link card).
  3. Minor. A Feed row left open on another tab stayed open but unregistered. Fixed: a row closes and unregisters when it leaves the screen. Registration keys are per Feed screen.
  4. Minor (latent). A grid, pager or carousel collection view could read as an open row. Fixed: only vertical lists count (no sideways content, cells at least 80% of the list's width).
  5. Nit. Table editing mode moves content right. Fixed: only leftward slides count.
  6. Nit. The touch-down probe walked the tree on every touch. Fixed: it walks only when the drawer is closed and on a tab root. Confirmed live that the probe sees the open row before UIKit closes it: the first rightward swipe closes the row and the second opens the drawer on Home, Workspaces and Feed.
  7. Minor (latent). With 3 actions, an open Feed row could sit past the full-swipe threshold. Fixed: the threshold is at least revealWidth + 40.
  8. Nit. Short Feed rows cropped the buttons. Fixed: under 80 pt a row shows the capsule alone, inset 8 pt.
  9. Minor. ChiefPinPushTests passes with 0 pushes. Partly fixed: PinnedGrid.open is now required (no silent dead pin). The positive push was checked live: one tap on the Chief pin opened one Chief, and Back returned to Home. The unit test still guards the double push.
  • macOS: CmuxConversationMacUI has its own thread layout (MacConversationRows). No app target links it (only the package's Mac lab), so the Mac app is not affected. It is left unchanged here.

Tests after the fixes: CmuxConversationGeometryTests 255/255, CmuxMobileChiefTests 68/68, CmuxMobileShellTests 10/10 (iOS 26.5 simulator on a fleet mini).

Head build, light and dark: the reply lines in both directions and the Feed's buttons.
Head: reply lines and Feed buttons, light and dark

CI reds on this PR are base findings, not from this change: cmux-next fast tier, cmux-next checks and nightly-guards / release-notary are red on several unrelated open PRs at once (#24203, #24205, #24210, #24212, #24204). release rails is the web rails suite (this PR has no web changes).

Upstream: the same CmuxConversation commits are in #24208 (feat-imsg-parity-gui), with the package byte-identical to this head. CmuxTabsKit holds no swipe-row code, so feat-cmux-next-tabs-kit is unchanged.

@azooz2003-bit azooz2003-bit added the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Oct 22, 2026
…ext-ios-ui-fixes

# Conflicts:
#	cmux-next-ios/CmuxMobileKit/Sources/CmuxMobileChief/ConversationsHome.swift
@azooz2003-bit azooz2003-bit added ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds and removed ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds labels Oct 22, 2026
@azooz2003-bit
azooz2003-bit merged commit fbb7db0 into feat-cmux-next Oct 22, 2026
@azooz2003-bit
azooz2003-bit deleted the feat-cmux-next-ios-ui-fixes branch October 22, 2026 07:23

This branch was previously deployed

1 inactive deployment
ci-routing-agent — ed327ff2 Deployed Oct 22, 2026 by azooz2003-bit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants