Skip to content

fix(android): align mixed nested list indents with iOS - #1023

Merged
hryhoriiK97 merged 2 commits into
mainfrom
fix/android-mixed-nested-list-indent
Oct 17, 2026
Merged

hryhoriiK97 merged 2 commits into
mainfrom
fix/android-mixed-nested-list-indent

Conversation

@hryhoriiK97

Copy link
Copy Markdown
Collaborator

What/Why?

Supersedes #1006 by @mwolson, whose commit is carried over unchanged (17188be) with a small follow-up on top. We could not push to the fork branch, so this PR lands the same work from a repo branch.

Closes #1004.

On Android, a nested list whose marker type differs from its parent's gets the wrong space between marker and text. A numbered list under a bullet draws 1. over the first letters of its items (the repo's own mixed_nested_list_test baseline showed "1Django"), a task list under a bullet puts its checkboxes against the text, and bullets under a short 1. sit far from their text. iOS already lays these out correctly.

Nested items used a fixed marginLeft as their text indent, so their text started from the parent's marker column while their marker was drawn from their own. Each nested item now starts its text from its own marker column, the way iOS does.

The change is one term in BaseListSpan.getLeadingMargin, next to the markerExtraWidth from #1015. Each item records the column it reserves before any widening (baselineMarkerWidth), and its nested items get it as parentMarkerWidth. A nested item's margin is the difference between its own truncated absolute indent and its parent's, plus its own whole-pixel widening. The sum telescopes, so text lands at int(depth * marginLeft + column + gap) plus the ancestors' widenings at every depth, which is the iOS headIndent formula, and the marker-to-text gap stays within a pixel of gapWidth. Top-level lists and same-type nests with a whole-pixel marginLeft (the default 24dp is 63 px on a Pixel 9) are unchanged. With a fractional pixel marginLeft, same-type nests now alternate whole-pixel steps instead of always truncating, so their gap no longer drifts.

Both Android renderers get the same change, react-native-enriched-markdown and the standalone enriched-markdown-android. In the React Native package the toggled copy of a task keeps parentMarkerWidth, so toggling leaves every indent where it was. iOS is not touched.

Follow-up on top of #1006 (358aefc)

  • getBaselineMarkerWidth() is now open val baselineMarkerWidth, matching the sibling markerExtraWidth.
  • ListItemRenderer restores listItemMarkerWidth through a previousMarkerWidth local, mirroring previousMarkerExtra.
  • The five Android baselines are recaptured on the repo's Pixel9-API36-EnrichedMarkdown AVD. The originals were captured on x86_64 Linux with software rendering and differed by anti-aliasing.

Testing

  • ListRenderingTest in both Android packages gains the mixed-nest cases: all six parent and child combinations (tasks checked and unchecked), same-type and top-level geometry, absolute indents with fractional bullet sizes and margins, mixed ancestors followed by sibling lists, mixed nests in and around wide numbered lists, wrapped lines, RTL, and equal markerMinWidth columns. Six of them fail against the old formula in each package.
  • React Native TaskListInteractionTest: toggling a task under a bullet and under a number keeps every margin and drawn marker.
  • Standalone package: testDebugUnitTest and ktlintCheck pass (61 suites). React Native package: unit tests and ktlint pass (ListRenderingTest 18/18, TaskListInteractionTest 3/3).
  • Maestro on the Pixel 9 API 36 AVD, update mode: the new Android-only mixed_nested_list_markers_test (bullets and numbers both ways, and task lists), mixed_nested_list_test (React Native and native Android examples) and list_sublist_first_combo_test all pass and their five baselines are refreshed from this AVD.
  • mixed_nested_list_test scrolls once on Android before its capture so the last rows are not under the gesture bar.

Screenshots

From #1006, React Native example on Android (mixed_nested_list_test and mixed_nested_list_markers_test), with iOS for reference:

Before After iOS (unchanged)

PR Checklist

  • Code compiles and runs on iOS (no iOS change)
  • Code compiles and runs on Android
  • Updated documentation/README if applicable
  • Ran example app to verify changes
  • E2E tests are passing
  • Required E2E tests have been added (if applicable)

🤖 Generated with Claude Code

mwolson and others added 2 commits October 17, 2026 08:54
…apture mixed-list baselines

Follow-up to the cherry-picked #1006 commit. `getBaselineMarkerWidth()` becomes
`open val baselineMarkerWidth` to match `markerExtraWidth`, and
`ListItemRenderer` restores `listItemMarkerWidth` through a
`previousMarkerWidth` local like `previousMarkerExtra`. The five Android
baselines are recaptured on the Pixel9-API36-EnrichedMarkdown AVD.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
@hryhoriiK97
hryhoriiK97 merged commit e585e16 into main Oct 17, 2026
15 checks passed
@hryhoriiK97
hryhoriiK97 deleted the fix/android-mixed-nested-list-indent branch October 17, 2026 07:18
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.

Android draws mixed nested list markers over their text

2 participants