I am engaged on a Flutter app the place I am utilizing GoRouter for navigation with a backside navigation bar to change between completely different sections. Every part has its personal nested navigation stack.
I wish to mechanically show a again button within the AppBar when the person will not be on the foundation route of a piece. Nonetheless, my present implementation will not be working as anticipated. Particularly, the next line doesn’t appropriately decide if there’s a path to pop within the nested navigation stack:
closing canPop = navigatorKey.currentState?.canPop() ?? false;
Here’s a simplified model of my code:
app.dart
import 'package deal:firebase_ui_auth/firebase_ui_auth.dart';
import 'package deal:flutter/materials.dart';
import 'package deal:go_router/go_router.dart';
import 'package deal:flutter_riverpod/flutter_riverpod.dart';
import 'package deal:hanazono_app/src/authentication/auth_gate.dart';
import 'package deal:hanazono_app/views/collection_screen.dart';
import 'package deal:hanazono_app/views/conversation_screen.dart';
import 'package deal:hanazono_app/views/home_screen.dart';
import 'package deal:hanazono_app/views/new_specimen_screen.dart';
import 'package deal:hanazono_app/views/scaffold_with_navbar.dart';
closing GlobalKey<NavigatorState> _rootNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'root');
closing GlobalKey<NavigatorState> _homeNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'house');
closing GlobalKey<NavigatorState> _collectionNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'assortment');
closing GlobalKey<NavigatorState> _newSpecimenNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'newSpecimen');
closing GlobalKey<NavigatorState> _conversationNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'dialog');
class MyApp extends ConsumerStatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends ConsumerState<MyApp> {
late closing GoRouter _router;
@override
void initState() {
tremendous.initState();
_router = GoRouter(
navigatorKey: _rootNavigatorKey,
initialLocation: "https://stackoverflow.com/",
routes: [
StatefulShellRoute.indexedStack(
parentNavigatorKey: _rootNavigatorKey,
builder: (BuildContext context, GoRouterState state,
StatefulNavigationShell navigationShell) {
return ScaffoldWithNavBar(navigationShell: navigationShell);
},
branches: [
StatefulShellBranch(
navigatorKey: _homeNavigatorKey,
routes: [
GoRoute(
path: "https://stackoverflow.com/",
builder: (context, state) => HomeScreen(),
),
],
),
StatefulShellBranch(
navigatorKey: _collectionNavigatorKey,
routes: [
GoRoute(
path: '/collection',
parentNavigatorKey: _collectionNavigatorKey,
builder: (context, state) => const CollectionScreen(),
routes: [
GoRoute(
path: 'newSpecimen',
builder: (context, state) => const NewSpecimenScreen(),
),
]),
],
),
StatefulShellBranch(
navigatorKey: _newSpecimenNavigatorKey,
routes: [
GoRoute(
path: '/newSpecimen0',
builder: (context, state) => const NewSpecimenScreen(),
),
],
),
StatefulShellBranch(
navigatorKey: _conversationNavigatorKey,
routes: [
GoRoute(
path: '/conversation',
builder: (context, state) {
final modelId = state.uri.queryParameters['modelId'] ??
'exampleModelId';
closing modelType =
state.uri.queryParameters['modelType'] ?? 'Taxon';
return ConversationScreen(
modelId: modelId, modelType: modelType);
},
),
],
),
],
),
GoRoute(
path: '/auth',
builder: (context, state) => const AuthGate(),
),
GoRoute(
path: '/profile',
builder: (context, state) => const ProfileScreen(),
),
],
);
}
@override
Widget construct(BuildContext context) {
return MaterialApp.router(
routerConfig: _router,
);
}
}
scaffold_with_navbar.dart
import 'package deal:flutter/materials.dart';
import 'package deal:go_router/go_router.dart';
import 'package deal:logging/logging.dart';
import 'package deal:flutter_riverpod/flutter_riverpod.dart';
import '../suppliers.dart';
class ScaffoldWithNavBar extends ConsumerWidget {
closing StatefulNavigationShell navigationShell;
const ScaffoldWithNavBar({
required this.navigationShell,
Key? key,
}) : tremendous(key: key ?? const ValueKey<String>('ScaffoldWithNavBar'));
@override
Widget construct(BuildContext context, WidgetRef ref) {
closing GoRouter router = GoRouter.of(context);
closing currentLocation = router.routerDelegate.currentConfiguration.fullPath;
Logger.root.information('Present path: $currentLocation');
int currentIndex = navigationShell.currentIndex;
Logger.root.information('Present index: $currentIndex');
closing person = ref.watch(authProvider).maybeWhen(
knowledge: (person) => person,
orElse: () => null,
);
closing navigatorKey = navigationShell.route.branches[currentIndex].navigatorKey;
closing canPop = navigatorKey.currentState?.canPop() ?? false;
Logger.root.information('Ought to show again button: $canPop');
// Log the state of the present tab's navigation stack
if (navigatorKey.currentState != null) {
Logger.root.information(
'Present tab's navigation stack: ${navigatorKey.currentState!.widget.toString()}');
}
return Scaffold(
appBar: AppBar(
main: canPop
? IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Logger.root.information('Again button pressed');
navigatorKey.currentState?.pop();
},
)
: null,
title: const Textual content('My App'),
actions: [
if (user != null && !user.isAnonymous)
IconButton(
icon: Icon(Icons.person),
onPressed: () {
context.go('/profile');
},
)
else
TextButton(
onPressed: () {
context.go('/auth');
},
child: Text('Login'),
),
],
),
physique: navigationShell,
bottomNavigationBar: NavigationBar(
backgroundColor: Colours.white,
selectedIndex: currentIndex,
locations: const [
NavigationDestination(
icon: Icon(Icons.home),
label: 'Home',
),
NavigationDestination(
icon: Icon(Icons.local_florist),
label: 'Collection',
),
NavigationDestination(
icon: Icon(Icons.add),
label: 'New Specimen',
),
NavigationDestination(
icon: Icon(Icons.chat),
label: 'Conversation',
),
],
onDestinationSelected: (index) {
Logger.root.information('Backside navigation merchandise tapped: $index');
navigationShell.goBranch(
index,
initialLocation: index == navigationShell.currentIndex,
);
},
),
);
}
}
Assortment Display
import 'package deal:flutter/materials.dart';
import 'package deal:go_router/go_router.dart';
import 'package deal:flutter_riverpod/flutter_riverpod.dart';
import '../suppliers.dart';
class CollectionScreen extends ConsumerWidget {
const CollectionScreen({tremendous.key});
@override
Widget construct(BuildContext context, WidgetRef ref) {
closing currentTabIndex = ref.watch(currentTabProvider);
closing navigatorKey =
ref.learn(navigationShellProvider.notifier).state[currentTabIndex];
return Scaffold(
physique: Heart(
youngster: Textual content(
'That is the gathering display',
fashion: Theme.of(context).textTheme.headlineLarge,
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
context.push('/assortment/newSpecimen');
},
youngster: Icon(Icons.add),
),
);
}
}
Problem:
When navigating inside a tab, the currentLocation solely reveals the bottom path of the tab, not the particular nested route (e.g., /assortment as a substitute of /assortment/newSpecimen). Consequently, the again button logic doesn’t work appropriately.
Objective:
Correctly handle the nested navigation stack for every tab in order that the again button is displayed when not on the foundation route of the tab.
Query:
How can I appropriately test the nested navigation stack for every tab to find out if the again button must be displayed?
Thanks on your assist!