feat(compose): add font color and text highlight to the formatting toolbar #189

Merged
JMR-dev merged 3 commits from feat-74-75-compose-color-highlight into main 2026-07-03 02:26:03 +00:00
JMR-dev commented 2026-07-03 01:52:29 +00:00 (Migrated from github.com)

Summary

Wires the previously-unused ColorSwatchRow composable into the compose FormattingToolbar, adding the two color controls the rich-text engine already supported end-to-end (serialize/parse/render) but had no UI for.

  • Font color button (A) applies RichStyle.FontColor(argb) over the selection; its glyph tints to the selection's current color.
  • Highlight button (H) applies RichStyle.Highlight(argb) over the selection; its background previews the selection's current highlight.
  • Both open a shared ColorPickerDialog built on the existing ColorSwatchRow:
    • Font color: ~8 fixed swatches (black, gray, red, orange, yellow, green, blue, purple).
    • Highlight: typical marker colors (yellow / green / cyan / pink).
    • ColorSwatchRow's leading "no color" / "none" entry clears the style outright via a new clearStyle op (needed because toggleStyle only removes a value when the selection is already uniformly that exact value).
  • Colors are opaque ARGB Ints (matching RichStyle.FontColor(argb: Int) / RichStyle.Highlight(argb: Int)), so they round-trip through the existing color: / background-color: HTML serialization.

Accessibility

  • Each toolbar button keeps the existing onClickLabel pattern (format_color, format_highlight); individual swatches carry their own contentDescription from ColorSwatchRow.
  • New user-facing strings added to strings.xml (format_color, format_highlight, and swatch labels); reuses the pre-existing format_color_none.

Tests

Added JVM unit tests for clearStyle (removes a color span regardless of value, splits partial-overlap spans, leaves other style kinds intact, no-op on a collapsed selection).

Local gate green under JDK 21: :app:assembleDebug :app:testDebugUnitTest :app:lintDebug :app:ktlintCheck :app:detekt :app:compileDebugAndroidTestKotlin — BUILD SUCCESSFUL.

Closes #74
Closes #75

🤖 Generated with Claude Code

## Summary Wires the previously-unused `ColorSwatchRow` composable into the compose `FormattingToolbar`, adding the two color controls the rich-text engine already supported end-to-end (serialize/parse/render) but had no UI for. - **Font color** button (`A`) applies `RichStyle.FontColor(argb)` over the selection; its glyph tints to the selection's current color. - **Highlight** button (`H`) applies `RichStyle.Highlight(argb)` over the selection; its background previews the selection's current highlight. - Both open a shared `ColorPickerDialog` built on the existing `ColorSwatchRow`: - Font color: ~8 fixed swatches (black, gray, red, orange, yellow, green, blue, purple). - Highlight: typical marker colors (yellow / green / cyan / pink). - `ColorSwatchRow`'s leading "no color" / "none" entry clears the style outright via a new `clearStyle` op (needed because `toggleStyle` only removes a value when the selection is already uniformly that exact value). - Colors are opaque ARGB `Int`s (matching `RichStyle.FontColor(argb: Int)` / `RichStyle.Highlight(argb: Int)`), so they round-trip through the existing `color:` / `background-color:` HTML serialization. ## Accessibility - Each toolbar button keeps the existing `onClickLabel` pattern (`format_color`, `format_highlight`); individual swatches carry their own `contentDescription` from `ColorSwatchRow`. - New user-facing strings added to `strings.xml` (`format_color`, `format_highlight`, and swatch labels); reuses the pre-existing `format_color_none`. ## Tests Added JVM unit tests for `clearStyle` (removes a color span regardless of value, splits partial-overlap spans, leaves other style kinds intact, no-op on a collapsed selection). Local gate green under JDK 21: `:app:assembleDebug :app:testDebugUnitTest :app:lintDebug :app:ktlintCheck :app:detekt :app:compileDebugAndroidTestKotlin` — BUILD SUCCESSFUL. Closes #74 Closes #75 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.