Files
MWClash/lib/models/config.dart
chen08209 3a43dc2fe9 Add android shortcuts
Fix init params issues

Fix dynamic color issues

Optimize navigator animate

Optimize window init

Optimize fab

Optimize save
2024-12-06 19:24:11 +08:00

493 lines
13 KiB
Dart

import 'dart:io';
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.g.dart';
part 'generated/config.freezed.dart';
final defaultAppSetting = const AppSetting().copyWith(
isAnimateToPage: system.isDesktop ? false : true,
);
@freezed
class AppSetting with _$AppSetting {
const factory AppSetting({
String? locale,
@Default(false) bool onlyProxy,
@Default(false) bool autoLaunch,
@Default(false) bool adminAutoLaunch,
@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,
}) = _AppSetting;
factory AppSetting.fromJson(Map<String, Object?> json) =>
_$AppSettingFromJson(json);
factory AppSetting.realFromJson(Map<String, Object?>? json) {
final appSetting = json == null
? defaultAppSetting
: AppSetting.fromJson(json);
return appSetting.copyWith(
isAnimateToPage: system.isDesktop ? false : appSetting.isAnimateToPage,
);
}
}
@freezed
class AccessControl with _$AccessControl {
const factory AccessControl({
@Default(AccessControlMode.rejectSelected) AccessControlMode mode,
@Default([]) List<String> acceptList,
@Default([]) List<String> rejectList,
@Default(AccessSortType.none) AccessSortType sort,
@Default(true) bool isFilterSystemApp,
}) = _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(900) double width,
@Default(600) double height,
double? top,
double? left,
}) = _WindowProps;
factory WindowProps.fromJson(Map<String, Object?>? json) =>
json == null ? const WindowProps() : _$WindowPropsFromJson(json);
}
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 defaultVpnProps = VpnProps();
@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(defaultBypassDomain) List<String> bypassDomain,
}) = _VpnProps;
factory VpnProps.fromJson(Map<String, Object?>? json) =>
json == null ? const VpnProps() : _$VpnPropsFromJson(json);
}
@freezed
class DesktopProps with _$DesktopProps {
const factory DesktopProps({
@Default(true) bool systemProxy,
}) = _DesktopProps;
factory DesktopProps.fromJson(Map<String, Object?>? json) =>
json == null ? const DesktopProps() : _$DesktopPropsFromJson(json);
}
const defaultProxiesStyle = ProxiesStyle();
@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);
}
final defaultThemeProps = Platform.isWindows
? const ThemeProps().copyWith(
fontFamily: FontFamily.miSans,
primaryColor: defaultPrimaryColor.value,
)
: const ThemeProps().copyWith(
primaryColor: defaultPrimaryColor.value,
);
@freezed
class ThemeProps with _$ThemeProps {
const factory ThemeProps({
int? primaryColor,
@Default(ThemeMode.system) ThemeMode themeMode,
@Default(false) bool prueBlack,
@Default(FontFamily.system) FontFamily fontFamily,
}) = _ThemeProps;
factory ThemeProps.fromJson(Map<String, Object?> json) =>
_$ThemePropsFromJson(json);
factory ThemeProps.realFromJson(Map<String, Object?>? json) {
if (json == null) {
return defaultThemeProps;
}
try {
return ThemeProps.fromJson(json);
} catch (_) {
return defaultThemeProps;
}
}
}
@JsonSerializable()
class Config extends ChangeNotifier {
AppSetting _appSetting;
List<Profile> _profiles;
String? _currentProfileId;
bool _isAccessControl;
AccessControl _accessControl;
DAV? _dav;
WindowProps _windowProps;
ThemeProps _themeProps;
VpnProps _vpnProps;
DesktopProps _desktopProps;
bool _overrideDns;
List<HotKeyAction> _hotKeyActions;
ProxiesStyle _proxiesStyle;
Config()
: _profiles = [],
_isAccessControl = false,
_accessControl = const AccessControl(),
_windowProps = const WindowProps(),
_vpnProps = defaultVpnProps,
_desktopProps = const DesktopProps(),
_overrideDns = false,
_appSetting = defaultAppSetting,
_hotKeyActions = [],
_proxiesStyle = defaultProxiesStyle,
_themeProps = defaultThemeProps;
@JsonKey(fromJson: AppSetting.realFromJson)
AppSetting get appSetting => _appSetting;
set appSetting(AppSetting value) {
if (_appSetting != value) {
_appSetting = value;
notifyListeners();
}
}
deleteProfileById(String id) {
_profiles = profiles.where((element) => element.id != id).toList();
notifyListeners();
}
Profile? getCurrentProfileForId(String? value) {
if (value == null) {
return null;
}
return _profiles.firstWhere((element) => element.id == value);
}
Profile? getCurrentProfile() {
return getCurrentProfileForId(_currentProfileId);
}
String? _getLabel(String? label, String id) {
final realLabel = label ?? id;
final hasDup = _profiles.indexWhere(
(element) => element.label == realLabel && element.id != id) !=
-1;
if (hasDup) {
return _getLabel(other.getOverwriteLabel(realLabel), id);
} else {
return label;
}
}
_setProfile(Profile profile) {
final List<Profile> profilesTemp = List.from(_profiles);
final index =
profilesTemp.indexWhere((element) => element.id == profile.id);
final updateProfile = profile.copyWith(
label: _getLabel(profile.label, profile.id),
);
if (index == -1) {
profilesTemp.add(updateProfile);
} else {
profilesTemp[index] = updateProfile;
}
_profiles = profilesTemp;
}
setProfile(Profile profile) {
_setProfile(profile);
notifyListeners();
}
@JsonKey(defaultValue: [])
List<Profile> get profiles => _profiles;
set profiles(List<Profile> value) {
if (_profiles != value) {
_profiles = value;
notifyListeners();
}
}
String? get currentProfileId => _currentProfileId;
set currentProfileId(String? value) {
if (_currentProfileId != value) {
_currentProfileId = value;
notifyListeners();
}
}
Profile? get currentProfile {
final index =
profiles.indexWhere((profile) => profile.id == _currentProfileId);
return index == -1 ? null : profiles[index];
}
String? get currentGroupName => currentProfile?.currentGroupName;
Set<String> get currentUnfoldSet => currentProfile?.unfoldSet ?? {};
updateCurrentUnfoldSet(Set<String> value) {
if (!stringSetEquality.equals(currentUnfoldSet, value)) {
_setProfile(
currentProfile!.copyWith(
unfoldSet: value,
),
);
notifyListeners();
}
}
updateCurrentGroupName(String groupName) {
if (currentProfile != null &&
currentProfile!.currentGroupName != groupName) {
_setProfile(
currentProfile!.copyWith(
currentGroupName: groupName,
),
);
notifyListeners();
}
}
SelectedMap get currentSelectedMap {
return currentProfile?.selectedMap ?? {};
}
updateCurrentSelectedMap(String groupName, String proxyName) {
if (currentProfile != null &&
currentProfile!.selectedMap[groupName] != proxyName) {
final SelectedMap selectedMap = Map.from(
currentProfile?.selectedMap ?? {},
)..[groupName] = proxyName;
_setProfile(
currentProfile!.copyWith(
selectedMap: selectedMap,
),
);
notifyListeners();
}
}
@JsonKey(defaultValue: false)
bool get isAccessControl {
if (!Platform.isAndroid) return false;
return _isAccessControl;
}
set isAccessControl(bool value) {
if (_isAccessControl != value) {
_isAccessControl = value;
notifyListeners();
}
}
AccessControl get accessControl => _accessControl;
set accessControl(AccessControl value) {
if (_accessControl != value) {
_accessControl = value;
notifyListeners();
}
}
DAV? get dav => _dav;
set dav(DAV? value) {
if (_dav != value) {
_dav = value;
notifyListeners();
}
}
WindowProps get windowProps => _windowProps;
set windowProps(WindowProps value) {
if (_windowProps != value) {
_windowProps = value;
notifyListeners();
}
}
VpnProps get vpnProps => _vpnProps;
set vpnProps(VpnProps value) {
if (_vpnProps != value) {
_vpnProps = value;
notifyListeners();
}
}
DesktopProps get desktopProps => _desktopProps;
set desktopProps(DesktopProps value) {
if (_desktopProps != value) {
_desktopProps = value;
notifyListeners();
}
}
@JsonKey(defaultValue: false)
bool get overrideDns => _overrideDns;
set overrideDns(bool value) {
if (_overrideDns != value) {
_overrideDns = value;
notifyListeners();
}
}
@JsonKey(defaultValue: [])
List<HotKeyAction> get hotKeyActions => _hotKeyActions;
set hotKeyActions(List<HotKeyAction> value) {
if (_hotKeyActions != value) {
_hotKeyActions = value;
notifyListeners();
}
}
ProxiesStyle get proxiesStyle => _proxiesStyle;
set proxiesStyle(ProxiesStyle value) {
if (_proxiesStyle != value ||
!stringAndStringMapEntryIterableEquality.equals(
_proxiesStyle.iconMap.entries,
value.iconMap.entries,
)) {
_proxiesStyle = value;
notifyListeners();
}
}
@JsonKey(fromJson: ThemeProps.realFromJson)
ThemeProps get themeProps => _themeProps;
set themeProps(ThemeProps value) {
if (_themeProps != value) {
_themeProps = value;
notifyListeners();
}
}
updateOrAddHotKeyAction(HotKeyAction hotKeyAction) {
final index =
_hotKeyActions.indexWhere((item) => item.action == hotKeyAction.action);
if (index == -1) {
_hotKeyActions = List.from(_hotKeyActions)..add(hotKeyAction);
} else {
_hotKeyActions = List.from(_hotKeyActions)..[index] = hotKeyAction;
}
notifyListeners();
}
update([
Config? config,
RecoveryOption recoveryOptions = RecoveryOption.all,
]) {
if (config != null) {
_profiles = config._profiles;
for (final profile in config._profiles) {
_setProfile(profile);
}
final onlyProfiles = recoveryOptions == RecoveryOption.onlyProfiles;
if (_currentProfileId == null && onlyProfiles && profiles.isNotEmpty) {
_currentProfileId = _profiles.first.id;
}
if (onlyProfiles) return;
_appSetting = config._appSetting;
_currentProfileId = config._currentProfileId;
_dav = config._dav;
_isAccessControl = config._isAccessControl;
_accessControl = config._accessControl;
_themeProps = config._themeProps;
_windowProps = config._windowProps;
_proxiesStyle = config._proxiesStyle;
_vpnProps = config._vpnProps;
_overrideDns = config._overrideDns;
_desktopProps = config._desktopProps;
_hotKeyActions = config._hotKeyActions;
}
notifyListeners();
}
Map<String, dynamic> toJson() {
return _$ConfigToJson(this);
}
factory Config.fromJson(Map<String, dynamic> json) {
return _$ConfigFromJson(json);
}
@override
String toString() {
return 'Config{_appSetting: $_appSetting, _profiles: $_profiles, _currentProfileId: $_currentProfileId, _isAccessControl: $_isAccessControl, _accessControl: $_accessControl, _dav: $_dav, _windowProps: $_windowProps, _themeProps: $_themeProps, _vpnProps: $_vpnProps, _desktopProps: $_desktopProps, _overrideDns: $_overrideDns, _hotKeyActions: $_hotKeyActions, _proxiesStyle: $_proxiesStyle}';
}
}