diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md index d8ce441d9980..a52afff1b9cf 100644 --- a/packages/go_router/CHANGELOG.md +++ b/packages/go_router/CHANGELOG.md @@ -1,3 +1,10 @@ +## 11.0.0 + +- Fixes the GoRouter.goBranch so that it doesn't reset extra to null if extra is not serializable. +- **BREAKING CHANGE**: + - Updates the function signature of `GoRouteInformationProvider.restore`. + - Adds `NavigationType.restore` to `NavigationType` enum. + ## 10.2.0 - Adds `onExit` to GoRoute. diff --git a/packages/go_router/README.md b/packages/go_router/README.md index 0a72dd18d200..f2cd542f95ba 100644 --- a/packages/go_router/README.md +++ b/packages/go_router/README.md @@ -37,6 +37,7 @@ See the API documentation for details on the following topics: - [Error handling](https://pub.dev/documentation/go_router/latest/topics/Error%20handling-topic.html) ## Migration Guides +- [Migrating to 11.0.0](https://flutter.dev/go/go-router-v11-breaking-changes). - [Migrating to 10.0.0](https://flutter.dev/go/go-router-v10-breaking-changes). - [Migrating to 9.0.0](https://flutter.dev/go/go-router-v9-breaking-changes). - [Migrating to 8.0.0](https://flutter.dev/go/go-router-v8-breaking-changes). diff --git a/packages/go_router/lib/src/information_provider.dart b/packages/go_router/lib/src/information_provider.dart index 31a9e6942799..9346c2a20b03 100644 --- a/packages/go_router/lib/src/information_provider.dart +++ b/packages/go_router/lib/src/information_provider.dart @@ -33,6 +33,10 @@ enum NavigatingType { /// Replace the entire [RouteMatchList] with the new location. go, + + /// Restore the current match list with + /// [RouteInformationState.baseRouteMatchList]. + restore, } /// The data class to be stored in [RouteInformation.state] to be used by @@ -48,8 +52,9 @@ class RouteInformationState { this.completer, this.baseRouteMatchList, required this.type, - }) : assert((type != NavigatingType.go) == - (completer != null && baseRouteMatchList != null)); + }) : assert((type == NavigatingType.go || type == NavigatingType.restore) == + (completer == null)), + assert((type != NavigatingType.go) == (baseRouteMatchList != null)); /// The extra object used when navigating with [GoRouter]. final Object? extra; @@ -57,7 +62,8 @@ class RouteInformationState { /// The completer that needs to be completed when the newly added route is /// popped off the screen. /// - /// This is only null if [type] is [NavigatingType.go]. + /// This is only null if [type] is [NavigatingType.go] or + /// [NavigatingType.restore]. final Completer? completer; /// The base route match list to push on top to. @@ -177,11 +183,15 @@ class GoRouteInformationProvider extends RouteInformationProvider ); } - /// Restores the current route matches with the `encodedMatchList`. - void restore(String location, {required Object encodedMatchList}) { + /// Restores the current route matches with the `matchList`. + void restore(String location, {required RouteMatchList matchList}) { _setValue( - location, - encodedMatchList, + matchList.uri.toString(), + RouteInformationState( + extra: matchList.extra, + baseRouteMatchList: matchList, + type: NavigatingType.restore, + ), ); } diff --git a/packages/go_router/lib/src/parser.dart b/packages/go_router/lib/src/parser.dart index cc5ca7039cb4..41f6ef875cf7 100644 --- a/packages/go_router/lib/src/parser.dart +++ b/packages/go_router/lib/src/parser.dart @@ -193,6 +193,11 @@ class GoRouteInformationParser extends RouteInformationParser { ); case NavigatingType.go: return newMatchList; + case NavigatingType.restore: + // Still need to consider redirection. + return baseRouteMatchList!.uri.toString() == newMatchList.uri.toString() + ? baseRouteMatchList + : newMatchList; } } diff --git a/packages/go_router/lib/src/router.dart b/packages/go_router/lib/src/router.dart index a5671e2fc9d0..e37151d4ffee 100644 --- a/packages/go_router/lib/src/router.dart +++ b/packages/go_router/lib/src/router.dart @@ -327,7 +327,7 @@ class GoRouter implements RouterConfig { log.info('restoring ${matchList.uri}'); routeInformationProvider.restore( matchList.uri.toString(), - encodedMatchList: RouteMatchListCodec(configuration).encode(matchList), + matchList: matchList, ); } diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml index 128569f1f1a1..4e3ba3dcbadd 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: 10.2.0 +version: 11.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 diff --git a/packages/go_router/test/go_router_test.dart b/packages/go_router/test/go_router_test.dart index 2d670296dae3..107e828e2945 100644 --- a/packages/go_router/test/go_router_test.dart +++ b/packages/go_router/test/go_router_test.dart @@ -2843,6 +2843,52 @@ void main() { expect(matches.pathParameters['pid'], pid); }); + testWidgets('StatefulShellRoute preserve extra when switching branch', + (WidgetTester tester) async { + StatefulNavigationShell? routeState; + Object? latestExtra; + final List routes = [ + StatefulShellRoute.indexedStack( + builder: (BuildContext context, GoRouterState state, + StatefulNavigationShell navigationShell) { + routeState = navigationShell; + return navigationShell; + }, + branches: [ + StatefulShellBranch( + routes: [ + GoRoute( + path: '/a', + builder: (BuildContext context, GoRouterState state) => + const Text('Screen A'), + ), + ], + ), + StatefulShellBranch( + routes: [ + GoRoute( + path: '/b', + builder: (BuildContext context, GoRouterState state) { + latestExtra = state.extra; + return const DummyScreen(); + }), + ], + ), + ], + ), + ]; + final Object expectedExtra = Object(); + + await createRouter(routes, tester, + initialLocation: '/b', initialExtra: expectedExtra); + expect(latestExtra, expectedExtra); + routeState!.goBranch(0); + await tester.pumpAndSettle(); + routeState!.goBranch(1); + await tester.pumpAndSettle(); + expect(latestExtra, expectedExtra); + }); + testWidgets('goNames should allow dynamics values for queryParams', (WidgetTester tester) async { const Map queryParametersAll = >{