fix(settings): declare ui.card_overlays for native clients (#530)
The Apple and Android clients are moving onto the canonical ui.card_overlays key (silo-apple#118, silo-android#158), so the manifest's advisory platforms metadata now lists them alongside web. Revision bumped to 4; Go/TS bindings and the conformance fixture regenerated. Client-repo bindings will pick the bump up on their next `make settings-bindings` run — nothing else in the manifest changed. Also stops the web client from erasing the two schema-legal ribbon ids it does not render yet: buildItems() rebuilt `items` from the web registry alone, so a stored `imdb_top_250` / `rt_certified_fresh` config (authorable from Android's native editor, and valid per card-overlays.json) vanished from both `items` and `order` on the next web save. Those ids now pass through parse/serialize untouched, on the same defaults the native registries use, while remaining invisible to web rendering and settings. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"fixture_version": 1,
|
||||
"manifest_revision": 3,
|
||||
"manifest_revision": 4,
|
||||
"description": "Cross-platform conformance cases for settings resolution. Every case runs against the shipped manifest in this directory: definitions are referenced by key, never restated, so an expectation can only be satisfied by resolving the real contract. Each platform's resolver (Go in internal/settingsresolve, TypeScript in web/src/lib/settingsResolve.ts, Kotlin and Swift in the client repos) runs every case through a hand-written runner; a runner must fail on any fixture field it does not know, because schema drift in the fixture itself is drift. A case's constraint_bindings attach a constraint to a copy of a real definition so constraint semantics stay testable even while no shipped definition carries that constraint kind. In expected entries, constrained:true requires stored_value and constraint_kind to be present, and stored_value may be null to mean the authored value was JSON null.",
|
||||
"cases": [
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"api_version": 1,
|
||||
"revision": 3,
|
||||
"revision": 4,
|
||||
"option_sets": {
|
||||
"playback_audio_languages": {
|
||||
"type": "language_tag",
|
||||
@@ -801,7 +801,7 @@
|
||||
"nullable": true
|
||||
},
|
||||
"default_value": null,
|
||||
"platforms": ["web"],
|
||||
"platforms": ["web", "ios", "tvos", "macos", "android", "android_tv"],
|
||||
"category": "appearance",
|
||||
"label": "Poster badges",
|
||||
"description": "Which badges appear on poster cards, and where.",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
package settingskeys
|
||||
|
||||
// Revision is the manifest revision these bindings were generated from.
|
||||
const Revision = 3
|
||||
const Revision = 4
|
||||
|
||||
// Setting keys, one constant per definition.
|
||||
const (
|
||||
|
||||
@@ -13,6 +13,22 @@ export function buildDefaultPrefs(): CardOverlayPrefs {
|
||||
return { version: 2, preset: "classic", order: [], items: buildItems(undefined) };
|
||||
}
|
||||
|
||||
// Ids that are legal in the contract schema (card-overlays.json) but have no
|
||||
// registry entry yet because no API field backs them. The web client neither
|
||||
// renders nor edits these, but their stored config must survive a round-trip:
|
||||
// the native clients' settings UIs can author them, and dropping them here
|
||||
// would erase another client's preference on the next web save. Their bases
|
||||
// mirror the native registries' defaults (ribbons: top-right, disabled).
|
||||
const PASSTHROUGH_IDS = ["imdb_top_250", "rt_certified_fresh"] as const satisfies readonly OverlayId[];
|
||||
const PASSTHROUGH_BASE: OverlayItemConfig = { enabled: false, position: "top-right" };
|
||||
|
||||
function isKnownOverlayId(v: unknown): v is OverlayId {
|
||||
return (
|
||||
typeof v === "string" &&
|
||||
(OVERLAY_MAP.has(v as OverlayId) || (PASSTHROUGH_IDS as readonly string[]).includes(v))
|
||||
);
|
||||
}
|
||||
|
||||
function isValidPosition(v: unknown): v is OverlayPosition {
|
||||
return typeof v === "string" && (OVERLAY_POSITIONS as readonly string[]).includes(v);
|
||||
}
|
||||
@@ -61,6 +77,12 @@ function buildItems(
|
||||
? applyItemPatch(base, entry as Record<string, unknown>)
|
||||
: base;
|
||||
}
|
||||
for (const id of PASSTHROUGH_IDS) {
|
||||
const entry = source?.[id];
|
||||
if (entry && typeof entry === "object") {
|
||||
items[id] = applyItemPatch(PASSTHROUGH_BASE, entry as Record<string, unknown>);
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -75,11 +97,7 @@ function parseV2(parsed: Record<string, unknown>): CardOverlayPrefs {
|
||||
return {
|
||||
version: 2,
|
||||
preset: isValidPreset(parsed.preset) ? parsed.preset : "classic",
|
||||
order: Array.isArray(parsed.order)
|
||||
? (parsed.order as unknown[]).filter(
|
||||
(id): id is OverlayId => typeof id === "string" && OVERLAY_MAP.has(id as OverlayId),
|
||||
)
|
||||
: [],
|
||||
order: Array.isArray(parsed.order) ? (parsed.order as unknown[]).filter(isKnownOverlayId) : [],
|
||||
items: buildItems(sourceItems),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"fixture_version": 1,
|
||||
"manifest_revision": 3,
|
||||
"manifest_revision": 4,
|
||||
"description": "Cross-platform conformance cases for settings resolution. Every case runs against the shipped manifest in this directory: definitions are referenced by key, never restated, so an expectation can only be satisfied by resolving the real contract. Each platform's resolver (Go in internal/settingsresolve, TypeScript in web/src/lib/settingsResolve.ts, Kotlin and Swift in the client repos) runs every case through a hand-written runner; a runner must fail on any fixture field it does not know, because schema drift in the fixture itself is drift. A case's constraint_bindings attach a constraint to a copy of a real definition so constraint semantics stay testable even while no shipped definition carries that constraint kind. In expected entries, constrained:true requires stored_value and constraint_kind to be present, and stored_value may be null to mean the authored value was JSON null.",
|
||||
"cases": [
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* is a manifest change plus a regeneration, never a hand-written key.
|
||||
*/
|
||||
|
||||
export const SETTINGS_REVISION = 3;
|
||||
export const SETTINGS_REVISION = 4;
|
||||
|
||||
export interface SettingSuggestedOption {
|
||||
value: string;
|
||||
@@ -934,7 +934,7 @@ export const SETTING_DEFINITIONS: Record<SettingKey, SettingDefinition> = {
|
||||
label: "Poster badges",
|
||||
description: "Which badges appear on poster cards, and where.",
|
||||
category: "appearance",
|
||||
platforms: ["web"],
|
||||
platforms: ["web", "ios", "tvos", "macos", "android", "android_tv"],
|
||||
},
|
||||
"ui.custom_css": {
|
||||
key: "ui.custom_css",
|
||||
|
||||
Reference in New Issue
Block a user