Show popup on un-caught exceptions to send errors via email

OmarHatem committed Jan 6, 2023 at 19:42 UTC e904c0a7b751cee11031dd953ddf035df2d7f872
3 files changed +40 -114
lib/main.dart
+39 -26
@@ -9,7 +9,6 @@ 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/screens/failure_page.dart';
12 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
13 import 'package:cake_wallet/store/yat/yat_store.dart';
14 import 'package:cake_wallet/themes/theme_list.dart';
@@ -17,6 +16,7 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
16 import 'package:flutter/foundation.dart';
17 import 'package:flutter/material.dart';
18 import 'package:flutter/services.dart';
19 +import 'package:flutter_mailer/flutter_mailer.dart';
20 import 'package:hive/hive.dart';
21 import 'package:cake_wallet/di.dart';
22 import 'package:path_provider/path_provider.dart';
@@ -57,31 +57,14 @@ Future<void> main() async {
57 WidgetsFlutterBinding.ensureInitialized();
58
59 FlutterError.onError = (errorDetails) {
60 - print("@@@@@@@@@@@@@@@@@ in on error");
61 - print(errorDetails.exception.toString());
60 _onError(errorDetails);
63 - _saveException(errorDetails.exception.toString(), errorDetails.stack);
64 - };
65 -
66 - ErrorWidget.builder = (errorDetails) {
67 - print("@@@@@@@@@@@@@@@@@ in widget error");
68 - // TODO: uncomment
69 - // if (kDebugMode) {
70 - // return ErrorWidget(errorDetails.exception);
71 - // }
72 -
73 - return FailurePage(
74 - error: errorDetails.exception.toString(),
75 - stackTrace: errorDetails.stack,
76 - );
61 };
62
63 /// A callback that is invoked when an unhandled error occurs in the root
64 /// isolate.
65 PlatformDispatcher.instance.onError = (error, stack) {
82 - print("@@@@@@@@@@@@@@@");
83 - print("PlatformDispatcher.instance.onError");
84 - _saveException(error.toString(), stack);
66 + _onError(FlutterErrorDetails(exception: error, stack: stack));
67 +
68 return true;
69 };
70
@@ -187,12 +170,42 @@ void _saveException(String? error, StackTrace? stackTrace) async {
170 }
171 };
172
190 - await file.writeAsString(jsonEncode(exception), mode: FileMode.append);
173 + String separator = "\n\n==========================================================" +
174 + "\n==========================================================\n\n";
175 +
176 + await file.writeAsString(
177 + jsonEncode(exception) + separator,
178 + mode: FileMode.append,
179 + );
180 }
181
193 -void _onError(FlutterErrorDetails details) {
194 - print("#############");
195 - print(details.exception.toString());
182 +void _sendExceptionFile() async {
183 + final appDocDir = await getApplicationDocumentsDirectory();
184 +
185 + final file = File('${appDocDir.path}/error.txt');
186 +
187 + print(file.readAsStringSync());
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 +}
205 +
206 +void _onError(FlutterErrorDetails errorDetails) {
207 + _saveException(errorDetails.exception.toString(), errorDetails.stack);
208 +
209 WidgetsBinding.instance.addPostFrameCallback(
210 (timeStamp) {
211 showPopUp<void>(
@@ -204,12 +217,12 @@ void _onError(FlutterErrorDetails details) {
217 alertContent: "Oops, we got some error.\n\nPlease send crash report to our support team to make the application better.",
218 rightButtonText: S.of(context).send,
219 leftButtonText: "Don't send",
207 - actionRightButton: () async {
220 + actionRightButton: () {
221 Navigator.of(context).pop();
222 + _sendExceptionFile();
223 },
224 actionLeftButton: () {
225 Navigator.of(context).pop();
212 - _saveException(details.exception.toString(), details.stack);
226 },
227 );
228 },
lib/src/screens/failure_page.dart deleted
-87
@@ -1,87 +0,0 @@
1 -import 'dart:io';
2 -
3 -import 'package:cake_wallet/generated/i18n.dart';
4 -import 'package:cake_wallet/src/widgets/primary_button.dart';
5 -import 'package:flutter/material.dart';
6 -import 'package:flutter_mailer/flutter_mailer.dart';
7 -import 'package:path_provider/path_provider.dart';
8 -
9 -class FailurePage extends StatelessWidget {
10 - final String? error;
11 - final StackTrace? stackTrace;
12 -
13 - FailurePage({Key? key, this.error, this.stackTrace});
14 -
15 - @override
16 - Widget build(BuildContext context) {
17 - final theme = Theme.of(context);
18 - return Scaffold(
19 - backgroundColor: Colors.grey.shade400,
20 - body: Center(
21 - child: Padding(
22 - padding: EdgeInsets.symmetric(
23 - horizontal: MediaQuery.of(context).size.width * 0.2),
24 - child: Column(
25 - mainAxisSize: MainAxisSize.min,
26 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
27 - children: [
28 - Icon(
29 - Icons.warning,
30 - color: theme.errorColor,
31 - size: 50,
32 - ),
33 - Padding(
34 - padding: const EdgeInsets.symmetric(vertical: 20),
35 - child: Text(
36 - "Oops, we got some error.",
37 - style: theme.textTheme.headline1?.copyWith(fontSize: 20),
38 - ),
39 - ),
40 - Text(
41 - "Please send crash report to our support team to make the application better.",
42 - textAlign: TextAlign.center,
43 - style: theme.textTheme.headline1?.copyWith(fontSize: 16),
44 - ),
45 - Padding(
46 - padding: const EdgeInsets.symmetric(vertical: 20),
47 - child: PrimaryButton(
48 - onPressed: _sendExceptionFile,
49 - text: S.of(context).send,
50 - textColor: Colors.white,
51 - color: theme.accentTextTheme.bodyText1!.color!,
52 - ),
53 - ),
54 - PrimaryButton(
55 - onPressed: () {
56 - },
57 - text: "Don't Send",
58 - color: Theme.of(context).accentTextTheme.caption!.color!,
59 - textColor:
60 - Theme.of(context).primaryTextTheme.headline6!.color!,
61 - ),
62 - ],
63 - ),
64 - ),
65 - ),
66 - );
67 - }
68 -
69 - void _sendExceptionFile() async {
70 - final appDocDir = await getApplicationDocumentsDirectory();
71 -
72 - final file = File('${appDocDir.path}/error.txt');
73 -
74 - print(file.readAsStringSync());
75 -
76 - final MailOptions mailOptions = MailOptions(
77 - subject: 'Mobile App Issue',
78 - recipients: ['support@cakewallet.com'],
79 - attachments: [file.path],
80 - );
81 -
82 - await FlutterMailer.send(mailOptions);
83 -
84 - // clear file content
85 - // file.writeAsString("", mode: FileMode.write);
86 - }
87 -}
pubspec_base.yaml
+1 -1
@@ -61,7 +61,7 @@ dependencies:
61 permission_handler: ^10.0.0
62 device_display_brightness: ^0.0.6
63 platform_device_id: ^1.0.1
64 - flutter_mailer: ^2.0.1
64 + flutter_mailer: ^2.0.2
65 cake_backup:
66 git:
67 url: https://github.com/cake-tech/cake_backup.git