feat(theme): scale the shard's radii and card depth onto the app's scale (M12 phase 2) #35
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/m12-phase-2-structure"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Phase 2 of M12 (
docs/android/THEMING_AND_NAV.md§5.2, §5.4) — the structure half of the admin's Appearance page, on top of phase 1's colors. Targetsedge; the milestone reachesmainas oneedge→mainmerge.ShardStructure.resolve(theme)turns the four--radius-*tokens and--shadow-cardinto a Material shape scale, a pill shape and a card elevation.RunicGatewayThemefeeds the scale toMaterialTheme.shapesand the other two to a newLocalShardStructure, mirroring phase 1's palette split. Resolution is pure, so every assertion is a plain JVM test with no Compose rule.Radii are a ratio, never a literal. The app's
Shapescame from the M5 mockup and the website's fromtheme.css, and the two scales genuinely differ (--radius-card10px againstmedium12dp). Copying the web value in would have restyled an untouched app on day one, so each field is scaled byresolved ÷ runic-gateway baselineinstead — the shipped theme and an explicitly-selectedrunic-gatewayboth give ratio 1.0 and are provable no-ops.Three things the spec did not survive contact with
1. Card depth is not a no-op — and that is the org lead's decision, taken before any code. Material3 1.3.0's filled
CardisElevationTokens.Level0(0dp — checked in the artifact's bytecode, not assumed) andFeatureCardwas aBoxdrawing none of the "soft shadow" its own KDoc claimed. So the app has been flat since M5, while therunic-gatewaypreset it was drawn from selects the Default shadow. §5.4 is applied as written rather than rebased on the flat baseline — rebasing would have collapsednone/Soft/Defaultonto 0dp and left onlyDeepdoing anything on the phone. Every card gains 4dp on an untouched instance. §2, §5.4 and AC-1 are amended to record it (docs#114).2. The shadow is matched by nearest blur, not by exact string. The
fantasypreset publishes0 16px 38px rgba(0, 0, 0, 0.45), which the server'sSHADOW_OPTIONSdoes not contain —resolveThemeTokenscopies a preset's tokens verbatim and they never pass through the admin form's dropdown. An exact match would have missed the one preset whose point is a heavier shadow.3.
--radius-pillis resolved as a literal px, becauseCircleShapeis a percentage and has no shipped dp for a ratio to scale against. Below the 500px floor the resolved px is taken as dp (Fantasy 4px → 4dp, Modern 8px → 8dp). It reaches exactly one composable: the app's other twoCircleShapeuses are 8dp status dots, and a dot stays a dot however square an admin makes the site.Why every
Card(became aShardCard(The color scheme and the shape scale both reach screens through
MaterialTheme, butCardtakes its elevation as a default argument — there is no composition local behindCardDefaults.cardElevation(). So all 24 call sites across 20 files moved to a one-line wrapper inThemeComponents.kt. The migration is mechanical because every one of them passed nothing but a modifier, which is also why the wrapper's signature is just(Modifier, ColumnScope.() -> Unit). ACard(outside that file is now, by construction, a card the shard cannot theme.Also:
FeatureCard's literalRoundedCornerShape(12.dp)becameMaterialTheme.shapes.medium— same value, now carried by the ratio.StatBar's threeRoundedCornerShape(3.dp)stay literal: half the height of a 6dp meter, not a member of the card radius family.Tests
Shapesdoes implementequals(the opposite of phase 1'sColorSchemefinding, also checked in bytecode), so the structural no-op proof is one assertion against a verbatim copy of the pre-M12 scale rather than a reflection walk. Both the empty theme and the fullrunic-gatewaytoken map assert==toShardStructure.Shipped.ShardStructureTest— 13 cases: the shipped scale against the pre-M12 copy, three no-op paths, Fantasy and Modern scaled onto the app's own dp, per-field fallback, a zero radius, the pill floor, all four shadow options, the off-catalog blurs, and an unreadable shadow.386 unit tests green (373 + 13),
lintDebugandassembleDebugclean. Not exercised on device — that is AC-5, in phase 8, where the new shadow should be looked at with the flat build beside it.Docs: RunicGateway/docs#114.