Line data Source code
1 : // Copyright 2023 The terCAD team. All rights reserved.
2 : // Use of this source code is governed by a CC BY-NC-ND 4.0 license that can be found in the LICENSE file.
3 :
4 : import 'dart:async';
5 :
6 : import 'package:app_finance/_classes/controller/fallback_localization_delegate.dart';
7 : import 'package:app_finance/_classes/herald/app_design.dart';
8 : import 'package:app_finance/_classes/herald/app_locale.dart';
9 : import 'package:app_finance/_classes/herald/app_palette.dart';
10 : import 'package:app_finance/_classes/herald/app_purchase.dart';
11 : import 'package:app_finance/_classes/herald/app_sync.dart';
12 : import 'package:app_finance/_classes/herald/app_theme.dart';
13 : import 'package:app_finance/_classes/herald/app_zoom.dart';
14 : import 'package:app_finance/_classes/storage/app_preferences.dart';
15 : import 'package:app_finance/_classes/structure/navigation/app_page_route.dart';
16 : import 'package:app_finance/_configs/custom_color_scheme.dart';
17 : import 'package:app_finance/_configs/custom_text_theme.dart';
18 : import 'package:app_finance/_classes/storage/app_data.dart';
19 : import 'package:app_finance/_classes/structure/navigation/app_route.dart';
20 : import 'package:app_finance/_configs/firebase_options.dart';
21 : import 'package:app_finance/pages/about/about_page.dart';
22 : import 'package:app_finance/pages/account/account_add_page.dart';
23 : import 'package:app_finance/pages/account/account_edit_page.dart';
24 : import 'package:app_finance/pages/account/account_view_page.dart';
25 : import 'package:app_finance/pages/account/account_page.dart';
26 : import 'package:app_finance/pages/automation/automation_page.dart';
27 : import 'package:app_finance/pages/bill/bill_add_page.dart';
28 : import 'package:app_finance/pages/bill/bill_edit_page.dart';
29 : import 'package:app_finance/pages/bill/bill_page.dart';
30 : import 'package:app_finance/pages/bill/bill_view_page.dart';
31 : import 'package:app_finance/pages/budget/budget_page.dart';
32 : import 'package:app_finance/pages/budget/budget_add_page.dart';
33 : import 'package:app_finance/pages/budget/budget_edit_page.dart';
34 : import 'package:app_finance/pages/budget/budget_view_page.dart';
35 : import 'package:app_finance/pages/currency/currency_add_page.dart';
36 : import 'package:app_finance/pages/currency/currency_page.dart';
37 : import 'package:app_finance/pages/goal/goal_add_page.dart';
38 : import 'package:app_finance/pages/goal/goal_edit_page.dart';
39 : import 'package:app_finance/pages/goal/goal_page.dart';
40 : import 'package:app_finance/pages/goal/goal_view_page.dart';
41 : import 'package:app_finance/pages/home/home_page.dart';
42 : import 'package:app_finance/pages/invoice/invoice_edit_page.dart';
43 : import 'package:app_finance/pages/invoice/invoice_view_page.dart';
44 : import 'package:app_finance/pages/metrics/metrics_page.dart';
45 : import 'package:app_finance/pages/settings/settings_page.dart';
46 : import 'package:app_finance/pages/start/start_page.dart';
47 : import 'package:app_finance/pages/subscription/subscription_page.dart';
48 : import 'package:firebase_analytics/firebase_analytics.dart';
49 : import 'package:firebase_core/firebase_core.dart';
50 : import 'package:firebase_crashlytics/firebase_crashlytics.dart';
51 : import 'package:flutter/foundation.dart';
52 : import 'package:flutter/material.dart';
53 : import 'package:flutter_currency_picker/flutter_currency_picker.dart';
54 : import 'package:flutter_gen/gen_l10n/app_localization.dart';
55 : import 'package:provider/provider.dart';
56 : import 'package:shared_preferences/shared_preferences.dart';
57 :
58 0 : void main() async {
59 0 : final platform = DefaultFirebaseOptions.currentPlatform;
60 0 : runZonedGuarded<Future<void>>(() async {
61 0 : WidgetsFlutterBinding.ensureInitialized();
62 : if (platform != null) {
63 0 : await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
64 0 : FirebaseAnalytics.instance.logAppOpen();
65 0 : PlatformDispatcher.instance.onError = (error, stack) {
66 0 : FirebaseAnalytics.instance.logEvent(
67 : name: 'platform-error',
68 0 : parameters: {'error': error.toString(), 'trace': stack.toString()},
69 : );
70 : return true;
71 : };
72 : if (kIsWeb) {
73 0 : FlutterError.onError = (details) {
74 0 : FlutterError.presentError(details);
75 0 : FirebaseAnalytics.instance.logEvent(name: 'flutter-error', parameters: {'error': details.toString()});
76 : };
77 : } else {
78 0 : FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError;
79 : }
80 : }
81 0 : AppPreferences.pref = await SharedPreferences.getInstance();
82 0 : CurrencyDefaults.cache = AppPreferences.pref;
83 0 : final appSync = AppSync();
84 0 : runApp(
85 0 : MultiProvider(
86 0 : providers: [
87 0 : ChangeNotifierProvider<AppSync>(
88 0 : create: (_) => appSync,
89 : ),
90 0 : ChangeNotifierProvider<AppData>(
91 0 : create: (_) => AppData(appSync),
92 : ),
93 0 : ChangeNotifierProvider<AppTheme>(
94 0 : create: (_) => AppTheme(ThemeMode.system),
95 : ),
96 0 : ChangeNotifierProvider<AppLocale>(
97 0 : create: (_) => AppLocale(),
98 : ),
99 0 : ChangeNotifierProvider<AppDesign>(
100 0 : create: (_) => AppDesign(),
101 : ),
102 0 : ChangeNotifierProvider<AppZoom>(
103 0 : create: (_) => AppZoom(),
104 : ),
105 0 : ChangeNotifierProvider<AppPalette>(
106 0 : create: (_) => AppPalette(),
107 : ),
108 0 : ChangeNotifierProvider<AppPurchase>(
109 0 : create: (_) => AppPurchase(),
110 : ),
111 : ],
112 0 : child: MyApp(platform: platform),
113 : ),
114 : );
115 0 : }, (error, stack) {
116 : if (platform != null) {
117 : if (kIsWeb) {
118 0 : FirebaseAnalytics.instance.logEvent(name: 'flutter-error', parameters: {'error': error.toString()});
119 : } else {
120 0 : FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
121 : }
122 : }
123 0 : FlutterError.presentError(FlutterErrorDetails(exception: error, stack: stack));
124 : // SystemNavigator.pop();
125 : });
126 : }
127 :
128 : class MyApp extends StatefulWidget {
129 : final FirebaseOptions? platform;
130 4 : const MyApp({super.key, this.platform});
131 :
132 3 : @override
133 3 : MyAppState createState() => MyAppState();
134 : }
135 :
136 : class MyAppState extends State<MyApp> {
137 3 : WidgetBuilder? getPage(String route, Object? arguments) {
138 : AppRoute.current = route;
139 6 : if (widget.platform != null) {
140 0 : FirebaseAnalytics.instance.logSelectContent(
141 : contentType: route,
142 : itemId: arguments != null ? 'dynamic' : 'static',
143 : );
144 : }
145 : final args = arguments as Map<String, dynamic>?;
146 0 : final String key = args?['uuid'] ?? args?['search'] ?? '';
147 :
148 3 : Widget router(String route) => switch (route) {
149 3 : AppRoute.aboutRoute => AboutPage(search: key),
150 3 : AppRoute.accountRoute => const AccountPage(),
151 2 : AppRoute.accountAddRoute => const AccountAddPage(),
152 2 : AppRoute.accountViewRoute => AccountViewPage(uuid: key),
153 2 : AppRoute.accountSearchRoute => AccountPage(search: key),
154 2 : AppRoute.accountEditRoute => AccountEditPage(uuid: key),
155 2 : AppRoute.automationRoute => const AutomationPage(),
156 2 : AppRoute.billRoute => const BillPage(),
157 2 : AppRoute.billAddRoute => const BillAddPage(),
158 1 : AppRoute.billViewRoute => BillViewPage(uuid: key),
159 1 : AppRoute.billEditRoute => BillEditPage(uuid: key),
160 1 : AppRoute.budgetRoute => const BudgetPage(),
161 1 : AppRoute.budgetAddRoute => const BudgetAddPage(),
162 1 : AppRoute.budgetViewRoute => BudgetViewPage(uuid: key),
163 1 : AppRoute.budgetSearchRoute => BudgetPage(search: key),
164 1 : AppRoute.budgetEditRoute => BudgetEditPage(uuid: key),
165 1 : AppRoute.currencyRoute => const CurrencyPage(),
166 1 : AppRoute.currencyAddRoute => const CurrencyAddPage(),
167 1 : AppRoute.goalRoute => const GoalPage(),
168 0 : AppRoute.goalAddRoute => const GoalAddPage(),
169 0 : AppRoute.goalViewRoute => GoalViewPage(uuid: key),
170 0 : AppRoute.goalEditRoute => GoalEditPage(uuid: key),
171 0 : AppRoute.invoiceViewRoute => InvoiceViewPage(uuid: key),
172 0 : AppRoute.invoiceEditRoute => InvoiceEditPage(uuid: key),
173 0 : AppRoute.homeRoute => const HomePage(),
174 0 : AppRoute.metricsRoute => const MetricsPage(),
175 0 : AppRoute.metricsSearchRoute => MetricsPage(search: key),
176 0 : AppRoute.settingsRoute => const SettingsPage(),
177 0 : AppRoute.startRoute => const StartPage(),
178 0 : AppRoute.subscriptionRoute => const SubscriptionPage(),
179 : _ => const HomePage(),
180 : };
181 6 : return (_) => Directionality(
182 : textDirection: TextDirection.ltr,
183 3 : child: router(route),
184 : );
185 : }
186 :
187 3 : @override
188 : Widget build(BuildContext context) {
189 6 : final palette = context.watch<AppPalette>().value;
190 9 : final text = Theme.of(context).textTheme.withCustom(palette, Brightness.light);
191 9 : final textDark = Theme.of(context).textTheme.withCustom(palette, Brightness.dark);
192 9 : final sheet = Theme.of(context).bottomSheetTheme.copyWith(
193 : constraints: const BoxConstraints(maxWidth: double.infinity),
194 : );
195 3 : return MaterialApp(
196 : debugShowCheckedModeBanner: false,
197 3 : localizationsDelegates: [
198 : ...AppLocalizations.localizationsDelegates,
199 3 : FallbackLocalizationDelegate(),
200 : ],
201 : supportedLocales: AppLocalizations.supportedLocales,
202 6 : locale: context.watch<AppLocale>().value,
203 3 : theme: ThemeData(
204 3 : colorScheme: const ColorScheme.light().withCustom(palette),
205 3 : floatingActionButtonTheme: const FloatingActionButtonThemeData().withCustom(palette, Brightness.light),
206 : brightness: Brightness.light,
207 : textTheme: text,
208 6 : datePickerTheme: DatePickerTheme.of(context).withCustom(palette, text, Brightness.light),
209 6 : timePickerTheme: TimePickerTheme.of(context).withCustom(palette, text, Brightness.light),
210 3 : dividerTheme: CustomDividerTheme(palette, Brightness.light),
211 : bottomSheetTheme: sheet,
212 : useMaterial3: true,
213 : ),
214 3 : darkTheme: ThemeData(
215 3 : colorScheme: const ColorScheme.dark().withCustom(palette),
216 3 : floatingActionButtonTheme: const FloatingActionButtonThemeData().withCustom(palette, Brightness.dark),
217 : brightness: Brightness.dark,
218 : textTheme: textDark,
219 6 : datePickerTheme: DatePickerTheme.of(context).withCustom(palette, textDark, Brightness.dark),
220 6 : timePickerTheme: TimePickerTheme.of(context).withCustom(palette, textDark, Brightness.dark),
221 3 : dividerTheme: CustomDividerTheme(palette, Brightness.dark),
222 : bottomSheetTheme: sheet,
223 : useMaterial3: true,
224 : ),
225 6 : themeMode: context.watch<AppTheme>().value,
226 : home: const Directionality(
227 : textDirection: TextDirection.ltr,
228 : child: HomePage(),
229 : ),
230 15 : onGenerateRoute: (settings) => AppPageRoute(builder: getPage(settings.name ?? '', settings.arguments)!),
231 : );
232 : }
233 : }
|