diff --git a/core/Clash.Meta b/core/Clash.Meta index 8d1f662..53b2dbb 160000 --- a/core/Clash.Meta +++ b/core/Clash.Meta @@ -1 +1 @@ -Subproject commit 8d1f6620f71dfe49976ec1e0b8ecb2394cfcfd67 +Subproject commit 53b2dbba62d298a6abbec23821f26eb538c50c91 diff --git a/core/common.go b/core/common.go index f63e09e..e767987 100644 --- a/core/common.go +++ b/core/common.go @@ -4,6 +4,7 @@ import "C" import ( "context" "errors" + route "github.com/metacubex/mihomo/hub/route" "math" "os" "os/exec" @@ -21,13 +22,11 @@ import ( "github.com/metacubex/mihomo/common/batch" "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/resolver" - "github.com/metacubex/mihomo/component/sniffer" "github.com/metacubex/mihomo/config" "github.com/metacubex/mihomo/constant" cp "github.com/metacubex/mihomo/constant/provider" "github.com/metacubex/mihomo/hub" "github.com/metacubex/mihomo/hub/executor" - "github.com/metacubex/mihomo/hub/route" "github.com/metacubex/mihomo/listener" "github.com/metacubex/mihomo/log" rp "github.com/metacubex/mihomo/rules/provider" @@ -191,7 +190,7 @@ func toExternalProvider(p cp.Provider) (*ExternalProvider, error) { VehicleType: psp.VehicleType().String(), Count: psp.Count(), Path: psp.Vehicle().Path(), - UpdateAt: psp.UpdatedAt, + UpdateAt: psp.UpdatedAt(), }, nil case *rp.RuleSetProvider: rsp := p.(*rp.RuleSetProvider) @@ -201,7 +200,7 @@ func toExternalProvider(p cp.Provider) (*ExternalProvider, error) { VehicleType: rsp.VehicleType().String(), Count: rsp.Count(), Path: rsp.Vehicle().Path(), - UpdateAt: rsp.UpdatedAt, + UpdateAt: rsp.UpdatedAt(), }, nil default: return nil, errors.New("not external provider") @@ -411,12 +410,13 @@ func overwriteConfig(targetConfig *config.RawConfig, patchConfig config.RawConfi targetConfig.Profile.StoreSelected = false targetConfig.GeoXUrl = patchConfig.GeoXUrl targetConfig.GlobalUA = patchConfig.GlobalUA - //if targetConfig.DNS.Enable == false { - // targetConfig.DNS = patchConfig.DNS - //} genHosts(targetConfig.Hosts, patchConfig.Hosts) if configParams.OverrideDns { targetConfig.DNS = patchConfig.DNS + } else { + if targetConfig.DNS.Enable == false { + targetConfig.DNS.Enable = true + } } //if runtime.GOOS == "android" { // targetConfig.DNS.NameServer = append(targetConfig.DNS.NameServer, "dhcp://"+dns.SystemDNSPlaceholder) @@ -430,12 +430,10 @@ func overwriteConfig(targetConfig *config.RawConfig, patchConfig config.RawConfi //} } -func patchConfig(general *config.General) { +func patchConfig(general *config.General, controller *config.Controller) { log.Infoln("[Apply] patch") - route.ReStartServer(general.ExternalController) - if sniffer.Dispatcher != nil { - tunnel.SetSniffing(general.Sniffing) - } + route.ReStartServer(controller.ExternalController) + tunnel.SetSniffing(general.Sniffing) tunnel.SetFindProcessMode(general.FindProcessMode) dialer.SetTcpConcurrent(general.TCPConcurrent) dialer.DefaultInterface.Store(general.Interface) @@ -455,6 +453,7 @@ func updateListeners(general *config.General, listeners map[string]constant.Inbo } runLock.Lock() defer runLock.Unlock() + listener.PatchInboundListeners(listeners, tunnel.Tunnel, true) listener.SetAllowLan(general.AllowLan) inbound.SetSkipAuthPrefixes(general.SkipAuthPrefixes) @@ -464,14 +463,12 @@ func updateListeners(general *config.General, listeners map[string]constant.Inbo listener.ReCreateHTTP(general.Port, tunnel.Tunnel) listener.ReCreateSocks(general.SocksPort, tunnel.Tunnel) listener.ReCreateRedir(general.RedirPort, tunnel.Tunnel) - listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tunnel.Tunnel) listener.ReCreateTProxy(general.TProxyPort, tunnel.Tunnel) listener.ReCreateMixed(general.MixedPort, tunnel.Tunnel) listener.ReCreateShadowSocks(general.ShadowSocksConfig, tunnel.Tunnel) listener.ReCreateVmess(general.VmessConfig, tunnel.Tunnel) listener.ReCreateTuic(general.TuicServer, tunnel.Tunnel) listener.ReCreateTun(general.Tun, tunnel.Tunnel) - listener.ReCreateRedirToTun(general.EBpf.RedirectToTun) } func stopListeners() { @@ -533,7 +530,7 @@ func applyConfig() error { constant.DefaultTestURL = *configParams.TestURL } if configParams.IsPatch { - patchConfig(cfg.General) + patchConfig(cfg.General, cfg.Controller) } else { closeConnections() runtime.GC() @@ -541,7 +538,9 @@ func applyConfig() error { patchSelectGroup() } updateListeners(cfg.General, cfg.Listeners) - hcCompatibleProvider(cfg.Providers) + if isRunning { + hcCompatibleProvider(cfg.Providers) + } externalProviders = getExternalProvidersRaw() return err } diff --git a/core/go.mod b/core/go.mod index 5d3a967..b3ef2ec 100644 --- a/core/go.mod +++ b/core/go.mod @@ -7,9 +7,8 @@ replace github.com/metacubex/mihomo => ./Clash.Meta require ( github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34 github.com/metacubex/mihomo v1.17.1 - github.com/miekg/dns v1.1.61 - golang.org/x/net v0.26.0 - golang.org/x/sync v0.7.0 + github.com/miekg/dns v1.1.62 + golang.org/x/sync v0.8.0 ) require ( @@ -20,17 +19,16 @@ require ( github.com/andybalholm/brotli v1.0.6 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/buger/jsonparser v1.1.1 // indirect - github.com/cilium/ebpf v0.12.3 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/coreos/go-iptables v0.7.0 // indirect - github.com/dlclark/regexp2 v1.11.0 // indirect + github.com/dlclark/regexp2 v1.11.4 // indirect github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 // indirect github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gaukas/godicttls v0.0.4 // indirect - github.com/go-chi/chi/v5 v5.0.14 // indirect + github.com/go-chi/chi/v5 v5.1.0 // indirect github.com/go-chi/cors v1.2.1 // indirect github.com/go-chi/render v1.0.3 // indirect github.com/go-ole/go-ole v1.3.0 // indirect @@ -38,12 +36,12 @@ require ( github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect github.com/gobwas/ws v1.4.0 // indirect - github.com/gofrs/uuid/v5 v5.2.0 // indirect + github.com/gofrs/uuid/v5 v5.3.0 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6 // indirect + github.com/insomniacslk/dhcp v0.0.0-20240812123929-b105c29bd1b5 // indirect github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect @@ -52,18 +50,19 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/socket v0.4.1 // indirect + github.com/metacubex/bbolt v0.0.0-20240822011022-aed6d4850399 // indirect github.com/metacubex/chacha v0.1.0 // indirect github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec // indirect - github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e // indirect + github.com/metacubex/quic-go v0.46.1-0.20240807232329-1c6cb2d67f58 // indirect github.com/metacubex/randv2 v0.2.0 // indirect - github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 // indirect - github.com/metacubex/sing-shadowsocks v0.2.7 // indirect - github.com/metacubex/sing-shadowsocks2 v0.2.1 // indirect - github.com/metacubex/sing-tun v0.2.7-0.20240719141246-19c49ac9589d // indirect + github.com/metacubex/sing-quic v0.0.0-20240827003841-cd97758ed8b4 // indirect + github.com/metacubex/sing-shadowsocks v0.2.8 // indirect + github.com/metacubex/sing-shadowsocks2 v0.2.2 // indirect + github.com/metacubex/sing-tun v0.2.7-0.20240729131039-ed03f557dee1 // indirect github.com/metacubex/sing-vmess v0.1.9-0.20240719134745-1df6fb20bbf9 // indirect - github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a // indirect - github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 // indirect + github.com/metacubex/sing-wireguard v0.0.0-20240826061955-1e4e67afe5cd // indirect + github.com/metacubex/tfo-go v0.0.0-20240830120620-c5e019b67785 // indirect github.com/metacubex/utls v1.6.6 // indirect github.com/mroth/weightedrand/v2 v2.1.0 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect @@ -72,10 +71,9 @@ require ( github.com/oschwald/maxminddb-golang v1.12.0 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/puzpuzpuz/xsync/v3 v3.2.0 // indirect + github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.4.1 // indirect - github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect github.com/sagernet/fswatch v0.1.1 // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect @@ -84,7 +82,7 @@ require ( github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e // indirect - github.com/samber/lo v1.39.0 // indirect + github.com/samber/lo v1.47.0 // indirect github.com/shirou/gopsutil/v3 v3.24.5 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect @@ -101,13 +99,14 @@ require ( gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.uber.org/mock v0.4.0 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.24.0 // indirect - golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect - golang.org/x/mod v0.18.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect + golang.org/x/mod v0.20.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sys v0.24.0 // indirect + golang.org/x/text v0.17.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.22.0 // indirect + golang.org/x/tools v0.24.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect diff --git a/core/go.sum b/core/go.sum index 58a3252..2e80016 100644 --- a/core/go.sum +++ b/core/go.sum @@ -19,8 +19,6 @@ github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx2 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= -github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= @@ -28,8 +26,8 @@ github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFE github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= -github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= +github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8= github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I= github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g= @@ -40,14 +38,12 @@ github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 h1:tlDMEdcPRQKBE github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4RfsapbGx2j/vU5xC/5/9qB3kn9Awp1YDiEnN43QrJ4= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 h1:fuGucgPk5dN6wzfnxl3D0D3rVLw4v2SbBT9jb4VnxzA= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010/go.mod h1:JtBcj7sBuTTRupn7c2bFspMDIObMJsVK8TeUvpShPok= -github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= -github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= -github.com/go-chi/chi/v5 v5.0.14 h1:PyEwo2Vudraa0x/Wl6eDRRW2NXBvekgfxyydcM0WGE0= -github.com/go-chi/chi/v5 v5.0.14/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= @@ -65,8 +61,8 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs= github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc= -github.com/gofrs/uuid/v5 v5.2.0 h1:qw1GMx6/y8vhVsx626ImfKMuS5CvJmhIKKtuyvfajMM= -github.com/gofrs/uuid/v5 v5.2.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk= +github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -82,8 +78,8 @@ github.com/google/tink/go v1.6.1/go.mod h1:IGW53kTgag+st5yPhKKwJ6u2l+SSp5/v9XF7s github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6 h1:dh8D8FksyMhD64mRMbUhZHWYJfNoNMCxfVq6eexleMw= -github.com/insomniacslk/dhcp v0.0.0-20240529192340-51bc6136a0a6/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic= +github.com/insomniacslk/dhcp v0.0.0-20240812123929-b105c29bd1b5 h1:GkMacU5ftc+IEg1449N3UEy2XLDz58W4fkrRu2fibb8= +github.com/insomniacslk/dhcp v0.0.0-20240812123929-b105c29bd1b5/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= @@ -92,10 +88,6 @@ github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2 github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= @@ -106,34 +98,36 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/ github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/metacubex/bbolt v0.0.0-20240822011022-aed6d4850399 h1:oBowHVKZycNtAFbZ6avaCSZJYeme2Nrj+4RpV2cNJig= +github.com/metacubex/bbolt v0.0.0-20240822011022-aed6d4850399/go.mod h1:4xcieuIK+M4bGQmQYZVqEaIYqjS1ahO4kXG7EmDgEro= github.com/metacubex/chacha v0.1.0 h1:tg9RSJ18NvL38cCWNyYH1eiG6qDCyyXIaTLQthon0sc= github.com/metacubex/chacha v0.1.0/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec h1:HxreOiFTUrJXJautEo8rnE1uKTVGY8wtZepY1Tii/Nc= github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec/go.mod h1:8BVmQ+3cxjqzWElafm24rb2Ae4jRI6vAXNXWqWjfrXw= -github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e h1:bLYn3GuRvWDcBDAkIv5kUYIhzHwafDVq635BuybnKqI= -github.com/metacubex/quic-go v0.45.1-0.20240610004319-163fee60637e/go.mod h1:Yza2H7Ax1rxWPUcJx0vW+oAt9EsPuSiyQFhFabUPzwU= +github.com/metacubex/quic-go v0.46.1-0.20240807232329-1c6cb2d67f58 h1:T6OxROLZBr9SOQxN5TzUslv81hEREy/dEgaUKVjaG7U= +github.com/metacubex/quic-go v0.46.1-0.20240807232329-1c6cb2d67f58/go.mod h1:Yza2H7Ax1rxWPUcJx0vW+oAt9EsPuSiyQFhFabUPzwU= github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs= github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY= -github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 h1:Wr4g1HCb5Z/QIFwFiVNjO2qL+dRu25+Mdn9xtAZZ+ew= -github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8= -github.com/metacubex/sing-shadowsocks v0.2.7 h1:9f3Dt2+71TNp0e202llA2ug5h/rkWs2EZxQ5IMpf+9g= -github.com/metacubex/sing-shadowsocks v0.2.7/go.mod h1:X3x88XtJpBxG0W0/ECOJL6Ib0SJ3xdniAkU/6/RMWU0= -github.com/metacubex/sing-shadowsocks2 v0.2.1 h1:XIZBXlazp8EEoPp1S0DViAhLkJakjQ2f+AOwwdKKNYg= -github.com/metacubex/sing-shadowsocks2 v0.2.1/go.mod h1:BhOug03a/RbI7y6hp6q+6ITM1dXjnLTmeWBHSTwvv2Q= -github.com/metacubex/sing-tun v0.2.7-0.20240719141246-19c49ac9589d h1:iYlepjRCYlPXtELupDL+pQjGqkCnQz4KQOfKImP9sog= -github.com/metacubex/sing-tun v0.2.7-0.20240719141246-19c49ac9589d/go.mod h1:olbEx9yVcaw5tHTNlRamRoxmMKcvDvcVS1YLnQGzvWE= +github.com/metacubex/sing-quic v0.0.0-20240827003841-cd97758ed8b4 h1:HobpULaPK6OoxrHMmgcwLkwwIduXVmwdcznwUfH1GQM= +github.com/metacubex/sing-quic v0.0.0-20240827003841-cd97758ed8b4/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8= +github.com/metacubex/sing-shadowsocks v0.2.8 h1:wIhlaigswzjPw4hej75sEvWte3QR0+AJRafgwBHO5B4= +github.com/metacubex/sing-shadowsocks v0.2.8/go.mod h1:X3x88XtJpBxG0W0/ECOJL6Ib0SJ3xdniAkU/6/RMWU0= +github.com/metacubex/sing-shadowsocks2 v0.2.2 h1:eaf42uVx4Lr21S6MDYs0ZdTvGA0GEhDpb9no4+gdXPo= +github.com/metacubex/sing-shadowsocks2 v0.2.2/go.mod h1:BhOug03a/RbI7y6hp6q+6ITM1dXjnLTmeWBHSTwvv2Q= +github.com/metacubex/sing-tun v0.2.7-0.20240729131039-ed03f557dee1 h1:ypfofGDZbP8p3Y4P/m74JYu7sQViesi3c8nbmT6cS0Y= +github.com/metacubex/sing-tun v0.2.7-0.20240729131039-ed03f557dee1/go.mod h1:olbEx9yVcaw5tHTNlRamRoxmMKcvDvcVS1YLnQGzvWE= github.com/metacubex/sing-vmess v0.1.9-0.20240719134745-1df6fb20bbf9 h1:OAXiCosqY8xKDp3pqTW3qbrCprZ1l6WkrXSFSCwyY4I= github.com/metacubex/sing-vmess v0.1.9-0.20240719134745-1df6fb20bbf9/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY= -github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a h1:NpSGclHJUYndUwBmyIpFBSoBVg8PoVX7QQKhYg0DjM0= -github.com/metacubex/sing-wireguard v0.0.0-20240618022557-a6efaa37127a/go.mod h1:uY+BYb0UEknLrqvbGcwi9i++KgrKxsurysgI6G1Pveo= -github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 h1:as/aO/fM8nv4W4pOr9EETP6kV/Oaujk3fUNyQSJK61c= -github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66/go.mod h1:c7bVFM9f5+VzeZ/6Kg77T/jrg1Xp8QpqlSHvG/aXVts= +github.com/metacubex/sing-wireguard v0.0.0-20240826061955-1e4e67afe5cd h1:r7alry8u4qlUFLNMwGvG1A8ZcfPM6AMSmrm6E2yKdB4= +github.com/metacubex/sing-wireguard v0.0.0-20240826061955-1e4e67afe5cd/go.mod h1:uY+BYb0UEknLrqvbGcwi9i++KgrKxsurysgI6G1Pveo= +github.com/metacubex/tfo-go v0.0.0-20240830120620-c5e019b67785 h1:NNmI+ZV0DzNuqaAInRQuZFLHlWVuyHeow8jYpdKjHjo= +github.com/metacubex/tfo-go v0.0.0-20240830120620-c5e019b67785/go.mod h1:c7bVFM9f5+VzeZ/6Kg77T/jrg1Xp8QpqlSHvG/aXVts= github.com/metacubex/utls v1.6.6 h1:3D12YKHTf2Z41UPhQU2dWerNWJ5TVQD9gKoQ+H+iLC8= github.com/metacubex/utls v1.6.6/go.mod h1:+WLFUnXjcpdxXCnyX25nggw8C6YonZ8zOK2Zm/oRvdo= -github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= -github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= +github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= +github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= github.com/mroth/weightedrand/v2 v2.1.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= @@ -156,16 +150,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/puzpuzpuz/xsync/v3 v3.2.0 h1:9AzuUeF88YC5bK8u2vEG1Fpvu4wgpM1wfPIExfaaDxQ= -github.com/puzpuzpuz/xsync/v3 v3.2.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4= +github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= -github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs= github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis= @@ -183,8 +173,8 @@ github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxe github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo= github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e h1:iGH0RMv2FzELOFNFQtvsxH7NPmlo7X5JizEK51UCojo= github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e/go.mod h1:YbL4TKHRR6APYQv3U2RGfwLDpPYSyWz6oUlpISBEzBE= -github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= -github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= +github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= @@ -230,21 +220,21 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= -golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -261,18 +251,18 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= -golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= diff --git a/core/hub.go b/core/hub.go index 45c0e61..d18b258 100644 --- a/core/hub.go +++ b/core/hub.go @@ -5,9 +5,11 @@ package main */ import "C" import ( + "context" bridge "core/dart-bridge" "encoding/json" "fmt" + "github.com/metacubex/mihomo/common/utils" "os" "runtime" "sort" @@ -18,7 +20,6 @@ import ( "github.com/metacubex/mihomo/adapter" "github.com/metacubex/mihomo/adapter/outboundgroup" "github.com/metacubex/mihomo/adapter/provider" - "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/updater" "github.com/metacubex/mihomo/config" "github.com/metacubex/mihomo/constant" @@ -27,7 +28,6 @@ import ( "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/tunnel" "github.com/metacubex/mihomo/tunnel/statistic" - "golang.org/x/net/context" ) var currentRawConfig = config.DefaultRawConfig() @@ -225,11 +225,13 @@ func asyncTestDelay(s *C.char, port C.longlong) { var params = &TestDelayParams{} err := json.Unmarshal([]byte(paramsString), params) if err != nil { + bridge.SendToPort(i, "") return false, nil } expectedStatus, err := utils.NewUnsignedRanges[uint16]("") if err != nil { + bridge.SendToPort(i, "") return false, nil } @@ -238,7 +240,6 @@ func asyncTestDelay(s *C.char, port C.longlong) { proxies := tunnel.ProxiesWithProviders() proxy := proxies[params.ProxyName] - proxy.Name() delayData := &Delay{ Name: params.ProxyName, diff --git a/lib/application.dart b/lib/application.dart index 5c7553c..cde7185 100644 --- a/lib/application.dart +++ b/lib/application.dart @@ -158,7 +158,9 @@ class ApplicationState extends State { GlobalWidgetsLocalizations.delegate ], builder: (_, child) { - return _buildPage(child!); + return MediaContainer( + child: _buildPage(child!), + ); }, scrollBehavior: BaseScrollBehavior(), title: appName, diff --git a/lib/common/dav_client.dart b/lib/common/dav_client.dart index 5b09db4..bf6102a 100644 --- a/lib/common/dav_client.dart +++ b/lib/common/dav_client.dart @@ -8,6 +8,7 @@ import 'package:webdav_client/webdav_client.dart'; class DAVClient { late Client client; Completer pingCompleter = Completer(); + late String fileName; DAVClient(DAV dav) { client = newClient( @@ -15,6 +16,7 @@ class DAVClient { user: dav.user, password: dav.password, ); + fileName = dav.fileName; client.setHeaders( { 'accept-charset': 'utf-8', @@ -38,7 +40,7 @@ class DAVClient { get root => "/$appName"; - get backupFile => "$root/backup.zip"; + get backupFile => "$root/$fileName"; backup(Uint8List data) async { await client.mkdir("$root"); diff --git a/lib/common/http.dart b/lib/common/http.dart index 2f55a06..6eb9f11 100644 --- a/lib/common/http.dart +++ b/lib/common/http.dart @@ -1,18 +1,20 @@ import 'dart:io'; +import 'package:flutter/cupertino.dart'; + import '../state.dart'; class FlClashHttpOverrides extends HttpOverrides { - @override HttpClient createHttpClient(SecurityContext? context) { final client = super.createHttpClient(context); client.badCertificateCallback = (_, __, ___) => true; client.findProxy = (url) { + debugPrint("find $url"); final port = globalState.appController.clashConfig.mixedPort; final isStart = globalState.appController.appState.isStart; - if(!isStart) return "DIRECT"; - return "PROXY localhost:$port;DIRECT"; + if (!isStart) return "DIRECT"; + return "PROXY localhost:$port"; }; return client; } diff --git a/lib/common/list.dart b/lib/common/list.dart index ca36db0..0eae151 100644 --- a/lib/common/list.dart +++ b/lib/common/list.dart @@ -2,4 +2,17 @@ extension ListExtension on List { List intersection(List list) { return where((item) => list.contains(item)).toList(); } -} \ No newline at end of file + + List> batch(int maxConcurrent) { + final batches = (length / maxConcurrent).ceil(); + final List> res = []; + for (int i = 0; i < batches; i++) { + if (i != batches - 1) { + res.add(sublist(i * maxConcurrent, maxConcurrent * (i + 1))); + } else { + res.add(sublist(i * maxConcurrent, length)); + } + } + return res; + } +} diff --git a/lib/common/measure.dart b/lib/common/measure.dart index 3f60606..4e8cd96 100644 --- a/lib/common/measure.dart +++ b/lib/common/measure.dart @@ -3,23 +3,21 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class Measure { - Measure.of(this.context); + final TextScaler _textScale; + late BuildContext context; - final _textScaleFactor = - WidgetsBinding.instance.platformDispatcher.textScaleFactor; + Measure.of(this.context) : _textScale = MediaQuery.of(context).textScaler; Size computeTextSize(Text text) { final textPainter = TextPainter( text: TextSpan(text: text.data, style: text.style), maxLines: text.maxLines, - textScaler: TextScaler.linear(_textScaleFactor), + textScaler: _textScale, textDirection: text.textDirection ?? TextDirection.ltr, )..layout(); return textPainter.size; } - late BuildContext context; - double? _bodyMediumHeight; double? _bodySmallHeight; double? _labelSmallHeight; diff --git a/lib/controller.dart b/lib/controller.dart index 9c96919..542e619 100644 --- a/lib/controller.dart +++ b/lib/controller.dart @@ -8,7 +8,6 @@ import 'package:fl_clash/common/archive.dart'; import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; -import 'package:lpinyin/lpinyin.dart'; import 'package:path/path.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -22,7 +21,6 @@ class AppController { late AppState appState; late Config config; late ClashConfig clashConfig; - late Measure measure; late Function updateClashConfigDebounce; late Function updateGroupDebounce; late Function addCheckIpNumDebounce; @@ -44,7 +42,6 @@ class AppController { updateGroupDebounce = debounce(() async { await updateGroups(); }); - measure = Measure.of(context); } updateStatus(bool isStart) async { @@ -125,10 +122,6 @@ class AppController { ); } - updateTray(){ - - } - Future applyProfile({bool isPrue = false}) async { if (isPrue) { await globalState.applyProfile( @@ -317,6 +310,14 @@ class AppController { autoCheckUpdate(); } + updateTray() { + globalState.updateTray( + appState: appState, + config: config, + clashConfig: clashConfig, + ); + } + setDelay(Delay delay) { appState.setDelay(delay); } diff --git a/lib/fragments/backup_and_recovery.dart b/lib/fragments/backup_and_recovery.dart index 722d071..e6f0be4 100644 --- a/lib/fragments/backup_and_recovery.dart +++ b/lib/fragments/backup_and_recovery.dart @@ -73,11 +73,11 @@ class BackupAndRecovery extends StatelessWidget { final res = await commonScaffoldState?.loadingRun( () async { final backupData = await globalState.appController.backupData(); - final value = await picker.saveFile( + final value = await picker.saveFile( other.getBackupFileName(), Uint8List.fromList(backupData), ); - if(value == null) return false; + if (value == null) return false; return true; }, title: appLocalizations.backup, @@ -204,6 +204,24 @@ class BackupAndRecovery extends StatelessWidget { const SizedBox( height: 4, ), + ListItem.input( + title: Text(appLocalizations.file), + subtitle: Text(dav.fileName), + delegate: InputDelegate( + title: appLocalizations.file, + value: dav.fileName, + resetValue: defaultDavFileName, + onChanged: (String? value) { + if (value == null) { + return; + } + globalState.appController.config.dav = + globalState.appController.config.dav?.copyWith( + fileName: value, + ); + }, + ), + ), ListItem( onTap: () { _backupOnWebDAV(context, client); diff --git a/lib/fragments/config/config.dart b/lib/fragments/config/config.dart index 69d7d21..e51f556 100644 --- a/lib/fragments/config/config.dart +++ b/lib/fragments/config/config.dart @@ -72,6 +72,7 @@ class _ConfigFragmentState extends State { widget: generateListView( dnsItems, ), + isScaffold: true, isBlur: false, extendPageWidth: 360, ), diff --git a/lib/fragments/config/dns.dart b/lib/fragments/config/dns.dart index 54ea538..70967fc 100644 --- a/lib/fragments/config/dns.dart +++ b/lib/fragments/config/dns.dart @@ -11,8 +11,27 @@ import 'package:provider/provider.dart'; class OverrideItem extends StatelessWidget { const OverrideItem({super.key}); + _initActions(BuildContext context) { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + final commonScaffoldState = + context.findAncestorStateOfType(); + commonScaffoldState?.actions = [ + IconButton( + onPressed: () { + globalState.appController.clashConfig.dns = const Dns(); + }, + tooltip: appLocalizations.resetDns, + icon: const Icon( + Icons.replay, + ), + ) + ]; + }); + } + @override Widget build(BuildContext context) { + _initActions(context); return Selector( selector: (_, config) => config.overrideDns, builder: (_, override, __) { @@ -35,8 +54,7 @@ class OverrideItem extends StatelessWidget { class DnsDisabledContainer extends StatelessWidget { final Widget child; - const DnsDisabledContainer( - this.child, { + const DnsDisabledContainer(this.child, { super.key, }); @@ -250,7 +268,7 @@ class FakeIpFilterItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.fakeIpFilter, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, fakeIpFilter, __) { return UpdatePage( title: appLocalizations.fakeipFilter, @@ -260,7 +278,8 @@ class FakeIpFilterItem extends StatelessWidget { final clashConfig = globalState.appController.clashConfig; final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( - fakeIpFilter: List.from(dns.fakeIpFilter)..remove(value), + fakeIpFilter: List.from(dns.fakeIpFilter) + ..remove(value), ); }, onAdd: (value) { @@ -268,7 +287,8 @@ class FakeIpFilterItem extends StatelessWidget { final dns = clashConfig.dns; if (fakeIpFilter.contains(value)) return; clashConfig.dns = dns.copyWith( - fakeIpFilter: List.from(dns.fakeIpFilter)..add(value), + fakeIpFilter: List.from(dns.fakeIpFilter) + ..add(value), ); }, ); @@ -294,7 +314,7 @@ class DefaultNameserverItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.defaultNameserver, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, defaultNameserver, __) { return UpdatePage( title: appLocalizations.defaultNameserver, @@ -340,7 +360,7 @@ class NameserverItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.nameserver, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, nameserver, __) { return UpdatePage( title: "域名服务器", @@ -350,7 +370,8 @@ class NameserverItem extends StatelessWidget { final clashConfig = globalState.appController.clashConfig; final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( - nameserver: List.from(dns.nameserver)..remove(value), + nameserver: List.from(dns.nameserver) + ..remove(value), ); }, onAdd: (value) { @@ -358,7 +379,8 @@ class NameserverItem extends StatelessWidget { final dns = clashConfig.dns; if (nameserver.contains(value)) return; clashConfig.dns = dns.copyWith( - nameserver: List.from(dns.nameserver)..add(value), + nameserver: List.from(dns.nameserver) + ..add(value), ); }, ); @@ -436,7 +458,7 @@ class NameserverPolicyItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.nameserverPolicy, shouldRebuild: (prev, next) => - !const MapEquality().equals(prev, next), + !const MapEquality().equals(prev, next), builder: (_, nameserverPolicy, __) { return UpdatePage( title: appLocalizations.nameserverPolicy, @@ -483,7 +505,7 @@ class ProxyServerNameserverItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.proxyServerNameserver, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, proxyServerNameserver, __) { return UpdatePage( title: appLocalizations.proxyNameserver, @@ -529,7 +551,7 @@ class FallbackItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.fallback, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, fallback, __) { return UpdatePage( title: appLocalizations.fallback, @@ -539,7 +561,8 @@ class FallbackItem extends StatelessWidget { final clashConfig = globalState.appController.clashConfig; final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( - fallback: List.from(dns.fallback)..remove(value), + fallback: List.from(dns.fallback) + ..remove(value), ); }, onAdd: (value) { @@ -547,7 +570,8 @@ class FallbackItem extends StatelessWidget { final dns = clashConfig.dns; if (fallback.contains(value)) return; clashConfig.dns = dns.copyWith( - fallback: List.from(dns.fallback)..add(value), + fallback: List.from(dns.fallback) + ..add(value), ); }, ); @@ -639,7 +663,7 @@ class GeositeItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.geosite, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, geosite, __) { return UpdatePage( title: "Geosite", @@ -650,7 +674,8 @@ class GeositeItem extends StatelessWidget { final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( fallbackFilter: dns.fallbackFilter.copyWith( - geosite: List.from(geosite)..remove(value), + geosite: List.from(geosite) + ..remove(value), ), ); }, @@ -659,7 +684,8 @@ class GeositeItem extends StatelessWidget { final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( fallbackFilter: dns.fallbackFilter.copyWith( - geosite: List.from(geosite)..add(value), + geosite: List.from(geosite) + ..add(value), ), ); }, @@ -685,7 +711,7 @@ class IpcidrItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.ipcidr, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, ipcidr, __) { return UpdatePage( title: appLocalizations.ipcidr, @@ -696,7 +722,8 @@ class IpcidrItem extends StatelessWidget { final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( fallbackFilter: dns.fallbackFilter.copyWith( - ipcidr: List.from(ipcidr)..remove(value), + ipcidr: List.from(ipcidr) + ..remove(value), ), ); }, @@ -705,7 +732,8 @@ class IpcidrItem extends StatelessWidget { final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( fallbackFilter: dns.fallbackFilter.copyWith( - ipcidr: List.from(ipcidr)..add(value), + ipcidr: List.from(ipcidr) + ..add(value), ), ); }, @@ -724,14 +752,14 @@ class DomainItem extends StatelessWidget { @override Widget build(BuildContext context) { return ListItem.open( - title: Text(appLocalizations.domain), + title: Text(appLocalizations.domain), delegate: OpenDelegate( isBlur: false, title: appLocalizations.domain, widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.domain, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, domain, __) { return UpdatePage( title: appLocalizations.domain, @@ -742,7 +770,8 @@ class DomainItem extends StatelessWidget { final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( fallbackFilter: dns.fallbackFilter.copyWith( - domain: List.from(domain)..remove(value), + domain: List.from(domain) + ..remove(value), ), ); }, @@ -751,7 +780,8 @@ class DomainItem extends StatelessWidget { final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( fallbackFilter: dns.fallbackFilter.copyWith( - domain: List.from(domain)..add(value), + domain: List.from(domain) + ..add(value), ), ); }, diff --git a/lib/fragments/config/general.dart b/lib/fragments/config/general.dart index 4082389..7ddae07 100644 --- a/lib/fragments/config/general.dart +++ b/lib/fragments/config/general.dart @@ -85,7 +85,8 @@ class KeepAliveIntervalItem extends StatelessWidget { delegate: InputDelegate( title: appLocalizations.keepAliveIntervalDesc, suffixText: appLocalizations.seconds, - value: value.toString(), + resetValue: "$defaultKeepAliveInterval", + value: "$value", onChanged: (String? value) { if (value != null) { try { @@ -125,6 +126,7 @@ class TestUrlItem extends StatelessWidget { title: Text(appLocalizations.testUrl), subtitle: Text(value), delegate: InputDelegate( + resetValue: defaultTestUrl, title: appLocalizations.testUrl, value: value, onChanged: (String? value) { @@ -165,7 +167,7 @@ class MixedPortItem extends StatelessWidget { subtitle: Text("$value"), delegate: InputDelegate( title: appLocalizations.proxyPort, - value: value.toString(), + value: "$value", onChanged: (String? value) { if (value != null) { try { @@ -184,6 +186,7 @@ class MixedPortItem extends StatelessWidget { } } }, + resetValue: "$defaultMixedPort", ), ); }, diff --git a/lib/fragments/dashboard/intranet_ip.dart b/lib/fragments/dashboard/intranet_ip.dart index f46f19b..6f71f7b 100644 --- a/lib/fragments/dashboard/intranet_ip.dart +++ b/lib/fragments/dashboard/intranet_ip.dart @@ -53,7 +53,7 @@ class _IntranetIPState extends State { }, child: Container( padding: const EdgeInsets.all(16).copyWith(top: 0), - height: globalState.appController.measure.titleLargeHeight + 24 - 2, + height: globalState.measure.titleLargeHeight + 24 - 2, child: ValueListenableBuilder( valueListenable: ipNotifier, builder: (_, value, __) { diff --git a/lib/fragments/dashboard/network_detection.dart b/lib/fragments/dashboard/network_detection.dart index a0886b2..0a22901 100644 --- a/lib/fragments/dashboard/network_detection.dart +++ b/lib/fragments/dashboard/network_detection.dart @@ -46,9 +46,7 @@ class _NetworkDetectionState extends State { isTesting: false, ipInfo: ipInfo, ); - } catch (_) { - - } + } catch (_) {} } _checkIpContainer(Widget child) { @@ -122,7 +120,7 @@ class _NetworkDetectionState extends State { : ipInfo != null ? Container( alignment: Alignment.centerLeft, - height: globalState.appController + height: globalState .measure.titleMediumHeight, child: Text( countryCodeToEmoji( @@ -150,9 +148,7 @@ class _NetworkDetectionState extends State { ), ), Container( - height: globalState.appController.measure.titleLargeHeight + - 24 - - 2, + height: globalState.measure.titleLargeHeight + 24 - 2, alignment: Alignment.centerLeft, padding: const EdgeInsets.all(16).copyWith(top: 0), child: FadeBox( diff --git a/lib/fragments/dashboard/network_speed.dart b/lib/fragments/dashboard/network_speed.dart index dca5d56..4e3bbd4 100644 --- a/lib/fragments/dashboard/network_speed.dart +++ b/lib/fragments/dashboard/network_speed.dart @@ -59,7 +59,7 @@ class _NetworkSpeedState extends State { style: bodyMedium, maxLines: 1, ); - final size = globalState.appController.measure.computeTextSize(valueText); + final size = globalState.measure.computeTextSize(valueText); return Column( crossAxisAlignment: CrossAxisAlignment.center, diff --git a/lib/fragments/dashboard/start_button.dart b/lib/fragments/dashboard/start_button.dart index 2bb0b5d..698c877 100644 --- a/lib/fragments/dashboard/start_button.dart +++ b/lib/fragments/dashboard/start_button.dart @@ -74,7 +74,7 @@ class _StartButtonState extends State if (!state.isInit || !state.hasProfile) { return Container(); } - final textWidth = globalState.appController.measure + final textWidth = globalState.measure .computeTextSize( Text( other.getTimeDifference( diff --git a/lib/fragments/profiles/profiles.dart b/lib/fragments/profiles/profiles.dart index 36f93c9..6bd30cd 100644 --- a/lib/fragments/profiles/profiles.dart +++ b/lib/fragments/profiles/profiles.dart @@ -495,26 +495,29 @@ class _ReorderableProfilesState extends State { itemCount: profiles.length, ), ), - Padding( + Container( padding: const EdgeInsets.symmetric( vertical: 8, - horizontal: 12, + horizontal: 24, ), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - IconButton( - onPressed: () { - Navigator.of(context).pop(); - globalState.appController.config.profiles = profiles; - }, - icon: const Icon( - Icons.check, - ), - iconSize: 32, - padding: const EdgeInsets.all(8), + child: FilledButton( + onPressed: () { + Navigator.of(context).pop(); + globalState.appController.config.profiles = profiles; + }, + style: ButtonStyle( + padding: WidgetStateProperty.all( + const EdgeInsets.symmetric(vertical: 16), ), - ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + appLocalizations.confirm, + ), + ], + ), ), ), ], diff --git a/lib/fragments/proxies/card.dart b/lib/fragments/proxies/card.dart index 02c7443..d51fc9f 100644 --- a/lib/fragments/proxies/card.dart +++ b/lib/fragments/proxies/card.dart @@ -23,7 +23,7 @@ class ProxyCard extends StatelessWidget { required this.type, }); - Measure get measure => globalState.appController.measure; + Measure get measure => globalState.measure; Widget _buildDelayText() { return SizedBox( @@ -119,7 +119,7 @@ class ProxyCard extends StatelessWidget { @override Widget build(BuildContext context) { - final measure = globalState.appController.measure; + final measure = globalState.measure; final delayText = _buildDelayText(); final proxyNameText = _buildProxyNameText(context); return currentGroupProxyNameBuilder( diff --git a/lib/fragments/proxies/common.dart b/lib/fragments/proxies/common.dart index db2c353..1d75326 100644 --- a/lib/fragments/proxies/common.dart +++ b/lib/fragments/proxies/common.dart @@ -1,7 +1,7 @@ import 'dart:math'; import 'package:fl_clash/clash/clash.dart'; -import 'package:fl_clash/common/other.dart'; +import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/models/models.dart'; import 'package:fl_clash/state.dart'; @@ -25,12 +25,12 @@ Widget currentGroupProxyNameBuilder({ } double get listHeaderHeight { - final measure = globalState.appController.measure; + final measure = globalState.measure; return 24 + measure.titleMediumHeight + 4 + measure.bodyMediumHeight; } double getItemHeight(ProxyCardType proxyCardType) { - final measure = globalState.appController.measure; + final measure = globalState.measure; final baseHeight = 12 * 2 + measure.bodyMediumHeight * 2 + measure.bodySmallHeight + 8; return switch (proxyCardType) { @@ -51,8 +51,12 @@ delayTest(List proxies) async { ), ); globalState.appController.setDelay(await clashCore.getDelay(proxyName)); - }); - await Future.wait(delayProxies); + }).toList(); + + final batchesDelayProxies = delayProxies.batch(100); + for (final batchDelayProxies in batchesDelayProxies) { + await Future.wait(batchDelayProxies); + } appController.appState.sortNum++; } diff --git a/lib/fragments/proxies/proxies.dart b/lib/fragments/proxies/proxies.dart index c2e9281..0572377 100644 --- a/lib/fragments/proxies/proxies.dart +++ b/lib/fragments/proxies/proxies.dart @@ -29,7 +29,7 @@ class _ProxiesFragmentState extends State { IconButton( onPressed: () { showExtendPage( - forceNotSide: true, + isScaffold: true, extendPageWidth: 360, context, body: const Providers(), diff --git a/lib/fragments/resources.dart b/lib/fragments/resources.dart index 98e94e1..14a7f45 100644 --- a/lib/fragments/resources.dart +++ b/lib/fragments/resources.dart @@ -33,13 +33,21 @@ class Resources extends StatelessWidget { fileName: geoIpFileName, key: "geoip", ), - GeoItem(label: "GeoSite", fileName: geoSiteFileName, key: "geosite"), + GeoItem( + label: "GeoSite", + fileName: geoSiteFileName, + key: "geosite", + ), GeoItem( label: "MMDB", fileName: mmdbFileName, key: "mmdb", ), - GeoItem(label: "ASN", fileName: asnFileName, key: "asn"), + GeoItem( + label: "ASN", + fileName: asnFileName, + key: "asn", + ), ]; return ListView.separated( @@ -81,6 +89,7 @@ class _GeoDataListItemState extends State { child: UpdateGeoUrlFormDialog( title: geoItem.label, url: url, + defaultValue: defaultGeoXMap[geoItem.key], ), ); if (newUrl != null && newUrl != url && mounted) { @@ -238,11 +247,13 @@ class _GeoDataListItemState extends State { class UpdateGeoUrlFormDialog extends StatefulWidget { final String title; final String url; + final String? defaultValue; const UpdateGeoUrlFormDialog({ super.key, required this.title, required this.url, + this.defaultValue }); @override @@ -258,6 +269,13 @@ class _UpdateGeoUrlFormDialogState extends State { urlController = TextEditingController(text: widget.url); } + _handleReset() async { + if (widget.defaultValue == null) { + return; + } + Navigator.of(context).pop(widget.defaultValue); + } + _handleUpdate() async { final url = urlController.value.text; if (url.isEmpty) return; @@ -285,6 +303,16 @@ class _UpdateGeoUrlFormDialogState extends State { ), ), actions: [ + if (widget.defaultValue != null && + urlController.value.text != widget.defaultValue) ...[ + TextButton( + onPressed: _handleReset, + child: Text(appLocalizations.reset), + ), + const SizedBox( + width: 4, + ), + ], TextButton( onPressed: _handleUpdate, child: Text(appLocalizations.submit), diff --git a/lib/fragments/theme.dart b/lib/fragments/theme.dart index d6b1e45..ff50dd0 100644 --- a/lib/fragments/theme.dart +++ b/lib/fragments/theme.dart @@ -238,15 +238,66 @@ class _ThemeColorsBoxState extends State { ), title: Text(appLocalizations.prueBlackMode), delegate: SwitchDelegate( - value: value, - onChanged: (value){ - globalState.appController.config.prueBlack = value; - } - ), + value: value, + onChanged: (value) { + globalState.appController.config.prueBlack = value; + }), ); }, ), - ) + ), + // Padding( + // padding: const EdgeInsets.symmetric(vertical: 16), + // child: Selector( + // selector: (_, config) => config.scaleProps.custom, + // builder: (_, value, ___) { + // return ListItem.switchItem( + // leading: Icon( + // Icons.format_size_sharp, + // color: context.colorScheme.primary, + // ), + // title: const Text("自定义字体大小"), + // delegate: SwitchDelegate( + // value: value, + // onChanged: (value) { + // globalState.appController.config.scaleProps = + // globalState.appController.config.scaleProps.copyWith( + // custom: value, + // ); + // }, + // ), + // ); + // }, + // ), + // ), + // SizedBox( + // height: 20, + // child: Selector( + // selector: (_, config) => config.scaleProps, + // builder: (_, props, ___) { + // return AbsorbPointer( + // absorbing: !props.custom, + // child: DisabledMask( + // status: !props.custom, + // child: Slider( + // value: props.scale, + // min: 0.8, + // max: 1.2, + // onChanged: (value) { + // globalState.appController.config.scaleProps = + // globalState.appController.config.scaleProps.copyWith( + // scale: value, + // ); + // }, + // ), + // ), + // ); + // }, + // ), + // ), + const SizedBox( + height: 64, + ), ], ); } diff --git a/lib/l10n/arb/intl_en.arb b/lib/l10n/arb/intl_en.arb index 4a4e065..e6652e6 100644 --- a/lib/l10n/arb/intl_en.arb +++ b/lib/l10n/arb/intl_en.arb @@ -286,5 +286,7 @@ "fallbackFilter": "Fallback filter", "geoipCode": "Geoip code", "ipcidr": "Ipcidr", - "domain": "Domain" + "domain": "Domain", + "resetDns": "Reset Dns", + "reset": "Reset" } \ No newline at end of file diff --git a/lib/l10n/arb/intl_zh_CN.arb b/lib/l10n/arb/intl_zh_CN.arb index 49da91d..a53e9db 100644 --- a/lib/l10n/arb/intl_zh_CN.arb +++ b/lib/l10n/arb/intl_zh_CN.arb @@ -286,5 +286,7 @@ "fallbackFilter": "Fallback过滤", "geoipCode": "Geoip代码", "ipcidr": "IP/掩码", - "domain": "域名" + "domain": "域名", + "resetDns": "重置DNS", + "reset": "重置" } \ No newline at end of file diff --git a/lib/l10n/intl/messages_en.dart b/lib/l10n/intl/messages_en.dart index 52c21ee..68e34a6 100644 --- a/lib/l10n/intl/messages_en.dart +++ b/lib/l10n/intl/messages_en.dart @@ -346,6 +346,8 @@ class MessageLookup extends MessageLookupByLibrary { "requests": MessageLookupByLibrary.simpleMessage("Requests"), "requestsDesc": MessageLookupByLibrary.simpleMessage( "View recently request records"), + "reset": MessageLookupByLibrary.simpleMessage("Reset"), + "resetDns": MessageLookupByLibrary.simpleMessage("Reset Dns"), "resources": MessageLookupByLibrary.simpleMessage("Resources"), "resourcesDesc": MessageLookupByLibrary.simpleMessage( "External resource related info"), diff --git a/lib/l10n/intl/messages_zh_CN.dart b/lib/l10n/intl/messages_zh_CN.dart index dd16973..07a9bbe 100644 --- a/lib/l10n/intl/messages_zh_CN.dart +++ b/lib/l10n/intl/messages_zh_CN.dart @@ -271,6 +271,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("通过WebDAV恢复数据"), "requests": MessageLookupByLibrary.simpleMessage("请求"), "requestsDesc": MessageLookupByLibrary.simpleMessage("查看最近请求记录"), + "reset": MessageLookupByLibrary.simpleMessage("重置"), + "resetDns": MessageLookupByLibrary.simpleMessage("重置DNS"), "resources": MessageLookupByLibrary.simpleMessage("资源"), "resourcesDesc": MessageLookupByLibrary.simpleMessage("外部资源相关信息"), "respectRules": MessageLookupByLibrary.simpleMessage("遵守规则"), diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index 2404c90..693413e 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -2929,6 +2929,26 @@ class AppLocalizations { args: [], ); } + + /// `Reset Dns` + String get resetDns { + return Intl.message( + 'Reset Dns', + name: 'resetDns', + desc: '', + args: [], + ); + } + + /// `Reset` + String get reset { + return Intl.message( + 'Reset', + name: 'reset', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/lib/main.dart b/lib/main.dart index 790774c..09bcd42 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -32,6 +32,11 @@ Future main() async { openLogs: config.openLogs, hasProxies: false, ); + globalState.updateTray( + appState: appState, + config: config, + clashConfig: clashConfig, + ); await globalState.init( appState: appState, config: config, diff --git a/lib/models/clash_config.dart b/lib/models/clash_config.dart index c93eab7..98d70c6 100644 --- a/lib/models/clash_config.dart +++ b/lib/models/clash_config.dart @@ -111,6 +111,9 @@ typedef GeoXMap = Map; typedef HostsMap = Map; +const defaultMixedPort = 7890; +const defaultKeepAliveInterval = 30; + @JsonSerializable() class ClashConfig extends ChangeNotifier { int _mixedPort; @@ -132,7 +135,7 @@ class ClashConfig extends ChangeNotifier { HostsMap _hosts; ClashConfig() - : _mixedPort = 7890, + : _mixedPort = defaultMixedPort, _mode = Mode.rule, _ipv6 = false, _findProcessMode = FindProcessMode.off, @@ -143,13 +146,13 @@ class ClashConfig extends ChangeNotifier { _unifiedDelay = false, _geodataLoader = geodataLoaderMemconservative, _externalController = '', - _keepAliveInterval = 30, + _keepAliveInterval = defaultKeepAliveInterval, _dns = const Dns(), _geoXUrl = defaultGeoXMap, _rules = [], _hosts = {}; - @JsonKey(name: "mixed-port", defaultValue: 7890) + @JsonKey(name: "mixed-port", defaultValue: defaultMixedPort) int get mixedPort => _mixedPort; set mixedPort(int value) { @@ -209,7 +212,7 @@ class ClashConfig extends ChangeNotifier { } } - @JsonKey(name: "keep-alive-interval", defaultValue: 30) + @JsonKey(name: "keep-alive-interval", defaultValue: defaultKeepAliveInterval) int get keepAliveInterval => _keepAliveInterval; set keepAliveInterval(int value) { diff --git a/lib/models/config.dart b/lib/models/config.dart index 60f34df..43141b9 100644 --- a/lib/models/config.dart +++ b/lib/models/config.dart @@ -95,6 +95,21 @@ class DesktopProps with _$DesktopProps { json == null ? const DesktopProps() : _$DesktopPropsFromJson(json); } +const defaultCustomFontSizeScale = 1.0; + +const defaultScaleProps = ScaleProps(); + +@freezed +class ScaleProps with _$ScaleProps { + const factory ScaleProps({ + @Default(false) bool custom, + @Default(defaultCustomFontSizeScale) double scale, + }) = _ScaleProps; + + factory ScaleProps.fromJson(Map? json) => + json == null ? defaultScaleProps : _$ScalePropsFromJson(json); +} + @JsonSerializable() class Config extends ChangeNotifier { List _profiles; @@ -124,6 +139,7 @@ class Config extends ChangeNotifier { bool _onlyProxy; bool _prueBlack; VpnProps _vpnProps; + ScaleProps _scaleProps; DesktopProps _desktopProps; bool _showLabel; bool _overrideDns; @@ -155,7 +171,8 @@ class Config extends ChangeNotifier { _vpnProps = const VpnProps(), _desktopProps = const DesktopProps(), _showLabel = false, - _overrideDns = false; + _overrideDns = false, + _scaleProps = const ScaleProps(); deleteProfileById(String id) { _profiles = profiles.where((element) => element.id != id).toList(); @@ -551,6 +568,15 @@ class Config extends ChangeNotifier { } } + ScaleProps get scaleProps => _scaleProps; + + set scaleProps(ScaleProps value) { + if (_scaleProps != value) { + _scaleProps = value; + notifyListeners(); + } + } + @JsonKey(defaultValue: false) bool get showLabel => _showLabel; @@ -589,6 +615,7 @@ class Config extends ChangeNotifier { _isCloseConnections = config._isCloseConnections; _isCompatible = config._isCompatible; _autoLaunch = config._autoLaunch; + _dav = config._dav; _silentLaunch = config._silentLaunch; _autoRun = config._autoRun; _proxiesType = config._proxiesType; diff --git a/lib/models/dav.dart b/lib/models/dav.dart index e6cfc63..2771021 100644 --- a/lib/models/dav.dart +++ b/lib/models/dav.dart @@ -4,14 +4,16 @@ part 'generated/dav.g.dart'; part 'generated/dav.freezed.dart'; +const defaultDavFileName = "backup.zip"; + @freezed -class DAV with _$DAV{ +class DAV with _$DAV { const factory DAV({ required String uri, required String user, required String password, + @Default(defaultDavFileName) String fileName, }) = _DAV; - factory DAV.fromJson(Map json) => - _$DAVFromJson(json); -} \ No newline at end of file + factory DAV.fromJson(Map json) => _$DAVFromJson(json); +} diff --git a/lib/models/generated/config.freezed.dart b/lib/models/generated/config.freezed.dart index ec469d1..a81ec31 100644 --- a/lib/models/generated/config.freezed.dart +++ b/lib/models/generated/config.freezed.dart @@ -1240,3 +1240,159 @@ abstract class _DesktopProps implements DesktopProps { _$$DesktopPropsImplCopyWith<_$DesktopPropsImpl> get copyWith => throw _privateConstructorUsedError; } + +ScaleProps _$ScalePropsFromJson(Map json) { + return _ScaleProps.fromJson(json); +} + +/// @nodoc +mixin _$ScaleProps { + bool get custom => throw _privateConstructorUsedError; + double get scale => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ScalePropsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ScalePropsCopyWith<$Res> { + factory $ScalePropsCopyWith( + ScaleProps value, $Res Function(ScaleProps) then) = + _$ScalePropsCopyWithImpl<$Res, ScaleProps>; + @useResult + $Res call({bool custom, double scale}); +} + +/// @nodoc +class _$ScalePropsCopyWithImpl<$Res, $Val extends ScaleProps> + implements $ScalePropsCopyWith<$Res> { + _$ScalePropsCopyWithImpl(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? custom = null, + Object? scale = null, + }) { + return _then(_value.copyWith( + custom: null == custom + ? _value.custom + : custom // ignore: cast_nullable_to_non_nullable + as bool, + scale: null == scale + ? _value.scale + : scale // ignore: cast_nullable_to_non_nullable + as double, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ScalePropsImplCopyWith<$Res> + implements $ScalePropsCopyWith<$Res> { + factory _$$ScalePropsImplCopyWith( + _$ScalePropsImpl value, $Res Function(_$ScalePropsImpl) then) = + __$$ScalePropsImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({bool custom, double scale}); +} + +/// @nodoc +class __$$ScalePropsImplCopyWithImpl<$Res> + extends _$ScalePropsCopyWithImpl<$Res, _$ScalePropsImpl> + implements _$$ScalePropsImplCopyWith<$Res> { + __$$ScalePropsImplCopyWithImpl( + _$ScalePropsImpl _value, $Res Function(_$ScalePropsImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? custom = null, + Object? scale = null, + }) { + return _then(_$ScalePropsImpl( + custom: null == custom + ? _value.custom + : custom // ignore: cast_nullable_to_non_nullable + as bool, + scale: null == scale + ? _value.scale + : scale // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ScalePropsImpl implements _ScaleProps { + const _$ScalePropsImpl( + {this.custom = false, this.scale = defaultCustomFontSizeScale}); + + factory _$ScalePropsImpl.fromJson(Map json) => + _$$ScalePropsImplFromJson(json); + + @override + @JsonKey() + final bool custom; + @override + @JsonKey() + final double scale; + + @override + String toString() { + return 'ScaleProps(custom: $custom, scale: $scale)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ScalePropsImpl && + (identical(other.custom, custom) || other.custom == custom) && + (identical(other.scale, scale) || other.scale == scale)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, custom, scale); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ScalePropsImplCopyWith<_$ScalePropsImpl> get copyWith => + __$$ScalePropsImplCopyWithImpl<_$ScalePropsImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ScalePropsImplToJson( + this, + ); + } +} + +abstract class _ScaleProps implements ScaleProps { + const factory _ScaleProps({final bool custom, final double scale}) = + _$ScalePropsImpl; + + factory _ScaleProps.fromJson(Map json) = + _$ScalePropsImpl.fromJson; + + @override + bool get custom; + @override + double get scale; + @override + @JsonKey(ignore: true) + _$$ScalePropsImplCopyWith<_$ScalePropsImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/generated/config.g.dart b/lib/models/generated/config.g.dart index 7a5819f..be970f2 100644 --- a/lib/models/generated/config.g.dart +++ b/lib/models/generated/config.g.dart @@ -53,6 +53,8 @@ Config _$ConfigFromJson(Map json) => Config() ..vpnProps = VpnProps.fromJson(json['vpnProps'] as Map?) ..desktopProps = DesktopProps.fromJson(json['desktopProps'] as Map?) + ..scaleProps = + ScaleProps.fromJson(json['scaleProps'] as Map?) ..showLabel = json['showLabel'] as bool? ?? false ..overrideDns = json['overrideDns'] as bool? ?? false; @@ -85,6 +87,7 @@ Map _$ConfigToJson(Config instance) => { 'windowProps': instance.windowProps, 'vpnProps': instance.vpnProps, 'desktopProps': instance.desktopProps, + 'scaleProps': instance.scaleProps, 'showLabel': instance.showLabel, 'overrideDns': instance.overrideDns, }; @@ -234,3 +237,15 @@ Map _$$DesktopPropsImplToJson(_$DesktopPropsImpl instance) => { 'systemProxy': instance.systemProxy, }; + +_$ScalePropsImpl _$$ScalePropsImplFromJson(Map json) => + _$ScalePropsImpl( + custom: json['custom'] as bool? ?? false, + scale: (json['scale'] as num?)?.toDouble() ?? defaultCustomFontSizeScale, + ); + +Map _$$ScalePropsImplToJson(_$ScalePropsImpl instance) => + { + 'custom': instance.custom, + 'scale': instance.scale, + }; diff --git a/lib/models/generated/dav.freezed.dart b/lib/models/generated/dav.freezed.dart index 5dea372..fab0cca 100644 --- a/lib/models/generated/dav.freezed.dart +++ b/lib/models/generated/dav.freezed.dart @@ -23,6 +23,7 @@ mixin _$DAV { String get uri => throw _privateConstructorUsedError; String get user => throw _privateConstructorUsedError; String get password => throw _privateConstructorUsedError; + String get fileName => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -34,7 +35,7 @@ abstract class $DAVCopyWith<$Res> { factory $DAVCopyWith(DAV value, $Res Function(DAV) then) = _$DAVCopyWithImpl<$Res, DAV>; @useResult - $Res call({String uri, String user, String password}); + $Res call({String uri, String user, String password, String fileName}); } /// @nodoc @@ -52,6 +53,7 @@ class _$DAVCopyWithImpl<$Res, $Val extends DAV> implements $DAVCopyWith<$Res> { Object? uri = null, Object? user = null, Object? password = null, + Object? fileName = null, }) { return _then(_value.copyWith( uri: null == uri @@ -66,6 +68,10 @@ class _$DAVCopyWithImpl<$Res, $Val extends DAV> implements $DAVCopyWith<$Res> { ? _value.password : password // ignore: cast_nullable_to_non_nullable as String, + fileName: null == fileName + ? _value.fileName + : fileName // ignore: cast_nullable_to_non_nullable + as String, ) as $Val); } } @@ -76,7 +82,7 @@ abstract class _$$DAVImplCopyWith<$Res> implements $DAVCopyWith<$Res> { __$$DAVImplCopyWithImpl<$Res>; @override @useResult - $Res call({String uri, String user, String password}); + $Res call({String uri, String user, String password, String fileName}); } /// @nodoc @@ -91,6 +97,7 @@ class __$$DAVImplCopyWithImpl<$Res> extends _$DAVCopyWithImpl<$Res, _$DAVImpl> Object? uri = null, Object? user = null, Object? password = null, + Object? fileName = null, }) { return _then(_$DAVImpl( uri: null == uri @@ -105,6 +112,10 @@ class __$$DAVImplCopyWithImpl<$Res> extends _$DAVCopyWithImpl<$Res, _$DAVImpl> ? _value.password : password // ignore: cast_nullable_to_non_nullable as String, + fileName: null == fileName + ? _value.fileName + : fileName // ignore: cast_nullable_to_non_nullable + as String, )); } } @@ -113,7 +124,10 @@ class __$$DAVImplCopyWithImpl<$Res> extends _$DAVCopyWithImpl<$Res, _$DAVImpl> @JsonSerializable() class _$DAVImpl implements _DAV { const _$DAVImpl( - {required this.uri, required this.user, required this.password}); + {required this.uri, + required this.user, + required this.password, + this.fileName = defaultDavFileName}); factory _$DAVImpl.fromJson(Map json) => _$$DAVImplFromJson(json); @@ -124,10 +138,13 @@ class _$DAVImpl implements _DAV { final String user; @override final String password; + @override + @JsonKey() + final String fileName; @override String toString() { - return 'DAV(uri: $uri, user: $user, password: $password)'; + return 'DAV(uri: $uri, user: $user, password: $password, fileName: $fileName)'; } @override @@ -138,12 +155,14 @@ class _$DAVImpl implements _DAV { (identical(other.uri, uri) || other.uri == uri) && (identical(other.user, user) || other.user == user) && (identical(other.password, password) || - other.password == password)); + other.password == password) && + (identical(other.fileName, fileName) || + other.fileName == fileName)); } @JsonKey(ignore: true) @override - int get hashCode => Object.hash(runtimeType, uri, user, password); + int get hashCode => Object.hash(runtimeType, uri, user, password, fileName); @JsonKey(ignore: true) @override @@ -163,7 +182,8 @@ abstract class _DAV implements DAV { const factory _DAV( {required final String uri, required final String user, - required final String password}) = _$DAVImpl; + required final String password, + final String fileName}) = _$DAVImpl; factory _DAV.fromJson(Map json) = _$DAVImpl.fromJson; @@ -174,6 +194,8 @@ abstract class _DAV implements DAV { @override String get password; @override + String get fileName; + @override @JsonKey(ignore: true) _$$DAVImplCopyWith<_$DAVImpl> get copyWith => throw _privateConstructorUsedError; diff --git a/lib/models/generated/dav.g.dart b/lib/models/generated/dav.g.dart index d321ac6..7d01b11 100644 --- a/lib/models/generated/dav.g.dart +++ b/lib/models/generated/dav.g.dart @@ -10,10 +10,12 @@ _$DAVImpl _$$DAVImplFromJson(Map json) => _$DAVImpl( uri: json['uri'] as String, user: json['user'] as String, password: json['password'] as String, + fileName: json['fileName'] as String? ?? defaultDavFileName, ); Map _$$DAVImplToJson(_$DAVImpl instance) => { 'uri': instance.uri, 'user': instance.user, 'password': instance.password, + 'fileName': instance.fileName, }; diff --git a/lib/models/generated/selector.freezed.dart b/lib/models/generated/selector.freezed.dart index e87814c..7dba063 100644 --- a/lib/models/generated/selector.freezed.dart +++ b/lib/models/generated/selector.freezed.dart @@ -3472,6 +3472,7 @@ mixin _$ClashConfigState { int get mixedPort => throw _privateConstructorUsedError; bool get allowLan => throw _privateConstructorUsedError; bool get ipv6 => throw _privateConstructorUsedError; + bool get overrideDns => throw _privateConstructorUsedError; String get geodataLoader => throw _privateConstructorUsedError; LogLevel get logLevel => throw _privateConstructorUsedError; String get externalController => throw _privateConstructorUsedError; @@ -3502,6 +3503,7 @@ abstract class $ClashConfigStateCopyWith<$Res> { {int mixedPort, bool allowLan, bool ipv6, + bool overrideDns, String geodataLoader, LogLevel logLevel, String externalController, @@ -3537,6 +3539,7 @@ class _$ClashConfigStateCopyWithImpl<$Res, $Val extends ClashConfigState> Object? mixedPort = null, Object? allowLan = null, Object? ipv6 = null, + Object? overrideDns = null, Object? geodataLoader = null, Object? logLevel = null, Object? externalController = null, @@ -3565,6 +3568,10 @@ class _$ClashConfigStateCopyWithImpl<$Res, $Val extends ClashConfigState> ? _value.ipv6 : ipv6 // ignore: cast_nullable_to_non_nullable as bool, + overrideDns: null == overrideDns + ? _value.overrideDns + : overrideDns // ignore: cast_nullable_to_non_nullable + as bool, geodataLoader: null == geodataLoader ? _value.geodataLoader : geodataLoader // ignore: cast_nullable_to_non_nullable @@ -3653,6 +3660,7 @@ abstract class _$$ClashConfigStateImplCopyWith<$Res> {int mixedPort, bool allowLan, bool ipv6, + bool overrideDns, String geodataLoader, LogLevel logLevel, String externalController, @@ -3688,6 +3696,7 @@ class __$$ClashConfigStateImplCopyWithImpl<$Res> Object? mixedPort = null, Object? allowLan = null, Object? ipv6 = null, + Object? overrideDns = null, Object? geodataLoader = null, Object? logLevel = null, Object? externalController = null, @@ -3716,6 +3725,10 @@ class __$$ClashConfigStateImplCopyWithImpl<$Res> ? _value.ipv6 : ipv6 // ignore: cast_nullable_to_non_nullable as bool, + overrideDns: null == overrideDns + ? _value.overrideDns + : overrideDns // ignore: cast_nullable_to_non_nullable + as bool, geodataLoader: null == geodataLoader ? _value.geodataLoader : geodataLoader // ignore: cast_nullable_to_non_nullable @@ -3783,6 +3796,7 @@ class _$ClashConfigStateImpl implements _ClashConfigState { {required this.mixedPort, required this.allowLan, required this.ipv6, + required this.overrideDns, required this.geodataLoader, required this.logLevel, required this.externalController, @@ -3808,6 +3822,8 @@ class _$ClashConfigStateImpl implements _ClashConfigState { @override final bool ipv6; @override + final bool overrideDns; + @override final String geodataLoader; @override final LogLevel logLevel; @@ -3856,7 +3872,7 @@ class _$ClashConfigStateImpl implements _ClashConfigState { @override String toString() { - return 'ClashConfigState(mixedPort: $mixedPort, allowLan: $allowLan, ipv6: $ipv6, geodataLoader: $geodataLoader, logLevel: $logLevel, externalController: $externalController, mode: $mode, findProcessMode: $findProcessMode, keepAliveInterval: $keepAliveInterval, unifiedDelay: $unifiedDelay, tcpConcurrent: $tcpConcurrent, hosts: $hosts, tun: $tun, dns: $dns, geoXUrl: $geoXUrl, rules: $rules, globalRealUa: $globalRealUa)'; + return 'ClashConfigState(mixedPort: $mixedPort, allowLan: $allowLan, ipv6: $ipv6, overrideDns: $overrideDns, geodataLoader: $geodataLoader, logLevel: $logLevel, externalController: $externalController, mode: $mode, findProcessMode: $findProcessMode, keepAliveInterval: $keepAliveInterval, unifiedDelay: $unifiedDelay, tcpConcurrent: $tcpConcurrent, hosts: $hosts, tun: $tun, dns: $dns, geoXUrl: $geoXUrl, rules: $rules, globalRealUa: $globalRealUa)'; } @override @@ -3869,6 +3885,8 @@ class _$ClashConfigStateImpl implements _ClashConfigState { (identical(other.allowLan, allowLan) || other.allowLan == allowLan) && (identical(other.ipv6, ipv6) || other.ipv6 == ipv6) && + (identical(other.overrideDns, overrideDns) || + other.overrideDns == overrideDns) && (identical(other.geodataLoader, geodataLoader) || other.geodataLoader == geodataLoader) && (identical(other.logLevel, logLevel) || @@ -3899,6 +3917,7 @@ class _$ClashConfigStateImpl implements _ClashConfigState { mixedPort, allowLan, ipv6, + overrideDns, geodataLoader, logLevel, externalController, @@ -3927,6 +3946,7 @@ abstract class _ClashConfigState implements ClashConfigState { {required final int mixedPort, required final bool allowLan, required final bool ipv6, + required final bool overrideDns, required final String geodataLoader, required final LogLevel logLevel, required final String externalController, @@ -3949,6 +3969,8 @@ abstract class _ClashConfigState implements ClashConfigState { @override bool get ipv6; @override + bool get overrideDns; + @override String get geodataLoader; @override LogLevel get logLevel; diff --git a/lib/models/selector.dart b/lib/models/selector.dart index 8bb363c..ff06789 100644 --- a/lib/models/selector.dart +++ b/lib/models/selector.dart @@ -228,6 +228,7 @@ class ClashConfigState with _$ClashConfigState { required int mixedPort, required bool allowLan, required bool ipv6, + required bool overrideDns, required String geodataLoader, required LogLevel logLevel, required String externalController, diff --git a/lib/state.dart b/lib/state.dart index ee98b03..28d217d 100644 --- a/lib/state.dart +++ b/lib/state.dart @@ -7,11 +7,15 @@ import 'package:fl_clash/plugins/service.dart'; import 'package:fl_clash/plugins/vpn.dart'; import 'package:fl_clash/widgets/scaffold.dart'; import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; import 'package:package_info_plus/package_info_plus.dart'; +import 'package:tray_manager/tray_manager.dart'; import 'package:url_launcher/url_launcher.dart'; import 'controller.dart'; +import 'enum/enum.dart'; +import 'l10n/l10n.dart'; import 'models/models.dart'; import 'common/common.dart'; @@ -23,11 +27,13 @@ class GlobalState { late PackageInfo packageInfo; Function? updateCurrentDelayDebounce; PageController? pageController; + late Measure measure; DateTime? startTime; final navigatorKey = GlobalKey(); late AppController appController; GlobalKey homeScaffoldKey = GlobalKey(); List updateFunctionLists = []; + var isTrayInit = false; bool get isStart => startTime != null && startTime!.isBeforeNow; @@ -190,6 +196,121 @@ class GlobalState { ); } + _updateOtherTray() async { + if (isTrayInit == false) { + await trayManager.setIcon( + other.getTrayIconPath(), + ); + await trayManager.setToolTip( + appName, + ); + isTrayInit = true; + } + } + + _updateLinuxTray() async { + await trayManager.destroy(); + await trayManager.setIcon( + other.getTrayIconPath(), + ); + await trayManager.setToolTip( + appName, + ); + } + + updateTray({ + required AppState appState, + required Config config, + required ClashConfig clashConfig, + }) async { + final appLocalizations = await AppLocalizations.load( + other.getLocaleForString(config.locale) ?? + WidgetsBinding.instance.platformDispatcher.locale, + ); + if (!Platform.isLinux) { + _updateOtherTray(); + } + List menuItems = []; + final showMenuItem = MenuItem( + label: appLocalizations.show, + onClick: (_) { + window?.show(); + }, + ); + menuItems.add(showMenuItem); + final startMenuItem = MenuItem.checkbox( + label: appState.isStart ? appLocalizations.stop : appLocalizations.start, + onClick: (_) async { + globalState.appController.updateStatus(!appState.isStart); + }, + checked: false, + ); + menuItems.add(startMenuItem); + menuItems.add(MenuItem.separator()); + for (final mode in Mode.values) { + menuItems.add( + MenuItem.checkbox( + label: Intl.message(mode.name), + onClick: (_) { + globalState.appController.clashConfig.mode = mode; + }, + checked: mode == appState.mode, + ), + ); + } + menuItems.add(MenuItem.separator()); + if (appState.isStart) { + menuItems.add( + MenuItem.checkbox( + label: appLocalizations.tun, + onClick: (_) { + final clashConfig = globalState.appController.clashConfig; + clashConfig.tun = clashConfig.tun.copyWith( + enable: !clashConfig.tun.enable, + ); + }, + checked: clashConfig.tun.enable, + ), + ); + menuItems.add( + MenuItem.checkbox( + label: appLocalizations.systemProxy, + onClick: (_) { + final config = globalState.appController.config; + config.desktopProps = config.desktopProps.copyWith( + systemProxy: !config.desktopProps.systemProxy, + ); + }, + checked: config.desktopProps.systemProxy, + ), + ); + menuItems.add(MenuItem.separator()); + } + final autoStartMenuItem = MenuItem.checkbox( + label: appLocalizations.autoLaunch, + onClick: (_) async { + globalState.appController.config.autoLaunch = + !globalState.appController.config.autoLaunch; + }, + checked: config.autoLaunch, + ); + menuItems.add(autoStartMenuItem); + menuItems.add(MenuItem.separator()); + final exitMenuItem = MenuItem( + label: appLocalizations.exit, + onClick: (_) async { + await globalState.appController.handleExit(); + }, + ); + menuItems.add(exitMenuItem); + final menu = Menu(); + menu.items = menuItems; + trayManager.setContextMenu(menu); + if (Platform.isLinux) { + _updateLinuxTray(); + } + } + changeProxy({ required Config config, required String groupName, diff --git a/lib/widgets/clash_container.dart b/lib/widgets/clash_container.dart index 6ccae7c..e7da16c 100644 --- a/lib/widgets/clash_container.dart +++ b/lib/widgets/clash_container.dart @@ -24,8 +24,9 @@ class _ClashContainerState extends State Function? updateClashConfigDebounce; Widget _updateContainer(Widget child) { - return Selector( - selector: (_, clashConfig) => ClashConfigState( + return Selector2( + selector: (_,config, clashConfig) => ClashConfigState( + overrideDns: config.overrideDns, mixedPort: clashConfig.mixedPort, allowLan: clashConfig.allowLan, ipv6: clashConfig.ipv6, diff --git a/lib/widgets/color_scheme_box.dart b/lib/widgets/color_scheme_box.dart index f0ef08b..6714f3d 100644 --- a/lib/widgets/color_scheme_box.dart +++ b/lib/widgets/color_scheme_box.dart @@ -33,66 +33,68 @@ class ColorSchemeBox extends StatelessWidget { @override Widget build(BuildContext context) { - return Theme( - data: _getTheme(context), - child: Builder( - builder: (context) { - final colorScheme = Theme.of(context).colorScheme; - return Stack( - children: [ - CommonCard( - isSelected: isSelected, - onPressed: onPressed, - selectWidget: Container( - alignment: Alignment.center, - child: const SelectIcon(), - ), - child: Container( - padding: const EdgeInsets.all(8), - child: ClipRRect( - borderRadius: BorderRadius.circular(36), - child: SizedBox( - width: 72, - height: 72, - child: Grid( - crossAxisCount: 2, - children: [ - GridItem( - mainAxisCellCount: 2, - child: Container( - color: colorScheme.primary, + return AspectRatio(aspectRatio: 1, + child: Theme( + data: _getTheme(context), + child: Builder( + builder: (context) { + final colorScheme = Theme.of(context).colorScheme; + return Stack( + children: [ + CommonCard( + isSelected: isSelected, + onPressed: onPressed, + selectWidget: Container( + alignment: Alignment.center, + child: const SelectIcon(), + ), + child: Container( + padding: const EdgeInsets.all(8), + child: ClipRRect( + borderRadius: BorderRadius.circular(36), + child: SizedBox( + width: 72, + height: 72, + child: Grid( + crossAxisCount: 2, + children: [ + GridItem( + mainAxisCellCount: 2, + child: Container( + color: colorScheme.primary, + ), ), - ), - GridItem( - mainAxisCellCount: 1, - child: Container( - color: colorScheme.secondary, + GridItem( + mainAxisCellCount: 1, + child: Container( + color: colorScheme.secondary, + ), ), - ), - GridItem( - mainAxisCellCount: 1, - child: Container( - color: colorScheme.tertiary, - ), - ) - ], + GridItem( + mainAxisCellCount: 1, + child: Container( + color: colorScheme.tertiary, + ), + ) + ], + ), ), ), ), ), - ), - if (primaryColor == null) - const Positioned( - bottom: 4, - right: 4, - child: Icon( - Icons.colorize, - size: 20, - ), - ) - ], - ); - }, + if (primaryColor == null) + const Positioned( + bottom: 4, + right: 4, + child: Icon( + Icons.colorize, + size: 20, + ), + ) + ], + ); + }, + ), ), ); } diff --git a/lib/widgets/input.dart b/lib/widgets/input.dart index 7fa3ef4..99fa42d 100644 --- a/lib/widgets/input.dart +++ b/lib/widgets/input.dart @@ -57,12 +57,14 @@ class InputDialog extends StatefulWidget { final String title; final String value; final String? suffixText; + final String? resetValue; const InputDialog({ super.key, required this.title, required this.value, this.suffixText, + this.resetValue, }); @override @@ -92,6 +94,13 @@ class _InputDialogState extends State { Navigator.of(context).pop(text); } + _handleReset() async { + if (widget.resetValue == null) { + return; + } + Navigator.of(context).pop(widget.resetValue); + } + @override Widget build(BuildContext context) { return AlertDialog( @@ -114,6 +123,16 @@ class _InputDialogState extends State { ), ), actions: [ + if (widget.resetValue != null && + textController.value.text != widget.resetValue) ...[ + TextButton( + onPressed: _handleReset, + child: Text(appLocalizations.reset), + ), + const SizedBox( + width: 4, + ), + ], TextButton( onPressed: _handleUpdate, child: Text(appLocalizations.submit), diff --git a/lib/widgets/line_chart.dart b/lib/widgets/line_chart.dart index 82956f8..d405858 100644 --- a/lib/widgets/line_chart.dart +++ b/lib/widgets/line_chart.dart @@ -120,9 +120,19 @@ class _LineChartState extends State Path getPath(List points, Size size) { final path = Path() ..moveTo(points[0].x * size.width, (1 - points[0].y) * size.height); - for (var i = 1; i < points.length; i++) { - path.lineTo(points[i].x * size.width, (1 - points[i].y) * size.height); + + for (var i = 1; i < points.length - 1; i++) { + final nextPoint = points[i + 1]; + final currentPoint = points[i]; + final midX = (currentPoint.x + nextPoint.x) / 2; + final midY = (currentPoint.y + nextPoint.y) / 2; + path.quadraticBezierTo( + currentPoint.x * size.width, (1 - currentPoint.y) * size.height, + midX * size.width, (1 - midY) * size.height, + ); } + path.lineTo(points.last.x * size.width, (1 - points.last.y) * size.height); + return path; } @@ -132,7 +142,7 @@ class _LineChartState extends State required progress, }) { nextPoints = getInterpolatePoints(prevPoints, points, progress); - Path setSize(Size size) { + return (size) { final prevPath = getPath(prevPoints, size); final nextPath = getPath(nextPoints, size); final prevMetric = prevPath.computeMetrics().first; @@ -143,9 +153,7 @@ class _LineChartState extends State 0, prevLength + (nextLength - prevLength) * progress, ); - } - - return setSize; + }; } @override diff --git a/lib/widgets/list.dart b/lib/widgets/list.dart index e419829..16195d0 100644 --- a/lib/widgets/list.dart +++ b/lib/widgets/list.dart @@ -50,12 +50,14 @@ class OpenDelegate extends Delegate { final String title; final double? extendPageWidth; final bool isBlur; + final bool isScaffold; const OpenDelegate({ required this.title, required this.widget, this.extendPageWidth, this.isBlur = true, + this.isScaffold = false, }); } @@ -92,12 +94,14 @@ class InputDelegate extends Delegate { final String value; final String? suffixText; final Function(String? value) onChanged; + final String? resetValue; const InputDelegate({ required this.title, required this.value, this.suffixText, required this.onChanged, + this.resetValue, }); } @@ -287,6 +291,7 @@ class ListItem extends StatelessWidget { title: openDelegate.title, extendPageWidth: openDelegate.extendPageWidth, isBlur: openDelegate.isBlur, + isScaffold: openDelegate.isScaffold, ); return; } @@ -332,6 +337,7 @@ class ListItem extends StatelessWidget { title: inputDelegate.title, value: inputDelegate.value, suffixText: inputDelegate.suffixText, + resetValue: inputDelegate.resetValue, ), ); inputDelegate.onChanged(value); diff --git a/lib/widgets/media_container.dart b/lib/widgets/media_container.dart new file mode 100644 index 0000000..d0c8770 --- /dev/null +++ b/lib/widgets/media_container.dart @@ -0,0 +1,35 @@ +import 'package:fl_clash/common/common.dart'; +import 'package:fl_clash/models/config.dart'; +import 'package:fl_clash/state.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class MediaContainer extends StatelessWidget { + final Widget child; + + const MediaContainer({ + super.key, + required this.child, + }); + + @override + Widget build(BuildContext context) { + return Selector( + selector: (_, config) => config.scaleProps, + builder: (_, props, child) { + return MediaQuery( + data: MediaQuery.of(context).copyWith( + textScaler: props.custom ? TextScaler.linear(props.scale) : null, + ), + child: Builder( + builder: (context) { + globalState.measure = Measure.of(context); + return child!; + }, + ), + ); + }, + child: child, + ); + } +} diff --git a/lib/widgets/sheet.dart b/lib/widgets/sheet.dart index 724a574..130d334 100644 --- a/lib/widgets/sheet.dart +++ b/lib/widgets/sheet.dart @@ -10,7 +10,7 @@ showExtendPage( required Widget body, required String title, double? extendPageWidth, - bool forceNotSide = false, + bool isScaffold = false, bool isBlur = true, Widget? action, }) { @@ -33,7 +33,7 @@ showExtendPage( ); return; } - final isNotSide = isMobile || forceNotSide; + final isNotSide = isMobile || isScaffold; navigator.push( ModalSideSheetRoute( modalBarrierColor: Colors.black38, diff --git a/lib/widgets/text.dart b/lib/widgets/text.dart index a2bee5d..7d4dec1 100644 --- a/lib/widgets/text.dart +++ b/lib/widgets/text.dart @@ -16,7 +16,7 @@ class TooltipText extends StatelessWidget { return LayoutBuilder( builder: (context, container) { final maxWidth = container.maxWidth; - final size = globalState.appController.measure.computeTextSize( + final size = globalState.measure.computeTextSize( text, ); if (maxWidth < size.width) { diff --git a/lib/widgets/tray_container.dart b/lib/widgets/tray_container.dart index 0a06aec..7ef0e42 100644 --- a/lib/widgets/tray_container.dart +++ b/lib/widgets/tray_container.dart @@ -22,7 +22,6 @@ class TrayContainer extends StatefulWidget { } class _TrayContainerState extends State with TrayListener { - var isTrayInit = false; @override void initState() { @@ -30,113 +29,6 @@ class _TrayContainerState extends State with TrayListener { trayManager.addListener(this); } - _updateOtherTray() async { - if (isTrayInit == false) { - await trayManager.setIcon( - other.getTrayIconPath(), - ); - await trayManager.setToolTip( - appName, - ); - isTrayInit = true; - } - } - - _updateLinuxTray() async { - await trayManager.destroy(); - await trayManager.setIcon( - other.getTrayIconPath(), - ); - await trayManager.setToolTip( - appName, - ); - } - - updateMenu(TrayContainerSelectorState state) { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (!Platform.isLinux) { - _updateOtherTray(); - } - List menuItems = []; - final showMenuItem = MenuItem( - label: appLocalizations.show, - onClick: (_) { - window?.show(); - }, - ); - menuItems.add(showMenuItem); - final startMenuItem = MenuItem.checkbox( - label: state.isStart ? appLocalizations.stop : appLocalizations.start, - onClick: (_) async { - globalState.appController.updateStatus(!state.isStart); - }, - checked: false, - ); - menuItems.add(startMenuItem); - menuItems.add(MenuItem.separator()); - for (final mode in Mode.values) { - menuItems.add( - MenuItem.checkbox( - label: Intl.message(mode.name), - onClick: (_) { - globalState.appController.clashConfig.mode = mode; - }, - checked: mode == state.mode, - ), - ); - } - menuItems.add(MenuItem.separator()); - if (state.isStart) { - menuItems.add( - MenuItem.checkbox( - label: appLocalizations.tun, - onClick: (_) { - final clashConfig = globalState.appController.clashConfig; - clashConfig.tun = - clashConfig.tun.copyWith(enable: !state.tunEnable); - }, - checked: state.tunEnable, - ), - ); - menuItems.add( - MenuItem.checkbox( - label: appLocalizations.systemProxy, - onClick: (_) { - final config = globalState.appController.config; - config.desktopProps = - config.desktopProps.copyWith(systemProxy: !state.systemProxy); - }, - checked: state.systemProxy, - ), - ); - menuItems.add(MenuItem.separator()); - } - final autoStartMenuItem = MenuItem.checkbox( - label: appLocalizations.autoLaunch, - onClick: (_) async { - globalState.appController.config.autoLaunch = - !globalState.appController.config.autoLaunch; - }, - checked: state.autoLaunch, - ); - menuItems.add(autoStartMenuItem); - menuItems.add(MenuItem.separator()); - final exitMenuItem = MenuItem( - label: appLocalizations.exit, - onClick: (_) async { - await globalState.appController.handleExit(); - }, - ); - menuItems.add(exitMenuItem); - final menu = Menu(); - menu.items = menuItems; - trayManager.setContextMenu(menu); - if (Platform.isLinux) { - _updateLinuxTray(); - } - }); - } - @override Widget build(BuildContext context) { return Selector3( @@ -149,8 +41,13 @@ class _TrayContainerState extends State with TrayListener { systemProxy: config.desktopProps.systemProxy, tunEnable: clashConfig.tun.enable, ), + shouldRebuild: (prev,next){ + if(prev != next){ + globalState.appController.updateTray(); + } + return prev != next; + }, builder: (_, state, child) { - updateMenu(state); return child!; }, child: widget.child, diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart index b7a96a0..a199899 100644 --- a/lib/widgets/widgets.dart +++ b/lib/widgets/widgets.dart @@ -28,3 +28,4 @@ export 'builder.dart'; export 'setting.dart'; export 'vpn_container.dart'; export 'input.dart'; +export 'media_container.dart'; diff --git a/plugins/flutter_distributor b/plugins/flutter_distributor index 7701c7b..4a8384e 160000 --- a/plugins/flutter_distributor +++ b/plugins/flutter_distributor @@ -1 +1 @@ -Subproject commit 7701c7be83d4b7fa91f9f16ee45dfcb8fc1e9645 +Subproject commit 4a8384e48a562bca652e1f9b3073e18999688f9d diff --git a/pubspec.yaml b/pubspec.yaml index ff96e1c..a314f27 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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.8.57+202409021 +version: 0.8.58+202409081 environment: sdk: '>=3.1.0 <4.0.0' flutter: 3.22.3 diff --git a/test/command_test.dart b/test/command_test.dart index be6097c..7200f5e 100644 --- a/test/command_test.dart +++ b/test/command_test.dart @@ -2,16 +2,14 @@ import 'dart:io'; +import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/common/other.dart'; import 'package:lpinyin/lpinyin.dart'; void main() { - final res = const [ - "https://doh.pub/dns-query", - "https://dns.alidns.com/dns-query" - ]; + final res = [1, 2, 3, 4, 5, 6,7,8,9,10,11]; - List.from(res)..remove("https://doh.pub/dns-query"); + print(res.batch(5)); } startService() async {