Skip to content

Commit

Permalink
Add AppStartupWidget class for asynchronous app initialization (#146)
Browse files Browse the repository at this point in the history
* Add AppStartupWidget class for asynchronous app initialization

* Use ref.invalidate inside onRetry
  • Loading branch information
bizz84 authored Jan 17, 2024
1 parent d6d17c3 commit 96a52cb
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 12 deletions.
17 changes: 5 additions & 12 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,31 +1,24 @@
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';
import 'package:starter_architecture_flutter_firebase/src/features/onboarding/data/onboarding_repository.dart';
// ignore:depend_on_referenced_packages
import 'package:flutter_web_plugins/url_strategy.dart';

Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
// turn off the # in the URLs on the web
usePathUrlStrategy();
// * Register error handlers. For more info, see:
// * https://docs.flutter.dev/testing/errors
registerErrorHandlers();
// * Entry point of the app

final container = ProviderContainer();
await container.read(onboardingRepositoryProvider.future);
runApp(UncontrolledProviderScope(
container: container,
child: const MyApp(),
runApp(ProviderScope(
child: AppStartupWidget(
onLoaded: (context) => const MyApp(),
),
));
}

Expand Down
85 changes: 85 additions & 0 deletions lib/src/app_startup.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
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';

part 'app_startup.g.dart';

@Riverpod(keepAlive: true)
Future<void> appStartup(AppStartupRef ref) async {
// 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)
]);
}

/// Widget class to manage asynchronous app initialization
class AppStartupWidget extends ConsumerWidget {
const AppStartupWidget({super.key, required this.onLoaded});
final WidgetBuilder onLoaded;

@override
Widget build(BuildContext context, WidgetRef ref) {
final appStartupState = ref.watch(appStartupProvider);
return appStartupState.when(
data: (_) => onLoaded(context),
loading: () => const AppStartupLoadingWidget(),
error: (e, st) => AppStartupErrorWidget(
message: e.toString(),
onRetry: () {
ref.invalidate(onboardingRepositoryProvider);
ref.invalidate(appStartupProvider);
},
),
);
}
}

class AppStartupLoadingWidget extends StatelessWidget {
const AppStartupLoadingWidget({super.key});

@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
),
);
}
}

class AppStartupErrorWidget extends StatelessWidget {
const AppStartupErrorWidget(
{super.key, required this.message, required this.onRetry});
final String message;
final VoidCallback onRetry;

@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'),
),
],
),
),
),
);
}
}
24 changes: 24 additions & 0 deletions lib/src/app_startup.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 96a52cb

Please sign in to comment.