parseJson static method
Reads a decoded JSON value leniently: keys and words are matched
case-insensitively (ignoring spaces, - and _), a few synonyms are
accepted, single values stand in for lists, and everything unusable
is dropped and listed. Never throws.
Implementation
static IntentParseResult parseJson(Object? json) {
final dropped = <String>[];
if (json is! Map) {
if (json != null) dropped.add('not a JSON object');
return IntentParseResult(ThemeIntent.none, List.unmodifiable(dropped));
}
final families = <ThemeFamily>[];
ThemeBrightness? brightness;
final colors = <IntentColor>[];
IntentChroma? chroma;
HarmonyScheme? harmony;
(int, int)? hueRange;
String? name;
for (final entry in json.entries) {
final key = entry.key is String ? _norm(entry.key as String) : '';
final value = entry.value;
switch (key) {
case 'families' || 'family' || 'style' || 'styles':
for (final v in _list(value)) {
final f = _family(v);
if (f == null) {
dropped.add('families: $v');
} else {
families.add(f);
}
}
case 'brightness' || 'mode' || 'tone':
final w = value is String ? _norm(value) : null;
switch (w) {
case 'light' || 'bright' || 'day':
brightness = ThemeBrightness.light;
case 'dark' || 'night':
brightness = ThemeBrightness.dark;
case 'any' || 'either' || 'auto' || 'none':
brightness = null;
default:
dropped.add('brightness: $value');
}
case 'colors' || 'colours' || 'color' || 'colour' || 'palette':
for (final v in _list(value, splitText: true)) {
final c = _color(v);
if (c == null) {
dropped.add('colors: $v');
} else {
colors.add(c);
}
}
case 'chroma' || 'saturation' || 'intensity' || 'vibrancy':
final c = value is String ? _chroma(_norm(value)) : null;
if (c == null) {
dropped.add('chroma: $value');
} else {
chroma = c;
}
case 'harmony' || 'scheme':
final h = value is String ? _harmony(_norm(value)) : null;
if (h == null) {
dropped.add('harmony: $value');
} else {
harmony = h;
}
case 'huerange' || 'hue':
final r = _hueRange(value);
if (r == null) {
dropped.add('hueRange: $value');
} else {
hueRange = r;
}
case 'name' || 'title':
final n = value is String ? _cleanName(value) : null;
if (n == null) {
dropped.add('name: $value');
} else {
name = n;
}
default:
dropped.add('unknown key ${entry.key}');
}
}
final distinctColors = _distinct(colors);
for (final c in distinctColors.skip(maxColors)) {
dropped.add('colors: ${c.word} (more than $maxColors)');
}
return IntentParseResult(
ThemeIntent(
families: families,
brightness: brightness,
colors: distinctColors,
chroma: chroma,
harmony: harmony,
hueRange: hueRange,
name: name,
),
List.unmodifiable(dropped),
);
}