2022-09-20 16:32:46 +02:00
|
|
|
import 'package:flutter/cupertino.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
|
|
class CustomNavigator extends StatefulWidget {
|
|
|
|
const CustomNavigator({
|
|
|
|
required this.home,
|
|
|
|
Key? key,
|
|
|
|
this.navigatorKey,
|
|
|
|
this.initialRoute,
|
|
|
|
this.onGenerateRoute,
|
|
|
|
this.routes = const <String, WidgetBuilder>{},
|
|
|
|
this.pageRoute,
|
|
|
|
this.onUnknownRoute,
|
|
|
|
this.navigatorObservers = const <NavigatorObserver>[],
|
|
|
|
}) : super(key: key);
|
|
|
|
|
|
|
|
final GlobalKey<NavigatorState>? navigatorKey;
|
|
|
|
final String? initialRoute;
|
|
|
|
final RouteFactory? onGenerateRoute;
|
|
|
|
final Map<String, WidgetBuilder> routes;
|
|
|
|
final PageRouteFactory? pageRoute;
|
|
|
|
final Widget home;
|
|
|
|
final RouteFactory? onUnknownRoute;
|
|
|
|
final List<NavigatorObserver> navigatorObservers;
|
|
|
|
|
|
|
|
@override
|
2022-09-21 14:58:46 +02:00
|
|
|
CustomNavigatorState createState() => CustomNavigatorState();
|
2022-09-20 16:32:46 +02:00
|
|
|
}
|
|
|
|
|
2022-09-21 14:58:46 +02:00
|
|
|
class CustomNavigatorState extends State<CustomNavigator>
|
2022-09-20 16:32:46 +02:00
|
|
|
implements WidgetsBindingObserver {
|
|
|
|
GlobalKey<NavigatorState>? _navigator;
|
|
|
|
|
|
|
|
void _setNavigator() =>
|
|
|
|
_navigator = widget.navigatorKey ?? GlobalObjectKey<NavigatorState>(this);
|
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
_setNavigator();
|
|
|
|
WidgetsBinding.instance.addObserver(this);
|
|
|
|
super.initState();
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void didChangeMetrics() {}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Navigator(
|
|
|
|
key: _navigator,
|
|
|
|
initialRoute: WidgetsBinding.instance.window.defaultRouteName !=
|
|
|
|
Navigator.defaultRouteName
|
|
|
|
? WidgetsBinding.instance.window.defaultRouteName
|
|
|
|
: widget.initialRoute ??
|
|
|
|
WidgetsBinding.instance.window.defaultRouteName,
|
|
|
|
onGenerateRoute: _onGenerateRoute,
|
|
|
|
onUnknownRoute: _onUnknownRoute,
|
|
|
|
observers: widget.navigatorObservers,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Future<bool> didPopRoute() async {
|
|
|
|
assert(mounted);
|
|
|
|
var navigator = _navigator?.currentState;
|
|
|
|
if (navigator == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return navigator.maybePop();
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Future<bool> didPushRoute(String route) async {
|
|
|
|
assert(mounted);
|
|
|
|
var navigator = _navigator?.currentState;
|
|
|
|
if (navigator == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
await navigator.pushNamed(route);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Route<dynamic>? _onGenerateRoute(RouteSettings settings) {
|
|
|
|
var name = settings.name;
|
|
|
|
var pageContentBuilder = name == Navigator.defaultRouteName
|
|
|
|
? (BuildContext context) => widget.home
|
|
|
|
: widget.routes[name!];
|
|
|
|
|
|
|
|
if (pageContentBuilder != null) {
|
|
|
|
assert(
|
|
|
|
widget.pageRoute != null,
|
|
|
|
'The default onGenerateRoute handler for CustomNavigator must have a '
|
|
|
|
'pageRoute set if the home or routes properties are set.');
|
|
|
|
Route<dynamic> route = widget.pageRoute!<dynamic>(
|
|
|
|
settings,
|
|
|
|
pageContentBuilder,
|
|
|
|
);
|
|
|
|
return route;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (widget.onGenerateRoute != null) {
|
|
|
|
return widget.onGenerateRoute!(settings);
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
Route<dynamic>? _onUnknownRoute(RouteSettings settings) {
|
|
|
|
assert(() {
|
|
|
|
if (widget.onUnknownRoute == null) {
|
|
|
|
throw FlutterError(
|
|
|
|
'Could not find a generator for route $settings in the $runtimeType.\n'
|
|
|
|
'Generators for routes are searched for in the following order:\n'
|
|
|
|
' 1. For the "/" route, the "home" property, if non-null, is used.\n'
|
|
|
|
' 2. Otherwise, the "routes" table is used, if it has an entry for '
|
|
|
|
'the route.\n'
|
|
|
|
' 3. Otherwise, onGenerateRoute is called. It should return a '
|
|
|
|
'non-null value for any valid route not handled by "home" and "routes".\n'
|
|
|
|
' 4. Finally if all else fails onUnknownRoute is called.\n'
|
|
|
|
'Unfortunately, onUnknownRoute was not set.');
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}());
|
|
|
|
final Route<dynamic>? result = widget.onUnknownRoute!(settings);
|
|
|
|
assert(() {
|
|
|
|
if (result == null) {
|
|
|
|
throw FlutterError('The onUnknownRoute callback returned null.\n'
|
|
|
|
'When the $runtimeType requested the route $settings from its '
|
|
|
|
'onUnknownRoute callback, the callback returned null. Such callbacks '
|
|
|
|
'must never return null.');
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}());
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-09-21 14:58:46 +02:00
|
|
|
@override
|
|
|
|
void didChangeAppLifecycleState(AppLifecycleState state) {}
|
2022-09-20 16:32:46 +02:00
|
|
|
|
2022-09-21 14:58:46 +02:00
|
|
|
@override
|
|
|
|
void noSuchMethod(Invocation invocation) {
|
2022-09-20 16:32:46 +02:00
|
|
|
var name = invocation.memberName.toString();
|
|
|
|
debugPrint(
|
|
|
|
'Expected a method to be called with name $name, '
|
|
|
|
'but no such method was found.',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class PageRoutes {
|
|
|
|
static final materialPageRoute =
|
2022-09-21 14:58:46 +02:00
|
|
|
<T>(RouteSettings settings, WidgetBuilder builder) =>
|
|
|
|
MaterialPageRoute<T>(settings: settings, builder: builder);
|
2022-09-20 16:32:46 +02:00
|
|
|
static final cupertinoPageRoute =
|
2022-09-21 14:58:46 +02:00
|
|
|
<T>(RouteSettings settings, WidgetBuilder builder) =>
|
|
|
|
CupertinoPageRoute<T>(settings: settings, builder: builder);
|
2022-09-20 16:32:46 +02:00
|
|
|
}
|