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
112 lines
3.8 KiB
Dart
112 lines
3.8 KiB
Dart
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>[Locale("en", "US")],
|
|
this.debugShowCheckedModeBanner = false,
|
|
});
|
|
|
|
final RouterConfig<Object> routerConfig;
|
|
final ThemeData theme;
|
|
final String title;
|
|
final TransitionBuilder? builder;
|
|
final Locale? locale;
|
|
final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates;
|
|
final Iterable<Locale> 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;
|
|
}
|
|
}
|
|
}
|