I have a LandingScreen which uses NavigationRail on the left and my screens (Home, Live, Settings ...) on the right, but I'm not sure on how to put it all together.
What I want to achieve is:
- /
- /login
- /profileSelecting
then once authenticated and inside the app, the second part of the route (i.e /landing/XX) should change according to the user click on the NavigationRailItem.
- /landing/home
- /landing/live
- /landing/settings ... etc
How can I make this ?
Here's my GoRouter instance:
final goRouterProvider = Provider<GoRouter>((ref) {
return GoRouter(
navigatorKey: _rootNavigatorKey,
debugLogDiagnostics: true,
initialLocation: Routes.root,
refreshListenable: ref.watch(authNotifier),
errorBuilder: (_, state) => NavigationErrorScreen(state.error!),
routes: [
GoRoute(
path: Routes.navigationError,
name: Routes.navigationError,
builder: (_, state) => NavigationErrorScreen(state.error!),
),
GoRoute(
path: Routes.root,
name: Routes.root,
redirect: (_, state) {
final isAuthenticated =
ref.read(authNotifier.notifier).isAuthenticated;
if (isAuthenticated) return Routes.profileSelecting;
return Routes.login;
},
builder: (_, __) => const VialisApp(),
),
GoRoute(
path: Routes.login,
name: Routes.login,
builder: (_, __) => const LoginScreen(),
),
GoRoute(
path: Routes.profileSelecting,
name: Routes.profileSelecting,
redirect: (_, state) async {
final stbAccount = await ref.read(asyncAccountProvider.future);
final isMultipleProfiles = stbAccount.data.profiles!.length > 1;
if (isMultipleProfiles) {
return Routes.profileSelecting;
}
return Routes.landing;
},
builder: (_, __) => const ProfileSelectionScreen(),
),
ShellRoute(
navigatorKey: _landingNavigatorKey,
builder: (context, state, child) => const LandingScreen(child: child),
routes: [
GoRoute(
path: Routes.home,
name: Routes.home,
builder: (_, __) => const HomeScreen(),
),
GoRoute(
path: Routes.live,
name: Routes.live,
builder: (_, __) => const LiveScreen(),
),
GoRoute(
path: Routes.tvGuide,
name: Routes.tvGuide,
builder: (_, __) => const TVGuideScreen(),
),
GoRoute(
path: Routes.weekly,
name: Routes.weekly,
builder: (_, __) => const WeeklyGuideScreen(),
),
GoRoute(
path: Routes.recordings,
name: Routes.recordings,
builder: (_, __) => const RecordingsScreen(),
),
GoRoute(
path: Routes.settings,
name: Routes.settings,
builder: (_, __) => const SettingsScreen(),
),
],
),
],
);
});
My LandingScreen looks like this:
class LandingScreen extends ConsumerStatefulWidget {
final Widget child;
const LandingScreen({super.key, required this.child});
@override
ConsumerState<ConsumerStatefulWidget> createState() => _LandingScreenState();
}
class _LandingScreenState extends ConsumerState<LandingScreen> {
final double _iconWidth = 24.0;
final _railItemPadding = const EdgeInsets.only(left: 8.0);
@override
void initState() {
super.initState();
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);
}
@override
Widget build(BuildContext context) {
final index = ref.watch(landingIndexProvider);
final currentProfileName = ref.watch(currentProfileStateProvider);
ref.watch(asyncProfilesProvider(currentProfileName));
return Scaffold(
backgroundColor: black,
body: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 0,
child: NavigationRail(
leading: Image.asset(
'assets/vialis_logo_operator.png',
width: 55,
),
extended: true,
backgroundColor: grey,
minExtendedWidth: 55,
minWidth: 55,
selectedIndex: index,
useIndicator: true,
indicatorColor: blue,
onDestinationSelected: (index) =>
ref.read(landingIndexProvider.notifier).updateIndex(index),
destinations: <NavigationRailDestination>[
//home
NavigationRailDestination(
padding: _railItemPadding,
icon: Icon(Icons.home_filled, color: white, size: _iconWidth),
selectedIcon:
Icon(Icons.home_filled, color: white, size: _iconWidth),
label: const Text(''),
),
//live
NavigationRailDestination(
padding: _railItemPadding,
icon: Image.asset('assets/icon_live.webp', width: _iconWidth),
selectedIcon:
Image.asset('assets/icon_live.webp', width: _iconWidth),
label: const Text(''),
),
//tv guide
NavigationRailDestination(
padding: _railItemPadding,
icon: Image.asset('assets/icon_guid_tv.webp',
width: _iconWidth),
selectedIcon: Image.asset('assets/icon_guid_tv.webp',
width: _iconWidth),
label: const Text(''),
),
//weekly guide
NavigationRailDestination(
padding: _railItemPadding,
icon: Image.asset('assets/icon_guid_week.webp',
width: _iconWidth),
selectedIcon: Image.asset('assets/icon_guid_week.webp',
width: _iconWidth),
label: const Text(''),
),
//recordings
NavigationRailDestination(
padding: _railItemPadding,
icon:
Image.asset('assets/icon_record.webp', width: _iconWidth),
selectedIcon:
Image.asset('assets/icon_record.webp', width: _iconWidth),
label: const Text(''),
),
//settings
NavigationRailDestination(
padding: _railItemPadding,
icon: Image.asset('assets/icon_gear.webp', width: _iconWidth),
selectedIcon:
Image.asset('assets/icon_gear.webp', width: _iconWidth),
label: const Text(''),
),
],
),
),
Expanded(flex: 7, child: widget.child),
],
),
);
}
}