add basic routing options, auto update routing assets,use ruleset, remove geo assets
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import 'package:hiddify/core/preferences/preferences_provider.dart';
|
||||
import 'package:hiddify/features/config_option/data/config_option_repository.dart';
|
||||
import 'package:hiddify/features/geo_asset/data/geo_asset_data_providers.dart';
|
||||
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'config_option_data_providers.g.dart';
|
||||
@@ -12,7 +12,5 @@ ConfigOptionRepository configOptionRepository(
|
||||
return ConfigOptionRepository(
|
||||
preferences: ref.watch(sharedPreferencesProvider).requireValue,
|
||||
getConfigOptions: () => ref.read(ConfigOptions.singboxConfigOptions.future),
|
||||
geoAssetRepository: ref.watch(geoAssetRepositoryProvider).requireValue,
|
||||
geoAssetPathResolver: ref.watch(geoAssetPathResolverProvider),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,13 +3,12 @@ import 'package:fpdart/fpdart.dart';
|
||||
import 'package:hiddify/core/model/optional_range.dart';
|
||||
import 'package:hiddify/core/model/region.dart';
|
||||
import 'package:hiddify/core/preferences/general_preferences.dart';
|
||||
|
||||
import 'package:hiddify/core/utils/exception_handler.dart';
|
||||
import 'package:hiddify/core/utils/json_converters.dart';
|
||||
import 'package:hiddify/core/utils/preferences_utils.dart';
|
||||
import 'package:hiddify/features/config_option/model/config_option_failure.dart';
|
||||
import 'package:hiddify/features/geo_asset/data/geo_asset_data_providers.dart';
|
||||
import 'package:hiddify/features/geo_asset/data/geo_asset_path_resolver.dart';
|
||||
import 'package:hiddify/features/geo_asset/data/geo_asset_repository.dart';
|
||||
|
||||
import 'package:hiddify/features/log/model/log_level.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_config_enum.dart';
|
||||
import 'package:hiddify/singbox/model/singbox_config_option.dart';
|
||||
@@ -26,6 +25,17 @@ abstract class ConfigOptions {
|
||||
mapTo: (value) => value.key,
|
||||
);
|
||||
|
||||
static final region = PreferencesNotifier.create<Region, String>(
|
||||
"region",
|
||||
Region.other,
|
||||
mapFrom: Region.values.byName,
|
||||
mapTo: (value) => value.name,
|
||||
);
|
||||
|
||||
static final blockAds = PreferencesNotifier.create<bool, bool>(
|
||||
"block-ads",
|
||||
false,
|
||||
);
|
||||
static final logLevel = PreferencesNotifier.create<LogLevel, String>(
|
||||
"log-level",
|
||||
LogLevel.warn,
|
||||
@@ -305,6 +315,8 @@ abstract class ConfigOptions {
|
||||
};
|
||||
|
||||
static final Map<String, StateNotifierProvider<PreferencesNotifier, dynamic>> preferences = {
|
||||
"region": region,
|
||||
"block-ads": blockAds,
|
||||
"service-mode": serviceMode,
|
||||
"log-level": logLevel,
|
||||
"resolve-destination": resolveDestination,
|
||||
@@ -359,44 +371,46 @@ abstract class ConfigOptions {
|
||||
|
||||
static final singboxConfigOptions = FutureProvider<SingboxConfigOption>(
|
||||
(ref) async {
|
||||
final region = ref.watch(Preferences.region);
|
||||
final rules = switch (region) {
|
||||
Region.ir => [
|
||||
const SingboxRule(
|
||||
domains: "domain:.ir,geosite:ir",
|
||||
ip: "geoip:ir",
|
||||
outbound: RuleOutbound.bypass,
|
||||
),
|
||||
],
|
||||
Region.cn => [
|
||||
const SingboxRule(
|
||||
domains: "domain:.cn,geosite:cn",
|
||||
ip: "geoip:cn",
|
||||
outbound: RuleOutbound.bypass,
|
||||
),
|
||||
],
|
||||
Region.ru => [
|
||||
const SingboxRule(
|
||||
domains: "domain:.ru",
|
||||
ip: "geoip:ru",
|
||||
outbound: RuleOutbound.bypass,
|
||||
),
|
||||
],
|
||||
Region.af => [
|
||||
const SingboxRule(
|
||||
domains: "domain:.af,geosite:af",
|
||||
ip: "geoip:af",
|
||||
outbound: RuleOutbound.bypass,
|
||||
),
|
||||
],
|
||||
_ => <SingboxRule>[],
|
||||
};
|
||||
|
||||
final geoAssetsRepo = await ref.watch(geoAssetRepositoryProvider.future);
|
||||
final geoAssets = await geoAssetsRepo.getActivePair().getOrElse((l) => throw l).run();
|
||||
// final region = ref.watch(Preferences.region);
|
||||
final rules = <SingboxRule>[];
|
||||
// final rules = switch (region) {
|
||||
// Region.ir => [
|
||||
// const SingboxRule(
|
||||
// domains: "domain:.ir,geosite:ir",
|
||||
// ip: "geoip:ir",
|
||||
// outbound: RuleOutbound.bypass,
|
||||
// ),
|
||||
// ],
|
||||
// Region.cn => [
|
||||
// const SingboxRule(
|
||||
// domains: "domain:.cn,geosite:cn",
|
||||
// ip: "geoip:cn",
|
||||
// outbound: RuleOutbound.bypass,
|
||||
// ),
|
||||
// ],
|
||||
// Region.ru => [
|
||||
// const SingboxRule(
|
||||
// domains: "domain:.ru",
|
||||
// ip: "geoip:ru",
|
||||
// outbound: RuleOutbound.bypass,
|
||||
// ),
|
||||
// ],
|
||||
// Region.af => [
|
||||
// const SingboxRule(
|
||||
// domains: "domain:.af,geosite:af",
|
||||
// ip: "geoip:af",
|
||||
// outbound: RuleOutbound.bypass,
|
||||
// ),
|
||||
// ],
|
||||
// _ => <SingboxRule>[],
|
||||
// };
|
||||
|
||||
final mode = ref.watch(serviceMode);
|
||||
// final reg = ref.watch(Preferences.region.notifier).raw();
|
||||
|
||||
return SingboxConfigOption(
|
||||
region: ref.watch(region).name,
|
||||
blockAds: ref.watch(blockAds),
|
||||
executeConfigAsIs: false,
|
||||
logLevel: ref.watch(logLevel),
|
||||
resolveDestination: ref.watch(resolveDestination),
|
||||
@@ -461,14 +475,14 @@ abstract class ConfigOptions {
|
||||
noise: ref.watch(warpNoise),
|
||||
noiseDelay: ref.watch(warpNoiseDelay),
|
||||
),
|
||||
geoipPath: ref.watch(geoAssetPathResolverProvider).relativePath(
|
||||
geoAssets.geoip.providerName,
|
||||
geoAssets.geoip.fileName,
|
||||
),
|
||||
geositePath: ref.watch(geoAssetPathResolverProvider).relativePath(
|
||||
geoAssets.geosite.providerName,
|
||||
geoAssets.geosite.fileName,
|
||||
),
|
||||
// geoipPath: ref.watch(geoAssetPathResolverProvider).relativePath(
|
||||
// geoAssets.geoip.providerName,
|
||||
// geoAssets.geoip.fileName,
|
||||
// ),
|
||||
// geositePath: ref.watch(geoAssetPathResolverProvider).relativePath(
|
||||
// geoAssets.geosite.providerName,
|
||||
// geoAssets.geosite.fileName,
|
||||
// ),
|
||||
rules: rules,
|
||||
);
|
||||
},
|
||||
@@ -479,14 +493,10 @@ class ConfigOptionRepository with ExceptionHandler, InfraLogger {
|
||||
ConfigOptionRepository({
|
||||
required this.preferences,
|
||||
required this.getConfigOptions,
|
||||
required this.geoAssetRepository,
|
||||
required this.geoAssetPathResolver,
|
||||
});
|
||||
|
||||
final SharedPreferences preferences;
|
||||
final Future<SingboxConfigOption> Function() getConfigOptions;
|
||||
final GeoAssetRepository geoAssetRepository;
|
||||
final GeoAssetPathResolver geoAssetPathResolver;
|
||||
|
||||
TaskEither<ConfigOptionFailure, SingboxConfigOption> getFullSingboxConfigOption() {
|
||||
return exceptionHandler(
|
||||
|
||||
@@ -15,16 +15,13 @@ class ConfigOptionNotifier extends _$ConfigOptionNotifier with AppLogger {
|
||||
@override
|
||||
Future<bool> build() async {
|
||||
final serviceRunning = await ref.watch(serviceRunningProvider.future);
|
||||
final serviceSingboxOptions =
|
||||
ref.read(connectionRepositoryProvider).configOptionsSnapshot;
|
||||
final serviceSingboxOptions = ref.read(connectionRepositoryProvider).configOptionsSnapshot;
|
||||
ref.listen(
|
||||
ConfigOptions.singboxConfigOptions,
|
||||
(previous, next) async {
|
||||
if (!serviceRunning || serviceSingboxOptions == null) return;
|
||||
if (next case AsyncData(:final value) when next != previous) {
|
||||
if (_lastUpdate == null ||
|
||||
DateTime.now().difference(_lastUpdate!) >
|
||||
const Duration(milliseconds: 100)) {
|
||||
if (_lastUpdate == null || DateTime.now().difference(_lastUpdate!) > const Duration(milliseconds: 100)) {
|
||||
_lastUpdate = DateTime.now();
|
||||
state = AsyncData(value != serviceSingboxOptions);
|
||||
}
|
||||
@@ -63,8 +60,7 @@ class ConfigOptionNotifier extends _$ConfigOptionNotifier with AppLogger {
|
||||
|
||||
Future<bool> importFromClipboard() async {
|
||||
try {
|
||||
final input =
|
||||
await Clipboard.getData("text/plain").then((value) => value?.text);
|
||||
final input = await Clipboard.getData("text/plain").then((value) => value?.text);
|
||||
if (input == null) return false;
|
||||
if (jsonDecode(input) case final Map<String, dynamic> map) {
|
||||
for (final option in ConfigOptions.preferences.entries) {
|
||||
|
||||
@@ -4,8 +4,8 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hiddify/core/localization/translations.dart';
|
||||
import 'package:hiddify/core/model/optional_range.dart';
|
||||
import 'package:hiddify/core/model/region.dart';
|
||||
import 'package:hiddify/core/notification/in_app_notification_controller.dart';
|
||||
import 'package:hiddify/core/preferences/general_preferences.dart';
|
||||
import 'package:hiddify/core/widget/adaptive_icon.dart';
|
||||
import 'package:hiddify/core/widget/tip_card.dart';
|
||||
import 'package:hiddify/features/common/confirmation_dialogs.dart';
|
||||
@@ -140,6 +140,18 @@ class ConfigOptionsPage extends HookConsumerWidget {
|
||||
),
|
||||
const SettingsDivider(),
|
||||
SettingsSection(t.config.section.route),
|
||||
ChoicePreferenceWidget(
|
||||
selected: ref.watch(ConfigOptions.region),
|
||||
preferences: ref.watch(ConfigOptions.region.notifier),
|
||||
choices: Region.values,
|
||||
title: t.settings.general.region,
|
||||
presentChoice: (value) => value.present(t),
|
||||
),
|
||||
SwitchListTile(
|
||||
title: Text(experimental(t.config.blockAds)),
|
||||
value: ref.watch(ConfigOptions.blockAds),
|
||||
onChanged: ref.watch(ConfigOptions.blockAds.notifier).update,
|
||||
),
|
||||
SwitchListTile(
|
||||
title: Text(experimental(t.config.bypassLan)),
|
||||
value: ref.watch(ConfigOptions.bypassLan),
|
||||
|
||||
Reference in New Issue
Block a user