From 905cb47d766664e853605182ae9859e8a78367fb Mon Sep 17 00:00:00 2001 From: jld3103 Date: Tue, 26 Sep 2023 17:01:34 +0200 Subject: [PATCH 1/5] refactor(neon): Rename NeonException to NeonError Signed-off-by: jld3103 --- .../neon/lib/src/pages/account_settings.dart | 4 +- packages/neon/neon/lib/src/pages/home.dart | 4 +- .../lib/src/pages/login_check_account.dart | 6 +- .../src/pages/login_check_server_status.dart | 4 +- .../neon/neon/lib/src/pages/login_flow.dart | 4 +- .../neon/lib/src/pages/login_qr_code.dart | 4 +- .../neon/neon/lib/src/pages/settings.dart | 8 +-- .../neon/lib/src/widgets/account_tile.dart | 4 +- .../neon/neon/lib/src/widgets/app_bar.dart | 4 +- .../neon/lib/src/widgets/cached_image.dart | 4 +- .../neon/neon/lib/src/widgets/drawer.dart | 4 +- .../widgets/{exception.dart => error.dart} | 56 +++++++++---------- .../neon/neon/lib/src/widgets/list_view.dart | 4 +- .../src/widgets/unified_search_results.dart | 4 +- packages/neon/neon/lib/widgets.dart | 2 +- packages/neon/neon_files/lib/pages/main.dart | 2 +- .../neon_files/lib/widgets/browser_view.dart | 2 +- .../neon/neon_news/lib/dialogs/add_feed.dart | 2 +- .../neon/neon_news/lib/pages/article.dart | 2 +- packages/neon/neon_news/lib/pages/main.dart | 2 +- .../neon_news/lib/widgets/articles_view.dart | 2 +- .../neon_notes/lib/dialogs/create_note.dart | 2 +- .../lib/dialogs/select_category.dart | 2 +- .../lib/utils/exception_handler.dart | 4 +- .../neon_notifications/lib/pages/main.dart | 2 +- 25 files changed, 69 insertions(+), 69 deletions(-) rename packages/neon/neon/lib/src/widgets/{exception.dart => error.dart} (81%) diff --git a/packages/neon/neon/lib/src/pages/account_settings.dart b/packages/neon/neon/lib/src/pages/account_settings.dart index f6bbf4d8..bcb694e9 100644 --- a/packages/neon/neon/lib/src/pages/account_settings.dart +++ b/packages/neon/neon/lib/src/pages/account_settings.dart @@ -13,7 +13,7 @@ import 'package:neon/src/settings/widgets/settings_category.dart'; import 'package:neon/src/settings/widgets/settings_list.dart'; import 'package:neon/src/theme/dialog.dart'; import 'package:neon/src/utils/confirmation_dialog.dart'; -import 'package:neon/src/widgets/exception.dart'; +import 'package:neon/src/widgets/error.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart'; import 'package:nextcloud/nextcloud.dart'; @@ -104,7 +104,7 @@ class AccountSettingsPage extends StatelessWidget { ), ), ], - NeonException( + NeonError( userDetails.error, onRetry: userDetailsBloc.refresh, ), diff --git a/packages/neon/neon/lib/src/pages/home.dart b/packages/neon/neon/lib/src/pages/home.dart index 44c5c057..2ff64712 100644 --- a/packages/neon/neon/lib/src/pages/home.dart +++ b/packages/neon/neon/lib/src/pages/home.dart @@ -14,7 +14,7 @@ import 'package:neon/src/utils/global_popups.dart'; import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/app_bar.dart'; import 'package:neon/src/widgets/drawer.dart'; -import 'package:neon/src/widgets/exception.dart'; +import 'package:neon/src/widgets/error.dart'; import 'package:neon/src/widgets/unified_search_results.dart'; import 'package:provider/provider.dart'; @@ -91,7 +91,7 @@ class _HomePageState extends State { debugPrint(e.toString()); debugPrint(s.toString()); if (mounted) { - NeonException.showSnackbar(context, e); + NeonError.showSnackbar(context, e); } } } diff --git a/packages/neon/neon/lib/src/pages/login_check_account.dart b/packages/neon/neon/lib/src/pages/login_check_account.dart index 31b8f775..0cb672f4 100644 --- a/packages/neon/neon/lib/src/pages/login_check_account.dart +++ b/packages/neon/neon/lib/src/pages/login_check_account.dart @@ -12,7 +12,7 @@ import 'package:neon/src/router.dart'; import 'package:neon/src/theme/dialog.dart'; import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/account_tile.dart'; -import 'package:neon/src/widgets/exception.dart'; +import 'package:neon/src/widgets/error.dart'; import 'package:neon/src/widgets/validation_tile.dart'; @internal @@ -68,7 +68,7 @@ class _LoginCheckAccountPageState extends State { if (state.hasError) ...[ Builder( builder: (final context) { - final details = NeonException.getDetails(context, state.error); + final details = NeonError.getDetails(context, state.error); return NeonValidationTile( title: details.isUnauthorized ? AppLocalizations.of(context).errorCredentialsForAccountNoLongerMatch @@ -91,7 +91,7 @@ class _LoginCheckAccountPageState extends State { const HomeRoute().go(context); } : () { - if (state.hasError && NeonException.getDetails(context, state.error).isUnauthorized) { + if (state.hasError && NeonError.getDetails(context, state.error).isUnauthorized) { Navigator.pop(context); return; } diff --git a/packages/neon/neon/lib/src/pages/login_check_server_status.dart b/packages/neon/neon/lib/src/pages/login_check_server_status.dart index aee497a2..5c59c2ea 100644 --- a/packages/neon/neon/lib/src/pages/login_check_server_status.dart +++ b/packages/neon/neon/lib/src/pages/login_check_server_status.dart @@ -6,7 +6,7 @@ import 'package:neon/src/bloc/result_builder.dart'; import 'package:neon/src/blocs/login_check_server_status.dart'; import 'package:neon/src/router.dart'; import 'package:neon/src/theme/dialog.dart'; -import 'package:neon/src/widgets/exception.dart'; +import 'package:neon/src/widgets/error.dart'; import 'package:neon/src/widgets/validation_tile.dart'; import 'package:nextcloud/nextcloud.dart'; @@ -67,7 +67,7 @@ class _LoginCheckServerStatusPageState extends State children: [ if (state.hasError) ...[ NeonValidationTile( - title: NeonException.getDetails(context, state.error).text, + title: NeonError.getDetails(context, state.error).text, state: ValidationState.failure, ), ], diff --git a/packages/neon/neon/lib/src/pages/login_flow.dart b/packages/neon/neon/lib/src/pages/login_flow.dart index 99fef108..e7144ae4 100644 --- a/packages/neon/neon/lib/src/pages/login_flow.dart +++ b/packages/neon/neon/lib/src/pages/login_flow.dart @@ -4,7 +4,7 @@ import 'package:neon/l10n/localizations.dart'; import 'package:neon/src/bloc/result_builder.dart'; import 'package:neon/src/blocs/login_flow.dart'; import 'package:neon/src/router.dart'; -import 'package:neon/src/widgets/exception.dart'; +import 'package:neon/src/widgets/error.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -68,7 +68,7 @@ class _LoginFlowPageState extends State { NeonLinearProgressIndicator( visible: init.isLoading, ), - NeonException( + NeonError( init.error, onRetry: bloc.refresh, ), diff --git a/packages/neon/neon/lib/src/pages/login_qr_code.dart b/packages/neon/neon/lib/src/pages/login_qr_code.dart index 2446dbbc..27bd88ba 100644 --- a/packages/neon/neon/lib/src/pages/login_qr_code.dart +++ b/packages/neon/neon/lib/src/pages/login_qr_code.dart @@ -4,7 +4,7 @@ import 'package:meta/meta.dart'; import 'package:neon/src/models/account.dart'; import 'package:neon/src/router.dart'; import 'package:neon/src/utils/exceptions.dart'; -import 'package:neon/src/widgets/exception.dart'; +import 'package:neon/src/widgets/error.dart'; @internal class LoginQRcodePage extends StatefulWidget { @@ -53,7 +53,7 @@ class _LoginQRcodePageState extends State { debugPrint(s.toString()); _lastErrorURL = url; - NeonException.showSnackbar(context, e); + NeonError.showSnackbar(context, e); } } }, diff --git a/packages/neon/neon/lib/src/pages/settings.dart b/packages/neon/neon/lib/src/pages/settings.dart index 878e8247..d4b4cd42 100644 --- a/packages/neon/neon/lib/src/pages/settings.dart +++ b/packages/neon/neon/lib/src/pages/settings.dart @@ -23,7 +23,7 @@ import 'package:neon/src/utils/confirmation_dialog.dart'; import 'package:neon/src/utils/global_options.dart'; import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/utils/save_file.dart'; -import 'package:neon/src/widgets/exception.dart'; +import 'package:neon/src/widgets/error.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -287,7 +287,7 @@ class _SettingsPageState extends State { debugPrint(e.toString()); debugPrint(s.toString()); if (mounted) { - NeonException.showSnackbar(context, e); + NeonError.showSnackbar(context, e); } } }, @@ -312,7 +312,7 @@ class _SettingsPageState extends State { if (!result.files.single.path!.endsWith('.json')) { if (mounted) { - NeonException.showSnackbar( + NeonError.showSnackbar( context, AppLocalizations.of(context).settingsImportWrongFileExtension, ); @@ -325,7 +325,7 @@ class _SettingsPageState extends State { debugPrint(e.toString()); debugPrint(s.toString()); if (mounted) { - NeonException.showSnackbar(context, e); + NeonError.showSnackbar(context, e); } } }, diff --git a/packages/neon/neon/lib/src/widgets/account_tile.dart b/packages/neon/neon/lib/src/widgets/account_tile.dart index 923e550d..559dc1b9 100644 --- a/packages/neon/neon/lib/src/widgets/account_tile.dart +++ b/packages/neon/neon/lib/src/widgets/account_tile.dart @@ -4,7 +4,7 @@ import 'package:neon/src/bloc/result_builder.dart'; import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/models/account.dart'; import 'package:neon/src/utils/provider.dart'; -import 'package:neon/src/widgets/exception.dart'; +import 'package:neon/src/widgets/error.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart'; import 'package:neon/src/widgets/user_avatar.dart'; import 'package:nextcloud/nextcloud.dart'; @@ -79,7 +79,7 @@ class NeonAccountTile extends StatelessWidget { const SizedBox( width: 5, ), - NeonException( + NeonError( userDetails.error, onlyIcon: true, iconSize: 24, diff --git a/packages/neon/neon/lib/src/widgets/app_bar.dart b/packages/neon/neon/lib/src/widgets/app_bar.dart index 25408ba7..d2ece2c6 100644 --- a/packages/neon/neon/lib/src/widgets/app_bar.dart +++ b/packages/neon/neon/lib/src/widgets/app_bar.dart @@ -12,7 +12,7 @@ import 'package:neon/src/models/notifications_interface.dart'; import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/account_switcher_button.dart'; import 'package:neon/src/widgets/app_implementation_icon.dart'; -import 'package:neon/src/widgets/exception.dart'; +import 'package:neon/src/widgets/error.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart'; import 'package:provider/provider.dart'; import 'package:rxdart/rxdart.dart'; @@ -89,7 +89,7 @@ class _NeonAppBarState extends State { const SizedBox( width: 8, ), - NeonException( + NeonError( appImplementations.error, onRetry: appsBloc.refresh, onlyIcon: true, diff --git a/packages/neon/neon/lib/src/widgets/cached_image.dart b/packages/neon/neon/lib/src/widgets/cached_image.dart index 11de17d9..d979ef2d 100644 --- a/packages/neon/neon/lib/src/widgets/cached_image.dart +++ b/packages/neon/neon/lib/src/widgets/cached_image.dart @@ -9,7 +9,7 @@ import 'package:neon/nextcloud.dart'; import 'package:neon/src/blocs/accounts.dart'; import 'package:neon/src/models/account.dart'; import 'package:neon/src/utils/provider.dart'; -import 'package:neon/src/widgets/exception.dart'; +import 'package:neon/src/widgets/error.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart'; typedef CacheReviver = FutureOr Function(CacheManager cacheManager); @@ -182,7 +182,7 @@ class _NeonCachedImageState extends State { Widget _buildError(final dynamic error) => widget.errorBuilder?.call(context, error) ?? - NeonException( + NeonError( error, onRetry: () { setState(() {}); diff --git a/packages/neon/neon/lib/src/widgets/drawer.dart b/packages/neon/neon/lib/src/widgets/drawer.dart index 5fa594be..8eea8854 100644 --- a/packages/neon/neon/lib/src/widgets/drawer.dart +++ b/packages/neon/neon/lib/src/widgets/drawer.dart @@ -11,7 +11,7 @@ import 'package:neon/src/router.dart'; import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/cached_image.dart'; import 'package:neon/src/widgets/drawer_destination.dart'; -import 'package:neon/src/widgets/exception.dart'; +import 'package:neon/src/widgets/error.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart'; import 'package:nextcloud/nextcloud.dart'; @@ -131,7 +131,7 @@ class NeonDrawerHeader extends StatelessWidget { } if (capabilities.hasError) { - return NeonException( + return NeonError( capabilities.error, onRetry: capabilitiesBloc.refresh, ); diff --git a/packages/neon/neon/lib/src/widgets/exception.dart b/packages/neon/neon/lib/src/widgets/error.dart similarity index 81% rename from packages/neon/neon/lib/src/widgets/exception.dart rename to packages/neon/neon/lib/src/widgets/error.dart index ff1cd0aa..5fe1d0ba 100644 --- a/packages/neon/neon/lib/src/widgets/exception.dart +++ b/packages/neon/neon/lib/src/widgets/error.dart @@ -11,9 +11,9 @@ import 'package:neon/src/utils/exceptions.dart'; import 'package:neon/src/utils/provider.dart'; import 'package:nextcloud/nextcloud.dart'; -class NeonException extends StatelessWidget { - const NeonException( - this.exception, { +class NeonError extends StatelessWidget { + const NeonError( + this.error, { required this.onRetry, this.onlyIcon = false, this.iconSize, @@ -21,14 +21,14 @@ class NeonException extends StatelessWidget { super.key, }); - final dynamic exception; + final dynamic error; final VoidCallback onRetry; final bool onlyIcon; final double? iconSize; final Color? color; - static void showSnackbar(final BuildContext context, final dynamic exception) { - final details = getDetails(context, exception); + static void showSnackbar(final BuildContext context, final dynamic error) { + final details = getDetails(context, error); ScaffoldMessenger.of(context).showSnackBar( SnackBar( @@ -45,11 +45,11 @@ class NeonException extends StatelessWidget { @override Widget build(final BuildContext context) { - if (exception == null) { + if (error == null) { return const SizedBox(); } - final details = getDetails(context, exception); + final details = getDetails(context, error); final color = this.color ?? Theme.of(context).colorScheme.error; final errorIcon = Icon( @@ -111,71 +111,71 @@ class NeonException extends StatelessWidget { } @internal - static ExceptionDetails getDetails(final BuildContext context, final dynamic exception) { - if (exception is String) { + static ExceptionDetails getDetails(final BuildContext context, final dynamic error) { + if (error is String) { return ExceptionDetails( - text: exception, + text: error, ); } - if (exception is MissingPermissionException) { + if (error is MissingPermissionException) { return ExceptionDetails( - text: AppLocalizations.of(context).errorMissingPermission(exception.permission.toString().split('.')[1]), + text: AppLocalizations.of(context).errorMissingPermission(error.permission.toString().split('.')[1]), ); } - if (exception is UnableToOpenFileException) { + if (error is UnableToOpenFileException) { return ExceptionDetails( text: AppLocalizations.of(context).errorUnableToOpenFile, ); } - if (exception is InvalidQRcodeException) { + if (error is InvalidQRcodeException) { return ExceptionDetails( text: AppLocalizations.of(context).errorInvalidQRcode, ); } - if (exception is DynamiteApiException) { - if (exception.statusCode == 401) { + if (error is DynamiteApiException) { + if (error.statusCode == 401) { return ExceptionDetails( text: AppLocalizations.of(context).errorCredentialsForAccountNoLongerMatch, isUnauthorized: true, ); } - if (exception.statusCode >= 500 && exception.statusCode <= 599) { + if (error.statusCode >= 500 && error.statusCode <= 599) { return ExceptionDetails( text: AppLocalizations.of(context).errorServerHadAProblemProcessingYourRequest, ); } } - if (exception is SocketException) { + if (error is SocketException) { return ExceptionDetails( - text: exception.address != null - ? AppLocalizations.of(context).errorUnableToReachServerAt(exception.address!.host) + text: error.address != null + ? AppLocalizations.of(context).errorUnableToReachServerAt(error.address!.host) : AppLocalizations.of(context).errorUnableToReachServer, ); } - if (exception is ClientException) { + if (error is ClientException) { return ExceptionDetails( - text: exception.uri != null - ? AppLocalizations.of(context).errorUnableToReachServerAt(exception.uri!.host) + text: error.uri != null + ? AppLocalizations.of(context).errorUnableToReachServerAt(error.uri!.host) : AppLocalizations.of(context).errorUnableToReachServer, ); } - if (exception is HttpException) { + if (error is HttpException) { return ExceptionDetails( - text: exception.uri != null - ? AppLocalizations.of(context).errorUnableToReachServerAt(exception.uri!.host) + text: error.uri != null + ? AppLocalizations.of(context).errorUnableToReachServerAt(error.uri!.host) : AppLocalizations.of(context).errorUnableToReachServer, ); } - if (exception is TimeoutException) { + if (error is TimeoutException) { return ExceptionDetails( text: AppLocalizations.of(context).errorConnectionTimedOut, ); diff --git a/packages/neon/neon/lib/src/widgets/list_view.dart b/packages/neon/neon/lib/src/widgets/list_view.dart index c33aae02..64015e4d 100644 --- a/packages/neon/neon/lib/src/widgets/list_view.dart +++ b/packages/neon/neon/lib/src/widgets/list_view.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:neon/src/widgets/exception.dart'; +import 'package:neon/src/widgets/error.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart'; class NeonListView extends StatelessWidget { @@ -47,7 +47,7 @@ class NeonListView extends StatelessWidget { padding: withFloatingActionButton ? const EdgeInsets.only(bottom: 88) : null, children: [ ...?topScrollingChildren, - NeonException( + NeonError( error, onRetry: onRefresh, ), diff --git a/packages/neon/neon/lib/src/widgets/unified_search_results.dart b/packages/neon/neon/lib/src/widgets/unified_search_results.dart index b3a419fc..1cad5370 100644 --- a/packages/neon/neon/lib/src/widgets/unified_search_results.dart +++ b/packages/neon/neon/lib/src/widgets/unified_search_results.dart @@ -10,7 +10,7 @@ import 'package:neon/src/models/account.dart'; import 'package:neon/src/theme/sizes.dart'; import 'package:neon/src/utils/provider.dart'; import 'package:neon/src/widgets/cached_image.dart'; -import 'package:neon/src/widgets/exception.dart'; +import 'package:neon/src/widgets/error.dart'; import 'package:neon/src/widgets/image_wrapper.dart'; import 'package:neon/src/widgets/linear_progress_indicator.dart'; import 'package:neon/src/widgets/list_view.dart'; @@ -66,7 +66,7 @@ class NeonUnifiedSearchResults extends StatelessWidget { provider.name, style: Theme.of(context).textTheme.headlineSmall, ), - NeonException( + NeonError( result.error, onRetry: bloc.refresh, ), diff --git a/packages/neon/neon/lib/widgets.dart b/packages/neon/neon/lib/widgets.dart index 09d78aee..bbd2556b 100644 --- a/packages/neon/neon/lib/widgets.dart +++ b/packages/neon/neon/lib/widgets.dart @@ -1,6 +1,6 @@ export 'package:neon/src/widgets/cached_image.dart'; export 'package:neon/src/widgets/dialog.dart'; -export 'package:neon/src/widgets/exception.dart' hide ExceptionDetails; +export 'package:neon/src/widgets/error.dart' hide ExceptionDetails; export 'package:neon/src/widgets/image_wrapper.dart'; export 'package:neon/src/widgets/linear_progress_indicator.dart'; export 'package:neon/src/widgets/list_view.dart'; diff --git a/packages/neon/neon_files/lib/pages/main.dart b/packages/neon/neon_files/lib/pages/main.dart index 1dad7796..ca993fe0 100644 --- a/packages/neon/neon_files/lib/pages/main.dart +++ b/packages/neon/neon_files/lib/pages/main.dart @@ -18,7 +18,7 @@ class _FilesMainPageState extends State { bloc = NeonProvider.of(context); bloc.errors.listen((final error) { - NeonException.showSnackbar(context, error); + NeonError.showSnackbar(context, error); }); } diff --git a/packages/neon/neon_files/lib/widgets/browser_view.dart b/packages/neon/neon_files/lib/widgets/browser_view.dart index f1f6d140..cc77c376 100644 --- a/packages/neon/neon_files/lib/widgets/browser_view.dart +++ b/packages/neon/neon_files/lib/widgets/browser_view.dart @@ -34,7 +34,7 @@ class _FilesBrowserViewState extends State { @override void initState() { widget.bloc.errors.listen((final error) { - NeonException.showSnackbar(context, error); + NeonError.showSnackbar(context, error); }); super.initState(); diff --git a/packages/neon/neon_news/lib/dialogs/add_feed.dart b/packages/neon/neon_news/lib/dialogs/add_feed.dart index 4c640a29..d212fe38 100644 --- a/packages/neon/neon_news/lib/dialogs/add_feed.dart +++ b/packages/neon/neon_news/lib/dialogs/add_feed.dart @@ -73,7 +73,7 @@ class _NewsAddFeedDialogState extends State { ), if (widget.folderID == null) ...[ Center( - child: NeonException( + child: NeonError( folders.error, onRetry: widget.bloc.refresh, ), diff --git a/packages/neon/neon_news/lib/pages/article.dart b/packages/neon/neon_news/lib/pages/article.dart index 43a61870..48e0f4f5 100644 --- a/packages/neon/neon_news/lib/pages/article.dart +++ b/packages/neon/neon_news/lib/pages/article.dart @@ -30,7 +30,7 @@ class _NewsArticlePageState extends State { super.initState(); widget.bloc.errors.listen((final error) { - NeonException.showSnackbar(context, error); + NeonError.showSnackbar(context, error); }); WidgetsBinding.instance.addPostFrameCallback((final _) { diff --git a/packages/neon/neon_news/lib/pages/main.dart b/packages/neon/neon_news/lib/pages/main.dart index e3390279..65e90c6a 100644 --- a/packages/neon/neon_news/lib/pages/main.dart +++ b/packages/neon/neon_news/lib/pages/main.dart @@ -19,7 +19,7 @@ class _NewsMainPageState extends State { bloc = NeonProvider.of(context); bloc.errors.listen((final error) { - NeonException.showSnackbar(context, error); + NeonError.showSnackbar(context, error); }); } diff --git a/packages/neon/neon_news/lib/widgets/articles_view.dart b/packages/neon/neon_news/lib/widgets/articles_view.dart index f14bad91..4a31fcc3 100644 --- a/packages/neon/neon_news/lib/widgets/articles_view.dart +++ b/packages/neon/neon_news/lib/widgets/articles_view.dart @@ -20,7 +20,7 @@ class _NewsArticlesViewState extends State { super.initState(); widget.bloc.errors.listen((final error) { - NeonException.showSnackbar(context, error); + NeonError.showSnackbar(context, error); }); } diff --git a/packages/neon/neon_notes/lib/dialogs/create_note.dart b/packages/neon/neon_notes/lib/dialogs/create_note.dart index fd3d8598..fc99c4c6 100644 --- a/packages/neon/neon_notes/lib/dialogs/create_note.dart +++ b/packages/neon/neon_notes/lib/dialogs/create_note.dart @@ -55,7 +55,7 @@ class _NotesCreateNoteDialogState extends State { ), if (widget.category == null) ...[ Center( - child: NeonException( + child: NeonError( notes.error, onRetry: widget.bloc.refresh, ), diff --git a/packages/neon/neon_notes/lib/dialogs/select_category.dart b/packages/neon/neon_notes/lib/dialogs/select_category.dart index 2cec920e..e8d8c956 100644 --- a/packages/neon/neon_notes/lib/dialogs/select_category.dart +++ b/packages/neon/neon_notes/lib/dialogs/select_category.dart @@ -37,7 +37,7 @@ class _NotesSelectCategoryDialogState extends State { crossAxisAlignment: CrossAxisAlignment.end, children: [ Center( - child: NeonException( + child: NeonError( notes.error, onRetry: widget.bloc.refresh, ), diff --git a/packages/neon/neon_notes/lib/utils/exception_handler.dart b/packages/neon/neon_notes/lib/utils/exception_handler.dart index 82e982c7..d658f1c3 100644 --- a/packages/neon/neon_notes/lib/utils/exception_handler.dart +++ b/packages/neon/neon_notes/lib/utils/exception_handler.dart @@ -2,8 +2,8 @@ part of '../neon_notes.dart'; void handleNotesException(final BuildContext context, final Object error) { if (error is DynamiteApiException && error.statusCode == 412) { - NeonException.showSnackbar(context, AppLocalizations.of(context).errorChangedOnServer); + NeonError.showSnackbar(context, AppLocalizations.of(context).errorChangedOnServer); } else { - NeonException.showSnackbar(context, error); + NeonError.showSnackbar(context, error); } } diff --git a/packages/neon/neon_notifications/lib/pages/main.dart b/packages/neon/neon_notifications/lib/pages/main.dart index 84add132..34d2b4cd 100644 --- a/packages/neon/neon_notifications/lib/pages/main.dart +++ b/packages/neon/neon_notifications/lib/pages/main.dart @@ -19,7 +19,7 @@ class _NotificationsMainPageState extends State { bloc = NeonProvider.of(context) as NotificationsBloc; bloc.errors.listen((final error) { - NeonException.showSnackbar(context, error); + NeonError.showSnackbar(context, error); }); } From 99a431e702d8fb17e4293e1e99c8c15dc0f7ce81 Mon Sep 17 00:00:00 2001 From: jld3103 Date: Tue, 26 Sep 2023 17:32:51 +0200 Subject: [PATCH 2/5] refactor(neon): Abstract away custom exceptions Signed-off-by: jld3103 --- packages/neon/neon/lib/l10n/en.arb | 1 - .../neon/neon/lib/l10n/localizations.dart | 6 -- .../neon/neon/lib/l10n/localizations_en.dart | 3 - .../lib/src/pages/login_check_account.dart | 6 +- .../src/pages/login_check_server_status.dart | 2 +- .../neon/lib/src/pages/login_qr_code.dart | 15 +++- .../neon/neon/lib/src/platform/android.dart | 2 +- .../neon/neon/lib/src/utils/exceptions.dart | 32 ++++++-- packages/neon/neon/lib/src/widgets/error.dart | 73 ++++++------------- packages/neon/neon/lib/widgets.dart | 2 +- packages/neon/neon_files/lib/blocs/files.dart | 12 ++- packages/neon/neon_files/lib/l10n/en.arb | 1 + .../neon_files/lib/l10n/localizations.dart | 6 ++ .../neon_files/lib/l10n/localizations_en.dart | 3 + 14 files changed, 91 insertions(+), 73 deletions(-) diff --git a/packages/neon/neon/lib/l10n/en.arb b/packages/neon/neon/lib/l10n/en.arb index a5a715f9..5bd46a6c 100644 --- a/packages/neon/neon/lib/l10n/en.arb +++ b/packages/neon/neon/lib/l10n/en.arb @@ -58,7 +58,6 @@ } } }, - "errorUnableToOpenFile": "Unable to open the file", "errorUnsupportedAppVersions": "Sorry, the version of the following apps on your Nextcloud instance are not supported. \n {names} \n Please contact your administrator to resolve the issues.", "@errorUnsupportedAppVersions" : { "placeholders": { diff --git a/packages/neon/neon/lib/l10n/localizations.dart b/packages/neon/neon/lib/l10n/localizations.dart index f95d6212..d287e80a 100644 --- a/packages/neon/neon/lib/l10n/localizations.dart +++ b/packages/neon/neon/lib/l10n/localizations.dart @@ -239,12 +239,6 @@ abstract class AppLocalizations { /// **'Permission for {name} is missing'** String errorMissingPermission(String name); - /// No description provided for @errorUnableToOpenFile. - /// - /// In en, this message translates to: - /// **'Unable to open the file'** - String get errorUnableToOpenFile; - /// No description provided for @errorUnsupportedAppVersions. /// /// In en, this message translates to: diff --git a/packages/neon/neon/lib/l10n/localizations_en.dart b/packages/neon/neon/lib/l10n/localizations_en.dart index 071828f9..45a8ccc8 100644 --- a/packages/neon/neon/lib/l10n/localizations_en.dart +++ b/packages/neon/neon/lib/l10n/localizations_en.dart @@ -106,9 +106,6 @@ class AppLocalizationsEn extends AppLocalizations { return 'Permission for $name is missing'; } - @override - String get errorUnableToOpenFile => 'Unable to open the file'; - @override String errorUnsupportedAppVersions(String names) { return 'Sorry, the version of the following apps on your Nextcloud instance are not supported. \n $names \n Please contact your administrator to resolve the issues.'; diff --git a/packages/neon/neon/lib/src/pages/login_check_account.dart b/packages/neon/neon/lib/src/pages/login_check_account.dart index 0cb672f4..08a9d0bf 100644 --- a/packages/neon/neon/lib/src/pages/login_check_account.dart +++ b/packages/neon/neon/lib/src/pages/login_check_account.dart @@ -68,11 +68,11 @@ class _LoginCheckAccountPageState extends State { if (state.hasError) ...[ Builder( builder: (final context) { - final details = NeonError.getDetails(context, state.error); + final details = NeonError.getDetails(state.error); return NeonValidationTile( title: details.isUnauthorized ? AppLocalizations.of(context).errorCredentialsForAccountNoLongerMatch - : details.text, + : details.getText(context), state: ValidationState.failure, ); }, @@ -91,7 +91,7 @@ class _LoginCheckAccountPageState extends State { const HomeRoute().go(context); } : () { - if (state.hasError && NeonError.getDetails(context, state.error).isUnauthorized) { + if (state.hasError && NeonError.getDetails(state.error).isUnauthorized) { Navigator.pop(context); return; } diff --git a/packages/neon/neon/lib/src/pages/login_check_server_status.dart b/packages/neon/neon/lib/src/pages/login_check_server_status.dart index 5c59c2ea..c9af2a0c 100644 --- a/packages/neon/neon/lib/src/pages/login_check_server_status.dart +++ b/packages/neon/neon/lib/src/pages/login_check_server_status.dart @@ -67,7 +67,7 @@ class _LoginCheckServerStatusPageState extends State children: [ if (state.hasError) ...[ NeonValidationTile( - title: NeonError.getDetails(context, state.error).text, + title: NeonError.getDetails(state.error).getText(context), state: ValidationState.failure, ), ], diff --git a/packages/neon/neon/lib/src/pages/login_qr_code.dart b/packages/neon/neon/lib/src/pages/login_qr_code.dart index 27bd88ba..d4293427 100644 --- a/packages/neon/neon/lib/src/pages/login_qr_code.dart +++ b/packages/neon/neon/lib/src/pages/login_qr_code.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_zxing/flutter_zxing.dart'; import 'package:meta/meta.dart'; +import 'package:neon/l10n/localizations.dart'; import 'package:neon/src/models/account.dart'; import 'package:neon/src/router.dart'; import 'package:neon/src/utils/exceptions.dart'; @@ -35,11 +36,11 @@ class _LoginQRcodePageState extends State { try { url = code.text; if (url == null) { - throw InvalidQRcodeException(); + throw const InvalidQRcodeException(); } final match = LoginQRcode.tryParse(url); if (match == null) { - throw InvalidQRcodeException(); + throw const InvalidQRcodeException(); } LoginCheckServerStatusRoute.withCredentials( @@ -60,3 +61,13 @@ class _LoginQRcodePageState extends State { ), ); } + +@immutable +class InvalidQRcodeException extends NeonException { + const InvalidQRcodeException(); + + @override + NeonExceptionDetails get details => NeonExceptionDetails( + getText: (final context) => AppLocalizations.of(context).errorInvalidQRcode, + ); +} diff --git a/packages/neon/neon/lib/src/platform/android.dart b/packages/neon/neon/lib/src/platform/android.dart index 253ec6bd..93c27089 100644 --- a/packages/neon/neon/lib/src/platform/android.dart +++ b/packages/neon/neon/lib/src/platform/android.dart @@ -31,7 +31,7 @@ class AndroidNeonPlatform implements NeonPlatform { @override Future get userAccessibleAppDataPath async { if (!await Permission.storage.request().isGranted) { - throw MissingPermissionException(Permission.storage); + throw const MissingPermissionException(Permission.storage); } return p.join((await getExternalStorageDirectory())!.path); diff --git a/packages/neon/neon/lib/src/utils/exceptions.dart b/packages/neon/neon/lib/src/utils/exceptions.dart index 394627e4..6fb6c3c9 100644 --- a/packages/neon/neon/lib/src/utils/exceptions.dart +++ b/packages/neon/neon/lib/src/utils/exceptions.dart @@ -1,11 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:neon/l10n/localizations.dart'; +import 'package:neon/src/models/label_builder.dart'; import 'package:permission_handler/permission_handler.dart'; -class MissingPermissionException implements Exception { - MissingPermissionException(this.permission); +class NeonExceptionDetails { + const NeonExceptionDetails({ + required this.getText, + this.isUnauthorized = false, + }); - final Permission permission; + final LabelBuilder getText; + final bool isUnauthorized; +} + +@immutable +abstract class NeonException implements Exception { + const NeonException(); + + NeonExceptionDetails get details; } -class UnableToOpenFileException implements Exception {} +class MissingPermissionException extends NeonException { + const MissingPermissionException(this.permission); -class InvalidQRcodeException implements Exception {} + final Permission permission; + + @override + NeonExceptionDetails get details => NeonExceptionDetails( + getText: (final context) => + AppLocalizations.of(context).errorMissingPermission(permission.toString().split('.')[1]), + ); +} diff --git a/packages/neon/neon/lib/src/widgets/error.dart b/packages/neon/neon/lib/src/widgets/error.dart index 5fe1d0ba..fe445ba6 100644 --- a/packages/neon/neon/lib/src/widgets/error.dart +++ b/packages/neon/neon/lib/src/widgets/error.dart @@ -28,11 +28,11 @@ class NeonError extends StatelessWidget { final Color? color; static void showSnackbar(final BuildContext context, final dynamic error) { - final details = getDetails(context, error); + final details = getDetails(error); ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(details.text), + content: Text(details.getText(context)), action: details.isUnauthorized ? SnackBarAction( label: AppLocalizations.of(context).loginAgain, @@ -49,7 +49,7 @@ class NeonError extends StatelessWidget { return const SizedBox(); } - final details = getDetails(context, error); + final details = getDetails(error); final color = this.color ?? Theme.of(context).colorScheme.error; final errorIcon = Icon( @@ -65,7 +65,7 @@ class NeonError extends StatelessWidget { if (onlyIcon) { return Semantics( - tooltip: details.text, + tooltip: details.getText(context), child: IconButton( icon: errorIcon, padding: EdgeInsets.zero, @@ -93,7 +93,7 @@ class NeonError extends StatelessWidget { ), Flexible( child: Text( - details.text, + details.getText(context), style: TextStyle( color: color, ), @@ -111,78 +111,64 @@ class NeonError extends StatelessWidget { } @internal - static ExceptionDetails getDetails(final BuildContext context, final dynamic error) { + static NeonExceptionDetails getDetails(final dynamic error) { if (error is String) { - return ExceptionDetails( - text: error, + return NeonExceptionDetails( + getText: (final _) => error, ); } - if (error is MissingPermissionException) { - return ExceptionDetails( - text: AppLocalizations.of(context).errorMissingPermission(error.permission.toString().split('.')[1]), - ); - } - - if (error is UnableToOpenFileException) { - return ExceptionDetails( - text: AppLocalizations.of(context).errorUnableToOpenFile, - ); - } - - if (error is InvalidQRcodeException) { - return ExceptionDetails( - text: AppLocalizations.of(context).errorInvalidQRcode, - ); + if (error is NeonException) { + return error.details; } if (error is DynamiteApiException) { if (error.statusCode == 401) { - return ExceptionDetails( - text: AppLocalizations.of(context).errorCredentialsForAccountNoLongerMatch, + return NeonExceptionDetails( + getText: (final context) => AppLocalizations.of(context).errorCredentialsForAccountNoLongerMatch, isUnauthorized: true, ); } if (error.statusCode >= 500 && error.statusCode <= 599) { - return ExceptionDetails( - text: AppLocalizations.of(context).errorServerHadAProblemProcessingYourRequest, + return NeonExceptionDetails( + getText: (final context) => AppLocalizations.of(context).errorServerHadAProblemProcessingYourRequest, ); } } if (error is SocketException) { - return ExceptionDetails( - text: error.address != null + return NeonExceptionDetails( + getText: (final context) => error.address != null ? AppLocalizations.of(context).errorUnableToReachServerAt(error.address!.host) : AppLocalizations.of(context).errorUnableToReachServer, ); } if (error is ClientException) { - return ExceptionDetails( - text: error.uri != null + return NeonExceptionDetails( + getText: (final context) => error.uri != null ? AppLocalizations.of(context).errorUnableToReachServerAt(error.uri!.host) : AppLocalizations.of(context).errorUnableToReachServer, ); } if (error is HttpException) { - return ExceptionDetails( - text: error.uri != null + return NeonExceptionDetails( + getText: (final context) => error.uri != null ? AppLocalizations.of(context).errorUnableToReachServerAt(error.uri!.host) : AppLocalizations.of(context).errorUnableToReachServer, ); } if (error is TimeoutException) { - return ExceptionDetails( - text: AppLocalizations.of(context).errorConnectionTimedOut, + return NeonExceptionDetails( + getText: (final context) => AppLocalizations.of(context).errorConnectionTimedOut, ); } - return ExceptionDetails( - text: AppLocalizations.of(context).errorSomethingWentWrongTryAgainLater, + return NeonExceptionDetails( + getText: (final context) => AppLocalizations.of(context).errorSomethingWentWrongTryAgainLater, ); } @@ -194,14 +180,3 @@ class NeonError extends StatelessWidget { ); } } - -@internal -class ExceptionDetails { - ExceptionDetails({ - required this.text, - this.isUnauthorized = false, - }); - - final String text; - final bool isUnauthorized; -} diff --git a/packages/neon/neon/lib/widgets.dart b/packages/neon/neon/lib/widgets.dart index bbd2556b..34bee9ed 100644 --- a/packages/neon/neon/lib/widgets.dart +++ b/packages/neon/neon/lib/widgets.dart @@ -1,6 +1,6 @@ export 'package:neon/src/widgets/cached_image.dart'; export 'package:neon/src/widgets/dialog.dart'; -export 'package:neon/src/widgets/error.dart' hide ExceptionDetails; +export 'package:neon/src/widgets/error.dart'; export 'package:neon/src/widgets/image_wrapper.dart'; export 'package:neon/src/widgets/linear_progress_indicator.dart'; export 'package:neon/src/widgets/list_view.dart'; diff --git a/packages/neon/neon_files/lib/blocs/files.dart b/packages/neon/neon_files/lib/blocs/files.dart index c61f730d..b8aae030 100644 --- a/packages/neon/neon_files/lib/blocs/files.dart +++ b/packages/neon/neon_files/lib/blocs/files.dart @@ -95,7 +95,7 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta } final result = await OpenFile.open(file.path, type: mimeType); if (result.type != ResultType.done) { - throw UnableToOpenFileException(); + throw const UnableToOpenFileException(); } }, disableTimeout: true, @@ -194,3 +194,13 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta _uploadQueue.parallel = options.uploadQueueParallelism.value; } } + +@immutable +class UnableToOpenFileException extends NeonException { + const UnableToOpenFileException(); + + @override + NeonExceptionDetails get details => NeonExceptionDetails( + getText: (final context) => AppLocalizations.of(context).errorUnableToOpenFile, + ); +} diff --git a/packages/neon/neon_files/lib/l10n/en.arb b/packages/neon/neon_files/lib/l10n/en.arb index 07661702..8a347043 100644 --- a/packages/neon/neon_files/lib/l10n/en.arb +++ b/packages/neon/neon_files/lib/l10n/en.arb @@ -7,6 +7,7 @@ "actionMove": "Move", "actionCopy": "Copy", "actionSync": "Sync", + "errorUnableToOpenFile": "Unable to open the file", "general": "General", "goToPath": "Go to /{path}", "@goToPath": { diff --git a/packages/neon/neon_files/lib/l10n/localizations.dart b/packages/neon/neon_files/lib/l10n/localizations.dart index f0372a5e..1914ad2c 100644 --- a/packages/neon/neon_files/lib/l10n/localizations.dart +++ b/packages/neon/neon_files/lib/l10n/localizations.dart @@ -131,6 +131,12 @@ abstract class AppLocalizations { /// **'Sync'** String get actionSync; + /// No description provided for @errorUnableToOpenFile. + /// + /// In en, this message translates to: + /// **'Unable to open the file'** + String get errorUnableToOpenFile; + /// No description provided for @general. /// /// In en, this message translates to: diff --git a/packages/neon/neon_files/lib/l10n/localizations_en.dart b/packages/neon/neon_files/lib/l10n/localizations_en.dart index 622b0ae2..adb1bd35 100644 --- a/packages/neon/neon_files/lib/l10n/localizations_en.dart +++ b/packages/neon/neon_files/lib/l10n/localizations_en.dart @@ -25,6 +25,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get actionSync => 'Sync'; + @override + String get errorUnableToOpenFile => 'Unable to open the file'; + @override String get general => 'General'; From 07791ce7db211eaf91b7f940dc888afe9f5e8275 Mon Sep 17 00:00:00 2001 From: jld3103 Date: Wed, 27 Sep 2023 14:49:53 +0200 Subject: [PATCH 3/5] refactor(neon): Cleanup NeonError Signed-off-by: jld3103 --- packages/neon/neon/lib/src/widgets/error.dart | 86 ++++++++----------- 1 file changed, 37 insertions(+), 49 deletions(-) diff --git a/packages/neon/neon/lib/src/widgets/error.dart b/packages/neon/neon/lib/src/widgets/error.dart index fe445ba6..3131c77e 100644 --- a/packages/neon/neon/lib/src/widgets/error.dart +++ b/packages/neon/neon/lib/src/widgets/error.dart @@ -112,59 +112,47 @@ class NeonError extends StatelessWidget { @internal static NeonExceptionDetails getDetails(final dynamic error) { - if (error is String) { - return NeonExceptionDetails( - getText: (final _) => error, - ); - } - - if (error is NeonException) { - return error.details; - } - - if (error is DynamiteApiException) { - if (error.statusCode == 401) { + switch (error) { + case String(): return NeonExceptionDetails( - getText: (final context) => AppLocalizations.of(context).errorCredentialsForAccountNoLongerMatch, - isUnauthorized: true, + getText: (final _) => error, ); - } - - if (error.statusCode >= 500 && error.statusCode <= 599) { + case NeonException(): + return error.details; + case DynamiteApiException(): + if (error.statusCode == 401) { + return NeonExceptionDetails( + getText: (final context) => AppLocalizations.of(context).errorCredentialsForAccountNoLongerMatch, + isUnauthorized: true, + ); + } + if (error.statusCode >= 500 && error.statusCode <= 599) { + return NeonExceptionDetails( + getText: (final context) => AppLocalizations.of(context).errorServerHadAProblemProcessingYourRequest, + ); + } + case SocketException(): return NeonExceptionDetails( - getText: (final context) => AppLocalizations.of(context).errorServerHadAProblemProcessingYourRequest, + getText: (final context) => error.address != null + ? AppLocalizations.of(context).errorUnableToReachServerAt(error.address!.host) + : AppLocalizations.of(context).errorUnableToReachServer, + ); + case ClientException(): + return NeonExceptionDetails( + getText: (final context) => error.uri != null + ? AppLocalizations.of(context).errorUnableToReachServerAt(error.uri!.host) + : AppLocalizations.of(context).errorUnableToReachServer, + ); + case HttpException(): + return NeonExceptionDetails( + getText: (final context) => error.uri != null + ? AppLocalizations.of(context).errorUnableToReachServerAt(error.uri!.host) + : AppLocalizations.of(context).errorUnableToReachServer, + ); + case TimeoutException(): + return NeonExceptionDetails( + getText: (final context) => AppLocalizations.of(context).errorConnectionTimedOut, ); - } - } - - if (error is SocketException) { - return NeonExceptionDetails( - getText: (final context) => error.address != null - ? AppLocalizations.of(context).errorUnableToReachServerAt(error.address!.host) - : AppLocalizations.of(context).errorUnableToReachServer, - ); - } - - if (error is ClientException) { - return NeonExceptionDetails( - getText: (final context) => error.uri != null - ? AppLocalizations.of(context).errorUnableToReachServerAt(error.uri!.host) - : AppLocalizations.of(context).errorUnableToReachServer, - ); - } - - if (error is HttpException) { - return NeonExceptionDetails( - getText: (final context) => error.uri != null - ? AppLocalizations.of(context).errorUnableToReachServerAt(error.uri!.host) - : AppLocalizations.of(context).errorUnableToReachServer, - ); - } - - if (error is TimeoutException) { - return NeonExceptionDetails( - getText: (final context) => AppLocalizations.of(context).errorConnectionTimedOut, - ); } return NeonExceptionDetails( From 7684ecb3c2b987118475e7c2a3d4f582a260527c Mon Sep 17 00:00:00 2001 From: jld3103 Date: Wed, 27 Sep 2023 15:05:23 +0200 Subject: [PATCH 4/5] docs(neon): Document NeonException, NeonExceptionDetails, NeonError Signed-off-by: jld3103 --- .../neon/neon/lib/src/utils/exceptions.dart | 15 +++++++++++++ packages/neon/neon/lib/src/widgets/error.dart | 21 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/packages/neon/neon/lib/src/utils/exceptions.dart b/packages/neon/neon/lib/src/utils/exceptions.dart index 6fb6c3c9..09084834 100644 --- a/packages/neon/neon/lib/src/utils/exceptions.dart +++ b/packages/neon/neon/lib/src/utils/exceptions.dart @@ -3,26 +3,41 @@ import 'package:neon/l10n/localizations.dart'; import 'package:neon/src/models/label_builder.dart'; import 'package:permission_handler/permission_handler.dart'; +/// Details of a [NeonException]. class NeonExceptionDetails { + /// Creates new [NeonExceptionDetails]. + /// + /// [isUnauthorized] defaults to false. const NeonExceptionDetails({ required this.getText, this.isUnauthorized = false, }); + /// Text that will be displayed in the UI final LabelBuilder getText; + + /// If the [Exception] is the result of an unauthorized API request this should be set to `true`. + /// + /// The user will then be shown a button to update the credentials of the account instead of retrying the action. final bool isUnauthorized; } +/// Extensible [Exception] to be used for displaying custom errors in the UI @immutable abstract class NeonException implements Exception { + /// Creates a NeonException const NeonException(); + /// Details that will be rendered by the UI NeonExceptionDetails get details; } +/// [Exception] that should be thrown when a native permission is denied. class MissingPermissionException extends NeonException { + /// Creates a MissingPermissionException const MissingPermissionException(this.permission); + /// Permission that was denied final Permission permission; @override diff --git a/packages/neon/neon/lib/src/widgets/error.dart b/packages/neon/neon/lib/src/widgets/error.dart index 3131c77e..4adb2282 100644 --- a/packages/neon/neon/lib/src/widgets/error.dart +++ b/packages/neon/neon/lib/src/widgets/error.dart @@ -11,7 +11,11 @@ import 'package:neon/src/utils/exceptions.dart'; import 'package:neon/src/utils/provider.dart'; import 'package:nextcloud/nextcloud.dart'; +/// An indicator that an [error] has occurred. +/// +/// The action that lead to the error can be retried. class NeonError extends StatelessWidget { + /// Creates a NeonError. const NeonError( this.error, { required this.onRetry, @@ -21,12 +25,28 @@ class NeonError extends StatelessWidget { super.key, }); + /// The error object. + /// + /// Can be of type [String] or [Exception], various subtypes of `Exception` are also handled separately. final dynamic error; + + /// A function that's called when the user decides to retry the action that lead to the error. final VoidCallback onRetry; + + /// Changes whether the text is displayed additionally or not. final bool onlyIcon; + + /// The size of the icon in logical pixels. + /// + /// Defaults to a size of `30`. final double? iconSize; + + /// The color to use when drawing the error indicator. + /// + /// Defaults to the nearest [IconTheme]'s [ColorScheme.error]. final Color? color; + /// Shows a [SnackBar] popup for the [error]. static void showSnackbar(final BuildContext context, final dynamic error) { final details = getDetails(error); @@ -110,6 +130,7 @@ class NeonError extends StatelessWidget { ); } + /// Gets the details for a given [error]. @internal static NeonExceptionDetails getDetails(final dynamic error) { switch (error) { From 7c1647fec5a717b1cb0933217e99159a1d1af96f Mon Sep 17 00:00:00 2001 From: jld3103 Date: Wed, 27 Sep 2023 19:41:06 +0200 Subject: [PATCH 5/5] refactor(neon): Use Object? instead of dynamic for errors Signed-off-by: jld3103 --- packages/neon/neon/lib/src/utils/exceptions.dart | 4 ++-- packages/neon/neon/lib/src/widgets/cached_image.dart | 2 +- packages/neon/neon/lib/src/widgets/error.dart | 6 +++--- packages/neon/neon/lib/src/widgets/list_view.dart | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/neon/neon/lib/src/utils/exceptions.dart b/packages/neon/neon/lib/src/utils/exceptions.dart index 09084834..41732471 100644 --- a/packages/neon/neon/lib/src/utils/exceptions.dart +++ b/packages/neon/neon/lib/src/utils/exceptions.dart @@ -22,13 +22,13 @@ class NeonExceptionDetails { final bool isUnauthorized; } -/// Extensible [Exception] to be used for displaying custom errors in the UI +/// Extensible [Exception] to be used for displaying custom errors in the UI. @immutable abstract class NeonException implements Exception { /// Creates a NeonException const NeonException(); - /// Details that will be rendered by the UI + /// Details that will be rendered by the UI. NeonExceptionDetails get details; } diff --git a/packages/neon/neon/lib/src/widgets/cached_image.dart b/packages/neon/neon/lib/src/widgets/cached_image.dart index d979ef2d..4f393d73 100644 --- a/packages/neon/neon/lib/src/widgets/cached_image.dart +++ b/packages/neon/neon/lib/src/widgets/cached_image.dart @@ -180,7 +180,7 @@ class _NeonCachedImageState extends State { ), ); - Widget _buildError(final dynamic error) => + Widget _buildError(final Object? error) => widget.errorBuilder?.call(context, error) ?? NeonError( error, diff --git a/packages/neon/neon/lib/src/widgets/error.dart b/packages/neon/neon/lib/src/widgets/error.dart index 4adb2282..f0a9328d 100644 --- a/packages/neon/neon/lib/src/widgets/error.dart +++ b/packages/neon/neon/lib/src/widgets/error.dart @@ -28,7 +28,7 @@ class NeonError extends StatelessWidget { /// The error object. /// /// Can be of type [String] or [Exception], various subtypes of `Exception` are also handled separately. - final dynamic error; + final Object? error; /// A function that's called when the user decides to retry the action that lead to the error. final VoidCallback onRetry; @@ -47,7 +47,7 @@ class NeonError extends StatelessWidget { final Color? color; /// Shows a [SnackBar] popup for the [error]. - static void showSnackbar(final BuildContext context, final dynamic error) { + static void showSnackbar(final BuildContext context, final Object? error) { final details = getDetails(error); ScaffoldMessenger.of(context).showSnackBar( @@ -132,7 +132,7 @@ class NeonError extends StatelessWidget { /// Gets the details for a given [error]. @internal - static NeonExceptionDetails getDetails(final dynamic error) { + static NeonExceptionDetails getDetails(final Object? error) { switch (error) { case String(): return NeonExceptionDetails( diff --git a/packages/neon/neon/lib/src/widgets/list_view.dart b/packages/neon/neon/lib/src/widgets/list_view.dart index 64015e4d..28035cde 100644 --- a/packages/neon/neon/lib/src/widgets/list_view.dart +++ b/packages/neon/neon/lib/src/widgets/list_view.dart @@ -18,7 +18,7 @@ class NeonListView extends StatelessWidget { final Iterable? items; final bool isLoading; - final dynamic error; + final Object? error; final RefreshCallback onRefresh; final Widget Function(BuildContext, T data) builder; final String? scrollKey;