diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md index b11aeb452d..075e950d61 100644 --- a/packages/go_router/CHANGELOG.md +++ b/packages/go_router/CHANGELOG.md @@ -1,3 +1,13 @@ +## 6.0.0 + +- **BREAKING CHANGE** + - `GoRouteData`'s `redirect` now takes 2 parameters `BuildContext context, GoRouterState state`. + - `GoRouteData`'s `build` now takes 2 parameters `BuildContext context, GoRouterState state`. + - `GoRouteData`'s `buildPageWithState` has been removed and replaced by `buildPage` with now takes 2 parameters `BuildContext context, GoRouterState state`. + - `replace` from `GoRouter`, `GoRouterDelegate` and `GoRouterHelper` has been renamed into `pushReplacement`. + - `replaceNamed` from `GoRouter`, `GoRouterDelegate` and `GoRouterHelper` has been renamed into `pushReplacementNamed`. + - [go_router v6 migration guide](https://flutter.dev/go/go-router-v6-breaking-changes) + ## 5.2.4 - Fixes crashes when using async redirect. diff --git a/packages/go_router/README.md b/packages/go_router/README.md index b0cd9ab19a..daed219153 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 6.0.0](https://flutter.dev/go/go-router-v6-breaking-changes) - [Migrating to 5.1.2](https://flutter.dev/go/go-router-v5-1-2-breaking-changes) - [Migrating to 5.0](https://flutter.dev/go/go-router-v5-breaking-changes) - [Migrating to 4.0](https://flutter.dev/go/go-router-v4-breaking-changes) diff --git a/packages/go_router/lib/src/delegate.dart b/packages/go_router/lib/src/delegate.dart index 82a6e6d28c..b34aac04f8 100644 --- a/packages/go_router/lib/src/delegate.dart +++ b/packages/go_router/lib/src/delegate.dart @@ -145,7 +145,7 @@ class GoRouterDelegate extends RouterDelegate /// /// See also: /// * [push] which pushes the given location onto the page stack. - void replace(RouteMatchList matches) { + void pushReplacement(RouteMatchList matches) { _matchList.pop(); push(matches); // [push] will notify the listeners. } diff --git a/packages/go_router/lib/src/misc/extensions.dart b/packages/go_router/lib/src/misc/extensions.dart index 65e45cba34..7030ad3c25 100644 --- a/packages/go_router/lib/src/misc/extensions.dart +++ b/packages/go_router/lib/src/misc/extensions.dart @@ -67,8 +67,8 @@ extension GoRouterHelper on BuildContext { /// See also: /// * [go] which navigates to the location. /// * [push] which pushes the location onto the page stack. - void replace(String location, {Object? extra}) => - GoRouter.of(this).replace(location, extra: extra); + void pushReplacement(String location, {Object? extra}) => + GoRouter.of(this).pushReplacement(location, extra: extra); /// Replaces the top-most page of the page stack with the named route w/ /// optional parameters, e.g. `name='person', params={'fid': 'f2', 'pid': @@ -77,13 +77,13 @@ extension GoRouterHelper on BuildContext { /// See also: /// * [goNamed] which navigates a named route. /// * [pushNamed] which pushes a named route onto the page stack. - void replaceNamed( + void pushReplacementNamed( String name, { Map params = const {}, Map queryParams = const {}, Object? extra, }) => - GoRouter.of(this).replaceNamed( + GoRouter.of(this).pushReplacementNamed( name, params: params, queryParams: queryParams, diff --git a/packages/go_router/lib/src/route_data.dart b/packages/go_router/lib/src/route_data.dart index ba862d0677..efa9e85a46 100644 --- a/packages/go_router/lib/src/route_data.dart +++ b/packages/go_router/lib/src/route_data.dart @@ -14,7 +14,7 @@ import 'state.dart'; /// Baseclass for supporting /// [Type-safe routing](https://pub.dev/documentation/go_router/latest/topics/Type-safe%20routes-topic.html). /// -/// Subclasses must override one of [build], [buildPageWithState], or +/// Subclasses must override one of [build], [buildPage], or /// [redirect]. /// {@category Type-safe routes} abstract class GoRouteData { @@ -25,53 +25,36 @@ abstract class GoRouteData { /// Creates the [Widget] for `this` route. /// - /// Subclasses must override one of [build], [buildPageWithState], or + /// Subclasses must override one of [build], [buildPage], or /// [redirect]. /// /// Corresponds to [GoRoute.builder]. - Widget build(BuildContext context) => throw UnimplementedError( - 'One of `build` or `buildPageWithState` must be implemented.', + Widget build(BuildContext context, GoRouterState state) => + throw UnimplementedError( + 'One of `build` or `buildPage` must be implemented.', ); /// A page builder for this route. /// /// Subclasses can override this function to provide a custom [Page]. /// - /// Subclasses must override one of [build], [buildPageWithState] or + /// Subclasses must override one of [build], [buildPage] or /// [redirect]. /// /// Corresponds to [GoRoute.pageBuilder]. /// /// By default, returns a [Page] instance that is ignored, causing a default /// [Page] implementation to be used with the results of [build]. - @Deprecated( - 'This method has been deprecated in favor of buildPageWithState. ' - 'This feature was deprecated after v4.3.0.', - ) - Page buildPage(BuildContext context) => const NoOpPage(); - - /// A page builder for this route with [GoRouterState]. - /// - /// Subclasses can override this function to provide a custom [Page]. - /// - /// Subclasses must override one of [build], [buildPageWithState] or - /// [redirect]. - /// - /// Corresponds to [GoRoute.pageBuilder]. - /// - /// By default, returns a [Page] instance that is ignored, causing a default - /// [Page] implementation to be used with the results of [build]. - Page buildPageWithState(BuildContext context, GoRouterState state) => - // ignore: deprecated_member_use_from_same_package - buildPage(context); + Page buildPage(BuildContext context, GoRouterState state) => + const NoOpPage(); /// An optional redirect function for this route. /// - /// Subclasses must override one of [build], [buildPageWithState], or + /// Subclasses must override one of [build], [buildPage], or /// [redirect]. /// /// Corresponds to [GoRoute.redirect]. - FutureOr redirect() => null; + FutureOr redirect(BuildContext context, GoRouterState state) => null; /// A helper function used by generated code. /// @@ -106,13 +89,13 @@ abstract class GoRouteData { } Widget builder(BuildContext context, GoRouterState state) => - factoryImpl(state).build(context); + factoryImpl(state).build(context, state); Page pageBuilder(BuildContext context, GoRouterState state) => - factoryImpl(state).buildPageWithState(context, state); + factoryImpl(state).buildPage(context, state); FutureOr redirect(BuildContext context, GoRouterState state) => - factoryImpl(state).redirect(); + factoryImpl(state).redirect(context, state); return GoRoute( path: path, diff --git a/packages/go_router/lib/src/router.dart b/packages/go_router/lib/src/router.dart index c3fb0a837b..73a86c645d 100644 --- a/packages/go_router/lib/src/router.dart +++ b/packages/go_router/lib/src/router.dart @@ -240,7 +240,7 @@ class GoRouter extends ChangeNotifier implements RouterConfig { /// See also: /// * [go] which navigates to the location. /// * [push] which pushes the location onto the page stack. - void replace(String location, {Object? extra}) { + void pushReplacement(String location, {Object? extra}) { routeInformationParser .parseRouteInformationWithDependencies( RouteInformation(location: location, state: extra), @@ -249,7 +249,7 @@ class GoRouter extends ChangeNotifier implements RouterConfig { _routerDelegate.navigatorKey.currentContext!, ) .then((RouteMatchList matchList) { - routerDelegate.replace(matchList); + routerDelegate.pushReplacement(matchList); }); } @@ -260,13 +260,13 @@ class GoRouter extends ChangeNotifier implements RouterConfig { /// See also: /// * [goNamed] which navigates a named route. /// * [pushNamed] which pushes a named route onto the page stack. - void replaceNamed( + void pushReplacementNamed( String name, { Map params = const {}, Map queryParams = const {}, Object? extra, }) { - replace( + pushReplacement( namedLocation(name, params: params, queryParams: queryParams), extra: extra, ); diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml index af92f1ccb7..edcfd0a077 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: 5.2.4 +version: 6.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/delegate_test.dart b/packages/go_router/test/delegate_test.dart index 7df8504c33..62f4b691d9 100644 --- a/packages/go_router/test/delegate_test.dart +++ b/packages/go_router/test/delegate_test.dart @@ -106,7 +106,7 @@ void main() { ); }); - group('replace', () { + group('pushReplacement', () { testWidgets('It should replace the last match with the given one', (WidgetTester tester) async { final GoRouter goRouter = GoRouter( @@ -128,7 +128,7 @@ void main() { goRouter.routerDelegate.addListener(expectAsync0(() {})); final RouteMatch first = goRouter.routerDelegate.matches.matches.first; final RouteMatch last = goRouter.routerDelegate.matches.last; - goRouter.replace('/page-1'); + goRouter.pushReplacement('/page-1'); expect(goRouter.routerDelegate.matches.matches.length, 2); expect( goRouter.routerDelegate.matches.matches.first, @@ -169,7 +169,7 @@ void main() { const Key('/a-p1'), ); - goRouter.replace('/a'); + goRouter.pushReplacement('/a'); await tester.pumpAndSettle(); expect(goRouter.routerDelegate.matches.matches.length, 2); @@ -181,7 +181,7 @@ void main() { ); }); - group('replaceNamed', () { + group('pushReplacementNamed', () { testWidgets( 'It should replace the last match with the given one', (WidgetTester tester) async { @@ -210,7 +210,7 @@ void main() { goRouter.routerDelegate.addListener(expectAsync0(() {})); final RouteMatch first = goRouter.routerDelegate.matches.matches.first; final RouteMatch last = goRouter.routerDelegate.matches.last; - goRouter.replaceNamed('page1'); + goRouter.pushReplacementNamed('page1'); expect(goRouter.routerDelegate.matches.matches.length, 2); expect( goRouter.routerDelegate.matches.matches.first, diff --git a/packages/go_router/test/route_data_test.dart b/packages/go_router/test/route_data_test.dart index 4ae12f6dfb..6c8a49a666 100644 --- a/packages/go_router/test/route_data_test.dart +++ b/packages/go_router/test/route_data_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; @@ -9,7 +11,8 @@ import 'package:go_router/go_router.dart'; class _GoRouteDataBuild extends GoRouteData { const _GoRouteDataBuild(); @override - Widget build(BuildContext context) => const SizedBox(key: Key('build')); + Widget build(BuildContext context, GoRouterState state) => + const SizedBox(key: Key('build')); } final GoRoute _goRouteDataBuild = GoRouteData.$route( @@ -20,7 +23,8 @@ final GoRoute _goRouteDataBuild = GoRouteData.$route( class _GoRouteDataBuildPage extends GoRouteData { const _GoRouteDataBuildPage(); @override - Page buildPage(BuildContext context) => const MaterialPage( + Page buildPage(BuildContext context, GoRouterState state) => + const MaterialPage( child: SizedBox(key: Key('buildPage')), ); } @@ -30,24 +34,22 @@ final GoRoute _goRouteDataBuildPage = GoRouteData.$route( factory: (GoRouterState state) => const _GoRouteDataBuildPage(), ); -class _GoRouteDataBuildPageWithState extends GoRouteData { - const _GoRouteDataBuildPageWithState(); +class _GoRouteDataRedirectPage extends GoRouteData { + const _GoRouteDataRedirectPage(); @override - Page buildPageWithState(BuildContext context, GoRouterState state) => - const MaterialPage( - child: SizedBox(key: Key('buildPageWithState')), - ); + FutureOr redirect(BuildContext context, GoRouterState state) => + '/build-page'; } -final GoRoute _goRouteDataBuildPageWithState = GoRouteData.$route( - path: '/build-page-with-state', - factory: (GoRouterState state) => const _GoRouteDataBuildPageWithState(), +final GoRoute _goRouteDataRedirect = GoRouteData.$route( + path: '/redirect', + factory: (GoRouterState state) => const _GoRouteDataRedirectPage(), ); final List _routes = [ _goRouteDataBuild, _goRouteDataBuildPage, - _goRouteDataBuildPageWithState, + _goRouteDataRedirect, ]; void main() { @@ -65,7 +67,6 @@ void main() { )); expect(find.byKey(const Key('build')), findsOneWidget); expect(find.byKey(const Key('buildPage')), findsNothing); - expect(find.byKey(const Key('buildPageWithState')), findsNothing); }, ); @@ -83,12 +84,11 @@ void main() { )); expect(find.byKey(const Key('build')), findsNothing); expect(find.byKey(const Key('buildPage')), findsOneWidget); - expect(find.byKey(const Key('buildPageWithState')), findsNothing); }, ); testWidgets( - 'It should build the page from the overridden buildPageWithState method', + 'It should build the page from the overridden buildPage method', (WidgetTester tester) async { final GoRouter goRouter = GoRouter( initialLocation: '/build-page-with-state', @@ -101,7 +101,39 @@ void main() { )); expect(find.byKey(const Key('build')), findsNothing); expect(find.byKey(const Key('buildPage')), findsNothing); - expect(find.byKey(const Key('buildPageWithState')), findsOneWidget); + }, + ); + testWidgets( + 'It should redirect using the overridden redirect method', + (WidgetTester tester) async { + final GoRouter goRouter = GoRouter( + initialLocation: '/redirect', + routes: _routes, + ); + await tester.pumpWidget(MaterialApp.router( + routeInformationProvider: goRouter.routeInformationProvider, + routeInformationParser: goRouter.routeInformationParser, + routerDelegate: goRouter.routerDelegate, + )); + expect(find.byKey(const Key('build')), findsNothing); + expect(find.byKey(const Key('buildPage')), findsOneWidget); + }, + ); + + testWidgets( + 'It should redirect using the overridden redirect method', + (WidgetTester tester) async { + final GoRouter goRouter = GoRouter( + initialLocation: '/redirect-with-state', + routes: _routes, + ); + await tester.pumpWidget(MaterialApp.router( + routeInformationProvider: goRouter.routeInformationProvider, + routeInformationParser: goRouter.routeInformationParser, + routerDelegate: goRouter.routerDelegate, + )); + expect(find.byKey(const Key('build')), findsNothing); + expect(find.byKey(const Key('buildPage')), findsNothing); }, ); }