diff --git a/lib/main.dart b/lib/main.dart index 76686a5e..9afcf463 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,9 @@ +import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:starter_architecture_flutter_firebase/firebase_options.dart'; import 'package:starter_architecture_flutter_firebase/src/app.dart'; -import 'package:starter_architecture_flutter_firebase/src/app_startup.dart'; import 'package:starter_architecture_flutter_firebase/src/localization/string_hardcoded.dart'; // ignore:depend_on_referenced_packages import 'package:flutter_web_plugins/url_strategy.dart'; @@ -14,11 +15,11 @@ Future main() async { // * Register error handlers. For more info, see: // * https://docs.flutter.dev/testing/errors registerErrorHandlers(); + // * Initialize Firebase + await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); // * Entry point of the app - runApp(ProviderScope( - child: AppStartupWidget( - onLoaded: (context) => const MyApp(), - ), + runApp(const ProviderScope( + child: MyApp(), )); } diff --git a/lib/src/app_startup.dart b/lib/src/app_startup.dart index e11bfb3a..4186a687 100644 --- a/lib/src/app_startup.dart +++ b/lib/src/app_startup.dart @@ -1,8 +1,6 @@ -import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; -import 'package:starter_architecture_flutter_firebase/firebase_options.dart'; import 'package:starter_architecture_flutter_firebase/src/constants/app_sizes.dart'; import 'package:starter_architecture_flutter_firebase/src/features/onboarding/data/onboarding_repository.dart'; @@ -20,12 +18,7 @@ Future appStartup(AppStartupRef ref) async { ref.invalidate(onboardingRepositoryProvider); }); // await for all initialization code to be complete before returning - await Future.wait([ - // Firebase init - Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform), - // list of providers to be warmed up - ref.watch(onboardingRepositoryProvider.future) - ]); + await ref.watch(onboardingRepositoryProvider.future); } /// Widget class to manage asynchronous app initialization @@ -52,11 +45,10 @@ class AppStartupLoadingWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold( - body: Center( - child: CircularProgressIndicator(), - ), + return Scaffold( + appBar: AppBar(), + body: const Center( + child: CircularProgressIndicator(), ), ); } @@ -70,20 +62,19 @@ class AppStartupErrorWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - body: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text(message, style: Theme.of(context).textTheme.headlineSmall), - gapH16, - ElevatedButton( - onPressed: onRetry, - child: const Text('Retry'), - ), - ], - ), + return Scaffold( + appBar: AppBar(), + body: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(message, style: Theme.of(context).textTheme.headlineSmall), + gapH16, + ElevatedButton( + onPressed: onRetry, + child: const Text('Retry'), + ), + ], ), ), ); diff --git a/lib/src/routing/app_router.dart b/lib/src/routing/app_router.dart index 84c8a42a..bc225dd0 100644 --- a/lib/src/routing/app_router.dart +++ b/lib/src/routing/app_router.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:starter_architecture_flutter_firebase/src/app_startup.dart'; import 'package:starter_architecture_flutter_firebase/src/features/authentication/data/firebase_auth_repository.dart'; import 'package:starter_architecture_flutter_firebase/src/features/authentication/presentation/custom_profile_screen.dart'; import 'package:starter_architecture_flutter_firebase/src/features/authentication/presentation/custom_sign_in_screen.dart'; @@ -40,16 +41,23 @@ enum AppRoute { } @riverpod -// ignore: unsupported_provider_value GoRouter goRouter(GoRouterRef ref) { + // rebuild GoRouter when app startup state changes + final appStartupState = ref.watch(appStartupProvider); final authRepository = ref.watch(authRepositoryProvider); - final onboardingRepository = - ref.watch(onboardingRepositoryProvider).requireValue; return GoRouter( initialLocation: '/signIn', navigatorKey: _rootNavigatorKey, debugLogDiagnostics: true, redirect: (context, state) { + if (appStartupState.isLoading) { + return '/loading'; + } + if (appStartupState.hasError) { + return '/error'; + } + final onboardingRepository = + ref.read(onboardingRepositoryProvider).requireValue; final didCompleteOnboarding = onboardingRepository.isOnboardingComplete(); final path = state.uri.path; if (!didCompleteOnboarding) { @@ -75,6 +83,21 @@ GoRouter goRouter(GoRouterRef ref) { }, refreshListenable: GoRouterRefreshStream(authRepository.authStateChanges()), routes: [ + GoRoute( + path: '/loading', + pageBuilder: (context, state) => const NoTransitionPage( + child: AppStartupLoadingWidget(), + ), + ), + GoRoute( + path: '/error', + pageBuilder: (context, state) => NoTransitionPage( + child: AppStartupErrorWidget( + message: 'App initialization failed', + onRetry: () => ref.invalidate(appStartupProvider), + ), + ), + ), GoRoute( path: '/onboarding', name: AppRoute.onboarding.name,