Change mapping and bug fixes

This commit is contained in:
problematicconsumer
2024-02-15 19:39:35 +03:30
parent bd4c5eed7e
commit 702c59c3bc
21 changed files with 501 additions and 422 deletions

View File

@@ -3,10 +3,8 @@ import 'package:hiddify/core/model/region.dart';
import 'package:hiddify/core/utils/exception_handler.dart';
import 'package:hiddify/features/config_option/model/config_option_entity.dart';
import 'package:hiddify/features/config_option/model/config_option_failure.dart';
import 'package:hiddify/features/config_option/model/config_option_patch.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/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';
@@ -36,7 +34,7 @@ class ConfigOptionRepositoryImpl
@override
Either<ConfigOptionFailure, ConfigOptionEntity> getConfigOption() {
try {
final map = ConfigOptionEntity.initial.toJson();
final map = ConfigOptionEntity.initial().toMap();
for (final key in map.keys) {
final persisted = preferences.get(key);
if (persisted != null) {
@@ -51,7 +49,7 @@ class ConfigOptionRepositoryImpl
map[key] = persisted;
}
}
final options = ConfigOptionEntity.fromJson(map);
final options = ConfigOptionEntityMapper.fromMap(map);
return right(options);
} catch (error, stackTrace) {
return left(ConfigOptionUnexpectedFailure(error, stackTrace));
@@ -64,7 +62,7 @@ class ConfigOptionRepositoryImpl
) {
return exceptionHandler(
() async {
final map = patch.toJson();
final map = patch.toMap();
await updateByJson(map);
return right(unit);
},
@@ -76,7 +74,7 @@ class ConfigOptionRepositoryImpl
TaskEither<ConfigOptionFailure, Unit> resetConfigOption() {
return exceptionHandler(
() async {
final map = ConfigOptionEntity.initial.toJson();
final map = ConfigOptionEntity.initial().toMap();
await updateByJson(map);
return right(unit);
},
@@ -88,7 +86,7 @@ class ConfigOptionRepositoryImpl
Future<void> updateByJson(
Map<String, dynamic> options,
) async {
final map = ConfigOptionEntity.initial.toJson();
final map = ConfigOptionEntity.initial().toMap();
for (final key in map.keys) {
final value = options[key];
if (value != null) {
@@ -172,48 +170,7 @@ class SingBoxConfigOptionRepositoryImpl
final persisted =
optionsRepository.getConfigOption().getOrElse((l) => throw l);
final singboxConfigOption = SingboxConfigOption(
executeConfigAsIs: false,
logLevel: persisted.logLevel,
resolveDestination: persisted.resolveDestination,
ipv6Mode: persisted.ipv6Mode,
remoteDnsAddress: persisted.remoteDnsAddress,
remoteDnsDomainStrategy: persisted.remoteDnsDomainStrategy,
directDnsAddress: persisted.directDnsAddress,
directDnsDomainStrategy: persisted.directDnsDomainStrategy,
mixedPort: persisted.mixedPort,
localDnsPort: persisted.localDnsPort,
tunImplementation: persisted.tunImplementation,
mtu: persisted.mtu,
strictRoute: persisted.strictRoute,
connectionTestUrl: persisted.connectionTestUrl,
urlTestInterval: persisted.urlTestInterval,
enableClashApi: persisted.enableClashApi,
clashApiPort: persisted.clashApiPort,
enableTun: persisted.serviceMode == ServiceMode.tun,
enableTunService: persisted.serviceMode == ServiceMode.tunService,
setSystemProxy: persisted.serviceMode == ServiceMode.systemProxy,
bypassLan: persisted.bypassLan,
allowConnectionFromLan: persisted.allowConnectionFromLan,
enableFakeDns: persisted.enableFakeDns,
enableDnsRouting: persisted.enableDnsRouting,
independentDnsCache: persisted.independentDnsCache,
enableTlsFragment: persisted.enableTlsFragment,
tlsFragmentSize: persisted.tlsFragmentSize,
tlsFragmentSleep: persisted.tlsFragmentSleep,
enableTlsMixedSniCase: persisted.enableTlsMixedSniCase,
enableTlsPadding: persisted.enableTlsPadding,
tlsPaddingSize: persisted.tlsPaddingSize,
enableMux: persisted.enableMux,
muxPadding: persisted.muxPadding,
muxMaxStreams: persisted.muxMaxStreams,
muxProtocol: persisted.muxProtocol,
enableWarp: persisted.enableWarp,
warpDetourMode: persisted.warpDetourMode,
warpLicenseKey: persisted.warpLicenseKey,
warpCleanIp: persisted.warpCleanIp,
warpPort: persisted.warpPort,
warpNoise: persisted.warpNoise,
final singboxConfigOption = persisted.toSingbox(
geoipPath: geoAssetPathResolver.relativePath(
geoAssets.geoip.providerName,
geoAssets.geoip.fileName,

View File

@@ -1,75 +1,107 @@
import 'dart:convert';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hiddify/core/model/range.dart';
import 'package:dart_mappable/dart_mappable.dart';
import 'package:hiddify/core/model/optional_range.dart';
import 'package:hiddify/core/utils/json_converters.dart';
import 'package:hiddify/features/config_option/model/config_option_patch.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';
import 'package:hiddify/singbox/model/singbox_rule.dart';
import 'package:hiddify/utils/platform_utils.dart';
part 'config_option_entity.freezed.dart';
part 'config_option_entity.g.dart';
part 'config_option_entity.mapper.dart';
@freezed
class ConfigOptionEntity with _$ConfigOptionEntity {
const ConfigOptionEntity._();
@MappableClass(
caseStyle: CaseStyle.paramCase,
includeCustomMappers: [
OptionalRangeJsonMapper(),
IntervalInSecondsMapper(),
],
)
class ConfigOptionEntity with ConfigOptionEntityMappable {
const ConfigOptionEntity({
required this.serviceMode,
this.logLevel = LogLevel.warn,
this.resolveDestination = false,
this.ipv6Mode = IPv6Mode.disable,
this.remoteDnsAddress = "http://1.1.1.1",
this.remoteDnsDomainStrategy = DomainStrategy.auto,
this.directDnsAddress = "1.1.1.1",
this.directDnsDomainStrategy = DomainStrategy.auto,
this.mixedPort = 2334,
this.localDnsPort = 6450,
this.tunImplementation = TunImplementation.mixed,
this.mtu = 9000,
this.strictRoute = true,
this.connectionTestUrl = "http://cp.cloudflare.com/",
this.urlTestInterval = const Duration(minutes: 10),
this.enableClashApi = true,
this.clashApiPort = 6756,
this.bypassLan = false,
this.allowConnectionFromLan = false,
this.enableFakeDns = false,
this.enableDnsRouting = true,
this.independentDnsCache = true,
this.enableTlsFragment = false,
this.tlsFragmentSize = const OptionalRange(min: 10, max: 100),
this.tlsFragmentSleep = const OptionalRange(min: 50, max: 200),
this.enableTlsMixedSniCase = false,
this.enableTlsPadding = false,
this.tlsPaddingSize = const OptionalRange(min: 100, max: 200),
this.enableMux = false,
this.muxPadding = false,
this.muxMaxStreams = 8,
this.muxProtocol = MuxProtocol.h2mux,
this.enableWarp = false,
this.warpDetourMode = WarpDetourMode.outbound,
this.warpLicenseKey = "",
this.warpCleanIp = "auto",
this.warpPort = 0,
this.warpNoise = const OptionalRange(),
});
@JsonSerializable(fieldRename: FieldRename.kebab)
const factory ConfigOptionEntity({
required ServiceMode serviceMode,
@Default(LogLevel.warn) LogLevel logLevel,
@Default(false) bool resolveDestination,
@Default(IPv6Mode.disable) IPv6Mode ipv6Mode,
@Default("udp://1.1.1.1") String remoteDnsAddress,
@Default(DomainStrategy.auto) DomainStrategy remoteDnsDomainStrategy,
@Default("1.1.1.1") String directDnsAddress,
@Default(DomainStrategy.auto) DomainStrategy directDnsDomainStrategy,
@Default(2334) int mixedPort,
@Default(6450) int localDnsPort,
@Default(TunImplementation.mixed) TunImplementation tunImplementation,
@Default(9000) int mtu,
@Default(true) bool strictRoute,
@Default("http://cp.cloudflare.com/") String connectionTestUrl,
@IntervalInSecondsConverter()
@Default(Duration(minutes: 10))
Duration urlTestInterval,
@Default(true) bool enableClashApi,
@Default(6756) int clashApiPort,
@Default(false) bool bypassLan,
@Default(false) bool allowConnectionFromLan,
@Default(false) bool enableFakeDns,
@Default(true) bool enableDnsRouting,
@Default(true) bool independentDnsCache,
@Default(false) bool enableTlsFragment,
@RangeWithOptionalCeilJsonConverter()
@Default(RangeWithOptionalCeil(min: 10, max: 100))
RangeWithOptionalCeil tlsFragmentSize,
@RangeWithOptionalCeilJsonConverter()
@Default(RangeWithOptionalCeil(min: 50, max: 200))
RangeWithOptionalCeil tlsFragmentSleep,
@Default(false) bool enableTlsMixedSniCase,
@Default(false) bool enableTlsPadding,
@RangeWithOptionalCeilJsonConverter()
@Default(RangeWithOptionalCeil(min: 100, max: 200))
RangeWithOptionalCeil tlsPaddingSize,
@Default(false) bool enableMux,
@Default(false) bool muxPadding,
@Default(8) int muxMaxStreams,
@Default(MuxProtocol.h2mux) MuxProtocol muxProtocol,
@Default(false) bool enableWarp,
@Default(WarpDetourMode.outbound) WarpDetourMode warpDetourMode,
@Default("") String warpLicenseKey,
@Default("auto") String warpCleanIp,
@Default(0) int warpPort,
@RangeWithOptionalCeilJsonConverter()
@Default(RangeWithOptionalCeil())
RangeWithOptionalCeil warpNoise,
}) = _ConfigOptionEntity;
final ServiceMode serviceMode;
final LogLevel logLevel;
final bool resolveDestination;
@MappableField(key: "ipv6-mode")
final IPv6Mode ipv6Mode;
final String remoteDnsAddress;
final DomainStrategy remoteDnsDomainStrategy;
final String directDnsAddress;
final DomainStrategy directDnsDomainStrategy;
final int mixedPort;
final int localDnsPort;
final TunImplementation tunImplementation;
final int mtu;
final bool strictRoute;
final String connectionTestUrl;
final Duration urlTestInterval;
final bool enableClashApi;
final int clashApiPort;
final bool bypassLan;
final bool allowConnectionFromLan;
final bool enableFakeDns;
final bool enableDnsRouting;
final bool independentDnsCache;
final bool enableTlsFragment;
final OptionalRange tlsFragmentSize;
final OptionalRange tlsFragmentSleep;
final bool enableTlsMixedSniCase;
final bool enableTlsPadding;
final OptionalRange tlsPaddingSize;
final bool enableMux;
final bool muxPadding;
final int muxMaxStreams;
final MuxProtocol muxProtocol;
final bool enableWarp;
final WarpDetourMode warpDetourMode;
final String warpLicenseKey;
final String warpCleanIp;
final int warpPort;
final OptionalRange warpNoise;
static ConfigOptionEntity initial = ConfigOptionEntity(
serviceMode: ServiceMode.defaultMode,
);
factory ConfigOptionEntity.initial() =>
ConfigOptionEntity(serviceMode: ServiceMode.defaultMode);
bool hasExperimentalOptions() {
if (PlatformUtils.isDesktop && serviceMode == ServiceMode.tun) {
@@ -88,56 +120,157 @@ class ConfigOptionEntity with _$ConfigOptionEntity {
String format() {
const encoder = JsonEncoder.withIndent(' ');
return encoder.convert(toJson());
return encoder.convert(toMap());
}
ConfigOptionEntity patch(ConfigOptionPatch patch) {
return copyWith(
serviceMode: patch.serviceMode ?? serviceMode,
logLevel: patch.logLevel ?? logLevel,
resolveDestination: patch.resolveDestination ?? resolveDestination,
ipv6Mode: patch.ipv6Mode ?? ipv6Mode,
remoteDnsAddress: patch.remoteDnsAddress ?? remoteDnsAddress,
remoteDnsDomainStrategy:
patch.remoteDnsDomainStrategy ?? remoteDnsDomainStrategy,
directDnsAddress: patch.directDnsAddress ?? directDnsAddress,
directDnsDomainStrategy:
patch.directDnsDomainStrategy ?? directDnsDomainStrategy,
mixedPort: patch.mixedPort ?? mixedPort,
localDnsPort: patch.localDnsPort ?? localDnsPort,
tunImplementation: patch.tunImplementation ?? tunImplementation,
mtu: patch.mtu ?? mtu,
strictRoute: patch.strictRoute ?? strictRoute,
connectionTestUrl: patch.connectionTestUrl ?? connectionTestUrl,
urlTestInterval: patch.urlTestInterval ?? urlTestInterval,
enableClashApi: patch.enableClashApi ?? enableClashApi,
clashApiPort: patch.clashApiPort ?? clashApiPort,
bypassLan: patch.bypassLan ?? bypassLan,
allowConnectionFromLan:
patch.allowConnectionFromLan ?? allowConnectionFromLan,
enableFakeDns: patch.enableFakeDns ?? enableFakeDns,
enableDnsRouting: patch.enableDnsRouting ?? enableDnsRouting,
independentDnsCache: patch.independentDnsCache ?? independentDnsCache,
enableTlsFragment: patch.enableTlsFragment ?? enableTlsFragment,
tlsFragmentSize: patch.tlsFragmentSize ?? tlsFragmentSize,
tlsFragmentSleep: patch.tlsFragmentSleep ?? tlsFragmentSleep,
enableTlsMixedSniCase:
patch.enableTlsMixedSniCase ?? enableTlsMixedSniCase,
enableTlsPadding: patch.enableTlsPadding ?? enableTlsPadding,
tlsPaddingSize: patch.tlsPaddingSize ?? tlsPaddingSize,
enableMux: patch.enableMux ?? enableMux,
muxPadding: patch.muxPadding ?? muxPadding,
muxMaxStreams: patch.muxMaxStreams ?? muxMaxStreams,
muxProtocol: patch.muxProtocol ?? muxProtocol,
enableWarp: patch.enableWarp ?? enableWarp,
warpDetourMode: patch.warpDetourMode ?? warpDetourMode,
warpLicenseKey: patch.warpLicenseKey ?? warpLicenseKey,
warpCleanIp: patch.warpCleanIp ?? warpCleanIp,
warpPort: patch.warpPort ?? warpPort,
warpNoise: patch.warpNoise ?? warpNoise,
);
return copyWith.$delta(patch.delta());
}
factory ConfigOptionEntity.fromJson(Map<String, dynamic> json) =>
_$ConfigOptionEntityFromJson(json);
SingboxConfigOption toSingbox({
required String geoipPath,
required String geositePath,
required List<SingboxRule> rules,
}) {
return SingboxConfigOption(
executeConfigAsIs: false,
logLevel: logLevel,
resolveDestination: resolveDestination,
ipv6Mode: ipv6Mode,
remoteDnsAddress: remoteDnsAddress,
remoteDnsDomainStrategy: remoteDnsDomainStrategy,
directDnsAddress: directDnsAddress,
directDnsDomainStrategy: directDnsDomainStrategy,
mixedPort: mixedPort,
localDnsPort: localDnsPort,
tunImplementation: tunImplementation,
mtu: mtu,
strictRoute: strictRoute,
connectionTestUrl: connectionTestUrl,
urlTestInterval: urlTestInterval,
enableClashApi: enableClashApi,
clashApiPort: clashApiPort,
enableTun: serviceMode == ServiceMode.tun,
enableTunService: serviceMode == ServiceMode.tunService,
setSystemProxy: serviceMode == ServiceMode.systemProxy,
bypassLan: bypassLan,
allowConnectionFromLan: allowConnectionFromLan,
enableFakeDns: enableFakeDns,
enableDnsRouting: enableDnsRouting,
independentDnsCache: independentDnsCache,
enableTlsFragment: enableTlsFragment,
tlsFragmentSize: tlsFragmentSize,
tlsFragmentSleep: tlsFragmentSleep,
enableTlsMixedSniCase: enableTlsMixedSniCase,
enableTlsPadding: enableTlsPadding,
tlsPaddingSize: tlsPaddingSize,
enableMux: enableMux,
muxPadding: muxPadding,
muxMaxStreams: muxMaxStreams,
muxProtocol: muxProtocol,
enableWarp: enableWarp,
warpDetourMode: warpDetourMode,
warpLicenseKey: warpLicenseKey,
warpCleanIp: warpCleanIp,
warpPort: warpPort,
warpNoise: warpNoise,
geoipPath: geoipPath,
geositePath: geositePath,
rules: rules,
);
}
}
@MappableClass(
caseStyle: CaseStyle.paramCase,
ignoreNull: true,
includeCustomMappers: [
OptionalRangeJsonMapper(),
IntervalInSecondsMapper(),
],
)
class ConfigOptionPatch with ConfigOptionPatchMappable {
const ConfigOptionPatch({
this.serviceMode,
this.logLevel,
this.resolveDestination,
this.ipv6Mode,
this.remoteDnsAddress,
this.remoteDnsDomainStrategy,
this.directDnsAddress,
this.directDnsDomainStrategy,
this.mixedPort,
this.localDnsPort,
this.tunImplementation,
this.mtu,
this.strictRoute,
this.connectionTestUrl,
this.urlTestInterval,
this.enableClashApi,
this.clashApiPort,
this.bypassLan,
this.allowConnectionFromLan,
this.enableFakeDns,
this.enableDnsRouting,
this.independentDnsCache,
this.enableTlsFragment,
this.tlsFragmentSize,
this.tlsFragmentSleep,
this.enableTlsMixedSniCase,
this.enableTlsPadding,
this.tlsPaddingSize,
this.enableMux,
this.muxPadding,
this.muxMaxStreams,
this.muxProtocol,
this.enableWarp,
this.warpDetourMode,
this.warpLicenseKey,
this.warpCleanIp,
this.warpPort,
this.warpNoise,
});
final ServiceMode? serviceMode;
final LogLevel? logLevel;
final bool? resolveDestination;
@MappableField(key: "ipv6-mode")
final IPv6Mode? ipv6Mode;
final String? remoteDnsAddress;
final DomainStrategy? remoteDnsDomainStrategy;
final String? directDnsAddress;
final DomainStrategy? directDnsDomainStrategy;
final int? mixedPort;
final int? localDnsPort;
final TunImplementation? tunImplementation;
final int? mtu;
final bool? strictRoute;
final String? connectionTestUrl;
final Duration? urlTestInterval;
final bool? enableClashApi;
final int? clashApiPort;
final bool? bypassLan;
final bool? allowConnectionFromLan;
final bool? enableFakeDns;
final bool? enableDnsRouting;
final bool? independentDnsCache;
final bool? enableTlsFragment;
final OptionalRange? tlsFragmentSize;
final OptionalRange? tlsFragmentSleep;
final bool? enableTlsMixedSniCase;
final bool? enableTlsPadding;
final OptionalRange? tlsPaddingSize;
final bool? enableMux;
final bool? muxPadding;
final int? muxMaxStreams;
final MuxProtocol? muxProtocol;
final bool? enableWarp;
final WarpDetourMode? warpDetourMode;
final String? warpLicenseKey;
final String? warpCleanIp;
final int? warpPort;
final OptionalRange? warpNoise;
Map<String, dynamic> delta() =>
toMap()..removeWhere((key, value) => value == null);
}

View File

@@ -1,60 +0,0 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hiddify/core/model/range.dart';
import 'package:hiddify/core/utils/json_converters.dart';
import 'package:hiddify/features/log/model/log_level.dart';
import 'package:hiddify/singbox/model/singbox_config_enum.dart';
part 'config_option_patch.freezed.dart';
part 'config_option_patch.g.dart';
@freezed
class ConfigOptionPatch with _$ConfigOptionPatch {
const ConfigOptionPatch._();
@JsonSerializable(fieldRename: FieldRename.kebab)
const factory ConfigOptionPatch({
ServiceMode? serviceMode,
LogLevel? logLevel,
bool? resolveDestination,
IPv6Mode? ipv6Mode,
String? remoteDnsAddress,
DomainStrategy? remoteDnsDomainStrategy,
String? directDnsAddress,
DomainStrategy? directDnsDomainStrategy,
int? mixedPort,
int? localDnsPort,
TunImplementation? tunImplementation,
int? mtu,
bool? strictRoute,
String? connectionTestUrl,
@IntervalInSecondsConverter() Duration? urlTestInterval,
bool? enableClashApi,
int? clashApiPort,
bool? bypassLan,
bool? allowConnectionFromLan,
bool? enableFakeDns,
bool? enableDnsRouting,
bool? independentDnsCache,
bool? enableTlsFragment,
@RangeWithOptionalCeilJsonConverter()
RangeWithOptionalCeil? tlsFragmentSize,
@RangeWithOptionalCeilJsonConverter()
RangeWithOptionalCeil? tlsFragmentSleep,
bool? enableTlsMixedSniCase,
bool? enableTlsPadding,
@RangeWithOptionalCeilJsonConverter() RangeWithOptionalCeil? tlsPaddingSize,
bool? enableMux,
bool? muxPadding,
int? muxMaxStreams,
MuxProtocol? muxProtocol,
bool? enableWarp,
WarpDetourMode? warpDetourMode,
String? warpLicenseKey,
String? warpCleanIp,
int? warpPort,
@RangeWithOptionalCeilJsonConverter() RangeWithOptionalCeil? warpNoise,
}) = _ConfigOptionPatch;
factory ConfigOptionPatch.fromJson(Map<String, dynamic> json) =>
_$ConfigOptionPatchFromJson(json);
}

View File

@@ -1,6 +1,5 @@
import 'package:hiddify/features/config_option/data/config_option_data_providers.dart';
import 'package:hiddify/features/config_option/model/config_option_entity.dart';
import 'package:hiddify/features/config_option/model/config_option_patch.dart';
import 'package:hiddify/utils/custom_loggers.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

View File

@@ -5,12 +5,11 @@ 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/core/model/optional_range.dart';
import 'package:hiddify/core/widget/adaptive_icon.dart';
import 'package:hiddify/core/widget/tip_card.dart';
import 'package:hiddify/features/common/nested_app_bar.dart';
import 'package:hiddify/features/config_option/model/config_option_entity.dart';
import 'package:hiddify/features/config_option/model/config_option_patch.dart';
import 'package:hiddify/features/config_option/notifier/config_option_notifier.dart';
import 'package:hiddify/features/config_option/overview/warp_options_widgets.dart';
import 'package:hiddify/features/log/model/log_level.dart';
@@ -28,7 +27,7 @@ class ConfigOptionsPage extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final t = ref.watch(translationsProvider);
final defaultOptions = ConfigOptionEntity.initial;
final defaultOptions = ConfigOptionEntity.initial();
final asyncOptions = ref.watch(configOptionNotifierProvider);
Future<void> changeOption(ConfigOptionPatch patch) async {
@@ -349,8 +348,7 @@ class ConfigOptionsPage extends HookConsumerWidget {
if (range == null) return;
await changeOption(
ConfigOptionPatch(
tlsFragmentSize:
RangeWithOptionalCeil.tryParse(range),
tlsFragmentSize: OptionalRange.tryParse(range),
),
);
},
@@ -367,8 +365,7 @@ class ConfigOptionsPage extends HookConsumerWidget {
if (range == null) return;
await changeOption(
ConfigOptionPatch(
tlsFragmentSleep:
RangeWithOptionalCeil.tryParse(range),
tlsFragmentSleep: OptionalRange.tryParse(range),
),
);
},
@@ -402,7 +399,7 @@ class ConfigOptionsPage extends HookConsumerWidget {
if (range == null) return;
await changeOption(
ConfigOptionPatch(
tlsPaddingSize: RangeWithOptionalCeil.tryParse(range),
tlsPaddingSize: OptionalRange.tryParse(range),
),
);
},

View File

@@ -3,9 +3,8 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:hiddify/core/localization/translations.dart';
import 'package:hiddify/core/model/constants.dart';
import 'package:hiddify/core/model/range.dart';
import 'package:hiddify/core/model/optional_range.dart';
import 'package:hiddify/features/config_option/model/config_option_entity.dart';
import 'package:hiddify/features/config_option/model/config_option_patch.dart';
import 'package:hiddify/features/config_option/notifier/warp_option_notifier.dart';
import 'package:hiddify/features/settings/widgets/settings_input_dialog.dart';
import 'package:hiddify/singbox/model/singbox_config_enum.dart';
@@ -134,10 +133,7 @@ class WarpOptionsTiles extends HookConsumerWidget {
if (warpNoise == null) return;
await onChange(
ConfigOptionPatch(
warpNoise: RangeWithOptionalCeil.tryParse(
warpNoise,
allowEmpty: true,
),
warpNoise: OptionalRange.tryParse(warpNoise, allowEmpty: true),
),
);
},

View File

@@ -1,12 +1,10 @@
import 'dart:async';
import 'dart:convert';
import 'dart:ffi';
import 'dart:io';
import 'package:hiddify/core/utils/ffi_utils.dart';
import 'package:hiddify/utils/custom_loggers.dart';
import 'package:hiddify/utils/utils.dart';
import 'package:path/path.dart' as p;
import 'package:posix/posix.dart';
import 'package:win32/win32.dart';

View File

@@ -1,6 +1,10 @@
import 'package:dart_mappable/dart_mappable.dart';
import 'package:dartx/dartx.dart';
import 'package:flutter/material.dart';
part 'log_level.mapper.dart';
@MappableEnum()
enum LogLevel {
trace,
debug,

View File

@@ -1,7 +1,6 @@
import 'package:dartx/dartx.dart';
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';
import 'package:gap/gap.dart';
import 'package:hiddify/core/localization/translations.dart';
import 'package:hiddify/core/widget/animated_visibility.dart';

View File

@@ -8,7 +8,6 @@ import 'package:hiddify/features/connection/notifier/connection_notifier.dart';
import 'package:hiddify/features/proxy/data/proxy_data_providers.dart';
import 'package:hiddify/features/proxy/model/proxy_entity.dart';
import 'package:hiddify/features/proxy/model/proxy_failure.dart';
import 'package:hiddify/singbox/model/singbox_proxy_type.dart';
import 'package:hiddify/utils/pref_notifier.dart';
import 'package:hiddify/utils/riverpod_utils.dart';
import 'package:hiddify/utils/utils.dart';
@@ -94,14 +93,14 @@ class ProxiesOverviewNotifier extends _$ProxiesOverviewNotifier with AppLogger {
for (final group in proxies) {
final sortedItems = switch (sortBy) {
ProxiesSort.name => group.items.sortedWith((a, b) {
if(a.type.isGroup && !b.type.isGroup) return -1;
if(!a.type.isGroup && b.type.isGroup) return 1;
if (a.type.isGroup && !b.type.isGroup) return -1;
if (!a.type.isGroup && b.type.isGroup) return 1;
return a.tag.compareTo(b.tag);
}),
}),
ProxiesSort.delay => group.items.sortedWith((a, b) {
if(a.type.isGroup && !b.type.isGroup) return -1;
if(!a.type.isGroup && b.type.isGroup) return 1;
if (a.type.isGroup && !b.type.isGroup) return -1;
if (!a.type.isGroup && b.type.isGroup) return 1;
final ai = a.urlTestDelay;
final bi = b.urlTestDelay;
if (ai == 0 && bi == 0) return -1;

View File

@@ -3,7 +3,7 @@ import 'dart:io';
import 'package:hiddify/core/localization/translations.dart';
import 'package:hiddify/core/model/constants.dart';
import 'package:hiddify/core/router/router.dart';
import 'package:hiddify/features/config_option/model/config_option_patch.dart';
import 'package:hiddify/features/config_option/model/config_option_entity.dart';
import 'package:hiddify/features/config_option/notifier/config_option_notifier.dart';
import 'package:hiddify/features/connection/model/connection_status.dart';
import 'package:hiddify/features/connection/notifier/connection_notifier.dart';