[go_router] [shell_route] Fix BottomNavigationBar might lost current index in long URIs. (#2636)
diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md
index 5d6e28f..537adf3 100644
--- a/packages/go_router/CHANGELOG.md
+++ b/packages/go_router/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 5.0.4
+
+- Fixes a bug in ShellRoute example where NavigationBar might lose current index in a nested routes.
+
## 5.0.3
- Changes examples to use the routerConfig API
diff --git a/packages/go_router/example/lib/shell_route.dart b/packages/go_router/example/lib/shell_route.dart
index b33c0bb..8c73c83 100644
--- a/packages/go_router/example/lib/shell_route.dart
+++ b/packages/go_router/example/lib/shell_route.dart
@@ -77,6 +77,24 @@
),
],
),
+
+ /// The third screen to display in the bottom navigation bar.
+ GoRoute(
+ path: '/c',
+ builder: (BuildContext context, GoRouterState state) {
+ return const ScreenC();
+ },
+ routes: <RouteBase>[
+ // The details screen to display stacked on the inner Navigator.
+ // This will cover screen A but not the application shell.
+ GoRoute(
+ path: 'details',
+ builder: (BuildContext context, GoRouterState state) {
+ return const DetailsScreen(label: 'C');
+ },
+ ),
+ ],
+ ),
],
),
],
@@ -121,6 +139,10 @@
icon: Icon(Icons.business),
label: 'B Screen',
),
+ BottomNavigationBarItem(
+ icon: Icon(Icons.notification_important_rounded),
+ label: 'C Screen',
+ ),
],
currentIndex: _calculateSelectedIndex(context),
onTap: (int idx) => _onItemTapped(idx, context),
@@ -131,12 +153,15 @@
static int _calculateSelectedIndex(BuildContext context) {
final GoRouter route = GoRouter.of(context);
final String location = route.location;
- if (location == '/a') {
+ if (location.startsWith('/a')) {
return 0;
}
- if (location == '/b') {
+ if (location.startsWith('/b')) {
return 1;
}
+ if (location.startsWith('/c')) {
+ return 2;
+ }
return 0;
}
@@ -148,6 +173,9 @@
case 1:
GoRouter.of(context).go('/b');
break;
+ case 2:
+ GoRouter.of(context).go('/c');
+ break;
}
}
}
@@ -206,7 +234,34 @@
}
}
-/// The details screen for either the A or B screen.
+/// The third screen in the bottom navigation bar.
+class ScreenC extends StatelessWidget {
+ /// Constructs a [ScreenC] widget.
+ const ScreenC({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(),
+ body: Center(
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: <Widget>[
+ const Text('Screen C'),
+ TextButton(
+ onPressed: () {
+ GoRouter.of(context).go('/c/details');
+ },
+ child: const Text('View C details'),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+/// The details screen for either the A, B or C screen.
class DetailsScreen extends StatelessWidget {
/// Constructs a [DetailsScreen].
const DetailsScreen({
diff --git a/packages/go_router/example/test/shell_route_test.dart b/packages/go_router/example/test/shell_route_test.dart
new file mode 100644
index 0000000..9327189
--- /dev/null
+++ b/packages/go_router/example/test/shell_route_test.dart
@@ -0,0 +1,42 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:go_router_examples/shell_route.dart' as example;
+
+void main() {
+ testWidgets('example works', (WidgetTester tester) async {
+ await tester.pumpWidget(example.ShellRouteExampleApp());
+ expect(find.text('Screen A'), findsOneWidget);
+ // navigate to a/details
+ await tester.tap(find.text('View A details'));
+ await tester.pumpAndSettle();
+ expect(find.text('Details for A'), findsOneWidget);
+
+ // navigate to ScreenB
+ await tester.tap(find.text('B Screen'));
+ await tester.pumpAndSettle();
+ expect(find.text('Screen B'), findsOneWidget);
+
+ // navigate to b/details
+ await tester.tap(find.text('View B details'));
+ await tester.pumpAndSettle();
+ expect(find.text('Details for B'), findsOneWidget);
+
+ // back to ScreenB.
+ await tester.tap(find.byType(BackButton));
+ await tester.pumpAndSettle();
+
+ // navigate to ScreenC
+ await tester.tap(find.text('C Screen'));
+ await tester.pumpAndSettle();
+ expect(find.text('Screen C'), findsOneWidget);
+
+ // navigate to c/details
+ await tester.tap(find.text('View C details'));
+ await tester.pumpAndSettle();
+ expect(find.text('Details for C'), findsOneWidget);
+ });
+}
diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml
index 3f45de0..641d577 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.0.3
+version: 5.0.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