diff --git a/assets/translations/strings_en.i18n.json b/assets/translations/strings_en.i18n.json index be9e915d..3bee715c 100644 --- a/assets/translations/strings_en.i18n.json +++ b/assets/translations/strings_en.i18n.json @@ -178,6 +178,7 @@ "clearSelection": "Clear selection" }, "config": { + "resetBtn": "Reset options", "serviceMode": "Service Mode", "serviceModes": { "proxy": "Proxy", diff --git a/assets/translations/strings_fa.i18n.json b/assets/translations/strings_fa.i18n.json index ff3b1a32..40bb8a96 100644 --- a/assets/translations/strings_fa.i18n.json +++ b/assets/translations/strings_fa.i18n.json @@ -223,7 +223,8 @@ "tlsFragmentSleep": "TLS Fragment Sleep", "enableTlsMixedSniCase": "Enable TLS Mixed SNI Case", "enableTlsPadding": "Enable TLS Padding", - "tlsPaddingSize": "TLS Padding" + "tlsPaddingSize": "TLS Padding", + "resetBtn": "گزینه ها را بازنشانی کنید" }, "geoAssets": { "pageTitle": "فایل‌های مسیریابی", diff --git a/assets/translations/strings_ru.i18n.json b/assets/translations/strings_ru.i18n.json index 75f4a07f..19662b03 100644 --- a/assets/translations/strings_ru.i18n.json +++ b/assets/translations/strings_ru.i18n.json @@ -223,7 +223,8 @@ "tlsFragmentSleep": "TLS Fragment Sleep", "enableTlsMixedSniCase": "Enable TLS Mixed SNI Case", "enableTlsPadding": "Enable TLS Padding", - "tlsPaddingSize": "TLS Padding" + "tlsPaddingSize": "TLS Padding", + "resetBtn": "Сбросить параметры" }, "geoAssets": { "pageTitle": "Активы маршрутизации", diff --git a/assets/translations/strings_tr.i18n.json b/assets/translations/strings_tr.i18n.json index 77f99721..1114ae24 100644 --- a/assets/translations/strings_tr.i18n.json +++ b/assets/translations/strings_tr.i18n.json @@ -223,7 +223,8 @@ "tlsFragmentSleep": "TLS Fragment Sleep", "enableTlsMixedSniCase": "Enable TLS Mixed SNI Case", "enableTlsPadding": "Enable TLS Padding", - "tlsPaddingSize": "TLS Padding" + "tlsPaddingSize": "TLS Padding", + "resetBtn": "Ayarları sıfırla" }, "geoAssets": { "pageTitle": "Varlıkları Yönlendirme", diff --git a/assets/translations/strings_zh-CN.i18n.json b/assets/translations/strings_zh-CN.i18n.json index 92a8365d..73b45786 100644 --- a/assets/translations/strings_zh-CN.i18n.json +++ b/assets/translations/strings_zh-CN.i18n.json @@ -223,7 +223,8 @@ "tlsFragmentSleep": "TLS Fragment Sleep", "enableTlsMixedSniCase": "Enable TLS Mixed SNI Case", "enableTlsPadding": "Enable TLS Padding", - "tlsPaddingSize": "TLS Padding" + "tlsPaddingSize": "TLS Padding", + "resetBtn": "重置选项" }, "geoAssets": { "pageTitle": "路由资源文件", diff --git a/lib/features/config_option/data/config_option_repository.dart b/lib/features/config_option/data/config_option_repository.dart index 50d95c6c..a4b5bb8c 100644 --- a/lib/features/config_option/data/config_option_repository.dart +++ b/lib/features/config_option/data/config_option_repository.dart @@ -10,6 +10,7 @@ import 'package:hiddify/singbox/model/singbox_config_enum.dart'; import 'package:hiddify/singbox/model/singbox_config_option.dart'; import 'package:hiddify/singbox/model/singbox_rule.dart'; import 'package:hiddify/utils/utils.dart'; +import 'package:meta/meta.dart'; import 'package:shared_preferences/shared_preferences.dart'; abstract interface class ConfigOptionRepository { @@ -19,6 +20,7 @@ abstract interface class ConfigOptionRepository { TaskEither updateConfigOption( ConfigOptionPatch patch, ); + TaskEither resetConfigOption(); } class ConfigOptionRepositoryImpl @@ -151,28 +153,48 @@ class ConfigOptionRepositoryImpl return exceptionHandler( () async { final map = patch.toJson(); - for (final key in map.keys) { - final value = map[key]; - if (value != null) { - loggy.debug("updating [$key] to [$value]"); - - switch (value) { - case bool _: - await preferences.setBool(key, value); - case String _: - await preferences.setString(key, value); - case int _: - await preferences.setInt(key, value); - case double _: - await preferences.setDouble(key, value); - default: - loggy.warning("unexpected type"); - } - } - } + await updateByJson(map); return right(unit); }, ConfigOptionUnexpectedFailure.new, ); } + + @override + TaskEither resetConfigOption() { + return exceptionHandler( + () async { + final map = ConfigOptionEntity.initial.toJson(); + await updateByJson(map); + return right(unit); + }, + ConfigOptionUnexpectedFailure.new, + ); + } + + @visibleForTesting + Future updateByJson( + Map options, + ) async { + final map = ConfigOptionEntity.initial.toJson(); + for (final key in map.keys) { + final value = options[key]; + if (value != null) { + loggy.debug("updating [$key] to [$value]"); + + switch (value) { + case bool _: + await preferences.setBool(key, value); + case String _: + await preferences.setString(key, value); + case int _: + await preferences.setInt(key, value); + case double _: + await preferences.setDouble(key, value); + default: + loggy.warning("unexpected type"); + } + } + } + } } diff --git a/lib/features/config_option/notifier/config_option_notifier.dart b/lib/features/config_option/notifier/config_option_notifier.dart index fba59b9c..40fb1490 100644 --- a/lib/features/config_option/notifier/config_option_notifier.dart +++ b/lib/features/config_option/notifier/config_option_notifier.dart @@ -28,4 +28,9 @@ class ConfigOptionNotifier extends _$ConfigOptionNotifier with AppLogger { .run(); } } + + Future resetOption() async { + await ref.read(configOptionRepositoryProvider).resetConfigOption().run(); + ref.invalidateSelf(); + } } diff --git a/lib/features/config_option/overview/config_options_page.dart b/lib/features/config_option/overview/config_options_page.dart index 245fb46c..c493ed29 100644 --- a/lib/features/config_option/overview/config_options_page.dart +++ b/lib/features/config_option/overview/config_options_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:gap/gap.dart'; import 'package:hiddify/core/localization/translations.dart'; +import 'package:hiddify/core/model/failures.dart'; import 'package:hiddify/core/model/range.dart'; import 'package:hiddify/features/config_option/model/config_option_entity.dart'; import 'package:hiddify/features/config_option/model/config_option_patch.dart'; @@ -45,6 +46,14 @@ class ConfigOptionsPage extends HookConsumerWidget { ); }, ), + PopupMenuItem( + child: Text(t.settings.config.resetBtn), + onTap: () async { + await ref + .read(configOptionNotifierProvider.notifier) + .resetOption(); + }, + ), ]; }, ), @@ -377,7 +386,26 @@ class ConfigOptionsPage extends HookConsumerWidget { const Gap(24), ], ), - // TODO show appropriate error/loading widgets + AsyncError(:final error) => Center( + child: SingleChildScrollView( + child: Column( + children: [ + const Icon(Icons.error), + const Gap(2), + Text(t.presentShortError(error)), + const Gap(2), + TextButton( + onPressed: () async { + await ref + .read(configOptionNotifierProvider.notifier) + .resetOption(); + }, + child: Text(t.settings.config.resetBtn), + ), + ], + ), + ), + ), _ => const SizedBox(), }, );