Line data Source code
1 : import 'package:fast_immutable_collections/fast_immutable_collections.dart';
2 : import 'package:firebase_core/firebase_core.dart';
3 : import 'package:flutter/material.dart';
4 : import 'package:flutter_redux/flutter_redux.dart';
5 : import 'package:redux/redux.dart';
6 :
7 : import '../../auth/utils/login_configs.dart';
8 : import '../../navigation/actions/remove_current_page_action.dart';
9 : import '../../navigation/extensions/page_data_list_extension.dart';
10 : import '../../navigation/models/page_data.dart';
11 : import '../../platform/plugins/wrappers/firebase_wrapper.dart';
12 : import '../../redux/extensions/reducers_list_extension.dart';
13 : import '../../settings/extensions/brightness_mode_enum_extensions.dart';
14 : import '../../settings/extensions/theme_set_extensions.dart';
15 : import '../../settings/models/settings.dart';
16 : import '../../types/red_fire_state.dart';
17 : import '../../types/redux_action.dart';
18 : import '../../utils/red_fire_config.dart';
19 : import '../../utils/red_fire_locator.dart';
20 : import '../redux/redfire_initial_actions.dart';
21 : import '../redux/redfire_middlewares.dart';
22 : import '../redux/redfire_reducers.dart';
23 : import 'initializing_error_page.dart';
24 : import 'initializing_indicator.dart';
25 :
26 : class AppWidget<T extends RedFireState> extends StatefulWidget {
27 : late final Store<T> _store;
28 : final FirebaseWrapper _firebase;
29 : final RedFireConfig _config;
30 : final String _title;
31 : final List<ReduxAction> _initialActions;
32 :
33 : // The default constructor takes an initialized store, currently only used
34 : // in tests.
35 2 : AppWidget.fromStore(
36 : {Key? key,
37 : required Store<T> initializedStore,
38 : required Widget homePage,
39 : ISet<PageDataTransforms>? pageTransforms,
40 : FirebaseWrapper? firebaseWrapper,
41 : required RedFireConfig config,
42 : required ISet<LoginConfig> logins,
43 : String? title})
44 : : _store = initializedStore,
45 0 : _firebase = firebaseWrapper ?? FirebaseWrapper(),
46 : _config = config,
47 : _title = title ?? 'Title Not Set',
48 2 : _initialActions = [],
49 2 : super(key: key) {
50 2 : addPageTransforms<T>(homePage, logins, pageTransforms ?? ISet());
51 : }
52 :
53 0 : AppWidget(
54 : {Key? key,
55 : required T initialState,
56 : required Widget homePage,
57 : List<ReduxAction>? initialActions,
58 : List<ReduxAction>? onSignInActions,
59 : List<Reducer<T>>? reducers,
60 : List<Middleware<T>>? middlewares,
61 : ISet<PageDataTransforms>? pageTransforms,
62 : FirebaseWrapper? firebaseWrapper,
63 : required RedFireConfig config,
64 : required ISet<LoginConfig> logins,
65 : String? title})
66 0 : : _firebase = firebaseWrapper ?? FirebaseWrapper(),
67 : _config = config,
68 : _title = title ?? 'Title Not Set',
69 0 : _initialActions = initialActions ?? [],
70 0 : super(key: key) {
71 0 : addPageTransforms<T>(homePage, logins, pageTransforms ?? ISet());
72 : // create the redux store, combining any provided reducers and middleware
73 0 : _store = Store<T>((redfireReducers<T>() + (reducers ?? [])).combine(),
74 : initialState: initialState,
75 0 : middleware: [...redfireMiddlewares(), ...(middlewares ?? [])]);
76 :
77 0 : RedFireLocator.provideOnSignInActions(onSignInActions);
78 : }
79 :
80 2 : @override
81 2 : _AppWidgetState<T> createState() => _AppWidgetState<T>();
82 : }
83 :
84 : class _AppWidgetState<T extends RedFireState> extends State<AppWidget<T>> {
85 : dynamic _error;
86 : bool _initialized = false;
87 :
88 2 : @override
89 : void initState() {
90 2 : super.initState();
91 : try {
92 6 : RedFireLocator.provideConfig(widget._config);
93 8 : _initializeFlutterFire(options: widget._config.firebase);
94 : } catch (e) {
95 0 : setState(() => _error = e);
96 : }
97 : }
98 :
99 2 : void _initializeFlutterFire({FirebaseOptions? options}) async {
100 : // firebase must be initialised first so createStore() can run
101 8 : await widget._firebase.init(options);
102 :
103 : // Dispatch any actions that were passed in.
104 2 : for (final action in [
105 4 : ...(widget._initialActions),
106 2 : ...redfireInitialActions,
107 2 : ]) {
108 6 : widget._store.dispatch(action);
109 : }
110 :
111 6 : setState(() => _initialized = true);
112 : }
113 :
114 2 : @override
115 : Widget build(BuildContext context) {
116 2 : if (_error != null) {
117 0 : return InitializingErrorPage(_error, StackTrace.current);
118 : }
119 :
120 : // Show a loader until FlutterFire is initialized
121 2 : if (!_initialized) {
122 4 : return InitializingIndicator(_initialized);
123 : }
124 :
125 2 : return StoreProvider<T>(
126 4 : store: widget._store,
127 2 : child: StoreConnector<T, Settings>(
128 : distinct: true,
129 6 : converter: (store) => store.state.settings,
130 2 : builder: (context, settings) {
131 2 : return MaterialApp(
132 4 : title: widget._title,
133 4 : theme: settings.lightTheme.data,
134 4 : darkTheme: settings.darkTheme.data,
135 4 : themeMode: settings.brightnessMode.theme,
136 2 : home: StoreConnector<T, IList<PageData>>(
137 : distinct: true,
138 6 : converter: (store) => store.state.pages,
139 4 : builder: (context, pages) => Navigator(
140 2 : pages: pages.toPages<T>(),
141 0 : onPopPage: (route, dynamic result) {
142 0 : if (!route.didPop(result)) {
143 : return false;
144 : }
145 :
146 0 : if (route.isCurrent) {
147 0 : widget._store.dispatch(const RemoveCurrentPageAction());
148 : }
149 :
150 : return true;
151 : }),
152 : ),
153 : );
154 : }),
155 : );
156 : }
157 : }
|