feat(android): organize block inserter into cards with search#469
Draft
jkmassel wants to merge 1 commit intojkmassel/android-block-pickerfrom
Draft
feat(android): organize block inserter into cards with search#469jkmassel wants to merge 1 commit intojkmassel/android-block-pickerfrom
jkmassel wants to merge 1 commit intojkmassel/android-block-pickerfrom
Conversation
2287a41 to
20b6773
Compare
ae080ac to
f19065a
Compare
4 tasks
Organizes the native block inserter into iOS-parity per-section cards
with a debounced search field and per-card Show More/Less, mirroring
the iOS `BlockInserterView`. All UI is Jetpack Compose, hosted in a
`ComposeView` inside the existing `BottomSheetDialog` so the
integration surface is unchanged.
## Layout
`LazyColumn` of rounded `colorSurfaceContainerHigh` section cards,
each containing a chunked-`Row` grid of icon-over-label tiles. Span
count is derived from display width with a min of 3 so narrow devices
stay readable. Tile = 44dp chip + 12sp caption (`maxLines = 2`,
ellipsize end). Matches the iOS `BlockInserterBlockView` stack of
`BlockIconView` over `Text(title).lineLimit(2, reservesSpace: true)`.
Sections with a null `name` render headerless, matching iOS
(`gbk-most-used` and `gbk-contextual` sit at the top with no label).
Sections with more than 16 blocks collapse with per-card Show More /
Show Less — same threshold iOS uses.
## Search
Debounced `TextField` at the top of the dialog. Ranking is a direct
port of `ios/Sources/GutenbergKit/Sources/Helpers/SearchEngine.swift`
(weighted title/name/keywords/description/category, prefix +
Levenshtein fallback for short queries), so results order matches iOS.
Empty query restores browsable sections; zero-match query shows a
`No results` empty state.
## SVG rendering
Adopts AndroidSVG (`com.caverock:androidsvg-aar:1.4`) — the rendering
engine Coil-SVG wraps, used directly to avoid pulling in Coil. Parses
each block's inline `@wordpress/icons` SVG once per `BlockType.id`,
caches the rendered bitmap so recomposition doesn't re-render. Three
patterns the browser handles via CSS that AndroidSVG does not:
1. **Missing `viewBox`** (e.g. `core/site-tagline`) — synthesise one
from intrinsic dimensions and set document width/height to 100%.
2. **`fill="none"` at root** (e.g. `core/icon`) — inject `svg { fill:
currentColor }` via `RenderOptions.css`.
3. **Multi-fill branded icons** (e.g. Pocket Casts, Animoto) — detect
hex fills in the raw string and skip the tint so internal contrast
survives.
## Contrast-aware tinting
`SvgIconCache.shouldTint` decides per-icon whether to apply the theme
tint:
1. **No declared colours** — pure monochrome; tint to text colour.
2. **Multiple declared colours** — render as-is. A PorterDuff SRC_IN
tint would flatten internal contrast into a silhouette.
3. **Single declared colour** — keep it if it has at least 3:1
contrast (WCAG 2.x SC 1.4.11 — minimum for UI graphics) against
the chip fill composited over the surface; otherwise strip it and
tint.
Measuring against bare black instead of the composited surface makes
marginal colours like WordPress blue (#0073AA) appear to pass at
3.16:1 while reading as dim against the actual ~`#3B3B3D` chip
surrogate (2.1:1).
## Bridge
`getBlockIcon` at `src/utils/blocks.js:44` previously dropped
`icon.foreground` — the JS metadata the web editor applies as CSS
`color`, which paths inside the SVG pick up via `currentColor`. Adds
`getBlockIconForeground` to the serialised inserter payload, with
matching `iconForeground: String?` fields on the Android `BlockType`
data class and the iOS `BlockType` struct (iOS gets the field for
parity; no rendering change).
## Test plan
- [x] `./gradlew :Gutenberg:testDebugUnitTest :Gutenberg:detekt :Gutenberg:assembleDebug` — BUILD SUCCESSFUL
- [x] Manually verified on Pixel 9 Pro XL with `enableNativeBlockInserter` on, dark theme: sections render, fuzzy search (`imge` → Image first), Show More/Less toggles in Theme section, swipe-to-dismiss, tile tap inserts block.
- [ ] Reviewer: verify in light theme.
- [ ] Reviewer: verify disabled blocks still render at 0.5 alpha and don't fire click handlers.
20b6773 to
f1afeab
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacks on top of #468. Organizes the native block inserter into iOS-parity per-section cards with a debounced search field and per-card Show More/Less, mirroring the iOS
BlockInserterView. All UI is Jetpack Compose, hosted in aComposeViewinsideGutenbergView'sBottomSheetDialogso the integration surface is unchanged.Changes
Layout
LazyColumnof roundedcolorSurfaceContainerHighsection cards, each containing a chunked-Rowgrid of icon-over-label tiles. Span count is derived from display width with a min of 3 so narrow devices stay readable.maxLines = 2, ellipsize end). Matches the iOSBlockInserterBlockViewstack ofBlockIconViewoverText(title).lineLimit(2, reservesSpace: true).namerender headerless, matching iOS (gbk-most-usedandgbk-contextualsit at the top with no label).Search
TextFieldat the top of the dialog. Ranking is a direct port ofios/Sources/GutenbergKit/Sources/Helpers/SearchEngine.swift(weighted title/name/keywords/description/category, prefix + Levenshtein fallback for short queries), so results order matches iOS.No resultsempty state.Compose
org.jetbrains.kotlin.plugin.composeplugin and Compose BOM + ui + material3 deps (already declared inlibs.versions.toml).BlockInserterDialogkeeps its existingBottomSheetDialogpublic surface; only the content is Compose.Icon chip sizing and the contrast-aware tinting from #468 are unchanged.
Test plan
./gradlew :Gutenberg:testDebugUnitTest :Gutenberg:detekt :Gutenberg:assembleDebug— BUILD SUCCESSFULenableNativeBlockInserteron, dark theme: sections render, fuzzy search (imge→ Image first), Show More/Less toggles in Theme section, swipe-to-dismiss, tile tap inserts block.Related