import "package:flutter/widgets.dart"; import "package:google_fonts/google_fonts.dart"; import "package:garage_ui/theme/theme_data.dart"; export "package:garage_ui/theme/theme_data.dart"; export "package:garage_ui/theme/colour_scheme.dart"; export "package:garage_ui/theme/typography.dart"; // The apps theme. Hands the theme data down via a plain inherited scope (no // animated wrapper, no per frame ColorScheme.lerp flattening the whole thing - // this is the bit that used to feel second class), AND establishes a sane // DefaultTextStyle + IconTheme so bare Text/Icon dont fall back to flutter's // yellow-underline "unstyled" debug look (MaterialApp only styles text inside a // Material, and our panels arent Material). class GarageTheme extends StatelessWidget { const GarageTheme({super.key, required this.data, required this.child}); final ThemeData data; final Widget child; static ThemeData of(BuildContext context) { final t = maybeOf(context); assert( t != null, "No GarageTheme found in context. Wrap the app in an GarageTheme.", ); return t!; } static ThemeData? maybeOf(BuildContext context) { return context .dependOnInheritedWidgetOfExactType<_GarageThemeScope>() ?.data; } @override Widget build(BuildContext context) { final cs = data.colorScheme; return _GarageThemeScope( data: data, child: DefaultTextStyle( // the one app-wide UI font, declared right here at the top of the tree. // everything below that doesnt override fontFamily inherits Geist. // (canvas-painted text - station labels, watermark - sits outside the // widget tree so it isnt touched by this.) style: GoogleFonts.geist( color: cs.foreground, // off the density, not a literal times scaling. this was the third // independent source of text size in the package - controls read // density.fontSize, the .xSmall()/.small()/.large() ladder now reads // it too, and this floated free at 11 * scaling. Retune fontSize and // page copy no longer stays behind while the controls move. // // fontSize, NOT textXs. The ladder above the control font is a set // of MULTIPLIERS (xs 1.1x, sm 1.4x, lg 1.8x), so what textXs means // depends on the tier: at A&A's 10 its 11, a hair over the control // font and harmless, and at the product tier's 16 its 18 - body copy // rendering BIGGER than the text inside the buttons and fields next // to it. Thats backwards, and its what made the product surfaces // read as oversized even with their control geometry correct. // // Body copy is the control font. A sentence and the text in the box // under it are the same size, at every tier, by construction. fontSize: data.density.fontSize, // the important bit - kills the yellow underline. decoration: TextDecoration.none, fontWeight: FontWeight.w300, ), child: IconTheme( data: IconThemeData( color: cs.foreground, size: data.iconTheme.medium.size, ), child: child, ), ), ); } } class _GarageThemeScope extends InheritedWidget { const _GarageThemeScope({required this.data, required super.child}); final ThemeData data; @override bool updateShouldNotify(_GarageThemeScope oldWidget) => oldWidget.data != data; }