diff --git a/lib/main.dart b/lib/main.dart index ba5b78e44..4ffb168f6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,9 +5,12 @@ import 'dart:isolate'; import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/entities/language_service.dart'; import 'package:cake_wallet/buy/order.dart'; +import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/ionia/ionia_category.dart'; import 'package:cake_wallet/ionia/ionia_merchant.dart'; +import 'package:cake_wallet/src/screens/failure_page.dart'; import 'package:cake_wallet/store/yat/yat_store.dart'; +import 'package:cake_wallet/themes/theme_list.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -50,24 +53,28 @@ Future main() async { WidgetsFlutterBinding.ensureInitialized(); FlutterError.onError = (errorDetails) { + print("@@@@@@@@@@@@@@@"); + print("FlutterError.onError"); + print(errorDetails); _saveException(errorDetails.exception.toString(), errorDetails.stack); }; + ErrorWidget.builder = (errorDetails) { + return FailurePage( + error: errorDetails.exception.toString(), + stackTrace: errorDetails.stack, + ); + }; + + /// A callback that is invoked when an unhandled error occurs in the root + /// isolate. PlatformDispatcher.instance.onError = (error, stack) { + print("@@@@@@@@@@@@@@@"); + print("PlatformDispatcher.instance.onError"); _saveException(error.toString(), stack); return true; }; - Isolate.current.addErrorListener(RawReceivePort((pair) async { - final errorAndStacktrace = pair as List; - _saveException( - errorAndStacktrace.first, - errorAndStacktrace.last == null - ? null - : StackTrace.fromString(errorAndStacktrace.last!), - ); - }).sendPort); - final appDir = await getApplicationDocumentsDirectory(); await Hive.close(); Hive.init(appDir.path); @@ -153,29 +160,49 @@ Future main() async { secureStorage: secureStorage, initialMigrationVersion: 17); runApp(App()); - }, (error, stackTrace) { + }, (error, stackTrace) async { _saveException(error.toString(), stackTrace); - runApp(MaterialApp( + final sharedPreferences = await SharedPreferences.getInstance(); + final theme = ThemeList.deserialize( + raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? 0); + + final savedLanguageCode = + sharedPreferences.getString(PreferencesKey.currentLanguageCode) ?? + await LanguageService.localeDetection(); + runApp( + MaterialApp( debugShowCheckedModeBanner: true, + theme: theme.themeData, + localizationsDelegates: [ + S.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: S.delegate.supportedLocales, + locale: Locale(savedLanguageCode), home: Scaffold( - body: Container( - margin: - EdgeInsets.only(top: 50, left: 20, right: 20, bottom: 20), - child: Text( - 'Error:\n${error.toString()}\nStacktrace: $stackTrace', - style: TextStyle(fontSize: 22), - ))))); + body: FailurePage( + error: error.toString(), + stackTrace: stackTrace, + ), + ), + ), + ); }); } void _saveException(String? error, StackTrace? stackTrace) async { - final file = File('/error.txt'); + final appDocDir = await getApplicationDocumentsDirectory(); + + final file = File('${appDocDir.path}/error.txt'); final exception = { "${DateTime.now()}": { "error": error, "stackTrace": stackTrace.toString(), } }; + await file.writeAsString(jsonEncode(exception), mode: FileMode.append); } diff --git a/lib/src/screens/failure_page.dart b/lib/src/screens/failure_page.dart new file mode 100644 index 000000000..ea3d75fcb --- /dev/null +++ b/lib/src/screens/failure_page.dart @@ -0,0 +1,87 @@ +import 'dart:io'; + +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mailer/flutter_mailer.dart'; +import 'package:path_provider/path_provider.dart'; + +class FailurePage extends StatelessWidget { + final String? error; + final StackTrace? stackTrace; + + FailurePage({Key? key, this.error, this.stackTrace}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return Scaffold( + backgroundColor: Colors.grey.shade400, + body: Center( + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: MediaQuery.of(context).size.width * 0.2), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Icon( + Icons.warning, + color: theme.errorColor, + size: 50, + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: Text( + "Oops, we got some error.", + style: theme.textTheme.headline1?.copyWith(fontSize: 20), + ), + ), + Text( + "Please send crash report to our support team to make the application better.", + textAlign: TextAlign.center, + style: theme.textTheme.headline1?.copyWith(fontSize: 16), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: PrimaryButton( + onPressed: _sendExceptionFile, + text: S.of(context).send, + textColor: Colors.white, + color: theme.accentTextTheme.bodyText1!.color!, + ), + ), + PrimaryButton( + onPressed: () { + }, + text: "Don't Send", + color: Theme.of(context).accentTextTheme.caption!.color!, + textColor: + Theme.of(context).primaryTextTheme.headline6!.color!, + ), + ], + ), + ), + ), + ); + } + + void _sendExceptionFile() async { + final appDocDir = await getApplicationDocumentsDirectory(); + + final file = File('${appDocDir.path}/error.txt'); + + print(file.readAsStringSync()); + + final MailOptions mailOptions = MailOptions( + subject: 'Mobile App Issue', + recipients: ['support@cakewallet.com'], + attachments: [file.path], + ); + + await FlutterMailer.send(mailOptions); + + // clear file content + // file.writeAsString("", mode: FileMode.write); + } +} diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 248a06de0..fe5e6efc4 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -61,6 +61,7 @@ dependencies: permission_handler: ^10.0.0 device_display_brightness: ^0.0.6 platform_device_id: ^1.0.1 + flutter_mailer: ^2.0.1 cake_backup: git: url: https://github.com/cake-tech/cake_backup.git