@@ -9,7 +9,7 @@ import 'package:flutter_news_app_mobile_client_full_source_code/app/config/app_e
99import 'package:flutter_news_app_mobile_client_full_source_code/app/services/app_status_service.dart' ;
1010import 'package:flutter_news_app_mobile_client_full_source_code/app/services/demo_data_migration_service.dart' ;
1111import 'package:flutter_news_app_mobile_client_full_source_code/authentication/bloc/authentication_bloc.dart' ;
12- import 'package:flutter_news_app_mobile_client_full_source_code/l10n/app_localizations .dart' ;
12+ import 'package:flutter_news_app_mobile_client_full_source_code/l10n/l10n .dart' ;
1313import 'package:flutter_news_app_mobile_client_full_source_code/router/router.dart' ;
1414import 'package:flutter_news_app_mobile_client_full_source_code/status/view/view.dart' ;
1515import 'package:go_router/go_router.dart' ;
@@ -191,132 +191,68 @@ class _AppViewState extends State<_AppView> {
191191 listener: (context, state) {
192192 _statusNotifier.value = state.status;
193193 },
194+ // The BlocBuilder is the core of the new stable startup architecture.
195+ // It acts as a high-level switch that determines which UI to show based
196+ // on the application's status.
194197 child: BlocBuilder <AppBloc , AppState >(
195- // Rebuild the UI based on AppBloc's state (theme, locale, and critical app statuses)
196198 builder: (context, state) {
197- // Defer l10n access until inside a MaterialApp context
199+ // --- Full-Screen Status Pages ---
200+ // The following states represent critical, app-wide conditions that
201+ // must be handled before the main router and UI are displayed.
202+ // By returning a dedicated widget here, we ensure these pages are
203+ // full-screen and exist outside the main app's navigation shell.
198204
199- // Handle critical RemoteConfig loading states globally
200- // These checks have the highest priority and will lock the entire UI.
201- //
202- // Check for Maintenance Mode.
203205 if (state.status == AppStatus .underMaintenance) {
204- return const MaterialApp (
206+ // The app is in maintenance mode. Show the MaintenancePage.
207+ // It's wrapped in a basic MaterialApp to provide theme and l10n.
208+ return MaterialApp (
205209 debugShowCheckedModeBanner: false ,
206- home: MaintenancePage (),
210+ theme: lightTheme (),
211+ darkTheme: darkTheme (),
212+ themeMode: state.themeMode,
213+ localizationsDelegates: AppLocalizations .localizationsDelegates,
214+ supportedLocales: AppLocalizations .supportedLocales,
215+ home: const MaintenancePage (),
207216 );
208217 }
209218
210- // Check for a Required Update.
211219 if (state.status == AppStatus .updateRequired) {
212- return const MaterialApp (
213- debugShowCheckedModeBanner: false ,
214- home: UpdateRequiredPage (),
215- );
216- }
217-
218- // Check for Config Fetching state.
219- if (state.status == AppStatus .configFetching) {
220+ // A mandatory update is required. Show the UpdateRequiredPage.
220221 return MaterialApp (
221222 debugShowCheckedModeBanner: false ,
222- theme: lightTheme (
223- scheme: FlexScheme .material,
224- appTextScaleFactor: AppTextScaleFactor .medium,
225- appFontWeight: AppFontWeight .regular,
226- fontFamily: null ,
227- ),
228- darkTheme: darkTheme (
229- scheme: FlexScheme .material,
230- appTextScaleFactor: AppTextScaleFactor .medium,
231- appFontWeight: AppFontWeight .regular,
232- fontFamily: null , // System default font
233- ),
234- themeMode: state
235- .themeMode, // Still respect light/dark if available from system
236- localizationsDelegates: const [
237- ...AppLocalizations .localizationsDelegates,
238- ...UiKitLocalizations .localizationsDelegates,
239- ],
240- supportedLocales: const [
241- ...AppLocalizations .supportedLocales,
242- ...UiKitLocalizations .supportedLocales,
243- ],
244- home: Scaffold (
245- body: Builder (
246- // Use Builder to get context under MaterialApp
247- builder: (innerContext) {
248- return LoadingStateWidget (
249- icon: Icons .settings_applications_outlined,
250- headline: AppLocalizations .of (
251- innerContext,
252- ).headlinesFeedLoadingHeadline,
253- subheadline: AppLocalizations .of (innerContext).pleaseWait,
254- );
255- },
256- ),
257- ),
223+ theme: lightTheme (),
224+ darkTheme: darkTheme (),
225+ themeMode: state.themeMode,
226+ localizationsDelegates: AppLocalizations .localizationsDelegates,
227+ supportedLocales: AppLocalizations .supportedLocales,
228+ home: const UpdateRequiredPage (),
258229 );
259230 }
260231
261- if (state.status == AppStatus .configFetchFailed) {
232+ if (state.status == AppStatus .configFetching ||
233+ state.status == AppStatus .configFetchFailed) {
234+ // The app is in the process of fetching its initial remote
235+ // configuration or has failed to do so. The StatusPage handles
236+ // both the loading indicator and the retry mechanism.
262237 return MaterialApp (
263238 debugShowCheckedModeBanner: false ,
264- theme: lightTheme (
265- scheme: FlexScheme .material,
266- appTextScaleFactor: AppTextScaleFactor .medium,
267- appFontWeight: AppFontWeight .regular,
268- fontFamily: null ,
269- ),
270- darkTheme: darkTheme (
271- scheme: FlexScheme .material,
272- appTextScaleFactor: AppTextScaleFactor .medium,
273- appFontWeight: AppFontWeight .regular,
274- fontFamily: null ,
275- ),
239+ theme: lightTheme (),
240+ darkTheme: darkTheme (),
276241 themeMode: state.themeMode,
277- localizationsDelegates: const [
278- ...AppLocalizations .localizationsDelegates,
279- ...UiKitLocalizations .localizationsDelegates,
280- ],
281- supportedLocales: const [
282- ...AppLocalizations .supportedLocales,
283- ...UiKitLocalizations .supportedLocales,
284- ],
285- home: Scaffold (
286- body: Builder (
287- // Use Builder to get context under MaterialApp
288- builder: (innerContext) {
289- return FailureStateWidget (
290- exception: const NetworkException (),
291- retryButtonText: UiKitLocalizations .of (
292- innerContext,
293- )! .retryButtonText,
294- onRetry: () {
295- // Use outer context for BLoC access
296- context.read <AppBloc >().add (
297- const AppConfigFetchRequested (),
298- );
299- },
300- );
301- },
302- ),
303- ),
242+ localizationsDelegates: AppLocalizations .localizationsDelegates,
243+ supportedLocales: AppLocalizations .supportedLocales,
244+ home: const StatusPage (),
304245 );
305246 }
306247
307- // If config is loaded (or not in a failed/fetching state for config), proceed with main app UI
308- // It's safe to access l10n here if needed for print statements,
309- // as this path implies we are about to build the main MaterialApp.router
310- // which provides localizations.
311- // final l10n = context.l10n;
312- print ('[_AppViewState] Building MaterialApp.router' );
313- print ('[_AppViewState] state.fontFamily: ${state .fontFamily }' );
314- print (
315- '[_AppViewState] state.settings.displaySettings.fontFamily: ${state .settings .displaySettings .fontFamily }' ,
316- );
317- print (
318- '[_AppViewState] state.settings.displaySettings.fontWeight: ${state .settings .displaySettings .fontWeight }' ,
319- );
248+ // --- Main Application UI ---
249+ // If none of the critical states above are met, the app is ready
250+ // to display its main UI. We build the MaterialApp.router here.
251+ //
252+ // This is the STABLE root of the main application. Because it is
253+ // only built when the app is in a "running" state, it will not be
254+ // destroyed and rebuilt during startup, which fixes the
255+ // `BuildContext` instability and related crashes.
320256 return MaterialApp .router (
321257 debugShowCheckedModeBanner: false ,
322258 themeMode: state.themeMode,
0 commit comments