Files
MWClash/lib/models/config.dart
chen08209 afbc5adb05 Support override script
Support proxies search

Support svg display

Optimize config persistence

Add some scenes auto close connections

Update core

Optimize more details
2025-06-07 23:52:27 +08:00

286 lines
8.2 KiB
Dart

// ignore_for_file: invalid_annotation_target
import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'models.dart';
part 'generated/config.freezed.dart';
part 'generated/config.g.dart';
const defaultBypassDomain = [
"*zhihu.com",
"*zhimg.com",
"*jd.com",
"100ime-iat-api.xfyun.cn",
"*360buyimg.com",
"localhost",
"*.local",
"127.*",
"10.*",
"172.16.*",
"172.17.*",
"172.18.*",
"172.19.*",
"172.2*",
"172.30.*",
"172.31.*",
"192.168.*"
];
const defaultAppSettingProps = AppSettingProps();
const defaultVpnProps = VpnProps();
const defaultNetworkProps = NetworkProps();
const defaultProxiesStyle = ProxiesStyle();
const defaultWindowProps = WindowProps();
const defaultAccessControl = AccessControl();
final defaultThemeProps = ThemeProps(
primaryColor: defaultPrimaryColor,
);
const List<DashboardWidget> defaultDashboardWidgets = [
DashboardWidget.networkSpeed,
DashboardWidget.systemProxyButton,
DashboardWidget.tunButton,
DashboardWidget.outboundMode,
DashboardWidget.networkDetection,
DashboardWidget.trafficUsage,
DashboardWidget.intranetIp,
];
List<DashboardWidget> dashboardWidgetsSafeFormJson(
List<dynamic>? dashboardWidgets,
) {
try {
return dashboardWidgets
?.map((e) => $enumDecode(_$DashboardWidgetEnumMap, e))
.toList() ??
defaultDashboardWidgets;
} catch (_) {
return defaultDashboardWidgets;
}
}
@freezed
class AppSettingProps with _$AppSettingProps {
const factory AppSettingProps({
String? locale,
@Default(defaultDashboardWidgets)
@JsonKey(fromJson: dashboardWidgetsSafeFormJson)
List<DashboardWidget> dashboardWidgets,
@Default(false) bool onlyStatisticsProxy,
@Default(false) bool autoLaunch,
@Default(false) bool silentLaunch,
@Default(false) bool autoRun,
@Default(false) bool openLogs,
@Default(true) bool closeConnections,
@Default(defaultTestUrl) String testUrl,
@Default(true) bool isAnimateToPage,
@Default(true) bool autoCheckUpdate,
@Default(false) bool showLabel,
@Default(false) bool disclaimerAccepted,
@Default(true) bool minimizeOnExit,
@Default(false) bool hidden,
@Default(false) bool developerMode,
@Default(RecoveryStrategy.compatible) RecoveryStrategy recoveryStrategy,
}) = _AppSettingProps;
factory AppSettingProps.fromJson(Map<String, Object?> json) =>
_$AppSettingPropsFromJson(json);
factory AppSettingProps.safeFromJson(Map<String, Object?>? json) {
return json == null
? defaultAppSettingProps
: AppSettingProps.fromJson(json);
}
}
@freezed
class AccessControl with _$AccessControl {
const factory AccessControl({
@Default(false) bool enable,
@Default(AccessControlMode.rejectSelected) AccessControlMode mode,
@Default([]) List<String> acceptList,
@Default([]) List<String> rejectList,
@Default(AccessSortType.none) AccessSortType sort,
@Default(true) bool isFilterSystemApp,
@Default(true) bool isFilterNonInternetApp,
}) = _AccessControl;
factory AccessControl.fromJson(Map<String, Object?> json) =>
_$AccessControlFromJson(json);
}
extension AccessControlExt on AccessControl {
List<String> get currentList => switch (mode) {
AccessControlMode.acceptSelected => acceptList,
AccessControlMode.rejectSelected => rejectList,
};
}
@freezed
class WindowProps with _$WindowProps {
const factory WindowProps({
@Default(750) double width,
@Default(600) double height,
double? top,
double? left,
}) = _WindowProps;
factory WindowProps.fromJson(Map<String, Object?>? json) =>
json == null ? const WindowProps() : _$WindowPropsFromJson(json);
}
@freezed
class VpnProps with _$VpnProps {
const factory VpnProps({
@Default(true) bool enable,
@Default(true) bool systemProxy,
@Default(false) bool ipv6,
@Default(true) bool allowBypass,
@Default(defaultAccessControl) AccessControl accessControl,
}) = _VpnProps;
factory VpnProps.fromJson(Map<String, Object?>? json) =>
json == null ? defaultVpnProps : _$VpnPropsFromJson(json);
}
@freezed
class NetworkProps with _$NetworkProps {
const factory NetworkProps({
@Default(true) bool systemProxy,
@Default(defaultBypassDomain) List<String> bypassDomain,
@Default(RouteMode.config) RouteMode routeMode,
@Default(true) bool autoSetSystemDns,
}) = _NetworkProps;
factory NetworkProps.fromJson(Map<String, Object?>? json) =>
json == null ? const NetworkProps() : _$NetworkPropsFromJson(json);
}
@freezed
class ProxiesStyle with _$ProxiesStyle {
const factory ProxiesStyle({
@Default(ProxiesType.tab) ProxiesType type,
@Default(ProxiesSortType.none) ProxiesSortType sortType,
@Default(ProxiesLayout.standard) ProxiesLayout layout,
@Default(ProxiesIconStyle.standard) ProxiesIconStyle iconStyle,
@Default(ProxyCardType.expand) ProxyCardType cardType,
@Default({}) Map<String, String> iconMap,
}) = _ProxiesStyle;
factory ProxiesStyle.fromJson(Map<String, Object?>? json) =>
json == null ? defaultProxiesStyle : _$ProxiesStyleFromJson(json);
}
@freezed
class TextScale with _$TextScale {
const factory TextScale({
@Default(false) enable,
@Default(1.0) scale,
}) = _TextScale;
factory TextScale.fromJson(Map<String, Object?> json) =>
_$TextScaleFromJson(json);
}
@freezed
class ThemeProps with _$ThemeProps {
const factory ThemeProps({
int? primaryColor,
@Default(defaultPrimaryColors) List<int> primaryColors,
@Default(ThemeMode.dark) ThemeMode themeMode,
@Default(DynamicSchemeVariant.content) DynamicSchemeVariant schemeVariant,
@Default(false) bool pureBlack,
@Default(TextScale()) TextScale textScale,
}) = _ThemeProps;
factory ThemeProps.fromJson(Map<String, Object?> json) =>
_$ThemePropsFromJson(json);
factory ThemeProps.safeFromJson(Map<String, Object?>? json) {
if (json == null) {
return defaultThemeProps;
}
try {
return ThemeProps.fromJson(json);
} catch (_) {
return defaultThemeProps;
}
}
}
@freezed
class ScriptProps with _$ScriptProps {
const factory ScriptProps({
String? currentId,
@Default([]) List<Script> scripts,
}) = _ScriptProps;
factory ScriptProps.fromJson(Map<String, Object?> json) =>
_$ScriptPropsFromJson(json);
}
extension ScriptPropsExt on ScriptProps {
String? get realId {
final index = scripts.indexWhere((script) => script.id == currentId);
if (index != -1) {
return currentId;
}
return null;
}
Script? get currentScript {
final index = scripts.indexWhere((script) => script.id == currentId);
if (index != -1) {
return scripts[index];
}
return null;
}
}
@freezed
class Config with _$Config {
const factory Config({
@JsonKey(fromJson: AppSettingProps.safeFromJson)
@Default(defaultAppSettingProps)
AppSettingProps appSetting,
@Default([]) List<Profile> profiles,
@Default([]) List<HotKeyAction> hotKeyActions,
String? currentProfileId,
@Default(false) bool overrideDns,
DAV? dav,
@Default(defaultNetworkProps) NetworkProps networkProps,
@Default(defaultVpnProps) VpnProps vpnProps,
@JsonKey(fromJson: ThemeProps.safeFromJson) required ThemeProps themeProps,
@Default(defaultProxiesStyle) ProxiesStyle proxiesStyle,
@Default(defaultWindowProps) WindowProps windowProps,
@Default(defaultClashConfig) ClashConfig patchClashConfig,
@Default(ScriptProps()) ScriptProps scriptProps,
}) = _Config;
factory Config.fromJson(Map<String, Object?> json) => _$ConfigFromJson(json);
factory Config.compatibleFromJson(Map<String, Object?> json) {
try {
final accessControlMap = json["accessControl"];
final isAccessControl = json["isAccessControl"];
if (accessControlMap != null) {
(accessControlMap as Map)["enable"] = isAccessControl;
if (json["vpnProps"] != null) {
(json["vpnProps"] as Map)["accessControl"] = accessControlMap;
}
}
} catch (_) {}
return Config.fromJson(json);
}
}
extension ConfigExt on Config {
Profile? get currentProfile {
return profiles.getProfile(currentProfileId);
}
}