Merge pull request 'docs(android): M12 phase 3 as landed' (#115) from docs/android-theming-nav-phase-3 into edge
Reviewed-on: #115
This commit is contained in:
@@ -239,21 +239,57 @@ is constructed server-side and the only part that carries the choice:
|
|||||||
<anything unrecognized> → the role's shipped family
|
<anything unrecognized> → the role's shipped family
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**The lookup is one global map, never scoped to the role's option list** —
|
||||||
|
settled in phase 3, and the same trap §5.4 hit with `--shadow-card`. The server
|
||||||
|
validates an *admin-entered* font against `FONT_OPTIONS[role]`, but a preset's
|
||||||
|
tokens are copied verbatim by `resolveThemeTokens` and never pass through that
|
||||||
|
list: `modern` publishes `--display: 'Work Sans', Arial, sans-serif`, which the
|
||||||
|
display dropdown does not offer, and `fantasy` publishes
|
||||||
|
`--sans: 'EB Garamond', Georgia, serif`, which the sans dropdown does not either.
|
||||||
|
A per-role lookup would have missed the display face of one preset and the label
|
||||||
|
face of the other.
|
||||||
|
|
||||||
The three roles map onto `Type.kt`'s existing three groups verbatim:
|
The three roles map onto `Type.kt`'s existing three groups verbatim:
|
||||||
`--display` → the Cinzel display/headline/title block, `--serif` → the `AppSerif`
|
`--display` → the Cinzel display/headline/title block, `--serif` → the `AppSerif`
|
||||||
body block, `--sans` → the `AppSans` label block. Sizes, weights and tracking do
|
body block, `--sans` → the `AppSans` label block. Sizes, weights and tracking do
|
||||||
not move — only the family.
|
not move — only the family.
|
||||||
|
|
||||||
**IM Fell English has no bold weight** (the website doc records the same). A
|
Because a family is not confined to the role its dropdown lives in, **every
|
||||||
`FontWeight.Bold` request against it must resolve to its single weight rather
|
bundled family supplies all four weights the scale asks for** — 400 (body), 500
|
||||||
than synthesize; check what Compose does here on device and pin the behavior in
|
and 700 (labels), 600 (display) — pinned through `FontVariation` on the variable
|
||||||
the phase's notes.
|
faces. Two exceptions, both upstream facts rather than choices:
|
||||||
|
|
||||||
APK cost: roughly **1.5–2.5 MB** across seven families, variable-axis where Google
|
- **IM Fell English has one weight per style.** Its 400 face answers all four
|
||||||
Fonts publishes one (Cinzel, EB Garamond, Merriweather, Playfair Display, Inter,
|
requests and Android synthesises the bold; the website's dropdown labels it
|
||||||
Work Sans, Source Sans 3) and single-weight for IM Fell English. Measure the
|
"(no bold weight)" for the same reason. What that synthesis actually looks like
|
||||||
release APK before and after, and record both numbers in the PR — R8 does not
|
is an AC-5 observation, not something a unit test can pin.
|
||||||
shrink `res/font/`.
|
- **Cinzel keeps the 500/600/700 it shipped with in M5.** It is the only family
|
||||||
|
the server offers in the display role alone, so nothing can ask it for 400 and
|
||||||
|
adding an instance would have edited M5's type for no reachable case.
|
||||||
|
|
||||||
|
**Italics mirror the website's set**, decided in phase 3: EB Garamond, IM Fell
|
||||||
|
English, Merriweather and Playfair Display carry a true italic, exactly the four
|
||||||
|
`client/index.html` requests one for. Inter, Work Sans, Source Sans 3 and Cinzel
|
||||||
|
are upright-only and Compose skews them — which is what the app already did for
|
||||||
|
every family before this milestone, and what the web does for its own
|
||||||
|
upright-only faces. The app draws italic in two places.
|
||||||
|
|
||||||
|
APK cost, **measured, not estimated** — the drafted "roughly 1.5–2.5 MB" was
|
||||||
|
wrong by more than 3×. Unsigned release APK, R8 full-mode + resource shrink, on
|
||||||
|
`edge` at the phase 2 merge:
|
||||||
|
|
||||||
|
| | added (compressed) | release APK |
|
||||||
|
|---|---|---|
|
||||||
|
| before phase 3 | — | 5,031,411 B — 4.80 MiB |
|
||||||
|
| after phase 3 | 8,543,292 B — 8.15 MiB | 13,574,703 B — **12.94 MiB** |
|
||||||
|
|
||||||
|
**Merriweather is 6.08 MiB of the 8.15** — upstream ships it as a three-axis
|
||||||
|
`[opsz,wdth,wght]` variable font with a full charset, 4.6 MB per style, and it
|
||||||
|
deflates only 31% where the others manage 50–60%. Bundling it verbatim anyway was
|
||||||
|
the org lead's call, taken with the cheaper options costed: Google's own static
|
||||||
|
400/700 builds would have held the whole app near 6.8 MiB, and not bundling it at
|
||||||
|
all near 6.2 MiB, at the price of a serif option that silently does nothing on
|
||||||
|
Android. R8 does not shrink `res/font/`; the APK's deflate is the only saving.
|
||||||
|
|
||||||
### 5.4 Shadow depth
|
### 5.4 Shadow depth
|
||||||
|
|
||||||
@@ -514,7 +550,7 @@ PR against `main`.
|
|||||||
| **0** ✅ | **Contract & appearance store** | `SettingsDto` gains `theme` and `nav_public`; `SiteAppearance` replaces the bare `BrandDto` in `AppViewModel`; second-stage JSON parse; resume refresh (§5.5). **No visual change** — this phase must be invisible |
|
| **0** ✅ | **Contract & appearance store** | `SettingsDto` gains `theme` and `nav_public`; `SiteAppearance` replaces the bare `BrandDto` in `AppViewModel`; second-stage JSON parse; resume refresh (§5.5). **No visual change** — this phase must be invisible |
|
||||||
| **1** ✅ | **Colors** | `ShardPalette` + `LocalShardPalette`; all direct `Color.kt` imports migrated; `RunicGatewayTheme(appearance)`; AC-1 + AC-2 tests |
|
| **1** ✅ | **Colors** | `ShardPalette` + `LocalShardPalette`; all direct `Color.kt` imports migrated; `RunicGatewayTheme(appearance)`; AC-1 + AC-2 tests |
|
||||||
| **2** ✅ | **Radii & shadow** | Ratio-scaled `Shapes` (§5.2), elevation map (§5.4) |
|
| **2** ✅ | **Radii & shadow** | Ratio-scaled `Shapes` (§5.2), elevation map (§5.4) |
|
||||||
| **3** | **Fonts** | Seven bundled families + licenses; stack → `FontFamily` resolution; `Type.kt` takes its three families from the resolved theme. APK size recorded |
|
| **3** ✅ | **Fonts** | Seven bundled families + licenses; stack → `FontFamily` resolution; `Type.kt` takes its three families from the resolved theme. APK size recorded |
|
||||||
| **4** | **Brand assets** | Logo in the drawer header and top bar, hero on Home (§5.6). Coil + `LocalAssetResolver` already exist; renders nothing when unset |
|
| **4** | **Brand assets** | Logo in the drawer header and top bar, hero on Home (§5.6). Coil + `LocalAssetResolver` already exist; renders nothing when unset |
|
||||||
| **5** | **Public nav: label / order / hidden** | The path→route table (§6.2), `Routes.news(category)`, the merge, drawer wiring. AC-3 |
|
| **5** | **Public nav: label / order / hidden** | The path→route table (§6.2), `Routes.news(category)`, the merge, drawer wiring. AC-3 |
|
||||||
| **6** | **Public nav: sections & added links** | Drawer groups, `pruneNav` port, link path validation, native-route resolution + Custom Tab fallback (§6.3) |
|
| **6** | **Public nav: sections & added links** | Drawer groups, `pruneNav` port, link path validation, native-route resolution + Custom Tab fallback (§6.3) |
|
||||||
@@ -660,6 +696,49 @@ proven not to have moved anything.
|
|||||||
in phase 8, where the new shadow should be looked at with the flat build beside
|
in phase 8, where the new shadow should be looked at with the flat build beside
|
||||||
it.
|
it.
|
||||||
|
|
||||||
|
### Phase 3 as landed
|
||||||
|
|
||||||
|
- **The APK nearly tripled, and that was a decision rather than a discovery.**
|
||||||
|
§5.3 now carries the measured before/after and the two cheaper options that
|
||||||
|
were costed and declined. The one number worth remembering: Merriweather is
|
||||||
|
75% of the payload, because upstream publishes it as a three-axis variable font
|
||||||
|
that barely compresses. Anyone revisiting the app's size should start there and
|
||||||
|
nowhere else.
|
||||||
|
- **The per-role font list is not the set of values a role can hold.** Two of the
|
||||||
|
three presets publish a font their own role's dropdown does not offer (§5.3).
|
||||||
|
The resolution map is therefore global, keyed by the lowercased first family
|
||||||
|
name, and the tests assert both preset cases by name so a future per-role
|
||||||
|
"tidy-up" fails loudly.
|
||||||
|
- **`Typography` implements `equals`** — like phase 2's `Shapes` and unlike phase
|
||||||
|
1's `ColorScheme`, checked the same way in the material3 1.3.0 bytecode. AC-1's
|
||||||
|
type half is one comparison against a verbatim copy of the pre-M12 scale held in
|
||||||
|
the test, so a stray edit to a size or a letter-spacing in `Type.kt` fails there
|
||||||
|
rather than quietly redefining what "shipped" means.
|
||||||
|
- **No `LocalShardTypeface`, deliberately.** The palette and the structure each
|
||||||
|
needed a composition local for the parts `MaterialTheme` cannot carry; the
|
||||||
|
families need none. Every text style in the app comes from
|
||||||
|
`MaterialTheme.typography`, and the two places that override anything
|
||||||
|
(`NotificationsScreen`'s hint, `BlockRenderer`'s italic title) override the
|
||||||
|
*style*, not the family. `FontFamily.Monospace` on the recovery-codes screen
|
||||||
|
stays fixed, as a semantic choice rather than a themed one.
|
||||||
|
- **`Type.kt`'s `val Typography` became `shardTypography(faces)`**, which is the
|
||||||
|
whole migration: the three families were referenced from that one file and
|
||||||
|
nowhere else, so unlike phase 1's colour imports and phase 2's 24 `Card(` sites
|
||||||
|
there was no call-site sweep at all.
|
||||||
|
- **Licences live in `app/licenses/`**, one `*-OFL.txt` per family, never under
|
||||||
|
`res/font/` — aapt rejects a `.txt` there, the M5 gotcha. Three of the seven
|
||||||
|
carry a Reserved Font Name (Merriweather, Playfair Display, Source Sans 3),
|
||||||
|
which is a further reason the binaries are taken verbatim rather than subsetted
|
||||||
|
or instanced locally.
|
||||||
|
- Tests: `ShardTypefaceTest` (15 — the shipped families and the pre-M12 scale, the
|
||||||
|
`runic-gateway` no-op, both preset bypasses by name, all thirteen shortlist
|
||||||
|
options, first-name parsing against quoting/casing/whitespace, per-field
|
||||||
|
fallback, a colours-only theme, blank and comma-only stacks, and a themed scale
|
||||||
|
proved to differ from the shipped one *only* in its families). **401 unit tests
|
||||||
|
green** (386 + 15), `lintDebug` and `assembleDebug` clean. Not exercised on
|
||||||
|
device — that is AC-5, in phase 8, where IM Fell English's synthesised bold is
|
||||||
|
the thing to look at.
|
||||||
|
|
||||||
### Phase 7, cancelled
|
### Phase 7, cancelled
|
||||||
|
|
||||||
Reading `nav_admin` / `nav_player` is **not scheduled**. The measurement in §6.4
|
Reading `nav_admin` / `nav_player` is **not scheduled**. The measurement in §6.4
|
||||||
|
|||||||
Reference in New Issue
Block a user