1+ import 'package:core/core.dart' ;
12import 'package:flutter/material.dart' ;
23import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart' ;
34import 'package:flutter_bloc/flutter_bloc.dart' ;
@@ -24,22 +25,17 @@ class AppShell extends StatelessWidget {
2425
2526 @override
2627 Widget build (BuildContext context) {
27- final l10n = AppLocalizationsX (context).l10n;
28- final theme = Theme .of (context);
28+ return BlocBuilder <AppBloc , AppState >(
29+ builder: (context, state) {
30+ final l10n = AppLocalizationsX (context).l10n;
31+ final theme = Theme .of (context);
32+ final userRole = state.user? .dashboardRole;
2933
30- // Use the same text style as the NavigationRail labels for consistency.
31- final navRailLabelStyle = theme.textTheme.labelMedium;
34+ // Use the same text style as the NavigationRail labels for consistency.
35+ final navRailLabelStyle = theme.textTheme.labelMedium;
3236
33- return Scaffold (
34- body: AdaptiveScaffold (
35- selectedIndex: navigationShell.currentIndex,
36- onSelectedIndexChange: (index) {
37- navigationShell.goBranch (
38- index,
39- initialLocation: index == navigationShell.currentIndex,
40- );
41- },
42- destinations: [
37+ // A complete list of all possible navigation destinations.
38+ final allDestinations = [
4339 NavigationDestination (
4440 icon: const Icon (Icons .dashboard_outlined),
4541 selectedIcon: const Icon (Icons .dashboard),
@@ -60,119 +56,149 @@ class AppShell extends StatelessWidget {
6056 selectedIcon: const Icon (Icons .settings_applications),
6157 label: l10n.appConfiguration,
6258 ),
63- ],
64- leadingUnextendedNavRail: Padding (
65- padding: const EdgeInsets .symmetric (vertical: AppSpacing .lg),
66- child: Icon (
67- Icons .newspaper_outlined,
68- color: theme.colorScheme.primary,
69- ),
70- ),
71- leadingExtendedNavRail: Padding (
72- padding: const EdgeInsets .all (AppSpacing .lg),
73- child: Row (
74- children: [
75- Icon (
59+ ];
60+
61+ // Filter the destinations based on the user's role.
62+ final accessibleDestinations = allDestinations.where ((destination) {
63+ if (userRole == null ) return false ;
64+
65+ switch (userRole) {
66+ case DashboardUserRole .admin:
67+ // Admin can see all destinations.
68+ return true ;
69+ case DashboardUserRole .publisher:
70+ // Publisher can only see Overview and Content Management.
71+ return destination.label == l10n.overview ||
72+ destination.label == l10n.contentManagement;
73+ case DashboardUserRole .none:
74+ return false ;
75+ }
76+ }).toList ();
77+
78+ return Scaffold (
79+ body: AdaptiveScaffold (
80+ selectedIndex: navigationShell.currentIndex,
81+ onSelectedIndexChange: (index) {
82+ navigationShell.goBranch (
83+ index,
84+ initialLocation: index == navigationShell.currentIndex,
85+ );
86+ },
87+ destinations: accessibleDestinations,
88+ leadingUnextendedNavRail: Padding (
89+ padding: const EdgeInsets .symmetric (vertical: AppSpacing .lg),
90+ child: Icon (
7691 Icons .newspaper_outlined,
7792 color: theme.colorScheme.primary,
7893 ),
79- const SizedBox (width: AppSpacing .md),
80- Text (
81- l10n.dashboardTitle,
82- style: theme.textTheme.titleLarge,
94+ ),
95+ leadingExtendedNavRail: Padding (
96+ padding: const EdgeInsets .all (AppSpacing .lg),
97+ child: Row (
98+ children: [
99+ Icon (
100+ Icons .newspaper_outlined,
101+ color: theme.colorScheme.primary,
102+ ),
103+ const SizedBox (width: AppSpacing .md),
104+ Text (
105+ l10n.dashboardTitle,
106+ style: theme.textTheme.titleLarge,
107+ ),
108+ ],
83109 ),
84- ],
85- ),
86- ),
87- trailingNavRail: Builder (
88- builder: (context) {
89- final isExtended =
90- Breakpoints .mediumLargeAndUp.isActive (context) ||
91- Breakpoints .small.isActive (context);
92- return Expanded (
93- child: Padding (
94- padding: const EdgeInsets .only (bottom: AppSpacing .lg),
95- child: Column (
96- mainAxisAlignment: MainAxisAlignment .end,
97- children: [
98- // Settings Tile
99- InkWell (
100- onTap: () => context.goNamed (Routes .settingsName),
101- child: Padding (
102- padding: EdgeInsets .symmetric (
103- vertical: AppSpacing .md,
104- horizontal: isExtended ? 24 : 16 ,
105- ),
106- child: Row (
107- mainAxisAlignment: isExtended
108- ? MainAxisAlignment .start
109- : MainAxisAlignment .center,
110- children: [
111- Icon (
112- Icons .settings_outlined,
113- color: theme.colorScheme.onSurfaceVariant,
114- size: 24 ,
110+ ),
111+ trailingNavRail: Builder (
112+ builder: (context) {
113+ final isExtended =
114+ Breakpoints .mediumLargeAndUp.isActive (context) ||
115+ Breakpoints .small.isActive (context);
116+ return Expanded (
117+ child: Padding (
118+ padding: const EdgeInsets .only (bottom: AppSpacing .lg),
119+ child: Column (
120+ mainAxisAlignment: MainAxisAlignment .end,
121+ children: [
122+ // Settings Tile - universally accessible to all roles.
123+ InkWell (
124+ onTap: () => context.goNamed (Routes .settingsName),
125+ child: Padding (
126+ padding: EdgeInsets .symmetric (
127+ vertical: AppSpacing .md,
128+ horizontal: isExtended ? 24 : 16 ,
115129 ),
116- if (isExtended) ...[
117- const SizedBox (width : AppSpacing .lg),
118- Text (
119- l10n.settings ,
120- style : navRailLabelStyle,
121- ),
122- ] ,
123- ] ,
124- ) ,
125- ),
126- ),
127- // Sign Out Tile
128- InkWell (
129- onTap : () => context. read < AppBloc >(). add (
130- const AppLogoutRequested () ,
131- ),
132- child : Padding (
133- padding : EdgeInsets . symmetric (
134- vertical : AppSpacing .md ,
135- horizontal : isExtended ? 24 : 16 ,
130+ child : Row (
131+ mainAxisAlignment : isExtended
132+ ? MainAxisAlignment .start
133+ : MainAxisAlignment .center ,
134+ children : [
135+ Icon (
136+ Icons .settings_outlined ,
137+ color : theme.colorScheme.onSurfaceVariant ,
138+ size : 24 ,
139+ ),
140+ if (isExtended) ...[
141+ const SizedBox (width : AppSpacing .lg),
142+ Text (
143+ l10n.settings,
144+ style : navRailLabelStyle ,
145+ ),
146+ ],
147+ ],
148+ ) ,
149+ ) ,
136150 ),
137- child : Row (
138- mainAxisAlignment : isExtended
139- ? MainAxisAlignment .start
140- : MainAxisAlignment .center ,
141- children : [
142- Icon (
143- Icons .logout,
144- color : theme.colorScheme.error ,
145- size : 24 ,
151+ // Sign Out Tile
152+ InkWell (
153+ onTap : () => context. read < AppBloc >(). add (
154+ const AppLogoutRequested () ,
155+ ),
156+ child : Padding (
157+ padding : EdgeInsets . symmetric (
158+ vertical : AppSpacing .md ,
159+ horizontal : isExtended ? 24 : 16 ,
146160 ),
147- if (isExtended) ...[
148- const SizedBox (width: AppSpacing .lg),
149- Text (
150- l10n.signOut,
151- style: navRailLabelStyle? .copyWith (
161+ child: Row (
162+ mainAxisAlignment: isExtended
163+ ? MainAxisAlignment .start
164+ : MainAxisAlignment .center,
165+ children: [
166+ Icon (
167+ Icons .logout,
152168 color: theme.colorScheme.error,
169+ size: 24 ,
153170 ),
154- ),
155- ],
156- ],
171+ if (isExtended) ...[
172+ const SizedBox (width: AppSpacing .lg),
173+ Text (
174+ l10n.signOut,
175+ style: navRailLabelStyle? .copyWith (
176+ color: theme.colorScheme.error,
177+ ),
178+ ),
179+ ],
180+ ],
181+ ),
182+ ),
157183 ),
158- ) ,
184+ ] ,
159185 ),
160- ],
161- ),
186+ ),
187+ );
188+ },
189+ ),
190+ body: (_) => Padding (
191+ padding: const EdgeInsets .fromLTRB (
192+ 0 ,
193+ AppSpacing .sm,
194+ AppSpacing .sm,
195+ AppSpacing .sm,
162196 ),
163- );
164- },
165- ),
166- body: (_) => Padding (
167- padding: const EdgeInsets .fromLTRB (
168- 0 ,
169- AppSpacing .sm,
170- AppSpacing .sm,
171- AppSpacing .sm,
197+ child: navigationShell,
198+ ),
172199 ),
173- child: navigationShell,
174- ),
175- ),
200+ );
201+ },
176202 );
177203 }
178204}
0 commit comments