From 4e877178cd881463c077c3a9aeffc69df789b94c Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Tue, 17 Jun 2025 11:39:12 +0800 Subject: [PATCH 01/17] [go_router] `ShellRoute` will merge `GoRouter`'s observers --- packages/go_router/lib/go_router.dart | 1 + .../lib/src/misc/merged_observer.dart | 60 +++++++++++++++++++ packages/go_router/lib/src/route.dart | 44 ++++++++++++-- packages/go_router/lib/src/route_data.dart | 14 +++++ .../test/shell_route_observers_test.dart | 35 +++++++++++ packages/go_router/test/test_helpers.dart | 2 + 6 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 packages/go_router/lib/src/misc/merged_observer.dart diff --git a/packages/go_router/lib/go_router.dart b/packages/go_router/lib/go_router.dart index d2728a077c08..267cf6764d52 100644 --- a/packages/go_router/lib/go_router.dart +++ b/packages/go_router/lib/go_router.dart @@ -14,6 +14,7 @@ export 'src/match.dart' hide RouteMatchListCodec; export 'src/misc/errors.dart'; export 'src/misc/extensions.dart'; export 'src/misc/inherited_router.dart'; +export 'src/misc/merged_observer.dart'; export 'src/pages/custom_transition_page.dart'; export 'src/parser.dart'; export 'src/route.dart'; diff --git a/packages/go_router/lib/src/misc/merged_observer.dart b/packages/go_router/lib/src/misc/merged_observer.dart new file mode 100644 index 000000000000..33b918f8e99c --- /dev/null +++ b/packages/go_router/lib/src/misc/merged_observer.dart @@ -0,0 +1,60 @@ +import 'package:flutter/widgets.dart'; + +/// A [NavigatorObserver] that merges the observers of the current +/// route with the observers of the previous route. +class MergedNavigatorObserver extends NavigatorObserver { + /// Default constructor for the merged navigator observer. + MergedNavigatorObserver(this.observers); + + /// The observers to be merged. + final List observers; + + @override + void didPush(Route route, Route? previousRoute) { + for (final NavigatorObserver observer in observers) { + observer.didPush(route, previousRoute); + } + } + + @override + void didPop(Route route, Route? previousRoute) { + for (final NavigatorObserver observer in observers) { + observer.didPop(route, previousRoute); + } + } + + @override + void didRemove(Route route, Route? previousRoute) { + for (final NavigatorObserver observer in observers) { + observer.didRemove(route, previousRoute); + } + } + + @override + void didReplace({Route? newRoute, Route? oldRoute}) { + for (final NavigatorObserver observer in observers) { + observer.didReplace(newRoute: newRoute, oldRoute: oldRoute); + } + } + + @override + void didChangeTop(Route topRoute, Route? previousTopRoute) { + for (final NavigatorObserver observer in observers) { + observer.didChangeTop(topRoute, previousTopRoute); + } + } + + @override + void didStartUserGesture(Route route, Route? previousRoute) { + for (final NavigatorObserver observer in observers) { + observer.didStartUserGesture(route, previousRoute); + } + } + + @override + void didStopUserGesture() { + for (final NavigatorObserver observer in observers) { + observer.didStopUserGesture(); + } + } +} diff --git a/packages/go_router/lib/src/route.dart b/packages/go_router/lib/src/route.dart index f6a4b80b1c65..2dab48e683d3 100644 --- a/packages/go_router/lib/src/route.dart +++ b/packages/go_router/lib/src/route.dart @@ -11,6 +11,7 @@ import 'package:meta/meta.dart'; import 'configuration.dart'; import 'match.dart'; +import 'misc/merged_observer.dart'; import 'path_utils.dart'; import 'router.dart'; import 'state.dart'; @@ -482,8 +483,18 @@ abstract class ShellRouteBase extends RouteBase { super.redirect, required super.routes, required super.parentNavigatorKey, + this.mergeObservers = true, }) : super._(); + /// Whether to merge the observers of the shell route's parent with the + /// observers of the shell route. + /// + /// When `true`, the observers of the shell route's parent will be merged with + /// the observers of the shell route. + /// + /// Defaults to `false`. + final bool mergeObservers; + static void _debugCheckSubRouteParentNavigatorKeys( List subRoutes, GlobalKey navigatorKey) { for (final RouteBase route in subRoutes) { @@ -552,9 +563,21 @@ class ShellRouteContext { final NavigatorBuilder navigatorBuilder; Widget _buildNavigatorForCurrentRoute( - List? observers, String? restorationScopeId) { - return navigatorBuilder( - navigatorKey, match, routeMatchList, observers, restorationScopeId); + BuildContext context, + List? observers, + bool mergeObservers, + String? restorationScopeId) { + final List effectiveObservers = [ + ...?observers, + if (mergeObservers) + MergedNavigatorObserver( + // ignore: invalid_use_of_visible_for_testing_member + GoRouter.of(context).routerDelegate.builder.observers, + ), + ]; + + return navigatorBuilder(navigatorKey, match, routeMatchList, + effectiveObservers, restorationScopeId); } } @@ -659,6 +682,7 @@ class ShellRoute extends ShellRouteBase { super.redirect, this.builder, this.pageBuilder, + super.mergeObservers, this.observers, required super.routes, super.parentNavigatorKey, @@ -695,7 +719,7 @@ class ShellRoute extends ShellRouteBase { ShellRouteContext shellRouteContext) { if (builder != null) { final Widget navigator = shellRouteContext._buildNavigatorForCurrentRoute( - observers, restorationScopeId); + context, observers, mergeObservers, restorationScopeId); return builder!(context, state, navigator); } return null; @@ -706,7 +730,7 @@ class ShellRoute extends ShellRouteBase { ShellRouteContext shellRouteContext) { if (pageBuilder != null) { final Widget navigator = shellRouteContext._buildNavigatorForCurrentRoute( - observers, restorationScopeId); + context, observers, mergeObservers, restorationScopeId); return pageBuilder!(context, state, navigator); } return null; @@ -822,6 +846,7 @@ class StatefulShellRoute extends ShellRouteBase { super.redirect, this.builder, this.pageBuilder, + super.mergeObservers, required this.navigatorContainerBuilder, super.parentNavigatorKey, this.restorationScopeId, @@ -848,6 +873,7 @@ class StatefulShellRoute extends ShellRouteBase { /// for a complete runnable example using StatefulShellRoute.indexedStack. StatefulShellRoute.indexedStack({ required List branches, + bool mergeObservers = true, GoRouterRedirect? redirect, StatefulShellRouteBuilder? builder, GlobalKey? parentNavigatorKey, @@ -859,6 +885,7 @@ class StatefulShellRoute extends ShellRouteBase { redirect: redirect, builder: builder, pageBuilder: pageBuilder, + mergeObservers: mergeObservers, parentNavigatorKey: parentNavigatorKey, restorationScopeId: restorationScopeId, navigatorContainerBuilder: _indexedStackContainerBuilder, @@ -955,6 +982,7 @@ class StatefulShellRoute extends ShellRouteBase { StatefulNavigationShell( shellRouteContext: shellRouteContext, router: GoRouter.of(context), + mergeObservers: mergeObservers, containerBuilder: navigatorContainerBuilder); static Widget _indexedStackContainerBuilder(BuildContext context, @@ -1121,6 +1149,7 @@ class StatefulNavigationShell extends StatefulWidget { required this.shellRouteContext, required GoRouter router, required this.containerBuilder, + this.mergeObservers = true, }) : assert(shellRouteContext.route is StatefulShellRoute), _router = router, currentIndex = _indexOfBranchNavigatorKey( @@ -1144,6 +1173,9 @@ class StatefulNavigationShell extends StatefulWidget { /// Corresponds to the index in the branches field of [StatefulShellRoute]. final int currentIndex; + /// Same to [ShellRoute.mergeObservers]. + final bool mergeObservers; + /// The associated [StatefulShellRoute]. StatefulShellRoute get route => shellRouteContext.route as StatefulShellRoute; @@ -1318,7 +1350,7 @@ class StatefulNavigationShellState extends State previousBranchLocation != currentBranchLocation; if (locationChanged || !hasExistingNavigator) { branchState.navigator = shellRouteContext._buildNavigatorForCurrentRoute( - branch.observers, branch.restorationScopeId); + context, branch.observers, false, branch.restorationScopeId); } _cleanUpObsoleteBranches(); diff --git a/packages/go_router/lib/src/route_data.dart b/packages/go_router/lib/src/route_data.dart index 24afed527405..b3d4808fc87b 100644 --- a/packages/go_router/lib/src/route_data.dart +++ b/packages/go_router/lib/src/route_data.dart @@ -201,6 +201,7 @@ abstract class ShellRouteData extends RouteData { GlobalKey? navigatorKey, GlobalKey? parentNavigatorKey, List routes = const [], + bool mergeObservers = true, List? observers, String? restorationScopeId, }) { @@ -239,6 +240,7 @@ abstract class ShellRouteData extends RouteData { parentNavigatorKey: parentNavigatorKey, routes: routes, navigatorKey: navigatorKey, + mergeObservers: mergeObservers, observers: observers, restorationScopeId: restorationScopeId, redirect: redirect, @@ -435,9 +437,15 @@ class TypedGoRoute extends TypedRoute { class TypedShellRoute extends TypedRoute { /// Default const constructor const TypedShellRoute({ + this.mergeObservers = true, this.routes = const >[], }); + /// Determines whether the observers should be merged. + /// + /// See [ShellRouteBase.mergeObservers]. + final bool mergeObservers; + /// Child route definitions. /// /// See [RouteBase.routes]. @@ -450,9 +458,15 @@ class TypedStatefulShellRoute extends TypedRoute { /// Default const constructor const TypedStatefulShellRoute({ + this.mergeObservers = true, this.branches = const >[], }); + /// Determines whether the observers should be merged. + /// + /// See [ShellRouteBase.mergeObservers]. + final bool mergeObservers; + /// Child route definitions. /// /// See [RouteBase.routes]. diff --git a/packages/go_router/test/shell_route_observers_test.dart b/packages/go_router/test/shell_route_observers_test.dart index f738daf52549..0d203d7aa7ab 100644 --- a/packages/go_router/test/shell_route_observers_test.dart +++ b/packages/go_router/test/shell_route_observers_test.dart @@ -2,10 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; +import 'test_helpers.dart'; + void main() { test('ShellRoute observers test', () { final ShellRoute shell = ShellRoute( @@ -25,4 +28,36 @@ void main() { expect(shell.observers!.length, 1); }); + + testWidgets('observers should be merged', (WidgetTester tester) async { + final HeroController observer = HeroController(); + final List observers = [observer]; + addTearDown(observer.dispose); + + final GlobalKey navKey = GlobalKey(); + await createRouter( + [ + ShellRoute( + navigatorKey: navKey, + builder: (_, __, Widget child) => child, + routes: [ + GoRoute( + path: '/', + parentNavigatorKey: navKey, + builder: (_, __) => const Text('Home'), + ), + ], + ), + ], + tester, + observers: observers, + ); + await tester.pumpAndSettle(); + + final List shellRouteObservers = + navKey.currentState!.widget.observers; + final MergedNavigatorObserver mergedObservers = + shellRouteObservers.single as MergedNavigatorObserver; + expect(listEquals(observers, mergedObservers.observers), isTrue); + }); } diff --git a/packages/go_router/test/test_helpers.dart b/packages/go_router/test/test_helpers.dart index cb1c2acdb966..2766b0489e3a 100644 --- a/packages/go_router/test/test_helpers.dart +++ b/packages/go_router/test/test_helpers.dart @@ -177,6 +177,7 @@ Future createRouter( GoExceptionHandler? onException, bool requestFocus = true, bool overridePlatformDefaultLocation = false, + List? observers, }) async { final GoRouter goRouter = GoRouter( routes: routes, @@ -191,6 +192,7 @@ Future createRouter( restorationScopeId: restorationScopeId, requestFocus: requestFocus, overridePlatformDefaultLocation: overridePlatformDefaultLocation, + observers: observers, ); addTearDown(goRouter.dispose); await tester.pumpWidget( From 962c175ee658717d0d466d7b9c8e9fbf74377008 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Tue, 17 Jun 2025 12:44:59 +0800 Subject: [PATCH 02/17] fix: test --- .../lib/src/misc/merged_observer.dart | 5 +++-- packages/go_router/lib/src/route.dart | 20 +++++++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/go_router/lib/src/misc/merged_observer.dart b/packages/go_router/lib/src/misc/merged_observer.dart index 33b918f8e99c..efc2c0078af1 100644 --- a/packages/go_router/lib/src/misc/merged_observer.dart +++ b/packages/go_router/lib/src/misc/merged_observer.dart @@ -1,6 +1,6 @@ import 'package:flutter/widgets.dart'; -/// A [NavigatorObserver] that merges the observers of the current +/// A [NavigatorObserver] that merges the observers of the current /// route with the observers of the previous route. class MergedNavigatorObserver extends NavigatorObserver { /// Default constructor for the merged navigator observer. @@ -45,7 +45,8 @@ class MergedNavigatorObserver extends NavigatorObserver { } @override - void didStartUserGesture(Route route, Route? previousRoute) { + void didStartUserGesture( + Route route, Route? previousRoute) { for (final NavigatorObserver observer in observers) { observer.didStartUserGesture(route, previousRoute); } diff --git a/packages/go_router/lib/src/route.dart b/packages/go_router/lib/src/route.dart index 2dab48e683d3..73718b30b1c7 100644 --- a/packages/go_router/lib/src/route.dart +++ b/packages/go_router/lib/src/route.dart @@ -492,6 +492,8 @@ abstract class ShellRouteBase extends RouteBase { /// When `true`, the observers of the shell route's parent will be merged with /// the observers of the shell route. /// + /// Only effective for `observers` passed into `GoRouter`. + /// /// Defaults to `false`. final bool mergeObservers; @@ -568,14 +570,20 @@ class ShellRouteContext { bool mergeObservers, String? restorationScopeId) { final List effectiveObservers = [ - ...?observers, - if (mergeObservers) - MergedNavigatorObserver( - // ignore: invalid_use_of_visible_for_testing_member - GoRouter.of(context).routerDelegate.builder.observers, - ), + ...?observers ]; + if (mergeObservers) { + final List? rootObservers = + // ignore: invalid_use_of_visible_for_testing_member + GoRouter.maybeOf(context)?.routerDelegate.builder.observers; + if (rootObservers != null) { + effectiveObservers.add(MergedNavigatorObserver( + rootObservers, + )); + } + } + return navigatorBuilder(navigatorKey, match, routeMatchList, effectiveObservers, restorationScopeId); } From d954fd5dfcfb9d2cfc63a25a590e4ef65a336641 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Tue, 17 Jun 2025 12:55:23 +0800 Subject: [PATCH 03/17] update CHANGELOG.md and pubspec.yaml --- packages/go_router/CHANGELOG.md | 5 +++++ packages/go_router/pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md index feba3bdfa0e4..c251ce7b5bb5 100644 --- a/packages/go_router/CHANGELOG.md +++ b/packages/go_router/CHANGELOG.md @@ -1,3 +1,8 @@ +## 15.3.0 + +- `ShellRoute` will auto merge the `observers` passed into `GoRouter`. +- Adds `mergeObservers` to `ShellRouteBase`, `ShellRoute`, `StatefulShellRoute`, `ShellRouteData.$route`. + ## 15.2.0 - `GoRouteData` now defines `.location`, `.go(context)`, `.push(context)`, `.pushReplacement(context)`, and `replace(context)` to be used for [Type-safe routing](https://pub.dev/documentation/go_router/latest/topics/Type-safe%20routes-topic.html). **Requires go_router_builder >= 3.0.0**. diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml index 9367be85902f..dd279a673026 100644 --- a/packages/go_router/pubspec.yaml +++ b/packages/go_router/pubspec.yaml @@ -1,7 +1,7 @@ name: go_router description: A declarative router for Flutter based on Navigation 2 supporting deep linking, data-driven routes and more -version: 15.2.0 +version: 15.3.0 repository: https://github.com/flutter/packages/tree/main/packages/go_router issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22 From 1bfdc41a5346999e8ab9aca077e44ba92192e06c Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Thu, 19 Jun 2025 14:03:31 +0800 Subject: [PATCH 04/17] Added `observers` property to `GoRouter` to make it easier to access observers through context --- packages/go_router/lib/src/route.dart | 3 +-- packages/go_router/lib/src/router.dart | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/go_router/lib/src/route.dart b/packages/go_router/lib/src/route.dart index 73718b30b1c7..670fca33e76e 100644 --- a/packages/go_router/lib/src/route.dart +++ b/packages/go_router/lib/src/route.dart @@ -575,8 +575,7 @@ class ShellRouteContext { if (mergeObservers) { final List? rootObservers = - // ignore: invalid_use_of_visible_for_testing_member - GoRouter.maybeOf(context)?.routerDelegate.builder.observers; + GoRouter.maybeOf(context)?.observers; if (rootObservers != null) { effectiveObservers.add(MergedNavigatorObserver( rootObservers, diff --git a/packages/go_router/lib/src/router.dart b/packages/go_router/lib/src/router.dart index 6dfef3166a6f..ff71cbacbdc5 100644 --- a/packages/go_router/lib/src/router.dart +++ b/packages/go_router/lib/src/router.dart @@ -177,7 +177,7 @@ class GoRouter implements RouterConfig { String? initialLocation, this.overridePlatformDefaultLocation = false, Object? initialExtra, - List? observers, + this.observers, bool debugLogDiagnostics = false, GlobalKey? navigatorKey, String? restorationScopeId, @@ -302,6 +302,9 @@ class GoRouter implements RouterConfig { @override late final GoRouteInformationParser routeInformationParser; + /// The navigator observers used by [GoRouter]. + final List? observers; + void _handleRoutingConfigChanged() { // Reparse is needed to update its builder restore(configuration.reparse(routerDelegate.currentConfiguration)); From 1cb0a5fd548c21ac4bb1da69443574e00f554502 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Tue, 21 Oct 2025 16:25:13 +0800 Subject: [PATCH 05/17] 1. hide _MergedNavigatorObserver implementation 2. rename `mergeObservers` to `notifyRootObserver` 3. set `notifyRootObserver`'s default value to `true` --- packages/go_router/CHANGELOG.md | 5 +- packages/go_router/lib/go_router.dart | 1 - .../lib/src/misc/merged_observer.dart | 61 ---------- packages/go_router/lib/src/route.dart | 105 ++++++++++++++---- packages/go_router/lib/src/route_data.dart | 16 +-- .../test/shell_route_observers_test.dart | 84 ++++++++------ 6 files changed, 146 insertions(+), 126 deletions(-) delete mode 100644 packages/go_router/lib/src/misc/merged_observer.dart diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md index d99ccdd11145..94958c2cf2c5 100644 --- a/packages/go_router/CHANGELOG.md +++ b/packages/go_router/CHANGELOG.md @@ -1,7 +1,8 @@ ## 17.0.0 -- `ShellRoute` will auto merge the `observers` passed into `GoRouter`. -- Adds `mergeObservers` to `ShellRouteBase`, `ShellRoute`, `StatefulShellRoute`, `ShellRouteData.$route`. +- **BREAKING CHANGE** + - `ShellRoute` will auto merge the `observers` passed into `GoRouter`. + - Adds `notifyRootObserver` to `ShellRouteBase`, `ShellRoute`, `StatefulShellRoute`, `ShellRouteData.$route`. ## 16.2.5 diff --git a/packages/go_router/lib/go_router.dart b/packages/go_router/lib/go_router.dart index 9b33e0719643..04fc0791ed8e 100644 --- a/packages/go_router/lib/go_router.dart +++ b/packages/go_router/lib/go_router.dart @@ -15,7 +15,6 @@ export 'src/misc/custom_parameter.dart'; export 'src/misc/errors.dart'; export 'src/misc/extensions.dart'; export 'src/misc/inherited_router.dart'; -export 'src/misc/merged_observer.dart'; export 'src/pages/custom_transition_page.dart'; export 'src/parser.dart'; export 'src/route.dart'; diff --git a/packages/go_router/lib/src/misc/merged_observer.dart b/packages/go_router/lib/src/misc/merged_observer.dart deleted file mode 100644 index efc2c0078af1..000000000000 --- a/packages/go_router/lib/src/misc/merged_observer.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:flutter/widgets.dart'; - -/// A [NavigatorObserver] that merges the observers of the current -/// route with the observers of the previous route. -class MergedNavigatorObserver extends NavigatorObserver { - /// Default constructor for the merged navigator observer. - MergedNavigatorObserver(this.observers); - - /// The observers to be merged. - final List observers; - - @override - void didPush(Route route, Route? previousRoute) { - for (final NavigatorObserver observer in observers) { - observer.didPush(route, previousRoute); - } - } - - @override - void didPop(Route route, Route? previousRoute) { - for (final NavigatorObserver observer in observers) { - observer.didPop(route, previousRoute); - } - } - - @override - void didRemove(Route route, Route? previousRoute) { - for (final NavigatorObserver observer in observers) { - observer.didRemove(route, previousRoute); - } - } - - @override - void didReplace({Route? newRoute, Route? oldRoute}) { - for (final NavigatorObserver observer in observers) { - observer.didReplace(newRoute: newRoute, oldRoute: oldRoute); - } - } - - @override - void didChangeTop(Route topRoute, Route? previousTopRoute) { - for (final NavigatorObserver observer in observers) { - observer.didChangeTop(topRoute, previousTopRoute); - } - } - - @override - void didStartUserGesture( - Route route, Route? previousRoute) { - for (final NavigatorObserver observer in observers) { - observer.didStartUserGesture(route, previousRoute); - } - } - - @override - void didStopUserGesture() { - for (final NavigatorObserver observer in observers) { - observer.didStopUserGesture(); - } - } -} diff --git a/packages/go_router/lib/src/route.dart b/packages/go_router/lib/src/route.dart index 5a289c1fe44b..c739bb1d7751 100644 --- a/packages/go_router/lib/src/route.dart +++ b/packages/go_router/lib/src/route.dart @@ -13,7 +13,6 @@ import 'package:meta/meta.dart' as meta; import 'configuration.dart'; import 'match.dart'; -import 'misc/merged_observer.dart'; import 'path_utils.dart'; import 'router.dart'; import 'state.dart'; @@ -499,19 +498,17 @@ abstract class ShellRouteBase extends RouteBase { super.redirect, required super.routes, required super.parentNavigatorKey, - this.mergeObservers = true, + this.notifyRootObserver = true, }) : super._(); - /// Whether to merge the observers of the shell route's parent with the - /// observers of the shell route. + /// Whether to merge the observers of the GoRouter with the observers + /// of the ShellRoute. /// - /// When `true`, the observers of the shell route's parent will be merged with - /// the observers of the shell route. + /// When `true`, the observers of the GoRouter will be merged with + /// the observers of the ShellRoute. /// - /// Only effective for `observers` passed into `GoRouter`. - /// - /// Defaults to `false`. - final bool mergeObservers; + /// Defaults to `true`. + final bool notifyRootObserver; static void _debugCheckSubRouteParentNavigatorKeys( List subRoutes, @@ -592,18 +589,18 @@ class ShellRouteContext { Widget _buildNavigatorForCurrentRoute( BuildContext context, List? observers, - bool mergeObservers, + bool notifyRootObserver, String? restorationScopeId, ) { final List effectiveObservers = [ ...?observers ]; - if (mergeObservers) { + if (notifyRootObserver) { final List? rootObservers = GoRouter.maybeOf(context)?.observers; if (rootObservers != null) { - effectiveObservers.add(MergedNavigatorObserver( + effectiveObservers.add(_MergedNavigatorObserver( rootObservers, )); } @@ -720,7 +717,7 @@ class ShellRoute extends ShellRouteBase { super.redirect, this.builder, this.pageBuilder, - super.mergeObservers, + super.notifyRootObserver, this.observers, required super.routes, super.parentNavigatorKey, @@ -764,7 +761,7 @@ class ShellRoute extends ShellRouteBase { final Widget navigator = shellRouteContext._buildNavigatorForCurrentRoute( context, observers, - mergeObservers, + notifyRootObserver, restorationScopeId, ); return builder!(context, state, navigator); @@ -782,7 +779,7 @@ class ShellRoute extends ShellRouteBase { final Widget navigator = shellRouteContext._buildNavigatorForCurrentRoute( context, observers, - mergeObservers, + notifyRootObserver, restorationScopeId, ); return pageBuilder!(context, state, navigator); @@ -904,7 +901,7 @@ class StatefulShellRoute extends ShellRouteBase { super.redirect, this.builder, this.pageBuilder, - super.mergeObservers, + super.notifyRootObserver, required this.navigatorContainerBuilder, super.parentNavigatorKey, this.restorationScopeId, @@ -935,7 +932,7 @@ class StatefulShellRoute extends ShellRouteBase { /// for a complete runnable example using StatefulShellRoute.indexedStack. StatefulShellRoute.indexedStack({ required List branches, - bool mergeObservers = true, + bool notifyRootObserver = true, GoRouterRedirect? redirect, StatefulShellRouteBuilder? builder, GlobalKey? parentNavigatorKey, @@ -947,7 +944,7 @@ class StatefulShellRoute extends ShellRouteBase { redirect: redirect, builder: builder, pageBuilder: pageBuilder, - mergeObservers: mergeObservers, + notifyRootObserver: notifyRootObserver, parentNavigatorKey: parentNavigatorKey, restorationScopeId: restorationScopeId, navigatorContainerBuilder: _indexedStackContainerBuilder, @@ -1055,7 +1052,7 @@ class StatefulShellRoute extends ShellRouteBase { ) => StatefulNavigationShell( shellRouteContext: shellRouteContext, router: GoRouter.of(context), - mergeObservers: mergeObservers, + notifyRootObserver: notifyRootObserver, containerBuilder: navigatorContainerBuilder, ); @@ -1245,7 +1242,7 @@ class StatefulNavigationShell extends StatefulWidget { required this.shellRouteContext, required GoRouter router, required this.containerBuilder, - this.mergeObservers = true, + this.notifyRootObserver = true, }) : assert(shellRouteContext.route is StatefulShellRoute), _router = router, currentIndex = _indexOfBranchNavigatorKey( @@ -1270,8 +1267,8 @@ class StatefulNavigationShell extends StatefulWidget { /// Corresponds to the index in the branches field of [StatefulShellRoute]. final int currentIndex; - /// Same to [ShellRoute.mergeObservers]. - final bool mergeObservers; + /// Same to [ShellRoute.notifyRootObserver]. + final bool notifyRootObserver; /// The associated [StatefulShellRoute]. StatefulShellRoute get route => shellRouteContext.route as StatefulShellRoute; @@ -1718,3 +1715,65 @@ class _IndexedStackedRouteBranchContainer extends StatelessWidget { ); } } + +/// A wrapper that merges multiple [NavigatorObserver]s into a single observer. +/// +/// This is necessary because a [NavigatorObserver] can only be attached to one +/// [NavigatorState] at a time. +class _MergedNavigatorObserver extends NavigatorObserver { + /// Default constructor for the merged navigator observer. + _MergedNavigatorObserver(this.observers); + + /// The observers to be merged. + final List observers; + + @override + void didPush(Route route, Route? previousRoute) { + for (final NavigatorObserver observer in observers) { + observer.didPush(route, previousRoute); + } + } + + @override + void didPop(Route route, Route? previousRoute) { + for (final NavigatorObserver observer in observers) { + observer.didPop(route, previousRoute); + } + } + + @override + void didRemove(Route route, Route? previousRoute) { + for (final NavigatorObserver observer in observers) { + observer.didRemove(route, previousRoute); + } + } + + @override + void didReplace({Route? newRoute, Route? oldRoute}) { + for (final NavigatorObserver observer in observers) { + observer.didReplace(newRoute: newRoute, oldRoute: oldRoute); + } + } + + @override + void didChangeTop(Route topRoute, Route? previousTopRoute) { + for (final NavigatorObserver observer in observers) { + observer.didChangeTop(topRoute, previousTopRoute); + } + } + + @override + void didStartUserGesture( + Route route, Route? previousRoute) { + for (final NavigatorObserver observer in observers) { + observer.didStartUserGesture(route, previousRoute); + } + } + + @override + void didStopUserGesture() { + for (final NavigatorObserver observer in observers) { + observer.didStopUserGesture(); + } + } +} diff --git a/packages/go_router/lib/src/route_data.dart b/packages/go_router/lib/src/route_data.dart index 309363087226..83430a0018a3 100644 --- a/packages/go_router/lib/src/route_data.dart +++ b/packages/go_router/lib/src/route_data.dart @@ -314,7 +314,7 @@ abstract class ShellRouteData extends RouteData { GlobalKey? navigatorKey, GlobalKey? parentNavigatorKey, List routes = const [], - bool mergeObservers = true, + bool notifyRootObserver = true, List? observers, String? restorationScopeId, }) { @@ -343,7 +343,7 @@ abstract class ShellRouteData extends RouteData { parentNavigatorKey: parentNavigatorKey, routes: routes, navigatorKey: navigatorKey, - mergeObservers: mergeObservers, + notifyRootObserver: notifyRootObserver, observers: observers, restorationScopeId: restorationScopeId, redirect: redirect, @@ -561,12 +561,12 @@ class TypedRelativeGoRoute @Target({TargetKind.library, TargetKind.classType}) class TypedShellRoute extends TypedRoute { /// Default const constructor - const TypedShellRoute({ this.mergeObservers = true,this.routes = const >[]}); + const TypedShellRoute({ this.notifyRootObserver = true,this.routes = const >[]}); /// Determines whether the observers should be merged. /// - /// See [ShellRouteBase.mergeObservers]. - final bool mergeObservers; + /// See [ShellRouteBase.notifyRootObserver]. + final bool notifyRootObserver; /// Child route definitions. /// @@ -580,14 +580,14 @@ class TypedStatefulShellRoute extends TypedRoute { /// Default const constructor const TypedStatefulShellRoute({ - this.mergeObservers = true, + this.notifyRootObserver = true, this.branches = const >[], }); /// Determines whether the observers should be merged. /// - /// See [ShellRouteBase.mergeObservers]. - final bool mergeObservers; + /// See [ShellRouteBase.notifyRootObserver]. + final bool notifyRootObserver; /// Child route definitions. /// diff --git a/packages/go_router/test/shell_route_observers_test.dart b/packages/go_router/test/shell_route_observers_test.dart index f417d364444f..317a8d171441 100644 --- a/packages/go_router/test/shell_route_observers_test.dart +++ b/packages/go_router/test/shell_route_observers_test.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; @@ -29,35 +28,58 @@ void main() { expect(shell.observers!.length, 1); }); - testWidgets('observers should be merged', (WidgetTester tester) async { - final HeroController observer = HeroController(); - final List observers = [observer]; - addTearDown(observer.dispose); - - final GlobalKey navKey = GlobalKey(); - await createRouter( - [ - ShellRoute( - navigatorKey: navKey, - builder: (_, __, Widget child) => child, - routes: [ - GoRoute( - path: '/', - parentNavigatorKey: navKey, - builder: (_, __) => const Text('Home'), - ), - ], - ), - ], - tester, - observers: observers, - ); - await tester.pumpAndSettle(); + testWidgets( + 'GoRouter observers should be notified when navigating within ShellRoute', + (WidgetTester tester) async { + final MockObserver observer = MockObserver(); - final List shellRouteObservers = - navKey.currentState!.widget.observers; - final MergedNavigatorObserver mergedObservers = - shellRouteObservers.single as MergedNavigatorObserver; - expect(listEquals(observers, mergedObservers.observers), isTrue); - }); + final GlobalKey root = GlobalKey( + debugLabel: 'root', + ); + await createRouter( + [ + GoRoute(path: '/', builder: (_, __) => const Text('Home')), + ShellRoute( + builder: (_, __, Widget child) => child, + routes: [ + GoRoute(path: '/test1', builder: (_, __) => const Text('Test1')), + GoRoute(path: '/test2', builder: (_, __) => const Text('Test2')), + ], + ), + ], + tester, + navigatorKey: root, + observers: [observer], + ); + await tester.pumpAndSettle(); + + root.currentContext!.push('/test1'); + await tester.pumpAndSettle(); + expect(observer.getCallCount('/test1'), 1); + + root.currentContext!.push('/test2'); + await tester.pumpAndSettle(); + expect(observer.getCallCount('/test2'), 1); + }, + ); +} + +class MockObserver extends NavigatorObserver { + final Map _callCounts = {}; + + @override + void didPush(Route route, Route? previousRoute) { + final String? routeName = route.settings.name; + if (routeName != null) { + test(routeName); + } + } + + void test(String name) { + _callCounts[name] = (_callCounts[name] ?? 0) + 1; + } + + int getCallCount(String name) { + return _callCounts[name] ?? 0; + } } From c558677af615b5889885660df5dda302dcc91574 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Tue, 21 Oct 2025 16:28:46 +0800 Subject: [PATCH 06/17] code format --- packages/go_router/lib/src/route.dart | 14 +++++++------- packages/go_router/lib/src/route_data.dart | 5 ++++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/go_router/lib/src/route.dart b/packages/go_router/lib/src/route.dart index c739bb1d7751..96415c1ee2b6 100644 --- a/packages/go_router/lib/src/route.dart +++ b/packages/go_router/lib/src/route.dart @@ -501,7 +501,7 @@ abstract class ShellRouteBase extends RouteBase { this.notifyRootObserver = true, }) : super._(); - /// Whether to merge the observers of the GoRouter with the observers + /// Whether to merge the observers of the GoRouter with the observers /// of the ShellRoute. /// /// When `true`, the observers of the GoRouter will be merged with @@ -593,16 +593,14 @@ class ShellRouteContext { String? restorationScopeId, ) { final List effectiveObservers = [ - ...?observers + ...?observers, ]; if (notifyRootObserver) { final List? rootObservers = GoRouter.maybeOf(context)?.observers; if (rootObservers != null) { - effectiveObservers.add(_MergedNavigatorObserver( - rootObservers, - )); + effectiveObservers.add(_MergedNavigatorObserver(rootObservers)); } } @@ -1717,7 +1715,7 @@ class _IndexedStackedRouteBranchContainer extends StatelessWidget { } /// A wrapper that merges multiple [NavigatorObserver]s into a single observer. -/// +/// /// This is necessary because a [NavigatorObserver] can only be attached to one /// [NavigatorState] at a time. class _MergedNavigatorObserver extends NavigatorObserver { @@ -1764,7 +1762,9 @@ class _MergedNavigatorObserver extends NavigatorObserver { @override void didStartUserGesture( - Route route, Route? previousRoute) { + Route route, + Route? previousRoute, + ) { for (final NavigatorObserver observer in observers) { observer.didStartUserGesture(route, previousRoute); } diff --git a/packages/go_router/lib/src/route_data.dart b/packages/go_router/lib/src/route_data.dart index 83430a0018a3..a57510bedb5e 100644 --- a/packages/go_router/lib/src/route_data.dart +++ b/packages/go_router/lib/src/route_data.dart @@ -561,7 +561,10 @@ class TypedRelativeGoRoute @Target({TargetKind.library, TargetKind.classType}) class TypedShellRoute extends TypedRoute { /// Default const constructor - const TypedShellRoute({ this.notifyRootObserver = true,this.routes = const >[]}); + const TypedShellRoute({ + this.notifyRootObserver = true, + this.routes = const >[], + }); /// Determines whether the observers should be merged. /// From f9d68846e3ab1350a9a7c065eef5cc8710cac75f Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Tue, 21 Oct 2025 16:31:40 +0800 Subject: [PATCH 07/17] update package version --- packages/go_router/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml index b474000e38b5..a65ff345c7de 100644 --- a/packages/go_router/pubspec.yaml +++ b/packages/go_router/pubspec.yaml @@ -1,7 +1,7 @@ name: go_router description: A declarative router for Flutter based on Navigation 2 supporting deep linking, data-driven routes and more -version: 16.2.5 +version: 17.0.0 repository: https://github.com/flutter/packages/tree/main/packages/go_router issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22 From 2b4491c1cdabe449d458168ed9803a5ad4f5cee6 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Wed, 22 Oct 2025 15:38:28 +0800 Subject: [PATCH 08/17] add test for `StatefulShellRoute` --- packages/go_router/lib/src/route.dart | 2 +- .../go_router/test/shell_route_observers_test.dart | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/go_router/lib/src/route.dart b/packages/go_router/lib/src/route.dart index 96415c1ee2b6..32c47ec5a595 100644 --- a/packages/go_router/lib/src/route.dart +++ b/packages/go_router/lib/src/route.dart @@ -1461,7 +1461,7 @@ class StatefulNavigationShellState extends State branchState.navigator = shellRouteContext._buildNavigatorForCurrentRoute( context, branch.observers, - false, + widget.notifyRootObserver, branch.restorationScopeId, ); } diff --git a/packages/go_router/test/shell_route_observers_test.dart b/packages/go_router/test/shell_route_observers_test.dart index 317a8d171441..068265558cd6 100644 --- a/packages/go_router/test/shell_route_observers_test.dart +++ b/packages/go_router/test/shell_route_observers_test.dart @@ -43,7 +43,16 @@ void main() { builder: (_, __, Widget child) => child, routes: [ GoRoute(path: '/test1', builder: (_, __) => const Text('Test1')), - GoRoute(path: '/test2', builder: (_, __) => const Text('Test2')), + ], + ), + StatefulShellRoute.indexedStack( + builder: (_, __, Widget child) => child, + branches: [ + StatefulShellBranch( + routes: [ + GoRoute(path: '/test2', builder: (_, __) => const Text('Test2')), + ], + ), ], ), ], From 45ba7eac700d4216e9b7ecbba0d5d2eac13786c5 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Wed, 22 Oct 2025 15:49:41 +0800 Subject: [PATCH 09/17] update `README.md` --- packages/go_router/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/go_router/README.md b/packages/go_router/README.md index b84638719630..40a1319c7d47 100644 --- a/packages/go_router/README.md +++ b/packages/go_router/README.md @@ -38,6 +38,7 @@ See the API documentation for details on the following topics: - [State restoration](https://pub.dev/documentation/go_router/latest/topics/State%20restoration-topic.html) ## Migration Guides +- [Migrating to 17.0.0](https://flutter.dev/go/go-router-v17-breaking-changes). - [Migrating to 16.0.0](https://flutter.dev/go/go-router-v16-breaking-changes). - [Migrating to 15.0.0](https://flutter.dev/go/go-router-v15-breaking-changes). - [Migrating to 14.0.0](https://flutter.dev/go/go-router-v14-breaking-changes). From f710a9431d3093957e787eb7fcd26fd100937c64 Mon Sep 17 00:00:00 2001 From: hhh <65709676+huanghui1998hhh@users.noreply.github.com> Date: Thu, 23 Oct 2025 13:35:21 +0800 Subject: [PATCH 10/17] Update packages/go_router/lib/src/route.dart Co-authored-by: chunhtai <47866232+chunhtai@users.noreply.github.com> --- packages/go_router/lib/src/route.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/go_router/lib/src/route.dart b/packages/go_router/lib/src/route.dart index 32c47ec5a595..55f48c8beaf1 100644 --- a/packages/go_router/lib/src/route.dart +++ b/packages/go_router/lib/src/route.dart @@ -504,7 +504,7 @@ abstract class ShellRouteBase extends RouteBase { /// Whether to merge the observers of the GoRouter with the observers /// of the ShellRoute. /// - /// When `true`, the observers of the GoRouter will be merged with + /// When `true`, navigation changes within this shell route will notify the GoRouter's observers. /// the observers of the ShellRoute. /// /// Defaults to `true`. From 549020886ac657d56d6d328444554413c20928e5 Mon Sep 17 00:00:00 2001 From: hhh <65709676+huanghui1998hhh@users.noreply.github.com> Date: Thu, 23 Oct 2025 13:35:32 +0800 Subject: [PATCH 11/17] Update packages/go_router/lib/src/route.dart Co-authored-by: chunhtai <47866232+chunhtai@users.noreply.github.com> --- packages/go_router/lib/src/route.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/go_router/lib/src/route.dart b/packages/go_router/lib/src/route.dart index 55f48c8beaf1..22d5d76a5a3f 100644 --- a/packages/go_router/lib/src/route.dart +++ b/packages/go_router/lib/src/route.dart @@ -501,7 +501,7 @@ abstract class ShellRouteBase extends RouteBase { this.notifyRootObserver = true, }) : super._(); - /// Whether to merge the observers of the GoRouter with the observers + /// Whether navigation changes will notify the GoRouter's observers. /// of the ShellRoute. /// /// When `true`, navigation changes within this shell route will notify the GoRouter's observers. From a313e2690787b71450257e4df460116c063bdd6b Mon Sep 17 00:00:00 2001 From: hhh <65709676+huanghui1998hhh@users.noreply.github.com> Date: Thu, 23 Oct 2025 13:35:51 +0800 Subject: [PATCH 12/17] Update packages/go_router/lib/src/route.dart Co-authored-by: chunhtai <47866232+chunhtai@users.noreply.github.com> --- packages/go_router/lib/src/route.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/go_router/lib/src/route.dart b/packages/go_router/lib/src/route.dart index 22d5d76a5a3f..bbacf5ad3386 100644 --- a/packages/go_router/lib/src/route.dart +++ b/packages/go_router/lib/src/route.dart @@ -1265,7 +1265,9 @@ class StatefulNavigationShell extends StatefulWidget { /// Corresponds to the index in the branches field of [StatefulShellRoute]. final int currentIndex; - /// Same to [ShellRoute.notifyRootObserver]. + /// Whether navigation changes will notify the GoRouter's observers. + /// + /// Same as [ShellRoute.notifyRootObserver]. final bool notifyRootObserver; /// The associated [StatefulShellRoute]. From 01b9c4fc08711889b468dabe22174da466011ba6 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Thu, 23 Oct 2025 14:05:41 +0800 Subject: [PATCH 13/17] Update comments for `ShellRouteBase.notifyRootObserver` --- packages/go_router/lib/src/route.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/go_router/lib/src/route.dart b/packages/go_router/lib/src/route.dart index bbacf5ad3386..b1467fc2995c 100644 --- a/packages/go_router/lib/src/route.dart +++ b/packages/go_router/lib/src/route.dart @@ -502,10 +502,9 @@ abstract class ShellRouteBase extends RouteBase { }) : super._(); /// Whether navigation changes will notify the GoRouter's observers. - /// of the ShellRoute. /// - /// When `true`, navigation changes within this shell route will notify the GoRouter's observers. - /// the observers of the ShellRoute. + /// When `true`, navigation changes within this shell route will notify + /// the GoRouter's observers. /// /// Defaults to `true`. final bool notifyRootObserver; From dc60e9064ca6d889b49e0efb34169400c7dbf433 Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Thu, 23 Oct 2025 14:55:54 +0800 Subject: [PATCH 14/17] Remove `StatefulNavigationShell.notifyRootObserver` and use `StatefulShellRoute.notifyRootObserver` instead --- packages/go_router/lib/src/route.dart | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/go_router/lib/src/route.dart b/packages/go_router/lib/src/route.dart index b1467fc2995c..6d66ed791857 100644 --- a/packages/go_router/lib/src/route.dart +++ b/packages/go_router/lib/src/route.dart @@ -1049,7 +1049,6 @@ class StatefulShellRoute extends ShellRouteBase { ) => StatefulNavigationShell( shellRouteContext: shellRouteContext, router: GoRouter.of(context), - notifyRootObserver: notifyRootObserver, containerBuilder: navigatorContainerBuilder, ); @@ -1239,7 +1238,6 @@ class StatefulNavigationShell extends StatefulWidget { required this.shellRouteContext, required GoRouter router, required this.containerBuilder, - this.notifyRootObserver = true, }) : assert(shellRouteContext.route is StatefulShellRoute), _router = router, currentIndex = _indexOfBranchNavigatorKey( @@ -1264,11 +1262,6 @@ class StatefulNavigationShell extends StatefulWidget { /// Corresponds to the index in the branches field of [StatefulShellRoute]. final int currentIndex; - /// Whether navigation changes will notify the GoRouter's observers. - /// - /// Same as [ShellRoute.notifyRootObserver]. - final bool notifyRootObserver; - /// The associated [StatefulShellRoute]. StatefulShellRoute get route => shellRouteContext.route as StatefulShellRoute; @@ -1462,7 +1455,7 @@ class StatefulNavigationShellState extends State branchState.navigator = shellRouteContext._buildNavigatorForCurrentRoute( context, branch.observers, - widget.notifyRootObserver, + route.notifyRootObserver, branch.restorationScopeId, ); } From 4ae512bb357cfc17c614873d6e84e979cef2a07a Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Thu, 23 Oct 2025 14:56:12 +0800 Subject: [PATCH 15/17] code format --- packages/go_router/test/shell_route_observers_test.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/go_router/test/shell_route_observers_test.dart b/packages/go_router/test/shell_route_observers_test.dart index 068265558cd6..8f803602670d 100644 --- a/packages/go_router/test/shell_route_observers_test.dart +++ b/packages/go_router/test/shell_route_observers_test.dart @@ -50,7 +50,10 @@ void main() { branches: [ StatefulShellBranch( routes: [ - GoRoute(path: '/test2', builder: (_, __) => const Text('Test2')), + GoRoute( + path: '/test2', + builder: (_, __) => const Text('Test2'), + ), ], ), ], From b6214c28aeb0d64bc7cbc9d4bc68ab22c15c03fa Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Thu, 23 Oct 2025 15:03:53 +0800 Subject: [PATCH 16/17] Update CHANGELOG.md --- packages/go_router/CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md index 2ca07c934ab5..12a6b980934c 100644 --- a/packages/go_router/CHANGELOG.md +++ b/packages/go_router/CHANGELOG.md @@ -1,9 +1,9 @@ ## 17.0.0 - **BREAKING CHANGE** - - `ShellRoute` will auto merge the `observers` passed into `GoRouter`. - - Adds `notifyRootObserver` to `ShellRouteBase`, `ShellRoute`, `StatefulShellRoute`, `ShellRouteData.$route`. - + - `ShellRoute`'s navigating changes notify `GoRouter`'s observers by default. + - Adds `notifyRootObserver` to `ShellRouteBase`, `ShellRoute`, `StatefulShellRoute`, `ShellRouteData.$route`, `TypedShellRoute`, `TypedStatefulShellRoute`. + ## 16.3.0 - Adds a top-level `onEnter` callback with access to current and next route states. From e6615691dd4c2f8a4c1af5394c51b7f8af994b5c Mon Sep 17 00:00:00 2001 From: hhh <1224991097@qq.com> Date: Thu, 23 Oct 2025 15:10:00 +0800 Subject: [PATCH 17/17] update comments for `TypedShellRoute`, `TypedStatefulShellRoute` --- packages/go_router/lib/src/route_data.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/go_router/lib/src/route_data.dart b/packages/go_router/lib/src/route_data.dart index a57510bedb5e..9a8f3bf8e7e4 100644 --- a/packages/go_router/lib/src/route_data.dart +++ b/packages/go_router/lib/src/route_data.dart @@ -566,7 +566,8 @@ class TypedShellRoute extends TypedRoute { this.routes = const >[], }); - /// Determines whether the observers should be merged. + /// Whether navigation changes within this shell route will notify the + /// GoRouter's observers. /// /// See [ShellRouteBase.notifyRootObserver]. final bool notifyRootObserver; @@ -587,7 +588,8 @@ class TypedStatefulShellRoute this.branches = const >[], }); - /// Determines whether the observers should be merged. + /// Whether navigation changes within this shell route will notify the + /// GoRouter's observers. /// /// See [ShellRouteBase.notifyRootObserver]. final bool notifyRootObserver;