From 3a5cb0f81b9c203323c87539777319b8bedbed83 Mon Sep 17 00:00:00 2001 From: NaiJi Date: Mon, 7 Nov 2022 23:17:15 +0400 Subject: [PATCH] feat: Implement critical error handling page Now when we can't handle an exception, application redirects user to a new ErrorPage where they can copy stacktrace, logs and share to our support chat --- assets/translations/en.json | 5 ++++ assets/translations/ru.json | 5 ++++ lib/main.dart | 16 +++++++---- lib/ui/pages/error_page.dart | 53 ++++++++++++++++++++++++++++++++++++ lib/ui/pages/more/more.dart | 14 +++++++++- 5 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 lib/ui/pages/error_page.dart diff --git a/assets/translations/en.json b/assets/translations/en.json index ddb5c541..afb1c034 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -1,6 +1,11 @@ { "test": "en-test", "locale": "en", + "error": { + "page_title": "Oops, something happened...", + "page_description": "We couldn't handle an exception, but it is important for us to know what just happened. Please share this log to our support!", + "page_share": "Share:" + }, "basis": { "providers": "Providers", "providers_title": "Your Data Center", diff --git a/assets/translations/ru.json b/assets/translations/ru.json index d2e298c2..69a5c661 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -1,6 +1,11 @@ { "test": "ru-test", "locale": "ru", + "error": { + "page_title": "Упс, что-то случилось...", + "page_description": "Нам не удалось обработать исключение, но нам важно знать, что только что произошло. Пожалуйста, отправьте нашей поддержке данный лог!", + "page_share": "Поделиться:" + }, "basis": { "providers": "Провайдеры", "providers_title": "Ваш Дата Центр", diff --git a/lib/main.dart b/lib/main.dart index ee771474..bbf30551 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,10 +1,12 @@ import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:selfprivacy/config/brand_colors.dart'; import 'package:selfprivacy/config/hive_config.dart'; import 'package:selfprivacy/theming/factory/app_theme_factory.dart'; +import 'package:selfprivacy/ui/pages/error_page.dart'; import 'package:selfprivacy/ui/pages/setup/initializing.dart'; import 'package:selfprivacy/ui/pages/onboarding/onboarding.dart'; import 'package:selfprivacy/ui/pages/root_route.dart'; @@ -93,13 +95,15 @@ class MyApp extends StatelessWidget { ? const OnboardingPage(nextPage: InitializingPage()) : const RootPage(), builder: (final BuildContext context, final Widget? widget) { - Widget error = const Text('...rendering error...'); - if (widget is Scaffold || widget is Navigator) { - error = Scaffold(body: Center(child: error)); - } ErrorWidget.builder = - (final FlutterErrorDetails errorDetails) => error; - return widget!; + (final FlutterErrorDetails errorDetails) => ErrorPage( + log: + '${errorDetails.stack?.toString() ?? ''}\n\n${errorDetails.exception}', + ); + if (widget != null) { + return widget; + } + throw 'widget is null'; }, ), ), diff --git a/lib/ui/pages/error_page.dart b/lib/ui/pages/error_page.dart new file mode 100644 index 00000000..9be3517e --- /dev/null +++ b/lib/ui/pages/error_page.dart @@ -0,0 +1,53 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:selfprivacy/config/brand_theme.dart'; +import 'package:flutter/services.dart'; +import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart'; +import 'package:selfprivacy/utils/ui_helpers.dart'; + +class ErrorPage extends StatelessWidget { + const ErrorPage({required this.log, super.key}); + + final String log; + final String telegramUrl = 'https://t.me/selfprivacy'; + + @override + Widget build(final BuildContext context) => BrandHeroScreen( + heroTitle: 'error.page_title'.tr(), + heroSubtitle: 'error.page_description'.tr(), + hasBackButton: false, + hasFlashButton: false, + children: [ + SizedBox( + width: 320, + child: Row( + children: [ + IconButton( + icon: const Icon(Icons.content_copy_outlined), + onPressed: () async => Clipboard.setData( + ClipboardData(text: log), + ), + ), + const SizedBox(width: 48), + Text('error.page_share'.tr()), + const SizedBox(width: 16), + InkWell( + onTap: () async => UiHelpers.launchExternalApplicationURL( + telegramUrl, + ), + child: const Icon(Icons.telegram_outlined), + ), + ], + ), + ), + const Divider(), + const SizedBox(height: 16), + Text( + log, + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontFamily: 'RobotoMono', + ), + ), + ], + ); +} diff --git a/lib/ui/pages/more/more.dart b/lib/ui/pages/more/more.dart index 2e75ad26..212aaee6 100644 --- a/lib/ui/pages/more/more.dart +++ b/lib/ui/pages/more/more.dart @@ -33,6 +33,18 @@ class MorePage extends StatelessWidget { final bool? usesBinds = context.watch().state.usesBinds; + return ListView( + children: [ + ListView( + children: [ + Row( + children: [Text("jfkhskdjfhdkjs")], + ) + ], + ) + ], + ); +/* return Scaffold( appBar: PreferredSize( preferredSize: const Size.fromHeight(52), @@ -132,7 +144,7 @@ class MorePage extends StatelessWidget { ) ], ), - ); + ); */ } }