Skip to content

Commit 96a52cb

Browse files
authored
Add AppStartupWidget class for asynchronous app initialization (bizz84#146)
* Add AppStartupWidget class for asynchronous app initialization * Use ref.invalidate inside onRetry
1 parent d6d17c3 commit 96a52cb

File tree

3 files changed

+114
-12
lines changed

3 files changed

+114
-12
lines changed

lib/main.dart

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,24 @@
1-
import 'package:firebase_core/firebase_core.dart';
21
import 'package:flutter/foundation.dart';
32
import 'package:flutter/material.dart';
43
import 'package:flutter_riverpod/flutter_riverpod.dart';
5-
import 'package:starter_architecture_flutter_firebase/firebase_options.dart';
64
import 'package:starter_architecture_flutter_firebase/src/app.dart';
5+
import 'package:starter_architecture_flutter_firebase/src/app_startup.dart';
76
import 'package:starter_architecture_flutter_firebase/src/localization/string_hardcoded.dart';
8-
import 'package:starter_architecture_flutter_firebase/src/features/onboarding/data/onboarding_repository.dart';
97
// ignore:depend_on_referenced_packages
108
import 'package:flutter_web_plugins/url_strategy.dart';
119

1210
Future<void> main() async {
1311
WidgetsFlutterBinding.ensureInitialized();
14-
await Firebase.initializeApp(
15-
options: DefaultFirebaseOptions.currentPlatform,
16-
);
1712
// turn off the # in the URLs on the web
1813
usePathUrlStrategy();
1914
// * Register error handlers. For more info, see:
2015
// * https://docs.flutter.dev/testing/errors
2116
registerErrorHandlers();
2217
// * Entry point of the app
23-
24-
final container = ProviderContainer();
25-
await container.read(onboardingRepositoryProvider.future);
26-
runApp(UncontrolledProviderScope(
27-
container: container,
28-
child: const MyApp(),
18+
runApp(ProviderScope(
19+
child: AppStartupWidget(
20+
onLoaded: (context) => const MyApp(),
21+
),
2922
));
3023
}
3124

lib/src/app_startup.dart

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import 'package:firebase_core/firebase_core.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:flutter_riverpod/flutter_riverpod.dart';
4+
import 'package:riverpod_annotation/riverpod_annotation.dart';
5+
import 'package:starter_architecture_flutter_firebase/firebase_options.dart';
6+
import 'package:starter_architecture_flutter_firebase/src/constants/app_sizes.dart';
7+
import 'package:starter_architecture_flutter_firebase/src/features/onboarding/data/onboarding_repository.dart';
8+
9+
part 'app_startup.g.dart';
10+
11+
@Riverpod(keepAlive: true)
12+
Future<void> appStartup(AppStartupRef ref) async {
13+
// await for all initialization code to be complete before returning
14+
await Future.wait([
15+
// Firebase init
16+
Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform),
17+
// list of providers to be warmed up
18+
ref.watch(onboardingRepositoryProvider.future)
19+
]);
20+
}
21+
22+
/// Widget class to manage asynchronous app initialization
23+
class AppStartupWidget extends ConsumerWidget {
24+
const AppStartupWidget({super.key, required this.onLoaded});
25+
final WidgetBuilder onLoaded;
26+
27+
@override
28+
Widget build(BuildContext context, WidgetRef ref) {
29+
final appStartupState = ref.watch(appStartupProvider);
30+
return appStartupState.when(
31+
data: (_) => onLoaded(context),
32+
loading: () => const AppStartupLoadingWidget(),
33+
error: (e, st) => AppStartupErrorWidget(
34+
message: e.toString(),
35+
onRetry: () {
36+
ref.invalidate(onboardingRepositoryProvider);
37+
ref.invalidate(appStartupProvider);
38+
},
39+
),
40+
);
41+
}
42+
}
43+
44+
class AppStartupLoadingWidget extends StatelessWidget {
45+
const AppStartupLoadingWidget({super.key});
46+
47+
@override
48+
Widget build(BuildContext context) {
49+
return const MaterialApp(
50+
home: Scaffold(
51+
body: Center(
52+
child: CircularProgressIndicator(),
53+
),
54+
),
55+
);
56+
}
57+
}
58+
59+
class AppStartupErrorWidget extends StatelessWidget {
60+
const AppStartupErrorWidget(
61+
{super.key, required this.message, required this.onRetry});
62+
final String message;
63+
final VoidCallback onRetry;
64+
65+
@override
66+
Widget build(BuildContext context) {
67+
return MaterialApp(
68+
home: Scaffold(
69+
body: Center(
70+
child: Column(
71+
mainAxisSize: MainAxisSize.min,
72+
children: [
73+
Text(message, style: Theme.of(context).textTheme.headlineSmall),
74+
gapH16,
75+
ElevatedButton(
76+
onPressed: onRetry,
77+
child: const Text('Retry'),
78+
),
79+
],
80+
),
81+
),
82+
),
83+
);
84+
}
85+
}

lib/src/app_startup.g.dart

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)