Skip to content

Commit

Permalink
[go_router] Fixes an issue where android back button pops wrong page.
Browse files Browse the repository at this point in the history
  • Loading branch information
chunhtai committed Aug 8, 2024
1 parent 2c49369 commit 6c05687
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 22 deletions.
5 changes: 3 additions & 2 deletions packages/go_router/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## NEXT
## 14.2.4

* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3.
- Updates minimum supported SDK version to Flutter 3.19/Dart 3.3.
- Fixes an issue where android back button pops wrong page.

## 14.2.3

Expand Down
39 changes: 21 additions & 18 deletions packages/go_router/lib/src/delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,30 +52,18 @@ class GoRouterDelegate extends RouterDelegate<RouteMatchList>

@override
Future<bool> popRoute() async {
NavigatorState? state = navigatorKey.currentState;
if (state == null) {
return false;
}
if (!state.canPop()) {
state = null;
}
RouteMatchBase walker = currentConfiguration.matches.last;
while (walker is ShellRouteMatch) {
if (walker.navigatorKey.currentState?.canPop() ?? false) {
state = walker.navigatorKey.currentState;
}
walker = walker.matches.last;
}
assert(walker is RouteMatch);
final NavigatorState? state = _findCurrentNavigator();
if (state != null) {
// now we have to figure out whether we are the last
return state.maybePop();
}
// This should be the only place where the last GoRoute exit the screen.
final GoRoute lastRoute = currentConfiguration.last.route;
if (lastRoute.onExit != null && navigatorKey.currentContext != null) {
return !(await lastRoute.onExit!(
navigatorKey.currentContext!,
walker.buildState(_configuration, currentConfiguration),
currentConfiguration.last
.buildState(_configuration, currentConfiguration),
));
}
return false;
Expand All @@ -98,6 +86,14 @@ class GoRouterDelegate extends RouterDelegate<RouteMatchList>

/// Pops the top-most route.
void pop<T extends Object?>([T? result]) {
final NavigatorState? state = _findCurrentNavigator();
if (state == null) {
throw GoError('There is nothing to pop');
}
state.pop(result);
}

NavigatorState? _findCurrentNavigator() {
NavigatorState? state;
if (navigatorKey.currentState?.canPop() ?? false) {
state = navigatorKey.currentState;
Expand All @@ -110,9 +106,16 @@ class GoRouterDelegate extends RouterDelegate<RouteMatchList>
walker = walker.matches.last;
}
if (state == null) {
throw GoError('There is nothing to pop');
return null;
}
state.pop(result);
NavigatorState currentState = state;
bool isNavigatorCurrent = ModalRoute.isCurrentOf(state.context) ?? true;
while (!isNavigatorCurrent) {
currentState =
currentState.context.findAncestorStateOfType<NavigatorState>()!;
isNavigatorCurrent = ModalRoute.isCurrentOf(currentState.context) ?? true;
}
return currentState;
}

void _debugAssertMatchListNotEmpty() {
Expand Down
2 changes: 1 addition & 1 deletion packages/go_router/lib/src/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class GoRouter implements RouterConfig<RouteMatchList> {
setLogging(enabled: debugLogDiagnostics);
WidgetsFlutterBinding.ensureInitialized();

navigatorKey ??= GlobalKey<NavigatorState>();
navigatorKey ??= GlobalKey<NavigatorState>(debugLabel: 'root');

_routingConfig.addListener(_handleRoutingConfigChanged);
configuration = RouteConfiguration(
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.2.3
version: 14.2.4
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
61 changes: 61 additions & 0 deletions packages/go_router/test/go_router_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,67 @@ void main() {
expect(find.byKey(settings), findsOneWidget);
});

testWidgets('android back button pop in correct order',
(WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/141906.
final List<RouteBase> routes = <RouteBase>[
GoRoute(
path: '/',
builder: (_, __) => const Text('home'),
routes: <RouteBase>[
ShellRoute(
builder: (
BuildContext context,
GoRouterState state,
Widget child,
) {
return Column(
children: <Widget>[
const Text('shell'),
child,
],
);
},
routes: <GoRoute>[
GoRoute(
path: 'page',
builder: (BuildContext context, __) {
return TextButton(
onPressed: () {
Navigator.of(context, rootNavigator: true).push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return const Text('pageless');
}),
);
},
child: const Text('page'),
);
},
),
],
),
]),
];
final GoRouter router =
await createRouter(routes, tester, initialLocation: '/page');
expect(find.text('shell'), findsOneWidget);
expect(find.text('page'), findsOneWidget);

await tester.tap(find.text('page'));
await tester.pumpAndSettle();
expect(find.text('shell'), findsNothing);
expect(find.text('page'), findsNothing);
expect(find.text('pageless'), findsOneWidget);

final bool result = await router.routerDelegate.popRoute();
expect(result, isTrue);
await tester.pumpAndSettle();
expect(find.text('shell'), findsOneWidget);
expect(find.text('page'), findsOneWidget);
expect(find.text('pageless'), findsNothing);
});

testWidgets('can correctly pop stacks of repeated pages',
(WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/#132229.
Expand Down

0 comments on commit 6c05687

Please sign in to comment.