dvModuleTheme function

Widget dvModuleTheme(
  1. BuildContext context,
  2. String moduleId,
  3. Widget child
)

Wraps child in whatever theme the module mounted as moduleId should render in.

Applied by the generated router around a module's own pages. A module nobody registered, or one that declared no theme of its own, renders in the application's: a parent can ask for override and mount a module that has nothing to override with, and dropping to Flutter's bare defaults there would look like the application had broken.

Implementation

Widget dvModuleTheme(BuildContext context, String moduleId, Widget child) {
  final DVModule? module = dvModuleRegistry.maybeGet(moduleId);
  if (module == null) return child;

  final DVModuleThemeMode mode = module.themeMode;
  if (mode == DVModuleThemeMode.inherit) return child;

  final ThemeData? own = module.declaredTheme;
  if (own == null) return child;

  final ThemeData parent = Theme.of(context);
  final ThemeData resolved = switch (mode) {
    // override and isolated coincide here, and it is worth being plain about
    // that rather than writing two branches that do the same thing. Theme
    // replaces what descendants see, so neither leaves a path back to the
    // parent's values -- not even through the fields the module left at
    // their defaults. Where the specification distinguishes them is what a
    // module may *reach for*, and a theme is not reached for: it is found by
    // looking up, and this stops the lookup either way.
    DVModuleThemeMode.override || DVModuleThemeMode.isolated => own,
    // What the module said, over what the application said. A ThemeData
    // carries a value for every field whether or not its author set one, so
    // "what the module did not say" is read from the fields that still hold
    // the framework's default.
    DVModuleThemeMode.extend => _extend(parent, own),
    DVModuleThemeMode.inherit => parent,
  };
  return Theme(data: resolved, child: child);
}