diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md index f1d95f90c9fc..ada12fc5780d 100644 --- a/packages/go_router/CHANGELOG.md +++ b/packages/go_router/CHANGELOG.md @@ -1,3 +1,7 @@ +## 17.2.0 + +- Adds `overrideOnExit` parameter to `TypedGoRoute` and `TypedRelativeGoRoute` to control whether the `onExit` method of route data classes should be invoked. + ## 17.1.0 - Adds `TypedQueryParameter` annotation to override parameter names in `TypedGoRoute` constructors. diff --git a/packages/go_router/lib/src/route_data.dart b/packages/go_router/lib/src/route_data.dart index 373efcb1d0cb..a1dcb2850b47 100644 --- a/packages/go_router/lib/src/route_data.dart +++ b/packages/go_router/lib/src/route_data.dart @@ -90,19 +90,20 @@ class _GoRouteParameters { required this.builder, required this.pageBuilder, required this.redirect, - required this.onExit, + this.onExit, }); final GoRouterWidgetBuilder builder; final GoRouterPageBuilder pageBuilder; final GoRouterRedirect redirect; - final ExitCallback onExit; + final ExitCallback? onExit; } /// Helper to create [GoRoute] parameters from a factory function and an Expando. _GoRouteParameters _createGoRouteParameters({ required T Function(GoRouterState) factory, required Expando<_GoRouteDataBase> expando, + bool overrideOnExit = false, }) { T factoryImpl(GoRouterState state) { final Object? extra = state.extra; @@ -123,8 +124,10 @@ _GoRouteParameters _createGoRouteParameters({ factoryImpl(state).buildPage(context, state), redirect: (BuildContext context, GoRouterState state) => factoryImpl(state).redirect(context, state), - onExit: (BuildContext context, GoRouterState state) => - factoryImpl(state).onExit(context, state), + onExit: overrideOnExit + ? (BuildContext context, GoRouterState state) => + factoryImpl(state).onExit(context, state) + : null, ); } @@ -156,10 +159,12 @@ abstract class GoRouteData extends _GoRouteDataBase { required T Function(GoRouterState) factory, GlobalKey? parentNavigatorKey, List routes = const [], + bool overrideOnExit = false, }) { final _GoRouteParameters params = _createGoRouteParameters( factory: factory, expando: _GoRouteDataBase.stateObjectExpando, + overrideOnExit: overrideOnExit, ); return GoRoute( @@ -227,10 +232,12 @@ abstract class RelativeGoRouteData extends _GoRouteDataBase { required T Function(GoRouterState) factory, GlobalKey? parentNavigatorKey, List routes = const [], + bool overrideOnExit = false, }) { final _GoRouteParameters params = _createGoRouteParameters( factory: factory, expando: _GoRouteDataBase.stateObjectExpando, + overrideOnExit: overrideOnExit, ); return GoRoute( @@ -483,6 +490,7 @@ class TypedGoRoute extends TypedRoute { this.name, this.routes = const >[], this.caseSensitive = true, + this.overrideOnExit = false, }); /// The path that corresponds to this route. @@ -515,6 +523,18 @@ class TypedGoRoute extends TypedRoute { /// /// Defaults to `true`. final bool caseSensitive; + + /// Whether to override the default behavior of [GoRoute.onExit] to invoke the + /// [GoRouteData.onExit] method of the route data class. + /// + /// When `true`, the [GoRouteData.onExit] method will be invoked when + /// the route is removed from GoRouter's route history. + /// + /// When `false`, the default behavior is used, which does not invoke + /// the [GoRouteData.onExit] method. + /// + /// Defaults to `false`. + final bool overrideOnExit; } /// A superclass for each typed relative go route descendant @@ -526,6 +546,7 @@ class TypedRelativeGoRoute required this.path, this.routes = const >[], this.caseSensitive = true, + this.overrideOnExit = false, }); /// The relative path that corresponds to this route. @@ -550,6 +571,18 @@ class TypedRelativeGoRoute /// /// Defaults to `true`. final bool caseSensitive; + + /// Whether to override the default behavior of [GoRoute.onExit] to invoke the + /// [RelativeGoRouteData.onExit] method of the route data class. + /// + /// When `true`, the [RelativeGoRouteData.onExit] method will be invoked when + /// the route is removed from GoRouter's route history. + /// + /// When `false`, the default behavior is used, which does not invoke + /// the [RelativeGoRouteData.onExit] method. + /// + /// Defaults to `false`. + final bool overrideOnExit; } /// A superclass for each typed shell route descendant diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml index 55ad56b1058c..a397f17cf850 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: 17.1.0 +version: 17.2.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 diff --git a/packages/go_router/test/route_data_test.dart b/packages/go_router/test/route_data_test.dart index a6a81b385762..00badafe7328 100644 --- a/packages/go_router/test/route_data_test.dart +++ b/packages/go_router/test/route_data_test.dart @@ -701,6 +701,7 @@ void main() { expect(typedGoRoute.path, '/path'); expect(typedGoRoute.name, isNull); expect(typedGoRoute.caseSensitive, true); + expect(typedGoRoute.overrideOnExit, false); expect(typedGoRoute.routes, isEmpty); }); @@ -709,11 +710,13 @@ void main() { path: '/path', name: 'name', caseSensitive: false, + overrideOnExit: true, routes: >[ TypedGoRoute( path: 'sub-path', name: 'subName', caseSensitive: false, + overrideOnExit: true, ), ], ); @@ -721,6 +724,7 @@ void main() { expect(typedGoRoute.path, '/path'); expect(typedGoRoute.name, 'name'); expect(typedGoRoute.caseSensitive, false); + expect(typedGoRoute.overrideOnExit, true); expect(typedGoRoute.routes, hasLength(1)); expect( typedGoRoute.routes.single, @@ -739,6 +743,11 @@ void main() { (TypedGoRoute route) => route.caseSensitive, 'caseSensitive', false, + ) + .having( + (TypedGoRoute route) => route.overrideOnExit, + 'overrideOnExit', + true, ), ); }); @@ -760,6 +769,7 @@ void main() { expect(typedGoRoute.path, 'path'); expect(typedGoRoute.caseSensitive, true); + expect(typedGoRoute.overrideOnExit, false); expect(typedGoRoute.routes, isEmpty); }); @@ -767,16 +777,19 @@ void main() { const typedGoRoute = TypedRelativeGoRoute( path: 'path', caseSensitive: false, + overrideOnExit: true, routes: >[ TypedRelativeGoRoute( path: 'sub-path', caseSensitive: false, + overrideOnExit: true, ), ], ); expect(typedGoRoute.path, 'path'); expect(typedGoRoute.caseSensitive, false); + expect(typedGoRoute.overrideOnExit, true); expect(typedGoRoute.routes, hasLength(1)); expect( typedGoRoute.routes.single, @@ -791,6 +804,12 @@ void main() { route.caseSensitive, 'caseSensitive', false, + ) + .having( + (TypedRelativeGoRoute route) => + route.overrideOnExit, + 'overrideOnExit', + true, ), ); });