| import 'package:flutter/foundation.dart'; |
| import 'package:flutter/material.dart'; |
| import 'package:gallery/deferred_widget.dart'; |
| import 'package:gallery/main.dart'; |
| import 'package:gallery/pages/demo.dart'; |
| import 'package:gallery/pages/home.dart'; |
| import 'package:gallery/studies/crane/app.dart' deferred as crane; |
| import 'package:gallery/studies/crane/routes.dart' as crane_routes; |
| import 'package:gallery/studies/fortnightly/app.dart' deferred as fortnightly; |
| import 'package:gallery/studies/fortnightly/routes.dart' as fortnightly_routes; |
| import 'package:gallery/studies/rally/app.dart' deferred as rally; |
| import 'package:gallery/studies/rally/routes.dart' as rally_routes; |
| import 'package:gallery/studies/reply/app.dart' as reply; |
| import 'package:gallery/studies/reply/routes.dart' as reply_routes; |
| import 'package:gallery/studies/shrine/app.dart' deferred as shrine; |
| import 'package:gallery/studies/shrine/routes.dart' as shrine_routes; |
| import 'package:gallery/studies/starter/app.dart' as starter_app; |
| import 'package:gallery/studies/starter/routes.dart' as starter_app_routes; |
| |
| typedef PathWidgetBuilder = Widget Function(BuildContext, String); |
| |
| class Path { |
| const Path(this.pattern, this.builder); |
| |
| /// A RegEx string for route matching. |
| final String pattern; |
| |
| /// The builder for the associated pattern route. The first argument is the |
| /// [BuildContext] and the second argument a RegEx match if that is included |
| /// in the pattern. |
| /// |
| /// ```dart |
| /// Path( |
| /// 'r'^/demo/([\w-]+)$', |
| /// (context, matches) => Page(argument: match), |
| /// ) |
| /// ``` |
| final PathWidgetBuilder builder; |
| } |
| |
| class RouteConfiguration { |
| /// List of [Path] to for route matching. When a named route is pushed with |
| /// [Navigator.pushNamed], the route name is matched with the [Path.pattern] |
| /// in the list below. As soon as there is a match, the associated builder |
| /// will be returned. This means that the paths higher up in the list will |
| /// take priority. |
| static List<Path> paths = [ |
| Path( |
| r'^' + DemoPage.baseRoute + r'/([\w-]+)$', |
| (context, match) => DemoPage(slug: match), |
| ), |
| Path( |
| r'^' + rally_routes.homeRoute, |
| (context, match) => StudyWrapper( |
| study: DeferredWidget(rally.loadLibrary, |
| () => rally.RallyApp()), // ignore: prefer_const_constructors |
| ), |
| ), |
| Path( |
| r'^' + shrine_routes.homeRoute, |
| (context, match) => StudyWrapper( |
| study: DeferredWidget(shrine.loadLibrary, |
| () => shrine.ShrineApp()), // ignore: prefer_const_constructors |
| ), |
| ), |
| Path( |
| r'^' + crane_routes.defaultRoute, |
| (context, match) => StudyWrapper( |
| study: DeferredWidget(crane.loadLibrary, |
| () => crane.CraneApp(), // ignore: prefer_const_constructors |
| placeholder: const DeferredLoadingPlaceholder(name: 'Crane')), |
| ), |
| ), |
| Path( |
| r'^' + fortnightly_routes.defaultRoute, |
| (context, match) => StudyWrapper( |
| study: DeferredWidget( |
| fortnightly.loadLibrary, |
| // ignore: prefer_const_constructors |
| () => fortnightly.FortnightlyApp()), |
| ), |
| ), |
| Path( |
| r'^' + reply_routes.homeRoute, |
| // ignore: prefer_const_constructors |
| (context, match) => StudyWrapper(study: reply.ReplyApp())), |
| Path( |
| r'^' + starter_app_routes.defaultRoute, |
| (context, match) => const StudyWrapper( |
| study: starter_app.StarterApp(), |
| ), |
| ), |
| Path( |
| r'^/', |
| (context, match) => const RootPage(), |
| ), |
| ]; |
| |
| /// The route generator callback used when the app is navigated to a named |
| /// route. Set it on the [MaterialApp.onGenerateRoute] or |
| /// [WidgetsApp.onGenerateRoute] to make use of the [paths] for route |
| /// matching. |
| static Route<dynamic> onGenerateRoute(RouteSettings settings) { |
| for (final path in paths) { |
| final regExpPattern = RegExp(path.pattern); |
| if (regExpPattern.hasMatch(settings.name)) { |
| final firstMatch = regExpPattern.firstMatch(settings.name); |
| final match = (firstMatch.groupCount == 1) ? firstMatch.group(1) : null; |
| if (kIsWeb) { |
| return NoAnimationMaterialPageRoute<void>( |
| builder: (context) => path.builder(context, match), |
| settings: settings, |
| ); |
| } |
| return MaterialPageRoute<void>( |
| builder: (context) => path.builder(context, match), |
| settings: settings, |
| ); |
| } |
| } |
| |
| // If no match was found, we let [WidgetsApp.onUnknownRoute] handle it. |
| return null; |
| } |
| } |
| |
| class NoAnimationMaterialPageRoute<T> extends MaterialPageRoute<T> { |
| NoAnimationMaterialPageRoute({ |
| @required WidgetBuilder builder, |
| RouteSettings settings, |
| }) : super(builder: builder, settings: settings); |
| |
| @override |
| Widget buildTransitions( |
| BuildContext context, |
| Animation<double> animation, |
| Animation<double> secondaryAnimation, |
| Widget child, |
| ) { |
| return child; |
| } |
| } |