Files
ImBenjiandClaude Opus 5.5 b269201919 The Garage SDKs, in the open
garage_auth, garage_entitlements, garage_iap and garage_ui, moved out of
Garage-Services and Metro-Map-Maker into one public repo. MIT, one readme,
docs under docs/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013F4NWNvYcdeSgqbWMT1VQ7
2026-09-23 18:49:21 +01:00

91 lines
3.5 KiB
Dart

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;
}