33// found in the LICENSE file.
44
55import 'package:collection/collection.dart' ;
6+ import 'package:flutter/foundation.dart' ;
67import 'package:flutter/widgets.dart' ;
78import 'package:meta/meta.dart' ;
89
@@ -96,7 +97,7 @@ import 'typedefs.dart';
9697/// ///
9798/// See [main.dart](https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/main.dart)
9899@immutable
99- abstract class RouteBase {
100+ abstract class RouteBase with Diagnosticable {
100101 const RouteBase ._({
101102 required this .routes,
102103 required this .parentNavigatorKey,
@@ -118,6 +119,15 @@ abstract class RouteBase {
118119 return routes.expand (
119120 (RouteBase e) => < RouteBase > [e, ...routesRecursively (e.routes)]);
120121 }
122+
123+ @override
124+ void debugFillProperties (DiagnosticPropertiesBuilder properties) {
125+ super .debugFillProperties (properties);
126+ if (parentNavigatorKey != null ) {
127+ properties.add (DiagnosticsProperty <GlobalKey <NavigatorState >>(
128+ 'parentNavKey' , parentNavigatorKey));
129+ }
130+ }
121131}
122132
123133/// A route that is displayed visually above the matching parent route using the
@@ -157,6 +167,11 @@ class GoRoute extends RouteBase {
157167 _pathRE = patternToRegExp (path, pathParameters);
158168 }
159169
170+ /// Whether this [GoRoute] only redirects to another route.
171+ ///
172+ /// If this is true, this route must redirect location other than itself.
173+ bool get redirectOnly => pageBuilder == null && builder == null ;
174+
160175 /// Optional name of the route.
161176 ///
162177 /// If used, a unique string name must be provided and it can not be empty.
@@ -323,8 +338,12 @@ class GoRoute extends RouteBase {
323338 final List <String > pathParameters = < String > [];
324339
325340 @override
326- String toString () {
327- return 'GoRoute(name: $name , path: $path )' ;
341+ void debugFillProperties (DiagnosticPropertiesBuilder properties) {
342+ super .debugFillProperties (properties);
343+ properties.add (StringProperty ('name' , name));
344+ properties.add (StringProperty ('path' , path));
345+ properties.add (
346+ FlagProperty ('redirect' , value: redirectOnly, ifTrue: 'Redirect Only' ));
328347 }
329348
330349 late final RegExp _pathRE;
@@ -338,6 +357,21 @@ abstract class ShellRouteBase extends RouteBase {
338357 {required super .routes, required super .parentNavigatorKey})
339358 : super ._();
340359
360+ static void _debugCheckSubRouteParentNavigatorKeys (
361+ List <RouteBase > subRoutes, GlobalKey <NavigatorState > navigatorKey) {
362+ for (final RouteBase route in subRoutes) {
363+ assert (
364+ route.parentNavigatorKey == null ||
365+ route.parentNavigatorKey == navigatorKey,
366+ "sub-route's parent navigator key must either be null or has the same navigator key as parent's key" );
367+ if (route is GoRoute && route.redirectOnly) {
368+ // This route does not produce a page, need to check its sub-routes
369+ // instead.
370+ _debugCheckSubRouteParentNavigatorKeys (route.routes, navigatorKey);
371+ }
372+ }
373+ }
374+
341375 /// Attempts to build the Widget representing this shell route.
342376 ///
343377 /// Returns null if this shell route does not build a Widget, but instead uses
@@ -506,12 +540,11 @@ class ShellRoute extends ShellRouteBase {
506540 }) : assert (routes.isNotEmpty),
507541 navigatorKey = navigatorKey ?? GlobalKey <NavigatorState >(),
508542 super ._() {
509- for (final RouteBase route in routes) {
510- if (route is GoRoute ) {
511- assert (route.parentNavigatorKey == null ||
512- route.parentNavigatorKey == navigatorKey);
513- }
514- }
543+ assert (() {
544+ ShellRouteBase ._debugCheckSubRouteParentNavigatorKeys (
545+ routes, this .navigatorKey);
546+ return true ;
547+ }());
515548 }
516549
517550 /// The widget builder for a shell route.
@@ -576,6 +609,13 @@ class ShellRoute extends ShellRouteBase {
576609 @override
577610 Iterable <GlobalKey <NavigatorState >> get _navigatorKeys =>
578611 < GlobalKey <NavigatorState >> [navigatorKey];
612+
613+ @override
614+ void debugFillProperties (DiagnosticPropertiesBuilder properties) {
615+ super .debugFillProperties (properties);
616+ properties.add (DiagnosticsProperty <GlobalKey <NavigatorState >>(
617+ 'navigatorKey' , navigatorKey));
618+ }
579619}
580620
581621/// A route that displays a UI shell with separate [Navigator] s for its
@@ -828,6 +868,13 @@ class StatefulShellRoute extends ShellRouteBase {
828868 }
829869 return true ;
830870 }
871+
872+ @override
873+ void debugFillProperties (DiagnosticPropertiesBuilder properties) {
874+ super .debugFillProperties (properties);
875+ properties.add (DiagnosticsProperty <Iterable <GlobalKey <NavigatorState >>>(
876+ 'navigatorKeys' , _navigatorKeys));
877+ }
831878}
832879
833880/// Representation of a separate branch in a stateful navigation tree, used to
@@ -854,7 +901,13 @@ class StatefulShellBranch {
854901 this .initialLocation,
855902 this .restorationScopeId,
856903 this .observers,
857- }) : navigatorKey = navigatorKey ?? GlobalKey <NavigatorState >();
904+ }) : navigatorKey = navigatorKey ?? GlobalKey <NavigatorState >() {
905+ assert (() {
906+ ShellRouteBase ._debugCheckSubRouteParentNavigatorKeys (
907+ routes, this .navigatorKey);
908+ return true ;
909+ }());
910+ }
858911
859912 /// The [GlobalKey] to be used by the [Navigator] built for this branch.
860913 ///
0 commit comments