Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
472cea9037 | ||
|
|
08d07498b9 | ||
|
|
d5aa09949a | ||
|
|
fd1dfe5c60 | ||
|
|
9f89fe8b29 | ||
|
|
78081a12e8 |
Submodule core/Clash.Meta updated: d1dc1e4433...1c46eb82bf
239
core/common.go
239
core/common.go
@@ -3,6 +3,7 @@ package main
|
||||
import "C"
|
||||
import (
|
||||
"github.com/metacubex/mihomo/adapter/inbound"
|
||||
ap "github.com/metacubex/mihomo/adapter/provider"
|
||||
"github.com/metacubex/mihomo/component/dialer"
|
||||
"github.com/metacubex/mihomo/component/process"
|
||||
"github.com/metacubex/mihomo/component/resolver"
|
||||
@@ -16,15 +17,53 @@ import (
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type healthCheckSchema struct {
|
||||
Enable bool `provider:"enable"`
|
||||
URL string `provider:"url"`
|
||||
Interval int `provider:"interval"`
|
||||
TestTimeout int `provider:"timeout,omitempty"`
|
||||
Lazy bool `provider:"lazy,omitempty"`
|
||||
ExpectedStatus string `provider:"expected-status,omitempty"`
|
||||
}
|
||||
|
||||
type proxyProviderSchema struct {
|
||||
Type string `provider:"type"`
|
||||
Path string `provider:"path,omitempty"`
|
||||
URL string `provider:"url,omitempty"`
|
||||
Proxy string `provider:"proxy,omitempty"`
|
||||
Interval int `provider:"interval,omitempty"`
|
||||
Filter string `provider:"filter,omitempty"`
|
||||
ExcludeFilter string `provider:"exclude-filter,omitempty"`
|
||||
ExcludeType string `provider:"exclude-type,omitempty"`
|
||||
DialerProxy string `provider:"dialer-proxy,omitempty"`
|
||||
|
||||
HealthCheck healthCheckSchema `provider:"health-check,omitempty"`
|
||||
Override ap.OverrideSchema `provider:"override,omitempty"`
|
||||
Header map[string][]string `provider:"header,omitempty"`
|
||||
}
|
||||
|
||||
type ruleProviderSchema struct {
|
||||
Type string `provider:"type"`
|
||||
Behavior string `provider:"behavior"`
|
||||
Path string `provider:"path,omitempty"`
|
||||
URL string `provider:"url,omitempty"`
|
||||
Proxy string `provider:"proxy,omitempty"`
|
||||
Format string `provider:"format,omitempty"`
|
||||
Interval int `provider:"interval,omitempty"`
|
||||
}
|
||||
|
||||
type GenerateConfigParams struct {
|
||||
ProfilePath *string `json:"profile-path"`
|
||||
Config *config.RawConfig `json:"config" `
|
||||
IsPatch *bool `json:"is-patch"`
|
||||
ProfilePath *string `json:"profile-path"`
|
||||
Config *config.RawConfig `json:"config" `
|
||||
IsPatch *bool `json:"is-patch"`
|
||||
IsCompatible *bool `json:"is-compatible"`
|
||||
}
|
||||
|
||||
type ChangeProxyParams struct {
|
||||
@@ -90,6 +129,19 @@ func readFile(path string) ([]byte, error) {
|
||||
return data, err
|
||||
}
|
||||
|
||||
func removeFile(path string) error {
|
||||
absPath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Remove(absPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRawConfigWithPath(path *string) *config.RawConfig {
|
||||
if path == nil {
|
||||
return config.DefaultRawConfig()
|
||||
@@ -108,18 +160,164 @@ func getRawConfigWithPath(path *string) *config.RawConfig {
|
||||
}
|
||||
}
|
||||
|
||||
func decorationConfig(profilePath *string, cfg config.RawConfig) *config.RawConfig {
|
||||
func decorationConfig(profilePath *string, cfg config.RawConfig, compatible bool) *config.RawConfig {
|
||||
prof := getRawConfigWithPath(profilePath)
|
||||
overwriteConfig(prof, cfg)
|
||||
overwriteConfig(prof, cfg, compatible)
|
||||
return prof
|
||||
}
|
||||
|
||||
func overwriteConfig(targetConfig *config.RawConfig, patchConfig config.RawConfig) {
|
||||
func Reduce[T any, U any](s []T, initVal U, f func(U, T) U) U {
|
||||
for _, v := range s {
|
||||
initVal = f(initVal, v)
|
||||
}
|
||||
return initVal
|
||||
}
|
||||
|
||||
func Map[T, U any](slice []T, fn func(T) U) []U {
|
||||
result := make([]U, len(slice))
|
||||
for i, v := range slice {
|
||||
result[i] = fn(v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func replaceFromMap(s string, m map[string]string) string {
|
||||
for k, v := range m {
|
||||
s = strings.ReplaceAll(s, k, v)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func removeDuplicateFromSlice[T any](slice []T) []T {
|
||||
result := make([]T, 0)
|
||||
seen := make(map[any]struct{})
|
||||
for _, value := range slice {
|
||||
if _, ok := seen[value]; !ok {
|
||||
result = append(result, value)
|
||||
seen[value] = struct{}{}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func generateProxyGroupAndRule(proxyGroup *[]map[string]any, rule *[]string) {
|
||||
var replacements = map[string]string{}
|
||||
var selectArr []map[string]any
|
||||
var urlTestArr []map[string]any
|
||||
var fallbackArr []map[string]any
|
||||
for _, group := range *proxyGroup {
|
||||
switch group["type"] {
|
||||
case "select":
|
||||
selectArr = append(selectArr, group)
|
||||
replacements[group["name"].(string)] = "Proxy"
|
||||
break
|
||||
case "url-test":
|
||||
urlTestArr = append(urlTestArr, group)
|
||||
replacements[group["name"].(string)] = "Auto"
|
||||
break
|
||||
case "fallback":
|
||||
fallbackArr = append(fallbackArr, group)
|
||||
replacements[group["name"].(string)] = "Fallback"
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
ProxyProxies := Reduce(selectArr, []string{}, func(res []string, cur map[string]any) []string {
|
||||
if cur["proxies"] == nil {
|
||||
return res
|
||||
}
|
||||
for _, proxyName := range cur["proxies"].([]interface{}) {
|
||||
if str, ok := proxyName.(string); ok {
|
||||
str = replaceFromMap(str, replacements)
|
||||
if str != "Proxy" {
|
||||
res = append(res, str)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
})
|
||||
|
||||
ProxyProxies = removeDuplicateFromSlice(ProxyProxies)
|
||||
|
||||
AutoProxies := Reduce(urlTestArr, []string{}, func(res []string, cur map[string]any) []string {
|
||||
if cur["proxies"] == nil {
|
||||
return res
|
||||
}
|
||||
for _, proxyName := range cur["proxies"].([]interface{}) {
|
||||
if str, ok := proxyName.(string); ok {
|
||||
str = replaceFromMap(str, replacements)
|
||||
if str != "Auto" {
|
||||
res = append(res, str)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
})
|
||||
|
||||
AutoProxies = removeDuplicateFromSlice(AutoProxies)
|
||||
|
||||
FallbackProxies := Reduce(fallbackArr, []string{}, func(res []string, cur map[string]any) []string {
|
||||
if cur["proxies"] == nil {
|
||||
return res
|
||||
}
|
||||
for _, proxyName := range cur["proxies"].([]interface{}) {
|
||||
if str, ok := proxyName.(string); ok {
|
||||
str = replaceFromMap(str, replacements)
|
||||
if str != "Fallback" {
|
||||
res = append(res, str)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
})
|
||||
|
||||
FallbackProxies = removeDuplicateFromSlice(FallbackProxies)
|
||||
|
||||
var computedProxyGroup []map[string]any
|
||||
|
||||
if len(ProxyProxies) > 0 {
|
||||
computedProxyGroup = append(computedProxyGroup,
|
||||
map[string]any{
|
||||
"name": "Proxy",
|
||||
"type": "select",
|
||||
"proxies": ProxyProxies,
|
||||
})
|
||||
}
|
||||
|
||||
if len(AutoProxies) > 0 {
|
||||
computedProxyGroup = append(computedProxyGroup,
|
||||
map[string]any{
|
||||
"name": "Auto",
|
||||
"type": "url-test",
|
||||
"proxies": AutoProxies,
|
||||
})
|
||||
}
|
||||
|
||||
if len(FallbackProxies) > 0 {
|
||||
computedProxyGroup = append(computedProxyGroup,
|
||||
map[string]any{
|
||||
"name": "Fallback",
|
||||
"type": "fallback",
|
||||
"proxies": FallbackProxies,
|
||||
})
|
||||
}
|
||||
|
||||
computedRule := Map(*rule, func(value string) string {
|
||||
return replaceFromMap(value, replacements)
|
||||
})
|
||||
|
||||
*proxyGroup = computedProxyGroup
|
||||
*rule = computedRule
|
||||
}
|
||||
|
||||
func overwriteConfig(targetConfig *config.RawConfig, patchConfig config.RawConfig, compatible bool) {
|
||||
targetConfig.ExternalController = ""
|
||||
targetConfig.ExternalUI = ""
|
||||
targetConfig.Interface = ""
|
||||
targetConfig.ExternalUIURL = ""
|
||||
targetConfig.IPv6 = patchConfig.IPv6
|
||||
//targetConfig.IPv6 = patchConfig.IPv6
|
||||
targetConfig.LogLevel = patchConfig.LogLevel
|
||||
targetConfig.FindProcessMode = process.FindProcessAlways
|
||||
targetConfig.AllowLan = patchConfig.AllowLan
|
||||
@@ -129,23 +327,22 @@ func overwriteConfig(targetConfig *config.RawConfig, patchConfig config.RawConfi
|
||||
targetConfig.Tun.Device = patchConfig.Tun.Device
|
||||
targetConfig.Tun.DNSHijack = patchConfig.Tun.DNSHijack
|
||||
targetConfig.Tun.Stack = patchConfig.Tun.Stack
|
||||
targetConfig.GeodataLoader = "standard"
|
||||
targetConfig.Profile.StoreSelected = false
|
||||
if targetConfig.DNS.Enable == false {
|
||||
targetConfig.DNS = patchConfig.DNS
|
||||
} else {
|
||||
targetConfig.DNS.UseHosts = patchConfig.DNS.UseHosts
|
||||
targetConfig.DNS.EnhancedMode = patchConfig.DNS.EnhancedMode
|
||||
targetConfig.DNS.IPv6 = patchConfig.DNS.IPv6
|
||||
targetConfig.DNS.DefaultNameserver = append(patchConfig.DNS.DefaultNameserver, targetConfig.DNS.DefaultNameserver...)
|
||||
targetConfig.DNS.NameServer = append(patchConfig.DNS.NameServer, targetConfig.DNS.NameServer...)
|
||||
targetConfig.DNS.FakeIPFilter = append(patchConfig.DNS.FakeIPFilter, targetConfig.DNS.FakeIPFilter...)
|
||||
targetConfig.DNS.Fallback = append(patchConfig.DNS.Fallback, targetConfig.DNS.Fallback...)
|
||||
if runtime.GOOS == "android" {
|
||||
targetConfig.DNS.NameServer = append(targetConfig.DNS.NameServer, "dhcp://"+dns.SystemDNSPlaceholder)
|
||||
} else if runtime.GOOS == "windows" {
|
||||
targetConfig.DNS.NameServer = append(targetConfig.DNS.NameServer, dns.SystemDNSPlaceholder)
|
||||
}
|
||||
}
|
||||
if runtime.GOOS == "android" {
|
||||
targetConfig.DNS.NameServer = append(targetConfig.DNS.NameServer, "dhcp://"+dns.SystemDNSPlaceholder)
|
||||
} else if runtime.GOOS == "windows" {
|
||||
targetConfig.DNS.NameServer = append(targetConfig.DNS.NameServer, dns.SystemDNSPlaceholder)
|
||||
}
|
||||
if compatible == false {
|
||||
targetConfig.ProxyProvider = make(map[string]map[string]any)
|
||||
targetConfig.RuleProvider = make(map[string]map[string]any)
|
||||
generateProxyGroupAndRule(&targetConfig.ProxyGroup, &targetConfig.Rule)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func patchConfig(general *config.General) {
|
||||
@@ -193,7 +390,6 @@ func hcCompatibleProvider(proxyProviders map[string]provider.ProxyProvider) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func applyConfig(isPatch bool) {
|
||||
@@ -205,5 +401,6 @@ func applyConfig(isPatch bool) {
|
||||
patchConfig(cfg.General)
|
||||
} else {
|
||||
executor.ApplyConfig(cfg, true)
|
||||
healthcheck()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@ type Message struct {
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func (message *Message) toJson() string {
|
||||
func (message *Message) Json() string {
|
||||
data, _ := json.Marshal(message)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func SendMessage(message Message) {
|
||||
SendToPort(*Port, message.toJson())
|
||||
SendToPort(*Port, message.Json())
|
||||
}
|
||||
|
||||
79
core/hub.go
79
core/hub.go
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/metacubex/mihomo/adapter"
|
||||
"github.com/metacubex/mihomo/adapter/outboundgroup"
|
||||
"github.com/metacubex/mihomo/adapter/provider"
|
||||
"github.com/metacubex/mihomo/common/structure"
|
||||
"github.com/metacubex/mihomo/common/utils"
|
||||
"github.com/metacubex/mihomo/config"
|
||||
"github.com/metacubex/mihomo/constant"
|
||||
@@ -74,7 +75,7 @@ func updateConfig(s *C.char, port C.longlong) {
|
||||
bridge.SendToPort(i, err.Error())
|
||||
return
|
||||
}
|
||||
prof := decorationConfig(params.ProfilePath, *params.Config)
|
||||
prof := decorationConfig(params.ProfilePath, *params.Config, *params.IsCompatible)
|
||||
currentConfig = prof
|
||||
if *params.IsPatch {
|
||||
applyConfig(true)
|
||||
@@ -85,6 +86,39 @@ func updateConfig(s *C.char, port C.longlong) {
|
||||
}()
|
||||
}
|
||||
|
||||
//export clearEffect
|
||||
func clearEffect(s *C.char) {
|
||||
path := C.GoString(s)
|
||||
go func() {
|
||||
rawCfg := getRawConfigWithPath(&path)
|
||||
for _, mapping := range rawCfg.RuleProvider {
|
||||
schema := &ruleProviderSchema{}
|
||||
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
|
||||
if err := decoder.Decode(mapping, schema); err != nil {
|
||||
return
|
||||
}
|
||||
if schema.Type == "http" {
|
||||
_ = removeFile(constant.Path.Resolve(schema.Path))
|
||||
}
|
||||
}
|
||||
for _, mapping := range rawCfg.ProxyProvider {
|
||||
schema := &proxyProviderSchema{
|
||||
HealthCheck: healthCheckSchema{
|
||||
Lazy: true,
|
||||
},
|
||||
}
|
||||
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
|
||||
if err := decoder.Decode(mapping, schema); err != nil {
|
||||
return
|
||||
}
|
||||
if schema.Type == "http" {
|
||||
_ = removeFile(constant.Path.Resolve(schema.Path))
|
||||
}
|
||||
}
|
||||
_ = removeFile(path)
|
||||
}()
|
||||
}
|
||||
|
||||
//export getProxies
|
||||
func getProxies() *C.char {
|
||||
data, err := json.Marshal(tunnel.ProxiesWithProviders())
|
||||
@@ -96,27 +130,28 @@ func getProxies() *C.char {
|
||||
|
||||
//export changeProxy
|
||||
func changeProxy(s *C.char) bool {
|
||||
paramsString := C.GoString(s)
|
||||
var params = &ChangeProxyParams{}
|
||||
err := json.Unmarshal([]byte(paramsString), params)
|
||||
if err != nil {
|
||||
log.Infoln("Unmarshal ChangeProxyParams %v", err)
|
||||
return false
|
||||
}
|
||||
proxies := tunnel.ProxiesWithProviders()
|
||||
proxy := proxies[*params.GroupName]
|
||||
if proxy == nil {
|
||||
return false
|
||||
}
|
||||
log.Infoln("change proxy %s", proxy.Name())
|
||||
adapterProxy := proxy.(*adapter.Proxy)
|
||||
selector, ok := adapterProxy.ProxyAdapter.(*outboundgroup.Selector)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if err := selector.Set(*params.ProxyName); err != nil {
|
||||
return false
|
||||
}
|
||||
go func() {
|
||||
paramsString := C.GoString(s)
|
||||
var params = &ChangeProxyParams{}
|
||||
err := json.Unmarshal([]byte(paramsString), params)
|
||||
if err != nil {
|
||||
log.Infoln("Unmarshal ChangeProxyParams %v", err)
|
||||
}
|
||||
proxies := tunnel.ProxiesWithProviders()
|
||||
proxy := proxies[*params.GroupName]
|
||||
if proxy == nil {
|
||||
return
|
||||
}
|
||||
log.Infoln("change proxy %s", proxy.Name())
|
||||
adapterProxy := proxy.(*adapter.Proxy)
|
||||
selector, ok := adapterProxy.ProxyAdapter.(*outboundgroup.Selector)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if err := selector.Set(*params.ProxyName); err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,14 @@ runAppWithPreferences(
|
||||
ChangeNotifierProvider<Config>(
|
||||
create: (_) => config,
|
||||
),
|
||||
ChangeNotifierProvider<AppState>(
|
||||
ChangeNotifierProxyProvider2<Config, ClashConfig, AppState>(
|
||||
create: (_) => appState,
|
||||
update: (_, config, clashConfig, appState) {
|
||||
appState?.mode = clashConfig.mode;
|
||||
appState?.isCompatible = config.isCompatible;
|
||||
appState?.selectedMap = config.currentSelectedMap;
|
||||
return appState!;
|
||||
},
|
||||
)
|
||||
],
|
||||
child: child,
|
||||
@@ -70,6 +76,7 @@ class ApplicationState extends State<Application> {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
appController.afterInit();
|
||||
appController.initLink();
|
||||
_updateGroups();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -102,6 +109,18 @@ class ApplicationState extends State<Application> {
|
||||
});
|
||||
}
|
||||
|
||||
_updateGroups() {
|
||||
if (globalState.groupsUpdateTimer != null) {
|
||||
globalState.groupsUpdateTimer?.cancel();
|
||||
globalState.groupsUpdateTimer = null;
|
||||
}
|
||||
globalState.groupsUpdateTimer ??=
|
||||
Timer.periodic(appConstant.httpTimeoutDuration, (timer) async {
|
||||
await appController.updateGroups();
|
||||
appController.appState.sortNum++;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(context) {
|
||||
return AppStateContainer(
|
||||
|
||||
@@ -100,9 +100,6 @@ class ClashCore {
|
||||
.map(
|
||||
(name) => proxies[name],
|
||||
)
|
||||
.where(
|
||||
(proxy) => proxy["type"] != GroupType.Selector.value,
|
||||
)
|
||||
.toList();
|
||||
return group;
|
||||
}).toList();
|
||||
@@ -110,6 +107,31 @@ class ClashCore {
|
||||
});
|
||||
}
|
||||
|
||||
Future<DelayMap> getDelayMap() {
|
||||
final proxiesRaw = clashFFI.getProxies();
|
||||
final proxiesRawString = proxiesRaw.cast<Utf8>().toDartString();
|
||||
return Isolate.run<DelayMap>(() {
|
||||
final proxies = json.decode(proxiesRawString) as Map<String, dynamic>;
|
||||
return proxies.map<String, int?>(
|
||||
(k, v) {
|
||||
final history = v["history"] as List<dynamic>;
|
||||
if (history.isEmpty) {
|
||||
return MapEntry(
|
||||
k,
|
||||
null,
|
||||
);
|
||||
} else {
|
||||
final delay = history.last["delay"];
|
||||
return MapEntry(
|
||||
k,
|
||||
delay != 0 ? delay : -1,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
bool changeProxy(ChangeProxyParams changeProxyParams) {
|
||||
final params = json.encode(changeProxyParams);
|
||||
return clashFFI.changeProxy(params.toNativeUtf8().cast()) == 1;
|
||||
@@ -124,6 +146,10 @@ class ClashCore {
|
||||
return true;
|
||||
}
|
||||
|
||||
clearEffect(String path) {
|
||||
clashFFI.clearEffect(path.toNativeUtf8().cast());
|
||||
}
|
||||
|
||||
healthcheck() {
|
||||
clashFFI.healthcheck();
|
||||
}
|
||||
|
||||
@@ -924,6 +924,20 @@ class ClashFFI {
|
||||
late final _updateConfig =
|
||||
_updateConfigPtr.asFunction<void Function(ffi.Pointer<ffi.Char>, int)>();
|
||||
|
||||
void clearEffect(
|
||||
ffi.Pointer<ffi.Char> s,
|
||||
) {
|
||||
return _clearEffect(
|
||||
s,
|
||||
);
|
||||
}
|
||||
|
||||
late final _clearEffectPtr =
|
||||
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Char>)>>(
|
||||
'clearEffect');
|
||||
late final _clearEffect =
|
||||
_clearEffectPtr.asFunction<void Function(ffi.Pointer<ffi.Char>)>();
|
||||
|
||||
ffi.Pointer<ffi.Char> getProxies() {
|
||||
return _getProxies();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'dart:io';
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/models/models.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'core.dart';
|
||||
|
||||
class ClashService {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -87,13 +85,7 @@ class AppController {
|
||||
config.deleteProfileById(id);
|
||||
final profilePath = await appPath.getProfilePath(id);
|
||||
if (profilePath == null) return;
|
||||
final file = File(profilePath);
|
||||
Isolate.run(() async {
|
||||
final isExists = await file.exists();
|
||||
if (isExists) {
|
||||
file.delete();
|
||||
}
|
||||
});
|
||||
clashCore.clearEffect(profilePath);
|
||||
if (config.currentProfileId == id) {
|
||||
if (config.profiles.isNotEmpty) {
|
||||
final updateId = config.profiles.first.id;
|
||||
@@ -172,13 +164,6 @@ class AppController {
|
||||
appState.systemColorSchemes = systemColorSchemes;
|
||||
}
|
||||
|
||||
clearCurrentDelay() {
|
||||
final currentProxyName =
|
||||
appState.getCurrentProxyName(config.currentProxyName, clashConfig.mode);
|
||||
if (currentProxyName == null) return;
|
||||
appState.setDelay(Delay(name: currentProxyName, value: null));
|
||||
}
|
||||
|
||||
savePreferences() async {
|
||||
await saveConfigPreferences();
|
||||
await saveClashConfigPreferences();
|
||||
@@ -236,7 +221,6 @@ class AppController {
|
||||
}
|
||||
|
||||
healthcheck() {
|
||||
if (globalState.healthcheckLock) return;
|
||||
for (final delay in appState.delayMap.entries) {
|
||||
setDelay(
|
||||
Delay(
|
||||
@@ -252,6 +236,10 @@ class AppController {
|
||||
appState.setDelay(delay);
|
||||
}
|
||||
|
||||
updateDelayMap() async {
|
||||
appState.delayMap = await clashCore.getDelayMap();
|
||||
}
|
||||
|
||||
toPage(int index, {bool hasAnimate = false}) {
|
||||
final nextLabel = globalState.currentNavigationItems[index].label;
|
||||
appState.currentLabel = nextLabel;
|
||||
@@ -362,4 +350,13 @@ class AppController {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
clearShowProxyDelay() {
|
||||
final showProxyDelay = appState.getRealProxyName(appState.showProxyName);
|
||||
if (showProxyDelay != null) {
|
||||
appState.setDelay(
|
||||
Delay(name: showProxyDelay, value: null),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
enum GroupType { Selector, URLTest, Fallback }
|
||||
|
||||
enum GroupName { GLOBAL, Proxy, Auto, Fallback }
|
||||
|
||||
extension GroupTypeExtension on GroupType {
|
||||
static List<String> get valueList => GroupType.values
|
||||
.map(
|
||||
|
||||
@@ -35,6 +35,26 @@ class ApplicationSettingFragment extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
Selector<Config, bool>(
|
||||
selector: (_, config) => config.isCompatible,
|
||||
builder: (_, isCompatible, __) {
|
||||
return ListItem.switchItem(
|
||||
leading: const Icon(Icons.device_hub),
|
||||
title: const Text("兼容模式"),
|
||||
subtitle: const Text("开启将失去部分应用能力,获得全量的Clash的支持"),
|
||||
delegate: SwitchDelegate(
|
||||
value: isCompatible,
|
||||
onChanged: (bool value) async {
|
||||
final appController = context.appController;
|
||||
appController.config.isCompatible = value;
|
||||
await appController.updateClashConfig(isPatch: false);
|
||||
await appController.updateGroups();
|
||||
appController.changeProxy();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
if (system.isDesktop)
|
||||
Selector<Config, bool>(
|
||||
selector: (_, config) => config.autoLaunch,
|
||||
|
||||
@@ -120,7 +120,7 @@ class _ConfigFragmentState extends State<ConfigFragment> {
|
||||
return ListView.separated(
|
||||
itemBuilder: (_, index) {
|
||||
return Container(
|
||||
height: 84,
|
||||
padding: kMaterialListPadding,
|
||||
alignment: Alignment.center,
|
||||
child: items[index],
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/models/models.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:fl_clash/widgets/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -72,6 +73,52 @@ class _NetworkDetectionState extends State<NetworkDetection> {
|
||||
);
|
||||
}
|
||||
|
||||
_updateCurrentDelay(
|
||||
String? currentProxyName,
|
||||
int? delay,
|
||||
bool isCurrent,
|
||||
bool isInit,
|
||||
) {
|
||||
if (!isCurrent || currentProxyName == null || !isInit) return;
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
if (delay == null) {
|
||||
context.appController.setDelay(
|
||||
Delay(
|
||||
name: currentProxyName,
|
||||
value: 0,
|
||||
),
|
||||
);
|
||||
globalState.updateCurrentDelay(
|
||||
currentProxyName,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_updateCurrentDelayContainer(Widget child) {
|
||||
return Selector2<AppState, Config, UpdateCurrentDelaySelectorState>(
|
||||
selector: (_, appState, config) {
|
||||
return UpdateCurrentDelaySelectorState(
|
||||
isInit: appState.isInit,
|
||||
currentProxyName: appState.getRealProxyName(appState.showProxyName),
|
||||
delay: appState
|
||||
.delayMap[appState.getRealProxyName(appState.showProxyName)],
|
||||
isCurrent: appState.currentLabel == 'dashboard',
|
||||
);
|
||||
},
|
||||
builder: (_, state, __) {
|
||||
_updateCurrentDelay(
|
||||
state.currentProxyName,
|
||||
state.delay,
|
||||
state.isCurrent,
|
||||
state.isInit,
|
||||
);
|
||||
return child;
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CommonCard(
|
||||
@@ -79,59 +126,57 @@ class _NetworkDetectionState extends State<NetworkDetection> {
|
||||
iconData: Icons.network_check,
|
||||
label: appLocalizations.networkDetection,
|
||||
),
|
||||
child: Selector3<AppState, Config, ClashConfig,
|
||||
NetworkDetectionSelectorState>(
|
||||
selector: (_, appState, config, clashConfig) {
|
||||
final proxyName = appState.getCurrentProxyName(
|
||||
config.currentProxyName,
|
||||
clashConfig.mode,
|
||||
);
|
||||
return NetworkDetectionSelectorState(
|
||||
isInit: appState.isInit,
|
||||
currentProxyName: proxyName,
|
||||
delay: appState.getDelay(
|
||||
proxyName,
|
||||
),
|
||||
);
|
||||
},
|
||||
builder: (_, state, __) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16).copyWith(top: 0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 0,
|
||||
child: TooltipText(
|
||||
text: Text(
|
||||
state.currentProxyName ?? appLocalizations.noProxy,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style:
|
||||
Theme.of(context).textTheme.titleMedium?.toSoftBold(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
Flexible(
|
||||
child: Container(
|
||||
height: context.appController.measure.titleLargeHeight,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: FadeBox(
|
||||
child: _buildDescription(
|
||||
state.currentProxyName,
|
||||
state.delay,
|
||||
child: _updateCurrentDelayContainer(
|
||||
Selector<AppState, NetworkDetectionSelectorState>(
|
||||
selector: (_, appState) {
|
||||
return NetworkDetectionSelectorState(
|
||||
currentProxyName: appState.showProxyName,
|
||||
delay: appState.getDelay(
|
||||
appState.showProxyName,
|
||||
),
|
||||
);
|
||||
},
|
||||
builder: (_, state, __) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16).copyWith(top: 0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 0,
|
||||
child: TooltipText(
|
||||
text: Text(
|
||||
state.currentProxyName ?? appLocalizations.noProxy,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleMedium
|
||||
?.toSoftBold(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
Flexible(
|
||||
child: Container(
|
||||
height: context.appController.measure.titleLargeHeight,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: FadeBox(
|
||||
child: _buildDescription(
|
||||
state.currentProxyName,
|
||||
state.delay,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,10 +11,18 @@ class OutboundMode extends StatelessWidget {
|
||||
|
||||
_changeMode(BuildContext context, Mode? value) async {
|
||||
final appController = context.appController;
|
||||
final clashConfig = context.read<ClashConfig>();
|
||||
final clashConfig = appController.clashConfig;
|
||||
final config = appController.config;
|
||||
if (value == null || clashConfig.mode == value) return;
|
||||
clashConfig.mode = value;
|
||||
await appController.updateClashConfig();
|
||||
if (!config.isCompatible) {
|
||||
final proxySelected = config.currentSelectedMap[GroupName.Proxy.name];
|
||||
final globalSelected = config.currentSelectedMap[GroupName.GLOBAL.name];
|
||||
if (proxySelected != null && globalSelected == null) {
|
||||
config.updateCurrentSelectedMap(GroupName.GLOBAL.name, proxySelected);
|
||||
}
|
||||
}
|
||||
appController.changeProxy();
|
||||
}
|
||||
|
||||
@@ -54,7 +62,8 @@ class OutboundMode extends StatelessWidget {
|
||||
),
|
||||
title: Text(
|
||||
Intl.message(item.name),
|
||||
style: Theme.of(context)
|
||||
style: Theme
|
||||
.of(context)
|
||||
.textTheme
|
||||
.titleMedium
|
||||
?.toSoftBold(),
|
||||
|
||||
@@ -51,7 +51,7 @@ class _StartButtonState extends State<StartButton>
|
||||
final appController = context.appController;
|
||||
await appController.updateSystemProxy(isStart);
|
||||
if (isStart && mounted) {
|
||||
appController.clearCurrentDelay();
|
||||
appController.clearShowProxyDelay();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,14 +66,17 @@ class _StartButtonState extends State<StartButton>
|
||||
if (!state.isInit || !state.hasProfile) {
|
||||
return Container();
|
||||
}
|
||||
final textWidth = context.appController.measure.computeTextSize(
|
||||
Text(
|
||||
Other.getTimeDifference(
|
||||
DateTime.now(),
|
||||
),
|
||||
style: Theme.of(context).textTheme.titleMedium?.toSoftBold(),
|
||||
),
|
||||
).width +
|
||||
final textWidth = context.appController.measure
|
||||
.computeTextSize(
|
||||
Text(
|
||||
Other.getTimeDifference(
|
||||
DateTime.now(),
|
||||
),
|
||||
style:
|
||||
Theme.of(context).textTheme.titleMedium?.toSoftBold(),
|
||||
),
|
||||
)
|
||||
.width +
|
||||
16;
|
||||
return AnimatedBuilder(
|
||||
animation: _controller.view,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:fl_clash/clash/clash.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -69,25 +69,23 @@ class _ProxiesFragmentState extends State<ProxiesFragment>
|
||||
},
|
||||
child: Selector3<AppState, Config, ClashConfig, ProxiesSelectorState>(
|
||||
selector: (_, appState, config, clashConfig) {
|
||||
final currentGroups = appState.getCurrentGroups(clashConfig.mode);
|
||||
final currentGroups = appState.currentGroups;
|
||||
final groupNames = currentGroups.map((e) => e.name).toList();
|
||||
final currentProxyName = appState.getCurrentGroupNameWithGroups(
|
||||
currentGroups,
|
||||
config.currentGroupName,
|
||||
clashConfig.mode,
|
||||
);
|
||||
final currentIndex = currentGroups
|
||||
.indexWhere((element) => element.name == currentProxyName);
|
||||
return ProxiesSelectorState(
|
||||
currentIndex: currentIndex,
|
||||
groupNames: groupNames,
|
||||
);
|
||||
},
|
||||
shouldRebuild: (prev, next) {
|
||||
if (prev.groupNames.length != next.groupNames.length) {
|
||||
_tabController?.dispose();
|
||||
_tabController = null;
|
||||
}
|
||||
return prev != next;
|
||||
},
|
||||
builder: (_, state, __) {
|
||||
_tabController ??= TabController(
|
||||
length: state.groupNames.length,
|
||||
vsync: this,
|
||||
initialIndex: state.currentIndex,
|
||||
);
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
@@ -148,12 +146,11 @@ class ProxiesTabView extends StatelessWidget {
|
||||
|
||||
List<Proxy> _sortOfDelay(BuildContext context, List<Proxy> proxies) {
|
||||
final appState = context.read<AppState>();
|
||||
final delayMap = appState.delayMap;
|
||||
return proxies = List.of(proxies)
|
||||
..sort(
|
||||
(a, b) {
|
||||
final aDelay = delayMap[a.name];
|
||||
final bDelay = delayMap[b.name];
|
||||
final aDelay = appState.delayMap[a.name];
|
||||
final bDelay = appState.delayMap[b.name];
|
||||
if (aDelay == null && bDelay == null) {
|
||||
return 0;
|
||||
}
|
||||
@@ -232,12 +229,22 @@ class ProxiesTabView extends StatelessWidget {
|
||||
),
|
||||
SizedBox(
|
||||
height: measure.bodySmallHeight,
|
||||
child: Text(
|
||||
proxy.type,
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
color: context.textTheme.bodySmall?.color?.toLight(),
|
||||
child: Selector<AppState, String>(
|
||||
selector: (context, appState) => appState.getDesc(
|
||||
proxy.type,
|
||||
proxy.name,
|
||||
),
|
||||
builder: (_, desc, __) {
|
||||
return TooltipText(
|
||||
text: Text(
|
||||
desc,
|
||||
style: context.textTheme.bodySmall?.copyWith(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
color: context.textTheme.bodySmall?.color?.toLight(),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
@@ -246,7 +253,9 @@ class ProxiesTabView extends StatelessWidget {
|
||||
SizedBox(
|
||||
height: measure.labelSmallHeight,
|
||||
child: Selector<AppState, int?>(
|
||||
selector: (context, appState) => appState.getDelay(proxy.name),
|
||||
selector: (context, appState) => appState.getDelay(
|
||||
proxy.name,
|
||||
),
|
||||
builder: (_, delay, __) {
|
||||
return FadeBox(
|
||||
child: Builder(
|
||||
@@ -303,23 +312,12 @@ class ProxiesTabView extends StatelessWidget {
|
||||
return Selector3<AppState, Config, ClashConfig,
|
||||
ProxiesCardSelectorState>(
|
||||
selector: (_, appState, config, clashConfig) {
|
||||
final currentGroupName = appState.getCurrentGroupName(
|
||||
config.currentGroupName,
|
||||
clashConfig.mode,
|
||||
);
|
||||
final currentProxyName = appState.getCurrentProxyName(
|
||||
config.currentProxyName,
|
||||
clashConfig.mode,
|
||||
);
|
||||
final group = appState.getGroupWithName(groupName);
|
||||
final isSelected = group.type == GroupType.Selector
|
||||
? group.name == currentGroupName &&
|
||||
proxy.name == currentProxyName
|
||||
: group.now == proxy.name;
|
||||
final group = appState.getGroupWithName(groupName)!;
|
||||
bool isSelected = config.currentSelectedMap[group.name] == proxy.name ||
|
||||
(config.currentSelectedMap[group.name] == null &&
|
||||
group.now == proxy.name);
|
||||
return ProxiesCardSelectorState(
|
||||
isSelected: isSelected,
|
||||
currentGroupName: currentGroupName,
|
||||
currentProxyName: currentProxyName,
|
||||
);
|
||||
},
|
||||
builder: (_, state, __) {
|
||||
@@ -327,15 +325,21 @@ class ProxiesTabView extends StatelessWidget {
|
||||
context,
|
||||
isSelected: state.isSelected,
|
||||
onPressed: () {
|
||||
final appController = context.appController;
|
||||
final group =
|
||||
context.appController.appState.getGroupWithName(groupName);
|
||||
if (group.type == GroupType.Selector) {
|
||||
final config = context.read<Config>();
|
||||
config.currentProfile?.groupName = group.name;
|
||||
config.currentProfile?.proxyName = proxy.name;
|
||||
config.update();
|
||||
context.appController.changeProxy();
|
||||
appController.appState.getGroupWithName(groupName)!;
|
||||
if (group.type != GroupType.Selector) {
|
||||
globalState.showSnackBar(
|
||||
context,
|
||||
message: "当前代理组无法选择",
|
||||
);
|
||||
return;
|
||||
}
|
||||
context.appController.config.updateCurrentSelectedMap(
|
||||
groupName,
|
||||
proxy.name,
|
||||
);
|
||||
context.appController.changeProxy();
|
||||
},
|
||||
proxy: proxy,
|
||||
);
|
||||
@@ -352,7 +356,7 @@ class ProxiesTabView extends StatelessWidget {
|
||||
return ProxiesTabViewSelectorState(
|
||||
proxiesSortType: config.proxiesSortType,
|
||||
sortNum: appState.sortNum,
|
||||
group: appState.getGroupWithName(groupName),
|
||||
group: appState.getGroupWithName(groupName)!,
|
||||
);
|
||||
},
|
||||
builder: (_, state, __) {
|
||||
|
||||
@@ -17,7 +17,11 @@ Future<void> main() async {
|
||||
await window?.init();
|
||||
final config = await preferences.getConfig() ?? Config();
|
||||
final clashConfig = await preferences.getClashConfig() ?? ClashConfig();
|
||||
final appState = AppState();
|
||||
final appState = AppState(
|
||||
mode: clashConfig.mode,
|
||||
isCompatible: config.isCompatible,
|
||||
selectedMap: config.currentSelectedMap,
|
||||
);
|
||||
await globalState.init(
|
||||
appState: appState,
|
||||
config: config,
|
||||
@@ -41,7 +45,11 @@ Future<void> vpnService() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final config = await preferences.getConfig() ?? Config();
|
||||
final clashConfig = await preferences.getClashConfig() ?? ClashConfig();
|
||||
final appState = AppState();
|
||||
final appState = AppState(
|
||||
mode: clashConfig.mode,
|
||||
isCompatible: config.isCompatible,
|
||||
selectedMap: config.currentSelectedMap,
|
||||
);
|
||||
clashMessage.addListener(ClashMessageListenerWithVpn(onTun: (String fd) {
|
||||
proxyManager.setProtect(
|
||||
int.parse(fd),
|
||||
|
||||
@@ -5,35 +5,47 @@ import 'ffi.dart';
|
||||
import 'log.dart';
|
||||
import 'navigation.dart';
|
||||
import 'package.dart';
|
||||
import 'profile.dart';
|
||||
import 'proxy.dart';
|
||||
import 'system_color_scheme.dart';
|
||||
import 'traffic.dart';
|
||||
import 'version.dart';
|
||||
|
||||
typedef DelayMap = Map<String, int?>;
|
||||
|
||||
class AppState with ChangeNotifier {
|
||||
List<NavigationItem> _navigationItems;
|
||||
int? _runTime;
|
||||
bool _isInit;
|
||||
DelayMap _delayMap;
|
||||
VersionInfo? _versionInfo;
|
||||
List<Traffic> _traffics;
|
||||
List<Log> _logs;
|
||||
List<Package> _packages;
|
||||
String _currentLabel;
|
||||
SystemColorSchemes _systemColorSchemes;
|
||||
List<Group> _groups;
|
||||
num _sortNum;
|
||||
Mode _mode;
|
||||
DelayMap _delayMap;
|
||||
SelectedMap _selectedMap;
|
||||
bool _isCompatible;
|
||||
List<Group> _groups;
|
||||
|
||||
AppState()
|
||||
: _navigationItems = [],
|
||||
_delayMap = {},
|
||||
AppState({
|
||||
required Mode mode,
|
||||
required bool isCompatible,
|
||||
required SelectedMap selectedMap,
|
||||
}) : _navigationItems = [],
|
||||
_isInit = false,
|
||||
_currentLabel = "dashboard",
|
||||
_traffics = [],
|
||||
_logs = [],
|
||||
_groups = [],
|
||||
_selectedMap = selectedMap,
|
||||
_packages = [],
|
||||
_sortNum = 0,
|
||||
_mode = mode,
|
||||
_delayMap = {},
|
||||
_groups = [],
|
||||
_isCompatible = isCompatible,
|
||||
_systemColorSchemes = SystemColorSchemes();
|
||||
|
||||
String get currentLabel => _currentLabel;
|
||||
@@ -72,29 +84,38 @@ class AppState with ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
DelayMap get delayMap => _delayMap;
|
||||
|
||||
set delayMap(DelayMap value) {
|
||||
if (_delayMap != value) {
|
||||
_delayMap = value;
|
||||
notifyListeners();
|
||||
String getDesc(String type, String? proxyName) {
|
||||
final groupTypeNamesList = GroupType.values.map((e) => e.name).toList();
|
||||
if (!groupTypeNamesList.contains(type)) {
|
||||
return type;
|
||||
} else {
|
||||
final index = groups.indexWhere((element) => element.name == proxyName);
|
||||
if (index == -1) return type;
|
||||
return "$type(${groups[index].now})";
|
||||
}
|
||||
}
|
||||
|
||||
String? getRealProxyName(String? proxyName) {
|
||||
if (proxyName == null) return null;
|
||||
final index = groups.indexWhere((element) => element.name == proxyName);
|
||||
if (index == -1) return proxyName;
|
||||
final group = groups[index];
|
||||
return getRealProxyName(selectedMap.containsKey(proxyName)
|
||||
? selectedMap[proxyName]
|
||||
: group.now);
|
||||
}
|
||||
|
||||
String? get showProxyName {
|
||||
if (currentGroups.isEmpty) {
|
||||
return UsedProxy.DIRECT.name;
|
||||
}
|
||||
final firstGroup = currentGroups.first;
|
||||
final firstGroupName = firstGroup.name;
|
||||
return selectedMap[firstGroupName] ?? firstGroup.now;
|
||||
}
|
||||
|
||||
int? getDelay(String? proxyName) {
|
||||
if (proxyName == null) return null;
|
||||
final index = groups.indexWhere((element) => element.name == proxyName);
|
||||
if (index == -1) return _delayMap[proxyName];
|
||||
final group = groups[index];
|
||||
if (group.now == null) return null;
|
||||
return _delayMap[group.now];
|
||||
}
|
||||
|
||||
setDelay(Delay delay) {
|
||||
if (_delayMap[delay.name] != delay.value) {
|
||||
_delayMap = Map.from(_delayMap)..[delay.name] = delay.value;
|
||||
notifyListeners();
|
||||
}
|
||||
return _delayMap[getRealProxyName(proxyName)];
|
||||
}
|
||||
|
||||
VersionInfo? get versionInfo => _versionInfo;
|
||||
@@ -170,53 +191,86 @@ class AppState with ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
List<Group> getCurrentGroups(Mode mode) {
|
||||
Mode get mode => _mode;
|
||||
|
||||
set mode(Mode value) {
|
||||
if (_mode != value) {
|
||||
_mode = value;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// String? get currentProxyName {
|
||||
// if (mode == Mode.direct) return UsedProxy.DIRECT.name;
|
||||
// if (_currentProxyName != null) return _currentProxyName!;
|
||||
// return currentGroup?.now;
|
||||
// }
|
||||
//
|
||||
// set currentProxyName(String? value) {
|
||||
// if (_currentProxyName != value) {
|
||||
// _currentProxyName = value;
|
||||
// notifyListeners();
|
||||
// }
|
||||
// }
|
||||
|
||||
bool get isCompatible {
|
||||
return _isCompatible;
|
||||
}
|
||||
|
||||
set isCompatible(bool value) {
|
||||
if (_isCompatible != value) {
|
||||
_isCompatible = value;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
SelectedMap get selectedMap {
|
||||
return _selectedMap;
|
||||
}
|
||||
|
||||
set selectedMap(SelectedMap value) {
|
||||
if (!const MapEquality<String, String>().equals(_selectedMap, value)) {
|
||||
_selectedMap = value;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
List<Group> get currentGroups {
|
||||
switch (mode) {
|
||||
case Mode.direct:
|
||||
return [];
|
||||
case Mode.global:
|
||||
return groups
|
||||
.where((element) => element.name == UsedProxy.GLOBAL.name)
|
||||
.where((element) => element.name == GroupName.GLOBAL.name)
|
||||
.toList();
|
||||
case Mode.rule:
|
||||
return groups
|
||||
.where((element) => element.name != UsedProxy.GLOBAL.name)
|
||||
.where((element) => element.name != GroupName.GLOBAL.name)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
String? getCurrentGroupNameWithGroups(
|
||||
List<Group> groups,
|
||||
String? groupName,
|
||||
Mode mode,
|
||||
) {
|
||||
switch (mode) {
|
||||
case Mode.direct:
|
||||
return null;
|
||||
case Mode.global:
|
||||
return UsedProxy.GLOBAL.name;
|
||||
case Mode.rule:
|
||||
return groupName ?? (groups.isNotEmpty ? groups.first.name : null);
|
||||
DelayMap get delayMap {
|
||||
return _delayMap;
|
||||
}
|
||||
|
||||
set delayMap(DelayMap value) {
|
||||
if (!const MapEquality<String, int?>().equals(_delayMap, value)) {
|
||||
_delayMap = value;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
String? getCurrentGroupName(String? groupName, Mode mode) {
|
||||
final currentGroups = getCurrentGroups(mode);
|
||||
return getCurrentGroupNameWithGroups(currentGroups, groupName, mode);
|
||||
}
|
||||
|
||||
Group getGroupWithName(String groupName) {
|
||||
return groups.firstWhere((e) => e.name == groupName);
|
||||
}
|
||||
|
||||
String? getCurrentProxyName(String? proxyName, Mode mode) {
|
||||
final currentGroups = getCurrentGroups(mode);
|
||||
switch (mode) {
|
||||
case Mode.direct:
|
||||
return UsedProxy.DIRECT.name;
|
||||
case Mode.global || Mode.rule:
|
||||
return proxyName ??
|
||||
(currentGroups.isNotEmpty ? currentGroups.first.now : null);
|
||||
setDelay(Delay delay) {
|
||||
if (_delayMap[delay.name] != delay.value) {
|
||||
_delayMap = Map.from(_delayMap)..[delay.name] = delay.value;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Group? getGroupWithName(String groupName) {
|
||||
final index =
|
||||
currentGroups.indexWhere((element) => element.name == groupName);
|
||||
return index != -1 ? currentGroups[index] : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ class AccessControl {
|
||||
@JsonSerializable()
|
||||
class Config extends ChangeNotifier {
|
||||
List<Profile> _profiles;
|
||||
bool _isCompatible;
|
||||
String? _currentProfileId;
|
||||
bool _autoLaunch;
|
||||
bool _silentLaunch;
|
||||
@@ -82,6 +83,7 @@ class Config extends ChangeNotifier {
|
||||
_autoRun = false,
|
||||
_themeMode = ThemeMode.system,
|
||||
_openLog = false,
|
||||
_isCompatible = false,
|
||||
_primaryColor = appConstant.defaultPrimaryColor.value,
|
||||
_proxiesSortType = ProxiesSortType.none,
|
||||
_isMinimizeOnExit = true,
|
||||
@@ -159,9 +161,18 @@ class Config extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
String? get currentProxyName => currentProfile?.proxyName;
|
||||
|
||||
String? get currentGroupName => currentProfile?.groupName;
|
||||
SelectedMap get currentSelectedMap {
|
||||
return currentProfile?.selectedMap ?? {};
|
||||
}
|
||||
|
||||
updateCurrentSelectedMap(String groupName, String proxyName) {
|
||||
if (currentProfile?.selectedMap[groupName] != proxyName) {
|
||||
currentProfile?.selectedMap = Map.from(currentProfile?.selectedMap ?? {})
|
||||
..[groupName] = proxyName;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@JsonKey(defaultValue: false)
|
||||
bool get autoLaunch {
|
||||
@@ -289,6 +300,18 @@ class Config extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
@JsonKey(defaultValue: false)
|
||||
bool get isCompatible {
|
||||
return _isCompatible;
|
||||
}
|
||||
|
||||
set isCompatible(bool value) {
|
||||
if (_isCompatible != value) {
|
||||
_isCompatible = value;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ class UpdateConfigParams with _$UpdateConfigParams {
|
||||
const factory UpdateConfigParams({
|
||||
@JsonKey(name: "profile-path") String? profilePath,
|
||||
required ClashConfig config,
|
||||
@JsonKey(name: "is-patch") bool? isPatch,
|
||||
@JsonKey(name: "is-patch") required bool isPatch,
|
||||
@JsonKey(name: "is-compatible") required bool isCompatible,
|
||||
}) = _UpdateConfigParams;
|
||||
|
||||
factory UpdateConfigParams.fromJson(Map<String, Object?> json) =>
|
||||
|
||||
@@ -55,7 +55,8 @@ Config _$ConfigFromJson(Map<String, dynamic> json) => Config()
|
||||
..isAccessControl = json['isAccessControl'] as bool? ?? false
|
||||
..accessControl =
|
||||
AccessControl.fromJson(json['accessControl'] as Map<String, dynamic>)
|
||||
..isAnimateToPage = json['isAnimateToPage'] as bool? ?? true;
|
||||
..isAnimateToPage = json['isAnimateToPage'] as bool? ?? true
|
||||
..isCompatible = json['isCompatible'] as bool? ?? false;
|
||||
|
||||
Map<String, dynamic> _$ConfigToJson(Config instance) => <String, dynamic>{
|
||||
'profiles': instance.profiles,
|
||||
@@ -72,6 +73,7 @@ Map<String, dynamic> _$ConfigToJson(Config instance) => <String, dynamic>{
|
||||
'isAccessControl': instance.isAccessControl,
|
||||
'accessControl': instance.accessControl,
|
||||
'isAnimateToPage': instance.isAnimateToPage,
|
||||
'isCompatible': instance.isCompatible,
|
||||
};
|
||||
|
||||
const _$ThemeModeEnumMap = {
|
||||
|
||||
@@ -24,7 +24,9 @@ mixin _$UpdateConfigParams {
|
||||
String? get profilePath => throw _privateConstructorUsedError;
|
||||
ClashConfig get config => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "is-patch")
|
||||
bool? get isPatch => throw _privateConstructorUsedError;
|
||||
bool get isPatch => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "is-compatible")
|
||||
bool get isCompatible => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
@@ -41,7 +43,8 @@ abstract class $UpdateConfigParamsCopyWith<$Res> {
|
||||
$Res call(
|
||||
{@JsonKey(name: "profile-path") String? profilePath,
|
||||
ClashConfig config,
|
||||
@JsonKey(name: "is-patch") bool? isPatch});
|
||||
@JsonKey(name: "is-patch") bool isPatch,
|
||||
@JsonKey(name: "is-compatible") bool isCompatible});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -59,7 +62,8 @@ class _$UpdateConfigParamsCopyWithImpl<$Res, $Val extends UpdateConfigParams>
|
||||
$Res call({
|
||||
Object? profilePath = freezed,
|
||||
Object? config = null,
|
||||
Object? isPatch = freezed,
|
||||
Object? isPatch = null,
|
||||
Object? isCompatible = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
profilePath: freezed == profilePath
|
||||
@@ -70,10 +74,14 @@ class _$UpdateConfigParamsCopyWithImpl<$Res, $Val extends UpdateConfigParams>
|
||||
? _value.config
|
||||
: config // ignore: cast_nullable_to_non_nullable
|
||||
as ClashConfig,
|
||||
isPatch: freezed == isPatch
|
||||
isPatch: null == isPatch
|
||||
? _value.isPatch
|
||||
: isPatch // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
as bool,
|
||||
isCompatible: null == isCompatible
|
||||
? _value.isCompatible
|
||||
: isCompatible // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@@ -89,7 +97,8 @@ abstract class _$$UpdateConfigParamsImplCopyWith<$Res>
|
||||
$Res call(
|
||||
{@JsonKey(name: "profile-path") String? profilePath,
|
||||
ClashConfig config,
|
||||
@JsonKey(name: "is-patch") bool? isPatch});
|
||||
@JsonKey(name: "is-patch") bool isPatch,
|
||||
@JsonKey(name: "is-compatible") bool isCompatible});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -105,7 +114,8 @@ class __$$UpdateConfigParamsImplCopyWithImpl<$Res>
|
||||
$Res call({
|
||||
Object? profilePath = freezed,
|
||||
Object? config = null,
|
||||
Object? isPatch = freezed,
|
||||
Object? isPatch = null,
|
||||
Object? isCompatible = null,
|
||||
}) {
|
||||
return _then(_$UpdateConfigParamsImpl(
|
||||
profilePath: freezed == profilePath
|
||||
@@ -116,10 +126,14 @@ class __$$UpdateConfigParamsImplCopyWithImpl<$Res>
|
||||
? _value.config
|
||||
: config // ignore: cast_nullable_to_non_nullable
|
||||
as ClashConfig,
|
||||
isPatch: freezed == isPatch
|
||||
isPatch: null == isPatch
|
||||
? _value.isPatch
|
||||
: isPatch // ignore: cast_nullable_to_non_nullable
|
||||
as bool?,
|
||||
as bool,
|
||||
isCompatible: null == isCompatible
|
||||
? _value.isCompatible
|
||||
: isCompatible // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -130,7 +144,8 @@ class _$UpdateConfigParamsImpl implements _UpdateConfigParams {
|
||||
const _$UpdateConfigParamsImpl(
|
||||
{@JsonKey(name: "profile-path") this.profilePath,
|
||||
required this.config,
|
||||
@JsonKey(name: "is-patch") this.isPatch});
|
||||
@JsonKey(name: "is-patch") required this.isPatch,
|
||||
@JsonKey(name: "is-compatible") required this.isCompatible});
|
||||
|
||||
factory _$UpdateConfigParamsImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$UpdateConfigParamsImplFromJson(json);
|
||||
@@ -142,11 +157,14 @@ class _$UpdateConfigParamsImpl implements _UpdateConfigParams {
|
||||
final ClashConfig config;
|
||||
@override
|
||||
@JsonKey(name: "is-patch")
|
||||
final bool? isPatch;
|
||||
final bool isPatch;
|
||||
@override
|
||||
@JsonKey(name: "is-compatible")
|
||||
final bool isCompatible;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UpdateConfigParams(profilePath: $profilePath, config: $config, isPatch: $isPatch)';
|
||||
return 'UpdateConfigParams(profilePath: $profilePath, config: $config, isPatch: $isPatch, isCompatible: $isCompatible)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -157,12 +175,15 @@ class _$UpdateConfigParamsImpl implements _UpdateConfigParams {
|
||||
(identical(other.profilePath, profilePath) ||
|
||||
other.profilePath == profilePath) &&
|
||||
(identical(other.config, config) || other.config == config) &&
|
||||
(identical(other.isPatch, isPatch) || other.isPatch == isPatch));
|
||||
(identical(other.isPatch, isPatch) || other.isPatch == isPatch) &&
|
||||
(identical(other.isCompatible, isCompatible) ||
|
||||
other.isCompatible == isCompatible));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, profilePath, config, isPatch);
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, profilePath, config, isPatch, isCompatible);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@@ -183,7 +204,8 @@ abstract class _UpdateConfigParams implements UpdateConfigParams {
|
||||
const factory _UpdateConfigParams(
|
||||
{@JsonKey(name: "profile-path") final String? profilePath,
|
||||
required final ClashConfig config,
|
||||
@JsonKey(name: "is-patch") final bool? isPatch}) =
|
||||
@JsonKey(name: "is-patch") required final bool isPatch,
|
||||
@JsonKey(name: "is-compatible") required final bool isCompatible}) =
|
||||
_$UpdateConfigParamsImpl;
|
||||
|
||||
factory _UpdateConfigParams.fromJson(Map<String, dynamic> json) =
|
||||
@@ -196,7 +218,10 @@ abstract class _UpdateConfigParams implements UpdateConfigParams {
|
||||
ClashConfig get config;
|
||||
@override
|
||||
@JsonKey(name: "is-patch")
|
||||
bool? get isPatch;
|
||||
bool get isPatch;
|
||||
@override
|
||||
@JsonKey(name: "is-compatible")
|
||||
bool get isCompatible;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$UpdateConfigParamsImplCopyWith<_$UpdateConfigParamsImpl> get copyWith =>
|
||||
|
||||
@@ -11,7 +11,8 @@ _$UpdateConfigParamsImpl _$$UpdateConfigParamsImplFromJson(
|
||||
_$UpdateConfigParamsImpl(
|
||||
profilePath: json['profile-path'] as String?,
|
||||
config: ClashConfig.fromJson(json['config'] as Map<String, dynamic>),
|
||||
isPatch: json['is-patch'] as bool?,
|
||||
isPatch: json['is-patch'] as bool,
|
||||
isCompatible: json['is-compatible'] as bool,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$UpdateConfigParamsImplToJson(
|
||||
@@ -20,6 +21,7 @@ Map<String, dynamic> _$$UpdateConfigParamsImplToJson(
|
||||
'profile-path': instance.profilePath,
|
||||
'config': instance.config,
|
||||
'is-patch': instance.isPatch,
|
||||
'is-compatible': instance.isCompatible,
|
||||
};
|
||||
|
||||
_$ChangeProxyParamsImpl _$$ChangeProxyParamsImplFromJson(
|
||||
|
||||
@@ -27,11 +27,13 @@ Profile _$ProfileFromJson(Map<String, dynamic> json) => Profile(
|
||||
userInfo: json['userInfo'] == null
|
||||
? null
|
||||
: UserInfo.fromJson(json['userInfo'] as Map<String, dynamic>),
|
||||
groupName: json['groupName'] as String?,
|
||||
proxyName: json['proxyName'] as String?,
|
||||
lastUpdateDate: json['lastUpdateDate'] == null
|
||||
? null
|
||||
: DateTime.parse(json['lastUpdateDate'] as String),
|
||||
selectedMap: (json['selectedMap'] as Map<String, dynamic>?)?.map(
|
||||
(k, e) => MapEntry(k, e as String),
|
||||
),
|
||||
autoUpdateDuration: json['autoUpdateDuration'] == null
|
||||
? null
|
||||
: Duration(microseconds: (json['autoUpdateDuration'] as num).toInt()),
|
||||
@@ -41,11 +43,11 @@ Profile _$ProfileFromJson(Map<String, dynamic> json) => Profile(
|
||||
Map<String, dynamic> _$ProfileToJson(Profile instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'label': instance.label,
|
||||
'groupName': instance.groupName,
|
||||
'proxyName': instance.proxyName,
|
||||
'url': instance.url,
|
||||
'lastUpdateDate': instance.lastUpdateDate?.toIso8601String(),
|
||||
'autoUpdateDuration': instance.autoUpdateDuration.inMicroseconds,
|
||||
'userInfo': instance.userInfo,
|
||||
'autoUpdate': instance.autoUpdate,
|
||||
'selectedMap': instance.selectedMap,
|
||||
};
|
||||
|
||||
@@ -219,6 +219,7 @@ Proxy _$ProxyFromJson(Map<String, dynamic> json) {
|
||||
mixin _$Proxy {
|
||||
String get name => throw _privateConstructorUsedError;
|
||||
String get type => throw _privateConstructorUsedError;
|
||||
String? get now => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
@@ -230,7 +231,7 @@ abstract class $ProxyCopyWith<$Res> {
|
||||
factory $ProxyCopyWith(Proxy value, $Res Function(Proxy) then) =
|
||||
_$ProxyCopyWithImpl<$Res, Proxy>;
|
||||
@useResult
|
||||
$Res call({String name, String type});
|
||||
$Res call({String name, String type, String? now});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -248,6 +249,7 @@ class _$ProxyCopyWithImpl<$Res, $Val extends Proxy>
|
||||
$Res call({
|
||||
Object? name = null,
|
||||
Object? type = null,
|
||||
Object? now = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
name: null == name
|
||||
@@ -258,6 +260,10 @@ class _$ProxyCopyWithImpl<$Res, $Val extends Proxy>
|
||||
? _value.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
now: freezed == now
|
||||
? _value.now
|
||||
: now // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@@ -269,7 +275,7 @@ abstract class _$$ProxyImplCopyWith<$Res> implements $ProxyCopyWith<$Res> {
|
||||
__$$ProxyImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String name, String type});
|
||||
$Res call({String name, String type, String? now});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -285,6 +291,7 @@ class __$$ProxyImplCopyWithImpl<$Res>
|
||||
$Res call({
|
||||
Object? name = null,
|
||||
Object? type = null,
|
||||
Object? now = freezed,
|
||||
}) {
|
||||
return _then(_$ProxyImpl(
|
||||
name: null == name
|
||||
@@ -295,6 +302,10 @@ class __$$ProxyImplCopyWithImpl<$Res>
|
||||
? _value.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
now: freezed == now
|
||||
? _value.now
|
||||
: now // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -302,21 +313,21 @@ class __$$ProxyImplCopyWithImpl<$Res>
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$ProxyImpl implements _Proxy {
|
||||
const _$ProxyImpl({this.name = "", this.type = ""});
|
||||
const _$ProxyImpl({required this.name, required this.type, this.now});
|
||||
|
||||
factory _$ProxyImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$ProxyImplFromJson(json);
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final String name;
|
||||
@override
|
||||
@JsonKey()
|
||||
final String type;
|
||||
@override
|
||||
final String? now;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Proxy(name: $name, type: $type)';
|
||||
return 'Proxy(name: $name, type: $type, now: $now)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -325,12 +336,13 @@ class _$ProxyImpl implements _Proxy {
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ProxyImpl &&
|
||||
(identical(other.name, name) || other.name == name) &&
|
||||
(identical(other.type, type) || other.type == type));
|
||||
(identical(other.type, type) || other.type == type) &&
|
||||
(identical(other.now, now) || other.now == now));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, name, type);
|
||||
int get hashCode => Object.hash(runtimeType, name, type, now);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@@ -347,7 +359,10 @@ class _$ProxyImpl implements _Proxy {
|
||||
}
|
||||
|
||||
abstract class _Proxy implements Proxy {
|
||||
const factory _Proxy({final String name, final String type}) = _$ProxyImpl;
|
||||
const factory _Proxy(
|
||||
{required final String name,
|
||||
required final String type,
|
||||
final String? now}) = _$ProxyImpl;
|
||||
|
||||
factory _Proxy.fromJson(Map<String, dynamic> json) = _$ProxyImpl.fromJson;
|
||||
|
||||
@@ -356,6 +371,8 @@ abstract class _Proxy implements Proxy {
|
||||
@override
|
||||
String get type;
|
||||
@override
|
||||
String? get now;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$ProxyImplCopyWith<_$ProxyImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
@@ -31,12 +31,14 @@ const _$GroupTypeEnumMap = {
|
||||
};
|
||||
|
||||
_$ProxyImpl _$$ProxyImplFromJson(Map<String, dynamic> json) => _$ProxyImpl(
|
||||
name: json['name'] as String? ?? "",
|
||||
type: json['type'] as String? ?? "",
|
||||
name: json['name'] as String,
|
||||
type: json['type'] as String,
|
||||
now: json['now'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ProxyImplToJson(_$ProxyImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'name': instance.name,
|
||||
'type': instance.type,
|
||||
'now': instance.now,
|
||||
};
|
||||
|
||||
@@ -349,7 +349,6 @@ abstract class _UpdateCurrentDelaySelectorState
|
||||
mixin _$NetworkDetectionSelectorState {
|
||||
String? get currentProxyName => throw _privateConstructorUsedError;
|
||||
int? get delay => throw _privateConstructorUsedError;
|
||||
bool get isInit => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$NetworkDetectionSelectorStateCopyWith<NetworkDetectionSelectorState>
|
||||
@@ -364,7 +363,7 @@ abstract class $NetworkDetectionSelectorStateCopyWith<$Res> {
|
||||
_$NetworkDetectionSelectorStateCopyWithImpl<$Res,
|
||||
NetworkDetectionSelectorState>;
|
||||
@useResult
|
||||
$Res call({String? currentProxyName, int? delay, bool isInit});
|
||||
$Res call({String? currentProxyName, int? delay});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -383,7 +382,6 @@ class _$NetworkDetectionSelectorStateCopyWithImpl<$Res,
|
||||
$Res call({
|
||||
Object? currentProxyName = freezed,
|
||||
Object? delay = freezed,
|
||||
Object? isInit = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
currentProxyName: freezed == currentProxyName
|
||||
@@ -394,10 +392,6 @@ class _$NetworkDetectionSelectorStateCopyWithImpl<$Res,
|
||||
? _value.delay
|
||||
: delay // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
isInit: null == isInit
|
||||
? _value.isInit
|
||||
: isInit // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@@ -411,7 +405,7 @@ abstract class _$$NetworkDetectionSelectorStateImplCopyWith<$Res>
|
||||
__$$NetworkDetectionSelectorStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String? currentProxyName, int? delay, bool isInit});
|
||||
$Res call({String? currentProxyName, int? delay});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -429,7 +423,6 @@ class __$$NetworkDetectionSelectorStateImplCopyWithImpl<$Res>
|
||||
$Res call({
|
||||
Object? currentProxyName = freezed,
|
||||
Object? delay = freezed,
|
||||
Object? isInit = null,
|
||||
}) {
|
||||
return _then(_$NetworkDetectionSelectorStateImpl(
|
||||
currentProxyName: freezed == currentProxyName
|
||||
@@ -440,10 +433,6 @@ class __$$NetworkDetectionSelectorStateImplCopyWithImpl<$Res>
|
||||
? _value.delay
|
||||
: delay // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
isInit: null == isInit
|
||||
? _value.isInit
|
||||
: isInit // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -453,20 +442,16 @@ class __$$NetworkDetectionSelectorStateImplCopyWithImpl<$Res>
|
||||
class _$NetworkDetectionSelectorStateImpl
|
||||
implements _NetworkDetectionSelectorState {
|
||||
const _$NetworkDetectionSelectorStateImpl(
|
||||
{required this.currentProxyName,
|
||||
required this.delay,
|
||||
required this.isInit});
|
||||
{required this.currentProxyName, required this.delay});
|
||||
|
||||
@override
|
||||
final String? currentProxyName;
|
||||
@override
|
||||
final int? delay;
|
||||
@override
|
||||
final bool isInit;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NetworkDetectionSelectorState(currentProxyName: $currentProxyName, delay: $delay, isInit: $isInit)';
|
||||
return 'NetworkDetectionSelectorState(currentProxyName: $currentProxyName, delay: $delay)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -476,12 +461,11 @@ class _$NetworkDetectionSelectorStateImpl
|
||||
other is _$NetworkDetectionSelectorStateImpl &&
|
||||
(identical(other.currentProxyName, currentProxyName) ||
|
||||
other.currentProxyName == currentProxyName) &&
|
||||
(identical(other.delay, delay) || other.delay == delay) &&
|
||||
(identical(other.isInit, isInit) || other.isInit == isInit));
|
||||
(identical(other.delay, delay) || other.delay == delay));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, currentProxyName, delay, isInit);
|
||||
int get hashCode => Object.hash(runtimeType, currentProxyName, delay);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@@ -496,16 +480,13 @@ abstract class _NetworkDetectionSelectorState
|
||||
implements NetworkDetectionSelectorState {
|
||||
const factory _NetworkDetectionSelectorState(
|
||||
{required final String? currentProxyName,
|
||||
required final int? delay,
|
||||
required final bool isInit}) = _$NetworkDetectionSelectorStateImpl;
|
||||
required final int? delay}) = _$NetworkDetectionSelectorStateImpl;
|
||||
|
||||
@override
|
||||
String? get currentProxyName;
|
||||
@override
|
||||
int? get delay;
|
||||
@override
|
||||
bool get isInit;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$NetworkDetectionSelectorStateImplCopyWith<
|
||||
_$NetworkDetectionSelectorStateImpl>
|
||||
@@ -1741,158 +1722,8 @@ abstract class _HomeNavigationSelectorState
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ProxiesSelectorState {
|
||||
int get currentIndex => throw _privateConstructorUsedError;
|
||||
List<String> get groupNames => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$ProxiesSelectorStateCopyWith<ProxiesSelectorState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ProxiesSelectorStateCopyWith<$Res> {
|
||||
factory $ProxiesSelectorStateCopyWith(ProxiesSelectorState value,
|
||||
$Res Function(ProxiesSelectorState) then) =
|
||||
_$ProxiesSelectorStateCopyWithImpl<$Res, ProxiesSelectorState>;
|
||||
@useResult
|
||||
$Res call({int currentIndex, List<String> groupNames});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ProxiesSelectorStateCopyWithImpl<$Res,
|
||||
$Val extends ProxiesSelectorState>
|
||||
implements $ProxiesSelectorStateCopyWith<$Res> {
|
||||
_$ProxiesSelectorStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? currentIndex = null,
|
||||
Object? groupNames = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
currentIndex: null == currentIndex
|
||||
? _value.currentIndex
|
||||
: currentIndex // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
groupNames: null == groupNames
|
||||
? _value.groupNames
|
||||
: groupNames // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ProxiesSelectorStateImplCopyWith<$Res>
|
||||
implements $ProxiesSelectorStateCopyWith<$Res> {
|
||||
factory _$$ProxiesSelectorStateImplCopyWith(_$ProxiesSelectorStateImpl value,
|
||||
$Res Function(_$ProxiesSelectorStateImpl) then) =
|
||||
__$$ProxiesSelectorStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({int currentIndex, List<String> groupNames});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ProxiesSelectorStateImplCopyWithImpl<$Res>
|
||||
extends _$ProxiesSelectorStateCopyWithImpl<$Res, _$ProxiesSelectorStateImpl>
|
||||
implements _$$ProxiesSelectorStateImplCopyWith<$Res> {
|
||||
__$$ProxiesSelectorStateImplCopyWithImpl(_$ProxiesSelectorStateImpl _value,
|
||||
$Res Function(_$ProxiesSelectorStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? currentIndex = null,
|
||||
Object? groupNames = null,
|
||||
}) {
|
||||
return _then(_$ProxiesSelectorStateImpl(
|
||||
currentIndex: null == currentIndex
|
||||
? _value.currentIndex
|
||||
: currentIndex // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
groupNames: null == groupNames
|
||||
? _value._groupNames
|
||||
: groupNames // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ProxiesSelectorStateImpl implements _ProxiesSelectorState {
|
||||
const _$ProxiesSelectorStateImpl(
|
||||
{required this.currentIndex, required final List<String> groupNames})
|
||||
: _groupNames = groupNames;
|
||||
|
||||
@override
|
||||
final int currentIndex;
|
||||
final List<String> _groupNames;
|
||||
@override
|
||||
List<String> get groupNames {
|
||||
if (_groupNames is EqualUnmodifiableListView) return _groupNames;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_groupNames);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxiesSelectorState(currentIndex: $currentIndex, groupNames: $groupNames)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ProxiesSelectorStateImpl &&
|
||||
(identical(other.currentIndex, currentIndex) ||
|
||||
other.currentIndex == currentIndex) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._groupNames, _groupNames));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, currentIndex,
|
||||
const DeepCollectionEquality().hash(_groupNames));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ProxiesSelectorStateImplCopyWith<_$ProxiesSelectorStateImpl>
|
||||
get copyWith =>
|
||||
__$$ProxiesSelectorStateImplCopyWithImpl<_$ProxiesSelectorStateImpl>(
|
||||
this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _ProxiesSelectorState implements ProxiesSelectorState {
|
||||
const factory _ProxiesSelectorState(
|
||||
{required final int currentIndex,
|
||||
required final List<String> groupNames}) = _$ProxiesSelectorStateImpl;
|
||||
|
||||
@override
|
||||
int get currentIndex;
|
||||
@override
|
||||
List<String> get groupNames;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$ProxiesSelectorStateImplCopyWith<_$ProxiesSelectorStateImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ProxiesCardSelectorState {
|
||||
String? get currentGroupName => throw _privateConstructorUsedError;
|
||||
String? get currentProxyName => throw _privateConstructorUsedError;
|
||||
bool get isSelected => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@@ -1906,8 +1737,7 @@ abstract class $ProxiesCardSelectorStateCopyWith<$Res> {
|
||||
$Res Function(ProxiesCardSelectorState) then) =
|
||||
_$ProxiesCardSelectorStateCopyWithImpl<$Res, ProxiesCardSelectorState>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{String? currentGroupName, String? currentProxyName, bool isSelected});
|
||||
$Res call({bool isSelected});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -1924,19 +1754,9 @@ class _$ProxiesCardSelectorStateCopyWithImpl<$Res,
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? currentGroupName = freezed,
|
||||
Object? currentProxyName = freezed,
|
||||
Object? isSelected = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
currentGroupName: freezed == currentGroupName
|
||||
? _value.currentGroupName
|
||||
: currentGroupName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
currentProxyName: freezed == currentProxyName
|
||||
? _value.currentProxyName
|
||||
: currentProxyName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
isSelected: null == isSelected
|
||||
? _value.isSelected
|
||||
: isSelected // ignore: cast_nullable_to_non_nullable
|
||||
@@ -1954,8 +1774,7 @@ abstract class _$$ProxiesCardSelectorStateImplCopyWith<$Res>
|
||||
__$$ProxiesCardSelectorStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{String? currentGroupName, String? currentProxyName, bool isSelected});
|
||||
$Res call({bool isSelected});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -1971,19 +1790,9 @@ class __$$ProxiesCardSelectorStateImplCopyWithImpl<$Res>
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? currentGroupName = freezed,
|
||||
Object? currentProxyName = freezed,
|
||||
Object? isSelected = null,
|
||||
}) {
|
||||
return _then(_$ProxiesCardSelectorStateImpl(
|
||||
currentGroupName: freezed == currentGroupName
|
||||
? _value.currentGroupName
|
||||
: currentGroupName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
currentProxyName: freezed == currentProxyName
|
||||
? _value.currentProxyName
|
||||
: currentProxyName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
isSelected: null == isSelected
|
||||
? _value.isSelected
|
||||
: isSelected // ignore: cast_nullable_to_non_nullable
|
||||
@@ -1995,21 +1804,14 @@ class __$$ProxiesCardSelectorStateImplCopyWithImpl<$Res>
|
||||
/// @nodoc
|
||||
|
||||
class _$ProxiesCardSelectorStateImpl implements _ProxiesCardSelectorState {
|
||||
const _$ProxiesCardSelectorStateImpl(
|
||||
{required this.currentGroupName,
|
||||
required this.currentProxyName,
|
||||
required this.isSelected});
|
||||
const _$ProxiesCardSelectorStateImpl({required this.isSelected});
|
||||
|
||||
@override
|
||||
final String? currentGroupName;
|
||||
@override
|
||||
final String? currentProxyName;
|
||||
@override
|
||||
final bool isSelected;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxiesCardSelectorState(currentGroupName: $currentGroupName, currentProxyName: $currentProxyName, isSelected: $isSelected)';
|
||||
return 'ProxiesCardSelectorState(isSelected: $isSelected)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -2017,17 +1819,12 @@ class _$ProxiesCardSelectorStateImpl implements _ProxiesCardSelectorState {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ProxiesCardSelectorStateImpl &&
|
||||
(identical(other.currentGroupName, currentGroupName) ||
|
||||
other.currentGroupName == currentGroupName) &&
|
||||
(identical(other.currentProxyName, currentProxyName) ||
|
||||
other.currentProxyName == currentProxyName) &&
|
||||
(identical(other.isSelected, isSelected) ||
|
||||
other.isSelected == isSelected));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, currentGroupName, currentProxyName, isSelected);
|
||||
int get hashCode => Object.hash(runtimeType, isSelected);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@@ -2038,15 +1835,9 @@ class _$ProxiesCardSelectorStateImpl implements _ProxiesCardSelectorState {
|
||||
}
|
||||
|
||||
abstract class _ProxiesCardSelectorState implements ProxiesCardSelectorState {
|
||||
const factory _ProxiesCardSelectorState(
|
||||
{required final String? currentGroupName,
|
||||
required final String? currentProxyName,
|
||||
required final bool isSelected}) = _$ProxiesCardSelectorStateImpl;
|
||||
const factory _ProxiesCardSelectorState({required final bool isSelected}) =
|
||||
_$ProxiesCardSelectorStateImpl;
|
||||
|
||||
@override
|
||||
String? get currentGroupName;
|
||||
@override
|
||||
String? get currentProxyName;
|
||||
@override
|
||||
bool get isSelected;
|
||||
@override
|
||||
@@ -2055,6 +1846,135 @@ abstract class _ProxiesCardSelectorState implements ProxiesCardSelectorState {
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ProxiesSelectorState {
|
||||
List<String> get groupNames => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$ProxiesSelectorStateCopyWith<ProxiesSelectorState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ProxiesSelectorStateCopyWith<$Res> {
|
||||
factory $ProxiesSelectorStateCopyWith(ProxiesSelectorState value,
|
||||
$Res Function(ProxiesSelectorState) then) =
|
||||
_$ProxiesSelectorStateCopyWithImpl<$Res, ProxiesSelectorState>;
|
||||
@useResult
|
||||
$Res call({List<String> groupNames});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ProxiesSelectorStateCopyWithImpl<$Res,
|
||||
$Val extends ProxiesSelectorState>
|
||||
implements $ProxiesSelectorStateCopyWith<$Res> {
|
||||
_$ProxiesSelectorStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? groupNames = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
groupNames: null == groupNames
|
||||
? _value.groupNames
|
||||
: groupNames // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ProxiesSelectorStateImplCopyWith<$Res>
|
||||
implements $ProxiesSelectorStateCopyWith<$Res> {
|
||||
factory _$$ProxiesSelectorStateImplCopyWith(_$ProxiesSelectorStateImpl value,
|
||||
$Res Function(_$ProxiesSelectorStateImpl) then) =
|
||||
__$$ProxiesSelectorStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({List<String> groupNames});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ProxiesSelectorStateImplCopyWithImpl<$Res>
|
||||
extends _$ProxiesSelectorStateCopyWithImpl<$Res, _$ProxiesSelectorStateImpl>
|
||||
implements _$$ProxiesSelectorStateImplCopyWith<$Res> {
|
||||
__$$ProxiesSelectorStateImplCopyWithImpl(_$ProxiesSelectorStateImpl _value,
|
||||
$Res Function(_$ProxiesSelectorStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? groupNames = null,
|
||||
}) {
|
||||
return _then(_$ProxiesSelectorStateImpl(
|
||||
groupNames: null == groupNames
|
||||
? _value._groupNames
|
||||
: groupNames // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ProxiesSelectorStateImpl implements _ProxiesSelectorState {
|
||||
const _$ProxiesSelectorStateImpl({required final List<String> groupNames})
|
||||
: _groupNames = groupNames;
|
||||
|
||||
final List<String> _groupNames;
|
||||
@override
|
||||
List<String> get groupNames {
|
||||
if (_groupNames is EqualUnmodifiableListView) return _groupNames;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_groupNames);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxiesSelectorState(groupNames: $groupNames)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ProxiesSelectorStateImpl &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._groupNames, _groupNames));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, const DeepCollectionEquality().hash(_groupNames));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ProxiesSelectorStateImplCopyWith<_$ProxiesSelectorStateImpl>
|
||||
get copyWith =>
|
||||
__$$ProxiesSelectorStateImplCopyWithImpl<_$ProxiesSelectorStateImpl>(
|
||||
this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _ProxiesSelectorState implements ProxiesSelectorState {
|
||||
const factory _ProxiesSelectorState(
|
||||
{required final List<String> groupNames}) = _$ProxiesSelectorStateImpl;
|
||||
|
||||
@override
|
||||
List<String> get groupNames;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$ProxiesSelectorStateImplCopyWith<_$ProxiesSelectorStateImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ProxiesTabViewSelectorState {
|
||||
ProxiesSortType get proxiesSortType => throw _privateConstructorUsedError;
|
||||
|
||||
@@ -12,6 +12,8 @@ import 'common.dart';
|
||||
|
||||
part 'generated/profile.g.dart';
|
||||
|
||||
typedef SelectedMap = Map<String, String>;
|
||||
|
||||
@JsonSerializable()
|
||||
class UserInfo {
|
||||
int upload;
|
||||
@@ -62,27 +64,28 @@ class UserInfo {
|
||||
class Profile {
|
||||
String id;
|
||||
String? label;
|
||||
String? groupName;
|
||||
String? proxyName;
|
||||
String? url;
|
||||
DateTime? lastUpdateDate;
|
||||
Duration autoUpdateDuration;
|
||||
UserInfo? userInfo;
|
||||
bool autoUpdate;
|
||||
SelectedMap selectedMap;
|
||||
|
||||
Profile({
|
||||
String? id,
|
||||
this.label,
|
||||
this.url,
|
||||
this.userInfo,
|
||||
this.groupName,
|
||||
this.proxyName,
|
||||
this.lastUpdateDate,
|
||||
SelectedMap? selectedMap,
|
||||
Duration? autoUpdateDuration,
|
||||
this.autoUpdate = true,
|
||||
}) : id = id ?? DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
autoUpdateDuration =
|
||||
autoUpdateDuration ?? appConstant.defaultUpdateDuration;
|
||||
autoUpdateDuration ?? appConstant.defaultUpdateDuration,
|
||||
selectedMap = selectedMap ?? {};
|
||||
|
||||
ProfileType get type => url == null ? ProfileType.file : ProfileType.url;
|
||||
|
||||
@@ -158,7 +161,6 @@ class Profile {
|
||||
runtimeType == other.runtimeType &&
|
||||
id == other.id &&
|
||||
label == other.label &&
|
||||
groupName == other.groupName &&
|
||||
proxyName == other.proxyName &&
|
||||
url == other.url &&
|
||||
lastUpdateDate == other.lastUpdateDate &&
|
||||
@@ -170,7 +172,6 @@ class Profile {
|
||||
int get hashCode =>
|
||||
id.hashCode ^
|
||||
label.hashCode ^
|
||||
groupName.hashCode ^
|
||||
proxyName.hashCode ^
|
||||
url.hashCode ^
|
||||
lastUpdateDate.hashCode ^
|
||||
@@ -180,7 +181,7 @@ class Profile {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Profile{id: $id, label: $label, groupName: $groupName, proxyName: $proxyName, url: $url, lastUpdateDate: $lastUpdateDate, autoUpdateDuration: $autoUpdateDuration, userInfo: $userInfo, autoUpdate: $autoUpdate}';
|
||||
return 'Profile{id: $id, label: $label, proxyName: $proxyName, url: $url, lastUpdateDate: $lastUpdateDate, autoUpdateDuration: $autoUpdateDuration, userInfo: $userInfo, autoUpdate: $autoUpdate}';
|
||||
}
|
||||
|
||||
Profile copyWith({
|
||||
@@ -192,14 +193,15 @@ class Profile {
|
||||
DateTime? lastUpdateDate,
|
||||
Duration? autoUpdateDuration,
|
||||
bool? autoUpdate,
|
||||
SelectedMap? selectedMap,
|
||||
}) {
|
||||
return Profile(
|
||||
id: id,
|
||||
label: label ?? this.label,
|
||||
url: url ?? this.url,
|
||||
groupName: groupName ?? this.groupName,
|
||||
proxyName: proxyName ?? this.proxyName,
|
||||
userInfo: userInfo ?? this.userInfo,
|
||||
selectedMap: selectedMap ?? this.selectedMap,
|
||||
lastUpdateDate: lastUpdateDate ?? this.lastUpdateDate,
|
||||
autoUpdateDuration: autoUpdateDuration ?? this.autoUpdateDuration,
|
||||
autoUpdate: autoUpdate ?? this.autoUpdate,
|
||||
|
||||
@@ -6,7 +6,7 @@ part 'generated/proxy.g.dart';
|
||||
|
||||
part 'generated/proxy.freezed.dart';
|
||||
|
||||
typedef DelayMap = Map<String, int?>;
|
||||
typedef ProxyMap = Map<String, Proxy>;
|
||||
|
||||
@freezed
|
||||
class Group with _$Group {
|
||||
@@ -23,8 +23,9 @@ class Group with _$Group {
|
||||
@freezed
|
||||
class Proxy with _$Proxy {
|
||||
const factory Proxy({
|
||||
@Default("") String name,
|
||||
@Default("") String type,
|
||||
required String name,
|
||||
required String type,
|
||||
String? now,
|
||||
}) = _Proxy;
|
||||
|
||||
factory Proxy.fromJson(Map<String, Object?> json) => _$ProxyFromJson(json);
|
||||
|
||||
@@ -32,7 +32,6 @@ class NetworkDetectionSelectorState with _$NetworkDetectionSelectorState {
|
||||
const factory NetworkDetectionSelectorState({
|
||||
required String? currentProxyName,
|
||||
required int? delay,
|
||||
required bool isInit,
|
||||
}) = _NetworkDetectionSelectorState;
|
||||
}
|
||||
|
||||
@@ -104,20 +103,17 @@ class HomeNavigationSelectorState with _$HomeNavigationSelectorState{
|
||||
}
|
||||
|
||||
@freezed
|
||||
class ProxiesSelectorState with _$ProxiesSelectorState{
|
||||
const factory ProxiesSelectorState({
|
||||
required int currentIndex,
|
||||
required List<String> groupNames,
|
||||
}) = _ProxiesSelectorState;
|
||||
class ProxiesCardSelectorState with _$ProxiesCardSelectorState{
|
||||
const factory ProxiesCardSelectorState({
|
||||
required bool isSelected,
|
||||
}) = _ProxiesCardSelectorState;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class ProxiesCardSelectorState with _$ProxiesCardSelectorState{
|
||||
const factory ProxiesCardSelectorState({
|
||||
required String? currentGroupName,
|
||||
required String? currentProxyName,
|
||||
required bool isSelected,
|
||||
}) = _ProxiesCardSelectorState;
|
||||
class ProxiesSelectorState with _$ProxiesSelectorState{
|
||||
const factory ProxiesSelectorState({
|
||||
required List<String> groupNames,
|
||||
}) = _ProxiesSelectorState;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
||||
105
lib/state.dart
105
lib/state.dart
@@ -14,8 +14,9 @@ import 'common/common.dart';
|
||||
|
||||
class GlobalState {
|
||||
Timer? timer;
|
||||
Function? updateCurrentDelayDebounce;
|
||||
Function? updateSortNumDebounce;
|
||||
Timer? groupsUpdateTimer;
|
||||
Function? updateCurrentDelayDebounce;
|
||||
PageController? pageController;
|
||||
final navigatorKey = GlobalKey<NavigatorState>();
|
||||
final Map<int, String?> packageNameMap = {};
|
||||
@@ -23,7 +24,6 @@ class GlobalState {
|
||||
List<Function> updateFunctionLists = [];
|
||||
List<NavigationItem> currentNavigationItems = [];
|
||||
bool updatePackagesLock = false;
|
||||
bool healthcheckLock = false;
|
||||
|
||||
startListenUpdate() {
|
||||
if (timer != null && timer!.isActive == true) return;
|
||||
@@ -50,6 +50,7 @@ class GlobalState {
|
||||
profilePath: profilePath,
|
||||
config: clashConfig,
|
||||
isPatch: isPatch,
|
||||
isCompatible: config.isCompatible,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -75,19 +76,6 @@ class GlobalState {
|
||||
stopListenUpdate();
|
||||
}
|
||||
|
||||
void updateCurrentDelay(
|
||||
String? proxyName,
|
||||
) {
|
||||
updateCurrentDelayDebounce ??= debounce<Function(String?)>((proxyName) {
|
||||
if (proxyName != null) {
|
||||
clashCore.delay(
|
||||
proxyName,
|
||||
);
|
||||
}
|
||||
});
|
||||
updateCurrentDelayDebounce!([proxyName]);
|
||||
}
|
||||
|
||||
applyProfile({
|
||||
required AppState appState,
|
||||
required Config config,
|
||||
@@ -133,29 +121,20 @@ class GlobalState {
|
||||
required Config config,
|
||||
required ClashConfig clashConfig,
|
||||
}) {
|
||||
final currentGroupName =
|
||||
appState.getCurrentGroupName(config.currentGroupName, clashConfig.mode);
|
||||
final currentProxyName =
|
||||
appState.getCurrentProxyName(config.currentProxyName, clashConfig.mode);
|
||||
if (config.profiles.isEmpty || currentProxyName == null) {
|
||||
stopSystemProxy();
|
||||
return;
|
||||
}
|
||||
if (currentGroupName == null) return;
|
||||
final groupIndex = appState.groups.indexWhere(
|
||||
(element) => element.name == currentGroupName,
|
||||
);
|
||||
if (groupIndex == -1) return;
|
||||
final proxyIndex = appState.groups[groupIndex].all.indexWhere(
|
||||
(element) => element.name == currentProxyName,
|
||||
);
|
||||
if (proxyIndex == -1) return;
|
||||
clashCore.changeProxy(
|
||||
ChangeProxyParams(
|
||||
groupName: currentGroupName,
|
||||
proxyName: currentProxyName,
|
||||
),
|
||||
);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (config.profiles.isEmpty) {
|
||||
stopSystemProxy();
|
||||
return;
|
||||
}
|
||||
config.currentSelectedMap.forEach((key, value) {
|
||||
clashCore.changeProxy(
|
||||
ChangeProxyParams(
|
||||
groupName: key,
|
||||
proxyName: value,
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
updatePackages(AppState appState) async {
|
||||
@@ -171,11 +150,11 @@ class GlobalState {
|
||||
required Config config,
|
||||
required ClashConfig clashConfig,
|
||||
}) {
|
||||
final hasGroups = appState.getCurrentGroups(clashConfig.mode).isNotEmpty;
|
||||
final group = appState.currentGroups;
|
||||
final hasProfile = config.profiles.isNotEmpty;
|
||||
appState.navigationItems = navigation.getItems(
|
||||
openLogs: config.openLogs,
|
||||
hasProxies: hasGroups && hasProfile,
|
||||
hasProxies: group.isNotEmpty && hasProfile,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -259,6 +238,52 @@ class GlobalState {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
showSnackBar(
|
||||
BuildContext context, {
|
||||
required String message,
|
||||
SnackBarAction? action,
|
||||
}) {
|
||||
final width = context.width;
|
||||
EdgeInsets margin;
|
||||
if (width < 600) {
|
||||
margin = const EdgeInsets.only(
|
||||
bottom: 96,
|
||||
right: 16,
|
||||
left: 16,
|
||||
);
|
||||
} else {
|
||||
margin = EdgeInsets.only(
|
||||
bottom: 16,
|
||||
left: 16,
|
||||
right: width - 316,
|
||||
);
|
||||
}
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
action: action,
|
||||
content: Text(message),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
duration: const Duration(milliseconds: 1500),
|
||||
margin: margin,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void updateCurrentDelay(
|
||||
String? proxyName,
|
||||
) {
|
||||
updateCurrentDelayDebounce ??= debounce<Function(String?)>((proxyName) {
|
||||
if (proxyName != null) {
|
||||
debugPrint("[delay]=====> $proxyName");
|
||||
clashCore.delay(
|
||||
proxyName,
|
||||
);
|
||||
}
|
||||
});
|
||||
updateCurrentDelayDebounce!([proxyName]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final globalState = GlobalState();
|
||||
|
||||
@@ -23,14 +23,13 @@ class AppStateContainer extends StatelessWidget {
|
||||
}
|
||||
|
||||
_updateNavigationsContainer(Widget child) {
|
||||
return Selector3<AppState, Config, ClashConfig, UpdateNavigationsSelector>(
|
||||
selector: (_, appState, config, clashConfig) {
|
||||
final hasGroups =
|
||||
appState.getCurrentGroups(clashConfig.mode).isNotEmpty;
|
||||
return Selector2<AppState, Config, UpdateNavigationsSelector>(
|
||||
selector: (_, appState, config) {
|
||||
final group = appState.currentGroups;
|
||||
final hasProfile = config.profiles.isNotEmpty;
|
||||
return UpdateNavigationsSelector(
|
||||
openLogs: config.openLogs,
|
||||
hasProxies: hasGroups && hasProfile,
|
||||
hasProxies: group.isNotEmpty && hasProfile,
|
||||
);
|
||||
},
|
||||
builder: (context, state, child) {
|
||||
|
||||
@@ -38,19 +38,8 @@ class _ClashMessageContainerState extends State<ClashMessageContainer>
|
||||
|
||||
@override
|
||||
void onDelay(Delay delay) {
|
||||
globalState.healthcheckLock = true;
|
||||
context.appController.setDelay(delay);
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
globalState.updateSortNumDebounce ??= debounce<Function()>(
|
||||
() {
|
||||
context.appController.updateGroups();
|
||||
context.appController.appState.sortNum++;
|
||||
globalState.healthcheckLock = false;
|
||||
},
|
||||
milliseconds: 5000,
|
||||
);
|
||||
globalState.updateSortNumDebounce!();
|
||||
});
|
||||
final appController = context.appController;
|
||||
appController.setDelay(delay);
|
||||
super.onDelay(delay);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: fl_clash
|
||||
description: A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free.
|
||||
publish_to: 'none'
|
||||
version: 0.7.10
|
||||
version: 0.8.0
|
||||
environment:
|
||||
sdk: '>=3.1.0 <4.0.0'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user