diff --git a/src/ui/flutter/lib/common/profile.dart b/src/ui/flutter/lib/common/profile.dart index bde6b4c2..fb1e5dc5 100644 --- a/src/ui/flutter/lib/common/profile.dart +++ b/src/ui/flutter/lib/common/profile.dart @@ -44,13 +44,8 @@ class Profile { Future commit() async { _file.create(recursive: true); - try { - final contents = jsonEncode(_values); - await _file.writeAsString(contents); - } catch (e) { - print('Error: $e'); - return false; - } + final contents = jsonEncode(_values); + await _file.writeAsString(contents); return true; } @@ -59,12 +54,8 @@ class Profile { final docDir = await getApplicationDocumentsDirectory(); _file = File('${docDir.path}/$fileName'); - try { - final contents = await _file.readAsString(); - _values = jsonDecode(contents); - } catch (e) { - return false; - } + final contents = await _file.readAsString(); + _values = jsonDecode(contents); return true; } diff --git a/src/ui/flutter/lib/engine/native_engine.dart b/src/ui/flutter/lib/engine/native_engine.dart index ae6c3f01..3e19d745 100644 --- a/src/ui/flutter/lib/engine/native_engine.dart +++ b/src/ui/flutter/lib/engine/native_engine.dart @@ -27,60 +27,29 @@ class NativeEngine extends AiEngine { static const platform = const MethodChannel('com.calcitem.sanmill/engine'); Future startup() async { - try { - await platform.invokeMethod('startup'); - } catch (e) { - print('Native startup Error: $e'); - } - + await platform.invokeMethod('startup'); await waitResponse(['uciok'], sleep: 1, times: 30); } Future send(String command) async { - try { - print("send: $command"); - await platform.invokeMethod('send', command); - } catch (e) { - print('Native sendCommand Error: $e'); - } + print("send: $command"); + await platform.invokeMethod('send', command); } Future read() async { - try { - return await platform.invokeMethod('read'); - } catch (e) { - print('Native readResponse Error: $e'); - } - - return null; + return await platform.invokeMethod('read'); } Future shutdown() async { - try { - await platform.invokeMethod('shutdown'); - } catch (e) { - print('Native shutdown Error: $e'); - } + await platform.invokeMethod('shutdown'); } Future isReady() async { - try { - return await platform.invokeMethod('isReady'); - } catch (e) { - print('Native readResponse Error: $e'); - } - - return null; + return await platform.invokeMethod('isReady'); } Future isThinking() async { - try { - return await platform.invokeMethod('isThinking'); - } catch (e) { - print('Native readResponse Error: $e'); - } - - return null; + return await platform.invokeMethod('isThinking'); } @override diff --git a/src/ui/flutter/lib/main.dart b/src/ui/flutter/lib/main.dart index dbb45977..870831c6 100644 --- a/src/ui/flutter/lib/main.dart +++ b/src/ui/flutter/lib/main.dart @@ -18,29 +18,62 @@ import 'dart:io'; -import 'package:flutter/foundation.dart'; +import 'package:catcher/catcher.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:sanmill/generated/l10n.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; import 'services/audios.dart'; import 'services/player.dart'; import 'widgets/main_menu.dart'; Future main() async { - if (kReleaseMode) { - await SentryFlutter.init( - (options) { - options.dsn = - 'https://62c565096ba146a6b70bc57dbb72386c@o525088.ingest.sentry.io/5638585'; - }, - appRunner: () => runApp(SanmillApp()), - ); - } else { - runApp(SanmillApp()); - } + var catcher = Catcher(rootWidget: SanmillApp(), ensureInitialized: true); + + //DateTime now = DateTime.now(); + //String formattedDate = DateFormat('yyyy-MM-dd_kk-mm').format(now); + Directory externalDir = await getExternalStorageDirectory(); + String path = externalDir.path.toString() + "/sanmill-crash-logs.txt"; + print("ExternalStorageDirectory: " + externalDir.path.toString()); + String recipients = "calcitem@outlook.com"; + + /// Create catcher configuration. + /// Debug configuration with dialog report mode and console handler. + /// It will show dialog and once user accepts it, error will be shown + /// in console. + //CatcherOptions debugOptions = CatcherOptions( + // PageReportMode(showStackTrace: true), [ConsoleHandler()]); + CatcherOptions debugOptions = + CatcherOptions(PageReportMode(showStackTrace: true), [ + ConsoleHandler(), + FileHandler(File(path), printLogs: true), + EmailManualHandler([recipients], printLogs: true) + ]); + + /// Release configuration. + /// Same as above, but once user accepts dialog, + /// user will be prompted to send email with crash to support. + CatcherOptions releaseOptions = + CatcherOptions(PageReportMode(showStackTrace: true), [ + FileHandler(File(path), printLogs: true), + EmailManualHandler([recipients], printLogs: true) + ]); + + CatcherOptions profileOptions = + CatcherOptions(PageReportMode(showStackTrace: true), [ + ConsoleHandler(), + FileHandler(File(path), printLogs: true), + EmailManualHandler([recipients], printLogs: true) + ]); + + /// Pass root widget (MyApp) along with Catcher configuration: + catcher.updateConfig( + debugConfig: debugOptions, + releaseConfig: releaseOptions, + profileConfig: profileOptions, + ); SystemChrome.setPreferredOrientations( [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown], @@ -70,14 +103,15 @@ class _SanmillAppState extends State { @override void initState() { super.initState(); - //Audios.loopBgm('bg_music.mp3'); Player.loadProfile(); } @override Widget build(BuildContext context) { - // return MaterialApp( + /// Add navigator key from Catcher. + /// It will be used to navigate user to report page or to show dialog. + navigatorKey: Catcher.navigatorKey, navigatorObservers: [routeObserver], localizationsDelegates: [ // ... app-specific localization delegate[s] here diff --git a/src/ui/flutter/lib/services/audios.dart b/src/ui/flutter/lib/services/audios.dart index b9073793..c2127183 100644 --- a/src/ui/flutter/lib/services/audios.dart +++ b/src/ui/flutter/lib/services/audios.dart @@ -26,19 +26,15 @@ class Audios { static AudioCache _bgmPlayer, _tonePlayer; static loopBgm(String fileName) async { - // - try { - if (_bgmPlayer == null) { - _fixedBgmPlayer = AudioPlayer(); - _bgmPlayer = - AudioCache(prefix: 'audios/', fixedPlayer: _fixedBgmPlayer); + if (_bgmPlayer == null) { + _fixedBgmPlayer = AudioPlayer(); + _bgmPlayer = AudioCache(prefix: 'audios/', fixedPlayer: _fixedBgmPlayer); - //await _bgmPlayer.loadAll(['bg_music.mp3']); - } + //await _bgmPlayer.loadAll(['bg_music.mp3']); + } - _fixedBgmPlayer.stop(); - _bgmPlayer.loop(fileName); - } catch (e) {} + _fixedBgmPlayer.stop(); + _bgmPlayer.loop(fileName); } static playTone(String fileName) async { @@ -46,49 +42,43 @@ class Audios { return; } - try { - if (_tonePlayer == null) { - // - _fixedTonePlayer = AudioPlayer(); - _tonePlayer = - AudioCache(prefix: 'audios/', fixedPlayer: _fixedTonePlayer); + if (_tonePlayer == null) { + // + _fixedTonePlayer = AudioPlayer(); + _tonePlayer = + AudioCache(prefix: 'audios/', fixedPlayer: _fixedTonePlayer); - await _tonePlayer.loadAll([ - 'draw.mp3', - 'go.mp3', - 'illegal.mp3', - 'mill.mp3', - 'fly.mp3', - 'lose.mp3', - 'place.mp3', - 'remove.mp3', - 'select.mp3', - 'win.mp3', - ]); - } + await _tonePlayer.loadAll([ + 'draw.mp3', + 'go.mp3', + 'illegal.mp3', + 'mill.mp3', + 'fly.mp3', + 'lose.mp3', + 'place.mp3', + 'remove.mp3', + 'select.mp3', + 'win.mp3', + ]); + } - //await _fixedTonePlayer.stop(); - await _fixedTonePlayer.pause(); - await _fixedTonePlayer.seek(Duration.zero); - //await release(); - await _tonePlayer.play(fileName); - } catch (e) {} + //await _fixedTonePlayer.stop(); + await _fixedTonePlayer.pause(); + await _fixedTonePlayer.seek(Duration.zero); + //await release(); + await _tonePlayer.play(fileName); } static stopBgm() { - try { - if (_fixedBgmPlayer != null) _fixedBgmPlayer.stop(); - } catch (e) {} + if (_fixedBgmPlayer != null) _fixedBgmPlayer.stop(); } static Future release() async { - try { - if (_fixedBgmPlayer != null) { - await _fixedBgmPlayer.release(); - } - if (_fixedTonePlayer != null) { - await _fixedTonePlayer.release(); - } - } catch (e) {} + if (_fixedBgmPlayer != null) { + await _fixedBgmPlayer.release(); + } + if (_fixedTonePlayer != null) { + await _fixedTonePlayer.release(); + } } } diff --git a/src/ui/flutter/lib/widgets/game_page.dart b/src/ui/flutter/lib/widgets/game_page.dart index 343f7d40..c60bd50f 100644 --- a/src/ui/flutter/lib/widgets/game_page.dart +++ b/src/ui/flutter/lib/widgets/game_page.dart @@ -285,13 +285,6 @@ class _GamePageState extends State with RouteAware { msg: S.of(context).analyzing, position: ToastPostion.bottom); setState(() => _searching = true); - - try {} catch (e) { - Toast.toast(context, - msg: S.of(context).error + ": $e", position: ToastPostion.bottom); - } finally { - setState(() => _searching = false); - } } showAnalyzeItems( diff --git a/src/ui/flutter/lib/widgets/main_menu.dart b/src/ui/flutter/lib/widgets/main_menu.dart index ee4e81ff..91bf8a34 100644 --- a/src/ui/flutter/lib/widgets/main_menu.dart +++ b/src/ui/flutter/lib/widgets/main_menu.dart @@ -58,17 +58,13 @@ class _MainMenuState extends State with TickerProviderStateMixin { if (status == AnimationStatus.completed) shadowController.reverse(); }); - /// use 'try...catch' to avoid exception - + /// TODO: use 'try...catch' to avoid exception - /// 'setState() or markNeedsBuild() called during build.' inAnimation.addListener(() { - try { - setState(() {}); - } catch (e) {} + setState(() {}); }); shadowAnimation.addListener(() { - try { - setState(() {}); - } catch (e) {} + setState(() {}); }); inController.forward(); diff --git a/src/ui/flutter/pubspec.yaml b/src/ui/flutter/pubspec.yaml index 9434c978..53171d95 100644 --- a/src/ui/flutter/pubspec.yaml +++ b/src/ui/flutter/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: url_launcher: ^5.7.10 intl: ^0.16.1 flutter_socket_io: ^0.6.0 - sentry_flutter: ^4.0.4 + catcher: ^0.4.1 dev_dependencies: flutter_test: