Improve error handling and presentation

This commit is contained in:
problematicconsumer
2023-10-02 23:57:20 +03:30
parent e1108dc1a7
commit 81658a1c86
6 changed files with 58 additions and 29 deletions

View File

@@ -63,7 +63,7 @@
"update": { "update": {
"buttonTxt": "Update", "buttonTxt": "Update",
"tooltip": "Update Profile", "tooltip": "Update Profile",
"failureMsg": "Update Failed: ${reason}", "failureMsg": "Update Failed",
"successMsg": "Profile updated successfully" "successMsg": "Profile updated successfully"
}, },
"edit": { "edit": {
@@ -241,6 +241,13 @@
"notFound": "Profile Not Found", "notFound": "Profile Not Found",
"invalidUrl": "Invalid URL", "invalidUrl": "Invalid URL",
"invalidConfig": "Invalid Configs" "invalidConfig": "Invalid Configs"
},
"connection": {
"unexpected": "Unexpected error",
"timeout": "Connection timeout",
"badCertificate": "Bad certificate",
"badResponse": "Bad response",
"connectionError": "Connection error"
} }
} }
} }

View File

@@ -63,7 +63,7 @@
"update": { "update": {
"buttonTxt": "بروزرسانی", "buttonTxt": "بروزرسانی",
"tooltip": "بروزرسانی پروفایل", "tooltip": "بروزرسانی پروفایل",
"failureMsg": "در بروزرسانی پروفایل خطایی رخ داد: ${reason}", "failureMsg": "در بروزرسانی پروفایل خطایی رخ داد",
"successMsg": "پروفایل با موفقیت بروزرسانی شد" "successMsg": "پروفایل با موفقیت بروزرسانی شد"
}, },
"edit": { "edit": {
@@ -241,6 +241,13 @@
"notFound": "پروفایل یافت نشد", "notFound": "پروفایل یافت نشد",
"invalidUrl": "لینک نامعتبر", "invalidUrl": "لینک نامعتبر",
"invalidConfig": "کانفیگ غیر معتبر" "invalidConfig": "کانفیگ غیر معتبر"
},
"connection": {
"unexpected": "خطای غیرمنتظره",
"timeout": "درخواست بیش از حد مجاز زمان برد",
"badCertificate": "خطای اعتبار سنجی",
"badResponse": "پاسخ نامعتبر",
"connectionError": "خطای اتصال"
} }
} }
} }

View File

@@ -15,7 +15,7 @@ extension ErrorPresenter on TranslationsEn {
final err = error.present(this); final err = error.present(this);
return err.type + (err.message == null ? "" : ": ${err.message}"); return err.type + (err.message == null ? "" : ": ${err.message}");
case DioException(): case DioException():
return error.toString(); return error.present(this);
default: default:
return null; return null;
} }
@@ -27,8 +27,37 @@ extension ErrorPresenter on TranslationsEn {
String? mayPrintError(Object? error) => String? mayPrintError(Object? error) =>
error != null ? _errorToMessage(error) : null; error != null ? _errorToMessage(error) : null;
({String type, String? message}) presentError(Object error) { ({String type, String? message}) presentError(
if (error case Failure()) return error.present(this); Object error, {
return (type: failure.unexpected, message: null); String? action,
}) {
final ({String type, String? message}) presentable;
if (error case Failure()) {
presentable = error.present(this);
} else {
presentable = (type: failure.unexpected, message: null);
}
return (
type: action == null ? presentable.type : "$action: ${presentable.type}",
message: presentable.message,
);
}
}
extension DioExceptionPresenter on DioException {
String presentType(TranslationsEn t) => switch (type) {
DioExceptionType.connectionTimeout ||
DioExceptionType.sendTimeout ||
DioExceptionType.receiveTimeout =>
t.failure.connection.timeout,
DioExceptionType.badCertificate => t.failure.connection.badCertificate,
DioExceptionType.badResponse => t.failure.connection.badResponse,
DioExceptionType.connectionError =>
t.failure.connection.connectionError,
_ => t.failure.unexpected,
};
String present(TranslationsEn t) {
return presentType(t) + (message == null ? "" : "\n$message");
} }
} }

View File

@@ -1,3 +1,4 @@
import 'package:dartx/dartx.dart';
import 'package:hiddify/core/prefs/general_prefs.dart'; import 'package:hiddify/core/prefs/general_prefs.dart';
import 'package:hiddify/features/common/app_update_notifier.dart'; import 'package:hiddify/features/common/app_update_notifier.dart';
import 'package:hiddify/features/common/connectivity/connectivity_controller.dart'; import 'package:hiddify/features/common/connectivity/connectivity_controller.dart';
@@ -19,7 +20,8 @@ void commonControllers(CommonControllersRef ref) {
introCompletedProvider, introCompletedProvider,
(_, completed) async { (_, completed) async {
if (completed) { if (completed) {
await ref.read(cronServiceProvider).startScheduler(); await Future.delayed(5.seconds)
.then((_) async => ref.read(cronServiceProvider).startScheduler());
} }
}, },
fireImmediately: true, fireImmediately: true,

View File

@@ -176,7 +176,9 @@ class ProfileActionButton extends HookConsumerWidget {
final updateProfileMutation = useMutation( final updateProfileMutation = useMutation(
initialOnFailure: (err) { initialOnFailure: (err) {
CustomAlertDialog.fromErr(t.presentError(err)).show(context); CustomAlertDialog.fromErr(
t.presentError(err, action: t.profile.update.failureMsg),
).show(context);
}, },
initialOnSuccess: () => initialOnSuccess: () =>
CustomToast.success(t.profile.update.successMsg).show(context), CustomToast.success(t.profile.update.successMsg).show(context),
@@ -241,7 +243,9 @@ class ProfileActionsMenu extends HookConsumerWidget {
final updateProfileMutation = useMutation( final updateProfileMutation = useMutation(
initialOnFailure: (err) { initialOnFailure: (err) {
CustomAlertDialog.fromErr(t.presentError(err)).show(context); CustomAlertDialog.fromErr(
t.presentError(err, action: t.profile.update.failureMsg),
).show(context);
}, },
initialOnSuccess: () => initialOnSuccess: () =>
CustomToast.success(t.profile.update.successMsg).show(context), CustomToast.success(t.profile.update.successMsg).show(context),

View File

@@ -1,9 +1,5 @@
import 'package:flutter/material.dart';
import 'package:fpdart/fpdart.dart'; import 'package:fpdart/fpdart.dart';
import 'package:hiddify/core/core_providers.dart';
import 'package:hiddify/core/router/router.dart';
import 'package:hiddify/data/data_providers.dart'; import 'package:hiddify/data/data_providers.dart';
import 'package:hiddify/domain/failures.dart';
import 'package:hiddify/domain/profiles/profiles.dart'; import 'package:hiddify/domain/profiles/profiles.dart';
import 'package:hiddify/services/service_providers.dart'; import 'package:hiddify/services/service_providers.dart';
import 'package:hiddify/utils/utils.dart'; import 'package:hiddify/utils/utils.dart';
@@ -20,22 +16,6 @@ typedef ProfileUpdateResult = ({
class ProfilesUpdateNotifier extends _$ProfilesUpdateNotifier with AppLogger { class ProfilesUpdateNotifier extends _$ProfilesUpdateNotifier with AppLogger {
@override @override
Stream<ProfileUpdateResult> build() { Stream<ProfileUpdateResult> build() {
ref.listenSelf(
(previous, next) {
if (next case AsyncData(value: final result)) {
final t = ref.read(translationsProvider);
final context = rootNavigatorKey.currentContext;
if (context == null || !context.mounted) return;
SnackBar(content: Text(t.profile.update.successMsg));
switch (result.failureOrSuccess) {
case Right():
CustomToast.success(t.profile.update.successMsg).show(context);
case Left(value: final err):
CustomToast.error(t.printError(err)).show(context);
}
}
},
);
_schedule(); _schedule();
return const Stream.empty(); return const Stream.empty();
} }