generate method
- int seed,
- ThemeFamily family,
- int engineVersion, {
- bool accessible = false,
- int? seedHueTenths,
- ThemeIntent? intent,
- bool intentCentred = false,
The theme for (seed, family, engineVersion) — and the Accessible
lock when accessible (labels and display text ≥ 7:1).
Throws UnsupportedEngineVersion for versions this build cannot
reproduce, and ArgumentError for ThemeFamily.plain and for
families engineVersion has not shipped (their placeholder
definitions are not frozen, so their output would not be a pure
function of the version).
seedHueTenths (0–3599, M3 Expressive only) is the Android "Match my
wallpaper" variant (spec §5.3 #1): it replaces the palette stream's
base-hue draw (every other draw is unchanged), the result is marked
ThemeVariant.wallpaper, and every guardrail runs exactly as for a
generated theme.
intent (engine v4+) steers the theme: steerable families narrow
their palette draws to it, every family takes its name, and the result
is marked ThemeVariant.steered. intentCentred puts each narrowed
choice at the middle of its range (the first theme of a steered
feed). An empty intent is no intent. When every attempt fails, the
fallback is the hero closest to the intent.
Implementation
ThemeSpec generate(
int seed,
ThemeFamily family,
int engineVersion, {
bool accessible = false,
int? seedHueTenths,
ThemeIntent? intent,
bool intentCentred = false,
}) {
if (!supportedEngineVersions.contains(engineVersion)) {
throw UnsupportedEngineVersion(engineVersion);
}
if (family == ThemeFamily.plain) {
throw ArgumentError.value(family, 'family', 'plain is never generated');
}
if (!familyShippedAt(family, engineVersion)) {
throw ArgumentError.value(
family,
'family',
'not shipped at engine version $engineVersion',
);
}
if (seedHueTenths != null && family != ThemeFamily.m3Expressive) {
throw ArgumentError.value(
family,
'family',
'only Material 3 Expressive has a wallpaper variant',
);
}
final steering = _steering(
intent,
intentCentred,
engineVersion,
seedHueTenths,
);
final s = seed & 0xFFFFFFFF;
for (var attempt = 0; attempt < maxAttempts; attempt++) {
final candidate = buildCandidate(
s,
family,
engineVersion,
attempt: attempt,
accessible: accessible,
seedHueTenths: seedHueTenths,
intent: steering?.intent,
intentCentred: intentCentred,
);
final fixed = repairTheme(candidate);
if (fixed != null) return fixed;
}
if (steering != null && engineVersion >= 5) {
// Before a hero: the family's own theme with only its accents
// turned to the intent (the family's colour rules then hold).
for (var attempt = 0; attempt < maxAttempts; attempt++) {
final candidate = _candidate(
s,
family,
engineVersion,
attempt: attempt,
accessible: accessible,
seedHueTenths: seedHueTenths,
intent: steering.intent,
intentCentred: intentCentred,
accentsOnly: true,
);
final fixed = repairTheme(candidate);
if (fixed != null) return fixed;
}
}
if (steering != null) {
return heroForAccessible(
steering.closestHero(s, family),
accessible: accessible,
);
}
return heroFallback(s, family, accessible: accessible);
}