Separate Exception Handler class from main [skip ci]
OmarHatem committed
Feb 1, 2023 at 17:37 UTC
15e7395fe9084b7d15a3501246f85f1c60cd2596
2 files changed
+108
-104
lib/main.dart
+4
-104
@@ -1,22 +1,12 @@
1
import 'dart:async';
2
-import 'dart:convert';
3
-import 'dart:io';
4
-import 'dart:isolate';
5
-import 'package:cake_wallet/bitcoin/bitcoin.dart';
2
import 'package:cake_wallet/core/auth_service.dart';
3
import 'package:cake_wallet/entities/language_service.dart';
4
import 'package:cake_wallet/buy/order.dart';
9
-import 'package:cake_wallet/entities/preferences_key.dart';
10
-import 'package:cake_wallet/ionia/ionia_category.dart';
11
-import 'package:cake_wallet/ionia/ionia_merchant.dart';
12
-import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
5
import 'package:cake_wallet/store/yat/yat_store.dart';
14
-import 'package:cake_wallet/themes/theme_list.dart';
15
-import 'package:cake_wallet/utils/show_pop_up.dart';
6
+import 'package:cake_wallet/utils/exception_handler.dart';
7
import 'package:flutter/foundation.dart';
8
import 'package:flutter/material.dart';
9
import 'package:flutter/services.dart';
19
-import 'package:flutter_mailer/flutter_mailer.dart';
10
import 'package:hive/hive.dart';
11
import 'package:cake_wallet/di.dart';
12
import 'package:path_provider/path_provider.dart';
@@ -50,21 +40,18 @@ import 'package:cake_wallet/wallet_type_utils.dart';
40
final navigatorKey = GlobalKey<NavigatorState>();
41
final rootKey = GlobalKey<RootState>();
42
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
53
-bool hasError = false;
43
44
Future<void> main() async {
45
46
await runZonedGuarded(() async {
47
WidgetsFlutterBinding.ensureInitialized();
48
60
- FlutterError.onError = (errorDetails) {
61
- _onError(errorDetails);
62
- };
49
+ FlutterError.onError = ExceptionHandler.onError;
50
51
/// A callback that is invoked when an unhandled error occurs in the root
52
/// isolate.
53
PlatformDispatcher.instance.onError = (error, stack) {
67
- _onError(FlutterErrorDetails(exception: error, stack: stack));
54
+ ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
55
56
return true;
57
};
@@ -155,97 +142,10 @@ Future<void> main() async {
142
initialMigrationVersion: 19);
143
runApp(App());
144
}, (error, stackTrace) async {
158
- _onError(FlutterErrorDetails(exception: error, stack: stackTrace));
145
+ ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
146
});
147
}
148
162
-void _saveException(String? error, StackTrace? stackTrace) async {
163
- final appDocDir = await getApplicationDocumentsDirectory();
164
-
165
- final file = File('${appDocDir.path}/error.txt');
166
- final exception = {
167
- "${DateTime.now()}": {
168
- "Error": error,
169
- "StackTrace": stackTrace.toString(),
170
- }
171
- };
172
-
173
- const String separator =
174
- '''\n\n==========================================================
175
- ==========================================================\n\n''';
176
-
177
- await file.writeAsString(
178
- jsonEncode(exception) + separator,
179
- mode: FileMode.append,
180
- );
181
-}
182
-
183
-void _sendExceptionFile() async {
184
- try {
185
- final appDocDir = await getApplicationDocumentsDirectory();
186
-
187
- final file = File('${appDocDir.path}/error.txt');
188
-
189
- final MailOptions mailOptions = MailOptions(
190
- subject: 'Mobile App Issue',
191
- recipients: ['support@cakewallet.com'],
192
- attachments: [file.path],
193
- );
194
-
195
- final result = await FlutterMailer.send(mailOptions);
196
-
197
- // Clear file content if the error was sent or saved.
198
- // On android we can't know if it was sent or saved
199
- if (result.name == MailerResponse.sent.name ||
200
- result.name == MailerResponse.saved.name ||
201
- result.name == MailerResponse.android.name) {
202
- file.writeAsString("", mode: FileMode.write);
203
- }
204
- } catch (e, s) {
205
- _saveException(e.toString(), s);
206
- }
207
-}
208
-
209
-void _onError(FlutterErrorDetails errorDetails) {
210
- // Add Exception for user's network connection issues to not be reported
211
- if (errorDetails.exception.toString().contains("Software caused connection abort")) {
212
- return;
213
- }
214
-
215
- _saveException(errorDetails.exception.toString(), errorDetails.stack);
216
-
217
- if (hasError) {
218
- return;
219
- }
220
- hasError = true;
221
-
222
- WidgetsBinding.instance.addPostFrameCallback(
223
- (timeStamp) async {
224
- await showPopUp<void>(
225
- context: navigatorKey.currentContext!,
226
- builder: (context) {
227
- return AlertWithTwoActions(
228
- isDividerExist: true,
229
- alertTitle: S.of(context).error,
230
- alertContent: S.of(context).error_dialog_content,
231
- rightButtonText: S.of(context).send,
232
- leftButtonText: S.of(context).do_not_send,
233
- actionRightButton: () {
234
- Navigator.of(context).pop();
235
- _sendExceptionFile();
236
- },
237
- actionLeftButton: () {
238
- Navigator.of(context).pop();
239
- },
240
- );
241
- },
242
- );
243
-
244
- hasError = false;
245
- },
246
- );
247
-}
248
-
149
Future<void> initialSetup(
150
{required SharedPreferences sharedPreferences,
151
required Box<Node> nodes,
lib/utils/exception_handler.dart
new
+104
@@ -0,0 +1,104 @@
1
+import 'dart:convert';
2
+import 'dart:io';
3
+
4
+import 'package:cake_wallet/generated/i18n.dart';
5
+import 'package:cake_wallet/main.dart';
6
+import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
7
+import 'package:cake_wallet/utils/show_pop_up.dart';
8
+import 'package:flutter/material.dart';
9
+import 'package:flutter_mailer/flutter_mailer.dart';
10
+import 'package:path_provider/path_provider.dart';
11
+
12
+class ExceptionHandler {
13
+ static bool _hasError = false;
14
+
15
+ static void _saveException(String? error, StackTrace? stackTrace) async {
16
+ final appDocDir = await getApplicationDocumentsDirectory();
17
+
18
+ final file = File('${appDocDir.path}/error.txt');
19
+ final exception = {
20
+ "${DateTime.now()}": {
21
+ "Error": error,
22
+ "StackTrace": stackTrace.toString(),
23
+ }
24
+ };
25
+
26
+ const String separator = '''\n\n==========================================================
27
+ ==========================================================\n\n''';
28
+
29
+ await file.writeAsString(
30
+ jsonEncode(exception) + separator,
31
+ mode: FileMode.append,
32
+ );
33
+ }
34
+
35
+ static void _sendExceptionFile() async {
36
+ try {
37
+ final appDocDir = await getApplicationDocumentsDirectory();
38
+
39
+ final file = File('${appDocDir.path}/error.txt');
40
+
41
+ final MailOptions mailOptions = MailOptions(
42
+ subject: 'Mobile App Issue',
43
+ recipients: ['support@cakewallet.com'],
44
+ attachments: [file.path],
45
+ );
46
+
47
+ final result = await FlutterMailer.send(mailOptions);
48
+
49
+ // Clear file content if the error was sent or saved.
50
+ // On android we can't know if it was sent or saved
51
+ if (result.name == MailerResponse.sent.name ||
52
+ result.name == MailerResponse.saved.name ||
53
+ result.name == MailerResponse.android.name) {
54
+ file.writeAsString("", mode: FileMode.write);
55
+ }
56
+ } catch (e, s) {
57
+ _saveException(e.toString(), s);
58
+ }
59
+ }
60
+
61
+ static void onError(FlutterErrorDetails errorDetails) {
62
+ if (_isErrorFromUser(errorDetails.exception.toString())) {
63
+ return;
64
+ }
65
+
66
+ _saveException(errorDetails.exception.toString(), errorDetails.stack);
67
+
68
+ if (_hasError) {
69
+ return;
70
+ }
71
+ _hasError = true;
72
+
73
+ WidgetsBinding.instance.addPostFrameCallback(
74
+ (timeStamp) async {
75
+ await showPopUp<void>(
76
+ context: navigatorKey.currentContext!,
77
+ builder: (context) {
78
+ return AlertWithTwoActions(
79
+ isDividerExist: true,
80
+ alertTitle: S.of(context).error,
81
+ alertContent: S.of(context).error_dialog_content,
82
+ rightButtonText: S.of(context).send,
83
+ leftButtonText: S.of(context).do_not_send,
84
+ actionRightButton: () {
85
+ Navigator.of(context).pop();
86
+ _sendExceptionFile();
87
+ },
88
+ actionLeftButton: () {
89
+ Navigator.of(context).pop();
90
+ },
91
+ );
92
+ },
93
+ );
94
+
95
+ _hasError = false;
96
+ },
97
+ );
98
+ }
99
+
100
+ /// User related errors to be added as exceptions here to not report
101
+ static bool _isErrorFromUser(String error) {
102
+ return error.contains("Software caused connection abort"); // User connection issue
103
+ }
104
+}