import "package:flutter/widgets.dart"; import "package:garage_ui/scrollbar.dart"; import "package:garage_ui/theme/garage_theme.dart"; /// The application shell for Garage UI apps. /// /// This deliberately uses [WidgetsApp] rather than [MaterialApp]. Garage UI /// owns the visual system while Flutter still supplies routing, overlays, /// media queries, directionality, and localization plumbing. class GarageApp extends StatelessWidget { const GarageApp.router({ super.key, required this.routerConfig, required this.theme, this.title = "", this.builder, this.locale, this.localizationsDelegates, this.supportedLocales = const [Locale("en", "US")], this.debugShowCheckedModeBanner = false, }); final RouterConfig routerConfig; final ThemeData theme; final String title; final TransitionBuilder? builder; final Locale? locale; final Iterable>? localizationsDelegates; final Iterable supportedLocales; final bool debugShowCheckedModeBanner; @override Widget build(BuildContext context) { return WidgetsApp.router( key: key, title: title, routerConfig: routerConfig, color: theme.colorScheme.background, locale: locale, localizationsDelegates: localizationsDelegates, supportedLocales: supportedLocales, debugShowCheckedModeBanner: debugShowCheckedModeBanner, // the Builder matters: without it `builder` is handed the context ABOVE // this GarageTheme, so GarageTheme.of() asserts inside the very callback // you were given for theming. // ScrollConfiguration, not WidgetsApp's `scrollBehavior` - that // parameter only exists on MaterialApp/CupertinoApp. builder: (context, child) => ScrollConfiguration( behavior: const GarageScrollBehavior(), child: GarageTheme( data: theme, child: Builder( builder: (themedContext) => builder?.call(themedContext, child) ?? child ?? const SizedBox.shrink(), ), ), ), ); } } /// Scrolling without Material's overscroll glow. /// /// The default ScrollBehavior hangs a GlowingOverscrollIndicator off every /// scrollable on Android and Fuchsia - the grey arc that swells out of the /// top or bottom edge when you drag past the end. Its a Material idiom, and /// this kit isnt a Material app: it paints a big soft shape over flat chrome /// and reads as a rendering fault rather than as feedback. /// /// Physics and drag devices are untouched, so a list still throws and settles /// the way the OS expects - it just doesnt glow at the ends. iOS and desktop /// never had the glow in the first place, so this only levels the other /// platforms up to what they already do. /// /// The scrollbar is ours too. The base behaviour hands desktop a stock /// [RawScrollbar] - 8px, square ends, a hardcoded grey that knows nothing /// about the scheme - and thats the pale bar that used to sit beside every /// nav list. [GarageScrollbar] replaces it here, once, for every scrollable /// in the app. Touch platforms keep no bar at all, same as the default. class GarageScrollBehavior extends ScrollBehavior { const GarageScrollBehavior(); @override Widget buildOverscrollIndicator( BuildContext context, Widget child, ScrollableDetails details, ) => child; @override Widget buildScrollbar( BuildContext context, Widget child, ScrollableDetails details, ) { switch (getPlatform(context)) { case TargetPlatform.linux: case TargetPlatform.macOS: case TargetPlatform.windows: return GarageScrollbar(controller: details.controller, child: child); case TargetPlatform.android: case TargetPlatform.fuchsia: case TargetPlatform.iOS: return child; } } }