Add service mode and strict route
This commit is contained in:
@@ -164,10 +164,10 @@
|
|||||||
"clearSelection": "Clear selection"
|
"clearSelection": "Clear selection"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"mode": "Mode",
|
"serviceMode": "Service Mode",
|
||||||
"modes": {
|
"serviceModes": {
|
||||||
"none": "None",
|
|
||||||
"proxy": "Proxy",
|
"proxy": "Proxy",
|
||||||
|
"systemProxy": "System Proxy",
|
||||||
"tun": "VPN"
|
"tun": "VPN"
|
||||||
},
|
},
|
||||||
"section": {
|
"section": {
|
||||||
@@ -199,7 +199,10 @@
|
|||||||
"enableClashApi": "Enable Clash API",
|
"enableClashApi": "Enable Clash API",
|
||||||
"clashApiPort": "Clash API Port",
|
"clashApiPort": "Clash API Port",
|
||||||
"enableTun": "Enable TUN",
|
"enableTun": "Enable TUN",
|
||||||
"setSystemProxy": "Set System Proxy"
|
"setSystemProxy": "Set System Proxy",
|
||||||
|
"enableFakeDns": "Enable Fake DNS",
|
||||||
|
"bypassLan": "Bypass Lan",
|
||||||
|
"strictRoute": "Strict Route"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"about": {
|
"about": {
|
||||||
|
|||||||
@@ -164,10 +164,10 @@
|
|||||||
"clearSelection": "حذف انتخابها"
|
"clearSelection": "حذف انتخابها"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"mode": "حالت",
|
"serviceMode": "حالت سرویس",
|
||||||
"modes": {
|
"serviceModes": {
|
||||||
"none": "هیچ یک",
|
|
||||||
"proxy": "پروکسی",
|
"proxy": "پروکسی",
|
||||||
|
"systemProxy": "پروکسی سیستم",
|
||||||
"tun": "VPN"
|
"tun": "VPN"
|
||||||
},
|
},
|
||||||
"section": {
|
"section": {
|
||||||
@@ -199,7 +199,10 @@
|
|||||||
"enableClashApi": "فعالسازی کلش",
|
"enableClashApi": "فعالسازی کلش",
|
||||||
"clashApiPort": "پورت کلش",
|
"clashApiPort": "پورت کلش",
|
||||||
"enableTun": "فعال سازی تونل",
|
"enableTun": "فعال سازی تونل",
|
||||||
"setSystemProxy": "تنظیم پروکسی سیستم"
|
"setSystemProxy": "تنظیم پروکسی سیستم",
|
||||||
|
"enableFakeDns": "Enable Fake DNS",
|
||||||
|
"bypassLan": "Bypass Lan",
|
||||||
|
"strictRoute": "Strict Route"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"about": {
|
"about": {
|
||||||
|
|||||||
@@ -164,10 +164,10 @@
|
|||||||
"clearSelection": "Очистить выбор"
|
"clearSelection": "Очистить выбор"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"mode": "Режим",
|
"serviceMode": "Сервисный режим",
|
||||||
"modes": {
|
"serviceModes": {
|
||||||
"none": "Нет",
|
|
||||||
"proxy": "Прокси",
|
"proxy": "Прокси",
|
||||||
|
"systemProxy": "Системный прокси",
|
||||||
"tun": "VPN"
|
"tun": "VPN"
|
||||||
},
|
},
|
||||||
"section": {
|
"section": {
|
||||||
@@ -199,7 +199,10 @@
|
|||||||
"enableClashApi": "Использовать Clash API",
|
"enableClashApi": "Использовать Clash API",
|
||||||
"clashApiPort": "Порт Clash API",
|
"clashApiPort": "Порт Clash API",
|
||||||
"enableTun": "Использовать TUN",
|
"enableTun": "Использовать TUN",
|
||||||
"setSystemProxy": "Установить системный прокси"
|
"setSystemProxy": "Установить системный прокси",
|
||||||
|
"enableFakeDns": "Enable Fake DNS",
|
||||||
|
"bypassLan": "Bypass Lan",
|
||||||
|
"strictRoute": "Strict Route"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"about": {
|
"about": {
|
||||||
|
|||||||
@@ -164,10 +164,10 @@
|
|||||||
"clearSelection": "清空选项"
|
"clearSelection": "清空选项"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"mode": "模式",
|
"serviceMode": "服务方式",
|
||||||
"modes": {
|
"serviceModes": {
|
||||||
"none": "无",
|
"proxy": "代理人",
|
||||||
"proxy": "代理",
|
"systemProxy": "系统代理",
|
||||||
"tun": "VPN"
|
"tun": "VPN"
|
||||||
},
|
},
|
||||||
"section": {
|
"section": {
|
||||||
@@ -199,7 +199,10 @@
|
|||||||
"enableClashApi": "启用 Clash API",
|
"enableClashApi": "启用 Clash API",
|
||||||
"clashApiPort": "Clash API 端口",
|
"clashApiPort": "Clash API 端口",
|
||||||
"enableTun": "启用 TUN",
|
"enableTun": "启用 TUN",
|
||||||
"setSystemProxy": "设置系统代理"
|
"setSystemProxy": "设置系统代理",
|
||||||
|
"enableFakeDns": "Enable Fake DNS",
|
||||||
|
"bypassLan": "Bypass Lan",
|
||||||
|
"strictRoute": "Strict Route"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"about": {
|
"about": {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import 'package:hiddify/core/prefs/prefs.dart';
|
|||||||
import 'package:hiddify/data/data_providers.dart';
|
import 'package:hiddify/data/data_providers.dart';
|
||||||
import 'package:hiddify/domain/singbox/singbox.dart';
|
import 'package:hiddify/domain/singbox/singbox.dart';
|
||||||
import 'package:hiddify/utils/pref_notifier.dart';
|
import 'package:hiddify/utils/pref_notifier.dart';
|
||||||
import 'package:hiddify/utils/utils.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
part 'config_options_store.g.dart';
|
part 'config_options_store.g.dart';
|
||||||
@@ -13,19 +12,19 @@ bool _debugConfigBuilder = false;
|
|||||||
final _default = ConfigOptions.initial;
|
final _default = ConfigOptions.initial;
|
||||||
|
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
class CoreModeStore extends _$CoreModeStore {
|
class ServiceModeStore extends _$ServiceModeStore {
|
||||||
late final _pref = Pref(
|
late final _pref = Pref(
|
||||||
ref.watch(sharedPreferencesProvider),
|
ref.watch(sharedPreferencesProvider),
|
||||||
"mode",
|
"service-mode",
|
||||||
PlatformUtils.isDesktop ? CoreMode.proxy : CoreMode.tun,
|
ServiceMode.defaultMode,
|
||||||
mapFrom: CoreMode.values.byName,
|
mapFrom: ServiceMode.values.byName,
|
||||||
mapTo: (value) => value.name,
|
mapTo: (value) => value.name,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
CoreMode build() => _pref.getValue();
|
ServiceMode build() => _pref.getValue();
|
||||||
|
|
||||||
Future<void> update(CoreMode value) {
|
Future<void> update(ServiceMode value) {
|
||||||
state = value;
|
state = value;
|
||||||
return _pref.update(value);
|
return _pref.update(value);
|
||||||
}
|
}
|
||||||
@@ -83,9 +82,14 @@ final enableClashApiStore =
|
|||||||
PrefNotifier.provider("enable-clash-api", _default.enableClashApi);
|
PrefNotifier.provider("enable-clash-api", _default.enableClashApi);
|
||||||
final clashApiPortStore =
|
final clashApiPortStore =
|
||||||
PrefNotifier.provider("clash-api-port", _default.clashApiPort);
|
PrefNotifier.provider("clash-api-port", _default.clashApiPort);
|
||||||
final enableTunStore = PrefNotifier.provider("enable-tun", _default.enableTun);
|
// final enableTunStore = PrefNotifier.provider("enable-tun", _default.enableTun);
|
||||||
final setSystemProxyStore =
|
// final setSystemProxyStore =
|
||||||
PrefNotifier.provider("set-system-proxy", _default.setSystemProxy);
|
// PrefNotifier.provider("set-system-proxy", _default.setSystemProxy);
|
||||||
|
final strictRouteStore =
|
||||||
|
PrefNotifier.provider("strict-route", _default.strictRoute);
|
||||||
|
final bypassLanStore = PrefNotifier.provider("bypass-lan", _default.bypassLan);
|
||||||
|
final enableFakeDnsStore =
|
||||||
|
PrefNotifier.provider("enable-fake-dns", _default.enableFakeDns);
|
||||||
|
|
||||||
// HACK temporary
|
// HACK temporary
|
||||||
@riverpod
|
@riverpod
|
||||||
@@ -138,38 +142,24 @@ ConfigOptions configPreferences(ConfigPreferencesRef ref) {
|
|||||||
localDnsPort: ref.watch(localDnsPortStore),
|
localDnsPort: ref.watch(localDnsPortStore),
|
||||||
tunImplementation: ref.watch(tunImplementationStore),
|
tunImplementation: ref.watch(tunImplementationStore),
|
||||||
mtu: ref.watch(mtuStore),
|
mtu: ref.watch(mtuStore),
|
||||||
|
strictRoute: ref.watch(strictRouteStore),
|
||||||
connectionTestUrl: ref.watch(connectionTestUrlStore),
|
connectionTestUrl: ref.watch(connectionTestUrlStore),
|
||||||
urlTestInterval: ref.watch(urlTestIntervalStore),
|
urlTestInterval: ref.watch(urlTestIntervalStore),
|
||||||
enableClashApi: ref.watch(enableClashApiStore),
|
enableClashApi: ref.watch(enableClashApiStore),
|
||||||
clashApiPort: ref.watch(clashApiPortStore),
|
clashApiPort: ref.watch(clashApiPortStore),
|
||||||
enableTun: ref.watch(enableTunStore),
|
// enableTun: ref.watch(enableTunStore),
|
||||||
setSystemProxy: ref.watch(setSystemProxyStore),
|
// setSystemProxy: ref.watch(setSystemProxyStore),
|
||||||
|
bypassLan: ref.watch(bypassLanStore),
|
||||||
|
enableFakeDns: ref.watch(enableFakeDnsStore),
|
||||||
rules: ref.watch(rulesProvider),
|
rules: ref.watch(rulesProvider),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
ConfigOptions configOptions(ConfigOptionsRef ref) {
|
ConfigOptions configOptions(ConfigOptionsRef ref) {
|
||||||
final mode = ref.watch(coreModeStoreProvider);
|
final serviceMode = ref.watch(serviceModeStoreProvider);
|
||||||
return ConfigOptions(
|
return ref.watch(configPreferencesProvider).copyWith(
|
||||||
executeConfigAsIs: kDebugMode && _debugConfigBuilder,
|
enableTun: serviceMode == ServiceMode.tun,
|
||||||
logLevel: ref.watch(logLevelStore),
|
setSystemProxy: serviceMode == ServiceMode.systemProxy,
|
||||||
resolveDestination: ref.watch(resolveDestinationStore),
|
|
||||||
ipv6Mode: ref.watch(ipv6ModeStore),
|
|
||||||
remoteDnsAddress: ref.watch(remoteDnsAddressStore),
|
|
||||||
remoteDnsDomainStrategy: ref.watch(remoteDnsDomainStrategyStore),
|
|
||||||
directDnsAddress: ref.watch(directDnsAddressStore),
|
|
||||||
directDnsDomainStrategy: ref.watch(directDnsDomainStrategyStore),
|
|
||||||
mixedPort: ref.watch(mixedPortStore),
|
|
||||||
localDnsPort: ref.watch(localDnsPortStore),
|
|
||||||
tunImplementation: ref.watch(tunImplementationStore),
|
|
||||||
mtu: ref.watch(mtuStore),
|
|
||||||
connectionTestUrl: ref.watch(connectionTestUrlStore),
|
|
||||||
urlTestInterval: ref.watch(urlTestIntervalStore),
|
|
||||||
enableClashApi: ref.watch(enableClashApiStore),
|
|
||||||
clashApiPort: ref.watch(clashApiPortStore),
|
|
||||||
enableTun: mode == CoreMode.tun || ref.watch(enableTunStore),
|
|
||||||
setSystemProxy: mode == CoreMode.proxy || ref.watch(setSystemProxyStore),
|
|
||||||
rules: ref.watch(rulesProvider),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ class ConfigOptions with _$ConfigOptions {
|
|||||||
@Default(6450) int localDnsPort,
|
@Default(6450) int localDnsPort,
|
||||||
@Default(TunImplementation.mixed) TunImplementation tunImplementation,
|
@Default(TunImplementation.mixed) TunImplementation tunImplementation,
|
||||||
@Default(9000) int mtu,
|
@Default(9000) int mtu,
|
||||||
|
@Default(true) bool strictRoute,
|
||||||
@Default("http://cp.cloudflare.com/") String connectionTestUrl,
|
@Default("http://cp.cloudflare.com/") String connectionTestUrl,
|
||||||
@IntervalConverter()
|
@IntervalConverter()
|
||||||
@Default(Duration(minutes: 10))
|
@Default(Duration(minutes: 10))
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import 'package:hiddify/core/prefs/locale_prefs.dart';
|
|
||||||
|
|
||||||
enum CoreMode {
|
|
||||||
none,
|
|
||||||
proxy,
|
|
||||||
tun;
|
|
||||||
|
|
||||||
String present(TranslationsEn t) => switch (this) {
|
|
||||||
none => t.settings.config.modes.none,
|
|
||||||
proxy => t.settings.config.modes.proxy,
|
|
||||||
tun => t.settings.config.modes.tun,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
24
lib/domain/singbox/service_mode.dart
Normal file
24
lib/domain/singbox/service_mode.dart
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import 'package:hiddify/core/prefs/locale_prefs.dart';
|
||||||
|
import 'package:hiddify/utils/platform_utils.dart';
|
||||||
|
|
||||||
|
enum ServiceMode {
|
||||||
|
proxy,
|
||||||
|
systemProxy,
|
||||||
|
tun;
|
||||||
|
|
||||||
|
static ServiceMode get defaultMode =>
|
||||||
|
PlatformUtils.isDesktop ? systemProxy : tun;
|
||||||
|
|
||||||
|
static List<ServiceMode> get choices {
|
||||||
|
if (PlatformUtils.isDesktop) {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
return [proxy, tun];
|
||||||
|
}
|
||||||
|
|
||||||
|
String present(TranslationsEn t) => switch (this) {
|
||||||
|
proxy => t.settings.config.serviceModes.proxy,
|
||||||
|
systemProxy => t.settings.config.serviceModes.systemProxy,
|
||||||
|
tun => t.settings.config.serviceModes.tun,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
export 'box_log.dart';
|
export 'box_log.dart';
|
||||||
export 'config_options.dart';
|
export 'config_options.dart';
|
||||||
export 'core_mode.dart';
|
|
||||||
export 'core_status.dart';
|
export 'core_status.dart';
|
||||||
export 'outbounds.dart';
|
export 'outbounds.dart';
|
||||||
export 'proxy_type.dart';
|
export 'proxy_type.dart';
|
||||||
export 'rules.dart';
|
export 'rules.dart';
|
||||||
|
export 'service_mode.dart';
|
||||||
export 'singbox_facade.dart';
|
export 'singbox_facade.dart';
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class ConfigOptionsPage extends HookConsumerWidget {
|
|||||||
final t = ref.watch(translationsProvider);
|
final t = ref.watch(translationsProvider);
|
||||||
|
|
||||||
final options = ref.watch(configPreferencesProvider);
|
final options = ref.watch(configPreferencesProvider);
|
||||||
|
final serviceMode = ref.watch(serviceModeStoreProvider);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
@@ -59,6 +60,11 @@ class ConfigOptionsPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
const SettingsDivider(),
|
const SettingsDivider(),
|
||||||
SettingsSection(t.settings.config.section.route),
|
SettingsSection(t.settings.config.section.route),
|
||||||
|
// SwitchListTile(
|
||||||
|
// title: Text(t.settings.config.bypassLan),
|
||||||
|
// value: options.bypassLan,
|
||||||
|
// onChanged: ref.read(bypassLanStore.notifier).update,
|
||||||
|
// ),
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
title: Text(t.settings.config.resolveDestination),
|
title: Text(t.settings.config.resolveDestination),
|
||||||
value: options.resolveDestination,
|
value: options.resolveDestination,
|
||||||
@@ -141,20 +147,47 @@ class ConfigOptionsPage extends HookConsumerWidget {
|
|||||||
.update(domainStrategy);
|
.update(domainStrategy);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
// SwitchListTile(
|
||||||
|
// title: Text(t.settings.config.enableFakeDns),
|
||||||
|
// value: options.enableFakeDns,
|
||||||
|
// onChanged: ref.read(enableFakeDnsStore.notifier).update,
|
||||||
|
// ),
|
||||||
const SettingsDivider(),
|
const SettingsDivider(),
|
||||||
SettingsSection(t.settings.config.section.inbound),
|
SettingsSection(t.settings.config.section.inbound),
|
||||||
if (PlatformUtils.isDesktop) ...[
|
// if (PlatformUtils.isDesktop) ...[
|
||||||
SwitchListTile(
|
// SwitchListTile(
|
||||||
title: Text(t.settings.config.enableTun),
|
// title: Text(t.settings.config.enableTun),
|
||||||
value: options.enableTun,
|
// value: options.enableTun,
|
||||||
onChanged: ref.read(enableTunStore.notifier).update,
|
// onChanged: ref.read(enableTunStore.notifier).update,
|
||||||
|
// ),
|
||||||
|
// SwitchListTile(
|
||||||
|
// title: Text(t.settings.config.setSystemProxy),
|
||||||
|
// value: options.setSystemProxy,
|
||||||
|
// onChanged: ref.read(setSystemProxyStore.notifier).update,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
ListTile(
|
||||||
|
title: Text(t.settings.config.serviceMode),
|
||||||
|
subtitle: Text(serviceMode.present(t)),
|
||||||
|
onTap: () async {
|
||||||
|
final pickedMode = await SettingsPickerDialog(
|
||||||
|
title: t.settings.config.serviceMode,
|
||||||
|
selected: serviceMode,
|
||||||
|
options: ServiceMode.choices,
|
||||||
|
getTitle: (e) => e.present(t),
|
||||||
|
resetValue: ServiceMode.defaultMode,
|
||||||
|
).show(context);
|
||||||
|
if (pickedMode == null) return;
|
||||||
|
await ref
|
||||||
|
.read(serviceModeStoreProvider.notifier)
|
||||||
|
.update(pickedMode);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
title: Text(t.settings.config.setSystemProxy),
|
title: Text(t.settings.config.strictRoute),
|
||||||
value: options.setSystemProxy,
|
value: options.strictRoute,
|
||||||
onChanged: ref.read(setSystemProxyStore.notifier).update,
|
onChanged: ref.read(strictRouteStore.notifier).update,
|
||||||
),
|
),
|
||||||
],
|
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(t.settings.config.tunImplementation),
|
title: Text(t.settings.config.tunImplementation),
|
||||||
subtitle: Text(options.tunImplementation.name),
|
subtitle: Text(options.tunImplementation.name),
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class SystemTrayController extends _$SystemTrayController
|
|||||||
}
|
}
|
||||||
|
|
||||||
final connection = await ref.watch(connectivityControllerProvider.future);
|
final connection = await ref.watch(connectivityControllerProvider.future);
|
||||||
final mode = ref.watch(coreModeStoreProvider);
|
final serviceMode = ref.watch(serviceModeStoreProvider);
|
||||||
|
|
||||||
final t = ref.watch(translationsProvider);
|
final t = ref.watch(translationsProvider);
|
||||||
|
|
||||||
@@ -56,19 +56,19 @@ class SystemTrayController extends _$SystemTrayController
|
|||||||
onClick: handleClickSetAsSystemProxy,
|
onClick: handleClickSetAsSystemProxy,
|
||||||
),
|
),
|
||||||
MenuItem.submenu(
|
MenuItem.submenu(
|
||||||
label: t.settings.config.mode,
|
label: t.settings.config.serviceMode,
|
||||||
submenu: Menu(
|
submenu: Menu(
|
||||||
items: [
|
items: [
|
||||||
...CoreMode.values.map(
|
...ServiceMode.values.map(
|
||||||
(e) => MenuItem.checkbox(
|
(e) => MenuItem.checkbox(
|
||||||
checked: e == mode,
|
checked: e == serviceMode,
|
||||||
key: e.name,
|
key: e.name,
|
||||||
label: e.present(t),
|
label: e.present(t),
|
||||||
onClick: (menuItem) async {
|
onClick: (menuItem) async {
|
||||||
final newMode = CoreMode.values.byName(menuItem.key!);
|
final newMode = ServiceMode.values.byName(menuItem.key!);
|
||||||
loggy.debug("switching core mode: [$newMode]");
|
loggy.debug("switching service mode: [$newMode]");
|
||||||
await ref
|
await ref
|
||||||
.read(coreModeStoreProvider.notifier)
|
.read(serviceModeStoreProvider.notifier)
|
||||||
.update(newMode);
|
.update(newMode);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
2
libcore
2
libcore
Submodule libcore updated: f89ede4990...5c8b283d9c
Reference in New Issue
Block a user