Skip to content

Commit

Permalink
[go_router] Added proper redirect handling for ShellRoute.$route
Browse files Browse the repository at this point in the history
…and `StatefulShellRoute.$route` for proper redirection handling in case of code generation (flutter#6841)

Added proper `redirect` handling for `ShellRoute.$route` and
`StatefulShellRoute.$route` for proper redirection handling in case of
code generation.

*List which issues are fixed by this PR. You must list at least one
issue.*
- I did not create an issue

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] page, which explains my
responsibilities.
- [x] I read and followed the [relevant style guides] and ran the
auto-formatter. (Unlike the flutter/flutter repo, the flutter/packages
repo does use `dart format`.)
- [x] I signed the [CLA].
- [x] The title of the PR starts with the name of the package surrounded
by square brackets, e.g. `[shared_preferences]`
- [ ] I [linked to at least one issue that this PR fixes] in the
description above.
- [x] I updated `pubspec.yaml` with an appropriate new version according
to the [pub versioning philosophy], or this PR is [exempt from version
changes].
- [x] I updated `CHANGELOG.md` to add a description of the change,
[following repository CHANGELOG style], or this PR is [exempt from
CHANGELOG changes].
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/packages/blob/main/CONTRIBUTING.md
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md
[relevant style guides]:
https://github.com/flutter/packages/blob/main/CONTRIBUTING.md#style
[CLA]: https://cla.developers.google.com/
[Discord]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Chat.md
[linked to at least one issue that this PR fixes]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#overview
[pub versioning philosophy]: https://dart.dev/tools/pub/versioning
[exempt from version changes]:
https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#version
[following repository CHANGELOG style]:
https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changelog-style
[exempt from CHANGELOG changes]:
https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changelog
[test-exempt]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#tests

---------

Co-authored-by: Vasiliy Ditsyak <vasilich6107@users.noreply.github.com>
  • Loading branch information
2 people authored and arc-yong committed Jun 14, 2024
1 parent 3b1f53e commit 9840922
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 1 deletion.
4 changes: 4 additions & 0 deletions packages/go_router/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 14.2.0

- Added proper `redirect` handling for `ShellRoute.$route` and `StatefulShellRoute.$route` for proper redirection handling in case of code generation.

## 14.1.4

- Fixes a URL in `navigation.md`.
Expand Down
25 changes: 25 additions & 0 deletions packages/go_router/lib/src/route_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,14 @@ abstract class ShellRouteData extends RouteData {
'One of `builder` or `pageBuilder` must be implemented.',
);

/// An optional redirect function for this route.
///
/// Subclasses must override one of [build], [buildPage], or
/// [redirect].
///
/// Corresponds to [GoRoute.redirect].
FutureOr<String?> redirect(BuildContext context, GoRouterState state) => null;

/// A helper function used by generated code.
///
/// Should not be used directly.
Expand All @@ -174,6 +182,9 @@ abstract class ShellRouteData extends RouteData {
return (_stateObjectExpando[state] ??= factory(state)) as T;
}

FutureOr<String?> redirect(BuildContext context, GoRouterState state) =>
factoryImpl(state).redirect(context, state);

Widget builder(
BuildContext context,
GoRouterState state,
Expand Down Expand Up @@ -204,6 +215,7 @@ abstract class ShellRouteData extends RouteData {
navigatorKey: navigatorKey,
observers: observers,
restorationScopeId: restorationScopeId,
redirect: redirect,
);
}

Expand All @@ -221,6 +233,14 @@ abstract class StatefulShellRouteData extends RouteData {
/// Default const constructor
const StatefulShellRouteData();

/// An optional redirect function for this route.
///
/// Subclasses must override one of [build], [buildPage], or
/// [redirect].
///
/// Corresponds to [GoRoute.redirect].
FutureOr<String?> redirect(BuildContext context, GoRouterState state) => null;

/// [pageBuilder] is used to build the page
Page<void> pageBuilder(
BuildContext context,
Expand Down Expand Up @@ -275,6 +295,9 @@ abstract class StatefulShellRouteData extends RouteData {
navigationShell,
);

FutureOr<String?> redirect(BuildContext context, GoRouterState state) =>
factoryImpl(state).redirect(context, state);

if (navigatorContainerBuilder != null) {
return StatefulShellRoute(
branches: branches,
Expand All @@ -283,6 +306,7 @@ abstract class StatefulShellRouteData extends RouteData {
navigatorContainerBuilder: navigatorContainerBuilder,
parentNavigatorKey: parentNavigatorKey,
restorationScopeId: restorationScopeId,
redirect: redirect,
);
}
return StatefulShellRoute.indexedStack(
Expand All @@ -291,6 +315,7 @@ abstract class StatefulShellRouteData extends RouteData {
pageBuilder: pageBuilder,
parentNavigatorKey: parentNavigatorKey,
restorationScopeId: restorationScopeId,
redirect: redirect,
);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/go_router/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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: 14.1.4
version: 14.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

Expand Down
83 changes: 83 additions & 0 deletions packages/go_router/test/route_data_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,20 @@ import 'package:go_router/go_router.dart';

class _GoRouteDataBuild extends GoRouteData {
const _GoRouteDataBuild();

@override
Widget build(BuildContext context, GoRouterState state) =>
const SizedBox(key: Key('build'));
}

class _ShellRouteDataRedirectPage extends ShellRouteData {
const _ShellRouteDataRedirectPage();

@override
FutureOr<String> redirect(BuildContext context, GoRouterState state) =>
'/build-page';
}

class _ShellRouteDataBuilder extends ShellRouteData {
const _ShellRouteDataBuilder();

Expand Down Expand Up @@ -49,7 +58,9 @@ class _ShellRouteDataWithKey extends ShellRouteData {

class _GoRouteDataBuildWithKey extends GoRouteData {
const _GoRouteDataBuildWithKey(this.key);

final Key key;

@override
Widget build(BuildContext context, GoRouterState state) => SizedBox(key: key);
}
Expand All @@ -71,6 +82,7 @@ final ShellRoute _shellRouteDataBuilder = ShellRouteData.$route(

class _GoRouteDataBuildPage extends GoRouteData {
const _GoRouteDataBuildPage();

@override
Page<void> buildPage(BuildContext context, GoRouterState state) =>
const MaterialPage<void>(
Expand All @@ -95,6 +107,14 @@ class _ShellRouteDataPageBuilder extends ShellRouteData {
);
}

class _StatefulShellRouteDataRedirectPage extends StatefulShellRouteData {
const _StatefulShellRouteDataRedirectPage();

@override
FutureOr<String> redirect(BuildContext context, GoRouterState state) =>
'/build-page';
}

final GoRoute _goRouteDataBuildPage = GoRouteData.$route(
path: '/build-page',
factory: (GoRouterState state) => const _GoRouteDataBuildPage(),
Expand All @@ -110,6 +130,21 @@ final ShellRoute _shellRouteDataPageBuilder = ShellRouteData.$route(
],
);

final ShellRoute _shellRouteDataRedirect = ShellRouteData.$route(
factory: (GoRouterState state) => const _ShellRouteDataPageBuilder(),
routes: <RouteBase>[
ShellRouteData.$route(
factory: (GoRouterState state) => const _ShellRouteDataRedirectPage(),
routes: <RouteBase>[
GoRouteData.$route(
path: '/child',
factory: (GoRouterState state) => const _GoRouteDataBuild(),
),
],
),
],
);

class _StatefulShellRouteDataBuilder extends StatefulShellRouteData {
const _StatefulShellRouteDataBuilder();

Expand Down Expand Up @@ -174,6 +209,7 @@ final StatefulShellRoute _statefulShellRouteDataPageBuilder =

class _GoRouteDataRedirectPage extends GoRouteData {
const _GoRouteDataRedirectPage();

@override
FutureOr<String> redirect(BuildContext context, GoRouterState state) =>
'/build-page';
Expand Down Expand Up @@ -311,6 +347,23 @@ void main() {
expect(find.byKey(const Key('page-builder')), findsOneWidget);
},
);

testWidgets(
'It should redirect using the overridden redirect method',
(WidgetTester tester) async {
final GoRouter goRouter = GoRouter(
initialLocation: '/child',
routes: <RouteBase>[
_goRouteDataBuildPage,
_shellRouteDataRedirect,
],
);
addTearDown(goRouter.dispose);
await tester.pumpWidget(MaterialApp.router(routerConfig: goRouter));
expect(find.byKey(const Key('build')), findsNothing);
expect(find.byKey(const Key('buildPage')), findsOneWidget);
},
);
});

group('StatefulShellRouteData', () {
Expand Down Expand Up @@ -381,6 +434,36 @@ void main() {
},
);

testWidgets(
'It should redirect using the overridden StatefulShellRoute redirect method',
(WidgetTester tester) async {
final GoRouter goRouter = GoRouter(
initialLocation: '/child',
routes: <RouteBase>[
_goRouteDataBuildPage,
StatefulShellRouteData.$route(
factory: (GoRouterState state) =>
const _StatefulShellRouteDataRedirectPage(),
branches: <StatefulShellBranch>[
StatefulShellBranchData.$branch(
routes: <GoRoute>[
GoRouteData.$route(
path: '/child',
factory: (GoRouterState state) => const _GoRouteDataBuild(),
),
],
)
],
)
],
);
addTearDown(goRouter.dispose);
await tester.pumpWidget(MaterialApp.router(routerConfig: goRouter));
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 {
Expand Down

0 comments on commit 9840922

Please sign in to comment.