From 4e679f776eee47d7bc074c9bc1975e0fa80a5379 Mon Sep 17 00:00:00 2001 From: chen08209 Date: Sun, 9 Feb 2025 18:39:38 +0800 Subject: [PATCH] Optimize performance Update core Optimize core stability Fix linux tun authority check error Fix some issues --- .gitmodules | 6 + analysis_options.yaml | 27 +- .../kotlin/com/follow/clash/models/Props.kt | 3 +- .../com/follow/clash/plugins/VpnPlugin.kt | 9 +- .../clash/services/FlClashVpnService.kt | 20 +- build.yaml | 1 + core/Clash.Meta | 2 +- core/action.go | 78 +- core/common.go | 3 +- core/constant.go | 12 +- core/go.mod | 41 +- core/go.sum | 88 +- core/hub.go | 25 +- core/lib.go | 6 +- core/lib_android.go | 68 +- core/lib_no_android.go | 6 +- core/server.go | 8 +- core/state/state.go | 22 +- core/tun/tun.go | 2 +- lib/application.dart | 97 +- lib/clash/core.dart | 17 +- lib/clash/interface.dart | 32 +- lib/clash/lib.dart | 19 +- lib/clash/service.dart | 92 +- lib/common/color.dart | 2 +- lib/common/common.dart | 3 +- lib/common/constant.dart | 14 +- lib/common/function.dart | 18 +- lib/common/future.dart | 2 +- lib/common/http.dart | 10 +- lib/common/link.dart | 7 +- lib/common/list.dart | 17 +- lib/common/measure.dart | 15 +- lib/common/mixin.dart | 46 + lib/common/navigation.dart | 66 +- lib/common/navigator.dart | 8 +- lib/common/num.dart | 11 +- lib/common/preferences.dart | 33 +- lib/common/print.dart | 31 + lib/common/render.dart | 12 +- lib/common/request.dart | 48 +- lib/common/state.dart | 0 lib/common/string.dart | 13 +- lib/common/system.dart | 2 +- lib/common/tray.dart | 47 +- lib/common/view.dart | 20 - lib/common/window.dart | 13 +- lib/common/windows.dart | 3 +- lib/controller.dart | 557 +++-- lib/enum/enum.dart | 51 +- lib/fragments/access.dart | 739 +++--- lib/fragments/application_setting.dart | 443 ++-- lib/fragments/backup_and_recovery.dart | 280 +-- lib/fragments/config/dns.dart | 761 +++--- lib/fragments/config/general.dart | 593 +++-- lib/fragments/config/network.dart | 443 ++-- lib/fragments/connection/connections.dart | 117 +- lib/fragments/connection/item.dart | 17 +- lib/fragments/connection/requests.dart | 197 +- lib/fragments/dashboard/dashboard.dart | 148 +- .../dashboard/widgets/core_info.dart | 58 - .../dashboard/widgets/intranet_ip.dart | 20 +- .../dashboard/widgets/memory_info.dart | 12 +- .../dashboard/widgets/network_detection.dart | 246 +- .../dashboard/widgets/network_speed.dart | 9 +- .../dashboard/widgets/outbound_mode.dart | 11 +- .../dashboard/widgets/quick_options.dart | 237 +- .../dashboard/widgets/start_button.dart | 121 +- .../dashboard/widgets/traffic_usage.dart | 9 +- lib/fragments/hotkey.dart | 29 +- lib/fragments/logs.dart | 185 +- lib/fragments/profiles/custom_profile.dart | 54 + lib/fragments/profiles/profiles.dart | 239 +- lib/fragments/proxies/card.dart | 275 ++- lib/fragments/proxies/common.dart | 47 +- lib/fragments/proxies/list.dart | 174 +- lib/fragments/proxies/providers.dart | 75 +- lib/fragments/proxies/proxies.dart | 205 +- lib/fragments/proxies/setting.dart | 116 +- lib/fragments/proxies/tab.dart | 417 ++-- lib/fragments/resources.dart | 141 +- lib/fragments/theme.dart | 452 ++-- lib/fragments/tools.dart | 388 +-- lib/l10n/arb/intl_en.arb | 3 +- lib/l10n/arb/intl_zh_CN.arb | 3 +- lib/l10n/intl/messages_en.dart | 3 + lib/l10n/intl/messages_zh_CN.dart | 1 + lib/l10n/l10n.dart | 10 + lib/main.dart | 107 +- lib/manager/android_manager.dart | 46 +- lib/manager/app_state_manager.dart | 57 +- lib/manager/clash_manager.dart | 107 +- lib/manager/hotkey_manager.dart | 30 +- lib/manager/manager.dart | 1 - lib/manager/media_manager.dart | 18 - lib/manager/proxy_manager.dart | 36 +- lib/manager/tray_manager.dart | 44 +- lib/manager/vpn_manager.dart | 50 +- lib/manager/window_manager.dart | 69 +- lib/models/app.dart | 377 +-- lib/models/clash_config.dart | 630 ++--- lib/models/common.dart | 120 +- lib/models/config.dart | 448 +--- lib/models/core.dart | 17 +- lib/models/generated/app.freezed.dart | 567 +++++ .../generated/clash_config.freezed.dart | 1405 ++++++++++- lib/models/generated/clash_config.g.dart | 249 +- lib/models/generated/common.freezed.dart | 369 ++- lib/models/generated/common.g.dart | 26 +- lib/models/generated/config.freezed.dart | 764 +++++- lib/models/generated/config.g.dart | 126 +- lib/models/generated/core.freezed.dart | 325 +-- lib/models/generated/core.g.dart | 46 +- lib/models/generated/selector.freezed.dart | 2171 +++++------------ lib/models/profile.dart | 8 + lib/models/selector.dart | 109 +- lib/pages/home.dart | 241 +- lib/plugins/service.dart | 1 + lib/providers/app.dart | 339 +++ lib/providers/config.dart | 256 ++ lib/providers/generated/app.g.dart | 277 +++ lib/providers/generated/config.g.dart | 198 ++ lib/providers/generated/state.g.dart | 1633 +++++++++++++ lib/providers/providers.dart | 3 + lib/providers/state.dart | 450 ++++ lib/state.dart | 281 +-- lib/widgets/builder.dart | 142 +- lib/widgets/card.dart | 27 +- lib/widgets/color_scheme_box.dart | 8 +- lib/widgets/fade_box.dart | 86 + lib/widgets/input.dart | 4 +- lib/widgets/list.dart | 7 +- lib/widgets/open_container.dart | 247 +- lib/widgets/scaffold.dart | 12 +- lib/widgets/sheet.dart | 13 +- macos/Podfile.lock | 32 +- pubspec.lock | 132 +- pubspec.yaml | 14 +- 138 files changed, 13013 insertions(+), 8723 deletions(-) create mode 100644 lib/common/mixin.dart create mode 100644 lib/common/print.dart create mode 100644 lib/common/state.dart delete mode 100644 lib/common/view.dart delete mode 100644 lib/fragments/dashboard/widgets/core_info.dart create mode 100644 lib/fragments/profiles/custom_profile.dart delete mode 100644 lib/manager/media_manager.dart create mode 100644 lib/models/generated/app.freezed.dart create mode 100644 lib/providers/app.dart create mode 100644 lib/providers/config.dart create mode 100644 lib/providers/generated/app.g.dart create mode 100644 lib/providers/generated/config.g.dart create mode 100644 lib/providers/generated/state.g.dart create mode 100644 lib/providers/providers.dart create mode 100644 lib/providers/state.dart diff --git a/.gitmodules b/.gitmodules index cc523a9..7577fac 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,9 @@ path = plugins/flutter_distributor url = git@github.com:chen08209/flutter_distributor.git branch = FlClash +[submodule "plugins/tray_manager"] + path = plugins/tray_manager + url = git@github.com:chen08209/tray_manager.git + branch = main + + diff --git a/analysis_options.yaml b/analysis_options.yaml index 61b6c4d..0fbea86 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,29 +1,8 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. include: package:flutter_lints/flutter.yaml linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at - # https://dart-lang.github.io/linter/lints/index.html. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options +analyzer: + plugins: + - custom_lint diff --git a/android/app/src/main/kotlin/com/follow/clash/models/Props.kt b/android/app/src/main/kotlin/com/follow/clash/models/Props.kt index 673ba1a..9a7ed7b 100644 --- a/android/app/src/main/kotlin/com/follow/clash/models/Props.kt +++ b/android/app/src/main/kotlin/com/follow/clash/models/Props.kt @@ -7,6 +7,7 @@ enum class AccessControlMode { } data class AccessControl( + val enable: Boolean, val mode: AccessControlMode, val acceptList: List, val rejectList: List, @@ -17,7 +18,7 @@ data class CIDR(val address: InetAddress, val prefixLength: Int) data class VpnOptions( val enable: Boolean, val port: Int, - val accessControl: AccessControl?, + val accessControl: AccessControl, val allowBypass: Boolean, val systemProxy: Boolean, val bypassDomain: List, diff --git a/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt b/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt index f97bc7d..a5f2ffd 100644 --- a/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt +++ b/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt @@ -10,6 +10,7 @@ import android.net.NetworkCapabilities import android.net.NetworkRequest import android.os.Build import android.os.IBinder +import android.util.Log import androidx.core.content.getSystemService import com.follow.clash.FlClashApplication import com.follow.clash.GlobalState @@ -92,11 +93,13 @@ data object VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler { "setProtect" -> { val fd = call.argument("fd") - if (fd != null) { - if (flClashService is FlClashVpnService) { + if (fd != null && flClashService is FlClashVpnService) { + try { (flClashService as FlClashVpnService).protect(fd) + result.success(true) + } catch (e: RuntimeException) { + result.success(false) } - result.success(true) } else { result.success(false) } diff --git a/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt b/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt index 092be19..7f097ae 100644 --- a/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt +++ b/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt @@ -68,17 +68,19 @@ class FlClashVpnService : VpnService(), BaseServiceInterface { } addDnsServer(options.dnsServerAddress) setMtu(9000) - options.accessControl?.let { accessControl -> - when (accessControl.mode) { - AccessControlMode.acceptSelected -> { - (accessControl.acceptList + packageName).forEach { - addAllowedApplication(it) + options.accessControl.let { accessControl -> + if (accessControl.enable) { + when (accessControl.mode) { + AccessControlMode.acceptSelected -> { + (accessControl.acceptList + packageName).forEach { + addAllowedApplication(it) + } } - } - AccessControlMode.rejectSelected -> { - (accessControl.rejectList - packageName).forEach { - addDisallowedApplication(it) + AccessControlMode.rejectSelected -> { + (accessControl.rejectList - packageName).forEach { + addDisallowedApplication(it) + } } } } diff --git a/build.yaml b/build.yaml index a3bc328..5098650 100644 --- a/build.yaml +++ b/build.yaml @@ -5,6 +5,7 @@ targets: options: build_extensions: '^lib/models/{{}}.dart': 'lib/models/generated/{{}}.g.dart' + '^lib/providers/{{}}.dart': 'lib/providers/generated/{{}}.g.dart' freezed: options: build_extensions: diff --git a/core/Clash.Meta b/core/Clash.Meta index 0c03d8e..76b0d7e 160000 --- a/core/Clash.Meta +++ b/core/Clash.Meta @@ -1 +1 @@ -Subproject commit 0c03d8e4b4b9ab7648359a00b939cdee7b066605 +Subproject commit 76b0d7e8bcdaf952c35d71e6852866414a7e1f6e diff --git a/core/action.go b/core/action.go index 01995fd..aff017d 100644 --- a/core/action.go +++ b/core/action.go @@ -22,99 +22,99 @@ func (result ActionResult) Json() ([]byte, error) { return data, err } -func (action Action) wrapMessage(data interface{}) []byte { - sendAction := ActionResult{ +func (action Action) getResult(data interface{}) []byte { + resultAction := ActionResult{ Id: action.Id, Method: action.Method, Data: data, } - res, _ := sendAction.Json() + res, _ := resultAction.Json() return res } -func handleAction(action *Action, send func([]byte)) { +func handleAction(action *Action, result func(data interface{})) { switch action.Method { case initClashMethod: data := action.Data.(string) - send(action.wrapMessage(handleInitClash(data))) + result(handleInitClash(data)) return case getIsInitMethod: - send(action.wrapMessage(handleGetIsInit())) + result(handleGetIsInit()) return case forceGcMethod: handleForceGc() - send(action.wrapMessage(true)) + result(true) return case shutdownMethod: - send(action.wrapMessage(handleShutdown())) + result(handleShutdown()) return case validateConfigMethod: data := []byte(action.Data.(string)) - send(action.wrapMessage(handleValidateConfig(data))) + result(handleValidateConfig(data)) return case updateConfigMethod: data := []byte(action.Data.(string)) - send(action.wrapMessage(handleUpdateConfig(data))) + result(handleUpdateConfig(data)) return case getProxiesMethod: - send(action.wrapMessage(handleGetProxies())) + result(handleGetProxies()) return case changeProxyMethod: data := action.Data.(string) handleChangeProxy(data, func(value string) { - send(action.wrapMessage(value)) + result(value) }) return case getTrafficMethod: - send(action.wrapMessage(handleGetTraffic())) + result(handleGetTraffic()) return case getTotalTrafficMethod: - send(action.wrapMessage(handleGetTotalTraffic())) + result(handleGetTotalTraffic()) return case resetTrafficMethod: handleResetTraffic() - send(action.wrapMessage(true)) + result(true) return case asyncTestDelayMethod: data := action.Data.(string) handleAsyncTestDelay(data, func(value string) { - send(action.wrapMessage(value)) + result(value) }) return case getConnectionsMethod: - send(action.wrapMessage(handleGetConnections())) + result(handleGetConnections()) return case closeConnectionsMethod: - send(action.wrapMessage(handleCloseConnections())) + result(handleCloseConnections()) return case closeConnectionMethod: id := action.Data.(string) - send(action.wrapMessage(handleCloseConnection(id))) + result(handleCloseConnection(id)) return case getExternalProvidersMethod: - send(action.wrapMessage(handleGetExternalProviders())) + result(handleGetExternalProviders()) return case getExternalProviderMethod: externalProviderName := action.Data.(string) - send(action.wrapMessage(handleGetExternalProvider(externalProviderName))) + result(handleGetExternalProvider(externalProviderName)) case updateGeoDataMethod: paramsString := action.Data.(string) var params = map[string]string{} err := json.Unmarshal([]byte(paramsString), ¶ms) if err != nil { - send(action.wrapMessage(err.Error())) + result(err.Error()) return } geoType := params["geo-type"] geoName := params["geo-name"] handleUpdateGeoData(geoType, geoName, func(value string) { - send(action.wrapMessage(value)) + result(value) }) return case updateExternalProviderMethod: providerName := action.Data.(string) handleUpdateExternalProvider(providerName, func(value string) { - send(action.wrapMessage(value)) + result(value) }) return case sideLoadExternalProviderMethod: @@ -122,46 +122,56 @@ func handleAction(action *Action, send func([]byte)) { var params = map[string]string{} err := json.Unmarshal([]byte(paramsString), ¶ms) if err != nil { - send(action.wrapMessage(err.Error())) + result(err.Error()) return } providerName := params["providerName"] data := params["data"] handleSideLoadExternalProvider(providerName, []byte(data), func(value string) { - send(action.wrapMessage(value)) + result(value) }) return case startLogMethod: handleStartLog() - send(action.wrapMessage(true)) + result(true) return case stopLogMethod: handleStopLog() - send(action.wrapMessage(true)) + result(true) return case startListenerMethod: - send(action.wrapMessage(handleStartListener())) + result(handleStartListener()) return case stopListenerMethod: - send(action.wrapMessage(handleStopListener())) + result(handleStopListener()) return case getCountryCodeMethod: ip := action.Data.(string) handleGetCountryCode(ip, func(value string) { - send(action.wrapMessage(value)) + result(value) }) return case getMemoryMethod: handleGetMemory(func(value string) { - send(action.wrapMessage(value)) + result(value) }) return + case getProfileMethod: + profileId := action.Data.(string) + handleGetMemory(func(value string) { + result(handleGetProfile(profileId)) + }) + return + case setStateMethod: + data := action.Data.(string) + handleSetState(data) + result(true) default: - handle := nextHandle(action, send) + handle := nextHandle(action, result) if handle { return } else { - send(action.wrapMessage(action.DefaultValue)) + result(action.DefaultValue) } } } diff --git a/core/common.go b/core/common.go index 5f9855c..236457c 100644 --- a/core/common.go +++ b/core/common.go @@ -31,7 +31,7 @@ import ( var ( isRunning = false runLock sync.Mutex - ips = []string{"ipwho.is", "ifconfig.me", "icanhazip.com", "api.ip.sb", "ipinfo.io"} + ips = []string{"ipwho.is", "api.ip.sb", "ipapi.co", "ipinfo.io"} b, _ = batch.New[bool](context.Background(), batch.WithConcurrencyNum[bool](50)) ) @@ -215,6 +215,7 @@ func overwriteConfig(targetConfig *config.RawConfig, patchConfig config.RawConfi targetConfig.Tun.Device = patchConfig.Tun.Device targetConfig.Tun.DNSHijack = patchConfig.Tun.DNSHijack targetConfig.Tun.Stack = patchConfig.Tun.Stack + targetConfig.Tun.RouteAddress = patchConfig.Tun.RouteAddress targetConfig.GeodataLoader = patchConfig.GeodataLoader targetConfig.Profile.StoreSelected = false targetConfig.GeoXUrl = patchConfig.GeoXUrl diff --git a/core/constant.go b/core/constant.go index c869315..a9355f6 100644 --- a/core/constant.go +++ b/core/constant.go @@ -8,12 +8,11 @@ import ( ) type ConfigExtendedParams struct { - IsPatch bool `json:"is-patch"` - IsCompatible bool `json:"is-compatible"` - SelectedMap map[string]string `json:"selected-map"` - TestURL *string `json:"test-url"` - OverrideDns bool `json:"override-dns"` - OnlyStatisticsProxy bool `json:"only-statistics-proxy"` + IsPatch bool `json:"is-patch"` + IsCompatible bool `json:"is-compatible"` + SelectedMap map[string]string `json:"selected-map"` + TestURL *string `json:"test-url"` + OverrideDns bool `json:"override-dns"` } type GenerateConfigParams struct { @@ -80,6 +79,7 @@ const ( getAndroidVpnOptionsMethod Method = "getAndroidVpnOptions" getRunTimeMethod Method = "getRunTime" getCurrentProfileNameMethod Method = "getCurrentProfileName" + getProfileMethod Method = "getProfile" ) type Method string diff --git a/core/go.mod b/core/go.mod index b6f1cfc..30037f0 100644 --- a/core/go.mod +++ b/core/go.mod @@ -6,7 +6,7 @@ replace github.com/metacubex/mihomo => ./Clash.Meta require ( github.com/metacubex/mihomo v0.0.0-00010101000000-000000000000 - github.com/samber/lo v1.47.0 + github.com/samber/lo v1.49.1 ) require ( @@ -19,28 +19,28 @@ require ( github.com/buger/jsonparser v1.1.1 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/coreos/go-iptables v0.8.0 // indirect - github.com/dlclark/regexp2 v1.11.4 // indirect - github.com/ebitengine/purego v0.8.1 // indirect - github.com/enfein/mieru/v3 v3.10.0 // indirect + github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/ebitengine/purego v0.8.2 // indirect + github.com/enfein/mieru/v3 v3.11.2 // 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.2.0 // indirect + github.com/go-chi/chi/v5 v5.2.1 // indirect github.com/go-chi/render v1.0.3 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect 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.3.0 // indirect + github.com/gofrs/uuid/v5 v5.3.1 // indirect github.com/google/btree v1.1.3 // 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.2 // indirect - github.com/insomniacslk/dhcp v0.0.0-20241224095048-b56fa0d5f25d // indirect + github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 // indirect github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // indirect @@ -51,21 +51,22 @@ require ( github.com/mdlayher/socket v0.4.1 // indirect github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab // indirect github.com/metacubex/bbolt v0.0.0-20240822011022-aed6d4850399 // indirect - github.com/metacubex/chacha v0.1.0 // indirect + github.com/metacubex/chacha v0.1.1 // indirect github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a // indirect - github.com/metacubex/quic-go v0.48.3-0.20241126053724-b69fea3888da // indirect + github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996 // indirect github.com/metacubex/randv2 v0.2.0 // indirect - github.com/metacubex/sing-quic v0.0.0-20240827003841-cd97758ed8b4 // indirect + github.com/metacubex/reality v0.0.0-20250219003814-74e8d7850629 // indirect + github.com/metacubex/sing-quic v0.0.0-20250119013740-2a19cce83925 // 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.4.5 // indirect - github.com/metacubex/sing-vmess v0.1.9-0.20240719134745-1df6fb20bbf9 // indirect + github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82 // indirect github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 // indirect github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 // indirect github.com/metacubex/utls v1.6.6 // indirect github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 // indirect - github.com/miekg/dns v1.1.62 // indirect + github.com/miekg/dns v1.1.63 // indirect github.com/mroth/weightedrand/v2 v2.1.0 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect @@ -73,18 +74,18 @@ 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.4.0 // indirect + github.com/puzpuzpuz/xsync/v3 v3.5.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/cors v1.2.1 // 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 - github.com/sagernet/sing v0.5.1 // indirect + github.com/sagernet/sing v0.5.2 // indirect github.com/sagernet/sing-mux v0.2.1 // indirect github.com/sagernet/sing-shadowtls v0.1.5 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect - github.com/shirou/gopsutil/v4 v4.24.11 // indirect + github.com/shirou/gopsutil/v4 v4.25.1 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e // indirect @@ -101,13 +102,13 @@ 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.31.0 // indirect + golang.org/x/crypto v0.33.0 // indirect golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect golang.org/x/mod v0.20.0 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.24.0 // indirect google.golang.org/protobuf v1.34.2 // indirect diff --git a/core/go.sum b/core/go.sum index 7ada655..63b60b7 100644 --- a/core/go.sum +++ b/core/go.sum @@ -24,12 +24,12 @@ github.com/coreos/go-iptables v0.8.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.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= -github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE= -github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= -github.com/enfein/mieru/v3 v3.10.0 h1:KMnAtY4s8MB74sUg4GbvF9R9v3jkXPQTSkxPxl1emxQ= -github.com/enfein/mieru/v3 v3.10.0/go.mod h1:jH2nXzJSNUn6UWuzD8E8AsRVa9Ca0CqcTcr9Z+CJO1o= +github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I= +github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/enfein/mieru/v3 v3.11.2 h1:06KyGbXiiGz2nSHLJDOOkztAVY3cRr3wBMOpYxPotTo= +github.com/enfein/mieru/v3 v3.11.2/go.mod h1:XvVfNsM78lUMSlJJKXJZ0Hn3lAB2o/ETXTbb84x5egw= 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= @@ -43,8 +43,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos 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.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0= -github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= +github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= @@ -59,8 +59,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.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk= -github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/gofrs/uuid/v5 v5.3.1 h1:aPx49MwJbekCzOyhZDjJVb0hx3A0KLjlbLx6p2gY0p0= +github.com/gofrs/uuid/v5 v5.3.1/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/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= @@ -74,8 +74,8 @@ github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20241224095048-b56fa0d5f25d h1:VkCNWh6tuQLgDBc6KrUOz/L1mCUQGnR1Ujj8uTgpwwk= -github.com/insomniacslk/dhcp v0.0.0-20241224095048-b56fa0d5f25d/go.mod h1:VvGYjkZoJyKqlmT1yzakUs4mfKMNB0XdODP0+rdml6k= +github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 h1:q3OEI9RaN/wwcx+qgGo6ZaoJkCiDYe/gjDLfq7lQQF4= +github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905/go.mod h1:VvGYjkZoJyKqlmT1yzakUs4mfKMNB0XdODP0+rdml6k= 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= @@ -84,6 +84,7 @@ 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.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 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= @@ -98,26 +99,28 @@ github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab h1:Chbw+/31 github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab/go.mod h1:xVKK8jC5Sd3hfh7WjmCq+HorehIbrBijaUWmcuKjPcI= 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/chacha v0.1.1 h1:OHIv11Nd9CISAIzegpjfupIoZp9DYm6uQw41RxvmU/c= +github.com/metacubex/chacha v0.1.1/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-20241126021258-5b028898cc5a h1:cZ6oNVrsmsi3SNlnSnRio4zOgtQq+/XidwsaNgKICcg= github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a/go.mod h1:xBw/SYJPgUMPQ1tklV/brGn2nxhfr3BnvBzNlyi4Nic= -github.com/metacubex/quic-go v0.48.3-0.20241126053724-b69fea3888da h1:Mq6cbHbPTLLTUfA9scrwBmOGkvl6y99E3WmtMIMqo30= -github.com/metacubex/quic-go v0.48.3-0.20241126053724-b69fea3888da/go.mod h1:AiZ+UPgrkO1DTnmiAX4b+kRoV1Vfc65UkYD7RbFlIZA= +github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996 h1:B+AP/Pj2/jBDS/kCYjz/x+0BCOKfd2VODYevyeIt+Ds= +github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996/go.mod h1:ExVjGyEwTUjCFqx+5uxgV7MOoA3fZI+th4D40H35xmY= 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-20240827003841-cd97758ed8b4 h1:HobpULaPK6OoxrHMmgcwLkwwIduXVmwdcznwUfH1GQM= -github.com/metacubex/sing-quic v0.0.0-20240827003841-cd97758ed8b4/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8= +github.com/metacubex/reality v0.0.0-20250219003814-74e8d7850629 h1:aHsYiTvubfgMa3JMTDY//hDXVvFWrHg6ARckR52ttZs= +github.com/metacubex/reality v0.0.0-20250219003814-74e8d7850629/go.mod h1:TTeIOZLdGmzc07Oedn++vWUUfkZoXLF4sEMxWuhBFr8= +github.com/metacubex/sing-quic v0.0.0-20250119013740-2a19cce83925 h1:UkPoRAnoBQMn7IK5qpoIV3OejU15q+rqel3NrbSCFKA= +github.com/metacubex/sing-quic v0.0.0-20250119013740-2a19cce83925/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.4.5 h1:kWSyQzuzHI40r50OFBczfWIDvMBMy1RIk+JsXeBPRB0= github.com/metacubex/sing-tun v0.4.5/go.mod h1:V0N4rr0dWPBEE20ESkTXdbtx2riQYcb6YtwC5w/9wl0= -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-vmess v0.1.14-0.20250228002636-abc39e113b82 h1:zZp5uct9+/0Hb1jKGyqDjCU4/72t43rs7qOq3Rc9oU8= +github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82/go.mod h1:nE7Mdzj/QUDwgRi/8BASPtsxtIFZTHA4Yst5GgwbGCQ= github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 h1:Z6bNy0HLTjx6BKIkV48sV/yia/GP8Bnyb5JQuGgSGzg= github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589/go.mod h1:4NclTLIZuk+QkHVCGrP87rHi/y8YjgPytxTgApJNMhc= github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY= @@ -126,10 +129,11 @@ 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/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 h1:hJLQviGySBuaynlCwf/oYgIxbVbGRUIKZCxdya9YrbQ= github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181/go.mod h1:phewKljNYiTVT31Gcif8RiCKnTUOgVWFJjccqYM8s+Y= -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/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= +github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= 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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= @@ -149,8 +153,8 @@ 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.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4= -github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/puzpuzpuz/xsync/v3 v3.5.0 h1:i+cMcpEDY1BkNm7lPDkCtE4oElsYLn+EKF8kAu2vXT4= +github.com/puzpuzpuz/xsync/v3 v3.5.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= @@ -164,18 +168,18 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJ github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I= github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y= -github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.5.2 h1:2OZQJNKGtji/66QLxbf/T/dqtK/3+fF/zuHH9tsGK7M= +github.com/sagernet/sing v0.5.2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.2.1 h1:N/3MHymfnFZRd29tE3TaXwPUVVgKvxhtOkiCMLp9HVo= github.com/sagernet/sing-mux v0.2.1/go.mod h1:dm3BWL6NvES9pbib7llpylrq7Gq+LjlzG+0RacdxcyE= github.com/sagernet/sing-shadowtls v0.1.5 h1:uXxmq/HXh8DIiBGLzpMjCbWnzIAFs+lIxiTOjdgG5qo= github.com/sagernet/sing-shadowtls v0.1.5/go.mod h1:tvrDPTGLrSM46Wnf7mSr+L8NHvgvF8M4YnJF790rZX4= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo= -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/v4 v4.24.11 h1:WaU9xqGFKvFfsUv94SXcUPD7rCkU0vr/asVdQOBZNj8= -github.com/shirou/gopsutil/v4 v4.24.11/go.mod h1:s4D/wg+ag4rG0WO7AiTj2BeYCRhym0vM7DHbZRxnIT8= +github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew= +github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o= +github.com/shirou/gopsutil/v4 v4.25.1 h1:QSWkTc+fu9LTAWfkZwZ6j8MSUk4A2LV7rbH0ZqmLjXs= +github.com/shirou/gopsutil/v4 v4.25.1/go.mod h1:RoUCUpndaJFtT+2zsZzzmhvbfGoDCJ7nFXKJf8GqJbI= github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b h1:rXHg9GrUEtWZhEkrykicdND3VPjlVbYiLdX9J7gimS8= github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b/go.mod h1:X7qrxNQViEaAN9LNZOPl9PfvQtp3V3c7LTo0dvGi0fM= github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c h1:DjKMC30y6yjG3IxDaeAj3PCoRr+IsO+bzyT+Se2m2Hk= @@ -218,8 +222,8 @@ 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.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk= golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -228,11 +232,11 @@ 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.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.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= @@ -248,12 +252,12 @@ 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.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -263,8 +267,8 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/core/hub.go b/core/hub.go index 7c9e824..4ee8452 100644 --- a/core/hub.go +++ b/core/hub.go @@ -2,6 +2,7 @@ package main import ( "context" + "core/state" "encoding/json" "fmt" "github.com/metacubex/mihomo/adapter" @@ -26,10 +27,8 @@ import ( ) var ( - isInit = false - configParams = ConfigExtendedParams{ - OnlyStatisticsProxy: false, - } + isInit = false + configParams = ConfigExtendedParams{} externalProviders = map[string]cp.Provider{} logSubscriber observable.Subscription[log.Event] currentConfig *config.Config @@ -152,7 +151,7 @@ func handleChangeProxy(data string, fn func(string string)) { } func handleGetTraffic() string { - up, down := statistic.DefaultManager.Current(configParams.OnlyStatisticsProxy) + up, down := statistic.DefaultManager.Current(state.CurrentState.OnlyStatisticsProxy) traffic := map[string]int64{ "up": up, "down": down, @@ -166,7 +165,7 @@ func handleGetTraffic() string { } func handleGetTotalTraffic() string { - up, down := statistic.DefaultManager.Total(configParams.OnlyStatisticsProxy) + up, down := statistic.DefaultManager.Total(state.CurrentState.OnlyStatisticsProxy) traffic := map[string]int64{ "up": up, "down": down, @@ -179,6 +178,15 @@ func handleGetTotalTraffic() string { return string(data) } +func handleGetProfile(profileId string) string { + prof := getRawConfigWithId(profileId) + data, err := json.Marshal(prof) + if err != nil { + return "" + } + return string(data) +} + func handleResetTraffic() { statistic.DefaultManager.ResetStatistic() } @@ -220,6 +228,7 @@ func handleAsyncTestDelay(paramsString string, fn func(string)) { if params.TestUrl != "" { testUrl = params.TestUrl } + delayData.Url = testUrl delay, err := proxy.URLTest(ctx, testUrl, expectedStatus) if err != nil || delay == 0 { @@ -423,6 +432,10 @@ func handleGetMemory(fn func(value string)) { }() } +func handleSetState(params string) { + _ = json.Unmarshal([]byte(params), state.CurrentState) +} + func init() { adapter.UrlTestHook = func(url string, name string, delay uint16) { delayData := &Delay{ diff --git a/core/lib.go b/core/lib.go index 7bf49ab..9f2c037 100644 --- a/core/lib.go +++ b/core/lib.go @@ -49,8 +49,8 @@ func invokeAction(paramsChar *C.char, port C.longlong) { bridge.SendToPort(i, err.Error()) return } - go handleAction(action, func(bytes []byte) { - bridge.SendToPort(i, string(bytes)) + go handleAction(action, func(data interface{}) { + bridge.SendToPort(i, string(action.getResult(data))) }) } @@ -64,7 +64,7 @@ func sendMessage(message Message) { } bridge.SendToPort(messagePort, string(Action{ Method: messageMethod, - }.wrapMessage(res))) + }.getResult(res))) } //export startListener diff --git a/core/lib_android.go b/core/lib_android.go index 13fc641..880607e 100644 --- a/core/lib_android.go +++ b/core/lib_android.go @@ -52,18 +52,6 @@ func NewInvokeManager() *InvokeManager { } } -func (m *InvokeManager) load(id string) string { - res, ok := m.invokeMap.Load(id) - if ok { - return res.(string) - } - return "" -} - -func (m *InvokeManager) delete(id string) { - m.invokeMap.Delete(id) -} - func (m *InvokeManager) completer(id string, value string) { m.invokeMap.Store(id, value) m.chanLock.Lock() @@ -74,7 +62,7 @@ func (m *InvokeManager) completer(id string, value string) { m.chanLock.Unlock() } -func (m *InvokeManager) await(id string) { +func (m *InvokeManager) await(id string) string { m.chanLock.Lock() if _, ok := m.chanMap[id]; !ok { m.chanMap[id] = make(chan struct{}) @@ -85,12 +73,17 @@ func (m *InvokeManager) await(id string) { timeout := time.After(500 * time.Millisecond) select { case <-ch: - return + res, ok := m.invokeMap.Load(id) + m.invokeMap.Delete(id) + if ok { + return res.(string) + } else { + return "" + } case <-timeout: m.completer(id, "") - return + return "" } - } var ( @@ -195,7 +188,6 @@ func initSocketHook() { }) fdInvokeMap.await(id) - fdInvokeMap.delete(id) }) } } @@ -214,10 +206,7 @@ func init() { Id: id, Metadata: metadata, }) - processInvokeMap.await(id) - res := processInvokeMap.load(id) - processInvokeMap.delete(id) - return res, nil + return processInvokeMap.await(id), nil } } @@ -225,14 +214,14 @@ func handleGetAndroidVpnOptions() string { tunLock.Lock() defer tunLock.Unlock() options := state.AndroidVpnOptions{ - Enable: state.CurrentState.Enable, + Enable: state.CurrentState.VpnProps.Enable, Port: currentConfig.General.MixedPort, Ipv4Address: state.DefaultIpv4Address, Ipv6Address: state.GetIpv6Address(), - AccessControl: state.CurrentState.AccessControl, - SystemProxy: state.CurrentState.SystemProxy, - AllowBypass: state.CurrentState.AllowBypass, - RouteAddress: state.CurrentState.RouteAddress, + AccessControl: state.CurrentState.VpnProps.AccessControl, + SystemProxy: state.CurrentState.VpnProps.SystemProxy, + AllowBypass: state.CurrentState.VpnProps.AllowBypass, + RouteAddress: currentConfig.General.Tun.RouteAddress, BypassDomain: state.CurrentState.BypassDomain, DnsServerAddress: state.GetDnsServerAddress(), } @@ -244,10 +233,6 @@ func handleGetAndroidVpnOptions() string { return string(data) } -func handleSetState(params string) { - _ = json.Unmarshal([]byte(params), state.CurrentState) -} - func handleUpdateDns(value string) { go func() { log.Infoln("[DNS] updateDns %s", value) @@ -263,46 +248,41 @@ func handleGetCurrentProfileName() string { return state.CurrentState.CurrentProfileName } -func nextHandle(action *Action, send func([]byte)) bool { +func nextHandle(action *Action, result func(data interface{})) bool { switch action.Method { case startTunMethod: data := action.Data.(string) var fd int _ = json.Unmarshal([]byte(data), &fd) - send(action.wrapMessage(handleStartTun(fd))) + result(handleStartTun(fd)) return true case stopTunMethod: handleStopTun() - send(action.wrapMessage(true)) - return true - case setStateMethod: - data := action.Data.(string) - handleSetState(data) - send(action.wrapMessage(true)) + result(true) return true case getAndroidVpnOptionsMethod: - send(action.wrapMessage(handleGetAndroidVpnOptions())) + result(handleGetAndroidVpnOptions()) return true case updateDnsMethod: data := action.Data.(string) handleUpdateDns(data) - send(action.wrapMessage(true)) + result(true) return true case setFdMapMethod: fdId := action.Data.(string) handleSetFdMap(fdId) - send(action.wrapMessage(true)) + result(true) return true case setProcessMapMethod: data := action.Data.(string) handleSetProcessMap(data) - send(action.wrapMessage(true)) + result(true) return true case getRunTimeMethod: - send(action.wrapMessage(handleGetRunTime())) + result(handleGetRunTime()) return true case getCurrentProfileNameMethod: - send(action.wrapMessage(handleGetCurrentProfileName())) + result(handleGetCurrentProfileName()) return true } return false diff --git a/core/lib_no_android.go b/core/lib_no_android.go index 5285f72..84f10ce 100644 --- a/core/lib_no_android.go +++ b/core/lib_no_android.go @@ -2,10 +2,6 @@ package main -func nextHandle(action *Action) { - return action -} - -func nextHandle(action *Action, send func([]byte)) bool { +func nextHandle(action *Action, result func(data interface{})) bool { return false } diff --git a/core/server.go b/core/server.go index a7b3250..719a793 100644 --- a/core/server.go +++ b/core/server.go @@ -19,7 +19,7 @@ func sendMessage(message Message) { } send(Action{ Method: messageMethod, - }.wrapMessage(res)) + }.getResult(res)) } func send(data []byte) { @@ -61,12 +61,12 @@ func startServer(arg string) { return } - go handleAction(action, func(bytes []byte) { - send(bytes) + go handleAction(action, func(data interface{}) { + send(action.getResult(data)) }) } } -func nextHandle(action *Action, send func([]byte)) bool { +func nextHandle(action *Action, result func(data interface{})) bool { return false } diff --git a/core/state/state.go b/core/state/state.go index 992774e..9bbb6ca 100644 --- a/core/state/state.go +++ b/core/state/state.go @@ -1,7 +1,7 @@ -//go:build android && cgo - package state +import "net/netip" + var DefaultIpv4Address = "172.19.0.1/30" var DefaultDnsAddress = "172.19.0.2" var DefaultIpv6Address = "fdfe:dcba:9876::1/126" @@ -13,13 +13,14 @@ type AndroidVpnOptions struct { AllowBypass bool `json:"allowBypass"` SystemProxy bool `json:"systemProxy"` BypassDomain []string `json:"bypassDomain"` - RouteAddress []string `json:"routeAddress"` + RouteAddress []netip.Prefix `json:"routeAddress"` Ipv4Address string `json:"ipv4Address"` Ipv6Address string `json:"ipv6Address"` DnsServerAddress string `json:"dnsServerAddress"` } type AccessControl struct { + Enable bool `json:"enable"` Mode string `json:"mode"` AcceptList []string `json:"acceptList"` RejectList []string `json:"rejectList"` @@ -31,20 +32,23 @@ type AndroidVpnRawOptions struct { AccessControl *AccessControl `json:"accessControl"` AllowBypass bool `json:"allowBypass"` SystemProxy bool `json:"systemProxy"` - RouteAddress []string `json:"routeAddress"` Ipv6 bool `json:"ipv6"` - BypassDomain []string `json:"bypassDomain"` } type State struct { - AndroidVpnRawOptions - CurrentProfileName string `json:"currentProfileName"` + VpnProps AndroidVpnRawOptions `json:"vpn-props"` + CurrentProfileName string `json:"current-profile-name"` + OnlyStatisticsProxy bool `json:"only-statistics-proxy"` + BypassDomain []string `json:"bypass-domain"` } -var CurrentState = &State{} +var CurrentState = &State{ + OnlyStatisticsProxy: false, + CurrentProfileName: "", +} func GetIpv6Address() string { - if CurrentState.Ipv6 { + if CurrentState.VpnProps.Ipv6 { return DefaultIpv6Address } else { return "" diff --git a/core/tun/tun.go b/core/tun/tun.go index a95ca5a..8cae371 100644 --- a/core/tun/tun.go +++ b/core/tun/tun.go @@ -33,7 +33,7 @@ func Start(fd int, device string, stack constant.TUNStack) (*sing_tun.Listener, } prefix4 = append(prefix4, tempPrefix4) var prefix6 []netip.Prefix - if state.CurrentState.Ipv6 { + if state.CurrentState.VpnProps.Ipv6 { tempPrefix6, err := netip.ParsePrefix(state.DefaultIpv6Address) if err != nil { log.Errorln("startTUN error:", err) diff --git a/lib/application.dart b/lib/application.dart index 0ef7330..9662a37 100644 --- a/lib/application.dart +++ b/lib/application.dart @@ -7,57 +7,27 @@ import 'package:fl_clash/l10n/l10n.dart'; import 'package:fl_clash/manager/hotkey_manager.dart'; import 'package:fl_clash/manager/manager.dart'; import 'package:fl_clash/plugins/app.dart'; +import 'package:fl_clash/providers/config.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'controller.dart'; import 'models/models.dart'; import 'pages/pages.dart'; -runAppWithPreferences( - Widget child, { - required AppState appState, - required Config config, - required AppFlowingState appFlowingState, - required ClashConfig clashConfig, -}) { - runApp(MultiProvider( - providers: [ - ChangeNotifierProvider( - create: (_) => clashConfig, - ), - ChangeNotifierProvider( - create: (_) => config, - ), - ChangeNotifierProvider( - create: (_) => appFlowingState, - ), - ChangeNotifierProxyProvider2( - create: (_) => appState, - update: (_, config, clashConfig, appState) { - appState?.mode = clashConfig.mode; - appState?.selectedMap = config.currentSelectedMap; - return appState!; - }, - ) - ], - child: child, - )); -} - -class Application extends StatefulWidget { +class Application extends ConsumerStatefulWidget { const Application({ super.key, }); @override - State createState() => ApplicationState(); + ConsumerState createState() => ApplicationState(); } -class ApplicationState extends State { - late SystemColorSchemes systemColorSchemes; +class ApplicationState extends ConsumerState { + late ColorSchemes systemColorSchemes; Timer? _autoUpdateGroupTaskTimer; Timer? _autoUpdateProfilesTaskTimer; @@ -73,7 +43,7 @@ class ApplicationState extends State { ColorScheme _getAppColorScheme({ required Brightness brightness, int? primaryColor, - required SystemColorSchemes systemColorSchemes, + required ColorSchemes systemColorSchemes, }) { if (primaryColor != null) { return ColorScheme.fromSeed( @@ -81,7 +51,7 @@ class ApplicationState extends State { brightness: brightness, ); } else { - return systemColorSchemes.getSystemColorSchemeForBrightness(brightness); + return systemColorSchemes.getColorSchemeForBrightness(brightness); } } @@ -90,12 +60,21 @@ class ApplicationState extends State { super.initState(); _autoUpdateGroupTask(); _autoUpdateProfilesTask(); - globalState.appController = AppController(context); + globalState.appController = AppController(context, ref); globalState.measure = Measure.of(context); + ref.listenManual(themeSettingProvider.select((state) => state.fontFamily), + (prev, next) { + if (prev != next) { + globalState.measure = Measure.of( + context, + fontFamily: next.value, + ); + } + }, fireImmediately: true); WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { final currentContext = globalState.navigatorKey.currentContext; if (currentContext != null) { - globalState.appController = AppController(currentContext); + globalState.appController = AppController(currentContext, ref); } await globalState.appController.init(); globalState.appController.initLink(); @@ -167,7 +146,7 @@ class ApplicationState extends State { ColorScheme? lightDynamic, ColorScheme? darkDynamic, ) { - systemColorSchemes = SystemColorSchemes( + systemColorSchemes = ColorSchemes( lightColorScheme: lightDynamic, darkColorScheme: darkDynamic, ); @@ -180,15 +159,11 @@ class ApplicationState extends State { Widget build(context) { return _buildPlatformWrap( _buildWrap( - Selector2( - selector: (_, appState, config) => ApplicationSelectorState( - locale: config.appSetting.locale, - themeMode: config.themeProps.themeMode, - primaryColor: config.themeProps.primaryColor, - prueBlack: config.themeProps.prueBlack, - fontFamily: config.themeProps.fontFamily, - ), - builder: (_, state, child) { + Consumer( + builder: (_, ref, child) { + final locale = + ref.watch(appSettingProvider.select((state) => state.locale)); + final themeProps = ref.watch(themeSettingProvider); return DynamicColorBuilder( builder: (lightDynamic, darkDynamic) { _updateSystemColorSchemes(lightDynamic, darkDynamic); @@ -204,11 +179,9 @@ class ApplicationState extends State { return MessageManager( child: LayoutBuilder( builder: (_, container) { - final appController = globalState.appController; - final maxWidth = container.maxWidth; - if (appController.appState.viewWidth != maxWidth) { - globalState.appController.updateViewWidth(maxWidth); - } + globalState.appController.updateViewWidth( + container.maxWidth, + ); return _buildPage(child!); }, ), @@ -216,28 +189,28 @@ class ApplicationState extends State { }, scrollBehavior: BaseScrollBehavior(), title: appName, - locale: other.getLocaleForString(state.locale), + locale: other.getLocaleForString(locale), supportedLocales: AppLocalizations.delegate.supportedLocales, - themeMode: state.themeMode, + themeMode: themeProps.themeMode, theme: ThemeData( useMaterial3: true, - fontFamily: state.fontFamily.value, + fontFamily: themeProps.fontFamily.value, pageTransitionsTheme: _pageTransitionsTheme, colorScheme: _getAppColorScheme( brightness: Brightness.light, systemColorSchemes: systemColorSchemes, - primaryColor: state.primaryColor, + primaryColor: themeProps.primaryColor, ), ), darkTheme: ThemeData( useMaterial3: true, - fontFamily: state.fontFamily.value, + fontFamily: themeProps.fontFamily.value, pageTransitionsTheme: _pageTransitionsTheme, colorScheme: _getAppColorScheme( brightness: Brightness.dark, systemColorSchemes: systemColorSchemes, - primaryColor: state.primaryColor, - ).toPrueBlack(state.prueBlack), + primaryColor: themeProps.primaryColor, + ).toPrueBlack(themeProps.prueBlack), ), home: child, ); diff --git a/lib/clash/core.dart b/lib/clash/core.dart index e92831d..f44ba03 100644 --- a/lib/clash/core.dart +++ b/lib/clash/core.dart @@ -63,15 +63,16 @@ class ClashCore { } } - Future init({ - required ClashConfig clashConfig, - required Config config, - }) async { + Future init() async { await initGeo(); final homeDirPath = await appPath.homeDirPath; return await clashInterface.init(homeDirPath); } + Future setState(CoreState state) async { + return await clashInterface.setState(state); + } + shutdown() async { await clashInterface.shutdown(); } @@ -234,6 +235,14 @@ class ClashCore { return int.parse(value); } + Future getProfile(String id) async { + final res = await clashInterface.getProfile(id); + if (res.isEmpty) { + return null; + } + return ClashConfig.fromJson(json.decode(res)); + } + resetTraffic() { clashInterface.resetTraffic(); } diff --git a/lib/clash/interface.dart b/lib/clash/interface.dart index 4beead8..1d62631 100644 --- a/lib/clash/interface.dart +++ b/lib/clash/interface.dart @@ -2,12 +2,9 @@ import 'dart:async'; import 'dart:convert'; import 'package:fl_clash/clash/message.dart'; -import 'package:fl_clash/common/constant.dart'; -import 'package:fl_clash/common/future.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:flutter/material.dart' hide Action; mixin ClashInterface { Future init(String homeDir); @@ -66,6 +63,10 @@ mixin ClashInterface { FutureOr closeConnection(String id); FutureOr closeConnections(); + + FutureOr getProfile(String id); + + Future setState(CoreState state); } mixin AndroidClashInterface { @@ -73,8 +74,6 @@ mixin AndroidClashInterface { Future setProcessMap(ProcessMapItem item); - Future setState(CoreState state); - Future stopTun(); Future updateDns(String value); @@ -106,6 +105,7 @@ abstract class ClashHandlerInterface with ClashInterface { case ActionMethod.closeConnections: case ActionMethod.closeConnection: case ActionMethod.stopListener: + case ActionMethod.setState: completer?.complete(result.data as bool); return; case ActionMethod.changeProxy: @@ -137,7 +137,7 @@ abstract class ClashHandlerInterface with ClashInterface { completer?.complete(result.data); } } catch (_) { - debugPrint(result.id); + commonPrint.log(result.id); } } @@ -198,6 +198,14 @@ abstract class ClashHandlerInterface with ClashInterface { ); } + @override + Future setState(CoreState state) { + return invoke( + method: ActionMethod.setState, + data: json.encode(state), + ); + } + @override shutdown() async { return await invoke( @@ -232,6 +240,7 @@ abstract class ClashHandlerInterface with ClashInterface { return await invoke( method: ActionMethod.updateConfig, data: json.encode(updateConfigParams), + timeout: Duration(minutes: 2), ); } @@ -239,6 +248,7 @@ abstract class ClashHandlerInterface with ClashInterface { Future getProxies() { return invoke( method: ActionMethod.getProxies, + timeout: Duration(seconds: 5), ); } @@ -318,6 +328,14 @@ abstract class ClashHandlerInterface with ClashInterface { ); } + @override + Future getProfile(String id) { + return invoke( + method: ActionMethod.getProfile, + data: id, + ); + } + @override FutureOr getTotalTraffic() { return invoke( diff --git a/lib/clash/lib.dart b/lib/clash/lib.dart index ede3a31..a8182f4 100644 --- a/lib/clash/lib.dart +++ b/lib/clash/lib.dart @@ -67,7 +67,6 @@ class ClashLib extends ClashHandlerInterface with AndroidClashInterface { switch (result.method) { case ActionMethod.setFdMap: case ActionMethod.setProcessMap: - case ActionMethod.setState: case ActionMethod.stopTun: case ActionMethod.updateDns: completer?.complete(result.data as bool); @@ -123,14 +122,6 @@ class ClashLib extends ClashHandlerInterface with AndroidClashInterface { ); } - @override - Future setState(CoreState state) { - return invoke( - method: ActionMethod.setState, - data: json.encode(state), - ); - } - @override Future startTun(int fd) async { final res = await invoke( @@ -259,7 +250,7 @@ class ClashLibHandler { setProcessMap(ProcessMapItem processMapItem) { final processMapItemChar = - json.encode(processMapItem).toNativeUtf8().cast(); + json.encode(processMapItem).toNativeUtf8().cast(); clashFFI.setProcessMap(processMapItemChar); malloc.free(processMapItemChar); } @@ -321,10 +312,10 @@ class ClashLibHandler { } Future quickStart( - String homeDir, - UpdateConfigParams updateConfigParams, - CoreState state, - ) { + String homeDir, + UpdateConfigParams updateConfigParams, + CoreState state, + ) { final completer = Completer(); final receiver = ReceivePort(); receiver.listen((message) { diff --git a/lib/clash/service.dart b/lib/clash/service.dart index 096ee98..5723b41 100644 --- a/lib/clash/service.dart +++ b/lib/clash/service.dart @@ -6,6 +6,7 @@ import 'dart:typed_data'; import 'package:fl_clash/clash/interface.dart'; import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/models/core.dart'; +import 'package:fl_clash/state.dart'; class ClashService extends ClashHandlerInterface { static ClashService? _instance; @@ -14,6 +15,8 @@ class ClashService extends ClashHandlerInterface { Completer socketCompleter = Completer(); + bool isStarting = false; + Process? process; factory ClashService() { @@ -27,48 +30,61 @@ class ClashService extends ClashHandlerInterface { } _initServer() async { - final address = !Platform.isWindows - ? InternetAddress( - unixSocketPath, - type: InternetAddressType.unix, - ) - : InternetAddress( - localhost, - type: InternetAddressType.IPv4, - ); - await _deleteSocketFile(); - final server = await ServerSocket.bind( - address, - 0, - shared: true, - ); - serverCompleter.complete(server); - await for (final socket in server) { - await _destroySocket(); - socketCompleter.complete(socket); - socket - .transform( - StreamTransformer.fromHandlers( - handleData: (Uint8List data, EventSink sink) { - sink.add(utf8.decode(data, allowMalformed: true)); + runZonedGuarded(() async { + final address = !Platform.isWindows + ? InternetAddress( + unixSocketPath, + type: InternetAddressType.unix, + ) + : InternetAddress( + localhost, + type: InternetAddressType.IPv4, + ); + await _deleteSocketFile(); + final server = await ServerSocket.bind( + address, + 0, + shared: true, + ); + serverCompleter.complete(server); + await for (final socket in server) { + await _destroySocket(); + socketCompleter.complete(socket); + socket + .transform( + StreamTransformer.fromHandlers( + handleData: (Uint8List data, EventSink sink) { + sink.add(utf8.decode(data, allowMalformed: true)); + }, + ), + ) + .transform(LineSplitter()) + .listen( + (data) { + handleResult( + ActionResult.fromJson( + json.decode(data.trim()), + ), + ); }, - ), - ) - .transform(LineSplitter()) - .listen( - (data) { - handleResult( - ActionResult.fromJson( - json.decode(data.trim()), - ), - ); - }, - ); - } + ); + } + }, (error, stack) { + commonPrint.log(error.toString()); + if(error is SocketException){ + globalState.showNotifier(error.toString()); + globalState.appController.restartCore(); + } + }); } @override reStart() async { + if (isStarting == true) { + return; + } + isStarting = true; + socketCompleter = Completer(); if (process != null) { await shutdown(); } @@ -90,6 +106,7 @@ class ClashService extends ClashHandlerInterface { ], ); process!.stdout.listen((_) {}); + isStarting = false; } @override @@ -125,7 +142,6 @@ class ClashService extends ClashHandlerInterface { @override shutdown() async { - await super.shutdown(); if (Platform.isWindows) { await request.stopCoreByHelper(); } diff --git a/lib/common/color.dart b/lib/common/color.dart index e7caf0e..8ec7170 100644 --- a/lib/common/color.dart +++ b/lib/common/color.dart @@ -11,7 +11,7 @@ extension ColorExtension on Color { } Color get toSoft { - return withOpacity(0.12); + return withOpacity(0.15); } Color get toLittle { diff --git a/lib/common/common.dart b/lib/common/common.dart index 7a4d1b7..4245f4c 100644 --- a/lib/common/common.dart +++ b/lib/common/common.dart @@ -35,4 +35,5 @@ export 'tray.dart'; export 'window.dart'; export 'windows.dart'; export 'render.dart'; -export 'view.dart'; \ No newline at end of file +export 'mixin.dart'; +export 'print.dart'; \ No newline at end of file diff --git a/lib/common/constant.dart b/lib/common/constant.dart index 0e16980..d751c6c 100644 --- a/lib/common/constant.dart +++ b/lib/common/constant.dart @@ -11,6 +11,8 @@ import 'package:flutter/material.dart'; const appName = "FlClash"; const appHelperService = "FlClashHelperService"; const coreName = "clash.meta"; +const browserUa = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"; const packageName = "com.follow.clash"; final unixSocketPath = "/tmp/FlClashSocket_${Random().nextInt(10000)}.sock"; const helperPort = 47890; @@ -33,16 +35,6 @@ final double kHeaderHeight = system.isDesktop ? 40 : 28 : 0; -const GeoXMap defaultGeoXMap = { - "mmdb": - "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", - "asn": - "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb", - "geoip": - "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat", - "geosite": - "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat" -}; const profilesDirectoryName = "profiles"; const localhost = "127.0.0.1"; const clashConfigKey = "clash_config"; @@ -53,8 +45,6 @@ const repository = "chen08209/FlClash"; const defaultExternalController = "127.0.0.1:9090"; const maxMobileWidth = 600; const maxLaptopWidth = 840; -const geodataLoaderMemconservative = "memconservative"; -const geodataLoaderStandard = "standard"; const defaultTestUrl = "https://www.gstatic.com/generate_204"; final filter = ImageFilter.blur( sigmaX: 5, diff --git a/lib/common/function.dart b/lib/common/function.dart index c46a225..8fd8a9f 100644 --- a/lib/common/function.dart +++ b/lib/common/function.dart @@ -63,7 +63,23 @@ class Throttler { } } +Future retry({ + required Future Function() task, + int maxAttempts = 3, + required bool Function(T res) retryIf, + Duration delay = Duration.zero, +}) async { + int attempts = 0; + while (attempts < maxAttempts) { + final res = await task(); + if (!retryIf(res) || attempts >= maxAttempts) { + return res; + } + attempts++; + } + throw "unknown error"; +} final debouncer = Debouncer(); -final throttler = Throttler(); \ No newline at end of file +final throttler = Throttler(); diff --git a/lib/common/future.dart b/lib/common/future.dart index 339dcf2..d61f264 100644 --- a/lib/common/future.dart +++ b/lib/common/future.dart @@ -10,7 +10,7 @@ extension CompleterExt on Completer { FutureOr Function()? onTimeout, required String functionName, }) { - final realTimeout = timeout ?? const Duration(seconds: 1); + final realTimeout = timeout ?? const Duration(seconds: 30); Timer(realTimeout + commonDuration, () { if (onLast != null) { onLast(); diff --git a/lib/common/http.dart b/lib/common/http.dart index 2eb302e..44db07e 100644 --- a/lib/common/http.dart +++ b/lib/common/http.dart @@ -1,9 +1,8 @@ import 'dart:io'; -import 'package:flutter/cupertino.dart'; +import 'package:fl_clash/common/common.dart'; import '../state.dart'; -import 'constant.dart'; class FlClashHttpOverrides extends HttpOverrides { @override @@ -14,10 +13,9 @@ class FlClashHttpOverrides extends HttpOverrides { if ([localhost].contains(url.host)) { return "DIRECT"; } - final appController = globalState.appController; - final port = appController.clashConfig.mixedPort; - final isStart = appController.appFlowingState.isStart; - debugPrint("find $url proxy:$isStart"); + final port = globalState.config.patchClashConfig.mixedPort; + final isStart = globalState.appState.runTime != null; + commonPrint.log("find $url proxy:$isStart"); if (!isStart) return "DIRECT"; return "PROXY localhost:$port"; }; diff --git a/lib/common/link.dart b/lib/common/link.dart index e4d1de2..3e6d2da 100644 --- a/lib/common/link.dart +++ b/lib/common/link.dart @@ -1,7 +1,8 @@ import 'dart:async'; import 'package:app_links/app_links.dart'; -import 'package:flutter/material.dart'; + +import 'print.dart'; typedef InstallConfigCallBack = void Function(String url); @@ -15,11 +16,11 @@ class LinkManager { } initAppLinksListen(installConfigCallBack) async { - debugPrint("initAppLinksListen"); + commonPrint.log("initAppLinksListen"); destroy(); subscription = _appLinks.uriLinkStream.listen( (uri) { - debugPrint('onAppLink: $uri'); + commonPrint.log('onAppLink: $uri'); if (uri.host == 'install-config') { final parameters = uri.queryParameters; final url = parameters['url']; diff --git a/lib/common/list.dart b/lib/common/list.dart index 6107f6a..531d56a 100644 --- a/lib/common/list.dart +++ b/lib/common/list.dart @@ -2,9 +2,9 @@ import 'dart:collection'; class FixedList { final int maxLength; - final List _list = []; + final List _list; - FixedList(this.maxLength); + FixedList(this.maxLength, {List? list}) : _list = list ?? []; add(T item) { if (_list.length == maxLength) { @@ -13,11 +13,22 @@ class FixedList { _list.add(item); } + clear() { + _list.clear(); + } + List get list => List.unmodifiable(_list); int get length => _list.length; T operator [](int index) => _list[index]; + + FixedList copyWith() { + return FixedList( + maxLength, + list: _list, + ); + } } class FixedMap { @@ -36,7 +47,7 @@ class FixedMap { _queue.add(key); } - clear(){ + clear() { _map.clear(); _queue.clear(); } diff --git a/lib/common/measure.dart b/lib/common/measure.dart index cd148a2..0415d95 100644 --- a/lib/common/measure.dart +++ b/lib/common/measure.dart @@ -4,19 +4,26 @@ import 'package:flutter/material.dart'; class Measure { final TextScaler _textScale; - late BuildContext context; + final BuildContext context; + final String? _fontFamily; - Measure.of(this.context) + Measure.of(this.context, {String? fontFamily}) : _textScale = TextScaler.linear( WidgetsBinding.instance.platformDispatcher.textScaleFactor, - ); + ), + _fontFamily = fontFamily ?? ""; Size computeTextSize( Text text, { double maxWidth = double.infinity, }) { final textPainter = TextPainter( - text: TextSpan(text: text.data, style: text.style), + text: TextSpan( + text: text.data, + style: text.style?.copyWith( + fontFamily: _fontFamily, + ), + ), maxLines: text.maxLines, textScaler: _textScale, textDirection: text.textDirection ?? TextDirection.ltr, diff --git a/lib/common/mixin.dart b/lib/common/mixin.dart new file mode 100644 index 0000000..e29efbb --- /dev/null +++ b/lib/common/mixin.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:riverpod/riverpod.dart'; +import 'context.dart'; + +mixin AutoDisposeNotifierMixin on AutoDisposeNotifier { + set value(T value) { + state = value; + } + + @override + bool updateShouldNotify(previous, next) { + final res = super.updateShouldNotify(previous, next); + if (res) { + onUpdate(next); + } + return res; + } + + onUpdate(T value) {} +} + +mixin PageMixin on State { + void onPageShow() { + initPageState(); + } + + initPageState() { + WidgetsBinding.instance.addPostFrameCallback((_) { + final commonScaffoldState = context.commonScaffoldState; + commonScaffoldState?.actions = actions; + commonScaffoldState?.floatingActionButton = floatingActionButton; + commonScaffoldState?.onSearch = onSearch; + commonScaffoldState?.onKeywordsUpdate = onKeywordsUpdate; + }); + } + + void onPageHidden() {} + + List get actions => []; + + Widget? get floatingActionButton => null; + + Function(String)? get onSearch => null; + + Function(List)? get onKeywordsUpdate => null; +} diff --git a/lib/common/navigation.dart b/lib/common/navigation.dart index 0218416..5d2ccab 100644 --- a/lib/common/navigation.dart +++ b/lib/common/navigation.dart @@ -6,55 +6,81 @@ import 'package:flutter/material.dart'; class Navigation { static Navigation? _instance; - getItems({ + List getItems({ bool openLogs = false, bool hasProxies = false, }) { return [ const NavigationItem( icon: Icon(Icons.space_dashboard), - label: "dashboard", - fragment: DashboardFragment(), + label: PageLabel.dashboard, + fragment: DashboardFragment( + key: GlobalObjectKey(PageLabel.dashboard), + ), ), NavigationItem( - icon: const Icon(Icons.rocket), - label: "proxies", - fragment: const ProxiesFragment(), + icon: const Icon(Icons.article), + label: PageLabel.proxies, + fragment: const ProxiesFragment( + key: GlobalObjectKey( + PageLabel.proxies, + ), + ), modes: hasProxies ? [NavigationItemMode.mobile, NavigationItemMode.desktop] : [], ), const NavigationItem( icon: Icon(Icons.folder), - label: "profiles", - fragment: ProfilesFragment(), + label: PageLabel.profiles, + fragment: ProfilesFragment( + key: GlobalObjectKey( + PageLabel.profiles, + ), + ), ), const NavigationItem( icon: Icon(Icons.view_timeline), - label: "requests", - fragment: RequestsFragment(), + label: PageLabel.requests, + fragment: RequestsFragment( + key: GlobalObjectKey( + PageLabel.requests, + ), + ), description: "requestsDesc", modes: [NavigationItemMode.desktop, NavigationItemMode.more], ), const NavigationItem( icon: Icon(Icons.ballot), - label: "connections", - fragment: ConnectionsFragment(), + label: PageLabel.connections, + fragment: ConnectionsFragment( + key: GlobalObjectKey( + PageLabel.connections, + ), + ), description: "connectionsDesc", modes: [NavigationItemMode.desktop, NavigationItemMode.more], ), const NavigationItem( icon: Icon(Icons.storage), - label: "resources", + label: PageLabel.resources, description: "resourcesDesc", keep: false, - fragment: Resources(), + fragment: Resources( + key: GlobalObjectKey( + PageLabel.resources, + ), + ), modes: [NavigationItemMode.more], ), NavigationItem( icon: const Icon(Icons.adb), - label: "logs", - fragment: const LogsFragment(), + label: PageLabel.logs, + fragment: const LogsFragment( + key: GlobalObjectKey( + PageLabel.logs, + ), + ), description: "logsDesc", modes: openLogs ? [NavigationItemMode.desktop, NavigationItemMode.more] @@ -62,8 +88,12 @@ class Navigation { ), const NavigationItem( icon: Icon(Icons.construction), - label: "tools", - fragment: ToolsFragment(), + label: PageLabel.tools, + fragment: ToolsFragment( + key: GlobalObjectKey( + PageLabel.tools, + ), + ), modes: [NavigationItemMode.desktop, NavigationItemMode.mobile], ), ]; diff --git a/lib/common/navigator.dart b/lib/common/navigator.dart index 83fe288..b927c34 100644 --- a/lib/common/navigator.dart +++ b/lib/common/navigator.dart @@ -1,10 +1,12 @@ 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'; import 'package:flutter/material.dart'; class BaseNavigator { static Future push(BuildContext context, Widget child) async { - if (!globalState.appController.isMobileView) { + if (globalState.appState.viewMode != ViewMode.mobile) { return await Navigator.of(context).push( CommonDesktopRoute( builder: (context) => child, @@ -68,7 +70,7 @@ class CommonRoute extends MaterialPageRoute { Duration get transitionDuration => const Duration(milliseconds: 500); @override - Duration get reverseTransitionDuration => const Duration(milliseconds: 300); + Duration get reverseTransitionDuration => const Duration(milliseconds: 250); } final Animatable _kRightMiddleTween = Tween( @@ -272,7 +274,7 @@ class _CommonEdgeShadowPainter extends BoxPainter { return; } - final double shadowWidth = 0.05 * configuration.size!.width; + final double shadowWidth = 0.03 * configuration.size!.width; final double shadowHeight = configuration.size!.height; final double bandWidth = shadowWidth / (colors.length - 1); diff --git a/lib/common/num.dart b/lib/common/num.dart index acb8fab..b9503b7 100644 --- a/lib/common/num.dart +++ b/lib/common/num.dart @@ -2,8 +2,15 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; extension NumExt on num { - String fixed({digit = 2}) { - return toStringAsFixed(truncateToDouble() == this ? 0 : digit); + String fixed({decimals = 2}) { + String formatted = toStringAsFixed(decimals); + if (formatted.contains('.')) { + formatted = formatted.replaceAll(RegExp(r'0*$'), ''); + if (formatted.endsWith('.')) { + formatted = formatted.substring(0, formatted.length - 1); + } + } + return formatted; } } diff --git a/lib/common/preferences.dart b/lib/common/preferences.dart index 18064f9..8cc63ce 100644 --- a/lib/common/preferences.dart +++ b/lib/common/preferences.dart @@ -4,18 +4,19 @@ import 'dart:convert'; import 'package:fl_clash/models/models.dart'; import 'package:shared_preferences/shared_preferences.dart'; - import 'constant.dart'; class Preferences { static Preferences? _instance; Completer sharedPreferencesCompleter = Completer(); - Future get isInit async => await sharedPreferencesCompleter.future != null; + Future get isInit async => + await sharedPreferencesCompleter.future != null; Preferences._internal() { - SharedPreferences.getInstance().then((value) => sharedPreferencesCompleter.complete(value)) - .onError((_,__)=>sharedPreferencesCompleter.complete(null)); + SharedPreferences.getInstance() + .then((value) => sharedPreferencesCompleter.complete(value)) + .onError((_, __) => sharedPreferencesCompleter.complete(null)); } factory Preferences() { @@ -23,7 +24,6 @@ class Preferences { return _instance!; } - Future getClashConfig() async { final preferences = await sharedPreferencesCompleter.future; final clashConfigString = preferences?.getString(clashConfigKey); @@ -32,29 +32,26 @@ class Preferences { return ClashConfig.fromJson(clashConfigMap); } - Future saveClashConfig(ClashConfig clashConfig) async { - final preferences = await sharedPreferencesCompleter.future; - preferences?.setString( - clashConfigKey, - json.encode(clashConfig), - ); - return true; - } - Future getConfig() async { final preferences = await sharedPreferencesCompleter.future; final configString = preferences?.getString(configKey); if (configString == null) return null; final configMap = json.decode(configString); - return Config.fromJson(configMap); + return Config.compatibleFromJson(configMap); } Future saveConfig(Config config) async { final preferences = await sharedPreferencesCompleter.future; return await preferences?.setString( - configKey, - json.encode(config), - ) ?? false; + configKey, + json.encode(config), + ) ?? + false; + } + + clearClashConfig() async { + final preferences = await sharedPreferencesCompleter.future; + preferences?.remove(clashConfigKey); } clearPreferences() async { diff --git a/lib/common/print.dart b/lib/common/print.dart new file mode 100644 index 0000000..7be5625 --- /dev/null +++ b/lib/common/print.dart @@ -0,0 +1,31 @@ +import 'package:fl_clash/enum/enum.dart'; +import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/state.dart'; +import 'package:flutter/cupertino.dart'; + +class CommonPrint { + static CommonPrint? _instance; + + CommonPrint._internal(); + + factory CommonPrint() { + _instance ??= CommonPrint._internal(); + return _instance!; + } + + log(String? text) { + final payload = "[FlClash] $text"; + debugPrint(payload); + if (globalState.isService) { + return; + } + globalState.appController.addLog( + Log( + logLevel: LogLevel.info, + payload: payload, + ), + ); + } +} + +final commonPrint = CommonPrint(); diff --git a/lib/common/render.dart b/lib/common/render.dart index 3689871..ae48ac4 100644 --- a/lib/common/render.dart +++ b/lib/common/render.dart @@ -1,5 +1,5 @@ import 'package:fl_clash/common/common.dart'; -import 'package:flutter/cupertino.dart'; +import 'package:fl_clash/enum/enum.dart'; import 'package:flutter/scheduler.dart'; class Render { @@ -23,14 +23,14 @@ class Render { pause() { debouncer.call( - "render_pause", + DebounceTag.renderPause, _pause, - duration: Duration(seconds: 5), + duration: Duration(seconds: 15), ); } resume() { - debouncer.cancel("render_pause"); + debouncer.cancel(DebounceTag.renderPause); _resume(); } @@ -41,7 +41,7 @@ class Render { _drawFrame = _dispatcher.onDrawFrame; _dispatcher.onBeginFrame = null; _dispatcher.onDrawFrame = null; - debugPrint("[App] pause"); + commonPrint.log("pause"); } void _resume() { @@ -50,7 +50,7 @@ class Render { _dispatcher.onBeginFrame = _beginFrame; _dispatcher.onDrawFrame = _drawFrame; _dispatcher.scheduleFrame(); - debugPrint("[App] resume"); + commonPrint.log("resume"); } } diff --git a/lib/common/request.dart b/lib/common/request.dart index 956edc0..a10fcd3 100644 --- a/lib/common/request.dart +++ b/lib/common/request.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'dart:typed_data'; import 'package:dio/dio.dart'; -import 'package:fl_clash/clash/clash.dart'; import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/models/models.dart'; import 'package:fl_clash/state.dart'; @@ -14,11 +13,10 @@ class Request { String? userAgent; Request() { - _dio = Dio(); - _dio.interceptors.add( - InterceptorsWrapper( - onRequest: (options, handler) { - return handler.next(options); // 继续请求 + _dio = Dio( + BaseOptions( + headers: { + "User-Agent": browserUa, }, ), ); @@ -30,7 +28,7 @@ class Request { url, options: Options( headers: { - "User-Agent": globalState.appController.clashConfig.globalUa + "User-Agent": globalState.ua, }, responseType: ResponseType.bytes, ), @@ -71,31 +69,32 @@ class Request { return data; } - final List _ipInfoSources = [ - "https://ipwho.is/?fields=ip&output=csv", - "https://ipinfo.io/ip", - "https://ifconfig.me/ip/", - ]; + final Map)> _ipInfoSources = { + "https://ipwho.is/": IpInfo.fromIpwhoIsJson, + "https://api.ip.sb/geoip/": IpInfo.fromIpSbJson, + "https://ipapi.co/json/": IpInfo.fromIpApiCoJson, + "https://ipinfo.io/json/": IpInfo.fromIpInfoIoJson, + }; Future checkIp({CancelToken? cancelToken}) async { - for (final source in _ipInfoSources) { + for (final source in _ipInfoSources.entries) { try { - final response = await _dio - .get( - source, - cancelToken: cancelToken, - ) - .timeout(httpTimeoutDuration); + final response = await _dio.get>( + source.key, + cancelToken: cancelToken, + options: Options( + responseType: ResponseType.json, + ), + ); if (response.statusCode != 200 || response.data == null) { continue; } - final ipInfo = await clashCore.getCountryCode(response.data!); - if (ipInfo == null && source != _ipInfoSources.last) { + if (response.data == null) { continue; } - return ipInfo; + return source.value(response.data!); } catch (e) { - debugPrint("checkIp error ===> $e"); + commonPrint.log("checkIp error ===> $e"); if (e is DioException && e.type == DioExceptionType.cancel) { throw "cancelled"; } @@ -110,6 +109,9 @@ class Request { .get( "http://$localhost:$helperPort/ping", options: Options( + headers: { + "User-Agent": browserUa, + }, responseType: ResponseType.plain, ), ) diff --git a/lib/common/state.dart b/lib/common/state.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/common/string.dart b/lib/common/string.dart index ec66eed..b4ccaeb 100644 --- a/lib/common/string.dart +++ b/lib/common/string.dart @@ -1,7 +1,7 @@ import 'dart:convert'; import 'dart:typed_data'; -import 'package:flutter/material.dart'; +import 'print.dart'; extension StringExtension on String { bool get isUrl { @@ -43,8 +43,17 @@ extension StringExtension on String { RegExp(this); return true; } catch (e) { - debugPrint(e.toString()); + commonPrint.log(e.toString()); return false; } } } + +extension StringExtensionSafe on String? { + String getSafeValue(String defaultValue) { + if (this == null || this!.isEmpty) { + return defaultValue; + } + return this!; + } +} diff --git a/lib/common/system.dart b/lib/common/system.dart index be68099..e0eadf9 100644 --- a/lib/common/system.dart +++ b/lib/common/system.dart @@ -46,7 +46,7 @@ class System { } else if (Platform.isLinux) { final result = await Process.run('stat', ['-c', '%U:%G %A', corePath]); final output = result.stdout.trim(); - if (output.startsWith('root:') && output.contains('rwx')) { + if (output.startsWith('root:') && output.contains('rws')) { return true; } return false; diff --git a/lib/common/tray.dart b/lib/common/tray.dart index 8ae4e83..69ace6d 100644 --- a/lib/common/tray.dart +++ b/lib/common/tray.dart @@ -39,10 +39,7 @@ class Tray { } update({ - required AppState appState, - required AppFlowingState appFlowingState, - required Config config, - required ClashConfig clashConfig, + required TrayState trayState, bool focus = false, }) async { if (Platform.isAndroid) { @@ -50,7 +47,7 @@ class Tray { } if (!Platform.isLinux) { await _updateSystemTray( - brightness: appState.brightness, + brightness: trayState.brightness, force: focus, ); } @@ -63,9 +60,7 @@ class Tray { ); menuItems.add(showMenuItem); final startMenuItem = MenuItem.checkbox( - label: appFlowingState.isStart - ? appLocalizations.stop - : appLocalizations.start, + label: trayState.isStart ? appLocalizations.stop : appLocalizations.start, onClick: (_) async { globalState.appController.updateStart(); }, @@ -80,23 +75,22 @@ class Tray { onClick: (_) { globalState.appController.changeMode(mode); }, - checked: mode == clashConfig.mode, + checked: mode == trayState.mode, ), ); } menuItems.add(MenuItem.separator()); if (!Platform.isWindows) { - final groups = appState.currentGroups; - for (final group in groups) { + for (final group in trayState.groups) { List subMenuItems = []; for (final proxy in group.all) { subMenuItems.add( MenuItem.checkbox( label: proxy.name, - checked: appState.selectedMap[group.name] == proxy.name, + checked: trayState.selectedMap[group.name] == proxy.name, onClick: (_) { final appController = globalState.appController; - appController.config.updateCurrentSelectedMap( + appController.updateCurrentSelectedMap( group.name, proxy.name, ); @@ -117,18 +111,18 @@ class Tray { ), ); } - if (groups.isNotEmpty) { + if (trayState.groups.isNotEmpty) { menuItems.add(MenuItem.separator()); } } - if (appFlowingState.isStart) { + if (trayState.isStart) { menuItems.add( MenuItem.checkbox( label: appLocalizations.tun, onClick: (_) { globalState.appController.updateTun(); }, - checked: clashConfig.tun.enable, + checked: trayState.tunEnable, ), ); menuItems.add( @@ -137,7 +131,7 @@ class Tray { onClick: (_) { globalState.appController.updateSystemProxy(); }, - checked: config.networkProps.systemProxy, + checked: trayState.systemProxy, ), ); menuItems.add(MenuItem.separator()); @@ -147,12 +141,12 @@ class Tray { onClick: (_) async { globalState.appController.updateAutoLaunch(); }, - checked: config.appSetting.autoLaunch, + checked: trayState.autoLaunch, ); final copyEnvVarMenuItem = MenuItem( label: appLocalizations.copyEnvVar, onClick: (_) async { - await _copyEnv(clashConfig.mixedPort); + await _copyEnv(trayState.port); }, ); menuItems.add(autoStartMenuItem); @@ -169,12 +163,25 @@ class Tray { await trayManager.setContextMenu(menu); if (Platform.isLinux) { await _updateSystemTray( - brightness: appState.brightness, + brightness: trayState.brightness, force: focus, ); } } + updateTrayTitle([Traffic? traffic]) async { + // if (!Platform.isMacOS) { + // return; + // } + // if (traffic == null) { + // await trayManager.setTitle(""); + // } else { + // await trayManager.setTitle( + // "${traffic.up.shortShow} ↑ \n${traffic.down.shortShow} ↓", + // ); + // } + } + Future _copyEnv(int port) async { final url = "http://127.0.0.1:$port"; diff --git a/lib/common/view.dart b/lib/common/view.dart deleted file mode 100644 index a118b37..0000000 --- a/lib/common/view.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:flutter/material.dart'; -import 'context.dart'; - -mixin ViewMixin on State { - List get actions => []; - - Widget? get floatingActionButton => null; - - initViewState() { - final commonScaffoldState = context.commonScaffoldState; - commonScaffoldState?.actions = actions; - commonScaffoldState?.floatingActionButton = floatingActionButton; - commonScaffoldState?.onSearch = onSearch; - commonScaffoldState?.onKeywordsUpdate = onKeywordsUpdate; - } - - Function(String)? get onSearch => null; - - Function(List)? get onKeywordsUpdate => null; -} diff --git a/lib/common/window.dart b/lib/common/window.dart index 575308f..384ccc2 100755 --- a/lib/common/window.dart +++ b/lib/common/window.dart @@ -1,13 +1,14 @@ import 'dart:io'; 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:screen_retriever/screen_retriever.dart'; import 'package:window_manager/window_manager.dart'; class Window { - init(WindowProps props, int version) async { + init(int version) async { + final props = globalState.config.windowProps; final acquire = await singleInstanceLock.acquire(); if (!acquire) { exit(0); @@ -24,6 +25,8 @@ class Window { ); if (!Platform.isMacOS || version > 10) { await windowManager.setTitleBarStyle(TitleBarStyle.hidden); + } + if(!Platform.isMacOS){ final left = props.left ?? 0; final top = props.top ?? 0; final right = left + props.width; @@ -33,7 +36,7 @@ class Window { } else { final displays = await screenRetriever.getAllDisplays(); final isPositionValid = displays.any( - (display) { + (display) { final displayBounds = Rect.fromLTWH( display.visiblePosition!.dx, display.visiblePosition!.dy, @@ -60,10 +63,10 @@ class Window { } show() async { + render?.resume(); await windowManager.show(); await windowManager.focus(); await windowManager.setSkipTaskbar(false); - render?.resume(); } Future isVisible() async { @@ -75,9 +78,9 @@ class Window { } hide() async { + render?.pause(); await windowManager.hide(); await windowManager.setSkipTaskbar(true); - render?.pause(); } } diff --git a/lib/common/windows.dart b/lib/common/windows.dart index af95d75..f23de1a 100644 --- a/lib/common/windows.dart +++ b/lib/common/windows.dart @@ -4,7 +4,6 @@ import 'dart:io'; import 'package:ffi/ffi.dart'; import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/enum/enum.dart'; -import 'package:flutter/cupertino.dart'; import 'package:path/path.dart'; class Windows { @@ -54,7 +53,7 @@ class Windows { calloc.free(argumentsPtr); calloc.free(operationPtr); - debugPrint("[Windows] runas: $command $arguments resultCode:$result"); + commonPrint.log("windows runas: $command $arguments resultCode:$result"); if (result < 42) { return false; diff --git a/lib/controller.dart b/lib/controller.dart index 9ace234..b72660c 100644 --- a/lib/controller.dart +++ b/lib/controller.dart @@ -8,28 +8,24 @@ import 'package:archive/archive.dart'; import 'package:fl_clash/clash/clash.dart'; import 'package:fl_clash/common/archive.dart'; import 'package:fl_clash/enum/enum.dart'; +import 'package:fl_clash/providers/providers.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path/path.dart'; -import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; import 'common/common.dart'; import 'models/models.dart'; class AppController { - final BuildContext context; - late AppState appState; - late AppFlowingState appFlowingState; - late Config config; - late ClashConfig clashConfig; + bool lastTunEnable = false; + int? lastProfileModified; - AppController(this.context) { - appState = context.read(); - config = context.read(); - clashConfig = context.read(); - appFlowingState = context.read(); - } + final BuildContext context; + final WidgetRef _ref; + + AppController(this.context, WidgetRef ref) : _ref = ref; updateClashConfigDebounce() { debouncer.call(DebounceTag.updateClashConfig, updateClashConfig); @@ -41,13 +37,13 @@ class AppController { addCheckIpNumDebounce() { debouncer.call(DebounceTag.addCheckIpNum, () { - appState.checkIpNum++; + _ref.read(checkIpNumProvider.notifier).add(); }); } applyProfileDebounce() { debouncer.call(DebounceTag.addCheckIpNum, () { - applyProfile(isPrue: true); + applyProfile(); }); } @@ -67,11 +63,12 @@ class AppController { } restartCore() async { - await globalState.restartCore( - appState: appState, - clashConfig: clashConfig, - config: config, - ); + await clashService?.reStart(); + await initCore(); + + if (_ref.read(runTimeProvider.notifier).isStart) { + await globalState.handleStart(); + } } updateStatus(bool isStart) async { @@ -81,13 +78,12 @@ class AppController { updateTraffic, ]); final currentLastModified = - await config.getCurrentProfile()?.profileLastModified; - if (currentLastModified == null || - globalState.lastProfileModified == null) { + await _ref.read(currentProfileProvider)?.profileLastModified; + if (currentLastModified == null || lastProfileModified == null) { addCheckIpNumDebounce(); return; } - if (currentLastModified <= (globalState.lastProfileModified ?? 0)) { + if (currentLastModified <= (lastProfileModified ?? 0)) { addCheckIpNumDebounce(); return; } @@ -95,9 +91,10 @@ class AppController { } else { await globalState.handleStop(); await clashCore.resetTraffic(); - appFlowingState.traffics = []; - appFlowingState.totalTraffic = Traffic(); - appFlowingState.runTime = null; + _ref.read(trafficsProvider.notifier).clear(); + _ref.read(totalTrafficProvider.notifier).value = Traffic(); + _ref.read(runTimeProvider.notifier).value = null; + // tray.updateTrayTitle(null); addCheckIpNumDebounce(); } } @@ -107,107 +104,214 @@ class AppController { if (startTime != null) { final startTimeStamp = startTime.millisecondsSinceEpoch; final nowTimeStamp = DateTime.now().millisecondsSinceEpoch; - appFlowingState.runTime = nowTimeStamp - startTimeStamp; + _ref.read(runTimeProvider.notifier).value = nowTimeStamp - startTimeStamp; } else { - appFlowingState.runTime = null; + _ref.read(runTimeProvider.notifier).value = null; } } - updateTraffic() { - globalState.updateTraffic( - config: config, - appFlowingState: appFlowingState, - ); + updateTraffic() async { + final traffic = await clashCore.getTraffic(); + _ref.read(trafficsProvider.notifier).addTraffic(traffic); + _ref.read(totalTrafficProvider.notifier).value = + await clashCore.getTotalTraffic(); } addProfile(Profile profile) async { - config.setProfile(profile); - if (config.currentProfileId != null) return; - await changeProfile(profile.id); + _ref.read(profilesProvider.notifier).setProfile(profile); + if (_ref.read(currentProfileIdProvider) != null) return; + _ref.read(currentProfileIdProvider.notifier).value = profile.id; } deleteProfile(String id) async { - config.deleteProfileById(id); + _ref.read(profilesProvider.notifier).deleteProfileById(id); clearEffect(id); - if (config.currentProfileId == id) { - if (config.profiles.isNotEmpty) { - final updateId = config.profiles.first.id; - changeProfile(updateId); + if (globalState.config.currentProfileId == id) { + final profiles = globalState.config.profiles; + final currentProfileId = _ref.read(currentProfileIdProvider.notifier); + if (profiles.isNotEmpty) { + final updateId = profiles.first.id; + currentProfileId.value = updateId; } else { - changeProfile(null); + currentProfileId.value = null; updateStatus(false); } } } updateProviders() async { - await globalState.updateProviders(appState); + _ref.read(providersProvider.notifier).value = + await clashCore.getExternalProviders(); } updateLocalIp() async { - appFlowingState.localIp = null; + _ref.read(localIpProvider.notifier).value = null; await Future.delayed(commonDuration); - appFlowingState.localIp = await other.getLocalIpAddress(); + _ref.read(localIpProvider.notifier).value = await other.getLocalIpAddress(); } Future updateProfile(Profile profile) async { final newProfile = await profile.update(); - config.setProfile( - newProfile.copyWith(isUpdating: false), - ); - if (profile.id == config.currentProfile?.id) { + _ref + .read(profilesProvider.notifier) + .setProfile(newProfile.copyWith(isUpdating: false)); + if (profile.id == _ref.read(currentProfileIdProvider)) { applyProfileDebounce(); } } + _setProfile(Profile profile) { + _ref.read(profilesProvider.notifier).setProfile(profile); + } + setProfile(Profile profile) { - config.setProfile(profile); - if (profile.id == config.currentProfile?.id) { + _setProfile(profile); + if (profile.id == _ref.read(currentProfileIdProvider)) { applyProfileDebounce(); } } - Future updateClashConfig({bool isPatch = true}) async { + setProfiles(List profiles) { + _ref.read(profilesProvider.notifier).value = profiles; + } + + addLog(Log log) { + _ref.read(logsProvider).add(log); + } + + updateOrAddHotKeyAction(HotKeyAction hotKeyAction) { + final hotKeyActions = _ref.read(hotKeyActionsProvider); + final index = + hotKeyActions.indexWhere((item) => item.action == hotKeyAction.action); + if (index == -1) { + _ref.read(hotKeyActionsProvider.notifier).value = List.from(hotKeyActions) + ..add(hotKeyAction); + } else { + _ref.read(hotKeyActionsProvider.notifier).value = List.from(hotKeyActions) + ..[index] = hotKeyAction; + } + + _ref.read(hotKeyActionsProvider.notifier).value = index == -1 + ? (List.from(hotKeyActions)..add(hotKeyAction)) + : (List.from(hotKeyActions)..[index] = hotKeyAction); + } + + List getCurrentGroups() { + return _ref.read(currentGroupsStateProvider.select((state) => state.value)); + } + + String getRealTestUrl(String? url) { + return _ref.read(getRealTestUrlProvider(url)); + } + + int getProxiesColumns() { + return _ref.read(getProxiesColumnsProvider); + } + + addSortNum() { + return _ref.read(sortNumProvider.notifier).add(); + } + + getCurrentGroupName() { + final currentGroupName = _ref.read(currentProfileProvider.select( + (state) => state?.currentGroupName, + )); + return currentGroupName; + } + + getRealProxyName(proxyName) { + return _ref.read(getRealTestUrlProvider(proxyName)); + } + + getSelectedProxyName(groupName) { + return _ref.read(getSelectedProxyNameProvider(groupName)); + } + + updateCurrentGroupName(String groupName) { + final profile = _ref.read(currentProfileProvider); + if (profile == null || profile.currentGroupName == groupName) { + return; + } + _setProfile( + profile.copyWith(currentGroupName: groupName), + ); + } + + Future updateClashConfig([bool? isPatch]) async { final commonScaffoldState = globalState.homeScaffoldKey.currentState; if (commonScaffoldState?.mounted != true) return; await commonScaffoldState?.loadingRun(() async { - await globalState.updateClashConfig( - appState: appState, - clashConfig: clashConfig, - config: config, - isPatch: isPatch, + await _updateClashConfig( + isPatch, ); }); } - Future applyProfile({bool isPrue = false}) async { - if (isPrue) { - await globalState.applyProfile( - appState: appState, - config: config, - clashConfig: clashConfig, - ); + Future _updateClashConfig([bool? isPatch]) async { + final profile = _ref.watch(currentProfileProvider); + await _ref.read(currentProfileProvider)?.checkAndUpdate(); + final patchConfig = _ref.read(patchClashConfigProvider); + final appSetting = _ref.read(appSettingProvider); + bool enableTun = patchConfig.tun.enable; + if (enableTun != lastTunEnable && + lastTunEnable == false && + !Platform.isAndroid) { + final code = await system.authorizeCore(); + switch (code) { + case AuthorizeCode.none: + break; + case AuthorizeCode.success: + lastTunEnable = enableTun; + await restartCore(); + return; + case AuthorizeCode.error: + enableTun = false; + } + } + if (appSetting.openLogs) { + clashCore.startLog(); + } else { + clashCore.stopLog(); + } + final res = await clashCore.updateConfig( + globalState.getUpdateConfigParams(isPatch), + ); + if (res.isNotEmpty) throw res; + lastTunEnable = enableTun; + lastProfileModified = await profile?.profileLastModified; + } + + Future _applyProfile() async { + await clashCore.requestGc(); + await updateClashConfig(); + await updateGroups(); + await updateProviders(); + } + + Future applyProfile({bool silence = false}) async { + if (silence) { + await _applyProfile(); } else { final commonScaffoldState = globalState.homeScaffoldKey.currentState; if (commonScaffoldState?.mounted != true) return; await commonScaffoldState?.loadingRun(() async { - await globalState.applyProfile( - appState: appState, - config: config, - clashConfig: clashConfig, - ); + await _applyProfile(); }); } addCheckIpNumDebounce(); } - changeProfile(String? value) async { - if (value == config.currentProfileId) return; - config.currentProfileId = value; + handleChangeProfile() { + _ref.read(delayDataSourceProvider.notifier).value = {}; + applyProfile(); + } + + updateBrightness(Brightness brightness) { + _ref.read(appBrightnessProvider.notifier).value = brightness; } autoUpdateProfiles() async { - for (final profile in config.profiles) { + for (final profile in _ref.read(profilesProvider)) { if (!profile.autoUpdate) continue; final isNotNeedUpdate = profile.lastUpdateDate ?.add( @@ -218,20 +322,29 @@ class AppController { continue; } try { - updateProfile(profile); + await updateProfile(profile); } catch (e) { - appFlowingState.addLog( - Log( - logLevel: LogLevel.info, - payload: e.toString(), - ), - ); + _ref.read(logsProvider.notifier).addLog( + Log( + logLevel: LogLevel.info, + payload: e.toString(), + ), + ); } } } + Future updateGroups() async { + _ref.read(groupsProvider.notifier).value = await retry( + task: () async { + return await clashCore.getProxiesGroups(); + }, + retryIf: (res) => res.isEmpty, + ); + } + updateProfiles() async { - for (final profile in config.profiles) { + for (final profile in _ref.read(profilesProvider)) { if (profile.type == ProfileType.file) { continue; } @@ -239,34 +352,33 @@ class AppController { } } - Future updateGroups() async { - await globalState.updateGroups(appState); - } - - updateSystemColorSchemes(SystemColorSchemes systemColorSchemes) { - appState.systemColorSchemes = systemColorSchemes; + updateSystemColorSchemes(ColorSchemes colorSchemes) { + _ref.read(appSchemesProvider.notifier).value = colorSchemes; } savePreferences() async { - debugPrint("[APP] savePreferences"); - await preferences.saveConfig(config); - await preferences.saveClashConfig(clashConfig); + commonPrint.log("save preferences"); + await preferences.saveConfig(globalState.config); } changeProxy({ required String groupName, required String proxyName, }) async { - await globalState.changeProxy( - config: config, - groupName: groupName, - proxyName: proxyName, + await clashCore.changeProxy( + ChangeProxyParams( + groupName: groupName, + proxyName: proxyName, + ), ); + if (_ref.read(appSettingProvider).closeConnections) { + clashCore.closeConnections(); + } addCheckIpNumDebounce(); } handleBackOrExit() async { - if (config.appSetting.minimizeOnExit) { + if (_ref.read(appSettingProvider).minimizeOnExit) { if (system.isDesktop) { await savePreferencesDebounce(); } @@ -289,7 +401,7 @@ class AppController { } autoCheckUpdate() async { - if (!config.appSetting.autoCheckUpdate) return; + if (!_ref.read(appSettingProvider).autoCheckUpdate) return; final res = await request.checkForUpdate(); checkUpdateResultHandle(data: res); } @@ -346,7 +458,7 @@ class AppController { title: appLocalizations.tip, message: TextSpan(text: appLocalizations.cacheCorrupt), ); - if (res) { + if (res == true) { final file = File(await appPath.sharedPreferencesPath); final isExists = await file.exists(); if (isExists) { @@ -356,33 +468,43 @@ class AppController { await handleExit(); } + Future initCore() async { + final isInit = await clashCore.isInit; + if (!isInit) { + await clashCore.setState( + globalState.getCoreState(), + ); + await clashCore.init(); + } + await applyProfile(); + } + init() async { await _handlePreference(); await _handlerDisclaimer(); - await globalState.initCore( - appState: appState, - clashConfig: clashConfig, - config: config, - ); + await initCore(); await _initStatus(); + updateTray(true); autoLaunch?.updateStatus( - config.appSetting.autoLaunch, + _ref.read(appSettingProvider).autoLaunch, ); autoUpdateProfiles(); autoCheckUpdate(); - if (!config.appSetting.silentLaunch) { + if (!_ref.read(appSettingProvider).silentLaunch) { window?.show(); } else { window?.hide(); } + _ref.read(initProvider.notifier).value = true; } _initStatus() async { if (Platform.isAndroid) { await globalState.updateStartTime(); } - final status = - globalState.isStart == true ? true : config.appSetting.autoRun; + final status = globalState.isStart == true + ? true + : _ref.read(appSettingProvider).autoRun; await updateStatus(status); if (!status) { @@ -391,18 +513,23 @@ class AppController { } setDelay(Delay delay) { - appState.setDelay(delay); + _ref.read(delayDataSourceProvider.notifier).setDelay(delay); } toPage( int index, { bool hasAnimate = false, }) { - if (index > appState.currentNavigationItems.length - 1) { + final navigations = _ref.read(currentNavigationsStateProvider).value; + if (index > navigations.length - 1) { return; } - appState.currentLabel = appState.currentNavigationItems[index].label; - if ((config.appSetting.isAnimateToPage || hasAnimate)) { + _ref.read(currentPageLabelProvider.notifier).value = + navigations[index].label; + final isAnimateToPage = _ref.read(appSettingProvider).isAnimateToPage; + final isMobile = + _ref.read(viewWidthProvider.notifier).viewMode == ViewMode.mobile; + if (isAnimateToPage && isMobile || hasAnimate) { globalState.pageController?.animateToPage( index, duration: kTabScrollDuration, @@ -414,9 +541,9 @@ class AppController { } toProfiles() { - final index = appState.currentNavigationItems.indexWhere( - (element) => element.label == "profiles", - ); + final index = _ref.read(currentNavigationsStateProvider).value.indexWhere( + (element) => element.label == PageLabel.profiles, + ); if (index != -1) { toPage(index); } @@ -476,9 +603,9 @@ class AppController { ), TextButton( onPressed: () { - config.appSetting = config.appSetting.copyWith( - disclaimerAccepted: true, - ); + _ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith(disclaimerAccepted: true), + ); Navigator.of(context).pop(true); }, child: Text(appLocalizations.agree), @@ -490,7 +617,7 @@ class AppController { } _handlerDisclaimer() async { - if (config.appSetting.disclaimerAccepted) { + if (_ref.read(appSettingProvider).disclaimerAccepted) { return; } final isDisclaimerAccepted = await showDisclaimer(); @@ -551,20 +678,12 @@ class AppController { updateViewWidth(double width) { WidgetsBinding.instance.addPostFrameCallback((_) { - appState.viewWidth = width; + _ref.read(viewWidthProvider.notifier).value = width; }); } - int? getDelay(String proxyName, [String? url]) { - final currentDelayMap = appState.delayMap[getRealTestUrl(url)]; - return currentDelayMap?[appState.getRealProxyName(proxyName)]; - } - - String getRealTestUrl(String? url) { - if (url == null || url.isEmpty) { - return config.appSetting.testUrl; - } - return url; + setProvider(ExternalProvider? provider) { + _ref.read(providersProvider.notifier).setProvider(provider); } List _sortOfName(List proxies) { @@ -577,12 +696,17 @@ class AppController { ); } - List _sortOfDelay(String url, List proxies) { + List _sortOfDelay({ + required List proxies, + String? testUrl, + }) { return List.of(proxies) ..sort( (a, b) { - final aDelay = getDelay(a.name, url); - final bDelay = getDelay(b.name, url); + final aDelay = + _ref.read(getDelayProvider(proxyName: a.name, testUrl: testUrl)); + final bDelay = + _ref.read(getDelayProvider(proxyName: b.name, testUrl: testUrl)); if (aDelay == null && bDelay == null) { return 0; } @@ -598,20 +722,16 @@ class AppController { } List getSortProxies(List proxies, [String? url]) { - return switch (config.proxiesStyle.sortType) { + return switch (_ref.read(proxiesStyleSettingProvider).sortType) { ProxiesSortType.none => proxies, - ProxiesSortType.delay => _sortOfDelay(getRealTestUrl(url), proxies), + ProxiesSortType.delay => _sortOfDelay( + proxies: proxies, + testUrl: url, + ), ProxiesSortType.name => _sortOfName(proxies), }; } - String getCurrentSelectedName(String groupName) { - final group = appState.getGroupWithName(groupName); - return group?.getCurrentSelectedName( - config.currentSelectedMap[groupName] ?? '') ?? - ''; - } - clearEffect(String profileId) async { final profilePath = await appPath.getProfilePath(profileId); final providersPath = await appPath.getProvidersPath(profileId); @@ -625,38 +745,67 @@ class AppController { }); } - bool get isMobileView { - return appState.viewMode == ViewMode.mobile; - } - updateTun() { - clashConfig.tun = clashConfig.tun.copyWith( - enable: !clashConfig.tun.enable, - ); + _ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith.tun(enable: !state.tun.enable), + ); } updateSystemProxy() { - config.networkProps = config.networkProps.copyWith( - systemProxy: !config.networkProps.systemProxy, - ); + _ref.read(networkSettingProvider.notifier).updateState( + (state) => state.copyWith( + systemProxy: state.systemProxy, + ), + ); } updateStart() { - updateStatus(!appFlowingState.isStart); + updateStatus(_ref.read(runTimeProvider.notifier).isStart); + } + + updateCurrentSelectedMap(String groupName, String proxyName) { + final currentProfile = _ref.read(currentProfileProvider); + if (currentProfile != null && + currentProfile.selectedMap[groupName] != proxyName) { + final SelectedMap selectedMap = Map.from( + currentProfile.selectedMap, + )..[groupName] = proxyName; + _ref.read(profilesProvider.notifier).setProfile( + currentProfile.copyWith( + selectedMap: selectedMap, + ), + ); + } + } + + updateCurrentUnfoldSet(Set value) { + final currentProfile = _ref.read(currentProfileProvider); + if (currentProfile == null) { + return; + } + _ref.read(profilesProvider.notifier).setProfile( + currentProfile.copyWith( + unfoldSet: value, + ), + ); } changeMode(Mode mode) { - clashConfig.mode = mode; + _ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith(mode: mode), + ); if (mode == Mode.global) { - config.updateCurrentGroupName(GroupName.GLOBAL.name); + updateCurrentGroupName(GroupName.GLOBAL.name); } addCheckIpNumDebounce(); } updateAutoLaunch() { - config.appSetting = config.appSetting.copyWith( - autoLaunch: !config.appSetting.autoLaunch, - ); + _ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith( + autoLaunch: !state.autoLaunch, + ), + ); } updateVisible() async { @@ -669,18 +818,24 @@ class AppController { } updateMode() { - final index = Mode.values.indexWhere((item) => item == clashConfig.mode); - if (index == -1) { - return; - } - final nextIndex = index + 1 > Mode.values.length - 1 ? 0 : index + 1; - clashConfig.mode = Mode.values[nextIndex]; + _ref.read(patchClashConfigProvider.notifier).updateState( + (state) { + final index = Mode.values.indexWhere((item) => item == state.mode); + if (index == -1) { + return null; + } + final nextIndex = index + 1 > Mode.values.length - 1 ? 0 : index + 1; + return state.copyWith( + mode: Mode.values[nextIndex], + ); + }, + ); } Future exportLogs() async { - final logsRaw = appFlowingState.logs.map( - (item) => item.toString(), - ); + final logsRaw = _ref.read(logsProvider).list.map( + (item) => item.toString(), + ); final data = await Isolate.run>(() async { final logsRawString = logsRaw.join("\n"); return utf8.encode(logsRawString); @@ -695,12 +850,10 @@ class AppController { Future> backupData() async { final homeDirPath = await appPath.homeDirPath; final profilesPath = await appPath.profilesPath; - final configJson = config.toJson(); - final clashConfigJson = clashConfig.toJson(); + final configJson = globalState.config.toJson(); return Isolate.run>(() async { final archive = Archive(); archive.add("config.json", configJson); - archive.add("clashConfig.json", clashConfigJson); await archive.addDirectoryToArchive(profilesPath, homeDirPath); final zipEncoder = ZipEncoder(); return zipEncoder.encode(archive) ?? []; @@ -709,11 +862,7 @@ class AppController { updateTray([bool focus = false]) async { tray.update( - appState: appState, - appFlowingState: appFlowingState, - config: config, - clashConfig: clashConfig, - focus: focus, + trayState: _ref.read(trayStateProvider), ); } @@ -732,32 +881,64 @@ class AppController { archive.files.where((item) => !item.name.endsWith(".json")); final configIndex = configs.indexWhere((config) => config.name == "config.json"); - final clashConfigIndex = - configs.indexWhere((config) => config.name == "clashConfig.json"); - if (configIndex == -1 || clashConfigIndex == -1) throw "invalid backup.zip"; + if (configIndex == -1) throw "invalid backup file"; final configFile = configs[configIndex]; - final clashConfigFile = configs[clashConfigIndex]; - final tempConfig = Config.fromJson( + var tempConfig = Config.compatibleFromJson( json.decode( utf8.decode(configFile.content), ), ); - final tempClashConfig = ClashConfig.fromJson( - json.decode( - utf8.decode(clashConfigFile.content), - ), - ); for (final profile in profiles) { final filePath = join(homeDirPath, profile.name); final file = File(filePath); await file.create(recursive: true); await file.writeAsBytes(profile.content); } - if (recoveryOption == RecoveryOption.onlyProfiles) { - config.update(tempConfig, RecoveryOption.onlyProfiles); - } else { - config.update(tempConfig, RecoveryOption.all); - clashConfig.update(tempClashConfig); + final clashConfigIndex = + configs.indexWhere((config) => config.name == "clashConfig.json"); + if (clashConfigIndex != -1) { + final clashConfigFile = configs[clashConfigIndex]; + tempConfig = tempConfig.copyWith( + patchClashConfig: ClashConfig.fromJson( + json.decode( + utf8.decode( + clashConfigFile.content, + ), + ), + ), + ); } + _recovery( + tempConfig, + recoveryOption, + ); + } + + _recovery(Config config, RecoveryOption recoveryOption) { + final profiles = config.profiles; + for (final profile in profiles) { + _ref.read(profilesProvider.notifier).setProfile(profile); + } + final onlyProfiles = recoveryOption == RecoveryOption.onlyProfiles; + if (onlyProfiles) { + final currentProfile = _ref.read(currentProfileProvider); + if (currentProfile != null) { + _ref.read(currentProfileIdProvider.notifier).value = profiles.first.id; + } + return; + } + _ref.read(patchClashConfigProvider.notifier).value = + config.patchClashConfig; + _ref.read(appSettingProvider.notifier).value = config.appSetting; + _ref.read(currentProfileIdProvider.notifier).value = + config.currentProfileId; + _ref.read(appDAVSettingProvider.notifier).value = config.dav; + _ref.read(themeSettingProvider.notifier).value = config.themeProps; + _ref.read(windowSettingProvider.notifier).value = config.windowProps; + _ref.read(vpnSettingProvider.notifier).value = config.vpnProps; + _ref.read(proxiesStyleSettingProvider.notifier).value = config.proxiesStyle; + _ref.read(overrideDnsProvider.notifier).value = config.overrideDns; + _ref.read(networkSettingProvider.notifier).value = config.networkProps; + _ref.read(hotKeyActionsProvider.notifier).value = config.hotKeyActions; } } diff --git a/lib/enum/enum.dart b/lib/enum/enum.dart index 39e3097..d0b738f 100644 --- a/lib/enum/enum.dart +++ b/lib/enum/enum.dart @@ -34,7 +34,24 @@ const desktopPlatforms = [ SupportPlatform.Windows, ]; -enum GroupType { Selector, URLTest, Fallback, LoadBalance, Relay } +enum GroupType { + Selector, + URLTest, + Fallback, + LoadBalance, + Relay; + + static GroupType parseProfileType(String type) { + return switch (type) { + "url-test" => URLTest, + "select" => Selector, + "fallback" => Fallback, + "load-balance" => LoadBalance, + "relay" => Relay, + String() => throw UnimplementedError(), + }; + } +} enum GroupName { GLOBAL, Proxy, Auto, Fallback } @@ -45,7 +62,7 @@ extension GroupTypeExtension on GroupType { ) .toList(); - bool get isURLTestOrFallback { + bool get isComputedSelected { return [GroupType.URLTest, GroupType.Fallback].contains(this); } @@ -138,6 +155,13 @@ enum DnsMode { hosts } +enum ExternalControllerStatus { + @JsonValue("") + close, + @JsonValue("127.0.0.1:9090") + open +} + enum KeyboardModifier { alt([ PhysicalKeyboardKey.altLeft, @@ -238,6 +262,7 @@ enum ActionMethod { stopListener, getCountryCode, getMemory, + getProfile, ///Android, setFdMap, @@ -270,7 +295,11 @@ enum DebounceTag { handleWill, updateDelay, vpnTip, - autoLaunch + autoLaunch, + renderPause, + updatePageIndex, + pageChange, + proxiesTabChange, } enum DashboardWidget { @@ -341,3 +370,19 @@ enum DashboardWidget { return dashboardWidgets[index]; } } + +enum GeodataLoader { + standard, + memconservative, +} + +enum PageLabel { + dashboard, + proxies, + profiles, + tools, + logs, + requests, + resources, + connections, +} diff --git a/lib/fragments/access.dart b/lib/fragments/access.dart index 4621101..30bd8f8 100644 --- a/lib/fragments/access.dart +++ b/lib/fragments/access.dart @@ -4,20 +4,21 @@ import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/models/models.dart'; import 'package:fl_clash/plugins/app.dart'; import 'package:fl_clash/common/common.dart'; +import 'package:fl_clash/providers/providers.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; -class AccessFragment extends StatefulWidget { +class AccessFragment extends ConsumerStatefulWidget { const AccessFragment({super.key}); @override - State createState() => _AccessFragmentState(); + ConsumerState createState() => _AccessFragmentState(); } -class _AccessFragmentState extends State { +class _AccessFragmentState extends ConsumerState { List acceptList = []; List rejectList = []; late ScrollController _controller; @@ -28,10 +29,11 @@ class _AccessFragmentState extends State { _updateInitList(); _controller = ScrollController(); WidgetsBinding.instance.addPostFrameCallback((_) { - final appState = globalState.appController.appState; + final appState = globalState.appState; if (appState.packages.isEmpty) { Future.delayed(const Duration(milliseconds: 300), () async { - appState.packages = await app?.getPackages() ?? []; + ref.read(packagesProvider.notifier).value = + await app?.getPackages() ?? []; }); } }); @@ -44,9 +46,8 @@ class _AccessFragmentState extends State { } _updateInitList() { - final accessControl = globalState.appController.config.accessControl; - acceptList = accessControl.acceptList; - rejectList = accessControl.rejectList; + acceptList = globalState.config.vpnProps.accessControl.acceptList; + rejectList = globalState.config.vpnProps.accessControl.rejectList; } Widget _buildSearchButton() { @@ -59,9 +60,13 @@ class _AccessFragmentState extends State { acceptList: acceptList, rejectList: rejectList, ), - ).then((_) => setState(() { + ).then( + (_) => setState( + () { _updateInitList(); - })); + }, + ), + ); }, icon: const Icon(Icons.search), ); @@ -77,28 +82,29 @@ class _AccessFragmentState extends State { return IconButton( tooltip: tooltip, onPressed: () { - final config = globalState.appController.config; - final isAccept = - config.accessControl.mode == AccessControlMode.acceptSelected; - if (isSelectedAll) { - config.accessControl = switch (isAccept) { - true => config.accessControl.copyWith( - acceptList: [], - ), - false => config.accessControl.copyWith( - rejectList: [], - ), - }; - } else { - config.accessControl = switch (isAccept) { - true => config.accessControl.copyWith( - acceptList: allValueList, - ), - false => config.accessControl.copyWith( - rejectList: allValueList, - ), - }; - } + ref.read(vpnSettingProvider.notifier).updateState((state) { + final isAccept = + state.accessControl.mode == AccessControlMode.acceptSelected; + if (isSelectedAll) { + return switch (isAccept) { + true => state.copyWith.accessControl( + acceptList: [], + ), + false => state.copyWith.accessControl( + rejectList: [], + ), + }; + } else { + return switch (isAccept) { + true => state.copyWith.accessControl( + acceptList: allValueList, + ), + false => state.copyWith.accessControl( + rejectList: allValueList, + ), + }; + } + }); }, icon: isSelectedAll ? const Icon(Icons.deselect) @@ -106,223 +112,239 @@ class _AccessFragmentState extends State { ); } - Widget _buildSettingButton() { - return IconButton( - onPressed: () { - showSheet( - title: appLocalizations.proxiesSetting, - context: context, - body: AccessControlWidget( - context: context, + _intelligentSelected() async { + final appState = globalState.appState; + final config = globalState.config; + final accessControl = config.vpnProps.accessControl; + final packageNames = appState.packages + .where( + (item) => + accessControl.isFilterSystemApp ? item.isSystem == false : true, + ) + .map((item) => item.packageName); + final commonScaffoldState = context.commonScaffoldState; + if (commonScaffoldState?.mounted != true) return; + final selectedPackageNames = + (await commonScaffoldState?.loadingRun>( + () async { + return await app?.getChinaPackageNames() ?? []; + }, + )) + ?.toSet() ?? + {}; + final acceptList = packageNames + .where((item) => !selectedPackageNames.contains(item)) + .toList(); + final rejectList = packageNames + .where((item) => selectedPackageNames.contains(item)) + .toList(); + ref.read(vpnSettingProvider.notifier).updateState( + (state) => state.copyWith.accessControl( + acceptList: acceptList, + rejectList: rejectList, ), ); + } + + Widget _buildSettingButton() { + return IconButton( + onPressed: () async { + final res = await showSheet( + title: appLocalizations.proxiesSetting, + context: context, + body: AccessControlPanel(), + ); + if (res == 1) { + _intelligentSelected(); + } }, icon: const Icon(Icons.tune), ); } + _handleSelected(List valueList, Package package, bool? value) { + if (value == true) { + valueList.add(package.packageName); + } else { + valueList.remove(package.packageName); + } + ref.read(vpnSettingProvider.notifier).updateState((state) { + return switch ( + state.accessControl.mode == AccessControlMode.acceptSelected) { + true => state.copyWith.accessControl( + acceptList: valueList, + ), + false => state.copyWith.accessControl( + rejectList: valueList, + ), + }; + }); + } + @override Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.isAccessControl, - builder: (_, isAccessControl, child) { - return Column( - mainAxisSize: MainAxisSize.max, - children: [ - Flexible( - flex: 0, - child: ListItem.switchItem( - title: Text(appLocalizations.appAccessControl), - delegate: SwitchDelegate( - value: isAccessControl, - onChanged: (isAccessControl) { - final config = context.read(); - config.isAccessControl = isAccessControl; - }, - ), - ), + final state = ref.watch(packageListSelectorStateProvider); + final accessControl = state.accessControl; + final accessControlMode = accessControl.mode; + final packages = state.getList( + accessControlMode == AccessControlMode.acceptSelected + ? acceptList + : rejectList, + ); + final currentList = accessControl.currentList; + final packageNameList = packages.map((e) => e.packageName).toList(); + final valueList = currentList.intersection(packageNameList); + final describe = accessControlMode == AccessControlMode.acceptSelected + ? appLocalizations.accessControlAllowDesc + : appLocalizations.accessControlNotAllowDesc; + return Column( + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + flex: 0, + child: ListItem.switchItem( + title: Text(appLocalizations.appAccessControl), + delegate: SwitchDelegate( + value: accessControl.enable, + onChanged: (enable) { + ref.read(vpnSettingProvider.notifier).updateState( + (state) => state.copyWith.accessControl( + enable: enable, + ), + ); + }, ), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 16), - child: Divider( - height: 12, - ), - ), - Flexible( - child: child!, - ), - ], - ); - }, - child: Selector>( - selector: (_, appState) => appState.packages, - builder: (_, packages, ___) { - return Selector2( - selector: (_, appState, config) => PackageListSelectorState( - accessControl: config.accessControl, - isAccessControl: config.isAccessControl, - packages: appState.packages, - ), - builder: (context, state, __) { - final accessControl = state.accessControl; - final isAccessControl = state.isAccessControl; - final accessControlMode = accessControl.mode; - final packages = state.getList( - accessControlMode == AccessControlMode.acceptSelected - ? acceptList - : rejectList, - ); - final currentList = accessControl.currentList; - final packageNameList = - packages.map((e) => e.packageName).toList(); - final valueList = currentList.intersection(packageNameList); - final describe = - accessControlMode == AccessControlMode.acceptSelected - ? appLocalizations.accessControlAllowDesc - : appLocalizations.accessControlNotAllowDesc; - return DisabledMask( - status: !isAccessControl, - child: Column( - children: [ - ActivateBox( - active: isAccessControl, - child: Padding( - padding: const EdgeInsets.only( - top: 4, - bottom: 4, - left: 16, - right: 8, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.max, - children: [ - Expanded( - child: IntrinsicHeight( - child: Column( - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Row( - children: [ - Flexible( - child: Text( - appLocalizations.selected, - style: Theme.of(context) - .textTheme - .labelLarge - ?.copyWith( - color: Theme.of(context) - .colorScheme - .primary, - ), - ), - ), - const Flexible( - child: SizedBox( - width: 8, - ), - ), - Flexible( - child: Text( - "${valueList.length}", - style: Theme.of(context) - .textTheme - .labelLarge - ?.copyWith( - color: Theme.of(context) - .colorScheme - .primary, - ), - ), - ), - ], - ), - ), - Flexible( - child: Text(describe), - ) - ], - ), - ), - ), - Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.end, + ), + ), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 16), + child: Divider( + height: 12, + ), + ), + Flexible( + child: DisabledMask( + status: !accessControl.enable, + child: Column( + children: [ + ActivateBox( + active: accessControl.enable, + child: Padding( + padding: const EdgeInsets.only( + top: 4, + bottom: 4, + left: 16, + right: 8, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: IntrinsicHeight( + child: Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Flexible( - child: _buildSearchButton(), - ), - Flexible( - child: _buildSelectedAllButton( - isSelectedAll: valueList.length == - packageNameList.length, - allValueList: packageNameList, + Expanded( + child: Row( + children: [ + Flexible( + child: Text( + appLocalizations.selected, + style: Theme.of(context) + .textTheme + .labelLarge + ?.copyWith( + color: Theme.of(context) + .colorScheme + .primary, + ), + ), + ), + const Flexible( + child: SizedBox( + width: 8, + ), + ), + Flexible( + child: Text( + "${valueList.length}", + style: Theme.of(context) + .textTheme + .labelLarge + ?.copyWith( + color: Theme.of(context) + .colorScheme + .primary, + ), + ), + ), + ], ), ), Flexible( - child: _buildSettingButton(), - ), + child: Text(describe), + ) ], ), + ), + ), + Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Flexible( + child: _buildSearchButton(), + ), + Flexible( + child: _buildSelectedAllButton( + isSelectedAll: + valueList.length == packageNameList.length, + allValueList: packageNameList, + ), + ), + Flexible( + child: _buildSettingButton(), + ), ], ), - ), + ], ), - Expanded( - flex: 1, - child: packages.isEmpty - ? const Center( - child: CircularProgressIndicator(), - ) - : CommonScrollBar( - controller: _controller, - child: ListView.builder( - controller: _controller, - itemCount: packages.length, - itemExtent: 72, - itemBuilder: (_, index) { - final package = packages[index]; - return PackageListItem( - key: Key(package.packageName), - package: package, - value: - valueList.contains(package.packageName), - isActive: isAccessControl, - onChanged: (value) { - if (value == true) { - valueList.add(package.packageName); - } else { - valueList.remove(package.packageName); - } - final config = - globalState.appController.config; - if (accessControlMode == - AccessControlMode.acceptSelected) { - config.accessControl = - config.accessControl.copyWith( - acceptList: valueList, - ); - } else { - config.accessControl = - config.accessControl.copyWith( - rejectList: valueList, - ); - } - }, - ); - }, - ), - ), - ), - ], + ), ), - ); - }, - ); - }, - ), + Expanded( + flex: 1, + child: packages.isEmpty + ? const Center( + child: CircularProgressIndicator(), + ) + : CommonScrollBar( + controller: _controller, + child: ListView.builder( + controller: _controller, + itemCount: packages.length, + itemExtent: 72, + itemBuilder: (_, index) { + final package = packages[index]; + return PackageListItem( + key: Key(package.packageName), + package: package, + value: valueList.contains(package.packageName), + isActive: accessControl.enable, + onChanged: (value) { + _handleSelected(valueList, package, value); + }, + ); + }, + ), + ), + ), + ], + ), + ), + ), + ], ); } } @@ -343,45 +365,47 @@ class PackageListItem extends StatelessWidget { @override Widget build(BuildContext context) { - return ActivateBox( - active: isActive, - child: ListItem.checkbox( - leading: SizedBox( - width: 48, - height: 48, - child: FutureBuilder( - future: app?.getPackageIcon(package.packageName), - builder: (_, snapshot) { - if (!snapshot.hasData && snapshot.data == null) { - return Container(); - } else { - return Image( - image: snapshot.data!, - gaplessPlayback: true, - width: 48, - height: 48, - ); - } - }, + return FadeScaleEnterBox( + child: ActivateBox( + active: isActive, + child: ListItem.checkbox( + leading: SizedBox( + width: 48, + height: 48, + child: FutureBuilder( + future: app?.getPackageIcon(package.packageName), + builder: (_, snapshot) { + if (!snapshot.hasData && snapshot.data == null) { + return Container(); + } else { + return Image( + image: snapshot.data!, + gaplessPlayback: true, + width: 48, + height: 48, + ); + } + }, + ), ), - ), - title: Text( - package.label, - style: const TextStyle( - overflow: TextOverflow.ellipsis, + title: Text( + package.label, + style: const TextStyle( + overflow: TextOverflow.ellipsis, + ), + maxLines: 1, ), - maxLines: 1, - ), - subtitle: Text( - package.packageName, - style: const TextStyle( - overflow: TextOverflow.ellipsis, + subtitle: Text( + package.packageName, + style: const TextStyle( + overflow: TextOverflow.ellipsis, + ), + maxLines: 1, + ), + delegate: CheckboxDelegate( + value: value, + onChanged: onChanged, ), - maxLines: 1, - ), - delegate: CheckboxDelegate( - value: value, - onChanged: onChanged, ), ), ); @@ -426,15 +450,31 @@ class AccessControlSearchDelegate extends SearchDelegate { ); } + _handleSelected( + WidgetRef ref, List valueList, Package package, bool? value) { + if (value == true) { + valueList.add(package.packageName); + } else { + valueList.remove(package.packageName); + } + ref.read(vpnSettingProvider.notifier).updateState((state) { + return switch ( + state.accessControl.mode == AccessControlMode.acceptSelected) { + true => state.copyWith.accessControl( + acceptList: valueList, + ), + false => state.copyWith.accessControl( + rejectList: valueList, + ), + }; + }); + } + Widget _packageList() { final lowQuery = query.toLowerCase(); - return Selector2( - selector: (_, appState, config) => PackageListSelectorState( - packages: appState.packages, - accessControl: config.accessControl, - isAccessControl: config.isAccessControl, - ), - builder: (context, state, __) { + return Consumer( + builder: (context, ref, __) { + final state = ref.watch(packageListSelectorStateProvider); final accessControl = state.accessControl; final accessControlMode = accessControl.mode; final packages = state.getList( @@ -449,7 +489,7 @@ class AccessControlSearchDelegate extends SearchDelegate { package.packageName.contains(lowQuery), ) .toList(); - final isAccessControl = state.isAccessControl; + final isAccessControl = state.accessControl.enable; final currentList = accessControl.currentList; final packageNameList = packages.map((e) => e.packageName).toList(); final valueList = currentList.intersection(packageNameList); @@ -465,21 +505,12 @@ class AccessControlSearchDelegate extends SearchDelegate { value: valueList.contains(package.packageName), isActive: isAccessControl, onChanged: (value) { - if (value == true) { - valueList.add(package.packageName); - } else { - valueList.remove(package.packageName); - } - final config = globalState.appController.config; - if (accessControlMode == AccessControlMode.acceptSelected) { - config.accessControl = config.accessControl.copyWith( - acceptList: valueList, - ); - } else { - config.accessControl = config.accessControl.copyWith( - rejectList: valueList, - ); - } + _handleSelected( + ref, + valueList, + package, + value, + ); }, ); }, @@ -500,14 +531,16 @@ class AccessControlSearchDelegate extends SearchDelegate { } } -class AccessControlWidget extends StatelessWidget { - final BuildContext context; - - const AccessControlWidget({ +class AccessControlPanel extends ConsumerStatefulWidget { + const AccessControlPanel({ super.key, - required this.context, }); + @override + ConsumerState createState() => _AccessControlPanelState(); +} + +class _AccessControlPanelState extends ConsumerState { IconData _getIconWithAccessControlMode(AccessControlMode mode) { return switch (mode) { AccessControlMode.acceptSelected => Icons.adjust_outlined, @@ -552,9 +585,11 @@ class AccessControlWidget extends StatelessWidget { SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16), scrollDirection: Axis.horizontal, - child: Selector( - selector: (_, config) => config.accessControl.mode, - builder: (_, accessControlMode, __) { + child: Consumer( + builder: (_, ref, __) { + final accessControlMode = ref.watch( + vpnSettingProvider.select((state) => state.accessControl.mode), + ); return Wrap( spacing: 16, children: [ @@ -566,10 +601,11 @@ class AccessControlWidget extends StatelessWidget { ), isSelected: accessControlMode == item, onPressed: () { - final config = globalState.appController.config; - config.accessControl = config.accessControl.copyWith( - mode: item, - ); + ref.read(vpnSettingProvider.notifier).updateState( + (state) => state.copyWith.accessControl( + mode: item, + ), + ); }, ) ], @@ -588,9 +624,11 @@ class AccessControlWidget extends StatelessWidget { SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16), scrollDirection: Axis.horizontal, - child: Selector( - selector: (_, config) => config.accessControl.sort, - builder: (_, accessSortType, __) { + child: Consumer( + builder: (_, ref, __) { + final accessSortType = ref.watch( + vpnSettingProvider.select((state) => state.accessControl.sort), + ); return Wrap( spacing: 16, children: [ @@ -602,10 +640,11 @@ class AccessControlWidget extends StatelessWidget { ), isSelected: accessSortType == item, onPressed: () { - final config = globalState.appController.config; - config.accessControl = config.accessControl.copyWith( - sort: item, - ); + ref.read(vpnSettingProvider.notifier).updateState( + (state) => state.copyWith.accessControl( + sort: item, + ), + ); }, ), ], @@ -624,9 +663,12 @@ class AccessControlWidget extends StatelessWidget { SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16), scrollDirection: Axis.horizontal, - child: Selector( - selector: (_, config) => config.accessControl.isFilterSystemApp, - builder: (_, isFilterSystemApp, __) { + child: Consumer( + builder: (_, ref, __) { + final isFilterSystemApp = ref.watch( + vpnSettingProvider + .select((state) => state.accessControl.isFilterSystemApp), + ); return Wrap( spacing: 16, children: [ @@ -635,10 +677,11 @@ class AccessControlWidget extends StatelessWidget { _getTextWithIsFilterSystemApp(item), isSelected: isFilterSystemApp == item, onPressed: () { - final config = globalState.appController.config; - config.accessControl = config.accessControl.copyWith( - isFilterSystemApp: item, - ); + ref.read(vpnSettingProvider.notifier).updateState( + (state) => state.copyWith.accessControl( + isFilterSystemApp: item, + ), + ); }, ) ], @@ -650,63 +693,35 @@ class AccessControlWidget extends StatelessWidget { ); } - _intelligentSelected() async { - final appState = globalState.appController.appState; - final config = globalState.appController.config; - final accessControl = config.accessControl; - final packageNames = appState.packages - .where( - (item) => - accessControl.isFilterSystemApp ? item.isSystem == false : true, - ) - .map((item) => item.packageName); - Navigator.of(context).pop(); - final commonScaffoldState = context.commonScaffoldState; - if (commonScaffoldState?.mounted != true) return; - final selectedPackageNames = - (await commonScaffoldState?.loadingRun>( - () async { - return await app?.getChinaPackageNames() ?? []; - }, - )) - ?.toSet() ?? - {}; - final acceptList = packageNames - .where((item) => !selectedPackageNames.contains(item)) - .toList(); - final rejectList = packageNames - .where((item) => selectedPackageNames.contains(item)) - .toList(); - config.accessControl = accessControl.copyWith( - acceptList: acceptList, - rejectList: rejectList, - ); - } - _copyToClipboard() async { await globalState.safeRun(() { - final data = globalState.appController.config.accessControl.toJson(); + final data = globalState.config.vpnProps.accessControl.toJson(); Clipboard.setData( ClipboardData( text: json.encode(data), ), ); }); - if (!context.mounted) return; + if (!mounted) return; Navigator.of(context).pop(); } _pasteToClipboard() async { - await globalState.safeRun(() async { - final config = globalState.appController.config; - final data = await Clipboard.getData('text/plain'); - final text = data?.text; - if (text == null) return; - config.accessControl = AccessControl.fromJson( - json.decode(text), - ); - }); - if (!context.mounted) return; + await globalState.safeRun( + () async { + final data = await Clipboard.getData('text/plain'); + final text = data?.text; + if (text == null) return; + ref.read(vpnSettingProvider.notifier).updateState( + (state) => state.copyWith( + accessControl: AccessControl.fromJson( + json.decode(text), + ), + ), + ); + }, + ); + if (!mounted) return; Navigator.of(context).pop(); } @@ -725,7 +740,9 @@ class AccessControlWidget extends StatelessWidget { CommonChip( avatar: const Icon(Icons.auto_awesome), label: appLocalizations.intelligentSelected, - onPressed: _intelligentSelected, + onPressed: () { + Navigator.of(context).pop(1); + }, ), CommonChip( avatar: const Icon(Icons.paste), diff --git a/lib/fragments/application_setting.dart b/lib/fragments/application_setting.dart index d3d2221..15fbc72 100644 --- a/lib/fragments/application_setting.dart +++ b/lib/fragments/application_setting.dart @@ -1,61 +1,258 @@ import 'dart:io'; import 'package:fl_clash/common/common.dart'; -import 'package:fl_clash/models/models.dart'; -import 'package:fl_clash/state.dart'; +import 'package:fl_clash/providers/config.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; -class CloseConnectionsSwitch extends StatelessWidget { - const CloseConnectionsSwitch({super.key}); +class CloseConnectionsItem extends ConsumerWidget { + const CloseConnectionsItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.appSetting.closeConnections, - builder: (_, closeConnections, __) { - return ListItem.switchItem( - title: Text(appLocalizations.autoCloseConnections), - subtitle: Text(appLocalizations.autoCloseConnectionsDesc), - delegate: SwitchDelegate( - value: closeConnections, - onChanged: (value) async { - final config = globalState.appController.config; - config.appSetting = config.appSetting.copyWith( - closeConnections: value, + Widget build(BuildContext context, ref) { + final closeConnections = ref.watch( + appSettingProvider.select((state) => state.closeConnections), + ); + return ListItem.switchItem( + title: Text(appLocalizations.autoCloseConnections), + subtitle: Text(appLocalizations.autoCloseConnectionsDesc), + delegate: SwitchDelegate( + value: closeConnections, + onChanged: (value) async { + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith( + closeConnections: value, + ), ); - }, - ), - ); - }, + }, + ), ); } } -class UsageSwitch extends StatelessWidget { - const UsageSwitch({super.key}); +class UsageItem extends ConsumerWidget { + const UsageItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.appSetting.onlyStatisticsProxy, - builder: (_, onlyProxy, __) { - return ListItem.switchItem( - title: Text(appLocalizations.onlyStatisticsProxy), - subtitle: Text(appLocalizations.onlyStatisticsProxyDesc), - delegate: SwitchDelegate( - value: onlyProxy, - onChanged: (bool value) async { - final config = globalState.appController.config; - config.appSetting = config.appSetting.copyWith( - onlyStatisticsProxy: value, + Widget build(BuildContext context, ref) { + final onlyStatisticsProxy = ref.watch( + appSettingProvider.select((state) => state.onlyStatisticsProxy), + ); + return ListItem.switchItem( + title: Text(appLocalizations.onlyStatisticsProxy), + subtitle: Text(appLocalizations.onlyStatisticsProxyDesc), + delegate: SwitchDelegate( + value: onlyStatisticsProxy, + onChanged: (bool value) async { + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith( + onlyStatisticsProxy: value, + ), ); - }, - ), - ); - }, + }, + ), + ); + } +} + +class MinimizeItem extends ConsumerWidget { + const MinimizeItem({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final minimizeOnExit = ref.watch( + appSettingProvider.select((state) => state.minimizeOnExit), + ); + return ListItem.switchItem( + title: Text(appLocalizations.minimizeOnExit), + subtitle: Text(appLocalizations.minimizeOnExitDesc), + delegate: SwitchDelegate( + value: minimizeOnExit, + onChanged: (bool value) { + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith( + minimizeOnExit: value, + ), + ); + }, + ), + ); + } +} + +class AutoLaunchItem extends ConsumerWidget { + const AutoLaunchItem({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final autoLaunch = ref.watch( + appSettingProvider.select((state) => state.autoLaunch), + ); + return ListItem.switchItem( + title: Text(appLocalizations.autoLaunch), + subtitle: Text(appLocalizations.autoLaunchDesc), + delegate: SwitchDelegate( + value: autoLaunch, + onChanged: (bool value) { + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith( + autoLaunch: value, + ), + ); + }, + ), + ); + } +} + +class SilentLaunchItem extends ConsumerWidget { + const SilentLaunchItem({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final silentLaunch = ref.watch( + appSettingProvider.select((state) => state.silentLaunch), + ); + return ListItem.switchItem( + title: Text(appLocalizations.silentLaunch), + subtitle: Text(appLocalizations.silentLaunchDesc), + delegate: SwitchDelegate( + value: silentLaunch, + onChanged: (bool value) { + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith( + silentLaunch: value, + ), + ); + }, + ), + ); + } +} + +class AutoRunItem extends ConsumerWidget { + const AutoRunItem({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final autoRun = ref.watch( + appSettingProvider.select((state) => state.autoRun), + ); + return ListItem.switchItem( + title: Text(appLocalizations.autoRun), + subtitle: Text(appLocalizations.autoRunDesc), + delegate: SwitchDelegate( + value: autoRun, + onChanged: (bool value) { + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith( + autoRun: value, + ), + ); + }, + ), + ); + } +} + +class HiddenItem extends ConsumerWidget { + const HiddenItem({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final hidden = ref.watch( + appSettingProvider.select((state) => state.hidden), + ); + return ListItem.switchItem( + title: Text(appLocalizations.exclude), + subtitle: Text(appLocalizations.excludeDesc), + delegate: SwitchDelegate( + value: hidden, + onChanged: (value) { + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith( + hidden: value, + ), + ); + }, + ), + ); + } +} + +class AnimateTabItem extends ConsumerWidget { + const AnimateTabItem({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final isAnimateToPage = ref.watch( + appSettingProvider.select((state) => state.isAnimateToPage), + ); + return ListItem.switchItem( + title: Text(appLocalizations.tabAnimation), + subtitle: Text(appLocalizations.tabAnimationDesc), + delegate: SwitchDelegate( + value: isAnimateToPage, + onChanged: (value) { + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith( + isAnimateToPage: value, + ), + ); + }, + ), + ); + } +} + +class OpenLogsItem extends ConsumerWidget { + const OpenLogsItem({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final openLogs = ref.watch( + appSettingProvider.select((state) => state.openLogs), + ); + return ListItem.switchItem( + title: Text(appLocalizations.logcat), + subtitle: Text(appLocalizations.logcatDesc), + delegate: SwitchDelegate( + value: openLogs, + onChanged: (bool value) { + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith( + openLogs: value, + ), + ); + }, + ), + ); + } +} + +class AutoCheckUpdateItem extends ConsumerWidget { + const AutoCheckUpdateItem({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final autoCheckUpdate = ref.watch( + appSettingProvider.select((state) => state.autoCheckUpdate), + ); + return ListItem.switchItem( + title: Text(appLocalizations.autoCheckUpdate), + subtitle: Text(appLocalizations.autoCheckUpdateDesc), + delegate: SwitchDelegate( + value: autoCheckUpdate, + onChanged: (bool value) { + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith( + autoCheckUpdate: value, + ), + ); + }, + ), ); } } @@ -71,156 +268,20 @@ class ApplicationSettingFragment extends StatelessWidget { @override Widget build(BuildContext context) { List items = [ - Selector( - selector: (_, config) => config.appSetting.minimizeOnExit, - builder: (_, isMinimizeOnExit, child) { - return ListItem.switchItem( - title: Text(appLocalizations.minimizeOnExit), - subtitle: Text(appLocalizations.minimizeOnExitDesc), - delegate: SwitchDelegate( - value: isMinimizeOnExit, - onChanged: (bool value) { - final config = context.read(); - config.appSetting = config.appSetting.copyWith( - minimizeOnExit: value, - ); - }, - ), - ); - }, - ), - if (system.isDesktop) - Selector( - selector: (_, config) => config.appSetting.autoLaunch, - builder: (_, autoLaunch, child) { - return ListItem.switchItem( - title: Text(appLocalizations.autoLaunch), - subtitle: Text(appLocalizations.autoLaunchDesc), - delegate: SwitchDelegate( - value: autoLaunch, - onChanged: (bool value) { - final config = globalState.appController.config; - config.appSetting = config.appSetting.copyWith( - autoLaunch: value, - ); - }, - ), - ); - }, - ), - if (system.isDesktop) - Selector( - selector: (_, config) => config.appSetting.silentLaunch, - builder: (_, silentLaunch, child) { - return ListItem.switchItem( - title: Text(appLocalizations.silentLaunch), - subtitle: Text(appLocalizations.silentLaunchDesc), - delegate: SwitchDelegate( - value: silentLaunch, - onChanged: (bool value) { - final config = globalState.appController.config; - config.appSetting = config.appSetting.copyWith( - silentLaunch: value, - ); - }, - ), - ); - }, - ), - Selector( - selector: (_, config) => config.appSetting.autoRun, - builder: (_, autoRun, child) { - return ListItem.switchItem( - title: Text(appLocalizations.autoRun), - subtitle: Text(appLocalizations.autoRunDesc), - delegate: SwitchDelegate( - value: autoRun, - onChanged: (bool value) { - final config = globalState.appController.config; - config.appSetting = config.appSetting.copyWith( - autoRun: value, - ); - }, - ), - ); - }, - ), - if (Platform.isAndroid) - Selector( - selector: (_, config) => config.appSetting.hidden, - builder: (_, isExclude, child) { - return ListItem.switchItem( - title: Text(appLocalizations.exclude), - subtitle: Text(appLocalizations.excludeDesc), - delegate: SwitchDelegate( - value: isExclude, - onChanged: (value) { - final config = globalState.appController.config; - config.appSetting = config.appSetting.copyWith( - hidden: value, - ); - }, - ), - ); - }, - ), - if (Platform.isAndroid) - Selector( - selector: (_, config) => config.appSetting.isAnimateToPage, - builder: (_, isAnimateToPage, child) { - return ListItem.switchItem( - title: Text(appLocalizations.tabAnimation), - subtitle: Text(appLocalizations.tabAnimationDesc), - delegate: SwitchDelegate( - value: isAnimateToPage, - onChanged: (value) { - final config = globalState.appController.config; - config.appSetting = config.appSetting.copyWith( - isAnimateToPage: value, - ); - }, - ), - ); - }, - ), - Selector( - selector: (_, config) => config.appSetting.openLogs, - builder: (_, openLogs, child) { - return ListItem.switchItem( - title: Text(appLocalizations.logcat), - subtitle: Text(appLocalizations.logcatDesc), - delegate: SwitchDelegate( - value: openLogs, - onChanged: (bool value) { - final config = globalState.appController.config; - config.appSetting = config.appSetting.copyWith( - openLogs: value, - ); - }, - ), - ); - }, - ), - const CloseConnectionsSwitch(), - const UsageSwitch(), - Selector( - selector: (_, config) => config.appSetting.autoCheckUpdate, - builder: (_, autoCheckUpdate, child) { - return ListItem.switchItem( - title: Text(appLocalizations.autoCheckUpdate), - subtitle: Text(appLocalizations.autoCheckUpdateDesc), - delegate: SwitchDelegate( - value: autoCheckUpdate, - onChanged: (bool value) { - final config = globalState.appController.config; - config.appSetting = config.appSetting.copyWith( - autoCheckUpdate: value, - ); - }, - ), - ); - }, - ), + MinimizeItem(), + if (system.isDesktop) ...[ + AutoLaunchItem(), + SilentLaunchItem(), + ], + AutoRunItem(), + if (Platform.isAndroid) ...[ + HiddenItem(), + AnimateTabItem(), + ], + OpenLogsItem(), + CloseConnectionsItem(), + UsageItem(), + AutoCheckUpdateItem(), ]; return ListView.separated( itemBuilder: (_, index) { diff --git a/lib/fragments/backup_and_recovery.dart b/lib/fragments/backup_and_recovery.dart index 4f0081a..c16e10c 100644 --- a/lib/fragments/backup_and_recovery.dart +++ b/lib/fragments/backup_and_recovery.dart @@ -4,14 +4,15 @@ import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/common/dav_client.dart'; import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/providers/config.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/fade_box.dart'; import 'package:fl_clash/widgets/list.dart'; import 'package:fl_clash/widgets/text.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; -class BackupAndRecovery extends StatelessWidget { +class BackupAndRecovery extends ConsumerWidget { const BackupAndRecovery({super.key}); _showAddWebDAV(DAV? dav) async { @@ -121,139 +122,140 @@ class BackupAndRecovery extends StatelessWidget { _recoveryOnLocal(context, recoveryOption); } - @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.dav, - builder: (_, dav, __) { - final client = dav != null ? DAVClient(dav) : null; - return ListView( - children: [ - ListHeader(title: appLocalizations.remote), - if (dav == null) - ListItem( - leading: const Icon(Icons.account_box), - title: Text(appLocalizations.noInfo), - subtitle: Text(appLocalizations.pleaseBindWebDAV), - trailing: FilledButton.tonal( - onPressed: () { - _showAddWebDAV(dav); - }, - child: Text( - appLocalizations.bind, - ), - ), - ) - else ...[ - ListItem( - leading: const Icon(Icons.account_box), - title: TooltipText( - text: Text( - dav.user, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - subtitle: Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text(appLocalizations.connectivity), - FutureBuilder( - future: client!.pingCompleter.future, - builder: (_, snapshot) { - return Center( - child: FadeBox( - child: snapshot.connectionState == - ConnectionState.waiting - ? const SizedBox( - width: 12, - height: 12, - child: CircularProgressIndicator( - strokeWidth: 1, - ), - ) - : Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: snapshot.data == true - ? Colors.green - : Colors.red, - ), - width: 12, - height: 12, - ), - ), - ); - }, - ), - ], - ), - ), - trailing: FilledButton.tonal( - onPressed: () { - _showAddWebDAV(dav); - }, - child: Text( - appLocalizations.edit, - ), - ), - ), - 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); - }, - title: Text(appLocalizations.backup), - subtitle: Text(appLocalizations.remoteBackupDesc), - ), - ListItem( - onTap: () { - _handleRecoveryOnWebDAV(context, client); - }, - title: Text(appLocalizations.recovery), - subtitle: Text(appLocalizations.remoteRecoveryDesc), - ), - ], - ListHeader(title: appLocalizations.local), - ListItem( - onTap: () { - _backupOnLocal(context); - }, - title: Text(appLocalizations.backup), - subtitle: Text(appLocalizations.localBackupDesc), - ), - ListItem( - onTap: () { - _handleRecoveryOnLocal(context); - }, - title: Text(appLocalizations.recovery), - subtitle: Text(appLocalizations.localRecoveryDesc), - ), - ], + _handleChange(String? value, WidgetRef ref) { + if (value == null) { + return; + } + ref.read(appDAVSettingProvider.notifier).updateState( + (state) => state?.copyWith( + fileName: value, + ), ); - }, + } + + @override + Widget build(BuildContext context, ref) { + final dav = ref.watch(appDAVSettingProvider); + final client = dav != null ? DAVClient(dav) : null; + return ListView( + children: [ + ListHeader(title: appLocalizations.remote), + if (dav == null) + ListItem( + leading: const Icon(Icons.account_box), + title: Text(appLocalizations.noInfo), + subtitle: Text(appLocalizations.pleaseBindWebDAV), + trailing: FilledButton.tonal( + onPressed: () { + _showAddWebDAV(dav); + }, + child: Text( + appLocalizations.bind, + ), + ), + ) + else ...[ + ListItem( + leading: const Icon(Icons.account_box), + title: TooltipText( + text: Text( + dav.user, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + subtitle: Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text(appLocalizations.connectivity), + FutureBuilder( + future: client!.pingCompleter.future, + builder: (_, snapshot) { + return Center( + child: FadeBox( + child: snapshot.connectionState == + ConnectionState.waiting + ? const SizedBox( + width: 12, + height: 12, + child: CircularProgressIndicator( + strokeWidth: 1, + ), + ) + : Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: snapshot.data == true + ? Colors.green + : Colors.red, + ), + width: 12, + height: 12, + ), + ), + ); + }, + ), + ], + ), + ), + trailing: FilledButton.tonal( + onPressed: () { + _showAddWebDAV(dav); + }, + child: Text( + appLocalizations.edit, + ), + ), + ), + 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: (value) { + _handleChange(value, ref); + }, + ), + ), + ListItem( + onTap: () { + _backupOnWebDAV(context, client); + }, + title: Text(appLocalizations.backup), + subtitle: Text(appLocalizations.remoteBackupDesc), + ), + ListItem( + onTap: () { + _handleRecoveryOnWebDAV(context, client); + }, + title: Text(appLocalizations.recovery), + subtitle: Text(appLocalizations.remoteRecoveryDesc), + ), + ], + ListHeader(title: appLocalizations.local), + ListItem( + onTap: () { + _backupOnLocal(context); + }, + title: Text(appLocalizations.backup), + subtitle: Text(appLocalizations.localBackupDesc), + ), + ListItem( + onTap: () { + _handleRecoveryOnLocal(context); + }, + title: Text(appLocalizations.recovery), + subtitle: Text(appLocalizations.localRecoveryDesc), + ), + ], ); } } @@ -302,16 +304,16 @@ class _RecoveryOptionsDialogState extends State { } } -class WebDAVFormDialog extends StatefulWidget { +class WebDAVFormDialog extends ConsumerStatefulWidget { final DAV? dav; const WebDAVFormDialog({super.key, this.dav}); @override - State createState() => _WebDAVFormDialogState(); + ConsumerState createState() => _WebDAVFormDialogState(); } -class _WebDAVFormDialogState extends State { +class _WebDAVFormDialogState extends ConsumerState { late TextEditingController uriController; late TextEditingController userController; late TextEditingController passwordController; @@ -328,7 +330,7 @@ class _WebDAVFormDialogState extends State { _submit() { if (!_formKey.currentState!.validate()) return; - globalState.appController.config.dav = DAV( + ref.read(appDAVSettingProvider.notifier).value = DAV( uri: uriController.text, user: userController.text, password: passwordController.text, @@ -337,7 +339,7 @@ class _WebDAVFormDialogState extends State { } _delete() { - globalState.appController.config.dav = null; + ref.read(appDAVSettingProvider.notifier).value = null; Navigator.pop(context); } diff --git a/lib/fragments/config/dns.dart b/lib/fragments/config/dns.dart index 97f6c98..4fbf24f 100644 --- a/lib/fragments/config/dns.dart +++ b/lib/fragments/config/dns.dart @@ -1,238 +1,199 @@ -import 'package:collection/collection.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/providers/config.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; -class OverrideItem extends StatelessWidget { +class OverrideItem extends ConsumerWidget { const OverrideItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.overrideDns, - builder: (_, override, __) { - return ListItem.switchItem( - title: Text(appLocalizations.overrideDns), - subtitle: Text(appLocalizations.overrideDnsDesc), - delegate: SwitchDelegate( - value: override, - onChanged: (bool value) async { - final config = globalState.appController.config; - config.overrideDns = value; - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final override = ref.watch(overrideDnsProvider); + return ListItem.switchItem( + title: Text(appLocalizations.overrideDns), + subtitle: Text(appLocalizations.overrideDnsDesc), + delegate: SwitchDelegate( + value: override, + onChanged: (bool value) async { + ref.read(overrideDnsProvider.notifier).value = value; + }, + ), ); } } -class StatusItem extends StatelessWidget { +class StatusItem extends ConsumerWidget { const StatusItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.dns.enable, - builder: (_, enable, __) { - return ListItem.switchItem( - title: Text(appLocalizations.status), - subtitle: Text(appLocalizations.statusDesc), - delegate: SwitchDelegate( - value: enable, - onChanged: (bool value) async { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - enable: value, - ); - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final enable = + ref.watch(patchClashConfigProvider.select((state) => state.dns.enable)); + return ListItem.switchItem( + title: Text(appLocalizations.status), + subtitle: Text(appLocalizations.statusDesc), + delegate: SwitchDelegate( + value: enable, + onChanged: (bool value) async { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns(enable: value)); + }, + ), ); } } -class PreferH3Item extends StatelessWidget { +class PreferH3Item extends ConsumerWidget { const PreferH3Item({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.dns.preferH3, - builder: (_, preferH3, __) { - return ListItem.switchItem( - title: const Text("PreferH3"), - subtitle: Text(appLocalizations.preferH3Desc), - delegate: SwitchDelegate( - value: preferH3, - onChanged: (bool value) async { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - preferH3: value, - ); - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final preferH3 = ref + .watch(patchClashConfigProvider.select((state) => state.dns.preferH3)); + return ListItem.switchItem( + title: const Text("PreferH3"), + subtitle: Text(appLocalizations.preferH3Desc), + delegate: SwitchDelegate( + value: preferH3, + onChanged: (bool value) async { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns(preferH3: value)); + }, + ), ); } } -class IPv6Item extends StatelessWidget { +class IPv6Item extends ConsumerWidget { const IPv6Item({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.dns.ipv6, - builder: (_, ipv6, __) { - return ListItem.switchItem( - title: const Text("IPv6"), - delegate: SwitchDelegate( - value: ipv6, - onChanged: (bool value) async { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - ipv6: value, - ); - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final ipv6 = ref.watch( + patchClashConfigProvider.select((state) => state.dns.ipv6), + ); + return ListItem.switchItem( + title: const Text("IPv6"), + delegate: SwitchDelegate( + value: ipv6, + onChanged: (bool value) async { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns(ipv6: value)); + }, + ), ); } } -class RespectRulesItem extends StatelessWidget { +class RespectRulesItem extends ConsumerWidget { const RespectRulesItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.dns.respectRules, - builder: (_, respectRules, __) { - return ListItem.switchItem( - title: Text(appLocalizations.respectRules), - subtitle: Text(appLocalizations.respectRulesDesc), - delegate: SwitchDelegate( - value: respectRules, - onChanged: (bool value) async { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - respectRules: value, - ); - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final respectRules = ref.watch( + patchClashConfigProvider.select((state) => state.dns.respectRules), + ); + return ListItem.switchItem( + title: Text(appLocalizations.respectRules), + subtitle: Text(appLocalizations.respectRulesDesc), + delegate: SwitchDelegate( + value: respectRules, + onChanged: (bool value) async { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns(respectRules: value)); + }, + ), ); } } -class DnsModeItem extends StatelessWidget { +class DnsModeItem extends ConsumerWidget { const DnsModeItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.dns.enhancedMode, - builder: (_, enhancedMode, __) { - return ListItem.options( - title: Text(appLocalizations.dnsMode), - subtitle: Text(enhancedMode.name), - delegate: OptionsDelegate( - title: appLocalizations.dnsMode, - options: DnsMode.values, - onChanged: (value) { - if (value == null) { - return; - } - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith(enhancedMode: value); - }, - textBuilder: (dnsMode) => dnsMode.name, - value: enhancedMode, - ), - ); - }, + Widget build(BuildContext context, ref) { + final enhancedMode = ref.watch( + patchClashConfigProvider.select((state) => state.dns.enhancedMode), + ); + return ListItem.options( + title: Text(appLocalizations.dnsMode), + subtitle: Text(enhancedMode.name), + delegate: OptionsDelegate( + title: appLocalizations.dnsMode, + options: DnsMode.values, + onChanged: (value) { + if (value == null) { + return; + } + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns(enhancedMode: value)); + }, + textBuilder: (dnsMode) => dnsMode.name, + value: enhancedMode, + ), ); } } -class FakeIpRangeItem extends StatelessWidget { +class FakeIpRangeItem extends ConsumerWidget { const FakeIpRangeItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.dns.fakeIpRange, - builder: (_, fakeIpRange, __) { - return ListItem.input( - title: Text(appLocalizations.fakeipRange), - subtitle: Text(fakeIpRange), - delegate: InputDelegate( - title: appLocalizations.fakeipRange, - value: fakeIpRange, - onChanged: (String? value) { - if (value != null) { - try { - final clashConfig = globalState.appController.clashConfig; - clashConfig.dns = clashConfig.dns.copyWith( - fakeIpRange: value, - ); - } catch (e) { - globalState.showMessage( - title: appLocalizations.fakeipRange, - message: TextSpan( - text: e.toString(), - ), - ); - } - } - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final fakeIpRange = ref.watch( + patchClashConfigProvider.select((state) => state.dns.fakeIpRange), + ); + return ListItem.input( + title: Text(appLocalizations.fakeipRange), + subtitle: Text(fakeIpRange), + delegate: InputDelegate( + title: appLocalizations.fakeipRange, + value: fakeIpRange, + onChanged: (String? value) { + if (value == null) { + return; + } + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns(fakeIpRange: value)); + }, + ), ); } } -class FakeIpFilterItem extends StatelessWidget { +class FakeIpFilterItem extends ConsumerWidget { const FakeIpFilterItem({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, ref) { + final fakeIpFilter = ref.watch( + patchClashConfigProvider.select((state) => state.dns.fakeIpFilter), + ); return ListItem.open( title: Text(appLocalizations.fakeipFilter), delegate: OpenDelegate( isBlur: false, title: appLocalizations.fakeipFilter, - widget: Selector>( - selector: (_, clashConfig) => clashConfig.dns.fakeIpFilter, - shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next), - builder: (_, fakeIpFilter, __) { - return ListPage( - title: appLocalizations.fakeipFilter, - items: fakeIpFilter, - titleBuilder: (item) => Text(item), - onChange: (items) { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - fakeIpFilter: List.from(items), - ); - }, - ); + widget: ListPage( + title: appLocalizations.fakeipFilter, + items: fakeIpFilter, + titleBuilder: (item) => Text(item), + onChange: (items) { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns( + fakeIpFilter: List.from(items), + )); }, ), extendPageWidth: 360, @@ -241,33 +202,30 @@ class FakeIpFilterItem extends StatelessWidget { } } -class DefaultNameserverItem extends StatelessWidget { +class DefaultNameserverItem extends ConsumerWidget { const DefaultNameserverItem({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, ref) { + final defaultNameserver = ref.watch( + patchClashConfigProvider.select((state) => state.dns.defaultNameserver), + ); return ListItem.open( title: Text(appLocalizations.defaultNameserver), subtitle: Text(appLocalizations.defaultNameserverDesc), delegate: OpenDelegate( isBlur: false, title: appLocalizations.defaultNameserver, - widget: Selector>( - selector: (_, clashConfig) => clashConfig.dns.defaultNameserver, - shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next), - builder: (_, defaultNameserver, __) { - return ListPage( - title: appLocalizations.defaultNameserver, - items: defaultNameserver, - titleBuilder: (item) => Text(item), - onChange: (items) { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - defaultNameserver: List.from(items), - ); - }, - ); + widget: ListPage( + title: appLocalizations.defaultNameserver, + items: defaultNameserver, + titleBuilder: (item) => Text(item), + onChange: (items) { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns( + defaultNameserver: List.from(items), + )); }, ), extendPageWidth: 360, @@ -276,33 +234,30 @@ class DefaultNameserverItem extends StatelessWidget { } } -class NameserverItem extends StatelessWidget { +class NameserverItem extends ConsumerWidget { const NameserverItem({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, ref) { + final nameserver = ref.watch( + patchClashConfigProvider.select((state) => state.dns.nameserver), + ); return ListItem.open( title: Text(appLocalizations.nameserver), subtitle: Text(appLocalizations.nameserverDesc), delegate: OpenDelegate( title: appLocalizations.nameserver, isBlur: false, - widget: Selector>( - selector: (_, clashConfig) => clashConfig.dns.nameserver, - shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next), - builder: (_, nameserver, __) { - return ListPage( - title: "域名服务器", - items: nameserver, - titleBuilder: (item) => Text(item), - onChange: (items) { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - nameserver: List.from(items), - ); - }, - ); + widget: ListPage( + title: "域名服务器", + items: nameserver, + titleBuilder: (item) => Text(item), + onChange: (items) { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns( + nameserver: List.from(items), + )); }, ), extendPageWidth: 360, @@ -311,87 +266,77 @@ class NameserverItem extends StatelessWidget { } } -class UseHostsItem extends StatelessWidget { +class UseHostsItem extends ConsumerWidget { const UseHostsItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.dns.useHosts, - builder: (_, useHosts, __) { - return ListItem.switchItem( - title: Text(appLocalizations.useHosts), - delegate: SwitchDelegate( - value: useHosts, - onChanged: (bool value) async { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - useHosts: value, - ); - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final useHosts = ref.watch( + patchClashConfigProvider.select((state) => state.dns.useHosts), + ); + return ListItem.switchItem( + title: Text(appLocalizations.useHosts), + delegate: SwitchDelegate( + value: useHosts, + onChanged: (bool value) async { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns(useHosts: value)); + }, + ), ); } } -class UseSystemHostsItem extends StatelessWidget { +class UseSystemHostsItem extends ConsumerWidget { const UseSystemHostsItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.dns.useSystemHosts, - builder: (_, useSystemHosts, __) { - return ListItem.switchItem( - title: Text(appLocalizations.useSystemHosts), - delegate: SwitchDelegate( - value: useSystemHosts, - onChanged: (bool value) async { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - useSystemHosts: value, - ); - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final useSystemHosts = ref.watch( + patchClashConfigProvider.select((state) => state.dns.useSystemHosts), + ); + return ListItem.switchItem( + title: Text(appLocalizations.useSystemHosts), + delegate: SwitchDelegate( + value: useSystemHosts, + onChanged: (bool value) async { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns( + useSystemHosts: value, + )); + }, + ), ); } } -class NameserverPolicyItem extends StatelessWidget { +class NameserverPolicyItem extends ConsumerWidget { const NameserverPolicyItem({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, ref) { + final nameserverPolicy = ref.watch( + patchClashConfigProvider.select((state) => state.dns.nameserverPolicy), + ); return ListItem.open( title: Text(appLocalizations.nameserverPolicy), subtitle: Text(appLocalizations.nameserverPolicyDesc), delegate: OpenDelegate( isBlur: false, title: appLocalizations.nameserverPolicy, - widget: Selector>( - selector: (_, clashConfig) => clashConfig.dns.nameserverPolicy, - shouldRebuild: (prev, next) => - !const MapEquality().equals(prev, next), - builder: (_, nameserverPolicy, __) { - return ListPage( - title: appLocalizations.nameserverPolicy, - items: nameserverPolicy.entries, - titleBuilder: (item) => Text(item.key), - subtitleBuilder: (item) => Text(item.value), - onChange: (items) { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - nameserverPolicy: Map.fromEntries(items), - ); - }, - ); + widget: ListPage( + title: appLocalizations.nameserverPolicy, + items: nameserverPolicy.entries, + titleBuilder: (item) => Text(item.key), + subtitleBuilder: (item) => Text(item.value), + onChange: (items) { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns( + nameserverPolicy: Map.fromEntries(items), + )); }, ), extendPageWidth: 360, @@ -400,33 +345,31 @@ class NameserverPolicyItem extends StatelessWidget { } } -class ProxyServerNameserverItem extends StatelessWidget { +class ProxyServerNameserverItem extends ConsumerWidget { const ProxyServerNameserverItem({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, ref) { + final proxyServerNameserver = ref.watch( + patchClashConfigProvider + .select((state) => state.dns.proxyServerNameserver), + ); return ListItem.open( title: Text(appLocalizations.proxyNameserver), subtitle: Text(appLocalizations.proxyNameserverDesc), delegate: OpenDelegate( isBlur: false, title: appLocalizations.proxyNameserver, - widget: Selector>( - selector: (_, clashConfig) => clashConfig.dns.proxyServerNameserver, - shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next), - builder: (_, proxyServerNameserver, __) { - return ListPage( - title: appLocalizations.proxyNameserver, - items: proxyServerNameserver, - titleBuilder: (item) => Text(item), - onChange: (items) { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - proxyServerNameserver: List.from(items), - ); - }, - ); + widget: ListPage( + title: appLocalizations.proxyNameserver, + items: proxyServerNameserver, + titleBuilder: (item) => Text(item), + onChange: (items) { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns( + proxyServerNameserver: List.from(items), + )); }, ), extendPageWidth: 360, @@ -435,33 +378,30 @@ class ProxyServerNameserverItem extends StatelessWidget { } } -class FallbackItem extends StatelessWidget { +class FallbackItem extends ConsumerWidget { const FallbackItem({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, ref) { + final fallback = ref.watch( + patchClashConfigProvider.select((state) => state.dns.fallback), + ); return ListItem.open( title: Text(appLocalizations.fallback), subtitle: Text(appLocalizations.fallbackDesc), delegate: OpenDelegate( isBlur: false, title: appLocalizations.fallback, - widget: Selector>( - selector: (_, clashConfig) => clashConfig.dns.fallback, - shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next), - builder: (_, fallback, __) { - return ListPage( - title: appLocalizations.fallback, - items: fallback, - titleBuilder: (item) => Text(item), - onChange: (items) { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - fallback: List.from(items), - ); - }, - ); + widget: ListPage( + title: appLocalizations.fallback, + items: fallback, + titleBuilder: (item) => Text(item), + onChange: (items) { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns( + fallback: List.from(items), + )); }, ), extendPageWidth: 360, @@ -470,101 +410,85 @@ class FallbackItem extends StatelessWidget { } } -class GeoipItem extends StatelessWidget { +class GeoipItem extends ConsumerWidget { const GeoipItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.geoip, - builder: (_, geoip, __) { - return ListItem.switchItem( - title: const Text("Geoip"), - delegate: SwitchDelegate( - value: geoip, - onChanged: (bool value) async { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - fallbackFilter: dns.fallbackFilter.copyWith(geoip: value), - ); - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final geoip = ref.watch( + patchClashConfigProvider + .select((state) => state.dns.fallbackFilter.geoip), + ); + return ListItem.switchItem( + title: const Text("Geoip"), + delegate: SwitchDelegate( + value: geoip, + onChanged: (bool value) async { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns.fallbackFilter( + geoip: value, + )); + }, + ), ); } } -class GeoipCodeItem extends StatelessWidget { +class GeoipCodeItem extends ConsumerWidget { const GeoipCodeItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.geoipCode, - builder: (_, geoipCode, __) { - return ListItem.input( - title: Text(appLocalizations.geoipCode), - subtitle: Text(geoipCode), - delegate: InputDelegate( - title: appLocalizations.geoipCode, - value: geoipCode, - onChanged: (String? value) { - if (value != null) { - try { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - fallbackFilter: dns.fallbackFilter.copyWith( - geoipCode: value, - ), - ); - } catch (e) { - globalState.showMessage( - title: appLocalizations.geoipCode, - message: TextSpan( - text: e.toString(), - ), - ); - } - } - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final geoipCode = ref.watch( + patchClashConfigProvider + .select((state) => state.dns.fallbackFilter.geoipCode), + ); + return ListItem.input( + title: Text(appLocalizations.geoipCode), + subtitle: Text(geoipCode), + delegate: InputDelegate( + title: appLocalizations.geoipCode, + value: geoipCode, + onChanged: (String? value) { + if (value == null) { + return; + } + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns.fallbackFilter( + geoipCode: value, + )); + }, + ), ); } } -class GeositeItem extends StatelessWidget { +class GeositeItem extends ConsumerWidget { const GeositeItem({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, ref) { + final geosite = ref.watch( + patchClashConfigProvider + .select((state) => state.dns.fallbackFilter.geosite), + ); return ListItem.open( title: const Text("Geosite"), delegate: OpenDelegate( isBlur: false, title: "Geosite", - widget: Selector>( - selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.geosite, - shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next), - builder: (_, geosite, __) { - return ListPage( - title: "Geosite", - items: geosite, - titleBuilder: (item) => Text(item), - onChange: (items) { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - fallbackFilter: dns.fallbackFilter.copyWith( - geosite: List.from(items), - ), - ); - }, - ); + widget: ListPage( + title: "Geosite", + items: geosite, + titleBuilder: (item) => Text(item), + onChange: (items) { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns.fallbackFilter( + geosite: List.from(items), + )); }, ), extendPageWidth: 360, @@ -573,34 +497,30 @@ class GeositeItem extends StatelessWidget { } } -class IpcidrItem extends StatelessWidget { +class IpcidrItem extends ConsumerWidget { const IpcidrItem({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, ref) { + final ipcidr = ref.watch( + patchClashConfigProvider + .select((state) => state.dns.fallbackFilter.ipcidr), + ); return ListItem.open( title: Text(appLocalizations.ipcidr), delegate: OpenDelegate( isBlur: false, title: appLocalizations.ipcidr, - widget: Selector>( - selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.ipcidr, - shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next), - builder: (_, ipcidr, __) { - return ListPage( - title: appLocalizations.ipcidr, - items: ipcidr, - titleBuilder: (item) => Text(item), - onChange: (items) { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - fallbackFilter: dns.fallbackFilter.copyWith( - ipcidr: List.from(items), - ), - ); - }, - ); + widget: ListPage( + title: appLocalizations.ipcidr, + items: ipcidr, + titleBuilder: (item) => Text(item), + onChange: (items) { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns.fallbackFilter( + ipcidr: List.from(items), + )); }, ), extendPageWidth: 360, @@ -609,34 +529,30 @@ class IpcidrItem extends StatelessWidget { } } -class DomainItem extends StatelessWidget { +class DomainItem extends ConsumerWidget { const DomainItem({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, ref) { + final domain = ref.watch( + patchClashConfigProvider + .select((state) => state.dns.fallbackFilter.domain), + ); return ListItem.open( title: Text(appLocalizations.domain), delegate: OpenDelegate( isBlur: false, title: appLocalizations.domain, - widget: Selector>( - selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.domain, - shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next), - builder: (_, domain, __) { - return ListPage( - title: appLocalizations.domain, - items: domain, - titleBuilder: (item) => Text(item), - onChange: (items) { - final clashConfig = globalState.appController.clashConfig; - final dns = clashConfig.dns; - clashConfig.dns = dns.copyWith( - fallbackFilter: dns.fallbackFilter.copyWith( - domain: List.from(items), - ), - ); - }, - ); + widget: ListPage( + title: appLocalizations.domain, + items: domain, + titleBuilder: (item) => Text(item), + onChange: (items) { + ref + .read(patchClashConfigProvider.notifier) + .updateState((state) => state.copyWith.dns.fallbackFilter( + domain: List.from(items), + )); }, ), extendPageWidth: 360, @@ -700,12 +616,12 @@ const dnsItems = [ FallbackFilterOptions(), ]; -class DnsListView extends StatelessWidget { +class DnsListView extends ConsumerWidget { const DnsListView({super.key}); - _initActions(BuildContext context) { + _initActions(BuildContext context, WidgetRef ref) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - context.commonScaffoldState?.actions = [ + context.commonScaffoldState?.actions = [ IconButton( onPressed: () async { final res = await globalState.showMessage( @@ -717,7 +633,12 @@ class DnsListView extends StatelessWidget { if (res != true) { return; } - globalState.appController.clashConfig.dns = defaultDns; + + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + dns: defaultDns, + ), + ); }, tooltip: appLocalizations.reset, icon: const Icon( @@ -729,8 +650,8 @@ class DnsListView extends StatelessWidget { } @override - Widget build(BuildContext context) { - _initActions(context); + Widget build(BuildContext context, ref) { + _initActions(context, ref); return generateListView( dnsItems, ); diff --git a/lib/fragments/config/general.dart b/lib/fragments/config/general.dart index 2f0b224..b86ee13 100644 --- a/lib/fragments/config/general.dart +++ b/lib/fragments/config/general.dart @@ -1,207 +1,201 @@ -import 'package:collection/collection.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/providers/providers.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; -class LogLevelItem extends StatelessWidget { +class LogLevelItem extends ConsumerWidget { const LogLevelItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.logLevel, - builder: (_, value, __) { - return ListItem.options( - leading: const Icon(Icons.info_outline), - title: Text(appLocalizations.logLevel), - subtitle: Text(value.name), - delegate: OptionsDelegate( - title: appLocalizations.logLevel, - options: LogLevel.values, - onChanged: (LogLevel? value) { - if (value == null) { - return; - } - final appController = globalState.appController; - appController.clashConfig.logLevel = value; - }, - textBuilder: (logLevel) => logLevel.name, - value: value, - ), - ); - }, + Widget build(BuildContext context, ref) { + final logLevel = + ref.watch(patchClashConfigProvider.select((state) => state.logLevel)); + return ListItem.options( + leading: const Icon(Icons.info_outline), + title: Text(appLocalizations.logLevel), + subtitle: Text(logLevel.name), + delegate: OptionsDelegate( + title: appLocalizations.logLevel, + options: LogLevel.values, + onChanged: (LogLevel? value) { + if (value == null) { + return; + } + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + logLevel: value, + ), + ); + }, + textBuilder: (logLevel) => logLevel.name, + value: logLevel, + ), ); } } -class UaItem extends StatelessWidget { +class UaItem extends ConsumerWidget { const UaItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.globalRealUa, - builder: (_, value, __) { - return ListItem.options( - leading: const Icon(Icons.computer_outlined), - title: const Text("UA"), - subtitle: Text(value ?? appLocalizations.defaultText), - delegate: OptionsDelegate( - title: "UA", - options: [ - null, - "clash-verge/v1.6.6", - "ClashforWindows/0.19.23", - ], - value: value, - onChanged: (ua) { - final appController = globalState.appController; - appController.clashConfig.globalRealUa = ua; - }, - textBuilder: (ua) => ua ?? appLocalizations.defaultText, - ), - ); - }, + Widget build(BuildContext context, ref) { + final globalUa = + ref.watch(patchClashConfigProvider.select((state) => state.globalUa)); + return ListItem.options( + leading: const Icon(Icons.computer_outlined), + title: const Text("UA"), + subtitle: Text(globalUa ?? appLocalizations.defaultText), + delegate: OptionsDelegate( + title: "UA", + options: [ + null, + "clash-verge/v1.6.6", + "ClashforWindows/0.19.23", + ], + value: globalUa, + onChanged: (value) { + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + globalUa: value, + ), + ); + }, + textBuilder: (ua) => ua ?? appLocalizations.defaultText, + ), ); } } -class KeepAliveIntervalItem extends StatelessWidget { +class KeepAliveIntervalItem extends ConsumerWidget { const KeepAliveIntervalItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.keepAliveInterval, - builder: (_, value, __) { - return ListItem.input( - leading: const Icon(Icons.timer_outlined), - title: Text(appLocalizations.keepAliveIntervalDesc), - subtitle: Text("$value ${appLocalizations.seconds}"), - delegate: InputDelegate( - title: appLocalizations.keepAliveIntervalDesc, - suffixText: appLocalizations.seconds, - resetValue: "$defaultKeepAliveInterval", - value: "$value", - onChanged: (String? value) { - if (value != null) { - try { - final intValue = int.parse(value); - if (intValue <= 0) { - throw "Invalid keepAliveInterval"; - } - globalState.appController.clashConfig.keepAliveInterval = - intValue; - } catch (e) { - globalState.showMessage( - title: appLocalizations.keepAliveIntervalDesc, - message: TextSpan( - text: e.toString(), + Widget build(BuildContext context, ref) { + final keepAliveInterval = ref.watch( + patchClashConfigProvider.select((state) => state.keepAliveInterval)); + return ListItem.input( + leading: const Icon(Icons.timer_outlined), + title: Text(appLocalizations.keepAliveIntervalDesc), + subtitle: Text("$keepAliveInterval ${appLocalizations.seconds}"), + delegate: InputDelegate( + title: appLocalizations.keepAliveIntervalDesc, + suffixText: appLocalizations.seconds, + resetValue: "$defaultKeepAliveInterval", + value: "$keepAliveInterval", + onChanged: (String? value) { + if (value == null) { + return; + } + globalState.safeRun( + () { + final intValue = int.parse(value); + if (intValue <= 0) { + throw "Invalid keepAliveInterval"; + } + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + keepAliveInterval: intValue, ), ); - } - } }, - ), - ); - }, + silence: false, + title: appLocalizations.keepAliveIntervalDesc, + ); + }, + ), ); } } -class TestUrlItem extends StatelessWidget { +class TestUrlItem extends ConsumerWidget { const TestUrlItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.appSetting.testUrl, - builder: (_, value, __) { - return ListItem.input( - leading: const Icon(Icons.timeline), - title: Text(appLocalizations.testUrl), - subtitle: Text(value), - delegate: InputDelegate( - resetValue: defaultTestUrl, - title: appLocalizations.testUrl, - value: value, - onChanged: (String? value) { - if (value != null) { - try { - if (!value.isUrl) { - throw "Invalid url"; - } - final config = globalState.appController.config; - config.appSetting = config.appSetting.copyWith( - testUrl: value, - ); - } catch (e) { - globalState.showMessage( - title: appLocalizations.testUrl, - message: TextSpan( - text: e.toString(), - ), - ); + Widget build(BuildContext context, ref) { + final testUrl = + ref.watch(appSettingProvider.select((state) => state.testUrl)); + return ListItem.input( + leading: const Icon(Icons.timeline), + title: Text(appLocalizations.testUrl), + subtitle: Text(testUrl), + delegate: InputDelegate( + resetValue: defaultTestUrl, + title: appLocalizations.testUrl, + value: testUrl, + onChanged: (String? value) { + if (value == null) { + return; + } + globalState.safeRun( + () { + if (!value.isUrl) { + throw "Invalid url"; } - } - }, - ), - ); - }, + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith( + testUrl: value, + ), + ); + }, + silence: false, + title: appLocalizations.testUrl, + ); + }), ); } } -class MixedPortItem extends StatelessWidget { +class MixedPortItem extends ConsumerWidget { const MixedPortItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.mixedPort, - builder: (_, value, __) { - return ListItem.input( - leading: const Icon(Icons.adjust_outlined), - title: Text(appLocalizations.proxyPort), - subtitle: Text("$value"), - delegate: InputDelegate( - title: appLocalizations.proxyPort, - value: "$value", - onChanged: (String? value) { - if (value != null) { - try { - final mixedPort = int.parse(value); - if (mixedPort < 1024 || mixedPort > 49151) { - throw "Invalid port"; - } - globalState.appController.clashConfig.mixedPort = mixedPort; - } catch (e) { - globalState.showMessage( - title: appLocalizations.proxyPort, - message: TextSpan( - text: e.toString(), + Widget build(BuildContext context, ref) { + final mixedPort = + ref.watch(patchClashConfigProvider.select((state) => state.mixedPort)); + return ListItem.input( + leading: const Icon(Icons.adjust_outlined), + title: Text(appLocalizations.proxyPort), + subtitle: Text("$mixedPort"), + delegate: InputDelegate( + title: appLocalizations.proxyPort, + value: "$mixedPort", + onChanged: (String? value) { + if (value == null) { + return; + } + globalState.safeRun( + () { + final mixedPort = int.parse(value); + if (mixedPort < 1024 || mixedPort > 49151) { + throw "Invalid port"; + } + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + mixedPort: mixedPort, ), ); - } - } }, - resetValue: "$defaultMixedPort", - ), - ); - }, + silence: false, + title: appLocalizations.proxyPort, + ); + }, + resetValue: "$defaultMixedPort", + ), ); } } -class HostsItem extends StatelessWidget { +class HostsItem extends ConsumerWidget { const HostsItem({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, ref) { + final hosts = + ref.watch(patchClashConfigProvider.select((state) => state.hosts)); return ListItem.open( leading: const Icon(Icons.view_list_outlined), title: const Text("Hosts"), @@ -209,22 +203,17 @@ class HostsItem extends StatelessWidget { delegate: OpenDelegate( isBlur: false, title: "Hosts", - widget: Selector( - selector: (_, clashConfig) => clashConfig.hosts, - shouldRebuild: (prev, next) => - !const MapEquality().equals(prev, next), - builder: (_, hosts, ___) { - final entries = hosts.entries; - return ListPage( - title: "Hosts", - items: entries, - titleBuilder: (item) => Text(item.key), - subtitleBuilder: (item) => Text(item.value), - onChange: (items){ - final clashConfig = globalState.appController.clashConfig; - clashConfig.hosts = Map.fromEntries(items); - }, - ); + widget: ListPage( + title: "Hosts", + items: hosts.entries, + titleBuilder: (item) => Text(item.key), + subtitleBuilder: (item) => Text(item.value), + onChange: (items) { + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + hosts: Map.fromEntries(items), + ), + ); }, ), extendPageWidth: 360, @@ -233,190 +222,192 @@ class HostsItem extends StatelessWidget { } } -class Ipv6Item extends StatelessWidget { +class Ipv6Item extends ConsumerWidget { const Ipv6Item({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.ipv6, - builder: (_, ipv6, __) { - return ListItem.switchItem( - leading: const Icon(Icons.water_outlined), - title: const Text("IPv6"), - subtitle: Text(appLocalizations.ipv6Desc), - delegate: SwitchDelegate( - value: ipv6, - onChanged: (bool value) async { - final appController = globalState.appController; - appController.clashConfig.ipv6 = value; - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final ipv6 = + ref.watch(patchClashConfigProvider.select((state) => state.ipv6)); + return ListItem.switchItem( + leading: const Icon(Icons.water_outlined), + title: const Text("IPv6"), + subtitle: Text(appLocalizations.ipv6Desc), + delegate: SwitchDelegate( + value: ipv6, + onChanged: (bool value) async { + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + ipv6: value, + ), + ); + }, + ), ); } } -class AllowLanItem extends StatelessWidget { +class AllowLanItem extends ConsumerWidget { const AllowLanItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.allowLan, - builder: (_, allowLan, __) { - return ListItem.switchItem( - leading: const Icon(Icons.device_hub), - title: Text(appLocalizations.allowLan), - subtitle: Text(appLocalizations.allowLanDesc), - delegate: SwitchDelegate( - value: allowLan, - onChanged: (bool value) async { - final clashConfig = context.read(); - clashConfig.allowLan = value; - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final allowLan = + ref.watch(patchClashConfigProvider.select((state) => state.allowLan)); + return ListItem.switchItem( + leading: const Icon(Icons.device_hub), + title: Text(appLocalizations.allowLan), + subtitle: Text(appLocalizations.allowLanDesc), + delegate: SwitchDelegate( + value: allowLan, + onChanged: (bool value) async { + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + allowLan: value, + ), + ); + }, + ), ); } } -class UnifiedDelayItem extends StatelessWidget { +class UnifiedDelayItem extends ConsumerWidget { const UnifiedDelayItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.unifiedDelay, - builder: (_, unifiedDelay, __) { - return ListItem.switchItem( - leading: const Icon(Icons.compress_outlined), - title: Text(appLocalizations.unifiedDelay), - subtitle: Text(appLocalizations.unifiedDelayDesc), - delegate: SwitchDelegate( - value: unifiedDelay, - onChanged: (bool value) async { - final appController = globalState.appController; - appController.clashConfig.unifiedDelay = value; - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final unifiedDelay = ref + .watch(patchClashConfigProvider.select((state) => state.unifiedDelay)); + + return ListItem.switchItem( + leading: const Icon(Icons.compress_outlined), + title: Text(appLocalizations.unifiedDelay), + subtitle: Text(appLocalizations.unifiedDelayDesc), + delegate: SwitchDelegate( + value: unifiedDelay, + onChanged: (bool value) async { + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + unifiedDelay: value, + ), + ); + }, + ), ); } } -class FindProcessItem extends StatelessWidget { +class FindProcessItem extends ConsumerWidget { const FindProcessItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => - clashConfig.findProcessMode == FindProcessMode.always, - builder: (_, findProcess, __) { - return ListItem.switchItem( - leading: const Icon(Icons.polymer_outlined), - title: Text(appLocalizations.findProcessMode), - subtitle: Text(appLocalizations.findProcessModeDesc), - delegate: SwitchDelegate( - value: findProcess, - onChanged: (bool value) async { - final appController = globalState.appController; - appController.clashConfig.findProcessMode = - value ? FindProcessMode.always : FindProcessMode.off; - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final findProcess = ref.watch(patchClashConfigProvider + .select((state) => state.findProcessMode == FindProcessMode.always)); + + return ListItem.switchItem( + leading: const Icon(Icons.polymer_outlined), + title: Text(appLocalizations.findProcessMode), + subtitle: Text(appLocalizations.findProcessModeDesc), + delegate: SwitchDelegate( + value: findProcess, + onChanged: (bool value) async { + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + findProcessMode: + value ? FindProcessMode.always : FindProcessMode.off, + ), + ); + }, + ), ); } } -class TcpConcurrentItem extends StatelessWidget { +class TcpConcurrentItem extends ConsumerWidget { const TcpConcurrentItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.tcpConcurrent, - builder: (_, tcpConcurrent, __) { - return ListItem.switchItem( - leading: const Icon(Icons.double_arrow_outlined), - title: Text(appLocalizations.tcpConcurrent), - subtitle: Text(appLocalizations.tcpConcurrentDesc), - delegate: SwitchDelegate( - value: tcpConcurrent, - onChanged: (bool value) async { - final appController = globalState.appController; - appController.clashConfig.tcpConcurrent = value; - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final tcpConcurrent = ref + .watch(patchClashConfigProvider.select((state) => state.tcpConcurrent)); + return ListItem.switchItem( + leading: const Icon(Icons.double_arrow_outlined), + title: Text(appLocalizations.tcpConcurrent), + subtitle: Text(appLocalizations.tcpConcurrentDesc), + delegate: SwitchDelegate( + value: tcpConcurrent, + onChanged: (value) async { + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + tcpConcurrent: value, + ), + ); + }, + ), ); } } -class GeodataLoaderItem extends StatelessWidget { +class GeodataLoaderItem extends ConsumerWidget { const GeodataLoaderItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => - clashConfig.geodataLoader == geodataLoaderMemconservative, - builder: (_, memconservative, __) { - return ListItem.switchItem( - leading: const Icon(Icons.memory), - title: Text(appLocalizations.geodataLoader), - subtitle: Text(appLocalizations.geodataLoaderDesc), - delegate: SwitchDelegate( - value: memconservative, - onChanged: (bool value) async { - final appController = globalState.appController; - appController.clashConfig.geodataLoader = - value ? geodataLoaderMemconservative : geodataLoaderStandard; - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final isMemconservative = ref.watch(patchClashConfigProvider.select( + (state) => state.geodataLoader == GeodataLoader.memconservative)); + return ListItem.switchItem( + leading: const Icon(Icons.memory), + title: Text(appLocalizations.geodataLoader), + subtitle: Text(appLocalizations.geodataLoaderDesc), + delegate: SwitchDelegate( + value: isMemconservative, + onChanged: (bool value) async { + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + geodataLoader: value + ? GeodataLoader.memconservative + : GeodataLoader.standard, + ), + ); + }, + ), ); } } -class ExternalControllerItem extends StatelessWidget { +class ExternalControllerItem extends ConsumerWidget { const ExternalControllerItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.externalController.isNotEmpty, - builder: (_, hasExternalController, __) { - return ListItem.switchItem( - leading: const Icon(Icons.api_outlined), - title: Text(appLocalizations.externalController), - subtitle: Text(appLocalizations.externalControllerDesc), - delegate: SwitchDelegate( - value: hasExternalController, - onChanged: (bool value) async { - final appController = globalState.appController; - appController.clashConfig.externalController = - value ? defaultExternalController : ''; - }, - ), - ); - }, + Widget build(BuildContext context, ref) { + final hasExternalController = ref.watch(patchClashConfigProvider.select( + (state) => state.externalController == ExternalControllerStatus.open)); + return ListItem.switchItem( + leading: const Icon(Icons.api_outlined), + title: Text(appLocalizations.externalController), + subtitle: Text(appLocalizations.externalControllerDesc), + delegate: SwitchDelegate( + value: hasExternalController, + onChanged: (bool value) async { + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + externalController: value + ? ExternalControllerStatus.open + : ExternalControllerStatus.close, + ), + ); + }, + ), ); } } -final generalItems = const [ +final generalItems = [ LogLevelItem(), UaItem(), - KeepAliveIntervalItem(), + if (system.isDesktop) KeepAliveIntervalItem(), TestUrlItem(), MixedPortItem(), HostsItem(), diff --git a/lib/fragments/config/network.dart b/lib/fragments/config/network.dart index f3fb6a0..c70a807 100644 --- a/lib/fragments/config/network.dart +++ b/lib/fragments/config/network.dart @@ -3,208 +3,193 @@ import 'dart:io'; 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/providers/config.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; -class VPNItem extends StatelessWidget { +class VPNItem extends ConsumerWidget { const VPNItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.vpnProps.enable, - builder: (_, enable, __) { - return ListItem.switchItem( - title: const Text("VPN"), - subtitle: Text(appLocalizations.vpnEnableDesc), - delegate: SwitchDelegate( - value: enable, - onChanged: (value) async { - final config = globalState.appController.config; - config.vpnProps = config.vpnProps.copyWith( - enable: value, + Widget build(BuildContext context, ref) { + final enable = + ref.watch(vpnSettingProvider.select((state) => state.enable)); + return ListItem.switchItem( + title: const Text("VPN"), + subtitle: Text(appLocalizations.vpnEnableDesc), + delegate: SwitchDelegate( + value: enable, + onChanged: (value) async { + ref.read(vpnSettingProvider.notifier).updateState( + (state) => state.copyWith( + enable: value, + ), ); - }, - ), - ); - }, + }, + ), ); } } -class TUNItem extends StatelessWidget { +class TUNItem extends ConsumerWidget { const TUNItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.tun.enable, - builder: (_, enable, __) { - return ListItem.switchItem( - title: Text(appLocalizations.tun), - subtitle: Text(appLocalizations.tunDesc), - delegate: SwitchDelegate( - value: enable, - onChanged: (value) async { - final clashConfig = globalState.appController.clashConfig; - clashConfig.tun = clashConfig.tun.copyWith( - enable: value, + Widget build(BuildContext context, ref) { + final enable = + ref.watch(patchClashConfigProvider.select((state) => state.tun.enable)); + + return ListItem.switchItem( + title: Text(appLocalizations.tun), + subtitle: Text(appLocalizations.tunDesc), + delegate: SwitchDelegate( + value: enable, + onChanged: (value) async { + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith.tun( + enable: value, + ), ); - }, - ), - ); - }, + }, + ), ); } } -class AllowBypassItem extends StatelessWidget { +class AllowBypassItem extends ConsumerWidget { const AllowBypassItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.vpnProps.allowBypass, - builder: (_, allowBypass, __) { - return ListItem.switchItem( - title: Text(appLocalizations.allowBypass), - subtitle: Text(appLocalizations.allowBypassDesc), - delegate: SwitchDelegate( - value: allowBypass, - onChanged: (bool value) async { - final config = globalState.appController.config; - final vpnProps = config.vpnProps; - config.vpnProps = vpnProps.copyWith( - allowBypass: value, + Widget build(BuildContext context, ref) { + final allowBypass = + ref.watch(vpnSettingProvider.select((state) => state.allowBypass)); + return ListItem.switchItem( + title: Text(appLocalizations.allowBypass), + subtitle: Text(appLocalizations.allowBypassDesc), + delegate: SwitchDelegate( + value: allowBypass, + onChanged: (bool value) async { + ref.read(vpnSettingProvider.notifier).updateState( + (state) => state.copyWith( + allowBypass: value, + ), ); - }, - ), - ); - }, + }, + ), ); } } -class VpnSystemProxyItem extends StatelessWidget { +class VpnSystemProxyItem extends ConsumerWidget { const VpnSystemProxyItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.vpnProps.systemProxy, - builder: (_, systemProxy, __) { - return ListItem.switchItem( - title: Text(appLocalizations.systemProxy), - subtitle: Text(appLocalizations.systemProxyDesc), - delegate: SwitchDelegate( - value: systemProxy, - onChanged: (bool value) async { - final config = globalState.appController.config; - final vpnProps = config.vpnProps; - config.vpnProps = vpnProps.copyWith( - systemProxy: value, + Widget build(BuildContext context, ref) { + final systemProxy = + ref.watch(vpnSettingProvider.select((state) => state.systemProxy)); + return ListItem.switchItem( + title: Text(appLocalizations.systemProxy), + subtitle: Text(appLocalizations.systemProxyDesc), + delegate: SwitchDelegate( + value: systemProxy, + onChanged: (bool value) async { + ref.read(vpnSettingProvider.notifier).updateState( + (state) => state.copyWith( + systemProxy: value, + ), ); - }, - ), - ); - }, + }, + ), ); } } -class SystemProxyItem extends StatelessWidget { +class SystemProxyItem extends ConsumerWidget { const SystemProxyItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.networkProps.systemProxy, - builder: (_, systemProxy, __) { - return ListItem.switchItem( - title: Text(appLocalizations.systemProxy), - subtitle: Text(appLocalizations.systemProxyDesc), - delegate: SwitchDelegate( - value: systemProxy, - onChanged: (bool value) async { - final config = globalState.appController.config; - final networkProps = config.networkProps; - config.networkProps = networkProps.copyWith( - systemProxy: value, + Widget build(BuildContext context, ref) { + final systemProxy = + ref.watch(networkSettingProvider.select((state) => state.systemProxy)); + + return ListItem.switchItem( + title: Text(appLocalizations.systemProxy), + subtitle: Text(appLocalizations.systemProxyDesc), + delegate: SwitchDelegate( + value: systemProxy, + onChanged: (bool value) async { + ref.read(networkSettingProvider.notifier).updateState( + (state) => state.copyWith( + systemProxy: value, + ), ); - }, - ), - ); - }, + }, + ), ); } } -class Ipv6Item extends StatelessWidget { +class Ipv6Item extends ConsumerWidget { const Ipv6Item({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.vpnProps.ipv6, - builder: (_, ipv6, __) { - return ListItem.switchItem( - title: const Text("IPv6"), - subtitle: Text(appLocalizations.ipv6InboundDesc), - delegate: SwitchDelegate( - value: ipv6, - onChanged: (bool value) async { - final config = globalState.appController.config; - final vpnProps = config.vpnProps; - config.vpnProps = vpnProps.copyWith( - ipv6: value, + Widget build(BuildContext context, ref) { + final ipv6 = ref.watch(vpnSettingProvider.select((state) => state.ipv6)); + return ListItem.switchItem( + title: const Text("IPv6"), + subtitle: Text(appLocalizations.ipv6InboundDesc), + delegate: SwitchDelegate( + value: ipv6, + onChanged: (bool value) async { + ref.read(vpnSettingProvider.notifier).updateState( + (state) => state.copyWith( + ipv6: value, + ), ); - }, - ), - ); - }, + }, + ), ); } } -class TunStackItem extends StatelessWidget { +class TunStackItem extends ConsumerWidget { const TunStackItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.tun.stack, - builder: (_, stack, __) { - return ListItem.options( - title: Text(appLocalizations.stackMode), - subtitle: Text(stack.name), - delegate: OptionsDelegate( - value: stack, - options: TunStack.values, - textBuilder: (value) => value.name, - onChanged: (value) { - if (value == null) { - return; - } - final clashConfig = globalState.appController.clashConfig; - clashConfig.tun = clashConfig.tun.copyWith( - stack: value, + Widget build(BuildContext context, ref) { + final stack = + ref.watch(patchClashConfigProvider.select((state) => state.tun.stack)); + + return ListItem.options( + title: Text(appLocalizations.stackMode), + subtitle: Text(stack.name), + delegate: OptionsDelegate( + value: stack, + options: TunStack.values, + textBuilder: (value) => value.name, + onChanged: (value) { + if (value == null) { + return; + } + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith.tun( + stack: value, + ), ); - }, - title: appLocalizations.stackMode, - ), - ); - }, + }, + title: appLocalizations.stackMode, + ), ); } } -class BypassDomainItem extends StatelessWidget { +class BypassDomainItem extends ConsumerWidget { const BypassDomainItem({super.key}); - _initActions(BuildContext context) { + _initActions(BuildContext context, WidgetRef ref) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { context.commonScaffoldState?.actions = [ IconButton( @@ -218,10 +203,11 @@ class BypassDomainItem extends StatelessWidget { if (res != true) { return; } - final config = globalState.appController.config; - config.networkProps = config.networkProps.copyWith( - bypassDomain: defaultBypassDomain, - ); + ref.read(networkSettingProvider.notifier).updateState( + (state) => state.copyWith( + bypassDomain: defaultBypassDomain, + ), + ); }, tooltip: appLocalizations.reset, icon: const Icon( @@ -233,7 +219,10 @@ class BypassDomainItem extends StatelessWidget { } @override - Widget build(BuildContext context) { + Widget build(BuildContext context, ref) { + final bypassDomain = + ref.watch(networkSettingProvider.select((state) => state.bypassDomain)); + return ListItem.open( title: Text(appLocalizations.bypassDomain), subtitle: Text(appLocalizations.bypassDomainDesc), @@ -241,101 +230,91 @@ class BypassDomainItem extends StatelessWidget { isBlur: false, isScaffold: true, title: appLocalizations.bypassDomain, - widget: Selector>( - selector: (_, config) => config.networkProps.bypassDomain, - shouldRebuild: (prev, next) => !stringListEquality.equals(prev, next), - builder: (context, bypassDomain, __) { - _initActions(context); - return ListPage( - title: appLocalizations.bypassDomain, - items: bypassDomain, - titleBuilder: (item) => Text(item), - onChange: (items) { - final config = globalState.appController.config; - config.networkProps = config.networkProps.copyWith( - bypassDomain: List.from(items), - ); - }, - ); - }, - ), + widget: Builder(builder: (context) { + _initActions(context, ref); + return ListPage( + title: appLocalizations.bypassDomain, + items: bypassDomain, + titleBuilder: (item) => Text(item), + onChange: (items) { + ref.read(networkSettingProvider.notifier).updateState( + (state) => state.copyWith( + bypassDomain: List.from(items), + ), + ); + }, + ); + }), extendPageWidth: 360, ), ); } } -class RouteModeItem extends StatelessWidget { +class RouteModeItem extends ConsumerWidget { const RouteModeItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.routeMode, - builder: (_, value, __) { - return ListItem.options( - title: Text(appLocalizations.routeMode), - subtitle: Text(Intl.message("routeMode_${value.name}")), - delegate: OptionsDelegate( - title: appLocalizations.routeMode, - options: RouteMode.values, - onChanged: (RouteMode? value) { - if (value == null) { - return; - } - final appController = globalState.appController; - appController.clashConfig.routeMode = value; - }, - textBuilder: (routeMode) => Intl.message( - "routeMode_${routeMode.name}", - ), - value: value, - ), - ); - }, + Widget build(BuildContext context, ref) { + final routeMode = + ref.watch(networkSettingProvider.select((state) => state.routeMode)); + return ListItem.options( + title: Text(appLocalizations.routeMode), + subtitle: Text(Intl.message("routeMode_${routeMode.name}")), + delegate: OptionsDelegate( + title: appLocalizations.routeMode, + options: RouteMode.values, + onChanged: (RouteMode? value) { + if (value == null) { + return; + } + ref.read(networkSettingProvider.notifier).updateState( + (state) => state.copyWith( + routeMode: value, + ), + ); + }, + textBuilder: (routeMode) => Intl.message( + "routeMode_${routeMode.name}", + ), + value: routeMode, + ), ); } } -class RouteAddressItem extends StatelessWidget { +class RouteAddressItem extends ConsumerWidget { const RouteAddressItem({super.key}); @override - Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => clashConfig.routeMode == RouteMode.config, - builder: (_, value, child) { - if (value) { - return child!; - } - return Container(); - }, - child: ListItem.open( - title: Text(appLocalizations.routeAddress), - subtitle: Text(appLocalizations.routeAddressDesc), - delegate: OpenDelegate( - isBlur: false, - isScaffold: true, + Widget build(BuildContext context, ref) { + final bypassPrivate = ref.watch(networkSettingProvider + .select((state) => state.routeMode == RouteMode.bypassPrivate)); + if (bypassPrivate) { + return Container(); + } + final routeAddress = ref.watch( + patchClashConfigProvider.select((state) => state.tun.routeAddress)); + return ListItem.open( + title: Text(appLocalizations.routeAddress), + subtitle: Text(appLocalizations.routeAddressDesc), + delegate: OpenDelegate( + isBlur: false, + isScaffold: true, + title: appLocalizations.routeAddress, + widget: ListPage( title: appLocalizations.routeAddress, - widget: Selector>( - selector: (_, clashConfig) => clashConfig.includeRouteAddress, - shouldRebuild: (prev, next) => - !stringListEquality.equals(prev, next), - builder: (context, routeAddress, __) { - return ListPage( - title: appLocalizations.routeAddress, - items: routeAddress, - titleBuilder: (item) => Text(item), - onChange: (items) { - final clashConfig = globalState.appController.clashConfig; - clashConfig.includeRouteAddress = - Set.from(items).toList(); - }, - ); - }, - ), - extendPageWidth: 360, + items: routeAddress, + titleBuilder: (item) => Text(item), + onChange: (items) { + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith.tun( + routeAddress: List.from(items), + ), + ); + }, ), + extendPageWidth: 360, ), ); } @@ -347,7 +326,8 @@ final networkItems = [ ...generateSection( title: "VPN", items: [ - const SystemProxyItem(), + const VpnSystemProxyItem(), + const BypassDomainItem(), const AllowBypassItem(), const Ipv6Item(), ], @@ -371,10 +351,10 @@ final networkItems = [ ), ]; -class NetworkListView extends StatelessWidget { +class NetworkListView extends ConsumerWidget { const NetworkListView({super.key}); - _initActions(BuildContext context) { + _initActions(BuildContext context, WidgetRef ref) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { context.commonScaffoldState?.actions = [ IconButton( @@ -388,9 +368,14 @@ class NetworkListView extends StatelessWidget { if (res != true) { return; } - final appController = globalState.appController; - appController.config.vpnProps = defaultVpnProps; - appController.clashConfig.tun = defaultTun; + ref.read(vpnSettingProvider.notifier).updateState( + (state) => defaultVpnProps, + ); + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith( + tun: defaultTun, + ), + ); }, tooltip: appLocalizations.reset, icon: const Icon( @@ -402,8 +387,8 @@ class NetworkListView extends StatelessWidget { } @override - Widget build(BuildContext context) { - _initActions(context); + Widget build(BuildContext context, ref) { + _initActions(context, ref); return generateListView( networkItems, ); diff --git a/lib/fragments/connection/connections.dart b/lib/fragments/connection/connections.dart index ed0e63c..8ae9e23 100644 --- a/lib/fragments/connection/connections.dart +++ b/lib/fragments/connection/connections.dart @@ -4,21 +4,23 @@ import 'package:fl_clash/clash/clash.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/providers/providers.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'item.dart'; -class ConnectionsFragment extends StatefulWidget { +class ConnectionsFragment extends ConsumerStatefulWidget { const ConnectionsFragment({super.key}); @override - State createState() => _ConnectionsFragmentState(); + ConsumerState createState() => + _ConnectionsFragmentState(); } -class _ConnectionsFragmentState extends State - with ViewMixin { +class _ConnectionsFragmentState extends ConsumerState + with PageMixin { final _connectionsStateNotifier = ValueNotifier( const ConnectionsState(), ); @@ -71,15 +73,20 @@ class _ConnectionsFragmentState extends State @override void initState() { super.initState(); - _updateConnections(); - } - - _initActions() { - WidgetsBinding.instance.addPostFrameCallback( - (_) { - initViewState(); + ref.listenManual( + isCurrentPageProvider( + PageLabel.connections, + handler: (pageLabel, viewMode) => + pageLabel == PageLabel.tools && viewMode == ViewMode.mobile, + ), + (prev, next) { + if (prev != next && next == true) { + initPageState(); + } }, + fireImmediately: true, ); + _updateConnections(); } _handleBlockConnection(String id) async { @@ -100,56 +107,44 @@ class _ConnectionsFragmentState extends State @override Widget build(BuildContext context) { - return Selector( - selector: (_, appState) => - appState.currentLabel == 'connections' || - appState.viewMode == ViewMode.mobile && - appState.currentLabel == "tools", - builder: (_, isCurrent, child) { - if (isCurrent == null || isCurrent) { - _initActions(); - } - return child!; - }, - child: ValueListenableBuilder( - valueListenable: _connectionsStateNotifier, - builder: (_, state, __) { - final connections = state.list; - if (connections.isEmpty) { - return NullStatus( - label: appLocalizations.nullConnectionsDesc, - ); - } - return CommonScrollBar( - controller: _scrollController, - child: ListView.separated( - controller: _scrollController, - itemBuilder: (_, index) { - final connection = connections[index]; - return ConnectionItem( - key: Key(connection.id), - connection: connection, - onClick: (value) { - context.commonScaffoldState?.addKeyword(value); - }, - trailing: IconButton( - icon: const Icon(Icons.block), - onPressed: () { - _handleBlockConnection(connection.id); - }, - ), - ); - }, - separatorBuilder: (BuildContext context, int index) { - return const Divider( - height: 0, - ); - }, - itemCount: connections.length, - ), + return ValueListenableBuilder( + valueListenable: _connectionsStateNotifier, + builder: (_, state, __) { + final connections = state.list; + if (connections.isEmpty) { + return NullStatus( + label: appLocalizations.nullConnectionsDesc, ); - }, - ), + } + return CommonScrollBar( + controller: _scrollController, + child: ListView.separated( + controller: _scrollController, + itemBuilder: (_, index) { + final connection = connections[index]; + return ConnectionItem( + key: Key(connection.id), + connection: connection, + onClick: (value) { + context.commonScaffoldState?.addKeyword(value); + }, + trailing: IconButton( + icon: const Icon(Icons.block), + onPressed: () { + _handleBlockConnection(connection.id); + }, + ), + ); + }, + separatorBuilder: (BuildContext context, int index) { + return const Divider( + height: 0, + ); + }, + itemCount: connections.length, + ), + ); + }, ); } } diff --git a/lib/fragments/connection/item.dart b/lib/fragments/connection/item.dart index fae0414..eef2d88 100644 --- a/lib/fragments/connection/item.dart +++ b/lib/fragments/connection/item.dart @@ -4,9 +4,10 @@ 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/plugins/app.dart'; +import 'package:fl_clash/providers/config.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; class FindProcessBuilder extends StatelessWidget { final Widget Function(bool value) builder; @@ -18,11 +19,15 @@ class FindProcessBuilder extends StatelessWidget { @override Widget build(BuildContext context) { - return Selector( - selector: (_, clashConfig) => - clashConfig.findProcessMode == FindProcessMode.always && - Platform.isAndroid, - builder: (_, value, __) { + return Consumer( + builder: (_, ref, __) { + final value = ref.watch( + patchClashConfigProvider.select( + (state) => + state.findProcessMode == FindProcessMode.always && + Platform.isAndroid, + ), + ); return builder(value); }, ); diff --git a/lib/fragments/connection/requests.dart b/lib/fragments/connection/requests.dart index 8a6bffd..2971472 100644 --- a/lib/fragments/connection/requests.dart +++ b/lib/fragments/connection/requests.dart @@ -1,28 +1,25 @@ -import 'dart:async'; -import 'dart:io'; -import 'dart:math'; - -import 'package:collection/collection.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/providers/providers.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'item.dart'; double _preOffset = 0; -class RequestsFragment extends StatefulWidget { +class RequestsFragment extends ConsumerStatefulWidget { const RequestsFragment({super.key}); @override - State createState() => _RequestsFragmentState(); + ConsumerState createState() => _RequestsFragmentState(); } -class _RequestsFragmentState extends State with ViewMixin { +class _RequestsFragmentState extends ConsumerState + with PageMixin { final _requestsStateNotifier = ValueNotifier(const ConnectionsState()); List _requests = []; @@ -51,18 +48,32 @@ class _RequestsFragmentState extends State with ViewMixin { @override void initState() { super.initState(); - final appController = globalState.appController; - final appState = appController.appState; _requestsStateNotifier.value = _requestsStateNotifier.value.copyWith( - connections: appState.requests, + connections: globalState.appState.requests.list, ); - } - _initActions() { - WidgetsBinding.instance.addPostFrameCallback( - (_) { - initViewState(); + ref.listenManual( + isCurrentPageProvider( + PageLabel.requests, + handler: (pageLabel, viewMode) => + pageLabel == PageLabel.tools && viewMode == ViewMode.mobile, + ), + (prev, next) { + if (prev != next && next == true) { + initPageState(); + } }, + fireImmediately: true, + ); + ref.listenManual( + requestsProvider.select((state) => state.list), + (prev, next) { + if (!connectionListEquality.equals(prev, next)) { + _requests = next; + updateRequestsThrottler(); + } + }, + fireImmediately: true, ); } @@ -111,22 +122,6 @@ class _RequestsFragmentState extends State with ViewMixin { super.dispose(); } - Widget _wrapPage(Widget child) { - return Selector( - selector: (_, appState) => - appState.currentLabel == 'requests' || - appState.viewMode == ViewMode.mobile && - appState.currentLabel == "tools", - builder: (_, isCurrent, child) { - if (isCurrent == null || isCurrent) { - _initActions(); - } - return child!; - }, - child: child, - ); - } - updateRequestsThrottler() { throttler.call("request", () { final isEquality = connectionListEquality.equals( @@ -144,93 +139,71 @@ class _RequestsFragmentState extends State with ViewMixin { }, duration: commonDuration); } - Widget _wrapRequestsUpdate(Widget child) { - return Selector>( - selector: (_, appState) => appState.requests, - shouldRebuild: (prev, next) { - final isEquality = connectionListEquality.equals(prev, next); - if (!isEquality) { - _requests = next; - updateRequestsThrottler(); - } - return !isEquality; - }, - builder: (_, next, child) { - return child!; - }, - child: child, - ); - } - @override Widget build(BuildContext context) { return LayoutBuilder( builder: (_, constraints) { return FindProcessBuilder(builder: (value) { _handleTryClearCache(constraints.maxWidth - 40 - (value ? 60 : 0)); - return _wrapPage( - _wrapRequestsUpdate( - ValueListenableBuilder( - valueListenable: _requestsStateNotifier, - builder: (_, state, __) { - final connections = state.list; - if (connections.isEmpty) { - return NullStatus( - label: appLocalizations.nullRequestsDesc, - ); - } - final items = connections - .map( - (connection) => ConnectionItem( - key: Key(connection.id), - connection: connection, - onClick: (value) { - context.commonScaffoldState?.addKeyword(value); - }, - ), - ) - .separated( - const Divider( - height: 0, - ), - ) - .toList(); - return Align( - alignment: Alignment.topCenter, - child: NotificationListener( - onNotification: (details) { - _preOffset = details.metrics.pixels; - return false; + return ValueListenableBuilder( + valueListenable: _requestsStateNotifier, + builder: (_, state, __) { + final connections = state.list; + if (connections.isEmpty) { + return NullStatus( + label: appLocalizations.nullRequestsDesc, + ); + } + final items = connections + .map( + (connection) => ConnectionItem( + key: Key(connection.id), + connection: connection, + onClick: (value) { + context.commonScaffoldState?.addKeyword(value); }, - child: CommonScrollBar( - controller: _scrollController, - child: ListView.builder( - reverse: true, - shrinkWrap: true, - physics: NextClampingScrollPhysics(), - controller: _scrollController, - itemExtentBuilder: (index, __) { - final widget = items[index]; - if (widget.runtimeType == Divider) { - return 0; - } - final measure = globalState.measure; - final bodyMediumHeight = measure.bodyMediumHeight; - final connection = connections[(index / 2).floor()]; - final height = _calcCacheHeight(connection); - return height + bodyMediumHeight + 32; - }, - itemBuilder: (_, index) { - return items[index]; - }, - itemCount: items.length, - ), - ), ), - ); - }, - ), - ), + ) + .separated( + const Divider( + height: 0, + ), + ) + .toList(); + return Align( + alignment: Alignment.topCenter, + child: NotificationListener( + onNotification: (details) { + _preOffset = details.metrics.pixels; + return false; + }, + child: CommonScrollBar( + controller: _scrollController, + child: ListView.builder( + reverse: true, + shrinkWrap: true, + physics: NextClampingScrollPhysics(), + controller: _scrollController, + itemExtentBuilder: (index, __) { + final widget = items[index]; + if (widget.runtimeType == Divider) { + return 0; + } + final measure = globalState.measure; + final bodyMediumHeight = measure.bodyMediumHeight; + final connection = connections[(index / 2).floor()]; + final height = _calcCacheHeight(connection); + return height + bodyMediumHeight + 32; + }, + itemBuilder: (_, index) { + return items[index]; + }, + itemCount: items.length, + ), + ), + ), + ); + }, ); }); }, diff --git a/lib/fragments/dashboard/dashboard.dart b/lib/fragments/dashboard/dashboard.dart index e76f56f..bdcf91c 100644 --- a/lib/fragments/dashboard/dashboard.dart +++ b/lib/fragments/dashboard/dashboard.dart @@ -2,31 +2,42 @@ import 'dart:math'; 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'; +import 'package:fl_clash/providers/providers.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'widgets/start_button.dart'; -class DashboardFragment extends StatefulWidget { +class DashboardFragment extends ConsumerStatefulWidget { const DashboardFragment({super.key}); @override - State createState() => _DashboardFragmentState(); + ConsumerState createState() => _DashboardFragmentState(); } -class _DashboardFragmentState extends State { +class _DashboardFragmentState extends ConsumerState + with PageMixin { final key = GlobalKey(); - _initScaffold(bool isCurrent) { - if (!isCurrent) { - return; - } - WidgetsBinding.instance.addPostFrameCallback((_) { - final commonScaffoldState = context.commonScaffoldState; - commonScaffoldState?.floatingActionButton = const StartButton(); - commonScaffoldState?.actions = [ + @override + initState() { + ref.listenManual( + isCurrentPageProvider(PageLabel.dashboard), + (prev, next) { + if (prev != next && next == true) { + initPageState(); + } + }, + fireImmediately: true, + ); + return super.initState(); + } + + @override + Widget? get floatingActionButton => const StartButton(); + + @override + List get actions => [ ValueListenableBuilder( valueListenable: key.currentState!.addedChildrenNotifier, builder: (_, addedChildren, child) { @@ -67,72 +78,59 @@ class _DashboardFragmentState extends State { }, ), ]; - }); + + _handleSave(List girdItems, WidgetRef ref) { + final dashboardWidgets = girdItems + .map( + (item) => DashboardWidget.getDashboardWidget(item), + ) + .toList(); + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith(dashboardWidgets: dashboardWidgets), + ); } @override Widget build(BuildContext context) { - return ActiveBuilder( - label: "dashboard", - builder: (isCurrent, child) { - _initScaffold(isCurrent); - return child!; - }, - child: Align( - alignment: Alignment.topCenter, - child: SingleChildScrollView( - padding: const EdgeInsets.all(16).copyWith( - bottom: 88, - ), - child: Selector2( - selector: (_, appState, config) => DashboardState( - dashboardWidgets: config.appSetting.dashboardWidgets, - viewWidth: appState.viewWidth, - ), - builder: (_, state, ___) { - final columns = max(4 * ((state.viewWidth / 350).ceil()), 8); - return SuperGrid( - key: key, - crossAxisCount: columns, - crossAxisSpacing: 16, - mainAxisSpacing: 16, - children: [ - ...state.dashboardWidgets - .where( - (item) => item.platforms.contains( - SupportPlatform.currentPlatform, - ), - ) - .map( - (item) => item.widget, + final dashboardState = ref.watch(dashboardStateProvider); + final columns = max(4 * ((dashboardState.viewWidth / 350).ceil()), 8); + return Align( + alignment: Alignment.topCenter, + child: SingleChildScrollView( + padding: const EdgeInsets.all(16).copyWith( + bottom: 88, + ), + child: SuperGrid( + key: key, + crossAxisCount: columns, + crossAxisSpacing: 16, + mainAxisSpacing: 16, + children: [ + ...dashboardState.dashboardWidgets + .where( + (item) => item.platforms.contains( + SupportPlatform.currentPlatform, + ), + ) + .map( + (item) => item.widget, + ), + ], + onSave: (girdItems) { + _handleSave(girdItems, ref); + }, + addedItemsBuilder: (girdItems) { + return DashboardWidget.values + .where( + (item) => + !girdItems.contains(item.widget) && + item.platforms.contains( + SupportPlatform.currentPlatform, ), - ], - onSave: (girdItems) { - final dashboardWidgets = girdItems - .map( - (item) => DashboardWidget.getDashboardWidget(item), - ) - .toList(); - final config = globalState.appController.config; - config.appSetting = config.appSetting.copyWith( - dashboardWidgets: dashboardWidgets, - ); - }, - addedItemsBuilder: (girdItems) { - return DashboardWidget.values - .where( - (item) => - !girdItems.contains(item.widget) && - item.platforms.contains( - SupportPlatform.currentPlatform, - ), - ) - .map((item) => item.widget) - .toList(); - }, - ); - }, - ), + ) + .map((item) => item.widget) + .toList(); + }, ), ), ); diff --git a/lib/fragments/dashboard/widgets/core_info.dart b/lib/fragments/dashboard/widgets/core_info.dart deleted file mode 100644 index a080556..0000000 --- a/lib/fragments/dashboard/widgets/core_info.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:fl_clash/models/models.dart'; -import 'package:fl_clash/widgets/widgets.dart'; -import 'package:fl_clash/common/common.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -class CoreInfo extends StatelessWidget { - const CoreInfo({super.key}); - - @override - Widget build(BuildContext context) { - return Selector( - selector: (_, appState) => appState.versionInfo, - builder: (_, versionInfo, __) { - return CommonCard( - onPressed: () {}, - info: Info( - label: appLocalizations.coreInfo, - iconData: Icons.memory, - ), - child: Container( - alignment: Alignment.centerLeft, - padding: const EdgeInsets.all(16).copyWith(top: 0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Flexible( - flex: 1, - child: Text( - versionInfo?.clashName ?? '', - style: context - .textTheme - .titleMedium - ?.toSoftBold, - ), - ), - const SizedBox( - height: 8, - ), - Flexible( - flex: 1, - child: Text( - versionInfo?.version ?? '', - style: context - .textTheme - .titleLarge - ?.toSoftBold, - ), - ), - ], - ), - ), - ); - }, - ); - } -} diff --git a/lib/fragments/dashboard/widgets/intranet_ip.dart b/lib/fragments/dashboard/widgets/intranet_ip.dart index 2586d41..7022a36 100644 --- a/lib/fragments/dashboard/widgets/intranet_ip.dart +++ b/lib/fragments/dashboard/widgets/intranet_ip.dart @@ -1,9 +1,9 @@ import 'package:fl_clash/common/common.dart'; -import 'package:fl_clash/models/app.dart'; +import 'package:fl_clash/providers/app.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; class IntranetIP extends StatelessWidget { const IntranetIP({super.key}); @@ -28,15 +28,15 @@ class IntranetIP extends StatelessWidget { children: [ SizedBox( height: globalState.measure.bodyMediumHeight + 2, - child: Selector( - selector: (_, appFlowingState) => appFlowingState.localIp, - builder: (_, value, __) { + child: Consumer( + builder: (_, ref, __) { + final localIp = ref.watch(localIpProvider); return FadeBox( - child: value != null + child: localIp != null ? TooltipText( text: Text( - value.isNotEmpty - ? value + localIp.isNotEmpty + ? localIp : appLocalizations.noNetwork, style: context.textTheme.bodyMedium?.toLight .adjustSize(1), @@ -48,7 +48,9 @@ class IntranetIP extends StatelessWidget { padding: EdgeInsets.all(2), child: AspectRatio( aspectRatio: 1, - child: CircularProgressIndicator(), + child: CircularProgressIndicator( + strokeWidth: 2, + ), ), ), ); diff --git a/lib/fragments/dashboard/widgets/memory_info.dart b/lib/fragments/dashboard/widgets/memory_info.dart index b5554dd..802bd61 100644 --- a/lib/fragments/dashboard/widgets/memory_info.dart +++ b/lib/fragments/dashboard/widgets/memory_info.dart @@ -47,6 +47,11 @@ class _MemoryInfoState extends State { @override Widget build(BuildContext context) { + final darkenLighter = context.colorScheme.secondaryContainer + .blendDarken(context, factor: 0.1) + .toLighter; + final darken = context.colorScheme.secondaryContainer + .blendDarken(context, factor: 0.1); return SizedBox( height: getWidgetHeight(2), child: CommonCard( @@ -90,17 +95,14 @@ class _MemoryInfoState extends State { child: WaveView( waveAmplitude: 12.0, waveFrequency: 0.35, - waveColor: context.colorScheme.secondaryContainer - .blendDarken(context, factor: 0.1) - .toLighter, + waveColor: darkenLighter, ), ), Positioned.fill( child: WaveView( waveAmplitude: 12.0, waveFrequency: 0.9, - waveColor: context.colorScheme.secondaryContainer - .blendDarken(context, factor: 0.1), + waveColor: darken, ), ), ], diff --git a/lib/fragments/dashboard/widgets/network_detection.dart b/lib/fragments/dashboard/widgets/network_detection.dart index 78b90a0..9fc8e0b 100644 --- a/lib/fragments/dashboard/widgets/network_detection.dart +++ b/lib/fragments/dashboard/widgets/network_detection.dart @@ -4,10 +4,11 @@ import 'package:dio/dio.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/providers/app.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; final _networkDetectionState = ValueNotifier( const NetworkDetectionState( @@ -16,14 +17,14 @@ final _networkDetectionState = ValueNotifier( ), ); -class NetworkDetection extends StatefulWidget { +class NetworkDetection extends ConsumerStatefulWidget { const NetworkDetection({super.key}); @override - State createState() => _NetworkDetectionState(); + ConsumerState createState() => _NetworkDetectionState(); } -class _NetworkDetectionState extends State { +class _NetworkDetectionState extends ConsumerState { bool? _preIsStart; Timer? _setTimeoutTimer; CancelToken? cancelToken; @@ -31,6 +32,11 @@ class _NetworkDetectionState extends State { @override void initState() { + ref.listenManual(checkIpNumProvider, (prev, next) { + if (prev != next) { + _startCheck(); + } + }); super.initState(); } @@ -47,12 +53,13 @@ class _NetworkDetectionState extends State { } _checkIp() async { - final appState = globalState.appController.appState; - final appFlowingState = globalState.appController.appFlowingState; + final appState = globalState.appState; final isInit = appState.isInit; if (!isInit) return; - final isStart = appFlowingState.isStart; - if (_preIsStart == false && _preIsStart == isStart) return; + final isStart = appState.runTime != null; + if (_preIsStart == false && + _preIsStart == isStart && + _networkDetectionState.value.ipInfo != null) return; _clearSetTimeoutTimer(); _networkDetectionState.value = _networkDetectionState.value.copyWith( isTesting: true, @@ -109,24 +116,6 @@ class _NetworkDetectionState extends State { } } - _checkIpContainer(Widget child) { - return Selector( - selector: (_, appState) { - return appState.checkIpNum; - }, - shouldRebuild: (prev, next) { - if (prev != next) { - _startCheck(); - } - return prev != next; - }, - builder: (_, checkIpNum, child) { - return child!; - }, - child: child, - ); - } - _countryCodeToEmoji(String countryCode) { final String code = countryCode.toUpperCase(); if (code.length != 2) { @@ -141,109 +130,130 @@ class _NetworkDetectionState extends State { Widget build(BuildContext context) { return SizedBox( height: getWidgetHeight(1), - child: _checkIpContainer( - ValueListenableBuilder( - valueListenable: _networkDetectionState, - builder: (_, state, __) { - final ipInfo = state.ipInfo; - final isTesting = state.isTesting; - return CommonCard( - onPressed: () {}, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - height: globalState.measure.titleMediumHeight + 16, - padding: baseInfoEdgeInsets.copyWith( - bottom: 0, - ), - child: Row( - mainAxisSize: MainAxisSize.max, - children: [ - ipInfo != null - ? Text( - _countryCodeToEmoji( - ipInfo.countryCode, - ), - style: Theme.of(context) - .textTheme - .titleMedium - ?.toLight - .copyWith( - fontFamily: FontFamily.twEmoji.value, - ), - ) - : Icon( - Icons.network_check, - color: Theme.of(context) - .colorScheme - .onSurfaceVariant, + child: ValueListenableBuilder( + valueListenable: _networkDetectionState, + builder: (_, state, __) { + final ipInfo = state.ipInfo; + final isTesting = state.isTesting; + return CommonCard( + onPressed: () {}, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + height: globalState.measure.titleMediumHeight + 16, + padding: baseInfoEdgeInsets.copyWith( + bottom: 0, + ), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + ipInfo != null + ? Text( + _countryCodeToEmoji( + ipInfo.countryCode, ), - const SizedBox( - width: 8, - ), - Flexible( - flex: 1, - child: TooltipText( - text: Text( - appLocalizations.networkDetection, - maxLines: 1, - overflow: TextOverflow.ellipsis, style: Theme.of(context) .textTheme - .titleSmall - ?.copyWith( - color: context.colorScheme.onSurfaceVariant, + .titleMedium + ?.toLight + .copyWith( + fontFamily: FontFamily.twEmoji.value, ), + ) + : Icon( + Icons.network_check, + color: Theme.of(context) + .colorScheme + .onSurfaceVariant, ), + const SizedBox( + width: 8, + ), + Flexible( + flex: 1, + child: TooltipText( + text: Text( + appLocalizations.networkDetection, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .titleSmall + ?.copyWith( + color: context.colorScheme.onSurfaceVariant, + ), ), ), - ], - ), + ), + SizedBox(width: 2), + AspectRatio( + aspectRatio: 1, + child: IconButton( + padding: EdgeInsets.zero, + onPressed: () { + globalState.showMessage( + title: appLocalizations.tip, + message: TextSpan( + text: appLocalizations.detectionTip, + ), + cancelable: false, + ); + }, + icon: Icon( + size: 16, + Icons.info_outline, + color: context.colorScheme.onSurfaceVariant, + ), + ), + ) + ], ), - Container( - padding: baseInfoEdgeInsets.copyWith( - top: 0, - ), - child: SizedBox( - height: globalState.measure.bodyMediumHeight + 2, - child: FadeBox( - child: ipInfo != null - ? TooltipText( - text: Text( - ipInfo.ip, - style: context.textTheme.bodyMedium?.toLight - .adjustSize(1), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ) - : FadeBox( - child: isTesting == false && ipInfo == null - ? Text( - "timeout", - style: context.textTheme.bodyMedium - ?.copyWith(color: Colors.red) - .adjustSize(1), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ) - : Container( - padding: const EdgeInsets.all(2), - child: const AspectRatio( - aspectRatio: 1, - child: CircularProgressIndicator(), + ), + Container( + padding: baseInfoEdgeInsets.copyWith( + top: 0, + ), + child: SizedBox( + height: globalState.measure.bodyMediumHeight + 2, + child: FadeBox( + child: ipInfo != null + ? TooltipText( + text: Text( + ipInfo.ip, + style: context.textTheme.bodyMedium?.toLight + .adjustSize(1), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ) + : FadeBox( + child: isTesting == false && ipInfo == null + ? Text( + "timeout", + style: context.textTheme.bodyMedium + ?.copyWith(color: Colors.red) + .adjustSize(1), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ) + : Container( + padding: const EdgeInsets.all(2), + child: const AspectRatio( + aspectRatio: 1, + child: CircularProgressIndicator( + strokeWidth: 2, ), ), - ), - ), + ), + ), ), - ) - ], - ), - ); - }, - ), + ), + ) + ], + ), + ); + }, ), ); } diff --git a/lib/fragments/dashboard/widgets/network_speed.dart b/lib/fragments/dashboard/widgets/network_speed.dart index 4446ac0..e9e8bd0 100644 --- a/lib/fragments/dashboard/widgets/network_speed.dart +++ b/lib/fragments/dashboard/widgets/network_speed.dart @@ -1,8 +1,9 @@ import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/providers/app.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; class NetworkSpeed extends StatefulWidget { const NetworkSpeed({super.key}); @@ -49,9 +50,9 @@ class _NetworkSpeedState extends State { label: appLocalizations.networkSpeed, iconData: Icons.speed_sharp, ), - child: Selector>( - selector: (_, appFlowingState) => appFlowingState.traffics, - builder: (_, traffics, __) { + child: Consumer( + builder: (_, ref, __) { + final traffics = ref.watch(trafficsProvider).list; return Stack( children: [ Positioned.fill( diff --git a/lib/fragments/dashboard/widgets/outbound_mode.dart b/lib/fragments/dashboard/widgets/outbound_mode.dart index 6727c41..c1a52b9 100644 --- a/lib/fragments/dashboard/widgets/outbound_mode.dart +++ b/lib/fragments/dashboard/widgets/outbound_mode.dart @@ -1,11 +1,11 @@ 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/providers/config.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; class OutboundMode extends StatelessWidget { const OutboundMode({super.key}); @@ -15,9 +15,10 @@ class OutboundMode extends StatelessWidget { final height = getWidgetHeight(2); return SizedBox( height: height, - child: Selector( - selector: (_, clashConfig) => clashConfig.mode, - builder: (_, mode, __) { + child: Consumer( + builder: (_, ref, __) { + final mode = + ref.watch(patchClashConfigProvider.select((state) => state.mode)); return CommonCard( onPressed: () {}, info: Info( diff --git a/lib/fragments/dashboard/widgets/quick_options.dart b/lib/fragments/dashboard/widgets/quick_options.dart index 2a69bfb..c330018 100644 --- a/lib/fragments/dashboard/widgets/quick_options.dart +++ b/lib/fragments/dashboard/widgets/quick_options.dart @@ -1,78 +1,76 @@ import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/fragments/config/network.dart'; -import 'package:fl_clash/models/models.dart'; -import 'package:fl_clash/state.dart'; +import 'package:fl_clash/providers/config.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; class TUNButton extends StatelessWidget { const TUNButton({super.key}); @override Widget build(BuildContext context) { - return LocaleBuilder( - builder: (_) => SizedBox( - height: getWidgetHeight(1), - child: CommonCard( - onPressed: () { - showSheet( - context: context, - body: generateListView(generateSection( - items: [ - if (system.isDesktop) const TUNItem(), - const TunStackItem(), - ], - )), - title: appLocalizations.tun, - ); - }, - info: Info( - label: appLocalizations.tun, - iconData: Icons.stacked_line_chart, + return SizedBox( + height: getWidgetHeight(1), + child: CommonCard( + onPressed: () { + showSheet( + context: context, + body: generateListView(generateSection( + items: [ + if (system.isDesktop) const TUNItem(), + const TunStackItem(), + ], + )), + title: appLocalizations.tun, + ); + }, + info: Info( + label: appLocalizations.tun, + iconData: Icons.stacked_line_chart, + ), + child: Container( + padding: baseInfoEdgeInsets.copyWith( + top: 4, + bottom: 8, + right: 8, ), - child: Container( - padding: baseInfoEdgeInsets.copyWith( - top: 4, - bottom: 8, - right: 8, - ), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - flex: 1, - child: TooltipText( - text: Text( - appLocalizations.options, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context) - .textTheme - .titleSmall - ?.adjustSize(-2) - .toLight, - ), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + flex: 1, + child: TooltipText( + text: Text( + appLocalizations.options, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .titleSmall + ?.adjustSize(-2) + .toLight, ), ), - Selector( - selector: (_, clashConfig) => clashConfig.tun.enable, - builder: (_, enable, __) { - return Switch( - value: enable, - onChanged: (value) { - final clashConfig = - globalState.appController.clashConfig; - clashConfig.tun = clashConfig.tun.copyWith( - enable: value, - ); - }, - ); - }, - ) - ], - ), + ), + Consumer( + builder: (_, ref, __) { + final enable = ref.watch(patchClashConfigProvider + .select((state) => state.tun.enable)); + return Switch( + value: enable, + onChanged: (value) { + ref.read(patchClashConfigProvider.notifier).updateState( + (state) => state.copyWith.tun( + enable: value, + ), + ); + }, + ); + }, + ) + ], ), ), ), @@ -87,67 +85,68 @@ class SystemProxyButton extends StatelessWidget { Widget build(BuildContext context) { return SizedBox( height: getWidgetHeight(1), - child: LocaleBuilder( - builder: (_) => CommonCard( - onPressed: () { - showSheet( - context: context, - body: generateListView( - generateSection( - items: [ - SystemProxyItem(), - BypassDomainItem(), - ], - ), + child: CommonCard( + onPressed: () { + showSheet( + context: context, + body: generateListView( + generateSection( + items: [ + SystemProxyItem(), + BypassDomainItem(), + ], ), - title: appLocalizations.systemProxy, - ); - }, - info: Info( - label: appLocalizations.systemProxy, - iconData: Icons.shuffle, - ), - child: Container( - padding: baseInfoEdgeInsets.copyWith( - top: 4, - bottom: 8, - right: 8, ), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - flex: 1, - child: TooltipText( - text: Text( - appLocalizations.options, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context) - .textTheme - .titleSmall - ?.adjustSize(-2) - .toLight, - ), + title: appLocalizations.systemProxy, + ); + }, + info: Info( + label: appLocalizations.systemProxy, + iconData: Icons.shuffle, + ), + child: Container( + padding: baseInfoEdgeInsets.copyWith( + top: 4, + bottom: 8, + right: 8, + ), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + flex: 1, + child: TooltipText( + text: Text( + appLocalizations.options, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .titleSmall + ?.adjustSize(-2) + .toLight, ), ), - Selector( - selector: (_, config) => config.networkProps.systemProxy, - builder: (_, systemProxy, __) { - return Switch( - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - value: systemProxy, - onChanged: (value) { - final config = globalState.appController.config; - config.networkProps = - config.networkProps.copyWith(systemProxy: value); - }, - ); - }, - ) - ], - ), + ), + Consumer( + builder: (_, ref, __) { + final systemProxy = ref.watch(networkSettingProvider + .select((state) => state.systemProxy)); + return Switch( + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + value: systemProxy, + onChanged: (value) { + ref.read(networkSettingProvider.notifier).updateState( + (state) => state.copyWith( + systemProxy: value, + ), + ); + }, + ); + }, + ) + ], ), ), ), diff --git a/lib/fragments/dashboard/widgets/start_button.dart b/lib/fragments/dashboard/widgets/start_button.dart index 1046de3..f7a0c0b 100644 --- a/lib/fragments/dashboard/widgets/start_button.dart +++ b/lib/fragments/dashboard/widgets/start_button.dart @@ -1,8 +1,9 @@ import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/providers/providers.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; class StartButton extends StatefulWidget { const StartButton({super.key}); @@ -19,7 +20,7 @@ class _StartButtonState extends State @override void initState() { super.initState(); - isStart = globalState.appController.appFlowingState.isStart; + isStart = globalState.appState.runTime != null; _controller = AnimationController( vsync: this, value: isStart ? 1 : 0, @@ -34,11 +35,10 @@ class _StartButtonState extends State } handleSwitchStart() { - final appController = globalState.appController; - if (isStart == appController.appFlowingState.isStart) { + if (isStart == globalState.appState.isStart) { isStart = !isStart; updateController(); - appController.updateStatus(isStart); + globalState.appController.updateStatus(isStart); } } @@ -50,31 +50,24 @@ class _StartButtonState extends State } } - Widget _updateControllerContainer(Widget child) { - return Selector( - selector: (_, appFlowingState) => appFlowingState.isStart, - builder: (_, isStart, child) { - if (isStart != this.isStart) { - this.isStart = isStart; - updateController(); - } - return child!; - }, - child: child, - ); - } - @override Widget build(BuildContext context) { - return Selector2( - selector: (_, appState, config) => StartButtonSelectorState( - isInit: appState.isInit, - hasProfile: config.profiles.isNotEmpty, - ), - builder: (_, state, child) { + return Consumer( + builder: (_, ref, child) { + final state = ref.watch(startButtonSelectorStateProvider); if (!state.isInit || !state.hasProfile) { return Container(); } + ref.listenManual( + runTimeProvider.select((state) => state != null), + (prev, next) { + if (next != isStart) { + isStart = next; + updateController(); + } + }, + fireImmediately: true, + ); final textWidth = globalState.measure .computeTextSize( Text( @@ -86,53 +79,51 @@ class _StartButtonState extends State ) .width + 16; - return _updateControllerContainer( - AnimatedBuilder( - animation: _controller.view, - builder: (_, child) { - return SizedBox( - width: 56 + textWidth * _controller.value, - height: 56, - child: FloatingActionButton( - heroTag: null, - onPressed: () { - handleSwitchStart(); - }, - child: Row( - children: [ - Container( - width: 56, - height: 56, - alignment: Alignment.center, - child: AnimatedIcon( - icon: AnimatedIcons.play_pause, - progress: _controller, - ), + return AnimatedBuilder( + animation: _controller.view, + builder: (_, child) { + return SizedBox( + width: 56 + textWidth * _controller.value, + height: 56, + child: FloatingActionButton( + heroTag: null, + onPressed: () { + handleSwitchStart(); + }, + child: Row( + children: [ + Container( + width: 56, + height: 56, + alignment: Alignment.center, + child: AnimatedIcon( + icon: AnimatedIcons.play_pause, + progress: _controller, ), - Expanded( - child: ClipRect( - child: OverflowBox( - maxWidth: textWidth, - child: Container( - alignment: Alignment.centerLeft, - child: child!, - ), + ), + Expanded( + child: ClipRect( + child: OverflowBox( + maxWidth: textWidth, + child: Container( + alignment: Alignment.centerLeft, + child: child!, ), ), ), - ], - ), + ), + ], ), - ); - }, - child: child, - ), + ), + ); + }, + child: child, ); }, - child: Selector( - selector: (_, appFlowingState) => appFlowingState.runTime, - builder: (_, int? value, __) { - final text = other.getTimeText(value); + child: Consumer( + builder: (_, ref, __) { + final runTime = ref.watch(runTimeProvider); + final text = other.getTimeText(runTime); return Text( text, style: Theme.of(context).textTheme.titleMedium?.toSoftBold, diff --git a/lib/fragments/dashboard/widgets/traffic_usage.dart b/lib/fragments/dashboard/widgets/traffic_usage.dart index 7a0e121..3633889 100644 --- a/lib/fragments/dashboard/widgets/traffic_usage.dart +++ b/lib/fragments/dashboard/widgets/traffic_usage.dart @@ -2,10 +2,11 @@ import 'dart:math'; import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/providers/app.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; class TrafficUsage extends StatelessWidget { const TrafficUsage({super.key}); @@ -62,9 +63,9 @@ class TrafficUsage extends StatelessWidget { iconData: Icons.data_saver_off, ), onPressed: () {}, - child: Selector( - selector: (_, appFlowingState) => appFlowingState.totalTraffic, - builder: (_, totalTraffic, __) { + child: Consumer( + builder: (_, ref, __) { + final totalTraffic = ref.watch(totalTrafficProvider); final upTotalTrafficValue = totalTraffic.up; final downTotalTrafficValue = totalTraffic.down; return Padding( diff --git a/lib/fragments/hotkey.dart b/lib/fragments/hotkey.dart index 51eb682..e11f8bf 100644 --- a/lib/fragments/hotkey.dart +++ b/lib/fragments/hotkey.dart @@ -1,13 +1,14 @@ 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/providers/providers.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/card.dart'; import 'package:fl_clash/widgets/list.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; extension IntlExt on Intl { static actionMessage(String messageText) => @@ -38,29 +39,20 @@ class HotKeyFragment extends StatelessWidget { itemCount: HotAction.values.length, itemBuilder: (_, index) { final hotAction = HotAction.values[index]; - return Selector( - selector: (_, config) { - final index = config.hotKeyActions.indexWhere( - (item) => item.action == hotAction, - ); - return index != -1 - ? config.hotKeyActions[index] - : HotKeyAction( - action: hotAction, - ); - }, - builder: (_, value, __) { + return Consumer( + builder: (_, ref, __) { + final hotKeyAction = ref.watch(getHotKeyActionProvider(hotAction)); return ListItem( title: Text(IntlExt.actionMessage(hotAction.name)), subtitle: Text( - getSubtitle(value), + getSubtitle(hotKeyAction), style: context.textTheme.bodyMedium ?.copyWith(color: context.colorScheme.primary), ), onTap: () { globalState.showCommonDialog( child: HotKeyRecorder( - hotKeyAction: value, + hotKeyAction: hotKeyAction, ), ); }, @@ -121,8 +113,7 @@ class _HotKeyRecorderState extends State { _handleRemove() { Navigator.of(context).pop(); - final config = globalState.appController.config; - config.updateOrAddHotKeyAction( + globalState.appController.updateOrAddHotKeyAction( hotKeyActionNotifier.value.copyWith( modifiers: {}, key: null, @@ -132,7 +123,7 @@ class _HotKeyRecorderState extends State { _handleConfirm() { Navigator.of(context).pop(); - final config = globalState.appController.config; + final config = globalState.config; final currentHotkeyAction = hotKeyActionNotifier.value; if (currentHotkeyAction.key == null || currentHotkeyAction.modifiers.isEmpty) { @@ -158,7 +149,7 @@ class _HotKeyRecorderState extends State { ); return; } - config.updateOrAddHotKeyAction( + globalState.appController.updateOrAddHotKeyAction( currentHotkeyAction, ); } diff --git a/lib/fragments/logs.dart b/lib/fragments/logs.dart index 5f5ed1f..99be6bf 100644 --- a/lib/fragments/logs.dart +++ b/lib/fragments/logs.dart @@ -1,24 +1,23 @@ -import 'dart:async'; - import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/enum/enum.dart'; +import 'package:fl_clash/providers/providers.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../models/models.dart'; import '../widgets/widgets.dart'; double _preOffset = 0; -class LogsFragment extends StatefulWidget { +class LogsFragment extends ConsumerStatefulWidget { const LogsFragment({super.key}); @override - State createState() => _LogsFragmentState(); + ConsumerState createState() => _LogsFragmentState(); } -class _LogsFragmentState extends State with ViewMixin { +class _LogsFragmentState extends ConsumerState with PageMixin { final _logsStateNotifier = ValueNotifier(LogsState()); final _scrollController = ScrollController( initialScrollOffset: _preOffset != 0 ? _preOffset : double.maxFinite, @@ -31,10 +30,34 @@ class _LogsFragmentState extends State with ViewMixin { @override void initState() { super.initState(); - final appController = globalState.appController; - final appFlowingState = appController.appFlowingState; _logsStateNotifier.value = _logsStateNotifier.value.copyWith( - logs: appFlowingState.logs, + logs: globalState.appState.logs.list, + ); + ref.listenManual( + logsProvider.select((state) => state.list), + (prev, next) { + if (prev != next) { + final isEquality = logListEquality.equals(prev, next); + if (!isEquality) { + _logs = next; + updateLogsThrottler(); + } + } + }, + fireImmediately: true, + ); + ref.listenManual( + isCurrentPageProvider( + PageLabel.logs, + handler: (pageLabel, viewMode) => + pageLabel == PageLabel.tools && viewMode == ViewMode.mobile, + ), + (prev, next) { + if (prev != next && next == true) { + initPageState(); + } + }, + fireImmediately: true, ); } @@ -93,12 +116,6 @@ class _LogsFragmentState extends State with ViewMixin { ); } - _initActions() { - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - super.initViewState(); - }); - } - double _calcCacheHeight(String text) { final cacheHeight = _cacheDynamicHeightMap.get(text); if (cacheHeight != null) { @@ -140,98 +157,66 @@ class _LogsFragmentState extends State with ViewMixin { }, duration: commonDuration); } - Widget _wrapLogsUpdate(Widget child) { - return Selector>( - selector: (_, appFlowingState) => appFlowingState.logs, - shouldRebuild: (prev, next) { - final isEquality = logListEquality.equals(prev, next); - if (!isEquality) { - _logs = next; - updateLogsThrottler(); - } - return !isEquality; - }, - builder: (_, next, child) { - return child!; - }, - child: child, - ); - } - @override Widget build(BuildContext context) { return LayoutBuilder( builder: (_, constraints) { _handleTryClearCache(constraints.maxWidth - 40); - return Selector( - selector: (_, appState) => - appState.currentLabel == 'logs' || - appState.viewMode == ViewMode.mobile && - appState.currentLabel == "tools", - builder: (_, isCurrent, child) { - if (isCurrent == null || isCurrent) { - _initActions(); - } - return child!; - }, - child: _wrapLogsUpdate( - Align( - alignment: Alignment.topCenter, - child: ValueListenableBuilder( - valueListenable: _logsStateNotifier, - builder: (_, state, __) { - final logs = state.list; - if (logs.isEmpty) { - return NullStatus( - label: appLocalizations.nullLogsDesc, - ); - } - final items = logs - .map( - (log) => LogItem( - key: Key(log.dateTime.toString()), - log: log, - onClick: (value) { - context.commonScaffoldState?.addKeyword(value); - }, - ), - ) - .separated( - const Divider( - height: 0, - ), - ) - .toList(); - return NotificationListener( - onNotification: (details) { - _preOffset = details.metrics.pixels; - return false; - }, - child: CommonScrollBar( - controller: _scrollController, - child: ListView.builder( - reverse: true, - shrinkWrap: true, - physics: NextClampingScrollPhysics(), - controller: _scrollController, - itemBuilder: (_, index) { - return items[index]; - }, - itemExtentBuilder: (index, __) { - final item = items[index]; - if (item.runtimeType == Divider) { - return 0; - } - final log = logs[(index / 2).floor()]; - return _getItemHeight(log); - }, - itemCount: items.length, - ), + return Align( + alignment: Alignment.topCenter, + child: ValueListenableBuilder( + valueListenable: _logsStateNotifier, + builder: (_, state, __) { + final logs = state.list; + if (logs.isEmpty) { + return NullStatus( + label: appLocalizations.nullLogsDesc, + ); + } + final items = logs + .map( + (log) => LogItem( + key: Key(log.dateTime.toString()), + log: log, + onClick: (value) { + context.commonScaffoldState?.addKeyword(value); + }, ), - ); + ) + .separated( + const Divider( + height: 0, + ), + ) + .toList(); + return NotificationListener( + onNotification: (details) { + _preOffset = details.metrics.pixels; + return false; }, - ), - ), + child: CommonScrollBar( + controller: _scrollController, + child: ListView.builder( + reverse: true, + shrinkWrap: true, + physics: NextClampingScrollPhysics(), + controller: _scrollController, + itemBuilder: (_, index) { + return items[index]; + }, + itemExtentBuilder: (index, __) { + final item = items[index]; + if (item.runtimeType == Divider) { + return 0; + } + final log = logs[(index / 2).floor()]; + return _getItemHeight(log); + }, + itemCount: items.length, + ), + ), + ); + }, ), ); }, diff --git a/lib/fragments/profiles/custom_profile.dart b/lib/fragments/profiles/custom_profile.dart new file mode 100644 index 0000000..754fc93 --- /dev/null +++ b/lib/fragments/profiles/custom_profile.dart @@ -0,0 +1,54 @@ +import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/widgets/scaffold.dart'; +import 'package:flutter/material.dart'; + +class CustomProfile extends StatefulWidget { + final String profileId; + + const CustomProfile({ + super.key, + required this.profileId, + }); + + @override + State createState() => _CustomProfileState(); +} + +class _CustomProfileState extends State { + final _currentClashConfigNotifier = ValueNotifier(null); + + @override + void initState() { + super.initState(); + _initCurrentClashConfig(); + } + + _initCurrentClashConfig() async { + // final currentProfileId = globalState.config.currentProfileId; + // if (currentProfileId == null) { + // return; + // } + // _currentClashConfigNotifier.value = + // await clashCore.getProfile(currentProfileId); + } + + @override + Widget build(BuildContext context) { + return CommonScaffold( + body: ValueListenableBuilder( + valueListenable: _currentClashConfigNotifier, + builder: (_, clashConfig, ___) { + if (clashConfig == null) { + return Center( + child: CircularProgressIndicator(), + ); + } + return Column( + children: [], + ); + }, + ), + title: "自定义", + ); + } +} diff --git a/lib/fragments/profiles/profiles.dart b/lib/fragments/profiles/profiles.dart index f8de93f..27395ed 100644 --- a/lib/fragments/profiles/profiles.dart +++ b/lib/fragments/profiles/profiles.dart @@ -4,11 +4,11 @@ import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/fragments/profiles/edit_profile.dart'; import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/providers/providers.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'add_profile.dart'; @@ -19,7 +19,7 @@ class ProfilesFragment extends StatefulWidget { State createState() => _ProfilesFragmentState(); } -class _ProfilesFragmentState extends State { +class _ProfilesFragmentState extends State with PageMixin { Function? applyConfigDebounce; _handleShowAddExtendPage() { @@ -33,21 +33,19 @@ class _ProfilesFragmentState extends State { } _updateProfiles() async { - final appController = globalState.appController; - final config = appController.config; - final profiles = appController.config.profiles; + final profiles = globalState.config.profiles; final messages = []; final updateProfiles = profiles.map( (profile) async { if (profile.type == ProfileType.file) return; - config.setProfile( + globalState.appController.setProfile( profile.copyWith(isUpdating: true), ); try { - await appController.updateProfile(profile); + await globalState.appController.updateProfile(profile); } catch (e) { messages.add("${profile.label ?? profile.id}: $e \n"); - config.setProfile( + globalState.appController.setProfile( profile.copyWith( isUpdating: false, ), @@ -70,96 +68,90 @@ class _ProfilesFragmentState extends State { } } - _initScaffold() { - WidgetsBinding.instance.addPostFrameCallback( - (_) { - if (!mounted) return; - final commonScaffoldState = context.commonScaffoldState; - commonScaffoldState?.actions = [ - IconButton( - onPressed: () { - _updateProfiles(); - }, - icon: const Icon(Icons.sync), - ), - IconButton( - onPressed: () { - final profiles = globalState.appController.config.profiles; - showSheet( - title: appLocalizations.profilesSort, - context: context, - body: SizedBox( - height: 400, - child: ReorderableProfiles(profiles: profiles), - ), - ); - }, - icon: const Icon(Icons.sort), - iconSize: 26, - ), - ]; - commonScaffoldState?.floatingActionButton = FloatingActionButton( - heroTag: null, - onPressed: _handleShowAddExtendPage, - child: const Icon( - Icons.add, - ), - ); - }, - ); - } + @override + List get actions => [ + IconButton( + onPressed: () { + _updateProfiles(); + }, + icon: const Icon(Icons.sync), + ), + IconButton( + onPressed: () { + final profiles = globalState.config.profiles; + showSheet( + title: appLocalizations.profilesSort, + context: context, + body: SizedBox( + height: 400, + child: ReorderableProfiles(profiles: profiles), + ), + ); + }, + icon: const Icon(Icons.sort), + iconSize: 26, + ), + ]; + + @override + Widget? get floatingActionButton => FloatingActionButton( + heroTag: null, + onPressed: _handleShowAddExtendPage, + child: const Icon( + Icons.add, + ), + ); @override Widget build(BuildContext context) { - return ActiveBuilder( - label: "profiles", - builder: (isCurrent, child) { - if (isCurrent) { - _initScaffold(); - } - return child!; - }, - child: Selector2( - selector: (_, appState, config) => ProfilesSelectorState( - profiles: config.profiles, - currentProfileId: config.currentProfileId, - columns: other.getProfilesColumns(appState.viewWidth), - ), - builder: (context, state, child) { - if (state.profiles.isEmpty) { - return NullStatus( - label: appLocalizations.nullProfileDesc, - ); - } - return Align( - alignment: Alignment.topCenter, - child: SingleChildScrollView( - padding: const EdgeInsets.only( - left: 16, - right: 16, - top: 16, - bottom: 88, - ), - child: Grid( - mainAxisSpacing: 16, - crossAxisSpacing: 16, - crossAxisCount: state.columns, - children: [ - for (int i = 0; i < state.profiles.length; i++) - GridItem( - child: ProfileItem( - key: Key(state.profiles[i].id), - profile: state.profiles[i], - groupValue: state.currentProfileId, - onChanged: globalState.appController.changeProfile, - ), - ), - ], - ), - ), + return Consumer( + builder: (_, ref, __) { + ref.listenManual( + isCurrentPageProvider(PageLabel.profiles), + (prev, next) { + if (prev != next && next == true) { + initPageState(); + } + }, + fireImmediately: true, + ); + final profilesSelectorState = ref.watch(profilesSelectorStateProvider); + if (profilesSelectorState.profiles.isEmpty) { + return NullStatus( + label: appLocalizations.nullProfileDesc, ); - }, - ), + } + return Align( + alignment: Alignment.topCenter, + child: SingleChildScrollView( + padding: const EdgeInsets.only( + left: 16, + right: 16, + top: 16, + bottom: 88, + ), + child: Grid( + mainAxisSpacing: 16, + crossAxisSpacing: 16, + crossAxisCount: profilesSelectorState.columns, + children: [ + for (int i = 0; i < profilesSelectorState.profiles.length; i++) + GridItem( + child: ProfileItem( + key: Key(profilesSelectorState.profiles[i].id), + profile: profilesSelectorState.profiles[i], + groupValue: profilesSelectorState.currentProfileId, + onChanged: (profileId) { + ref.read(currentProfileIdProvider.notifier).value = + profileId; + }, + ), + ), + ], + ), + ), + ); + }, ); } } @@ -195,18 +187,17 @@ class ProfileItem extends StatelessWidget { Future updateProfile() async { final appController = globalState.appController; - final config = appController.config; if (profile.type == ProfileType.file) return; await globalState.safeRun(silence: false, () async { try { - config.setProfile( + appController.setProfile( profile.copyWith( isUpdating: true, ), ); await appController.updateProfile(profile); } catch (e) { - config.setProfile( + appController.setProfile( profile.copyWith( isUpdating: false, ), @@ -256,16 +247,16 @@ class ProfileItem extends StatelessWidget { ]; } - _handleCopyLink(BuildContext context) async { - await Clipboard.setData( - ClipboardData( - text: profile.url, - ), - ); - if (context.mounted) { - context.showNotifier(appLocalizations.copySuccess); - } - } + // _handleCopyLink(BuildContext context) async { + // await Clipboard.setData( + // ClipboardData( + // text: profile.url, + // ), + // ); + // if (context.mounted) { + // context.showNotifier(appLocalizations.copySuccess); + // } + // } _handleExportFile(BuildContext context) async { final commonScaffoldState = context.commonScaffoldState; @@ -286,6 +277,15 @@ class ProfileItem extends StatelessWidget { } } + // _handlePushCustomPage(BuildContext context, String id) { + // BaseNavigator.push( + // context, + // CustomProfile( + // profileId: id, + // ), + // ); + // } + @override Widget build(BuildContext context) { final key = GlobalKey(); @@ -326,14 +326,21 @@ class ProfileItem extends StatelessWidget { _handleUpdateProfile(); }, ), - ActionItemData( - icon: Icons.copy, - label: appLocalizations.copyLink, - onPressed: () { - _handleCopyLink(context); - }, - ), + // ActionItemData( + // icon: Icons.copy, + // label: appLocalizations.copyLink, + // onPressed: () { + // _handleCopyLink(context); + // }, + // ), ], + // ActionItemData( + // icon: Icons.extension_outlined, + // label: "自定义", + // onPressed: () { + // _handlePushCustomPage(context, profile.id); + // }, + // ), ActionItemData( icon: Icons.file_copy_outlined, label: appLocalizations.exportFile, @@ -499,7 +506,7 @@ class _ReorderableProfilesState extends State { child: FilledButton.tonal( onPressed: () { Navigator.of(context).pop(); - globalState.appController.config.profiles = profiles; + globalState.appController.setProfiles(profiles); }, style: ButtonStyle( padding: WidgetStateProperty.all( diff --git a/lib/fragments/proxies/card.dart b/lib/fragments/proxies/card.dart index 51c5170..a6020d4 100644 --- a/lib/fragments/proxies/card.dart +++ b/lib/fragments/proxies/card.dart @@ -2,10 +2,11 @@ import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/fragments/proxies/common.dart'; import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/providers/providers.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; class ProxyCard extends StatelessWidget { final String groupName; @@ -35,30 +36,28 @@ class ProxyCard extends StatelessWidget { Widget _buildDelayText() { return SizedBox( height: measure.labelSmallHeight, - child: Selector( - selector: (context, appState) => - globalState.appController.getDelay(proxy.name,testUrl), - builder: (context, delay, __) { - return FadeBox( - child: Builder( - builder: (_) { - if (delay == 0 || delay == null) { - return SizedBox( - height: measure.labelSmallHeight, - width: measure.labelSmallHeight, - child: delay == 0 - ? const CircularProgressIndicator( - strokeWidth: 2, - ) - : IconButton( - icon: const Icon(Icons.bolt), - iconSize: globalState.measure.labelSmallHeight, - padding: EdgeInsets.zero, - onPressed: _handleTestCurrentDelay, - ), - ); - } - return GestureDetector( + child: Consumer( + builder: (context, ref, __) { + final delay = ref.watch(getDelayProvider( + proxyName: proxy.name, + testUrl: testUrl, + )); + return delay == 0 || delay == null + ? SizedBox( + height: measure.labelSmallHeight, + width: measure.labelSmallHeight, + child: delay == 0 + ? const CircularProgressIndicator( + strokeWidth: 2, + ) + : IconButton( + icon: const Icon(Icons.bolt), + iconSize: globalState.measure.labelSmallHeight, + padding: EdgeInsets.zero, + onPressed: _handleTestCurrentDelay, + ), + ) + : GestureDetector( onTap: _handleTestCurrentDelay, child: Text( delay > 0 ? '$delay ms' : "Timeout", @@ -70,9 +69,6 @@ class ProxyCard extends StatelessWidget { ), ), ); - }, - ), - ); }, ), ); @@ -102,18 +98,17 @@ class ProxyCard extends StatelessWidget { } } - _changeProxy(BuildContext context) async { - final appController = globalState.appController; - final isURLTestOrFallback = groupType.isURLTestOrFallback; + _changeProxy(WidgetRef ref) async { + final isComputedSelected = groupType.isComputedSelected; final isSelector = groupType == GroupType.Selector; - if (isURLTestOrFallback || isSelector) { - final currentProxyName = - appController.config.currentSelectedMap[groupName]; - final nextProxyName = switch (isURLTestOrFallback) { + if (isComputedSelected || isSelector) { + final currentProxyName = ref.read(getProxyNameProvider(groupName)); + final nextProxyName = switch (isComputedSelected) { true => currentProxyName == proxy.name ? "" : proxy.name, false => proxy.name, }; - appController.config.updateCurrentSelectedMap( + final appController = globalState.appController; + appController.updateCurrentSelectedMap( groupName, nextProxyName, ); @@ -130,108 +125,136 @@ class ProxyCard extends StatelessWidget { final measure = globalState.measure; final delayText = _buildDelayText(); final proxyNameText = _buildProxyNameText(context); - return currentSelectedProxyNameBuilder( - groupName: groupName, - builder: (currentGroupName) { - return Stack( - children: [ - CommonCard( + return Stack( + children: [ + Consumer( + builder: (_, ref, child) { + final selectedProxyName = + ref.watch(getSelectedProxyNameProvider(groupName)); + return CommonCard( key: key, + enterAnimated: true, onPressed: () { - _changeProxy(context); + _changeProxy(ref); }, - isSelected: currentGroupName == proxy.name, - child: Container( - padding: const EdgeInsets.all(12), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - proxyNameText, - const SizedBox( - height: 8, + isSelected: selectedProxyName == proxy.name, + child: child!, + ); + }, + child: Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + proxyNameText, + const SizedBox( + height: 8, + ), + if (type == ProxyCardType.expand) ...[ + SizedBox( + height: measure.bodySmallHeight, + child: _ProxyDesc( + proxy: proxy, ), - if (type == ProxyCardType.expand) ...[ - SizedBox( - height: measure.bodySmallHeight, - child: Selector( - selector: (context, appState) => appState.getDesc( - proxy.type, - proxy.name, - ), - builder: (_, desc, __) { - return EmojiText( - desc, - overflow: TextOverflow.ellipsis, + ), + const SizedBox( + height: 6, + ), + delayText, + ] else + SizedBox( + height: measure.bodySmallHeight, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Flexible( + flex: 1, + child: TooltipText( + text: Text( + proxy.type, style: context.textTheme.bodySmall?.copyWith( + overflow: TextOverflow.ellipsis, color: context.textTheme.bodySmall?.color?.toLight, ), - ); - }, - ), - ), - const SizedBox( - height: 8, - ), - delayText, - ] else - SizedBox( - height: measure.bodySmallHeight, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Flexible( - flex: 1, - child: TooltipText( - text: Text( - proxy.type, - style: context.textTheme.bodySmall?.copyWith( - overflow: TextOverflow.ellipsis, - color: context - .textTheme.bodySmall?.color?.toLight, - ), - ), - ), ), - delayText, - ], + ), ), - ), - ], - ), - ), - ), - if (groupType.isURLTestOrFallback) - Selector( - selector: (_, config) { - final selectedProxyName = - config.currentSelectedMap[groupName]; - return selectedProxyName ?? ''; - }, - builder: (_, value, child) { - if (value != proxy.name) return Container(); - return child!; - }, - child: Positioned.fill( - child: Container( - alignment: Alignment.topRight, - margin: const EdgeInsets.all(8), - child: Container( - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context).colorScheme.secondaryContainer, - ), - child: const SelectIcon(), + delayText, + ], ), ), - ), - ) - ], - ); - }, + ], + ), + ), + ), + if (groupType.isComputedSelected) + Positioned( + top: 0, + right: 0, + child: _ProxyComputedMark( + groupName: groupName, + proxy: proxy, + ), + ) + ], + ); + } +} + +class _ProxyDesc extends ConsumerWidget { + final Proxy proxy; + + const _ProxyDesc({ + required this.proxy, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final desc = ref.watch( + getProxyDescProvider(proxy), + ); + return EmojiText( + desc, + overflow: TextOverflow.ellipsis, + style: context.textTheme.bodySmall?.copyWith( + color: context.textTheme.bodySmall?.color?.toLight, + ), + ); + } +} + +class _ProxyComputedMark extends ConsumerWidget { + final String groupName; + final Proxy proxy; + + const _ProxyComputedMark({ + required this.groupName, + required this.proxy, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final proxyName = ref.watch( + getProxyNameProvider(groupName), + ); + if (proxyName != proxy.name) { + return SizedBox(); + } + return Container( + alignment: Alignment.topRight, + margin: const EdgeInsets.all(8), + child: Container( + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Theme.of(context).colorScheme.secondaryContainer, + ), + child: const SelectIcon(), + ), ); } } diff --git a/lib/fragments/proxies/common.dart b/lib/fragments/proxies/common.dart index 4c6151d..7115ad4 100644 --- a/lib/fragments/proxies/common.dart +++ b/lib/fragments/proxies/common.dart @@ -3,24 +3,6 @@ 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'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -Widget currentSelectedProxyNameBuilder({ - required String groupName, - required Widget Function(String currentGroupName) builder, -}) { - return Selector2( - selector: (_, appState, config) { - final group = appState.getGroupWithName(groupName); - final selectedProxyName = config.currentSelectedMap[groupName]; - return group?.getCurrentSelectedName(selectedProxyName ?? "") ?? ""; - }, - builder: (_, currentSelectedProxyName, ___) { - return builder(currentSelectedProxyName); - }, - ); -} double get listHeaderHeight { final measure = globalState.measure; @@ -30,9 +12,9 @@ double get listHeaderHeight { double getItemHeight(ProxyCardType proxyCardType) { final measure = globalState.measure; final baseHeight = - 12 * 2 + measure.bodyMediumHeight * 2 + measure.bodySmallHeight + 8 + 4; + 16 + measure.bodyMediumHeight * 2 + measure.bodySmallHeight + 8 + 4; return switch (proxyCardType) { - ProxyCardType.expand => baseHeight + measure.labelSmallHeight + 8, + ProxyCardType.expand => baseHeight + measure.labelSmallHeight + 6, ProxyCardType.shrink => baseHeight, ProxyCardType.min => baseHeight - measure.bodyMediumHeight, }; @@ -40,16 +22,16 @@ double getItemHeight(ProxyCardType proxyCardType) { proxyDelayTest(Proxy proxy, [String? testUrl]) async { final appController = globalState.appController; - final proxyName = appController.appState.getRealProxyName(proxy.name); + final proxyName = appController.getRealProxyName(proxy.name); final url = appController.getRealTestUrl(testUrl); - globalState.appController.setDelay( + appController.setDelay( Delay( url: url, name: proxyName, value: 0, ), ); - globalState.appController.setDelay( + appController.setDelay( await clashCore.getDelay( url, proxyName, @@ -60,21 +42,21 @@ proxyDelayTest(Proxy proxy, [String? testUrl]) async { delayTest(List proxies, [String? testUrl]) async { final appController = globalState.appController; final proxyNames = proxies - .map((proxy) => appController.appState.getRealProxyName(proxy.name)) + .map((proxy) => appController.getRealProxyName(proxy.name)) .toSet() .toList(); final url = appController.getRealTestUrl(testUrl); final delayProxies = proxyNames.map((proxyName) async { - globalState.appController.setDelay( + appController.setDelay( Delay( url: url, name: proxyName, value: 0, ), ); - globalState.appController.setDelay( + appController.setDelay( await clashCore.getDelay( url, proxyName, @@ -86,7 +68,7 @@ delayTest(List proxies, [String? testUrl]) async { for (final batchDelayProxies in batchesDelayProxies) { await Future.wait(batchDelayProxies); } - appController.appState.sortNum++; + appController.addSortNum(); } double getScrollToSelectedOffset({ @@ -94,14 +76,11 @@ double getScrollToSelectedOffset({ required List proxies, }) { final appController = globalState.appController; - final columns = other.getProxiesColumns( - appController.appState.viewWidth, - appController.config.proxiesStyle.layout, - ); - final proxyCardType = appController.config.proxiesStyle.cardType; - final selectedName = appController.getCurrentSelectedName(groupName); + final columns = appController.getProxiesColumns(); + final proxyCardType = globalState.config.proxiesStyle.cardType; + final selectedProxyName = appController.getSelectedProxyName(groupName); final findSelectedIndex = proxies.indexWhere( - (proxy) => proxy.name == selectedName, + (proxy) => proxy.name == selectedProxyName, ); final selectedIndex = findSelectedIndex != -1 ? findSelectedIndex : 0; final rows = (selectedIndex / columns).floor(); diff --git a/lib/fragments/proxies/list.dart b/lib/fragments/proxies/list.dart index 8520fe0..324d3e8 100644 --- a/lib/fragments/proxies/list.dart +++ b/lib/fragments/proxies/list.dart @@ -3,10 +3,13 @@ import 'dart:math'; 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/providers/app.dart'; +import 'package:fl_clash/providers/config.dart'; +import 'package:fl_clash/providers/state.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'card.dart'; import 'common.dart'; @@ -78,7 +81,7 @@ class _ProxiesListFragmentState extends State { } else { tempUnfoldSet.add(groupName); } - globalState.appController.config.updateCurrentUnfoldSet( + globalState.appController.updateCurrentUnfoldSet( tempUnfoldSet, ); WidgetsBinding.instance.addPostFrameCallback((_) { @@ -105,7 +108,8 @@ class _ProxiesListFragmentState extends State { return itemHeightList; } - List _buildItems({ + List _buildItems( + WidgetRef ref, { required List groupNames, required int columns, required Set currentUnfoldSet, @@ -115,7 +119,10 @@ class _ProxiesListFragmentState extends State { final GroupNameProxiesMap groupNameProxiesMap = {}; for (final groupName in groupNames) { final group = - globalState.appController.appState.getGroupWithName(groupName)!; + ref.read(groupsProvider.select((state) => state.getGroup(groupName))); + if (group == null) { + continue; + } final isExpand = currentUnfoldSet.contains(groupName); items.addAll([ ListHeader( @@ -186,16 +193,21 @@ class _ProxiesListFragmentState extends State { return items; } - _buildHeader({ + _buildHeader( + WidgetRef ref, { required String groupName, required Set currentUnfoldSet, }) { final group = - globalState.appController.appState.getGroupWithName(groupName)!; + ref.read(groupsProvider.select((state) => state.getGroup(groupName))); + if (group == null) { + return SizedBox(); + } final isExpand = currentUnfoldSet.contains(groupName); return SizedBox( height: listHeaderHeight, child: ListHeader( + enterAnimated: false, onScrollToSelected: _scrollToGroupSelected, key: Key(groupName), isExpand: isExpand, @@ -212,7 +224,7 @@ class _ProxiesListFragmentState extends State { return; } final appController = globalState.appController; - final currentGroups = appController.appState.currentGroups; + final currentGroups = appController.getCurrentGroups(); final groupNames = currentGroups.map((e) => e.name).toList(); final findIndex = groupNames.indexWhere((item) => item == groupName); final index = findIndex != -1 ? findIndex : 0; @@ -235,38 +247,16 @@ class _ProxiesListFragmentState extends State { @override Widget build(BuildContext context) { - return Selector2( - selector: (_, appState, config) { - final currentGroups = appState.currentGroups; - final groupNames = currentGroups.map((e) => e.name).toList(); - return ProxiesListSelectorState( - groupNames: groupNames, - currentUnfoldSet: config.currentUnfoldSet, - proxyCardType: config.proxiesStyle.cardType, - proxiesSortType: config.proxiesStyle.sortType, - columns: other.getProxiesColumns( - appState.viewWidth, - config.proxiesStyle.layout, - ), - sortNum: appState.sortNum, - ); - }, - shouldRebuild: (prev, next) { - if (!stringListEquality.equals(prev.groupNames, next.groupNames)) { - _headerStateNotifier.value = const ProxiesListHeaderSelectorState( - offset: 0, - currentIndex: 0, - ); - } - return prev != next; - }, - builder: (_, state, __) { + return Consumer( + builder: (_, ref, __) { + final state = ref.watch(proxiesListSelectorStateProvider); if (state.groupNames.isEmpty) { return NullStatus( label: appLocalizations.nullProxies, ); } final items = _buildItems( + ref, groupNames: state.groupNames, currentUnfoldSet: state.currentUnfoldSet, columns: state.columns, @@ -318,6 +308,7 @@ class _ProxiesListFragmentState extends State { bottom: 8, ), child: _buildHeader( + ref, groupName: state.groupNames[index], currentUnfoldSet: state.currentUnfoldSet, ), @@ -343,8 +334,11 @@ class ListHeader extends StatefulWidget { final Function(String groupName) onScrollToSelected; final bool isExpand; + final bool enterAnimated; + const ListHeader({ super.key, + this.enterAnimated = true, required this.group, required this.onChange, required this.onScrollToSelected, @@ -417,57 +411,53 @@ class _ListHeaderState extends State } Widget _buildIcon() { - return Selector( - selector: (_, config) => config.proxiesStyle.iconStyle, - builder: (_, iconStyle, child) { - return Selector( - selector: (_, config) { - final iconMapEntryList = - config.proxiesStyle.iconMap.entries.toList(); - final index = iconMapEntryList.indexWhere((item) { - try { - return RegExp(item.key).hasMatch(groupName); - } catch (_) { - return false; - } - }); - if (index != -1) { - return iconMapEntryList[index].value; + return Consumer( + builder: (_, ref, child) { + final iconStyle = ref.watch( + proxiesStyleSettingProvider.select((state) => state.iconStyle)); + final icon = ref.watch(proxiesStyleSettingProvider.select((state) { + final iconMapEntryList = state.iconMap.entries.toList(); + final index = iconMapEntryList.indexWhere((item) { + try { + return RegExp(item.key).hasMatch(groupName); + } catch (_) { + return false; } - return icon; - }, - builder: (_, icon, __) { - return switch (iconStyle) { - ProxiesIconStyle.standard => Container( - height: 48, - width: 48, - margin: const EdgeInsets.only( - right: 16, - ), - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: context.colorScheme.secondaryContainer, - borderRadius: BorderRadius.circular(12), - ), - clipBehavior: Clip.antiAlias, - child: CommonTargetIcon( - src: icon, - size: 32, - ), - ), - ProxiesIconStyle.icon => Container( - margin: const EdgeInsets.only( - right: 16, - ), - child: CommonTargetIcon( - src: icon, - size: 42, - ), - ), - ProxiesIconStyle.none => Container(), - }; - }, - ); + }); + if (index != -1) { + return iconMapEntryList[index].value; + } + return this.icon; + })); + return switch (iconStyle) { + ProxiesIconStyle.standard => Container( + height: 48, + width: 48, + margin: const EdgeInsets.only( + right: 16, + ), + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: context.colorScheme.secondaryContainer, + borderRadius: BorderRadius.circular(12), + ), + clipBehavior: Clip.antiAlias, + child: CommonTargetIcon( + src: icon, + size: 32, + ), + ), + ProxiesIconStyle.icon => Container( + margin: const EdgeInsets.only( + right: 16, + ), + child: CommonTargetIcon( + src: icon, + size: 42, + ), + ), + ProxiesIconStyle.none => Container(), + }; }, ); } @@ -475,13 +465,15 @@ class _ListHeaderState extends State @override Widget build(BuildContext context) { return CommonCard( + enterAnimated: widget.enterAnimated, key: widget.key, + borderSide: WidgetStatePropertyAll(BorderSide.none), backgroundColor: WidgetStatePropertyAll( context.colorScheme.surfaceContainer, ), radius: 14, type: CommonCardType.filled, - child: Container( + child: Padding( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12, @@ -518,9 +510,13 @@ class _ListHeaderState extends State ), Flexible( flex: 1, - child: currentSelectedProxyNameBuilder( - groupName: groupName, - builder: (currentGroupName) { + child: Consumer( + builder: (_, ref, __) { + final proxyName = ref + .watch(getSelectedProxyNameProvider( + groupName, + )) + .getSafeValue(""); return Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: @@ -528,12 +524,12 @@ class _ListHeaderState extends State crossAxisAlignment: CrossAxisAlignment.center, children: [ - if (currentGroupName.isNotEmpty) ...[ + if (proxyName.isNotEmpty) ...[ Flexible( flex: 1, child: EmojiText( overflow: TextOverflow.ellipsis, - " · $currentGroupName", + " · $proxyName", style: context.textTheme .labelMedium?.toLight, ), diff --git a/lib/fragments/proxies/providers.dart b/lib/fragments/proxies/providers.dart index 95526c9..95855ea 100644 --- a/lib/fragments/proxies/providers.dart +++ b/lib/fragments/proxies/providers.dart @@ -3,25 +3,25 @@ import 'dart:io'; import 'package:fl_clash/clash/clash.dart'; import 'package:fl_clash/common/common.dart'; -import 'package:fl_clash/models/app.dart'; import 'package:fl_clash/models/core.dart'; +import 'package:fl_clash/providers/app.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; typedef UpdatingMap = Map; -class Providers extends StatefulWidget { - const Providers({ +class ProvidersView extends ConsumerStatefulWidget { + const ProvidersView({ super.key, }); @override - State createState() => _ProvidersState(); + ConsumerState createState() => _ProvidersViewState(); } -class _ProvidersState extends State { +class _ProvidersViewState extends ConsumerState { @override void initState() { super.initState(); @@ -43,12 +43,12 @@ class _ProvidersState extends State { } _updateProviders() async { - final appState = globalState.appController.appState; - final providers = globalState.appController.appState.providers; + final providers = ref.read(providersProvider); + final providersNotifier = ref.read(providersProvider.notifier); final messages = []; final updateProviders = providers.map( (provider) async { - appState.setProvider( + providersNotifier.setProvider( provider.copyWith(isUpdating: true), ); final message = await clashCore.updateExternalProvider( @@ -57,7 +57,7 @@ class _ProvidersState extends State { if (message.isNotEmpty) { messages.add("${provider.name}: $message \n"); } - appState.setProvider( + providersNotifier.setProvider( await clashCore.getExternalProvider(provider.name), ); }, @@ -83,35 +83,29 @@ class _ProvidersState extends State { @override Widget build(BuildContext context) { - return Selector>( - selector: (_, appState) => appState.providers, - builder: (_, providers, ___) { - final proxyProviders = - providers.where((item) => item.type == "Proxy").map( - (item) => ProviderItem( - provider: item, - ), - ); - final ruleProviders = - providers.where((item) => item.type == "Rule").map( - (item) => ProviderItem( - provider: item, - ), - ); - final proxySection = generateSection( - title: appLocalizations.proxyProviders, - items: proxyProviders, + final providers = ref.watch(providersProvider); + final proxyProviders = providers.where((item) => item.type == "Proxy").map( + (item) => ProviderItem( + provider: item, + ), ); - final ruleSection = generateSection( - title: appLocalizations.ruleProviders, - items: ruleProviders, + final ruleProviders = providers.where((item) => item.type == "Rule").map( + (item) => ProviderItem( + provider: item, + ), ); - return generateListView([ - ...proxySection, - ...ruleSection, - ]); - }, + final proxySection = generateSection( + title: appLocalizations.proxyProviders, + items: proxyProviders, ); + final ruleSection = generateSection( + title: appLocalizations.ruleProviders, + items: ruleProviders, + ); + return generateListView([ + ...proxySection, + ...ruleSection, + ]); } } @@ -124,11 +118,11 @@ class ProviderItem extends StatelessWidget { }); _handleUpdateProvider() async { - final appState = globalState.appController.appState; + final appController = globalState.appController; if (provider.vehicleType != "HTTP") return; await globalState.safeRun( () async { - appState.setProvider( + appController.setProvider( provider.copyWith( isUpdating: true, ), @@ -140,7 +134,7 @@ class ProviderItem extends StatelessWidget { }, silence: false, ); - appState.setProvider( + appController.setProvider( await clashCore.getExternalProvider(provider.name), ); await globalState.appController.updateGroupsDebounce(); @@ -149,7 +143,6 @@ class ProviderItem extends StatelessWidget { _handleSideLoadProvider() async { await globalState.safeRun(() async { final platformFile = await picker.pickerFile(); - final appState = globalState.appController.appState; final bytes = platformFile?.bytes; if (bytes == null || provider.path == null) return; final file = await File(provider.path!).create(recursive: true); @@ -160,7 +153,7 @@ class ProviderItem extends StatelessWidget { data: utf8.decode(bytes), ); if (message.isNotEmpty) throw message; - appState.setProvider( + globalState.appController.setProvider( await clashCore.getExternalProvider(provider.name), ); if (message.isNotEmpty) throw message; diff --git a/lib/fragments/proxies/proxies.dart b/lib/fragments/proxies/proxies.dart index aa42a1c..b414ccc 100644 --- a/lib/fragments/proxies/proxies.dart +++ b/lib/fragments/proxies/proxies.dart @@ -1,36 +1,38 @@ import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/fragments/proxies/list.dart'; -import 'package:fl_clash/models/models.dart'; -import 'package:fl_clash/state.dart'; +import 'package:fl_clash/fragments/proxies/providers.dart'; +import 'package:fl_clash/providers/providers.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'providers.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'common.dart'; import 'setting.dart'; import 'tab.dart'; -class ProxiesFragment extends StatefulWidget { +class ProxiesFragment extends ConsumerStatefulWidget { const ProxiesFragment({super.key}); @override - State createState() => _ProxiesFragmentState(); + ConsumerState createState() => _ProxiesFragmentState(); } -class _ProxiesFragmentState extends State { +class _ProxiesFragmentState extends ConsumerState + with PageMixin { final GlobalKey _proxiesTabKey = GlobalKey(); + bool _hasProviders = false; + bool _isTab = false; - _initActions(ProxiesType proxiesType, bool hasProvider) { - WidgetsBinding.instance.addPostFrameCallback((_) { - context.commonScaffoldState?.actions = [ - if (hasProvider) ...[ + @override + get actions => [ + if (_hasProviders) IconButton( onPressed: () { showExtendPage( isScaffold: true, extendPageWidth: 360, context, - body: const Providers(), + body: const ProvidersView(), title: appLocalizations.providers, ); }, @@ -38,71 +40,28 @@ class _ProxiesFragmentState extends State { Icons.poll_outlined, ), ), - ], - if (proxiesType == ProxiesType.tab) ...[ - IconButton( - onPressed: () { - _proxiesTabKey.currentState?.scrollToGroupSelected(); - }, - icon: const Icon( - Icons.adjust_outlined, - ), - ), - ] else ...[ - IconButton( - onPressed: () { - showExtendPage( - context, - extendPageWidth: 360, - title: appLocalizations.iconConfiguration, - body: Selector>( - selector: (_, config) => config.proxiesStyle.iconMap, - shouldRebuild: (prev, next) { - return !stringAndStringMapEntryIterableEquality.equals( - prev.entries, - next.entries, - ); - }, - builder: (_, iconMap, __) { - final entries = iconMap.entries.toList(); - return ListPage( - title: appLocalizations.iconConfiguration, - items: entries, - keyLabel: appLocalizations.regExp, - valueLabel: appLocalizations.icon, - keyBuilder: (item) => Key(item.key), - titleBuilder: (item) => Text(item.key), - leadingBuilder: (item) => Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - ), - clipBehavior: Clip.antiAlias, - child: CommonTargetIcon( - src: item.value, - size: 42, - ), - ), - subtitleBuilder: (item) => Text( - item.value, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - onChange: (entries) { - final config = globalState.appController.config; - config.proxiesStyle = config.proxiesStyle.copyWith( - iconMap: Map.fromEntries(entries), - ); - }, - ); - }, + _isTab + ? IconButton( + onPressed: () { + _proxiesTabKey.currentState?.scrollToGroupSelected(); + }, + icon: const Icon( + Icons.adjust_outlined, ), - ); - }, - icon: const Icon( - Icons.style_outlined, - ), - ), - ], + ) + : IconButton( + onPressed: () { + showExtendPage( + context, + extendPageWidth: 360, + title: appLocalizations.iconConfiguration, + body: _IconConfigView(), + ); + }, + icon: const Icon( + Icons.style_outlined, + ), + ), IconButton( onPressed: () { showSheet( @@ -116,28 +75,88 @@ class _ProxiesFragmentState extends State { ), ) ]; - }); + + @override + get floatingActionButton => _isTab + ? DelayTestButton( + onClick: () async { + await delayTest( + currentTabProxies, + currentTabTestUrl, + ); + }, + ) + : null; + + @override + void initState() { + ref.listenManual( + proxiesActionsStateProvider, + fireImmediately: true, + (prev, next) { + if (prev == next) { + return; + } + if (next.pageLabel == PageLabel.proxies) { + _hasProviders = next.hasProviders; + _isTab = next.type == ProxiesType.tab; + initPageState(); + return; + } + }, + ); + super.initState(); } @override Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.proxiesStyle.type, - builder: (_, proxiesType, __) { - return ProxiesActionsBuilder( - builder: (state, child) { - if (state.isCurrent) { - _initActions(proxiesType, state.hasProvider); - } - return child!; - }, - child: switch (proxiesType) { - ProxiesType.tab => ProxiesTabFragment( - key: _proxiesTabKey, + final proxiesType = + ref.watch(proxiesStyleSettingProvider.select((state) => state.type)); + return switch (proxiesType) { + ProxiesType.tab => ProxiesTabFragment( + key: _proxiesTabKey, + ), + ProxiesType.list => const ProxiesListFragment(), + }; + } +} + +class _IconConfigView extends ConsumerWidget { + const _IconConfigView(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final iconMap = + ref.watch(proxiesStyleSettingProvider.select((state) => state.iconMap)); + final entries = iconMap.entries.toList(); + return ListPage( + title: appLocalizations.iconConfiguration, + items: entries, + keyLabel: appLocalizations.regExp, + valueLabel: appLocalizations.icon, + keyBuilder: (item) => Key(item.key), + titleBuilder: (item) => Text(item.key), + leadingBuilder: (item) => Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + ), + clipBehavior: Clip.antiAlias, + child: CommonTargetIcon( + src: item.value, + size: 42, + ), + ), + subtitleBuilder: (item) => Text( + item.value, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + onChange: (entries) { + ref.read(proxiesStyleSettingProvider.notifier).updateState( + (state) => state.copyWith( + iconMap: Map.fromEntries(entries), ), - ProxiesType.list => const ProxiesListFragment(), - }, - ); + ); }, ); } diff --git a/lib/fragments/proxies/setting.dart b/lib/fragments/proxies/setting.dart index fc83d9e..a654eb3 100644 --- a/lib/fragments/proxies/setting.dart +++ b/lib/fragments/proxies/setting.dart @@ -1,11 +1,10 @@ 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'; +import 'package:fl_clash/providers/config.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; class ProxiesSetting extends StatelessWidget { const ProxiesSetting({super.key}); @@ -56,10 +55,11 @@ class ProxiesSetting extends StatelessWidget { SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16), scrollDirection: Axis.horizontal, - child: Selector( - selector: (_, config) => config.proxiesStyle.type, - builder: (_, proxiesType, __) { - final config = globalState.appController.config; + child: Consumer( + builder: (_, ref, __) { + final proxiesType = ref.watch(proxiesStyleSettingProvider.select( + (state) => state.type, + )); return Wrap( spacing: 16, children: [ @@ -71,9 +71,13 @@ class ProxiesSetting extends StatelessWidget { ), isSelected: proxiesType == item, onPressed: () { - config.proxiesStyle = config.proxiesStyle.copyWith( - type: item, - ); + ref + .read(proxiesStyleSettingProvider.notifier) + .updateState((state) { + return state.copyWith( + type: item, + ); + }); }, ) ], @@ -92,10 +96,11 @@ class ProxiesSetting extends StatelessWidget { SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16), scrollDirection: Axis.horizontal, - child: Selector( - selector: (_, config) => config.proxiesStyle.sortType, - builder: (_, proxiesSortType, __) { - final config = globalState.appController.config; + child: Consumer( + builder: (_, ref, __) { + final sortType = ref.watch(proxiesStyleSettingProvider.select( + (state) => state.sortType, + )); return Wrap( spacing: 16, children: [ @@ -105,11 +110,15 @@ class ProxiesSetting extends StatelessWidget { label: _getStringProxiesSortType(item), iconData: _getIconWithProxiesSortType(item), ), - isSelected: proxiesSortType == item, + isSelected: sortType == item, onPressed: () { - config.proxiesStyle = config.proxiesStyle.copyWith( - sortType: item, - ); + ref + .read(proxiesStyleSettingProvider.notifier) + .updateState((state) { + return state.copyWith( + sortType: item, + ); + }); }, ), ], @@ -128,21 +137,26 @@ class ProxiesSetting extends StatelessWidget { SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16), scrollDirection: Axis.horizontal, - child: Selector( - selector: (_, config) => config.proxiesStyle.cardType, - builder: (_, proxyCardType, __) { - final config = globalState.appController.config; + child: Consumer( + builder: (_, ref, __) { + final cardType = ref.watch(proxiesStyleSettingProvider.select( + (state) => state.cardType, + )); return Wrap( spacing: 16, children: [ for (final item in ProxyCardType.values) SettingTextCard( Intl.message(item.name), - isSelected: item == proxyCardType, + isSelected: item == cardType, onPressed: () { - config.proxiesStyle = config.proxiesStyle.copyWith( - cardType: item, - ); + ref + .read(proxiesStyleSettingProvider.notifier) + .updateState((state) { + return state.copyWith( + cardType: item, + ); + }); }, ) ], @@ -163,21 +177,26 @@ class ProxiesSetting extends StatelessWidget { horizontal: 16, ), scrollDirection: Axis.horizontal, - child: Selector( - selector: (_, config) => config.proxiesStyle.layout, - builder: (_, proxiesLayout, __) { - final config = globalState.appController.config; + child: Consumer( + builder: (_, ref, __) { + final layout = ref.watch(proxiesStyleSettingProvider.select( + (state) => state.layout, + )); return Wrap( spacing: 16, children: [ for (final item in ProxiesLayout.values) SettingTextCard( getTextForProxiesLayout(item), - isSelected: item == proxiesLayout, + isSelected: item == layout, onPressed: () { - config.proxiesStyle = config.proxiesStyle.copyWith( - layout: item, - ); + ref + .watch(proxiesStyleSettingProvider.notifier) + .updateState((state) { + return state.copyWith( + layout: item, + ); + }); }, ) ], @@ -196,9 +215,11 @@ class ProxiesSetting extends StatelessWidget { SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16), scrollDirection: Axis.horizontal, - child: Selector( - selector: (_, config) => config.proxiesStyle.iconStyle, - builder: (_, iconStyle, __) { + child: Consumer( + builder: (_, ref, __) { + final iconStyle = ref.watch(proxiesStyleSettingProvider.select( + (state) => state.iconStyle, + )); return Wrap( spacing: 16, children: [ @@ -207,10 +228,13 @@ class ProxiesSetting extends StatelessWidget { _getTextWithProxiesIconStyle(item), isSelected: iconStyle == item, onPressed: () { - final config = globalState.appController.config; - config.proxiesStyle = config.proxiesStyle.copyWith( - iconStyle: item, - ); + ref + .read(proxiesStyleSettingProvider.notifier) + .updateState((state) { + return state.copyWith( + iconStyle: item, + ); + }); }, ), ], @@ -234,11 +258,11 @@ class ProxiesSetting extends StatelessWidget { ..._buildSortSetting(), ..._buildLayoutSetting(), ..._buildSizeSetting(), - Selector( - selector: (_, config) => - config.proxiesStyle.type == ProxiesType.list, - builder: (_, value, child) { - if (value) { + Consumer( + builder: (_, ref, child) { + final isList = ref.watch(proxiesStyleSettingProvider + .select((state) => state.type == ProxiesType.list)); + if (isList) { return child!; } return Container(); diff --git a/lib/fragments/proxies/tab.dart b/lib/fragments/proxies/tab.dart index c8c05d2..bf5dee1 100644 --- a/lib/fragments/proxies/tab.dart +++ b/lib/fragments/proxies/tab.dart @@ -1,34 +1,40 @@ import 'dart:math'; 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/models/common.dart'; +import 'package:fl_clash/providers/providers.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'card.dart'; import 'common.dart'; -List currentProxies = []; -String? currentTestUrl; +List currentTabProxies = []; +String? currentTabTestUrl; typedef GroupNameKeyMap = Map>; -class ProxiesTabFragment extends StatefulWidget { +class ProxiesTabFragment extends ConsumerStatefulWidget { const ProxiesTabFragment({super.key}); @override - State createState() => ProxiesTabFragmentState(); + ConsumerState createState() => ProxiesTabFragmentState(); } -class ProxiesTabFragmentState extends State +class ProxiesTabFragmentState extends ConsumerState with TickerProviderStateMixin { TabController? _tabController; final _hasMoreButtonNotifier = ValueNotifier(false); GroupNameKeyMap _keyMap = {}; + @override + void initState() { + super.initState(); + _handleTabListen(); + } + @override void dispose() { _destroyTabController(); @@ -36,17 +42,17 @@ class ProxiesTabFragmentState extends State } scrollToGroupSelected() { - final currentGroupName = globalState.appController.config.currentGroupName; + final currentGroupName = globalState.appController.getCurrentGroupName(); _keyMap[currentGroupName]?.currentState?.scrollToSelected(); } _buildMoreButton() { - return Selector( - selector: (_, appState) => appState.viewMode == ViewMode.mobile, - builder: (_, value, ___) { + return Consumer( + builder: (_, ref, ___) { + final isMobileView = ref.watch(viewWidthProvider.notifier).isMobileView; return IconButton( onPressed: _showMoreMenu, - icon: value + icon: isMobileView ? const Icon( Icons.expand_more, ) @@ -65,16 +71,9 @@ class ProxiesTabFragmentState extends State isScrollControlled: false, body: SingleChildScrollView( padding: const EdgeInsets.all(16), - child: Selector2( - selector: (_, appState, config) { - final currentGroups = appState.currentGroups; - final groupNames = currentGroups.map((e) => e.name).toList(); - return ProxiesSelectorState( - groupNames: groupNames, - currentGroupName: config.currentGroupName, - ); - }, - builder: (_, state, __) { + child: Consumer( + builder: (_, ref, __) { + final state = ref.watch(proxiesSelectorStateProvider); return SizedBox( width: double.infinity, child: Wrap( @@ -86,13 +85,13 @@ class ProxiesTabFragmentState extends State SettingTextCard( groupName, onPressed: () { - final index = state.groupNames - .indexWhere((item) => item == groupName); + final index = state.groupNames.indexWhere( + (item) => item == groupName, + ); if (index == -1) return; _tabController?.animateTo(index); - globalState.appController.config.updateCurrentGroupName( - groupName, - ); + globalState.appController + .updateCurrentGroupName(groupName); Navigator.of(context).pop(); }, isSelected: groupName == state.currentGroupName, @@ -108,16 +107,24 @@ class ProxiesTabFragmentState extends State } _tabControllerListener([int? index]) { - final appController = globalState.appController; - final currentGroups = appController.appState.currentGroups; - if (_tabController?.index == null) { + int? groupIndex = index; + if(groupIndex == -1){ return; } - final currentGroup = currentGroups[index ?? _tabController!.index]; - currentProxies = currentGroup.all; - currentTestUrl = currentGroup.testUrl; + final appController = globalState.appController; + if (groupIndex == null) { + final currentIndex = _tabController?.index; + groupIndex = currentIndex; + } + final currentGroups = appController.getCurrentGroups(); + if (groupIndex == null || groupIndex > currentGroups.length) { + return; + } + final currentGroup = currentGroups[groupIndex]; + currentTabProxies = currentGroup.all; + currentTabTestUrl = currentGroup.testUrl; WidgetsBinding.instance.addPostFrameCallback((_) { - appController.config.updateCurrentGroupName( + globalState.appController.updateCurrentGroupName( currentGroup.name, ); }); @@ -144,122 +151,117 @@ class ProxiesTabFragmentState extends State _tabController?.addListener(_tabControllerListener); } + _handleTabListen() { + ref.listenManual( + proxiesSelectorStateProvider, + (prev, next) { + if (prev == next) { + return; + } + if (prev?.groupNames.length != next.groupNames.length) { + _destroyTabController(); + final index = next.groupNames.indexWhere( + (item) => item == next.currentGroupName, + ); + _updateTabController(next.groupNames.length, index); + } + }, + fireImmediately: true, + ); + } + @override Widget build(BuildContext context) { - return Selector2( - selector: (_, appState, config) { - final currentGroups = appState.currentGroups; - final groupNames = currentGroups.map((e) => e.name).toList(); - return ProxiesSelectorState( - groupNames: groupNames, - currentGroupName: config.currentGroupName, - ); - }, - shouldRebuild: (prev, next) { - if (!stringListEquality.equals(prev.groupNames, next.groupNames)) { - _destroyTabController(); - return true; - } - return false; - }, - builder: (_, state, __) { - if (state.groupNames.isEmpty) { - return NullStatus( - label: appLocalizations.nullProxies, - ); - } - final index = state.groupNames.indexWhere( - (item) => item == state.currentGroupName, - ); - _updateTabController(state.groupNames.length, index); - if (state.groupNames.isEmpty) { - return Container(); - } - final GroupNameKeyMap keyMap = {}; - final children = state.groupNames.map((groupName) { - keyMap[groupName] = GlobalObjectKey(groupName); - return KeepScope( - child: ProxyGroupView( - key: keyMap[groupName], - groupName: groupName, - ), - ); - }).toList(); - _keyMap = keyMap; - return Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - NotificationListener( - onNotification: (scrollNotification) { - _hasMoreButtonNotifier.value = - scrollNotification.metrics.maxScrollExtent > 0; - return true; - }, - child: ValueListenableBuilder( - valueListenable: _hasMoreButtonNotifier, - builder: (_, value, child) { - return Stack( - alignment: AlignmentDirectional.centerStart, - children: [ - TabBar( - controller: _tabController, - padding: EdgeInsets.only( - left: 16, - right: 16 + (value ? 16 : 0), - ), - dividerColor: Colors.transparent, - isScrollable: true, - tabAlignment: TabAlignment.start, - overlayColor: - const WidgetStatePropertyAll(Colors.transparent), - tabs: [ - for (final groupName in state.groupNames) - Tab( - text: groupName, - ), - ], - ), - if (value) - Positioned( - right: 0, - child: child!, + final state = ref.watch(groupNamesStateProvider); + final groupNames = state.groupNames; + if (groupNames.isEmpty) { + return NullStatus( + label: appLocalizations.nullProxies, + ); + } + final GroupNameKeyMap keyMap = {}; + final children = groupNames.map((groupName) { + keyMap[groupName] = GlobalObjectKey(groupName); + return KeepScope( + child: ProxyGroupView( + key: keyMap[groupName], + groupName: groupName, + ), + ); + }).toList(); + _keyMap = keyMap; + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + NotificationListener( + onNotification: (scrollNotification) { + _hasMoreButtonNotifier.value = + scrollNotification.metrics.maxScrollExtent > 0; + return true; + }, + child: ValueListenableBuilder( + valueListenable: _hasMoreButtonNotifier, + builder: (_, value, child) { + return Stack( + alignment: AlignmentDirectional.centerStart, + children: [ + TabBar( + controller: _tabController, + padding: EdgeInsets.only( + left: 16, + right: 16 + (value ? 16 : 0), + ), + dividerColor: Colors.transparent, + isScrollable: true, + tabAlignment: TabAlignment.start, + overlayColor: + const WidgetStatePropertyAll(Colors.transparent), + tabs: [ + for (final groupName in groupNames) + Tab( + text: groupName, ), ], - ); - }, - child: Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - context.colorScheme.surface.withOpacity(0.1), - context.colorScheme.surface, - ], - stops: const [ - 0.0, - 0.1 - ]), ), - child: _buildMoreButton(), - ), + if (value) + Positioned( + right: 0, + child: child!, + ), + ], + ); + }, + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + context.colorScheme.surface.withOpacity(0.1), + context.colorScheme.surface, + ], + stops: const [ + 0.0, + 0.1 + ]), ), + child: _buildMoreButton(), ), - Expanded( - child: TabBarView( - controller: _tabController, - children: children, - ), - ) - ], - ); - }, + ), + ), + Expanded( + child: TabBarView( + controller: _tabController, + children: children, + ), + ) + ], ); } } -class ProxyGroupView extends StatefulWidget { +class ProxyGroupView extends ConsumerStatefulWidget { final String groupName; const ProxyGroupView({ @@ -268,25 +270,14 @@ class ProxyGroupView extends StatefulWidget { }); @override - State createState() => ProxyGroupViewState(); + ConsumerState createState() => ProxyGroupViewState(); } -class ProxyGroupViewState extends State { - var isLock = false; +class ProxyGroupViewState extends ConsumerState { final _controller = ScrollController(); String get groupName => widget.groupName; - _delayTest() async { - if (isLock) return; - isLock = true; - await delayTest( - currentProxies, - currentTestUrl, - ); - isLock = false; - } - @override void dispose() { _controller.dispose(); @@ -297,9 +288,10 @@ class ProxyGroupViewState extends State { if (_controller.position.maxScrollExtent == 0) { return; } + final sortedProxies = globalState.appController.getSortProxies( - currentProxies, - currentTestUrl, + currentTabProxies, + currentTabTestUrl, ); _controller.animateTo( min( @@ -315,83 +307,45 @@ class ProxyGroupViewState extends State { ); } - initFab(bool isCurrent) { - if (!isCurrent) { - return; - } - WidgetsBinding.instance.addPostFrameCallback((_) { - context.commonScaffoldState?.floatingActionButton = DelayTestButton( - onClick: () async { - await _delayTest(); - }, - ); - }); - } - @override Widget build(BuildContext context) { - return Selector2( - selector: (_, appState, config) { - final group = appState.getGroupWithName(groupName)!; - return ProxyGroupSelectorState( - proxyCardType: config.proxiesStyle.cardType, - proxiesSortType: config.proxiesStyle.sortType, - columns: other.getProxiesColumns( - appState.viewWidth, - config.proxiesStyle.layout, - ), - sortNum: appState.sortNum, - proxies: group.all, - groupType: group.type, - testUrl: group.testUrl, - ); - }, - builder: (_, state, __) { - final proxies = state.proxies; - final columns = state.columns; - final proxyCardType = state.proxyCardType; - final sortedProxies = globalState.appController.getSortProxies( - proxies, - state.testUrl, - ); - return ActiveBuilder( - label: "proxies", - builder: (isCurrent, child) { - initFab(isCurrent); - return child!; - }, - child: Align( - alignment: Alignment.topCenter, - child: GridView.builder( - controller: _controller, - padding: const EdgeInsets.only( - top: 16, - left: 16, - right: 16, - bottom: 96, - ), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: columns, - mainAxisSpacing: 8, - crossAxisSpacing: 8, - mainAxisExtent: getItemHeight(proxyCardType), - ), - itemCount: sortedProxies.length, - itemBuilder: (_, index) { - final proxy = sortedProxies[index]; - return ProxyCard( - testUrl: state.testUrl, - groupType: state.groupType, - type: proxyCardType, - key: ValueKey('$groupName.${proxy.name}'), - proxy: proxy, - groupName: groupName, - ); - }, - ), - ), - ); - }, + final state = ref.watch(proxyGroupSelectorStateProvider(groupName)); + final proxies = state.proxies; + final columns = state.columns; + final proxyCardType = state.proxyCardType; + final sortedProxies = globalState.appController.getSortProxies( + proxies, + state.testUrl, + ); + return Align( + alignment: Alignment.topCenter, + child: GridView.builder( + controller: _controller, + padding: const EdgeInsets.only( + top: 16, + left: 16, + right: 16, + bottom: 96, + ), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: columns, + mainAxisSpacing: 8, + crossAxisSpacing: 8, + mainAxisExtent: getItemHeight(proxyCardType), + ), + itemCount: sortedProxies.length, + itemBuilder: (_, index) { + final proxy = sortedProxies[index]; + return ProxyCard( + testUrl: state.testUrl, + groupType: state.groupType, + type: proxyCardType, + key: ValueKey('$groupName.${proxy.name}'), + proxy: proxy, + groupName: groupName, + ); + }, + ), ); } } @@ -414,6 +368,9 @@ class _DelayTestButtonState extends State late Animation _scale; _healthcheck() async { + if (_controller.isAnimating) { + return; + } _controller.forward(); await widget.onClick(); if (mounted) { diff --git a/lib/fragments/resources.dart b/lib/fragments/resources.dart index 559fa73..694bc91 100644 --- a/lib/fragments/resources.dart +++ b/lib/fragments/resources.dart @@ -3,11 +3,12 @@ import 'dart:io'; import 'package:fl_clash/clash/clash.dart'; import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/providers/config.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path/path.dart' hide context; -import 'package:provider/provider.dart'; @immutable class GeoItem { @@ -84,12 +85,13 @@ class _GeoDataListItemState extends State { GeoItem get geoItem => widget.geoItem; - _updateUrl(String url) async { + _updateUrl(String url, WidgetRef ref) async { + final defaultMap = defaultGeoXUrl.toJson(); final newUrl = await globalState.showCommonDialog( child: UpdateGeoUrlFormDialog( title: geoItem.label, url: url, - defaultValue: defaultGeoXMap[geoItem.key], + defaultValue: defaultMap[geoItem.key], ), ); if (newUrl != null && newUrl != url && mounted) { @@ -97,9 +99,13 @@ class _GeoDataListItemState extends State { if (!newUrl.isUrl) { throw "Invalid url"; } - final appController = globalState.appController; - appController.clashConfig.geoXUrl = - Map.from(appController.clashConfig.geoXUrl)..[geoItem.key] = newUrl; + ref.read(patchClashConfigProvider.notifier).updateState((state) { + final map = state.geoXUrl.toJson(); + map[geoItem.key] = newUrl; + return state.copyWith( + geoXUrl: GeoXUrl.fromJson(map), + ); + }); } catch (e) { globalState.showMessage( title: geoItem.label, @@ -122,63 +128,74 @@ class _GeoDataListItemState extends State { ); } - Widget _buildSubtitle(String url) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox( - height: 4, - ), - FutureBuilder( - future: _getGeoFileLastModified(geoItem.fileName), - builder: (_, snapshot) { - return SizedBox( - height: 24, - child: FadeBox( - key: Key("fade_box_${geoItem.label}"), - child: snapshot.data == null - ? const SizedBox( - width: 24, - height: 24, - child: CircularProgressIndicator( - strokeWidth: 2, - ), - ) - : Text( - snapshot.data!.desc, - ), - ), - ); - }, - ), - Text( - url, - style: context.textTheme.bodyMedium?.toLight, - ), - const SizedBox( - height: 8, - ), - Wrap( - runSpacing: 6, - spacing: 12, + Widget _buildSubtitle() { + return Consumer( + builder: (_, ref, __) { + final url = ref.watch( + patchClashConfigProvider + .select((state) => state.geoXUrl.toJson()[geoItem.key]), + ); + if (url == null) { + return SizedBox(); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - CommonChip( - avatar: const Icon(Icons.edit), - label: appLocalizations.edit, - onPressed: () { - _updateUrl(url); + const SizedBox( + height: 4, + ), + FutureBuilder( + future: _getGeoFileLastModified(geoItem.fileName), + builder: (_, snapshot) { + return SizedBox( + height: 24, + child: FadeBox( + key: Key("fade_box_${geoItem.label}"), + child: snapshot.data == null + ? const SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator( + strokeWidth: 2, + ), + ) + : Text( + snapshot.data!.desc, + ), + ), + ); }, ), - CommonChip( - avatar: const Icon(Icons.sync), - label: appLocalizations.sync, - onPressed: () { - _handleUpdateGeoDataItem(); - }, + Text( + url, + style: context.textTheme.bodyMedium?.toLight, + ), + const SizedBox( + height: 8, + ), + Wrap( + runSpacing: 6, + spacing: 12, + children: [ + CommonChip( + avatar: const Icon(Icons.edit), + label: appLocalizations.edit, + onPressed: () { + _updateUrl(url, ref); + }, + ), + CommonChip( + avatar: const Icon(Icons.sync), + label: appLocalizations.sync, + onPressed: () { + _handleUpdateGeoDataItem(); + }, + ), + ], ), ], - ), - ], + ); + }, ); } @@ -201,7 +218,6 @@ class _GeoDataListItemState extends State { geoType: geoItem.label, ), ); - print(message); if (message.isNotEmpty) throw message; } catch (e) { isUpdating.value = false; @@ -225,12 +241,7 @@ class _GeoDataListItemState extends State { vertical: 4, ), title: Text(geoItem.label), - subtitle: Selector( - selector: (_, clashConfig) => clashConfig.geoXUrl[geoItem.key]!, - builder: (_, value, __) { - return _buildSubtitle(value); - }, - ), + subtitle: _buildSubtitle(), trailing: SizedBox( height: 48, width: 48, diff --git a/lib/fragments/theme.dart b/lib/fragments/theme.dart index bb85a71..3c1a3e9 100644 --- a/lib/fragments/theme.dart +++ b/lib/fragments/theme.dart @@ -1,11 +1,9 @@ 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'; +import 'package:fl_clash/providers/config.dart'; +import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -import '../widgets/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; class ThemeModeItem { final ThemeMode themeMode; @@ -88,99 +86,106 @@ class ItemCard extends StatelessWidget { } } -class ThemeColorsBox extends StatefulWidget { +class ThemeColorsBox extends ConsumerStatefulWidget { const ThemeColorsBox({super.key}); @override - State createState() => _ThemeColorsBoxState(); + ConsumerState createState() => _ThemeColorsBoxState(); } -class _ThemeColorsBoxState extends State { - Widget _themeModeCheckBox({ - bool? isSelected, - required ThemeModeItem themeModeItem, - }) { - return CommonCard( - isSelected: isSelected, - onPressed: () { - final appController = globalState.appController; - appController.config.themeProps = - appController.config.themeProps.copyWith( - themeMode: themeModeItem.themeMode, - ); - }, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Flexible( - child: Icon(themeModeItem.iconData), - ), - const SizedBox( - width: 8, - ), - Flexible( - child: Text( - themeModeItem.label, - ), - ), - ], - ), - ), - ); - } - - Widget _primaryColorCheckBox({ - bool? isSelected, - Color? color, - }) { - return ColorSchemeBox( - isSelected: isSelected, - primaryColor: color, - onPressed: () { - final appController = globalState.appController; - appController.config.themeProps = - appController.config.themeProps.copyWith( - primaryColor: color?.value, - ); - }, - ); - } - - Widget _fontFamilyCheckBox({ - bool? isSelected, - required FontFamilyItem fontFamilyItem, - }) { - return CommonCard( - isSelected: isSelected, - onPressed: () { - final appController = globalState.appController; - appController.config.themeProps = - appController.config.themeProps.copyWith( - fontFamily: fontFamilyItem.fontFamily, - ); - }, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Flexible( - child: Text( - fontFamilyItem.label, - ), - ), - ], - ), - ), - ); - } - +class _ThemeColorsBoxState extends ConsumerState { @override Widget build(BuildContext context) { + return Column( + children: [ + _FontFamilyItem(), + _ThemeModeItem(), + _PrimaryColorItem(), + _PrueBlackItem(), + const SizedBox( + height: 64, + ), + ], + ); + } +} + +class _FontFamilyItem extends ConsumerWidget { + const _FontFamilyItem(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final fontFamily = + ref.watch(themeSettingProvider.select((state) => state.fontFamily)); + List fontFamilyItems = [ + FontFamilyItem( + label: appLocalizations.systemFont, + fontFamily: FontFamily.system, + ), + const FontFamilyItem( + label: "MiSans", + fontFamily: FontFamily.miSans, + ), + ]; + return ItemCard( + info: Info( + label: appLocalizations.fontFamily, + iconData: Icons.text_fields, + ), + child: Container( + margin: const EdgeInsets.only( + left: 16, + right: 16, + ), + height: 48, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemBuilder: (_, index) { + final fontFamilyItem = fontFamilyItems[index]; + return CommonCard( + isSelected: fontFamilyItem.fontFamily == fontFamily, + onPressed: () { + ref.read(themeSettingProvider.notifier).updateState( + (state) => state.copyWith( + fontFamily: fontFamilyItem.fontFamily, + ), + ); + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Flexible( + child: Text( + fontFamilyItem.label, + ), + ), + ], + ), + ), + ); + }, + separatorBuilder: (_, __) { + return const SizedBox( + width: 16, + ); + }, + itemCount: fontFamilyItems.length, + ), + ), + ); + } +} + +class _ThemeModeItem extends ConsumerWidget { + const _ThemeModeItem(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final themeMode = + ref.watch(themeSettingProvider.select((state) => state.themeMode)); List themeModeItems = [ ThemeModeItem( iconData: Icons.auto_mode, @@ -198,6 +203,68 @@ class _ThemeColorsBoxState extends State { themeMode: ThemeMode.dark, ), ]; + return ItemCard( + info: Info( + label: appLocalizations.themeMode, + iconData: Icons.brightness_high, + ), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16), + height: 64, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: themeModeItems.length, + itemBuilder: (_, index) { + final themeModeItem = themeModeItems[index]; + return CommonCard( + isSelected: themeModeItem.themeMode == themeMode, + onPressed: () { + ref.read(themeSettingProvider.notifier).updateState( + (state) => state.copyWith( + themeMode: themeModeItem.themeMode, + ), + ); + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Flexible( + child: Icon(themeModeItem.iconData), + ), + const SizedBox( + width: 8, + ), + Flexible( + child: Text( + themeModeItem.label, + ), + ), + ], + ), + ), + ); + }, + separatorBuilder: (_, __) { + return const SizedBox( + width: 16, + ); + }, + ), + ), + ); + } +} + +class _PrimaryColorItem extends ConsumerWidget { + const _PrimaryColorItem(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final primaryColor = + ref.watch(themeSettingProvider.select((state) => state.primaryColor)); List primaryColors = [ null, defaultPrimaryColor, @@ -207,147 +274,72 @@ class _ThemeColorsBoxState extends State { Colors.yellowAccent, Colors.purple, ]; - List fontFamilyItems = [ - FontFamilyItem( - label: appLocalizations.systemFont, - fontFamily: FontFamily.system, + return ItemCard( + info: Info( + label: appLocalizations.themeColor, + iconData: Icons.palette, ), - const FontFamilyItem( - label: "MiSans", - fontFamily: FontFamily.miSans, + child: Container( + margin: const EdgeInsets.only( + left: 16, + right: 16, + bottom: 16, + ), + height: 88, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemBuilder: (_, index) { + final color = primaryColors[index]; + return ColorSchemeBox( + isSelected: color?.value == primaryColor, + primaryColor: color, + onPressed: () { + ref.read(themeSettingProvider.notifier).updateState( + (state) => state.copyWith( + primaryColor: color?.value, + ), + ); + }, + ); + }, + separatorBuilder: (_, __) { + return const SizedBox( + width: 16, + ); + }, + itemCount: primaryColors.length, + ), + ), + ); + } +} + +class _PrueBlackItem extends ConsumerWidget { + const _PrueBlackItem(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final prueBlack = + ref.watch(themeSettingProvider.select((state) => state.prueBlack)); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 16), + child: ListItem.switchItem( + leading: Icon( + Icons.contrast, + color: context.colorScheme.primary, + ), + title: Text(appLocalizations.prueBlackMode), + delegate: SwitchDelegate( + value: prueBlack, + onChanged: (value) { + ref.read(themeSettingProvider.notifier).updateState( + (state) => state.copyWith( + prueBlack: value, + ), + ); + }, + ), ), - ]; - return Column( - children: [ - ItemCard( - info: Info( - label: appLocalizations.fontFamily, - iconData: Icons.text_fields, - ), - child: Container( - margin: const EdgeInsets.only( - left: 16, - right: 16, - ), - height: 48, - child: Selector( - selector: (_, config) => config.themeProps.fontFamily, - builder: (_, fontFamily, __) { - return ListView.separated( - scrollDirection: Axis.horizontal, - itemBuilder: (_, index) { - final fontFamilyItem = fontFamilyItems[index]; - return _fontFamilyCheckBox( - isSelected: fontFamily == fontFamilyItem.fontFamily, - fontFamilyItem: fontFamilyItem, - ); - }, - separatorBuilder: (_, __) { - return const SizedBox( - width: 16, - ); - }, - itemCount: fontFamilyItems.length, - ); - }, - ), - ), - ), - ItemCard( - info: Info( - label: appLocalizations.themeMode, - iconData: Icons.brightness_high, - ), - child: Selector( - selector: (_, config) => config.themeProps.themeMode, - builder: (_, themeMode, __) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 16), - height: 64, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: themeModeItems.length, - itemBuilder: (_, index) { - final themeModeItem = themeModeItems[index]; - return _themeModeCheckBox( - isSelected: themeMode == themeModeItem.themeMode, - themeModeItem: themeModeItem, - ); - }, - separatorBuilder: (_, __) { - return const SizedBox( - width: 16, - ); - }, - ), - ); - }, - ), - ), - ItemCard( - info: Info( - label: appLocalizations.themeColor, - iconData: Icons.palette, - ), - child: Container( - margin: const EdgeInsets.only( - left: 16, - right: 16, - bottom: 16, - ), - height: 88, - child: Selector( - selector: (_, config) => config.themeProps.primaryColor, - builder: (_, currentPrimaryColor, __) { - return ListView.separated( - scrollDirection: Axis.horizontal, - itemBuilder: (_, index) { - final primaryColor = primaryColors[index]; - return _primaryColorCheckBox( - isSelected: currentPrimaryColor == primaryColor?.value, - color: primaryColor, - ); - }, - separatorBuilder: (_, __) { - return const SizedBox( - width: 16, - ); - }, - itemCount: primaryColors.length, - ); - }, - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 16), - child: Selector( - selector: (_, config) => config.themeProps.prueBlack, - builder: (_, value, ___) { - return ListItem.switchItem( - leading: Icon( - Icons.contrast, - color: context.colorScheme.primary, - ), - title: Text(appLocalizations.prueBlackMode), - delegate: SwitchDelegate( - value: value, - onChanged: (value) { - final appController = globalState.appController; - appController.config.themeProps = - appController.config.themeProps.copyWith( - prueBlack: value, - ); - }, - ), - ); - }, - ), - ), - const SizedBox( - height: 64, - ), - ], ); } } diff --git a/lib/fragments/tools.dart b/lib/fragments/tools.dart index d99f64f..9a04a48 100644 --- a/lib/fragments/tools.dart +++ b/lib/fragments/tools.dart @@ -1,6 +1,5 @@ import 'dart:io'; import 'package:fl_clash/common/common.dart'; -import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/fragments/about.dart'; import 'package:fl_clash/fragments/access.dart'; import 'package:fl_clash/fragments/application_setting.dart'; @@ -8,32 +7,33 @@ import 'package:fl_clash/fragments/config/config.dart'; import 'package:fl_clash/fragments/hotkey.dart'; import 'package:fl_clash/l10n/l10n.dart'; import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/providers/providers.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; import 'backup_and_recovery.dart'; import 'theme.dart'; import 'package:path/path.dart' show dirname, join; -class ToolsFragment extends StatefulWidget { +class ToolsFragment extends ConsumerStatefulWidget { const ToolsFragment({super.key}); @override - State createState() => _ToolboxFragmentState(); + ConsumerState createState() => _ToolboxFragmentState(); } -class _ToolboxFragmentState extends State { +class _ToolboxFragmentState extends ConsumerState { _buildNavigationMenuItem(NavigationItem navigationItem) { return ListItem.open( leading: navigationItem.icon, - title: Text(Intl.message(navigationItem.label)), + title: Text(Intl.message(navigationItem.label.name)), subtitle: navigationItem.description != null ? Text(Intl.message(navigationItem.description!)) : null, delegate: OpenDelegate( - title: Intl.message(navigationItem.label), + title: Intl.message(navigationItem.label.name), widget: navigationItem.fragment, extendPageWidth: 360, ), @@ -55,34 +55,12 @@ class _ToolboxFragmentState extends State { ); } - String _getLocaleString(Locale? locale) { - if (locale == null) return appLocalizations.defaultText; - return Intl.message(locale.toString()); - } - List _getOtherList() { return generateSection( title: appLocalizations.other, items: [ - ListItem( - leading: const Icon(Icons.gavel), - title: Text(appLocalizations.disclaimer), - onTap: () async { - final isDisclaimerAccepted = - await globalState.appController.showDisclaimer(); - if (!isDisclaimerAccepted) { - globalState.appController.handleExit(); - } - }, - ), - ListItem.open( - leading: const Icon(Icons.info), - title: Text(appLocalizations.about), - delegate: OpenDelegate( - title: appLocalizations.about, - widget: const AboutFragment(), - ), - ), + _DisclaimerItem(), + _InfoItem(), ], ); } @@ -91,145 +69,233 @@ class _ToolboxFragmentState extends State { return generateSection( title: appLocalizations.settings, items: [ - Selector( - selector: (_, config) => config.appSetting.locale, - builder: (_, localeString, __) { - final subTitle = localeString ?? appLocalizations.defaultText; - final currentLocale = other.getLocaleForString(localeString); - return ListItem.options( - leading: const Icon(Icons.language_outlined), - title: Text(appLocalizations.language), - subtitle: Text(Intl.message(subTitle)), - delegate: OptionsDelegate( - title: appLocalizations.language, - options: [null, ...AppLocalizations.delegate.supportedLocales], - onChanged: (Locale? value) { - final config = globalState.appController.config; - config.appSetting = config.appSetting.copyWith( - locale: value?.toString(), - ); - }, - textBuilder: (locale) => _getLocaleString(locale), - value: currentLocale, - ), - ); - }, - ), - ListItem.open( - leading: const Icon(Icons.style), - title: Text(appLocalizations.theme), - subtitle: Text(appLocalizations.themeDesc), - delegate: OpenDelegate( - title: appLocalizations.theme, - widget: const ThemeFragment(), - extendPageWidth: 360, - ), - ), - ListItem.open( - leading: const Icon(Icons.cloud_sync), - title: Text(appLocalizations.backupAndRecovery), - subtitle: Text(appLocalizations.backupAndRecoveryDesc), - delegate: OpenDelegate( - title: appLocalizations.backupAndRecovery, - widget: const BackupAndRecovery(), - ), - ), - if (system.isDesktop) - ListItem.open( - leading: const Icon(Icons.keyboard), - title: Text(appLocalizations.hotkeyManagement), - subtitle: Text(appLocalizations.hotkeyManagementDesc), - delegate: OpenDelegate( - title: appLocalizations.hotkeyManagement, - widget: const HotKeyFragment(), - ), - ), - if (Platform.isWindows) - ListItem( - leading: const Icon(Icons.lock), - title: Text(appLocalizations.loopback), - subtitle: Text(appLocalizations.loopbackDesc), - onTap: () { - windows?.runas( - '"${join(dirname(Platform.resolvedExecutable), "EnableLoopback.exe")}"', - "", - ); - }, - ), - if (Platform.isAndroid) - ListItem.open( - leading: const Icon(Icons.view_list), - title: Text(appLocalizations.accessControl), - subtitle: Text(appLocalizations.accessControlDesc), - delegate: OpenDelegate( - title: appLocalizations.appAccessControl, - widget: const AccessFragment(), - ), - ), - ListItem.open( - leading: const Icon(Icons.edit), - title: Text(appLocalizations.override), - subtitle: Text(appLocalizations.overrideDesc), - delegate: OpenDelegate( - title: appLocalizations.override, - widget: const ConfigFragment(), - ), - ), - ListItem.open( - leading: const Icon(Icons.settings), - title: Text(appLocalizations.application), - subtitle: Text(appLocalizations.applicationDesc), - delegate: OpenDelegate( - title: appLocalizations.application, - widget: const ApplicationSettingFragment(), - ), - ), + _LocaleItem(), + _ThemeItem(), + _BackupItem(), + if (system.isDesktop) _HotkeyItem(), + if (Platform.isWindows) _LoopbackItem(), + if (Platform.isAndroid) _AccessItem(), + _OverrideItem(), + _SettingItem(), ], ); } @override Widget build(BuildContext context) { - return LocaleBuilder( - builder: (_) { - final items = [ - Selector( - selector: (_, appState) { - return MoreToolsSelectorState( - navigationItems: appState.navigationItems.where((element) { - final isMore = - element.modes.contains(NavigationItemMode.more); - final isDesktop = - element.modes.contains(NavigationItemMode.desktop); - if (isMore && !isDesktop) return true; - if (appState.viewMode != ViewMode.mobile || !isMore) { - return false; - } - return true; - }).toList(), + ref.watch(appSettingProvider.select((state) => state.locale)); + final items = [ + Consumer( + builder: (_, ref, __) { + final state = ref.watch(moreToolsSelectorStateProvider); + if (state.navigationItems.isEmpty) { + return Container(); + } + return Column( + children: [ + ListHeader(title: appLocalizations.more), + _buildNavigationMenu(state.navigationItems) + ], + ); + }, + ), + ..._getSettingList(), + ..._getOtherList(), + ]; + return ListView.builder( + itemCount: items.length, + itemBuilder: (_, index) => items[index], + padding: const EdgeInsets.only(bottom: 20), + ); + } +} + +class _LocaleItem extends ConsumerWidget { + const _LocaleItem(); + + String _getLocaleString(Locale? locale) { + if (locale == null) return appLocalizations.defaultText; + return Intl.message(locale.toString()); + } + + @override + Widget build(BuildContext context, WidgetRef ref) { + final locale = + ref.watch(appSettingProvider.select((state) => state.locale)); + final subTitle = locale ?? appLocalizations.defaultText; + final currentLocale = other.getLocaleForString(locale); + return ListItem.options( + leading: const Icon(Icons.language_outlined), + title: Text(appLocalizations.language), + subtitle: Text(Intl.message(subTitle)), + delegate: OptionsDelegate( + title: appLocalizations.language, + options: [null, ...AppLocalizations.delegate.supportedLocales], + onChanged: (Locale? locale) { + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith(locale: locale?.toString()), ); - }, - builder: (_, state, __) { - if (state.navigationItems.isEmpty) { - return Container(); - } - return Column( - children: [ - ListHeader(title: appLocalizations.more), - _buildNavigationMenu(state.navigationItems) - ], - ); - }, - ), - ..._getSettingList(), - ..._getOtherList(), - ]; - return ListView.builder( - itemCount: items.length, - itemBuilder: (_, index) => items[index], - padding: const EdgeInsets.only(bottom: 20), + }, + textBuilder: (locale) => _getLocaleString(locale), + value: currentLocale, + ), + ); + } +} + +class _ThemeItem extends StatelessWidget { + const _ThemeItem(); + + @override + Widget build(BuildContext context) { + return ListItem.open( + leading: const Icon(Icons.style), + title: Text(appLocalizations.theme), + subtitle: Text(appLocalizations.themeDesc), + delegate: OpenDelegate( + title: appLocalizations.theme, + widget: const ThemeFragment(), + extendPageWidth: 360, + ), + ); + } +} + +class _BackupItem extends StatelessWidget { + const _BackupItem(); + + @override + Widget build(BuildContext context) { + return ListItem.open( + leading: const Icon(Icons.cloud_sync), + title: Text(appLocalizations.backupAndRecovery), + subtitle: Text(appLocalizations.backupAndRecoveryDesc), + delegate: OpenDelegate( + title: appLocalizations.backupAndRecovery, + widget: const BackupAndRecovery(), + ), + ); + } +} + +class _HotkeyItem extends StatelessWidget { + const _HotkeyItem(); + + @override + Widget build(BuildContext context) { + return ListItem.open( + leading: const Icon(Icons.keyboard), + title: Text(appLocalizations.hotkeyManagement), + subtitle: Text(appLocalizations.hotkeyManagementDesc), + delegate: OpenDelegate( + title: appLocalizations.hotkeyManagement, + widget: const HotKeyFragment(), + ), + ); + } +} + +class _LoopbackItem extends StatelessWidget { + const _LoopbackItem(); + + @override + Widget build(BuildContext context) { + return ListItem( + leading: const Icon(Icons.lock), + title: Text(appLocalizations.loopback), + subtitle: Text(appLocalizations.loopbackDesc), + onTap: () { + windows?.runas( + '"${join(dirname(Platform.resolvedExecutable), "EnableLoopback.exe")}"', + "", ); }, ); } } + +class _AccessItem extends StatelessWidget { + const _AccessItem(); + + @override + Widget build(BuildContext context) { + return ListItem.open( + leading: const Icon(Icons.view_list), + title: Text(appLocalizations.accessControl), + subtitle: Text(appLocalizations.accessControlDesc), + delegate: OpenDelegate( + title: appLocalizations.appAccessControl, + widget: const AccessFragment(), + ), + ); + } +} + +class _OverrideItem extends StatelessWidget { + const _OverrideItem(); + + @override + Widget build(BuildContext context) { + return ListItem.open( + leading: const Icon(Icons.edit), + title: Text(appLocalizations.override), + subtitle: Text(appLocalizations.overrideDesc), + delegate: OpenDelegate( + title: appLocalizations.override, + widget: const ConfigFragment(), + ), + ); + } +} + +class _SettingItem extends StatelessWidget { + const _SettingItem(); + + @override + Widget build(BuildContext context) { + return ListItem.open( + leading: const Icon(Icons.settings), + title: Text(appLocalizations.application), + subtitle: Text(appLocalizations.applicationDesc), + delegate: OpenDelegate( + title: appLocalizations.application, + widget: const ApplicationSettingFragment(), + ), + ); + } +} + +class _DisclaimerItem extends StatelessWidget { + const _DisclaimerItem(); + + @override + Widget build(BuildContext context) { + return ListItem( + leading: const Icon(Icons.gavel), + title: Text(appLocalizations.disclaimer), + onTap: () async { + final isDisclaimerAccepted = + await globalState.appController.showDisclaimer(); + if (!isDisclaimerAccepted) { + globalState.appController.handleExit(); + } + }, + ); + } +} + +class _InfoItem extends StatelessWidget { + const _InfoItem(); + + @override + Widget build(BuildContext context) { + return ListItem.open( + leading: const Icon(Icons.info), + title: Text(appLocalizations.about), + delegate: OpenDelegate( + title: appLocalizations.about, + widget: const AboutFragment(), + ), + ); + } +} diff --git a/lib/l10n/arb/intl_en.arb b/lib/l10n/arb/intl_en.arb index baf26cb..aba5586 100644 --- a/lib/l10n/arb/intl_en.arb +++ b/lib/l10n/arb/intl_en.arb @@ -342,5 +342,6 @@ "copySuccess": "Copy success", "copyLink": "Copy link", "exportFile": "Export file", - "cacheCorrupt": "The cache is corrupt. Do you want to clear it?" + "cacheCorrupt": "The cache is corrupt. Do you want to clear it?", + "detectionTip": "Relying on third-party APIs is for reference only" } \ 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 5ed858d..9250297 100644 --- a/lib/l10n/arb/intl_zh_CN.arb +++ b/lib/l10n/arb/intl_zh_CN.arb @@ -342,5 +342,6 @@ "copySuccess": "复制成功", "copyLink": "复制链接", "exportFile": "导出文件", - "cacheCorrupt": "缓存已损坏,是否清空?" + "cacheCorrupt": "缓存已损坏,是否清空?", + "detectionTip": "依赖第三方程序仅供参考" } diff --git a/lib/l10n/intl/messages_en.dart b/lib/l10n/intl/messages_en.dart index d6ad39e..1e3d592 100644 --- a/lib/l10n/intl/messages_en.dart +++ b/lib/l10n/intl/messages_en.dart @@ -180,6 +180,9 @@ class MessageLookup extends MessageLookupByLibrary { "desc": MessageLookupByLibrary.simpleMessage( "A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free.", ), + "detectionTip": MessageLookupByLibrary.simpleMessage( + "Relying on third-party APIs is for reference only", + ), "direct": MessageLookupByLibrary.simpleMessage("Direct"), "disclaimer": MessageLookupByLibrary.simpleMessage("Disclaimer"), "disclaimerDesc": MessageLookupByLibrary.simpleMessage( diff --git a/lib/l10n/intl/messages_zh_CN.dart b/lib/l10n/intl/messages_zh_CN.dart index 8127657..3fde908 100644 --- a/lib/l10n/intl/messages_zh_CN.dart +++ b/lib/l10n/intl/messages_zh_CN.dart @@ -122,6 +122,7 @@ class MessageLookup extends MessageLookupByLibrary { "desc": MessageLookupByLibrary.simpleMessage( "基于ClashMeta的多平台代理客户端,简单易用,开源无广告。", ), + "detectionTip": MessageLookupByLibrary.simpleMessage("依赖第三方程序仅供参考"), "direct": MessageLookupByLibrary.simpleMessage("直连"), "disclaimer": MessageLookupByLibrary.simpleMessage("免责声明"), "disclaimerDesc": MessageLookupByLibrary.simpleMessage( diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index f8f2eb5..69d3a21 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -2669,6 +2669,16 @@ class AppLocalizations { args: [], ); } + + /// `Relying on third-party APIs is for reference only` + String get detectionTip { + return Intl.message( + 'Relying on third-party APIs is for reference only', + name: 'detectionTip', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/lib/main.dart b/lib/main.dart index f104a60..3f95d19 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,53 +11,26 @@ import 'package:fl_clash/plugins/tile.dart'; import 'package:fl_clash/plugins/vpn.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; -import 'package:package_info_plus/package_info_plus.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'application.dart'; import 'clash/core.dart'; import 'clash/lib.dart'; import 'common/common.dart'; -import 'l10n/l10n.dart'; import 'models/models.dart'; Future main() async { globalState.isService = false; WidgetsFlutterBinding.ensureInitialized(); - await clashCore.preload(); - globalState.packageInfo = await PackageInfo.fromPlatform(); final version = await system.version; - final config = await preferences.getConfig() ?? Config(); - final clashConfig = await preferences.getClashConfig() ?? ClashConfig(); - await AppLocalizations.load( - other.getLocaleForString(config.appSetting.locale) ?? - WidgetsBinding.instance.platformDispatcher.locale, - ); + await clashCore.preload(); + await globalState.initApp(version); await android?.init(); - await window?.init(config.windowProps, version); - final appState = AppState( - mode: clashConfig.mode, - version: version, - selectedMap: config.currentSelectedMap, - ); - final appFlowingState = AppFlowingState(); - appState.navigationItems = navigation.getItems( - openLogs: config.appSetting.openLogs, - hasProxies: false, - ); - tray.update( - appState: appState, - appFlowingState: appFlowingState, - config: config, - clashConfig: clashConfig, - ); + await window?.init(version); HttpOverrides.global = FlClashHttpOverrides(); - runAppWithPreferences( - const Application(), - appState: appState, - appFlowingState: appFlowingState, - config: config, - clashConfig: clashConfig, - ); + runApp(ProviderScope( + child: const Application(), + )); } @pragma('vm:entry-point') @@ -66,11 +39,7 @@ Future _service(List flags) async { WidgetsFlutterBinding.ensureInitialized(); final quickStart = flags.contains("quick"); final clashLibHandler = ClashLibHandler(); - final config = await preferences.getConfig() ?? Config(); - await AppLocalizations.load( - other.getLocaleForString(config.appSetting.locale) ?? - WidgetsBinding.instance.platformDispatcher.locale, - ); + await globalState.init(); tile?.addListener( _TileListenerWithService( @@ -83,33 +52,6 @@ Future _service(List flags) async { }, ), ); - if (!quickStart) { - _handleMainIpc(clashLibHandler); - } else { - await ClashCore.initGeo(); - globalState.packageInfo = await PackageInfo.fromPlatform(); - final clashConfig = await preferences.getClashConfig() ?? ClashConfig(); - final homeDirPath = await appPath.homeDirPath; - await app?.tip(appLocalizations.startVpn); - clashLibHandler - .quickStart( - homeDirPath, - globalState.getUpdateConfigParams(config, clashConfig, false), - globalState.getCoreState(config, clashConfig), - ) - .then( - (res) async { - if (res.isNotEmpty) { - await vpn?.stop(); - exit(0); - } - await vpn?.start( - clashLibHandler.getAndroidVpnOptions(), - ); - clashLibHandler.startListener(); - }, - ); - } vpn?.handleGetStartForegroundParams = () { final traffic = clashLibHandler.getTraffic(); @@ -122,17 +64,22 @@ Future _service(List flags) async { vpn?.addListener( _VpnListenerWithService( onStarted: (int fd) { - clashLibHandler.startTun(fd); + commonPrint.log("vpn started fd: $fd"); + final time = clashLibHandler.startTun(fd); + commonPrint.log("vpn start tun time: $time"); }, onDnsChanged: (String dns) { clashLibHandler.updateDns(dns); }, ), ); + final invokeReceiverPort = ReceivePort(); + clashLibHandler.attachInvokePort( invokeReceiverPort.sendPort.nativePort, ); + invokeReceiverPort.listen( (message) async { final invokeMessage = InvokeMessage.fromJson(json.decode(message)); @@ -153,6 +100,32 @@ Future _service(List flags) async { } }, ); + if (!quickStart) { + _handleMainIpc(clashLibHandler); + } else { + commonPrint.log("quick start"); + await ClashCore.initGeo(); + app?.tip(appLocalizations.startVpn); + final homeDirPath = await appPath.homeDirPath; + clashLibHandler + .quickStart( + homeDirPath, + globalState.getUpdateConfigParams(), + globalState.getCoreState(), + ) + .then( + (res) async { + if (res.isNotEmpty) { + await vpn?.stop(); + exit(0); + } + await vpn?.start( + clashLibHandler.getAndroidVpnOptions(), + ); + clashLibHandler.startListener(); + }, + ); + } } _handleMainIpc(ClashLibHandler clashLibHandler) { diff --git a/lib/manager/android_manager.dart b/lib/manager/android_manager.dart index 2fdf7c6..7a051a4 100644 --- a/lib/manager/android_manager.dart +++ b/lib/manager/android_manager.dart @@ -1,12 +1,10 @@ -import 'package:fl_clash/clash/clash.dart'; -import 'package:fl_clash/models/models.dart'; import 'package:fl_clash/plugins/app.dart'; -import 'package:fl_clash/state.dart'; +import 'package:fl_clash/providers/config.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; -class AndroidManager extends StatefulWidget { +class AndroidManager extends ConsumerStatefulWidget { final Widget child; const AndroidManager({ @@ -15,47 +13,25 @@ class AndroidManager extends StatefulWidget { }); @override - State createState() => _AndroidContainerState(); + ConsumerState createState() => _AndroidContainerState(); } -class _AndroidContainerState extends State { +class _AndroidContainerState extends ConsumerState { @override void initState() { super.initState(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); - } - - Widget _updateCoreState(Widget child) { - return Selector2( - selector: (_, config, clashConfig) => globalState.getCoreState( - config, - clashConfig, - ), - builder: (__, state, child) { - clashLib?.setState(state); - return child!; + ref.listenManual( + appSettingProvider.select((state) => state.hidden), + (prev, next) { + app?.updateExcludeFromRecents(next); }, - child: child, - ); - } - - Widget _excludeContainer(Widget child) { - return Selector( - selector: (_, config) => config.appSetting.hidden, - builder: (_, hidden, child) { - app?.updateExcludeFromRecents(hidden); - return child!; - }, - child: child, + fireImmediately: true ); } @override Widget build(BuildContext context) { - return _updateCoreState( - _excludeContainer( - widget.child, - ), - ); + return widget.child; } } diff --git a/lib/manager/app_state_manager.dart b/lib/manager/app_state_manager.dart index f996a02..abb64ee 100644 --- a/lib/manager/app_state_manager.dart +++ b/lib/manager/app_state_manager.dart @@ -1,8 +1,6 @@ import 'package:fl_clash/common/common.dart'; -import 'package:fl_clash/models/models.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; class AppStateManager extends StatefulWidget { final Widget child; @@ -18,48 +16,6 @@ class AppStateManager extends StatefulWidget { class _AppStateManagerState extends State with WidgetsBindingObserver { - _updateNavigationsContainer(Widget child) { - return Selector2( - selector: (_, appState, config) { - final group = appState.currentGroups; - final hasProfile = config.profiles.isNotEmpty; - return UpdateNavigationsSelector( - openLogs: config.appSetting.openLogs, - hasProxies: group.isNotEmpty && hasProfile, - ); - }, - builder: (context, state, child) { - WidgetsBinding.instance.addPostFrameCallback( - (_) { - globalState.appController.appState.navigationItems = - navigation.getItems( - openLogs: state.openLogs, - hasProxies: state.hasProxies, - ); - }, - ); - return child!; - }, - child: child, - ); - } - - _cacheStateChange(Widget child) { - return Selector2( - selector: (_, config, clashConfig) => "$clashConfig $config", - shouldRebuild: (prev, next) { - if (prev != next) { - globalState.appController.savePreferencesDebounce(); - } - return prev != next; - }, - builder: (context, state, child) { - return child!; - }, - child: child, - ); - } - @override void initState() { super.initState(); @@ -76,7 +32,7 @@ class _AppStateManagerState extends State Future didChangeAppLifecycleState(AppLifecycleState state) async { if (state == AppLifecycleState.paused || state == AppLifecycleState.inactive) { - globalState.appController.savePreferencesDebounce(); + globalState.appController.savePreferences(); render?.pause(); } else { render?.resume(); @@ -85,8 +41,9 @@ class _AppStateManagerState extends State @override void didChangePlatformBrightness() { - globalState.appController.appState.brightness = - WidgetsBinding.instance.platformDispatcher.platformBrightness; + globalState.appController.updateBrightness( + WidgetsBinding.instance.platformDispatcher.platformBrightness, + ); } @override @@ -95,11 +52,7 @@ class _AppStateManagerState extends State onPointerHover: (_) { render?.resume(); }, - child: _cacheStateChange( - _updateNavigationsContainer( - widget.child, - ), - ), + child: widget.child, ); } } diff --git a/lib/manager/clash_manager.dart b/lib/manager/clash_manager.dart index 72dc671..feec44c 100644 --- a/lib/manager/clash_manager.dart +++ b/lib/manager/clash_manager.dart @@ -2,13 +2,14 @@ import 'package:fl_clash/clash/clash.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/providers/app.dart'; +import 'package:fl_clash/providers/config.dart'; +import 'package:fl_clash/providers/state.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; -import '../../common/function.dart'; - -class ClashManager extends StatefulWidget { +class ClashManager extends ConsumerStatefulWidget { final Widget child; const ClashManager({ @@ -17,78 +18,35 @@ class ClashManager extends StatefulWidget { }); @override - State createState() => _ClashContainerState(); + ConsumerState createState() => _ClashContainerState(); } -class _ClashContainerState extends State with AppMessageListener { - Widget _updateContainer(Widget child) { - return Selector2( - selector: (_, config, clashConfig) => ClashConfigState( - overrideDns: config.overrideDns, - mixedPort: clashConfig.mixedPort, - allowLan: clashConfig.allowLan, - ipv6: clashConfig.ipv6, - logLevel: clashConfig.logLevel, - geodataLoader: clashConfig.geodataLoader, - externalController: clashConfig.externalController, - mode: clashConfig.mode, - findProcessMode: clashConfig.findProcessMode, - keepAliveInterval: clashConfig.keepAliveInterval, - unifiedDelay: clashConfig.unifiedDelay, - tcpConcurrent: clashConfig.tcpConcurrent, - tun: clashConfig.tun, - dns: clashConfig.dns, - hosts: clashConfig.hosts, - geoXUrl: clashConfig.geoXUrl, - rules: clashConfig.rules, - globalRealUa: clashConfig.globalRealUa, - ), - shouldRebuild: (prev, next) { - if (prev != next) { - globalState.appController.updateClashConfigDebounce(); - } - return prev != next; - }, - builder: (__, state, child) { - return child!; - }, - child: child, - ); - } - - Widget _changeProfileContainer(Widget child) { - return Selector( - selector: (_, config) => config.currentProfileId, - shouldRebuild: (prev, next) { - if (prev != next) { - WidgetsBinding.instance.addPostFrameCallback((_) { - final appController = globalState.appController; - appController.appState.delayMap = {}; - appController.applyProfile(); - }); - } - return prev != next; - }, - builder: (__, state, child) { - return child!; - }, - child: child, - ); - } - +class _ClashContainerState extends ConsumerState + with AppMessageListener { @override Widget build(BuildContext context) { - return _changeProfileContainer( - _updateContainer( - widget.child, - ), - ); + return widget.child; } @override void initState() { super.initState(); clashMessage.addListener(this); + ref.listenManual(currentProfileIdProvider, (prev, next) { + if (prev != next) { + globalState.appController.handleChangeProfile(); + } + }); + ref.listenManual(coreStateProvider, (prev, next) async { + if (prev != next) { + await clashCore.setState(next); + } + }); + ref.listenManual(clashConfigStateProvider, (prev, next) { + if (prev != next) { + globalState.appController.updateClashConfigDebounce(); + } + }); } @override @@ -113,7 +71,7 @@ class _ClashContainerState extends State with AppMessageListener { @override void onLog(Log log) { - globalState.appController.appFlowingState.addLog(log); + ref.watch(logsProvider.notifier).addLog(log); if (log.logLevel == LogLevel.error) { globalState.showNotifier(log.payload ?? ''); } @@ -122,19 +80,18 @@ class _ClashContainerState extends State with AppMessageListener { @override void onRequest(Connection connection) async { - globalState.appController.appState.addRequest(connection); + ref.watch(requestsProvider.notifier).addRequest(connection); super.onRequest(connection); } @override Future onLoaded(String providerName) async { - final appController = globalState.appController; - appController.appState.setProvider( - await clashCore.getExternalProvider( - providerName, - ), - ); - await appController.updateGroupsDebounce(); + ref.watch(providersProvider.notifier).setProvider( + await clashCore.getExternalProvider( + providerName, + ), + ); + await globalState.appController.updateGroupsDebounce(); super.onLoaded(providerName); } } diff --git a/lib/manager/hotkey_manager.dart b/lib/manager/hotkey_manager.dart index 5106889..1f6d540 100644 --- a/lib/manager/hotkey_manager.dart +++ b/lib/manager/hotkey_manager.dart @@ -1,12 +1,12 @@ import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/models/common.dart'; -import 'package:fl_clash/models/config.dart'; +import 'package:fl_clash/providers/config.dart'; import 'package:fl_clash/state.dart'; -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:hotkey_manager/hotkey_manager.dart'; -import 'package:provider/provider.dart'; class HotKeyManager extends StatelessWidget { final Widget child; @@ -36,11 +36,11 @@ class HotKeyManager extends StatelessWidget { }) async { await hotKeyManager.unregisterAll(); final hotkeyActionHandles = hotKeyActions.where( - (hotKeyAction) { + (hotKeyAction) { return hotKeyAction.key != null && hotKeyAction.modifiers.isNotEmpty; }, ).map( - (hotKeyAction) async { + (hotKeyAction) async { final modifiers = hotKeyAction.modifiers .map((item) => item.toHotKeyModifier()) .toList(); @@ -61,14 +61,18 @@ class HotKeyManager extends StatelessWidget { @override Widget build(BuildContext context) { - return Selector>( - selector: (_, config) => config.hotKeyActions, - shouldRebuild: (prev, next) { - return !hotKeyActionListEquality.equals(prev, next); - }, - builder: (_, hotKeyActions, __) { - _updateHotKeys(hotKeyActions: hotKeyActions); - return child; + return Consumer( + builder: (_, ref, child) { + ref.listenManual( + hotKeyActionsProvider, + (prev, next) { + if (!hotKeyActionListEquality.equals(prev, next)) { + _updateHotKeys(hotKeyActions: next); + } + }, + fireImmediately: true, + ); + return child!; }, child: child, ); diff --git a/lib/manager/manager.dart b/lib/manager/manager.dart index d818169..3d435b6 100644 --- a/lib/manager/manager.dart +++ b/lib/manager/manager.dart @@ -5,7 +5,6 @@ export 'clash_manager.dart'; export 'tile_manager.dart'; export 'app_state_manager.dart'; export 'vpn_manager.dart'; -export 'media_manager.dart'; export 'proxy_manager.dart'; export 'connectivity_manager.dart'; export 'message_manager.dart'; \ No newline at end of file diff --git a/lib/manager/media_manager.dart b/lib/manager/media_manager.dart deleted file mode 100644 index aad9d46..0000000 --- a/lib/manager/media_manager.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:fl_clash/common/common.dart'; -import 'package:fl_clash/state.dart'; -import 'package:flutter/material.dart'; - -class MediaManager extends StatelessWidget { - final Widget child; - - const MediaManager({ - super.key, - required this.child, - }); - - @override - Widget build(BuildContext context) { - globalState.measure = Measure.of(context); - return child; - } -} diff --git a/lib/manager/proxy_manager.dart b/lib/manager/proxy_manager.dart index 875fdbd..5edd356 100644 --- a/lib/manager/proxy_manager.dart +++ b/lib/manager/proxy_manager.dart @@ -1,13 +1,19 @@ import 'package:fl_clash/common/proxy.dart'; import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/providers/state.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; -class ProxyManager extends StatelessWidget { +class ProxyManager extends ConsumerStatefulWidget { final Widget child; const ProxyManager({super.key, required this.child}); + @override + ConsumerState createState() => _ProxyManagerState(); +} + +class _ProxyManagerState extends ConsumerState { _updateProxy(ProxyState proxyState) async { final isStart = proxyState.isStart; final systemProxy = proxyState.systemProxy; @@ -20,19 +26,21 @@ class ProxyManager extends StatelessWidget { } @override - Widget build(BuildContext context) { - return Selector3( - selector: (_, appFlowingState, config, clashConfig) => ProxyState( - isStart: appFlowingState.isStart, - systemProxy: config.networkProps.systemProxy, - port: clashConfig.mixedPort, - bassDomain: config.networkProps.bypassDomain, - ), - builder: (_, state, child) { - _updateProxy(state); - return child!; + void initState() { + super.initState(); + ref.listenManual( + proxyStateProvider, + (prev, next) { + if (prev != next) { + _updateProxy(next); + } }, - child: child, + fireImmediately: true, ); } + + @override + Widget build(BuildContext context) { + return widget.child; + } } diff --git a/lib/manager/tray_manager.dart b/lib/manager/tray_manager.dart index 1be9d21..fb3017a 100755 --- a/lib/manager/tray_manager.dart +++ b/lib/manager/tray_manager.dart @@ -1,11 +1,11 @@ import 'package:fl_clash/common/common.dart'; -import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/providers/state.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:tray_manager/tray_manager.dart'; -class TrayManager extends StatefulWidget { +class TrayManager extends ConsumerStatefulWidget { final Widget child; const TrayManager({ @@ -14,43 +14,27 @@ class TrayManager extends StatefulWidget { }); @override - State createState() => _TrayContainerState(); + ConsumerState createState() => _TrayContainerState(); } -class _TrayContainerState extends State with TrayListener { +class _TrayContainerState extends ConsumerState with TrayListener { @override void initState() { super.initState(); trayManager.addListener(this); + ref.listenManual( + trayStateProvider, + (prev, next) { + if (prev != next) { + globalState.appController.updateTray(); + } + }, + ); } @override Widget build(BuildContext context) { - return Selector4( - selector: (_, appState, appFlowingState, config, clashConfig) => - TrayState( - mode: clashConfig.mode, - autoLaunch: config.appSetting.autoLaunch, - isStart: appFlowingState.isStart, - locale: config.appSetting.locale, - systemProxy: config.networkProps.systemProxy, - tunEnable: clashConfig.tun.enable, - brightness: appState.brightness, - port: clashConfig.mixedPort, - groups: appState.groups, - map: appState.selectedMap, - ), - shouldRebuild: (prev, next) { - if (prev != next) { - globalState.appController.updateTray(); - } - return prev != next; - }, - builder: (_, state, child) { - return child!; - }, - child: widget.child, - ); + return widget.child; } @override diff --git a/lib/manager/vpn_manager.dart b/lib/manager/vpn_manager.dart index 6b734f3..5ad197c 100644 --- a/lib/manager/vpn_manager.dart +++ b/lib/manager/vpn_manager.dart @@ -1,11 +1,12 @@ 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/providers/app.dart'; +import 'package:fl_clash/providers/state.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; -class VpnManager extends StatefulWidget { +class VpnManager extends ConsumerStatefulWidget { final Widget child; const VpnManager({ @@ -14,44 +15,33 @@ class VpnManager extends StatefulWidget { }); @override - State createState() => _VpnContainerState(); + ConsumerState createState() => _VpnContainerState(); } -class _VpnContainerState extends State { +class _VpnContainerState extends ConsumerState { + @override + void initState() { + super.initState(); + ref.listenManual(vpnStateProvider, (prev, next) { + showTip(); + }); + } + showTip() { debouncer.call( DebounceTag.vpnTip, () { - WidgetsBinding.instance.addPostFrameCallback((_) { - final appFlowingState = globalState.appController.appFlowingState; - if (appFlowingState.isStart) { - globalState.showNotifier( - appLocalizations.vpnTip, - ); - } - }); + if (ref.read(runTimeProvider.notifier).isStart) { + globalState.showNotifier( + appLocalizations.vpnTip, + ); + } }, ); } @override Widget build(BuildContext context) { - return Selector2( - selector: (_, config, clashConfig) => VPNState( - accessControl: config.accessControl, - vpnProps: config.vpnProps, - stack: clashConfig.tun.stack, - ), - shouldRebuild: (prev, next) { - if (prev != next) { - showTip(); - } - return prev != next; - }, - builder: (_, __, child) { - return child!; - }, - child: widget.child, - ); + return widget.child; } } diff --git a/lib/manager/window_manager.dart b/lib/manager/window_manager.dart index 715bb0d..1aebae0 100644 --- a/lib/manager/window_manager.dart +++ b/lib/manager/window_manager.dart @@ -2,14 +2,15 @@ import 'dart:io'; 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/providers/app.dart'; +import 'package:fl_clash/providers/config.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:window_ext/window_ext.dart'; import 'package:window_manager/window_manager.dart'; -class WindowManager extends StatefulWidget { +class WindowManager extends ConsumerStatefulWidget { final Widget child; const WindowManager({ @@ -18,17 +19,22 @@ class WindowManager extends StatefulWidget { }); @override - State createState() => _WindowContainerState(); + ConsumerState createState() => _WindowContainerState(); } -class _WindowContainerState extends State +class _WindowContainerState extends ConsumerState with WindowListener, WindowExtListener { - Function? updateLaunchDebounce; + @override + Widget build(BuildContext context) { + return widget.child; + } - _autoLaunchContainer(Widget child) { - return Selector( - selector: (_, config) => config.appSetting.autoLaunch, - shouldRebuild: (prev, next) { + @override + void initState() { + super.initState(); + ref.listenManual( + appSettingProvider.select((state) => state.autoLaunch), + (prev, next) { if (prev != next) { debouncer.call( DebounceTag.autoLaunch, @@ -37,23 +43,8 @@ class _WindowContainerState extends State }, ); } - return prev != next; }, - builder: (_, state, child) { - return child!; - }, - child: child, ); - } - - @override - Widget build(BuildContext context) { - return _autoLaunchContainer(widget.child); - } - - @override - void initState() { - super.initState(); windowExtManager.addListener(this); windowManager.addListener(this); } @@ -86,22 +77,24 @@ class _WindowContainerState extends State Future onWindowMoved() async { super.onWindowMoved(); final offset = await windowManager.getPosition(); - final config = globalState.appController.config; - config.windowProps = config.windowProps.copyWith( - top: offset.dy, - left: offset.dx, - ); + ref.read(windowSettingProvider.notifier).updateState( + (state) => state.copyWith( + top: offset.dy, + left: offset.dx, + ), + ); } @override Future onWindowResized() async { super.onWindowResized(); final size = await windowManager.getSize(); - final config = globalState.appController.config; - config.windowProps = config.windowProps.copyWith( - width: size.width, - height: size.height, - ); + ref.read(windowSettingProvider.notifier).updateState( + (state) => state.copyWith( + width: size.width, + height: size.height, + ), + ); } @override @@ -134,9 +127,9 @@ class WindowHeaderContainer extends StatelessWidget { @override Widget build(BuildContext context) { - return Selector( - selector: (_, appState) => appState.version, - builder: (_, version, child) { + return Consumer( + builder: (_, ref, child) { + final version = ref.watch(versionProvider); if (version <= 10 && Platform.isMacOS) { return child!; } diff --git a/lib/models/app.dart b/lib/models/app.dart index 599fd56..94228c7 100644 --- a/lib/models/app.dart +++ b/lib/models/app.dart @@ -1,364 +1,41 @@ import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/enum/enum.dart'; import 'package:flutter/material.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; import 'common.dart'; import 'core.dart'; -import 'profile.dart'; + +part 'generated/app.freezed.dart'; typedef DelayMap = Map>; -class AppState with ChangeNotifier { - List _navigationItems; - bool _isInit; - VersionInfo? _versionInfo; - String _currentLabel; - SystemColorSchemes _systemColorSchemes; - num _sortNum; - Mode _mode; - DelayMap _delayMap; - SelectedMap _selectedMap; - List _groups; - double _viewWidth; - final FixedList _requests; - num _checkIpNum; - List _providers; - List _packages; - Brightness? _brightness; - int _version; - - AppState({ - required Mode mode, - required SelectedMap selectedMap, +@freezed +class AppState with _$AppState { + const factory AppState({ + @Default(false) bool isInit, + @Default(PageLabel.dashboard) PageLabel pageLabel, + @Default([]) List packages, + @Default(ColorSchemes()) ColorSchemes colorSchemes, + @Default(0) int sortNum, + required double viewWidth, + @Default({}) DelayMap delayMap, + @Default([]) List groups, + @Default(0) int checkIpNum, + Brightness? brightness, + int? runTime, + @Default([]) List providers, + String? localIp, + required FixedList requests, required int version, - }) - : _navigationItems = [], - _isInit = false, - _currentLabel = "dashboard", - _viewWidth = other - .getScreenSize() - .width, - _selectedMap = selectedMap, - _sortNum = 0, - _checkIpNum = 0, - _requests = FixedList(1000), - _mode = mode, - _brightness = null, - _delayMap = {}, - _groups = [], - _providers = [], - _packages = [], - _systemColorSchemes = const SystemColorSchemes(), - _version = version; - - String get currentLabel => _currentLabel; - - set currentLabel(String value) { - if (_currentLabel != value) { - _currentLabel = value; - notifyListeners(); - } - } - - List get navigationItems => _navigationItems; - - set navigationItems(List value) { - if (!navigationItemListEquality.equals(_navigationItems, value)) { - _navigationItems = value; - notifyListeners(); - } - } - - List get currentNavigationItems { - NavigationItemMode navigationItemMode; - if (_viewWidth <= maxMobileWidth) { - navigationItemMode = NavigationItemMode.mobile; - } else { - navigationItemMode = NavigationItemMode.desktop; - } - return navigationItems - .where( - (element) => element.modes.contains(navigationItemMode), - ) - .toList(); - } - - bool get isInit => _isInit; - - set isInit(bool value) { - if (_isInit != value) { - _isInit = value; - notifyListeners(); - } - } - - String getDesc(String type, String proxyName) { - final groupTypeNamesList = GroupType.values.map((e) => e.name).toList(); - if (!groupTypeNamesList.contains(type)) { - return type; - } else { - final index = groups.indexWhere((element) => element.name == proxyName); - if (index == -1) return type; - return "$type(${groups[index].now ?? '*'})"; - } - } - - String getRealProxyName(String proxyName) { - if (proxyName.isEmpty) return proxyName; - final index = groups.indexWhere((element) => element.name == proxyName); - if (index == -1) return proxyName; - final group = groups[index]; - final currentSelectedName = - group.getCurrentSelectedName(selectedMap[proxyName] ?? ''); - if (currentSelectedName.isEmpty) return proxyName; - return getRealProxyName( - currentSelectedName, - ); - } - - String? get showProxyName { - if (currentGroups.isEmpty) { - return UsedProxy.DIRECT.name; - } - final firstGroup = currentGroups.first; - final firstGroupName = firstGroup.name; - return selectedMap[firstGroupName] ?? firstGroup.now; - } - - VersionInfo? get versionInfo => _versionInfo; - - set versionInfo(VersionInfo? value) { - if (_versionInfo != value) { - _versionInfo = value; - notifyListeners(); - } - } - - List get requests => _requests.list; - - addRequest(Connection value) { - _requests.add(value); - notifyListeners(); - } - - SystemColorSchemes get systemColorSchemes => _systemColorSchemes; - - set systemColorSchemes(SystemColorSchemes value) { - if (_systemColorSchemes != value) { - _systemColorSchemes = value; - notifyListeners(); - } - } - - List get groups => _groups; - - set groups(List value) { - if (!groupListEquality.equals(_groups, value)) { - _groups = value; - notifyListeners(); - } - } - - num get sortNum => _sortNum; - - set sortNum(num value) { - if (_sortNum != value) { - _sortNum = value; - notifyListeners(); - } - } - - num get checkIpNum => _checkIpNum; - - set checkIpNum(num value) { - if (_checkIpNum != value) { - _checkIpNum = value; - notifyListeners(); - } - } - - Mode get mode => _mode; - - set mode(Mode value) { - if (_mode != value) { - _mode = value; - notifyListeners(); - } - } - - SelectedMap get selectedMap { - return _selectedMap; - } - - set selectedMap(SelectedMap value) { - if (!stringAndStringMapEquality.equals(_selectedMap, value)) { - _selectedMap = value; - notifyListeners(); - } - } - - List get currentGroups { - switch (mode) { - case Mode.direct: - return []; - case Mode.global: - return groups.toList(); - case Mode.rule: - return groups - .where((item) => item.hidden == false) - .where((element) => element.name != GroupName.GLOBAL.name) - .toList(); - } - } - - double get viewWidth => _viewWidth; - - set viewWidth(double value) { - if (_viewWidth != value) { - _viewWidth = value; - notifyListeners(); - } - } - - ViewMode get viewMode => other.getViewMode(_viewWidth); - - DelayMap get delayMap { - return _delayMap; - } - - set delayMap(DelayMap value) { - if (_delayMap != value) { - _delayMap = value; - notifyListeners(); - } - } - - setDelay(Delay delay) { - if (_delayMap[delay.url]?[delay.name] != delay.value) { - final DelayMap newDelayMap = Map.from(_delayMap); - if (newDelayMap[delay.url] == null) { - newDelayMap[delay.url] = {}; - } - newDelayMap[delay.url]![delay.name] = delay.value; - _delayMap = newDelayMap; - notifyListeners(); - } - } - - List get packages => _packages; - - set packages(List value) { - if (!packageListEquality.equals(_packages, value)) { - _packages = value; - notifyListeners(); - } - } - - List get providers => _providers; - - set providers(List value) { - if (!externalProviderListEquality.equals(_providers, value)) { - _providers = value; - notifyListeners(); - } - } - - setProvider(ExternalProvider? provider) { - if (provider == null) return; - final index = _providers.indexWhere((item) => item.name == provider.name); - if (index == -1) return; - _providers = List.from(_providers) - ..[index] = provider; - notifyListeners(); - } - - Group? getGroupWithName(String groupName) { - final index = - currentGroups.indexWhere((element) => element.name == groupName); - return index != -1 ? currentGroups[index] : null; - } - - Brightness? get brightness => _brightness; - - set brightness(Brightness? value) { - if (_brightness != value) { - _brightness = value; - notifyListeners(); - } - } - - int get version => _version; - - set version(int value) { - if (_version != value) { - _version = value; - notifyListeners(); - } - } + required FixedList logs, + required FixedList traffics, + required Traffic totalTraffic, + }) = _AppState; } -class AppFlowingState with ChangeNotifier { - int? _runTime; - final FixedList _logs; - List _traffics; - Traffic _totalTraffic; - String? _localIp; +extension AppStateExt on AppState { + ViewMode get viewMode => other.getViewMode(viewWidth); - AppFlowingState() - : _logs = FixedList(1000), - _traffics = [], - _totalTraffic = Traffic(); - - bool get isStart => _runTime != null; - - int? get runTime => _runTime; - - set runTime(int? value) { - if (_runTime != value) { - _runTime = value; - notifyListeners(); - } - } - - List get logs => _logs.list; - - addLog(Log log) { - _logs.add(log); - notifyListeners(); - } - - List get traffics => _traffics; - - set traffics(List value) { - if (_traffics != value) { - _traffics = value; - notifyListeners(); - } - } - - addTraffic(Traffic traffic) { - _traffics = List.from(_traffics) - ..add(traffic); - const maxLength = 30; - _traffics = _traffics.safeSublist(_traffics.length - maxLength); - notifyListeners(); - } - - Traffic get totalTraffic => _totalTraffic; - - set totalTraffic(Traffic value) { - if (_totalTraffic != value) { - _totalTraffic = value; - notifyListeners(); - } - } - - String? get localIp => _localIp; - - set localIp(String? value) { - if (_localIp != value) { - _localIp = value; - notifyListeners(); - } - } + bool get isStart => runTime != null; } diff --git a/lib/models/clash_config.dart b/lib/models/clash_config.dart index 2ae52e1..039726f 100644 --- a/lib/models/clash_config.dart +++ b/lib/models/clash_config.dart @@ -1,127 +1,22 @@ // ignore_for_file: invalid_annotation_target import 'package:fl_clash/common/common.dart'; -import 'package:fl_clash/state.dart'; -import 'package:flutter/material.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import '../enum/enum.dart'; part 'generated/clash_config.freezed.dart'; + part 'generated/clash_config.g.dart'; -const defaultTun = Tun(); - -@freezed -class Tun with _$Tun { - const factory Tun({ - @Default(false) bool enable, - @Default(appName) String device, - @Default(TunStack.gvisor) TunStack stack, - @JsonKey(name: "dns-hijack") @Default(["any:53"]) List dnsHijack, - }) = _Tun; - - factory Tun.fromJson(Map json) => _$TunFromJson(json); - - factory Tun.realFromJson(Map? json) { - if (json == null) { - return defaultTun; - } - try { - return Tun.fromJson(json); - } catch (_) { - return defaultTun; - } - } -} - -@freezed -class FallbackFilter with _$FallbackFilter { - const factory FallbackFilter({ - @Default(true) bool geoip, - @Default("CN") @JsonKey(name: "geoip-code") String geoipCode, - @Default(["gfw"]) List geosite, - @Default(["240.0.0.0/4"]) List ipcidr, - @Default([ - "+.google.com", - "+.facebook.com", - "+.youtube.com", - ]) - List domain, - }) = _FallbackFilter; - - factory FallbackFilter.fromJson(Map json) => - _$FallbackFilterFromJson(json); -} - -const defaultDns = Dns(); - -@freezed -class Dns with _$Dns { - const factory Dns({ - @Default(true) bool enable, - @Default(false) @JsonKey(name: "prefer-h3") bool preferH3, - @Default(true) @JsonKey(name: "use-hosts") bool useHosts, - @Default(true) @JsonKey(name: "use-system-hosts") bool useSystemHosts, - @Default(false) @JsonKey(name: "respect-rules") bool respectRules, - @Default(false) bool ipv6, - @Default(["223.5.5.5"]) - @JsonKey(name: "default-nameserver") - List defaultNameserver, - @Default(DnsMode.fakeIp) - @JsonKey(name: "enhanced-mode") - DnsMode enhancedMode, - @Default("198.18.0.1/16") - @JsonKey(name: "fake-ip-range") - String fakeIpRange, - @Default([ - "*.lan", - "localhost.ptlogin2.qq.com", - ]) - @JsonKey(name: "fake-ip-filter") - List fakeIpFilter, - @Default({ - "www.baidu.com": "114.114.114.114", - "+.internal.crop.com": "10.0.0.1", - "geosite:cn": "https://doh.pub/dns-query" - }) - @JsonKey(name: "nameserver-policy") - Map nameserverPolicy, - @Default([ - "https://doh.pub/dns-query", - "https://dns.alidns.com/dns-query", - ]) - List nameserver, - @Default([ - "tls://8.8.4.4", - "tls://1.1.1.1", - ]) - List fallback, - @Default([ - "https://doh.pub/dns-query", - ]) - @JsonKey(name: "proxy-server-nameserver") - List proxyServerNameserver, - @Default(FallbackFilter()) - @JsonKey(name: "fallback-filter") - FallbackFilter fallbackFilter, - }) = _Dns; - - factory Dns.fromJson(Map json) => _$DnsFromJson(json); - - factory Dns.safeDnsFromJson(Map json) { - try { - return Dns.fromJson(json); - } catch (_) { - return const Dns(); - } - } -} - -typedef GeoXMap = Map; - typedef HostsMap = Map; +const defaultClashConfig = ClashConfig(); + +const defaultTun = Tun(); +const defaultDns = Dns(); +const defaultGeoXUrl = GeoXUrl(); + const defaultMixedPort = 7890; const defaultKeepAliveInterval = 30; @@ -210,310 +105,221 @@ const defaultBypassPrivateRouteAddress = [ "fec0::/10" ]; -@JsonSerializable() -class ClashConfig extends ChangeNotifier { - int _mixedPort; - bool _allowLan; - bool _ipv6; - String _geodataLoader; - LogLevel _logLevel; - String _externalController; - Mode _mode; - FindProcessMode _findProcessMode; - int _keepAliveInterval; - bool _unifiedDelay; - bool _tcpConcurrent; - Tun _tun; - Dns _dns; - GeoXMap _geoXUrl; - List _rules; - String? _globalRealUa; - HostsMap _hosts; - List _includeRouteAddress; - RouteMode _routeMode; +@freezed +class ProxyGroup with _$ProxyGroup { + const factory ProxyGroup({ + required String name, + @JsonKey( + fromJson: GroupType.parseProfileType, + ) + required GroupType type, + List? proxies, + List? use, + int? interval, + bool? lazy, + String? url, + int? timeout, + @JsonKey(name: "max-failed-times") int? maxFailedTimes, + String? filter, + @JsonKey(name: "expected-filter") String? excludeFilter, + @JsonKey(name: "exclude-type") String? excludeType, + @JsonKey(name: "expected-status") int? expectedStatus, + bool? hidden, + String? icon, + }) = _ProxyGroup; - ClashConfig() - : _mixedPort = defaultMixedPort, - _mode = Mode.rule, - _ipv6 = false, - _findProcessMode = FindProcessMode.off, - _allowLan = false, - _tcpConcurrent = false, - _logLevel = LogLevel.info, - _tun = const Tun(), - _unifiedDelay = false, - _geodataLoader = geodataLoaderMemconservative, - _externalController = '', - _keepAliveInterval = defaultKeepAliveInterval, - _dns = defaultDns, - _geoXUrl = defaultGeoXMap, - _routeMode = RouteMode.config, - _includeRouteAddress = [], - _rules = [], - _hosts = {}; + factory ProxyGroup.fromJson(Map json) => + _$ProxyGroupFromJson(json); +} - @JsonKey(name: "mixed-port", defaultValue: defaultMixedPort) - int get mixedPort => _mixedPort; +@freezed +class Tun with _$Tun { + const factory Tun({ + @Default(false) bool enable, + @Default(appName) String device, + @Default(TunStack.gvisor) TunStack stack, + @JsonKey(name: "dns-hijack") @Default(["any:53"]) List dnsHijack, + @JsonKey(name: "route-address") @Default([]) List routeAddress, + }) = _Tun; - set mixedPort(int value) { - if (_mixedPort != value) { - _mixedPort = value; - notifyListeners(); + factory Tun.fromJson(Map json) => _$TunFromJson(json); + + factory Tun.safeFormJson(Map? json) { + if (json == null) { + return defaultTun; } - } - - @JsonKey(defaultValue: Mode.rule) - Mode get mode => _mode; - - set mode(Mode value) { - if (_mode != value) { - _mode = value; - notifyListeners(); + try { + return Tun.fromJson(json); + } catch (_) { + return defaultTun; + } + } +} + +@freezed +class FallbackFilter with _$FallbackFilter { + const factory FallbackFilter({ + @Default(true) bool geoip, + @Default("CN") @JsonKey(name: "geoip-code") String geoipCode, + @Default(["gfw"]) List geosite, + @Default(["240.0.0.0/4"]) List ipcidr, + @Default([ + "+.google.com", + "+.facebook.com", + "+.youtube.com", + ]) + List domain, + }) = _FallbackFilter; + + factory FallbackFilter.fromJson(Map json) => + _$FallbackFilterFromJson(json); +} + +@freezed +class Dns with _$Dns { + const factory Dns({ + @Default(true) bool enable, + @Default(false) @JsonKey(name: "prefer-h3") bool preferH3, + @Default(true) @JsonKey(name: "use-hosts") bool useHosts, + @Default(true) @JsonKey(name: "use-system-hosts") bool useSystemHosts, + @Default(false) @JsonKey(name: "respect-rules") bool respectRules, + @Default(false) bool ipv6, + @Default(["223.5.5.5"]) + @JsonKey(name: "default-nameserver") + List defaultNameserver, + @Default(DnsMode.fakeIp) + @JsonKey(name: "enhanced-mode") + DnsMode enhancedMode, + @Default("198.18.0.1/16") + @JsonKey(name: "fake-ip-range") + String fakeIpRange, + @Default([ + "*.lan", + "localhost.ptlogin2.qq.com", + ]) + @JsonKey(name: "fake-ip-filter") + List fakeIpFilter, + @Default({ + "www.baidu.com": "114.114.114.114", + "+.internal.crop.com": "10.0.0.1", + "geosite:cn": "https://doh.pub/dns-query" + }) + @JsonKey(name: "nameserver-policy") + Map nameserverPolicy, + @Default([ + "https://doh.pub/dns-query", + "https://dns.alidns.com/dns-query", + ]) + List nameserver, + @Default([ + "tls://8.8.4.4", + "tls://1.1.1.1", + ]) + List fallback, + @Default([ + "https://doh.pub/dns-query", + ]) + @JsonKey(name: "proxy-server-nameserver") + List proxyServerNameserver, + @Default(FallbackFilter()) + @JsonKey(name: "fallback-filter") + FallbackFilter fallbackFilter, + }) = _Dns; + + factory Dns.fromJson(Map json) => _$DnsFromJson(json); + + factory Dns.safeDnsFromJson(Map json) { + try { + return Dns.fromJson(json); + } catch (_) { + return const Dns(); + } + } +} + +@freezed +class GeoXUrl with _$GeoXUrl { + const factory GeoXUrl({ + @Default( + "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", + ) + String mmdb, + @Default( + "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", + ) + String asn, + @Default( + "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat", + ) + String geoip, + @Default( + "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat", + ) + String geosite, + }) = _GeoXUrl; + + factory GeoXUrl.fromJson(Map json) => + _$GeoXUrlFromJson(json); + + factory GeoXUrl.safeFormJson(Map? json) { + if (json == null) { + return defaultGeoXUrl; + } + try { + return GeoXUrl.fromJson(json); + } catch (_) { + return defaultGeoXUrl; + } + } +} + +@freezed +class ClashConfig with _$ClashConfig { + const factory ClashConfig({ + @Default(defaultMixedPort) @JsonKey(name: "mixed-port") int mixedPort, + @Default(Mode.rule) Mode mode, + @Default(false) @JsonKey(name: "allow-lan") bool allowLan, + @Default(LogLevel.info) @JsonKey(name: "log-level") LogLevel logLevel, + @Default(false) bool ipv6, + @Default(FindProcessMode.off) + @JsonKey( + name: "find-process-mode", + unknownEnumValue: FindProcessMode.off, + ) + FindProcessMode findProcessMode, + @Default(defaultKeepAliveInterval) + @JsonKey(name: "keep-alive-interval") + int keepAliveInterval, + @Default(true) @JsonKey(name: "unified-delay") bool unifiedDelay, + @Default(true) @JsonKey(name: "tcp-concurrent") bool tcpConcurrent, + @Default(defaultTun) @JsonKey(fromJson: Tun.safeFormJson) Tun tun, + @Default(defaultDns) @JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns, + @Default(defaultGeoXUrl) + @JsonKey(name: "geox-url", fromJson: GeoXUrl.safeFormJson) + GeoXUrl geoXUrl, + @Default(GeodataLoader.memconservative) + @JsonKey(name: "geodata-loader") + GeodataLoader geodataLoader, + @Default([]) @JsonKey(name: "proxy-groups") List proxyGroups, + @Default([]) List rules, + @JsonKey(name: "global-ua") String? globalUa, + @Default(ExternalControllerStatus.close) + @JsonKey(name: "external-controller") + ExternalControllerStatus externalController, + @Default({}) HostsMap hosts, + }) = _ClashConfig; + + factory ClashConfig.fromJson(Map json) => + _$ClashConfigFromJson(json); + + factory ClashConfig.safeFormJson(Map? json) { + if (json == null) { + return defaultClashConfig; + } + try { + return ClashConfig.fromJson(json); + } catch (_) { + return defaultClashConfig; } } - - @JsonKey(name: "find-process-mode", defaultValue: FindProcessMode.off) - FindProcessMode get findProcessMode => _findProcessMode; - - set findProcessMode(FindProcessMode value) { - if (_findProcessMode != value) { - _findProcessMode = value; - notifyListeners(); - } - } - - @JsonKey(name: "allow-lan") - bool get allowLan => _allowLan; - - set allowLan(bool value) { - if (_allowLan != value) { - _allowLan = value; - notifyListeners(); - } - } - - @JsonKey(name: "log-level", defaultValue: LogLevel.info) - LogLevel get logLevel => _logLevel; - - set logLevel(LogLevel value) { - if (_logLevel != value) { - _logLevel = value; - notifyListeners(); - } - } - - @JsonKey(name: "external-controller", defaultValue: '') - String get externalController => _externalController; - - set externalController(String value) { - if (_externalController != value) { - _externalController = value; - notifyListeners(); - } - } - - @JsonKey(name: "keep-alive-interval", defaultValue: defaultKeepAliveInterval) - int get keepAliveInterval => _keepAliveInterval; - - set keepAliveInterval(int value) { - if (_keepAliveInterval != value) { - _keepAliveInterval = value; - notifyListeners(); - } - } - - @JsonKey(defaultValue: false) - bool get ipv6 => _ipv6; - - set ipv6(bool value) { - if (_ipv6 != value) { - _ipv6 = value; - notifyListeners(); - } - } - - @JsonKey(name: "geodata-loader", defaultValue: geodataLoaderMemconservative) - String get geodataLoader => _geodataLoader; - - set geodataLoader(String value) { - if (_geodataLoader != value) { - _geodataLoader = value; - notifyListeners(); - } - } - - @JsonKey(name: "unified-delay", defaultValue: false) - bool get unifiedDelay => _unifiedDelay; - - set unifiedDelay(bool value) { - if (_unifiedDelay != value) { - _unifiedDelay = value; - notifyListeners(); - } - } - - @JsonKey(name: "tcp-concurrent", defaultValue: false) - bool get tcpConcurrent => _tcpConcurrent; - - set tcpConcurrent(bool value) { - if (_tcpConcurrent != value) { - _tcpConcurrent = value; - notifyListeners(); - } - } - - Tun get tun { - return _tun; - } - - set tun(Tun value) { - if (_tun != value) { - _tun = value; - notifyListeners(); - } - } - - @JsonKey(fromJson: Dns.safeDnsFromJson) - Dns get dns => _dns; - - set dns(Dns value) { - if (_dns != value) { - _dns = value; - notifyListeners(); - } - } - - List get rules => _rules; - - set rules(List value) { - if (_rules != value) { - _rules = value; - notifyListeners(); - } - } - - @JsonKey(name: "global-ua", includeFromJson: false, includeToJson: true) - String get globalUa { - if (_globalRealUa == null) { - return globalState.packageInfo.ua; - } else { - return _globalRealUa!; - } - } - - @JsonKey(name: "global-real-ua", defaultValue: null) - String? get globalRealUa => _globalRealUa; - - set globalRealUa(String? value) { - if (_globalRealUa != value) { - _globalRealUa = value; - notifyListeners(); - } - } - - @JsonKey(name: "geox-url", defaultValue: defaultGeoXMap) - GeoXMap get geoXUrl => _geoXUrl; - - set geoXUrl(GeoXMap value) { - if (!stringAndStringMapEquality.equals(value, _geoXUrl)) { - _geoXUrl = value; - notifyListeners(); - } - } - - @JsonKey(defaultValue: {}) - HostsMap get hosts => _hosts; - - set hosts(HostsMap value) { - if (!stringAndStringMapEquality.equals(value, _hosts)) { - _hosts = value; - notifyListeners(); - } - } - - @JsonKey(name: "route-address", includeFromJson: false, includeToJson: true) - List get routeAddress { - return switch (_routeMode == RouteMode.config) { - true => _includeRouteAddress, - false => defaultBypassPrivateRouteAddress, - }; - } - - @JsonKey(name: "include-route-address", defaultValue: []) - List get includeRouteAddress => _includeRouteAddress; - - set includeRouteAddress(List value) { - if (!stringListEquality.equals(value, _includeRouteAddress)) { - _includeRouteAddress = value; - notifyListeners(); - } - } - - @JsonKey(name: "route-mode", defaultValue: RouteMode.config) - RouteMode get routeMode => _routeMode; - - set routeMode(RouteMode value) { - if (value != _routeMode) { - _routeMode = value; - notifyListeners(); - } - } - - update([ClashConfig? clashConfig]) { - if (clashConfig != null) { - _mixedPort = clashConfig._mixedPort; - _allowLan = clashConfig._allowLan; - _hosts = clashConfig._hosts; - _mode = clashConfig._mode; - _logLevel = clashConfig._logLevel; - _tun = clashConfig._tun; - _findProcessMode = clashConfig._findProcessMode; - _geoXUrl = clashConfig._geoXUrl; - _unifiedDelay = clashConfig._unifiedDelay; - _globalRealUa = clashConfig._globalRealUa; - _tcpConcurrent = clashConfig._tcpConcurrent; - _externalController = clashConfig._externalController; - _geodataLoader = clashConfig._geodataLoader; - _dns = clashConfig._dns; - _rules = clashConfig._rules; - _routeMode = clashConfig._routeMode; - _includeRouteAddress = clashConfig._includeRouteAddress; - } - notifyListeners(); - } - - ClashConfig copyWith() { - return ClashConfig() - ..mixedPort = _mixedPort - ..mode = _mode - ..ipv6 = _ipv6 - ..findProcessMode = _findProcessMode - ..allowLan = _allowLan - ..tcpConcurrent = _tcpConcurrent - ..logLevel = _logLevel - ..tun = tun - ..unifiedDelay = _unifiedDelay - ..geodataLoader = _geodataLoader - ..externalController = _externalController - ..keepAliveInterval = _keepAliveInterval - ..dns = _dns - ..geoXUrl = _geoXUrl - ..routeMode = _routeMode - ..includeRouteAddress = _includeRouteAddress - ..rules = _rules - ..hosts = _hosts; - } - - Map toJson() { - return _$ClashConfigToJson(this); - } - - factory ClashConfig.fromJson(Map json) { - return _$ClashConfigFromJson(json); - } - - @override - String toString() { - return 'ClashConfig{_mixedPort: $_mixedPort, _allowLan: $_allowLan, _ipv6: $_ipv6, _geodataLoader: $_geodataLoader, _logLevel: $_logLevel, _externalController: $_externalController, _mode: $_mode, _findProcessMode: $_findProcessMode, _keepAliveInterval: $_keepAliveInterval, _unifiedDelay: $_unifiedDelay, _tcpConcurrent: $_tcpConcurrent, _tun: $_tun, _dns: $_dns, _geoXUrl: $_geoXUrl, _rules: $_rules, _globalRealUa: $_globalRealUa, _hosts: $_hosts}'; - } } diff --git a/lib/models/common.dart b/lib/models/common.dart index 2917bb0..db9b43e 100644 --- a/lib/models/common.dart +++ b/lib/models/common.dart @@ -8,13 +8,14 @@ import 'package:flutter/material.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'generated/common.freezed.dart'; + part 'generated/common.g.dart'; @freezed class NavigationItem with _$NavigationItem { const factory NavigationItem({ required Icon icon, - required String label, + required PageLabel label, final String? description, required Widget fragment, @Default(true) bool keep, @@ -244,7 +245,7 @@ class Traffic { @immutable class TrafficValueShow { - final String value; + final double value; final TrafficUnit unit; const TrafficValueShow({ @@ -253,6 +254,50 @@ class TrafficValueShow { }); } +@freezed +class Proxy with _$Proxy { + const factory Proxy({ + required String name, + required String type, + String? now, + }) = _Proxy; + + factory Proxy.fromJson(Map json) => _$ProxyFromJson(json); +} + +@freezed +class Group with _$Group { + const factory Group({ + required GroupType type, + @Default([]) List all, + String? now, + bool? hidden, + String? testUrl, + @Default("") String icon, + required String name, + }) = _Group; + + factory Group.fromJson(Map json) => _$GroupFromJson(json); +} + +extension GroupsExt on List { + Group? getGroup(String groupName) { + final index = indexWhere((element) => element.name == groupName); + return index != -1 ? this[index] : null; + } +} + +extension GroupExt on Group { + String get realNow => now ?? ""; + + String getCurrentSelectedName(String proxyName) { + if (type.isComputedSelected) { + return realNow.isNotEmpty ? realNow : proxyName; + } + return proxyName.isNotEmpty ? proxyName : realNow; + } +} + @immutable class TrafficValue { final int _value; @@ -263,35 +308,38 @@ class TrafficValue { String get show => "$showValue $showUnit"; - String get showValue => trafficValueShow.value; + String get shortShow => + "${trafficValueShow.value.fixed(decimals: 1)} $showUnit"; + + String get showValue => trafficValueShow.value.fixed(); String get showUnit => trafficValueShow.unit.name; TrafficValueShow get trafficValueShow { if (_value > pow(1024, 4)) { return TrafficValueShow( - value: (_value / pow(1024, 4)).fixed(), + value: _value / pow(1024, 4), unit: TrafficUnit.TB, ); } if (_value > pow(1024, 3)) { return TrafficValueShow( - value: (_value / pow(1024, 3)).fixed(), + value: _value / pow(1024, 3), unit: TrafficUnit.GB, ); } if (_value > pow(1024, 2)) { return TrafficValueShow( - value: (_value / pow(1024, 2)).fixed(), unit: TrafficUnit.MB); + value: _value / pow(1024, 2), unit: TrafficUnit.MB); } if (_value > pow(1024, 1)) { return TrafficValueShow( - value: (_value / pow(1024, 1)).fixed(), + value: _value / pow(1024, 2), unit: TrafficUnit.KB, ); } return TrafficValueShow( - value: _value.fixed(), + value: _value.toDouble(), unit: TrafficUnit.B, ); } @@ -312,56 +360,16 @@ class TrafficValue { int get hashCode => _value.hashCode; } -typedef ProxyMap = Map; - @freezed -class Group with _$Group { - const factory Group({ - required GroupType type, - @Default([]) List all, - String? now, - bool? hidden, - String? testUrl, - @Default("") String icon, - required String name, - }) = _Group; - - factory Group.fromJson(Map json) => _$GroupFromJson(json); +class ColorSchemes with _$ColorSchemes { + const factory ColorSchemes({ + ColorScheme? lightColorScheme, + ColorScheme? darkColorScheme, + }) = _ColorSchemes; } -extension GroupExt on Group { - String get realNow => now ?? ""; - - String getCurrentSelectedName(String proxyName) { - if (type.isURLTestOrFallback) { - return realNow.isNotEmpty ? realNow : proxyName; - } - return proxyName.isNotEmpty ? proxyName : realNow; - } -} - -@freezed -class Proxy with _$Proxy { - const factory Proxy({ - required String name, - required String type, - String? now, - }) = _Proxy; - - factory Proxy.fromJson(Map json) => _$ProxyFromJson(json); -} - -@immutable -class SystemColorSchemes { - final ColorScheme? lightColorScheme; - final ColorScheme? darkColorScheme; - - const SystemColorSchemes({ - this.lightColorScheme, - this.darkColorScheme, - }); - - getSystemColorSchemeForBrightness(Brightness? brightness) { +extension ColorSchemesExt on ColorSchemes { + ColorScheme getColorSchemeForBrightness(Brightness? brightness) { if (brightness == Brightness.dark) { return darkColorScheme != null ? ColorScheme.fromSeed( @@ -492,4 +500,4 @@ class ActionItemData { final VoidCallback onPressed; final IconData? icon; final ActionType? type; -} +} \ No newline at end of file diff --git a/lib/models/config.dart b/lib/models/config.dart index 1dce9f1..d7d0f0f 100644 --- a/lib/models/config.dart +++ b/lib/models/config.dart @@ -13,9 +13,41 @@ part 'generated/config.freezed.dart'; part 'generated/config.g.dart'; -final defaultAppSetting = const AppSetting().copyWith( - isAnimateToPage: system.isDesktop ? false : true, -); +const defaultBypassDomain = [ + "*zhihu.com", + "*zhimg.com", + "*jd.com", + "100ime-iat-api.xfyun.cn", + "*360buyimg.com", + "localhost", + "*.local", + "127.*", + "10.*", + "172.16.*", + "172.17.*", + "172.18.*", + "172.19.*", + "172.2*", + "172.30.*", + "172.31.*", + "192.168.*" +]; + +const defaultAppSettingProps = AppSettingProps(); +const defaultVpnProps = VpnProps(); +const defaultNetworkProps = NetworkProps(); +const defaultProxiesStyle = ProxiesStyle(); +const defaultWindowProps = WindowProps(); +const defaultAccessControl = AccessControl(); +final defaultThemeProps = Platform.isWindows + ? ThemeProps().copyWith( + fontFamily: FontFamily.miSans, + primaryColor: defaultPrimaryColor.value, + ) + : ThemeProps().copyWith( + primaryColor: defaultPrimaryColor.value, + themeMode: ThemeMode.dark, + ); const List defaultDashboardWidgets = [ DashboardWidget.networkSpeed, @@ -27,8 +59,9 @@ const List defaultDashboardWidgets = [ DashboardWidget.intranetIp, ]; -List dashboardWidgetsRealFormJson( - List? dashboardWidgets) { +List dashboardWidgetsSafeFormJson( + List? dashboardWidgets, +) { try { return dashboardWidgets ?.map((e) => $enumDecode(_$DashboardWidgetEnumMap, e)) @@ -40,11 +73,11 @@ List dashboardWidgetsRealFormJson( } @freezed -class AppSetting with _$AppSetting { - const factory AppSetting({ +class AppSettingProps with _$AppSettingProps { + const factory AppSettingProps({ String? locale, - @JsonKey(fromJson: dashboardWidgetsRealFormJson) @Default(defaultDashboardWidgets) + @JsonKey(fromJson: dashboardWidgetsSafeFormJson) List dashboardWidgets, @Default(false) bool onlyStatisticsProxy, @Default(false) bool autoLaunch, @@ -59,23 +92,22 @@ class AppSetting with _$AppSetting { @Default(false) bool disclaimerAccepted, @Default(true) bool minimizeOnExit, @Default(false) bool hidden, - }) = _AppSetting; + }) = _AppSettingProps; - factory AppSetting.fromJson(Map json) => - _$AppSettingFromJson(json); + factory AppSettingProps.fromJson(Map json) => + _$AppSettingPropsFromJson(json); - factory AppSetting.realFromJson(Map? json) { - final appSetting = - json == null ? defaultAppSetting : AppSetting.fromJson(json); - return appSetting.copyWith( - isAnimateToPage: system.isDesktop ? false : appSetting.isAnimateToPage, - ); + factory AppSettingProps.safeFromJson(Map? json) { + return json == null + ? defaultAppSettingProps + : AppSettingProps.fromJson(json); } } @freezed class AccessControl with _$AccessControl { const factory AccessControl({ + @Default(false) bool enable, @Default(AccessControlMode.rejectSelected) AccessControlMode mode, @Default([]) List acceptList, @Default([]) List rejectList, @@ -107,28 +139,6 @@ class WindowProps with _$WindowProps { json == null ? const WindowProps() : _$WindowPropsFromJson(json); } -const defaultBypassDomain = [ - "*zhihu.com", - "*zhimg.com", - "*jd.com", - "100ime-iat-api.xfyun.cn", - "*360buyimg.com", - "localhost", - "*.local", - "127.*", - "10.*", - "172.16.*", - "172.17.*", - "172.18.*", - "172.19.*", - "172.2*", - "172.30.*", - "172.31.*", - "192.168.*" -]; - -const defaultVpnProps = VpnProps(); - @freezed class VpnProps with _$VpnProps { const factory VpnProps({ @@ -136,6 +146,7 @@ class VpnProps with _$VpnProps { @Default(true) bool systemProxy, @Default(false) bool ipv6, @Default(true) bool allowBypass, + @Default(defaultAccessControl) AccessControl accessControl, }) = _VpnProps; factory VpnProps.fromJson(Map? json) => @@ -147,14 +158,13 @@ class NetworkProps with _$NetworkProps { const factory NetworkProps({ @Default(true) bool systemProxy, @Default(defaultBypassDomain) List bypassDomain, + @Default(RouteMode.bypassPrivate) RouteMode routeMode, }) = _NetworkProps; factory NetworkProps.fromJson(Map? json) => json == null ? const NetworkProps() : _$NetworkPropsFromJson(json); } -const defaultProxiesStyle = ProxiesStyle(); - @freezed class ProxiesStyle with _$ProxiesStyle { const factory ProxiesStyle({ @@ -170,15 +180,6 @@ class ProxiesStyle with _$ProxiesStyle { json == null ? defaultProxiesStyle : _$ProxiesStyleFromJson(json); } -final defaultThemeProps = Platform.isWindows - ? const ThemeProps().copyWith( - fontFamily: FontFamily.miSans, - primaryColor: defaultPrimaryColor.value, - ) - : const ThemeProps().copyWith( - primaryColor: defaultPrimaryColor.value, - ); - @freezed class ThemeProps with _$ThemeProps { const factory ThemeProps({ @@ -191,7 +192,7 @@ class ThemeProps with _$ThemeProps { factory ThemeProps.fromJson(Map json) => _$ThemePropsFromJson(json); - factory ThemeProps.realFromJson(Map? json) { + factory ThemeProps.safeFromJson(Map? json) { if (json == null) { return defaultThemeProps; } @@ -203,316 +204,45 @@ class ThemeProps with _$ThemeProps { } } -@JsonSerializable() -class Config extends ChangeNotifier { - AppSetting _appSetting; - List _profiles; - String? _currentProfileId; - bool _isAccessControl; - AccessControl _accessControl; - DAV? _dav; - WindowProps _windowProps; - ThemeProps _themeProps; - VpnProps _vpnProps; - NetworkProps _networkProps; - bool _overrideDns; - List _hotKeyActions; - ProxiesStyle _proxiesStyle; +@freezed +class Config with _$Config { + const factory Config({ + @JsonKey(fromJson: AppSettingProps.safeFromJson) + @Default(defaultAppSettingProps) + AppSettingProps appSetting, + @Default([]) List profiles, + @Default([]) List hotKeyActions, + String? currentProfileId, + @Default(false) bool overrideDns, + DAV? dav, + @Default(defaultNetworkProps) NetworkProps networkProps, + @Default(defaultVpnProps) VpnProps vpnProps, + @JsonKey(fromJson: ThemeProps.safeFromJson) required ThemeProps themeProps, + @Default(defaultProxiesStyle) ProxiesStyle proxiesStyle, + @Default(defaultWindowProps) WindowProps windowProps, + @Default(defaultClashConfig) ClashConfig patchClashConfig, + }) = _Config; - Config() - : _profiles = [], - _isAccessControl = false, - _accessControl = const AccessControl(), - _windowProps = const WindowProps(), - _vpnProps = defaultVpnProps, - _networkProps = const NetworkProps(), - _overrideDns = false, - _appSetting = defaultAppSetting, - _hotKeyActions = [], - _proxiesStyle = defaultProxiesStyle, - _themeProps = defaultThemeProps; + factory Config.fromJson(Map json) => _$ConfigFromJson(json); - @JsonKey(fromJson: AppSetting.realFromJson) - AppSetting get appSetting => _appSetting; - - set appSetting(AppSetting value) { - if (_appSetting != value) { - _appSetting = value; - notifyListeners(); - } - } - - deleteProfileById(String id) { - _profiles = profiles.where((element) => element.id != id).toList(); - notifyListeners(); - } - - Profile? getCurrentProfileForId(String? value) { - if (value == null) { - return null; - } - return _profiles.firstWhere((element) => element.id == value); - } - - Profile? getCurrentProfile() { - return getCurrentProfileForId(_currentProfileId); - } - - String? _getLabel(String? label, String id) { - final realLabel = label ?? id; - final hasDup = _profiles.indexWhere( - (element) => element.label == realLabel && element.id != id) != - -1; - if (hasDup) { - return _getLabel(other.getOverwriteLabel(realLabel), id); - } else { - return label; - } - } - - _setProfile(Profile profile) { - final List profilesTemp = List.from(_profiles); - final index = - profilesTemp.indexWhere((element) => element.id == profile.id); - final updateProfile = profile.copyWith( - label: _getLabel(profile.label, profile.id), - ); - if (index == -1) { - profilesTemp.add(updateProfile); - } else { - profilesTemp[index] = updateProfile; - } - _profiles = profilesTemp; - } - - setProfile(Profile profile) { - _setProfile(profile); - notifyListeners(); - } - - @JsonKey(defaultValue: []) - List get profiles => _profiles; - - set profiles(List value) { - if (_profiles != value) { - _profiles = value; - notifyListeners(); - } - } - - String? get currentProfileId => _currentProfileId; - - set currentProfileId(String? value) { - if (_currentProfileId != value) { - _currentProfileId = value; - notifyListeners(); - } - } - - Profile? get currentProfile { - final index = - profiles.indexWhere((profile) => profile.id == _currentProfileId); - return index == -1 ? null : profiles[index]; - } - - String? get currentGroupName => currentProfile?.currentGroupName; - - Set get currentUnfoldSet => currentProfile?.unfoldSet ?? {}; - - updateCurrentUnfoldSet(Set value) { - if (!stringSetEquality.equals(currentUnfoldSet, value)) { - _setProfile( - currentProfile!.copyWith( - unfoldSet: value, - ), - ); - notifyListeners(); - } - } - - updateCurrentGroupName(String groupName) { - if (currentProfile != null && - currentProfile!.currentGroupName != groupName) { - _setProfile( - currentProfile!.copyWith( - currentGroupName: groupName, - ), - ); - notifyListeners(); - } - } - - SelectedMap get currentSelectedMap { - return currentProfile?.selectedMap ?? {}; - } - - updateCurrentSelectedMap(String groupName, String proxyName) { - if (currentProfile != null && - currentProfile!.selectedMap[groupName] != proxyName) { - final SelectedMap selectedMap = Map.from( - currentProfile?.selectedMap ?? {}, - )..[groupName] = proxyName; - _setProfile( - currentProfile!.copyWith( - selectedMap: selectedMap, - ), - ); - notifyListeners(); - } - } - - @JsonKey(defaultValue: false) - bool get isAccessControl { - if (!Platform.isAndroid) return false; - return _isAccessControl; - } - - set isAccessControl(bool value) { - if (_isAccessControl != value) { - _isAccessControl = value; - notifyListeners(); - } - } - - AccessControl get accessControl => _accessControl; - - set accessControl(AccessControl value) { - if (_accessControl != value) { - _accessControl = value; - notifyListeners(); - } - } - - DAV? get dav => _dav; - - set dav(DAV? value) { - if (_dav != value) { - _dav = value; - notifyListeners(); - } - } - - WindowProps get windowProps => _windowProps; - - set windowProps(WindowProps value) { - if (_windowProps != value) { - _windowProps = value; - notifyListeners(); - } - } - - VpnProps get vpnProps => _vpnProps; - - set vpnProps(VpnProps value) { - if (_vpnProps != value) { - _vpnProps = value; - notifyListeners(); - } - } - - NetworkProps get networkProps => _networkProps; - - set networkProps(NetworkProps value) { - if (_networkProps != value) { - _networkProps = value; - notifyListeners(); - } - } - - @JsonKey(defaultValue: false) - bool get overrideDns => _overrideDns; - - set overrideDns(bool value) { - if (_overrideDns != value) { - _overrideDns = value; - notifyListeners(); - } - } - - @JsonKey(defaultValue: []) - List get hotKeyActions => _hotKeyActions; - - set hotKeyActions(List value) { - if (_hotKeyActions != value) { - _hotKeyActions = value; - notifyListeners(); - } - } - - ProxiesStyle get proxiesStyle => _proxiesStyle; - - set proxiesStyle(ProxiesStyle value) { - if (_proxiesStyle != value || - !stringAndStringMapEntryIterableEquality.equals( - _proxiesStyle.iconMap.entries, - value.iconMap.entries, - )) { - _proxiesStyle = value; - notifyListeners(); - } - } - - @JsonKey(fromJson: ThemeProps.realFromJson) - ThemeProps get themeProps => _themeProps; - - set themeProps(ThemeProps value) { - if (_themeProps != value) { - _themeProps = value; - notifyListeners(); - } - } - - updateOrAddHotKeyAction(HotKeyAction hotKeyAction) { - final index = - _hotKeyActions.indexWhere((item) => item.action == hotKeyAction.action); - if (index == -1) { - _hotKeyActions = List.from(_hotKeyActions)..add(hotKeyAction); - } else { - _hotKeyActions = List.from(_hotKeyActions)..[index] = hotKeyAction; - } - notifyListeners(); - } - - update([ - Config? config, - RecoveryOption recoveryOptions = RecoveryOption.all, - ]) { - if (config != null) { - _profiles = config._profiles; - for (final profile in config._profiles) { - _setProfile(profile); + factory Config.compatibleFromJson(Map json) { + try { + final accessControlMap = json["accessControl"]; + final isAccessControl = json["isAccessControl"]; + if (accessControlMap != null) { + (accessControlMap as Map)["enable"] = isAccessControl; + if (json["vpnProps"] != null) { + (json["vpnProps"] as Map)["accessControl"] = accessControlMap; + } } - final onlyProfiles = recoveryOptions == RecoveryOption.onlyProfiles; - if (_currentProfileId == null && onlyProfiles && profiles.isNotEmpty) { - _currentProfileId = _profiles.first.id; - } - if (onlyProfiles) return; - _appSetting = config._appSetting; - _currentProfileId = config._currentProfileId; - _dav = config._dav; - _isAccessControl = config._isAccessControl; - _accessControl = config._accessControl; - _themeProps = config._themeProps; - _windowProps = config._windowProps; - _proxiesStyle = config._proxiesStyle; - _vpnProps = config._vpnProps; - _overrideDns = config._overrideDns; - _networkProps = config._networkProps; - _hotKeyActions = config._hotKeyActions; - } - notifyListeners(); - } - - Map toJson() { - return _$ConfigToJson(this); - } - - factory Config.fromJson(Map json) { - return _$ConfigFromJson(json); - } - - @override - String toString() { - return 'Config{_appSetting: $_appSetting, _profiles: $_profiles, _currentProfileId: $_currentProfileId, _isAccessControl: $_isAccessControl, _accessControl: $_accessControl, _dav: $_dav, _windowProps: $_windowProps, _themeProps: $_themeProps, _vpnProps: $_vpnProps, _networkProps: $_networkProps, _overrideDns: $_overrideDns, _hotKeyActions: $_hotKeyActions, _proxiesStyle: $_proxiesStyle}'; + } catch (_) {} + return Config.fromJson(json); } } + +extension ConfigExt on Config { + Profile? get currentProfile { + return profiles.getProfile(currentProfileId); + } + +} diff --git a/lib/models/core.dart b/lib/models/core.dart index 7073db1..8d9319b 100644 --- a/lib/models/core.dart +++ b/lib/models/core.dart @@ -1,6 +1,5 @@ // ignore_for_file: invalid_annotation_target - import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/models/models.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -28,14 +27,10 @@ abstract mixin class ServiceMessageListener { @freezed class CoreState with _$CoreState { const factory CoreState({ - required bool enable, - AccessControl? accessControl, - required String currentProfileName, - required bool allowBypass, - required bool systemProxy, - required List bypassDomain, - required List routeAddress, - required bool ipv6, + @JsonKey(name: "vpn-props") required VpnProps vpnProps, + @JsonKey(name: "only-statistics-proxy") required bool onlyStatisticsProxy, + @JsonKey(name: "current-profile-name") required String currentProfileName, + @JsonKey(name: "bypass-domain") @Default([]) List bypassDomain, }) = _CoreState; factory CoreState.fromJson(Map json) => @@ -53,7 +48,7 @@ class AndroidVpnOptions with _$AndroidVpnOptions { required List bypassDomain, required String ipv4Address, required String ipv6Address, - required List routeAddress, + @Default([]) List routeAddress, required String dnsServerAddress, }) = _AndroidVpnOptions; @@ -65,11 +60,9 @@ class AndroidVpnOptions with _$AndroidVpnOptions { class ConfigExtendedParams with _$ConfigExtendedParams { const factory ConfigExtendedParams({ @JsonKey(name: "is-patch") required bool isPatch, - @JsonKey(name: "is-compatible") required bool isCompatible, @JsonKey(name: "selected-map") required SelectedMap selectedMap, @JsonKey(name: "override-dns") required bool overrideDns, @JsonKey(name: "test-url") required String testUrl, - @JsonKey(name: "only-statistics-proxy") required bool onlyStatisticsProxy, }) = _ConfigExtendedParams; factory ConfigExtendedParams.fromJson(Map json) => diff --git a/lib/models/generated/app.freezed.dart b/lib/models/generated/app.freezed.dart new file mode 100644 index 0000000..b8b94b7 --- /dev/null +++ b/lib/models/generated/app.freezed.dart @@ -0,0 +1,567 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of '../app.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$AppState { + bool get isInit => throw _privateConstructorUsedError; + PageLabel get pageLabel => throw _privateConstructorUsedError; + List get packages => throw _privateConstructorUsedError; + ColorSchemes get colorSchemes => throw _privateConstructorUsedError; + int get sortNum => throw _privateConstructorUsedError; + double get viewWidth => throw _privateConstructorUsedError; + Map> get delayMap => + throw _privateConstructorUsedError; + List get groups => throw _privateConstructorUsedError; + int get checkIpNum => throw _privateConstructorUsedError; + Brightness? get brightness => throw _privateConstructorUsedError; + int? get runTime => throw _privateConstructorUsedError; + List get providers => throw _privateConstructorUsedError; + String? get localIp => throw _privateConstructorUsedError; + FixedList get requests => throw _privateConstructorUsedError; + int get version => throw _privateConstructorUsedError; + FixedList get logs => throw _privateConstructorUsedError; + FixedList get traffics => throw _privateConstructorUsedError; + Traffic get totalTraffic => throw _privateConstructorUsedError; + + /// Create a copy of AppState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $AppStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AppStateCopyWith<$Res> { + factory $AppStateCopyWith(AppState value, $Res Function(AppState) then) = + _$AppStateCopyWithImpl<$Res, AppState>; + @useResult + $Res call( + {bool isInit, + PageLabel pageLabel, + List packages, + ColorSchemes colorSchemes, + int sortNum, + double viewWidth, + Map> delayMap, + List groups, + int checkIpNum, + Brightness? brightness, + int? runTime, + List providers, + String? localIp, + FixedList requests, + int version, + FixedList logs, + FixedList traffics, + Traffic totalTraffic}); + + $ColorSchemesCopyWith<$Res> get colorSchemes; +} + +/// @nodoc +class _$AppStateCopyWithImpl<$Res, $Val extends AppState> + implements $AppStateCopyWith<$Res> { + _$AppStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of AppState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? isInit = null, + Object? pageLabel = null, + Object? packages = null, + Object? colorSchemes = null, + Object? sortNum = null, + Object? viewWidth = null, + Object? delayMap = null, + Object? groups = null, + Object? checkIpNum = null, + Object? brightness = freezed, + Object? runTime = freezed, + Object? providers = null, + Object? localIp = freezed, + Object? requests = null, + Object? version = null, + Object? logs = null, + Object? traffics = null, + Object? totalTraffic = null, + }) { + return _then(_value.copyWith( + isInit: null == isInit + ? _value.isInit + : isInit // ignore: cast_nullable_to_non_nullable + as bool, + pageLabel: null == pageLabel + ? _value.pageLabel + : pageLabel // ignore: cast_nullable_to_non_nullable + as PageLabel, + packages: null == packages + ? _value.packages + : packages // ignore: cast_nullable_to_non_nullable + as List, + colorSchemes: null == colorSchemes + ? _value.colorSchemes + : colorSchemes // ignore: cast_nullable_to_non_nullable + as ColorSchemes, + sortNum: null == sortNum + ? _value.sortNum + : sortNum // ignore: cast_nullable_to_non_nullable + as int, + viewWidth: null == viewWidth + ? _value.viewWidth + : viewWidth // ignore: cast_nullable_to_non_nullable + as double, + delayMap: null == delayMap + ? _value.delayMap + : delayMap // ignore: cast_nullable_to_non_nullable + as Map>, + groups: null == groups + ? _value.groups + : groups // ignore: cast_nullable_to_non_nullable + as List, + checkIpNum: null == checkIpNum + ? _value.checkIpNum + : checkIpNum // ignore: cast_nullable_to_non_nullable + as int, + brightness: freezed == brightness + ? _value.brightness + : brightness // ignore: cast_nullable_to_non_nullable + as Brightness?, + runTime: freezed == runTime + ? _value.runTime + : runTime // ignore: cast_nullable_to_non_nullable + as int?, + providers: null == providers + ? _value.providers + : providers // ignore: cast_nullable_to_non_nullable + as List, + localIp: freezed == localIp + ? _value.localIp + : localIp // ignore: cast_nullable_to_non_nullable + as String?, + requests: null == requests + ? _value.requests + : requests // ignore: cast_nullable_to_non_nullable + as FixedList, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as int, + logs: null == logs + ? _value.logs + : logs // ignore: cast_nullable_to_non_nullable + as FixedList, + traffics: null == traffics + ? _value.traffics + : traffics // ignore: cast_nullable_to_non_nullable + as FixedList, + totalTraffic: null == totalTraffic + ? _value.totalTraffic + : totalTraffic // ignore: cast_nullable_to_non_nullable + as Traffic, + ) as $Val); + } + + /// Create a copy of AppState + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $ColorSchemesCopyWith<$Res> get colorSchemes { + return $ColorSchemesCopyWith<$Res>(_value.colorSchemes, (value) { + return _then(_value.copyWith(colorSchemes: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$AppStateImplCopyWith<$Res> + implements $AppStateCopyWith<$Res> { + factory _$$AppStateImplCopyWith( + _$AppStateImpl value, $Res Function(_$AppStateImpl) then) = + __$$AppStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {bool isInit, + PageLabel pageLabel, + List packages, + ColorSchemes colorSchemes, + int sortNum, + double viewWidth, + Map> delayMap, + List groups, + int checkIpNum, + Brightness? brightness, + int? runTime, + List providers, + String? localIp, + FixedList requests, + int version, + FixedList logs, + FixedList traffics, + Traffic totalTraffic}); + + @override + $ColorSchemesCopyWith<$Res> get colorSchemes; +} + +/// @nodoc +class __$$AppStateImplCopyWithImpl<$Res> + extends _$AppStateCopyWithImpl<$Res, _$AppStateImpl> + implements _$$AppStateImplCopyWith<$Res> { + __$$AppStateImplCopyWithImpl( + _$AppStateImpl _value, $Res Function(_$AppStateImpl) _then) + : super(_value, _then); + + /// Create a copy of AppState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? isInit = null, + Object? pageLabel = null, + Object? packages = null, + Object? colorSchemes = null, + Object? sortNum = null, + Object? viewWidth = null, + Object? delayMap = null, + Object? groups = null, + Object? checkIpNum = null, + Object? brightness = freezed, + Object? runTime = freezed, + Object? providers = null, + Object? localIp = freezed, + Object? requests = null, + Object? version = null, + Object? logs = null, + Object? traffics = null, + Object? totalTraffic = null, + }) { + return _then(_$AppStateImpl( + isInit: null == isInit + ? _value.isInit + : isInit // ignore: cast_nullable_to_non_nullable + as bool, + pageLabel: null == pageLabel + ? _value.pageLabel + : pageLabel // ignore: cast_nullable_to_non_nullable + as PageLabel, + packages: null == packages + ? _value._packages + : packages // ignore: cast_nullable_to_non_nullable + as List, + colorSchemes: null == colorSchemes + ? _value.colorSchemes + : colorSchemes // ignore: cast_nullable_to_non_nullable + as ColorSchemes, + sortNum: null == sortNum + ? _value.sortNum + : sortNum // ignore: cast_nullable_to_non_nullable + as int, + viewWidth: null == viewWidth + ? _value.viewWidth + : viewWidth // ignore: cast_nullable_to_non_nullable + as double, + delayMap: null == delayMap + ? _value._delayMap + : delayMap // ignore: cast_nullable_to_non_nullable + as Map>, + groups: null == groups + ? _value._groups + : groups // ignore: cast_nullable_to_non_nullable + as List, + checkIpNum: null == checkIpNum + ? _value.checkIpNum + : checkIpNum // ignore: cast_nullable_to_non_nullable + as int, + brightness: freezed == brightness + ? _value.brightness + : brightness // ignore: cast_nullable_to_non_nullable + as Brightness?, + runTime: freezed == runTime + ? _value.runTime + : runTime // ignore: cast_nullable_to_non_nullable + as int?, + providers: null == providers + ? _value._providers + : providers // ignore: cast_nullable_to_non_nullable + as List, + localIp: freezed == localIp + ? _value.localIp + : localIp // ignore: cast_nullable_to_non_nullable + as String?, + requests: null == requests + ? _value.requests + : requests // ignore: cast_nullable_to_non_nullable + as FixedList, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as int, + logs: null == logs + ? _value.logs + : logs // ignore: cast_nullable_to_non_nullable + as FixedList, + traffics: null == traffics + ? _value.traffics + : traffics // ignore: cast_nullable_to_non_nullable + as FixedList, + totalTraffic: null == totalTraffic + ? _value.totalTraffic + : totalTraffic // ignore: cast_nullable_to_non_nullable + as Traffic, + )); + } +} + +/// @nodoc + +class _$AppStateImpl implements _AppState { + const _$AppStateImpl( + {this.isInit = false, + this.pageLabel = PageLabel.dashboard, + final List packages = const [], + this.colorSchemes = const ColorSchemes(), + this.sortNum = 0, + required this.viewWidth, + final Map> delayMap = const {}, + final List groups = const [], + this.checkIpNum = 0, + this.brightness, + this.runTime, + final List providers = const [], + this.localIp, + required this.requests, + required this.version, + required this.logs, + required this.traffics, + required this.totalTraffic}) + : _packages = packages, + _delayMap = delayMap, + _groups = groups, + _providers = providers; + + @override + @JsonKey() + final bool isInit; + @override + @JsonKey() + final PageLabel pageLabel; + final List _packages; + @override + @JsonKey() + List get packages { + if (_packages is EqualUnmodifiableListView) return _packages; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_packages); + } + + @override + @JsonKey() + final ColorSchemes colorSchemes; + @override + @JsonKey() + final int sortNum; + @override + final double viewWidth; + final Map> _delayMap; + @override + @JsonKey() + Map> get delayMap { + if (_delayMap is EqualUnmodifiableMapView) return _delayMap; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_delayMap); + } + + final List _groups; + @override + @JsonKey() + List get groups { + if (_groups is EqualUnmodifiableListView) return _groups; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_groups); + } + + @override + @JsonKey() + final int checkIpNum; + @override + final Brightness? brightness; + @override + final int? runTime; + final List _providers; + @override + @JsonKey() + List get providers { + if (_providers is EqualUnmodifiableListView) return _providers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_providers); + } + + @override + final String? localIp; + @override + final FixedList requests; + @override + final int version; + @override + final FixedList logs; + @override + final FixedList traffics; + @override + final Traffic totalTraffic; + + @override + String toString() { + return 'AppState(isInit: $isInit, pageLabel: $pageLabel, packages: $packages, colorSchemes: $colorSchemes, sortNum: $sortNum, viewWidth: $viewWidth, delayMap: $delayMap, groups: $groups, checkIpNum: $checkIpNum, brightness: $brightness, runTime: $runTime, providers: $providers, localIp: $localIp, requests: $requests, version: $version, logs: $logs, traffics: $traffics, totalTraffic: $totalTraffic)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AppStateImpl && + (identical(other.isInit, isInit) || other.isInit == isInit) && + (identical(other.pageLabel, pageLabel) || + other.pageLabel == pageLabel) && + const DeepCollectionEquality().equals(other._packages, _packages) && + (identical(other.colorSchemes, colorSchemes) || + other.colorSchemes == colorSchemes) && + (identical(other.sortNum, sortNum) || other.sortNum == sortNum) && + (identical(other.viewWidth, viewWidth) || + other.viewWidth == viewWidth) && + const DeepCollectionEquality().equals(other._delayMap, _delayMap) && + const DeepCollectionEquality().equals(other._groups, _groups) && + (identical(other.checkIpNum, checkIpNum) || + other.checkIpNum == checkIpNum) && + (identical(other.brightness, brightness) || + other.brightness == brightness) && + (identical(other.runTime, runTime) || other.runTime == runTime) && + const DeepCollectionEquality() + .equals(other._providers, _providers) && + (identical(other.localIp, localIp) || other.localIp == localIp) && + (identical(other.requests, requests) || + other.requests == requests) && + (identical(other.version, version) || other.version == version) && + (identical(other.logs, logs) || other.logs == logs) && + (identical(other.traffics, traffics) || + other.traffics == traffics) && + (identical(other.totalTraffic, totalTraffic) || + other.totalTraffic == totalTraffic)); + } + + @override + int get hashCode => Object.hash( + runtimeType, + isInit, + pageLabel, + const DeepCollectionEquality().hash(_packages), + colorSchemes, + sortNum, + viewWidth, + const DeepCollectionEquality().hash(_delayMap), + const DeepCollectionEquality().hash(_groups), + checkIpNum, + brightness, + runTime, + const DeepCollectionEquality().hash(_providers), + localIp, + requests, + version, + logs, + traffics, + totalTraffic); + + /// Create a copy of AppState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$AppStateImplCopyWith<_$AppStateImpl> get copyWith => + __$$AppStateImplCopyWithImpl<_$AppStateImpl>(this, _$identity); +} + +abstract class _AppState implements AppState { + const factory _AppState( + {final bool isInit, + final PageLabel pageLabel, + final List packages, + final ColorSchemes colorSchemes, + final int sortNum, + required final double viewWidth, + final Map> delayMap, + final List groups, + final int checkIpNum, + final Brightness? brightness, + final int? runTime, + final List providers, + final String? localIp, + required final FixedList requests, + required final int version, + required final FixedList logs, + required final FixedList traffics, + required final Traffic totalTraffic}) = _$AppStateImpl; + + @override + bool get isInit; + @override + PageLabel get pageLabel; + @override + List get packages; + @override + ColorSchemes get colorSchemes; + @override + int get sortNum; + @override + double get viewWidth; + @override + Map> get delayMap; + @override + List get groups; + @override + int get checkIpNum; + @override + Brightness? get brightness; + @override + int? get runTime; + @override + List get providers; + @override + String? get localIp; + @override + FixedList get requests; + @override + int get version; + @override + FixedList get logs; + @override + FixedList get traffics; + @override + Traffic get totalTraffic; + + /// Create a copy of AppState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$AppStateImplCopyWith<_$AppStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/generated/clash_config.freezed.dart b/lib/models/generated/clash_config.freezed.dart index 118ba50..67db5f3 100644 --- a/lib/models/generated/clash_config.freezed.dart +++ b/lib/models/generated/clash_config.freezed.dart @@ -14,6 +14,494 @@ T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); +ProxyGroup _$ProxyGroupFromJson(Map json) { + return _ProxyGroup.fromJson(json); +} + +/// @nodoc +mixin _$ProxyGroup { + String get name => throw _privateConstructorUsedError; + @JsonKey(fromJson: GroupType.parseProfileType) + GroupType get type => throw _privateConstructorUsedError; + List? get proxies => throw _privateConstructorUsedError; + List? get use => throw _privateConstructorUsedError; + int? get interval => throw _privateConstructorUsedError; + bool? get lazy => throw _privateConstructorUsedError; + String? get url => throw _privateConstructorUsedError; + int? get timeout => throw _privateConstructorUsedError; + @JsonKey(name: "max-failed-times") + int? get maxFailedTimes => throw _privateConstructorUsedError; + String? get filter => throw _privateConstructorUsedError; + @JsonKey(name: "expected-filter") + String? get excludeFilter => throw _privateConstructorUsedError; + @JsonKey(name: "exclude-type") + String? get excludeType => throw _privateConstructorUsedError; + @JsonKey(name: "expected-status") + int? get expectedStatus => throw _privateConstructorUsedError; + bool? get hidden => throw _privateConstructorUsedError; + String? get icon => throw _privateConstructorUsedError; + + /// Serializes this ProxyGroup to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ProxyGroup + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ProxyGroupCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ProxyGroupCopyWith<$Res> { + factory $ProxyGroupCopyWith( + ProxyGroup value, $Res Function(ProxyGroup) then) = + _$ProxyGroupCopyWithImpl<$Res, ProxyGroup>; + @useResult + $Res call( + {String name, + @JsonKey(fromJson: GroupType.parseProfileType) GroupType type, + List? proxies, + List? use, + int? interval, + bool? lazy, + String? url, + int? timeout, + @JsonKey(name: "max-failed-times") int? maxFailedTimes, + String? filter, + @JsonKey(name: "expected-filter") String? excludeFilter, + @JsonKey(name: "exclude-type") String? excludeType, + @JsonKey(name: "expected-status") int? expectedStatus, + bool? hidden, + String? icon}); +} + +/// @nodoc +class _$ProxyGroupCopyWithImpl<$Res, $Val extends ProxyGroup> + implements $ProxyGroupCopyWith<$Res> { + _$ProxyGroupCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ProxyGroup + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? type = null, + Object? proxies = freezed, + Object? use = freezed, + Object? interval = freezed, + Object? lazy = freezed, + Object? url = freezed, + Object? timeout = freezed, + Object? maxFailedTimes = freezed, + Object? filter = freezed, + Object? excludeFilter = freezed, + Object? excludeType = freezed, + Object? expectedStatus = freezed, + Object? hidden = freezed, + Object? icon = freezed, + }) { + return _then(_value.copyWith( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as GroupType, + proxies: freezed == proxies + ? _value.proxies + : proxies // ignore: cast_nullable_to_non_nullable + as List?, + use: freezed == use + ? _value.use + : use // ignore: cast_nullable_to_non_nullable + as List?, + interval: freezed == interval + ? _value.interval + : interval // ignore: cast_nullable_to_non_nullable + as int?, + lazy: freezed == lazy + ? _value.lazy + : lazy // ignore: cast_nullable_to_non_nullable + as bool?, + url: freezed == url + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String?, + timeout: freezed == timeout + ? _value.timeout + : timeout // ignore: cast_nullable_to_non_nullable + as int?, + maxFailedTimes: freezed == maxFailedTimes + ? _value.maxFailedTimes + : maxFailedTimes // ignore: cast_nullable_to_non_nullable + as int?, + filter: freezed == filter + ? _value.filter + : filter // ignore: cast_nullable_to_non_nullable + as String?, + excludeFilter: freezed == excludeFilter + ? _value.excludeFilter + : excludeFilter // ignore: cast_nullable_to_non_nullable + as String?, + excludeType: freezed == excludeType + ? _value.excludeType + : excludeType // ignore: cast_nullable_to_non_nullable + as String?, + expectedStatus: freezed == expectedStatus + ? _value.expectedStatus + : expectedStatus // ignore: cast_nullable_to_non_nullable + as int?, + hidden: freezed == hidden + ? _value.hidden + : hidden // ignore: cast_nullable_to_non_nullable + as bool?, + icon: freezed == icon + ? _value.icon + : icon // ignore: cast_nullable_to_non_nullable + as String?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ProxyGroupImplCopyWith<$Res> + implements $ProxyGroupCopyWith<$Res> { + factory _$$ProxyGroupImplCopyWith( + _$ProxyGroupImpl value, $Res Function(_$ProxyGroupImpl) then) = + __$$ProxyGroupImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String name, + @JsonKey(fromJson: GroupType.parseProfileType) GroupType type, + List? proxies, + List? use, + int? interval, + bool? lazy, + String? url, + int? timeout, + @JsonKey(name: "max-failed-times") int? maxFailedTimes, + String? filter, + @JsonKey(name: "expected-filter") String? excludeFilter, + @JsonKey(name: "exclude-type") String? excludeType, + @JsonKey(name: "expected-status") int? expectedStatus, + bool? hidden, + String? icon}); +} + +/// @nodoc +class __$$ProxyGroupImplCopyWithImpl<$Res> + extends _$ProxyGroupCopyWithImpl<$Res, _$ProxyGroupImpl> + implements _$$ProxyGroupImplCopyWith<$Res> { + __$$ProxyGroupImplCopyWithImpl( + _$ProxyGroupImpl _value, $Res Function(_$ProxyGroupImpl) _then) + : super(_value, _then); + + /// Create a copy of ProxyGroup + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? type = null, + Object? proxies = freezed, + Object? use = freezed, + Object? interval = freezed, + Object? lazy = freezed, + Object? url = freezed, + Object? timeout = freezed, + Object? maxFailedTimes = freezed, + Object? filter = freezed, + Object? excludeFilter = freezed, + Object? excludeType = freezed, + Object? expectedStatus = freezed, + Object? hidden = freezed, + Object? icon = freezed, + }) { + return _then(_$ProxyGroupImpl( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as GroupType, + proxies: freezed == proxies + ? _value._proxies + : proxies // ignore: cast_nullable_to_non_nullable + as List?, + use: freezed == use + ? _value._use + : use // ignore: cast_nullable_to_non_nullable + as List?, + interval: freezed == interval + ? _value.interval + : interval // ignore: cast_nullable_to_non_nullable + as int?, + lazy: freezed == lazy + ? _value.lazy + : lazy // ignore: cast_nullable_to_non_nullable + as bool?, + url: freezed == url + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String?, + timeout: freezed == timeout + ? _value.timeout + : timeout // ignore: cast_nullable_to_non_nullable + as int?, + maxFailedTimes: freezed == maxFailedTimes + ? _value.maxFailedTimes + : maxFailedTimes // ignore: cast_nullable_to_non_nullable + as int?, + filter: freezed == filter + ? _value.filter + : filter // ignore: cast_nullable_to_non_nullable + as String?, + excludeFilter: freezed == excludeFilter + ? _value.excludeFilter + : excludeFilter // ignore: cast_nullable_to_non_nullable + as String?, + excludeType: freezed == excludeType + ? _value.excludeType + : excludeType // ignore: cast_nullable_to_non_nullable + as String?, + expectedStatus: freezed == expectedStatus + ? _value.expectedStatus + : expectedStatus // ignore: cast_nullable_to_non_nullable + as int?, + hidden: freezed == hidden + ? _value.hidden + : hidden // ignore: cast_nullable_to_non_nullable + as bool?, + icon: freezed == icon + ? _value.icon + : icon // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ProxyGroupImpl implements _ProxyGroup { + const _$ProxyGroupImpl( + {required this.name, + @JsonKey(fromJson: GroupType.parseProfileType) required this.type, + final List? proxies, + final List? use, + this.interval, + this.lazy, + this.url, + this.timeout, + @JsonKey(name: "max-failed-times") this.maxFailedTimes, + this.filter, + @JsonKey(name: "expected-filter") this.excludeFilter, + @JsonKey(name: "exclude-type") this.excludeType, + @JsonKey(name: "expected-status") this.expectedStatus, + this.hidden, + this.icon}) + : _proxies = proxies, + _use = use; + + factory _$ProxyGroupImpl.fromJson(Map json) => + _$$ProxyGroupImplFromJson(json); + + @override + final String name; + @override + @JsonKey(fromJson: GroupType.parseProfileType) + final GroupType type; + final List? _proxies; + @override + List? get proxies { + final value = _proxies; + if (value == null) return null; + if (_proxies is EqualUnmodifiableListView) return _proxies; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + final List? _use; + @override + List? get use { + final value = _use; + if (value == null) return null; + if (_use is EqualUnmodifiableListView) return _use; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + + @override + final int? interval; + @override + final bool? lazy; + @override + final String? url; + @override + final int? timeout; + @override + @JsonKey(name: "max-failed-times") + final int? maxFailedTimes; + @override + final String? filter; + @override + @JsonKey(name: "expected-filter") + final String? excludeFilter; + @override + @JsonKey(name: "exclude-type") + final String? excludeType; + @override + @JsonKey(name: "expected-status") + final int? expectedStatus; + @override + final bool? hidden; + @override + final String? icon; + + @override + String toString() { + return 'ProxyGroup(name: $name, type: $type, proxies: $proxies, use: $use, interval: $interval, lazy: $lazy, url: $url, timeout: $timeout, maxFailedTimes: $maxFailedTimes, filter: $filter, excludeFilter: $excludeFilter, excludeType: $excludeType, expectedStatus: $expectedStatus, hidden: $hidden, icon: $icon)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProxyGroupImpl && + (identical(other.name, name) || other.name == name) && + (identical(other.type, type) || other.type == type) && + const DeepCollectionEquality().equals(other._proxies, _proxies) && + const DeepCollectionEquality().equals(other._use, _use) && + (identical(other.interval, interval) || + other.interval == interval) && + (identical(other.lazy, lazy) || other.lazy == lazy) && + (identical(other.url, url) || other.url == url) && + (identical(other.timeout, timeout) || other.timeout == timeout) && + (identical(other.maxFailedTimes, maxFailedTimes) || + other.maxFailedTimes == maxFailedTimes) && + (identical(other.filter, filter) || other.filter == filter) && + (identical(other.excludeFilter, excludeFilter) || + other.excludeFilter == excludeFilter) && + (identical(other.excludeType, excludeType) || + other.excludeType == excludeType) && + (identical(other.expectedStatus, expectedStatus) || + other.expectedStatus == expectedStatus) && + (identical(other.hidden, hidden) || other.hidden == hidden) && + (identical(other.icon, icon) || other.icon == icon)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + name, + type, + const DeepCollectionEquality().hash(_proxies), + const DeepCollectionEquality().hash(_use), + interval, + lazy, + url, + timeout, + maxFailedTimes, + filter, + excludeFilter, + excludeType, + expectedStatus, + hidden, + icon); + + /// Create a copy of ProxyGroup + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ProxyGroupImplCopyWith<_$ProxyGroupImpl> get copyWith => + __$$ProxyGroupImplCopyWithImpl<_$ProxyGroupImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ProxyGroupImplToJson( + this, + ); + } +} + +abstract class _ProxyGroup implements ProxyGroup { + const factory _ProxyGroup( + {required final String name, + @JsonKey(fromJson: GroupType.parseProfileType) + required final GroupType type, + final List? proxies, + final List? use, + final int? interval, + final bool? lazy, + final String? url, + final int? timeout, + @JsonKey(name: "max-failed-times") final int? maxFailedTimes, + final String? filter, + @JsonKey(name: "expected-filter") final String? excludeFilter, + @JsonKey(name: "exclude-type") final String? excludeType, + @JsonKey(name: "expected-status") final int? expectedStatus, + final bool? hidden, + final String? icon}) = _$ProxyGroupImpl; + + factory _ProxyGroup.fromJson(Map json) = + _$ProxyGroupImpl.fromJson; + + @override + String get name; + @override + @JsonKey(fromJson: GroupType.parseProfileType) + GroupType get type; + @override + List? get proxies; + @override + List? get use; + @override + int? get interval; + @override + bool? get lazy; + @override + String? get url; + @override + int? get timeout; + @override + @JsonKey(name: "max-failed-times") + int? get maxFailedTimes; + @override + String? get filter; + @override + @JsonKey(name: "expected-filter") + String? get excludeFilter; + @override + @JsonKey(name: "exclude-type") + String? get excludeType; + @override + @JsonKey(name: "expected-status") + int? get expectedStatus; + @override + bool? get hidden; + @override + String? get icon; + + /// Create a copy of ProxyGroup + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ProxyGroupImplCopyWith<_$ProxyGroupImpl> get copyWith => + throw _privateConstructorUsedError; +} + Tun _$TunFromJson(Map json) { return _Tun.fromJson(json); } @@ -25,6 +513,8 @@ mixin _$Tun { TunStack get stack => throw _privateConstructorUsedError; @JsonKey(name: "dns-hijack") List get dnsHijack => throw _privateConstructorUsedError; + @JsonKey(name: "route-address") + List get routeAddress => throw _privateConstructorUsedError; /// Serializes this Tun to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -44,7 +534,8 @@ abstract class $TunCopyWith<$Res> { {bool enable, String device, TunStack stack, - @JsonKey(name: "dns-hijack") List dnsHijack}); + @JsonKey(name: "dns-hijack") List dnsHijack, + @JsonKey(name: "route-address") List routeAddress}); } /// @nodoc @@ -65,6 +556,7 @@ class _$TunCopyWithImpl<$Res, $Val extends Tun> implements $TunCopyWith<$Res> { Object? device = null, Object? stack = null, Object? dnsHijack = null, + Object? routeAddress = null, }) { return _then(_value.copyWith( enable: null == enable @@ -83,6 +575,10 @@ class _$TunCopyWithImpl<$Res, $Val extends Tun> implements $TunCopyWith<$Res> { ? _value.dnsHijack : dnsHijack // ignore: cast_nullable_to_non_nullable as List, + routeAddress: null == routeAddress + ? _value.routeAddress + : routeAddress // ignore: cast_nullable_to_non_nullable + as List, ) as $Val); } } @@ -97,7 +593,8 @@ abstract class _$$TunImplCopyWith<$Res> implements $TunCopyWith<$Res> { {bool enable, String device, TunStack stack, - @JsonKey(name: "dns-hijack") List dnsHijack}); + @JsonKey(name: "dns-hijack") List dnsHijack, + @JsonKey(name: "route-address") List routeAddress}); } /// @nodoc @@ -115,6 +612,7 @@ class __$$TunImplCopyWithImpl<$Res> extends _$TunCopyWithImpl<$Res, _$TunImpl> Object? device = null, Object? stack = null, Object? dnsHijack = null, + Object? routeAddress = null, }) { return _then(_$TunImpl( enable: null == enable @@ -133,6 +631,10 @@ class __$$TunImplCopyWithImpl<$Res> extends _$TunCopyWithImpl<$Res, _$TunImpl> ? _value._dnsHijack : dnsHijack // ignore: cast_nullable_to_non_nullable as List, + routeAddress: null == routeAddress + ? _value._routeAddress + : routeAddress // ignore: cast_nullable_to_non_nullable + as List, )); } } @@ -145,8 +647,11 @@ class _$TunImpl implements _Tun { this.device = appName, this.stack = TunStack.gvisor, @JsonKey(name: "dns-hijack") - final List dnsHijack = const ["any:53"]}) - : _dnsHijack = dnsHijack; + final List dnsHijack = const ["any:53"], + @JsonKey(name: "route-address") + final List routeAddress = const []}) + : _dnsHijack = dnsHijack, + _routeAddress = routeAddress; factory _$TunImpl.fromJson(Map json) => _$$TunImplFromJson(json); @@ -169,9 +674,18 @@ class _$TunImpl implements _Tun { return EqualUnmodifiableListView(_dnsHijack); } + final List _routeAddress; + @override + @JsonKey(name: "route-address") + List get routeAddress { + if (_routeAddress is EqualUnmodifiableListView) return _routeAddress; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_routeAddress); + } + @override String toString() { - return 'Tun(enable: $enable, device: $device, stack: $stack, dnsHijack: $dnsHijack)'; + return 'Tun(enable: $enable, device: $device, stack: $stack, dnsHijack: $dnsHijack, routeAddress: $routeAddress)'; } @override @@ -183,13 +697,20 @@ class _$TunImpl implements _Tun { (identical(other.device, device) || other.device == device) && (identical(other.stack, stack) || other.stack == stack) && const DeepCollectionEquality() - .equals(other._dnsHijack, _dnsHijack)); + .equals(other._dnsHijack, _dnsHijack) && + const DeepCollectionEquality() + .equals(other._routeAddress, _routeAddress)); } @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash(runtimeType, enable, device, stack, - const DeepCollectionEquality().hash(_dnsHijack)); + int get hashCode => Object.hash( + runtimeType, + enable, + device, + stack, + const DeepCollectionEquality().hash(_dnsHijack), + const DeepCollectionEquality().hash(_routeAddress)); /// Create a copy of Tun /// with the given fields replaced by the non-null parameter values. @@ -209,10 +730,12 @@ class _$TunImpl implements _Tun { abstract class _Tun implements Tun { const factory _Tun( - {final bool enable, - final String device, - final TunStack stack, - @JsonKey(name: "dns-hijack") final List dnsHijack}) = _$TunImpl; + {final bool enable, + final String device, + final TunStack stack, + @JsonKey(name: "dns-hijack") final List dnsHijack, + @JsonKey(name: "route-address") final List routeAddress}) = + _$TunImpl; factory _Tun.fromJson(Map json) = _$TunImpl.fromJson; @@ -225,6 +748,9 @@ abstract class _Tun implements Tun { @override @JsonKey(name: "dns-hijack") List get dnsHijack; + @override + @JsonKey(name: "route-address") + List get routeAddress; /// Create a copy of Tun /// with the given fields replaced by the non-null parameter values. @@ -1076,3 +1602,858 @@ abstract class _Dns implements Dns { _$$DnsImplCopyWith<_$DnsImpl> get copyWith => throw _privateConstructorUsedError; } + +GeoXUrl _$GeoXUrlFromJson(Map json) { + return _GeoXUrl.fromJson(json); +} + +/// @nodoc +mixin _$GeoXUrl { + String get mmdb => throw _privateConstructorUsedError; + String get asn => throw _privateConstructorUsedError; + String get geoip => throw _privateConstructorUsedError; + String get geosite => throw _privateConstructorUsedError; + + /// Serializes this GeoXUrl to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of GeoXUrl + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $GeoXUrlCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $GeoXUrlCopyWith<$Res> { + factory $GeoXUrlCopyWith(GeoXUrl value, $Res Function(GeoXUrl) then) = + _$GeoXUrlCopyWithImpl<$Res, GeoXUrl>; + @useResult + $Res call({String mmdb, String asn, String geoip, String geosite}); +} + +/// @nodoc +class _$GeoXUrlCopyWithImpl<$Res, $Val extends GeoXUrl> + implements $GeoXUrlCopyWith<$Res> { + _$GeoXUrlCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of GeoXUrl + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? mmdb = null, + Object? asn = null, + Object? geoip = null, + Object? geosite = null, + }) { + return _then(_value.copyWith( + mmdb: null == mmdb + ? _value.mmdb + : mmdb // ignore: cast_nullable_to_non_nullable + as String, + asn: null == asn + ? _value.asn + : asn // ignore: cast_nullable_to_non_nullable + as String, + geoip: null == geoip + ? _value.geoip + : geoip // ignore: cast_nullable_to_non_nullable + as String, + geosite: null == geosite + ? _value.geosite + : geosite // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$GeoXUrlImplCopyWith<$Res> implements $GeoXUrlCopyWith<$Res> { + factory _$$GeoXUrlImplCopyWith( + _$GeoXUrlImpl value, $Res Function(_$GeoXUrlImpl) then) = + __$$GeoXUrlImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String mmdb, String asn, String geoip, String geosite}); +} + +/// @nodoc +class __$$GeoXUrlImplCopyWithImpl<$Res> + extends _$GeoXUrlCopyWithImpl<$Res, _$GeoXUrlImpl> + implements _$$GeoXUrlImplCopyWith<$Res> { + __$$GeoXUrlImplCopyWithImpl( + _$GeoXUrlImpl _value, $Res Function(_$GeoXUrlImpl) _then) + : super(_value, _then); + + /// Create a copy of GeoXUrl + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? mmdb = null, + Object? asn = null, + Object? geoip = null, + Object? geosite = null, + }) { + return _then(_$GeoXUrlImpl( + mmdb: null == mmdb + ? _value.mmdb + : mmdb // ignore: cast_nullable_to_non_nullable + as String, + asn: null == asn + ? _value.asn + : asn // ignore: cast_nullable_to_non_nullable + as String, + geoip: null == geoip + ? _value.geoip + : geoip // ignore: cast_nullable_to_non_nullable + as String, + geosite: null == geosite + ? _value.geosite + : geosite // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$GeoXUrlImpl implements _GeoXUrl { + const _$GeoXUrlImpl( + {this.mmdb = + "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", + this.asn = + "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", + this.geoip = + "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat", + this.geosite = + "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat"}); + + factory _$GeoXUrlImpl.fromJson(Map json) => + _$$GeoXUrlImplFromJson(json); + + @override + @JsonKey() + final String mmdb; + @override + @JsonKey() + final String asn; + @override + @JsonKey() + final String geoip; + @override + @JsonKey() + final String geosite; + + @override + String toString() { + return 'GeoXUrl(mmdb: $mmdb, asn: $asn, geoip: $geoip, geosite: $geosite)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$GeoXUrlImpl && + (identical(other.mmdb, mmdb) || other.mmdb == mmdb) && + (identical(other.asn, asn) || other.asn == asn) && + (identical(other.geoip, geoip) || other.geoip == geoip) && + (identical(other.geosite, geosite) || other.geosite == geosite)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, mmdb, asn, geoip, geosite); + + /// Create a copy of GeoXUrl + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$GeoXUrlImplCopyWith<_$GeoXUrlImpl> get copyWith => + __$$GeoXUrlImplCopyWithImpl<_$GeoXUrlImpl>(this, _$identity); + + @override + Map toJson() { + return _$$GeoXUrlImplToJson( + this, + ); + } +} + +abstract class _GeoXUrl implements GeoXUrl { + const factory _GeoXUrl( + {final String mmdb, + final String asn, + final String geoip, + final String geosite}) = _$GeoXUrlImpl; + + factory _GeoXUrl.fromJson(Map json) = _$GeoXUrlImpl.fromJson; + + @override + String get mmdb; + @override + String get asn; + @override + String get geoip; + @override + String get geosite; + + /// Create a copy of GeoXUrl + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$GeoXUrlImplCopyWith<_$GeoXUrlImpl> get copyWith => + throw _privateConstructorUsedError; +} + +ClashConfig _$ClashConfigFromJson(Map json) { + return _ClashConfig.fromJson(json); +} + +/// @nodoc +mixin _$ClashConfig { + @JsonKey(name: "mixed-port") + int get mixedPort => throw _privateConstructorUsedError; + Mode get mode => throw _privateConstructorUsedError; + @JsonKey(name: "allow-lan") + bool get allowLan => throw _privateConstructorUsedError; + @JsonKey(name: "log-level") + LogLevel get logLevel => throw _privateConstructorUsedError; + bool get ipv6 => throw _privateConstructorUsedError; + @JsonKey(name: "find-process-mode", unknownEnumValue: FindProcessMode.off) + FindProcessMode get findProcessMode => throw _privateConstructorUsedError; + @JsonKey(name: "keep-alive-interval") + int get keepAliveInterval => throw _privateConstructorUsedError; + @JsonKey(name: "unified-delay") + bool get unifiedDelay => throw _privateConstructorUsedError; + @JsonKey(name: "tcp-concurrent") + bool get tcpConcurrent => throw _privateConstructorUsedError; + @JsonKey(fromJson: Tun.safeFormJson) + Tun get tun => throw _privateConstructorUsedError; + @JsonKey(fromJson: Dns.safeDnsFromJson) + Dns get dns => throw _privateConstructorUsedError; + @JsonKey(name: "geox-url", fromJson: GeoXUrl.safeFormJson) + GeoXUrl get geoXUrl => throw _privateConstructorUsedError; + @JsonKey(name: "geodata-loader") + GeodataLoader get geodataLoader => throw _privateConstructorUsedError; + @JsonKey(name: "proxy-groups") + List get proxyGroups => throw _privateConstructorUsedError; + List get rules => throw _privateConstructorUsedError; + @JsonKey(name: "global-ua") + String? get globalUa => throw _privateConstructorUsedError; + @JsonKey(name: "external-controller") + ExternalControllerStatus get externalController => + throw _privateConstructorUsedError; + Map get hosts => throw _privateConstructorUsedError; + + /// Serializes this ClashConfig to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ClashConfig + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ClashConfigCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ClashConfigCopyWith<$Res> { + factory $ClashConfigCopyWith( + ClashConfig value, $Res Function(ClashConfig) then) = + _$ClashConfigCopyWithImpl<$Res, ClashConfig>; + @useResult + $Res call( + {@JsonKey(name: "mixed-port") int mixedPort, + Mode mode, + @JsonKey(name: "allow-lan") bool allowLan, + @JsonKey(name: "log-level") LogLevel logLevel, + bool ipv6, + @JsonKey(name: "find-process-mode", unknownEnumValue: FindProcessMode.off) + FindProcessMode findProcessMode, + @JsonKey(name: "keep-alive-interval") int keepAliveInterval, + @JsonKey(name: "unified-delay") bool unifiedDelay, + @JsonKey(name: "tcp-concurrent") bool tcpConcurrent, + @JsonKey(fromJson: Tun.safeFormJson) Tun tun, + @JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns, + @JsonKey(name: "geox-url", fromJson: GeoXUrl.safeFormJson) + GeoXUrl geoXUrl, + @JsonKey(name: "geodata-loader") GeodataLoader geodataLoader, + @JsonKey(name: "proxy-groups") List proxyGroups, + List rules, + @JsonKey(name: "global-ua") String? globalUa, + @JsonKey(name: "external-controller") + ExternalControllerStatus externalController, + Map hosts}); + + $TunCopyWith<$Res> get tun; + $DnsCopyWith<$Res> get dns; + $GeoXUrlCopyWith<$Res> get geoXUrl; +} + +/// @nodoc +class _$ClashConfigCopyWithImpl<$Res, $Val extends ClashConfig> + implements $ClashConfigCopyWith<$Res> { + _$ClashConfigCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ClashConfig + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? mixedPort = null, + Object? mode = null, + Object? allowLan = null, + Object? logLevel = null, + Object? ipv6 = null, + Object? findProcessMode = null, + Object? keepAliveInterval = null, + Object? unifiedDelay = null, + Object? tcpConcurrent = null, + Object? tun = null, + Object? dns = null, + Object? geoXUrl = null, + Object? geodataLoader = null, + Object? proxyGroups = null, + Object? rules = null, + Object? globalUa = freezed, + Object? externalController = null, + Object? hosts = null, + }) { + return _then(_value.copyWith( + mixedPort: null == mixedPort + ? _value.mixedPort + : mixedPort // ignore: cast_nullable_to_non_nullable + as int, + mode: null == mode + ? _value.mode + : mode // ignore: cast_nullable_to_non_nullable + as Mode, + allowLan: null == allowLan + ? _value.allowLan + : allowLan // ignore: cast_nullable_to_non_nullable + as bool, + logLevel: null == logLevel + ? _value.logLevel + : logLevel // ignore: cast_nullable_to_non_nullable + as LogLevel, + ipv6: null == ipv6 + ? _value.ipv6 + : ipv6 // ignore: cast_nullable_to_non_nullable + as bool, + findProcessMode: null == findProcessMode + ? _value.findProcessMode + : findProcessMode // ignore: cast_nullable_to_non_nullable + as FindProcessMode, + keepAliveInterval: null == keepAliveInterval + ? _value.keepAliveInterval + : keepAliveInterval // ignore: cast_nullable_to_non_nullable + as int, + unifiedDelay: null == unifiedDelay + ? _value.unifiedDelay + : unifiedDelay // ignore: cast_nullable_to_non_nullable + as bool, + tcpConcurrent: null == tcpConcurrent + ? _value.tcpConcurrent + : tcpConcurrent // ignore: cast_nullable_to_non_nullable + as bool, + tun: null == tun + ? _value.tun + : tun // ignore: cast_nullable_to_non_nullable + as Tun, + dns: null == dns + ? _value.dns + : dns // ignore: cast_nullable_to_non_nullable + as Dns, + geoXUrl: null == geoXUrl + ? _value.geoXUrl + : geoXUrl // ignore: cast_nullable_to_non_nullable + as GeoXUrl, + geodataLoader: null == geodataLoader + ? _value.geodataLoader + : geodataLoader // ignore: cast_nullable_to_non_nullable + as GeodataLoader, + proxyGroups: null == proxyGroups + ? _value.proxyGroups + : proxyGroups // ignore: cast_nullable_to_non_nullable + as List, + rules: null == rules + ? _value.rules + : rules // ignore: cast_nullable_to_non_nullable + as List, + globalUa: freezed == globalUa + ? _value.globalUa + : globalUa // ignore: cast_nullable_to_non_nullable + as String?, + externalController: null == externalController + ? _value.externalController + : externalController // ignore: cast_nullable_to_non_nullable + as ExternalControllerStatus, + hosts: null == hosts + ? _value.hosts + : hosts // ignore: cast_nullable_to_non_nullable + as Map, + ) as $Val); + } + + /// Create a copy of ClashConfig + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $TunCopyWith<$Res> get tun { + return $TunCopyWith<$Res>(_value.tun, (value) { + return _then(_value.copyWith(tun: value) as $Val); + }); + } + + /// Create a copy of ClashConfig + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $DnsCopyWith<$Res> get dns { + return $DnsCopyWith<$Res>(_value.dns, (value) { + return _then(_value.copyWith(dns: value) as $Val); + }); + } + + /// Create a copy of ClashConfig + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $GeoXUrlCopyWith<$Res> get geoXUrl { + return $GeoXUrlCopyWith<$Res>(_value.geoXUrl, (value) { + return _then(_value.copyWith(geoXUrl: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$ClashConfigImplCopyWith<$Res> + implements $ClashConfigCopyWith<$Res> { + factory _$$ClashConfigImplCopyWith( + _$ClashConfigImpl value, $Res Function(_$ClashConfigImpl) then) = + __$$ClashConfigImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(name: "mixed-port") int mixedPort, + Mode mode, + @JsonKey(name: "allow-lan") bool allowLan, + @JsonKey(name: "log-level") LogLevel logLevel, + bool ipv6, + @JsonKey(name: "find-process-mode", unknownEnumValue: FindProcessMode.off) + FindProcessMode findProcessMode, + @JsonKey(name: "keep-alive-interval") int keepAliveInterval, + @JsonKey(name: "unified-delay") bool unifiedDelay, + @JsonKey(name: "tcp-concurrent") bool tcpConcurrent, + @JsonKey(fromJson: Tun.safeFormJson) Tun tun, + @JsonKey(fromJson: Dns.safeDnsFromJson) Dns dns, + @JsonKey(name: "geox-url", fromJson: GeoXUrl.safeFormJson) + GeoXUrl geoXUrl, + @JsonKey(name: "geodata-loader") GeodataLoader geodataLoader, + @JsonKey(name: "proxy-groups") List proxyGroups, + List rules, + @JsonKey(name: "global-ua") String? globalUa, + @JsonKey(name: "external-controller") + ExternalControllerStatus externalController, + Map hosts}); + + @override + $TunCopyWith<$Res> get tun; + @override + $DnsCopyWith<$Res> get dns; + @override + $GeoXUrlCopyWith<$Res> get geoXUrl; +} + +/// @nodoc +class __$$ClashConfigImplCopyWithImpl<$Res> + extends _$ClashConfigCopyWithImpl<$Res, _$ClashConfigImpl> + implements _$$ClashConfigImplCopyWith<$Res> { + __$$ClashConfigImplCopyWithImpl( + _$ClashConfigImpl _value, $Res Function(_$ClashConfigImpl) _then) + : super(_value, _then); + + /// Create a copy of ClashConfig + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? mixedPort = null, + Object? mode = null, + Object? allowLan = null, + Object? logLevel = null, + Object? ipv6 = null, + Object? findProcessMode = null, + Object? keepAliveInterval = null, + Object? unifiedDelay = null, + Object? tcpConcurrent = null, + Object? tun = null, + Object? dns = null, + Object? geoXUrl = null, + Object? geodataLoader = null, + Object? proxyGroups = null, + Object? rules = null, + Object? globalUa = freezed, + Object? externalController = null, + Object? hosts = null, + }) { + return _then(_$ClashConfigImpl( + mixedPort: null == mixedPort + ? _value.mixedPort + : mixedPort // ignore: cast_nullable_to_non_nullable + as int, + mode: null == mode + ? _value.mode + : mode // ignore: cast_nullable_to_non_nullable + as Mode, + allowLan: null == allowLan + ? _value.allowLan + : allowLan // ignore: cast_nullable_to_non_nullable + as bool, + logLevel: null == logLevel + ? _value.logLevel + : logLevel // ignore: cast_nullable_to_non_nullable + as LogLevel, + ipv6: null == ipv6 + ? _value.ipv6 + : ipv6 // ignore: cast_nullable_to_non_nullable + as bool, + findProcessMode: null == findProcessMode + ? _value.findProcessMode + : findProcessMode // ignore: cast_nullable_to_non_nullable + as FindProcessMode, + keepAliveInterval: null == keepAliveInterval + ? _value.keepAliveInterval + : keepAliveInterval // ignore: cast_nullable_to_non_nullable + as int, + unifiedDelay: null == unifiedDelay + ? _value.unifiedDelay + : unifiedDelay // ignore: cast_nullable_to_non_nullable + as bool, + tcpConcurrent: null == tcpConcurrent + ? _value.tcpConcurrent + : tcpConcurrent // ignore: cast_nullable_to_non_nullable + as bool, + tun: null == tun + ? _value.tun + : tun // ignore: cast_nullable_to_non_nullable + as Tun, + dns: null == dns + ? _value.dns + : dns // ignore: cast_nullable_to_non_nullable + as Dns, + geoXUrl: null == geoXUrl + ? _value.geoXUrl + : geoXUrl // ignore: cast_nullable_to_non_nullable + as GeoXUrl, + geodataLoader: null == geodataLoader + ? _value.geodataLoader + : geodataLoader // ignore: cast_nullable_to_non_nullable + as GeodataLoader, + proxyGroups: null == proxyGroups + ? _value._proxyGroups + : proxyGroups // ignore: cast_nullable_to_non_nullable + as List, + rules: null == rules + ? _value._rules + : rules // ignore: cast_nullable_to_non_nullable + as List, + globalUa: freezed == globalUa + ? _value.globalUa + : globalUa // ignore: cast_nullable_to_non_nullable + as String?, + externalController: null == externalController + ? _value.externalController + : externalController // ignore: cast_nullable_to_non_nullable + as ExternalControllerStatus, + hosts: null == hosts + ? _value._hosts + : hosts // ignore: cast_nullable_to_non_nullable + as Map, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ClashConfigImpl implements _ClashConfig { + const _$ClashConfigImpl( + {@JsonKey(name: "mixed-port") this.mixedPort = defaultMixedPort, + this.mode = Mode.rule, + @JsonKey(name: "allow-lan") this.allowLan = false, + @JsonKey(name: "log-level") this.logLevel = LogLevel.info, + this.ipv6 = false, + @JsonKey(name: "find-process-mode", unknownEnumValue: FindProcessMode.off) + this.findProcessMode = FindProcessMode.off, + @JsonKey(name: "keep-alive-interval") + this.keepAliveInterval = defaultKeepAliveInterval, + @JsonKey(name: "unified-delay") this.unifiedDelay = true, + @JsonKey(name: "tcp-concurrent") this.tcpConcurrent = true, + @JsonKey(fromJson: Tun.safeFormJson) this.tun = defaultTun, + @JsonKey(fromJson: Dns.safeDnsFromJson) this.dns = defaultDns, + @JsonKey(name: "geox-url", fromJson: GeoXUrl.safeFormJson) + this.geoXUrl = defaultGeoXUrl, + @JsonKey(name: "geodata-loader") + this.geodataLoader = GeodataLoader.memconservative, + @JsonKey(name: "proxy-groups") + final List proxyGroups = const [], + final List rules = const [], + @JsonKey(name: "global-ua") this.globalUa, + @JsonKey(name: "external-controller") + this.externalController = ExternalControllerStatus.close, + final Map hosts = const {}}) + : _proxyGroups = proxyGroups, + _rules = rules, + _hosts = hosts; + + factory _$ClashConfigImpl.fromJson(Map json) => + _$$ClashConfigImplFromJson(json); + + @override + @JsonKey(name: "mixed-port") + final int mixedPort; + @override + @JsonKey() + final Mode mode; + @override + @JsonKey(name: "allow-lan") + final bool allowLan; + @override + @JsonKey(name: "log-level") + final LogLevel logLevel; + @override + @JsonKey() + final bool ipv6; + @override + @JsonKey(name: "find-process-mode", unknownEnumValue: FindProcessMode.off) + final FindProcessMode findProcessMode; + @override + @JsonKey(name: "keep-alive-interval") + final int keepAliveInterval; + @override + @JsonKey(name: "unified-delay") + final bool unifiedDelay; + @override + @JsonKey(name: "tcp-concurrent") + final bool tcpConcurrent; + @override + @JsonKey(fromJson: Tun.safeFormJson) + final Tun tun; + @override + @JsonKey(fromJson: Dns.safeDnsFromJson) + final Dns dns; + @override + @JsonKey(name: "geox-url", fromJson: GeoXUrl.safeFormJson) + final GeoXUrl geoXUrl; + @override + @JsonKey(name: "geodata-loader") + final GeodataLoader geodataLoader; + final List _proxyGroups; + @override + @JsonKey(name: "proxy-groups") + List get proxyGroups { + if (_proxyGroups is EqualUnmodifiableListView) return _proxyGroups; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_proxyGroups); + } + + final List _rules; + @override + @JsonKey() + List get rules { + if (_rules is EqualUnmodifiableListView) return _rules; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_rules); + } + + @override + @JsonKey(name: "global-ua") + final String? globalUa; + @override + @JsonKey(name: "external-controller") + final ExternalControllerStatus externalController; + final Map _hosts; + @override + @JsonKey() + Map get hosts { + if (_hosts is EqualUnmodifiableMapView) return _hosts; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_hosts); + } + + @override + String toString() { + return 'ClashConfig(mixedPort: $mixedPort, mode: $mode, allowLan: $allowLan, logLevel: $logLevel, ipv6: $ipv6, findProcessMode: $findProcessMode, keepAliveInterval: $keepAliveInterval, unifiedDelay: $unifiedDelay, tcpConcurrent: $tcpConcurrent, tun: $tun, dns: $dns, geoXUrl: $geoXUrl, geodataLoader: $geodataLoader, proxyGroups: $proxyGroups, rules: $rules, globalUa: $globalUa, externalController: $externalController, hosts: $hosts)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ClashConfigImpl && + (identical(other.mixedPort, mixedPort) || + other.mixedPort == mixedPort) && + (identical(other.mode, mode) || other.mode == mode) && + (identical(other.allowLan, allowLan) || + other.allowLan == allowLan) && + (identical(other.logLevel, logLevel) || + other.logLevel == logLevel) && + (identical(other.ipv6, ipv6) || other.ipv6 == ipv6) && + (identical(other.findProcessMode, findProcessMode) || + other.findProcessMode == findProcessMode) && + (identical(other.keepAliveInterval, keepAliveInterval) || + other.keepAliveInterval == keepAliveInterval) && + (identical(other.unifiedDelay, unifiedDelay) || + other.unifiedDelay == unifiedDelay) && + (identical(other.tcpConcurrent, tcpConcurrent) || + other.tcpConcurrent == tcpConcurrent) && + (identical(other.tun, tun) || other.tun == tun) && + (identical(other.dns, dns) || other.dns == dns) && + (identical(other.geoXUrl, geoXUrl) || other.geoXUrl == geoXUrl) && + (identical(other.geodataLoader, geodataLoader) || + other.geodataLoader == geodataLoader) && + const DeepCollectionEquality() + .equals(other._proxyGroups, _proxyGroups) && + const DeepCollectionEquality().equals(other._rules, _rules) && + (identical(other.globalUa, globalUa) || + other.globalUa == globalUa) && + (identical(other.externalController, externalController) || + other.externalController == externalController) && + const DeepCollectionEquality().equals(other._hosts, _hosts)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + mixedPort, + mode, + allowLan, + logLevel, + ipv6, + findProcessMode, + keepAliveInterval, + unifiedDelay, + tcpConcurrent, + tun, + dns, + geoXUrl, + geodataLoader, + const DeepCollectionEquality().hash(_proxyGroups), + const DeepCollectionEquality().hash(_rules), + globalUa, + externalController, + const DeepCollectionEquality().hash(_hosts)); + + /// Create a copy of ClashConfig + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ClashConfigImplCopyWith<_$ClashConfigImpl> get copyWith => + __$$ClashConfigImplCopyWithImpl<_$ClashConfigImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ClashConfigImplToJson( + this, + ); + } +} + +abstract class _ClashConfig implements ClashConfig { + const factory _ClashConfig( + {@JsonKey(name: "mixed-port") final int mixedPort, + final Mode mode, + @JsonKey(name: "allow-lan") final bool allowLan, + @JsonKey(name: "log-level") final LogLevel logLevel, + final bool ipv6, + @JsonKey(name: "find-process-mode", unknownEnumValue: FindProcessMode.off) + final FindProcessMode findProcessMode, + @JsonKey(name: "keep-alive-interval") final int keepAliveInterval, + @JsonKey(name: "unified-delay") final bool unifiedDelay, + @JsonKey(name: "tcp-concurrent") final bool tcpConcurrent, + @JsonKey(fromJson: Tun.safeFormJson) final Tun tun, + @JsonKey(fromJson: Dns.safeDnsFromJson) final Dns dns, + @JsonKey(name: "geox-url", fromJson: GeoXUrl.safeFormJson) + final GeoXUrl geoXUrl, + @JsonKey(name: "geodata-loader") final GeodataLoader geodataLoader, + @JsonKey(name: "proxy-groups") final List proxyGroups, + final List rules, + @JsonKey(name: "global-ua") final String? globalUa, + @JsonKey(name: "external-controller") + final ExternalControllerStatus externalController, + final Map hosts}) = _$ClashConfigImpl; + + factory _ClashConfig.fromJson(Map json) = + _$ClashConfigImpl.fromJson; + + @override + @JsonKey(name: "mixed-port") + int get mixedPort; + @override + Mode get mode; + @override + @JsonKey(name: "allow-lan") + bool get allowLan; + @override + @JsonKey(name: "log-level") + LogLevel get logLevel; + @override + bool get ipv6; + @override + @JsonKey(name: "find-process-mode", unknownEnumValue: FindProcessMode.off) + FindProcessMode get findProcessMode; + @override + @JsonKey(name: "keep-alive-interval") + int get keepAliveInterval; + @override + @JsonKey(name: "unified-delay") + bool get unifiedDelay; + @override + @JsonKey(name: "tcp-concurrent") + bool get tcpConcurrent; + @override + @JsonKey(fromJson: Tun.safeFormJson) + Tun get tun; + @override + @JsonKey(fromJson: Dns.safeDnsFromJson) + Dns get dns; + @override + @JsonKey(name: "geox-url", fromJson: GeoXUrl.safeFormJson) + GeoXUrl get geoXUrl; + @override + @JsonKey(name: "geodata-loader") + GeodataLoader get geodataLoader; + @override + @JsonKey(name: "proxy-groups") + List get proxyGroups; + @override + List get rules; + @override + @JsonKey(name: "global-ua") + String? get globalUa; + @override + @JsonKey(name: "external-controller") + ExternalControllerStatus get externalController; + @override + Map get hosts; + + /// Create a copy of ClashConfig + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ClashConfigImplCopyWith<_$ClashConfigImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/generated/clash_config.g.dart b/lib/models/generated/clash_config.g.dart index 0d518af..98b3aee 100644 --- a/lib/models/generated/clash_config.g.dart +++ b/lib/models/generated/clash_config.g.dart @@ -6,96 +6,51 @@ part of '../clash_config.dart'; // JsonSerializableGenerator // ************************************************************************** -ClashConfig _$ClashConfigFromJson(Map json) => ClashConfig() - ..mixedPort = (json['mixed-port'] as num?)?.toInt() ?? 7890 - ..mode = $enumDecodeNullable(_$ModeEnumMap, json['mode']) ?? Mode.rule - ..findProcessMode = $enumDecodeNullable( - _$FindProcessModeEnumMap, json['find-process-mode']) ?? - FindProcessMode.off - ..allowLan = json['allow-lan'] as bool - ..logLevel = - $enumDecodeNullable(_$LogLevelEnumMap, json['log-level']) ?? LogLevel.info - ..externalController = json['external-controller'] as String? ?? '' - ..keepAliveInterval = (json['keep-alive-interval'] as num?)?.toInt() ?? 30 - ..ipv6 = json['ipv6'] as bool? ?? false - ..geodataLoader = json['geodata-loader'] as String? ?? 'memconservative' - ..unifiedDelay = json['unified-delay'] as bool? ?? false - ..tcpConcurrent = json['tcp-concurrent'] as bool? ?? false - ..tun = Tun.fromJson(json['tun'] as Map) - ..dns = Dns.safeDnsFromJson(json['dns'] as Map) - ..rules = (json['rules'] as List).map((e) => e as String).toList() - ..globalRealUa = json['global-real-ua'] as String? - ..geoXUrl = (json['geox-url'] as Map?)?.map( - (k, e) => MapEntry(k, e as String), - ) ?? - { - 'mmdb': - 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb', - 'asn': - 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb', - 'geoip': - 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat', - 'geosite': - 'https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat' - } - ..hosts = (json['hosts'] as Map?)?.map( - (k, e) => MapEntry(k, e as String), - ) ?? - {} - ..includeRouteAddress = (json['include-route-address'] as List?) - ?.map((e) => e as String) - .toList() ?? - [] - ..routeMode = $enumDecodeNullable(_$RouteModeEnumMap, json['route-mode']) ?? - RouteMode.config; +_$ProxyGroupImpl _$$ProxyGroupImplFromJson(Map json) => + _$ProxyGroupImpl( + name: json['name'] as String, + type: GroupType.parseProfileType(json['type'] as String), + proxies: + (json['proxies'] as List?)?.map((e) => e as String).toList(), + use: (json['use'] as List?)?.map((e) => e as String).toList(), + interval: (json['interval'] as num?)?.toInt(), + lazy: json['lazy'] as bool?, + url: json['url'] as String?, + timeout: (json['timeout'] as num?)?.toInt(), + maxFailedTimes: (json['max-failed-times'] as num?)?.toInt(), + filter: json['filter'] as String?, + excludeFilter: json['expected-filter'] as String?, + excludeType: json['exclude-type'] as String?, + expectedStatus: (json['expected-status'] as num?)?.toInt(), + hidden: json['hidden'] as bool?, + icon: json['icon'] as String?, + ); -Map _$ClashConfigToJson(ClashConfig instance) => +Map _$$ProxyGroupImplToJson(_$ProxyGroupImpl instance) => { - 'mixed-port': instance.mixedPort, - 'mode': _$ModeEnumMap[instance.mode]!, - 'find-process-mode': _$FindProcessModeEnumMap[instance.findProcessMode]!, - 'allow-lan': instance.allowLan, - 'log-level': _$LogLevelEnumMap[instance.logLevel]!, - 'external-controller': instance.externalController, - 'keep-alive-interval': instance.keepAliveInterval, - 'ipv6': instance.ipv6, - 'geodata-loader': instance.geodataLoader, - 'unified-delay': instance.unifiedDelay, - 'tcp-concurrent': instance.tcpConcurrent, - 'tun': instance.tun, - 'dns': instance.dns, - 'rules': instance.rules, - 'global-ua': instance.globalUa, - 'global-real-ua': instance.globalRealUa, - 'geox-url': instance.geoXUrl, - 'hosts': instance.hosts, - 'route-address': instance.routeAddress, - 'include-route-address': instance.includeRouteAddress, - 'route-mode': _$RouteModeEnumMap[instance.routeMode]!, + 'name': instance.name, + 'type': _$GroupTypeEnumMap[instance.type]!, + 'proxies': instance.proxies, + 'use': instance.use, + 'interval': instance.interval, + 'lazy': instance.lazy, + 'url': instance.url, + 'timeout': instance.timeout, + 'max-failed-times': instance.maxFailedTimes, + 'filter': instance.filter, + 'expected-filter': instance.excludeFilter, + 'exclude-type': instance.excludeType, + 'expected-status': instance.expectedStatus, + 'hidden': instance.hidden, + 'icon': instance.icon, }; -const _$ModeEnumMap = { - Mode.rule: 'rule', - Mode.global: 'global', - Mode.direct: 'direct', -}; - -const _$FindProcessModeEnumMap = { - FindProcessMode.always: 'always', - FindProcessMode.off: 'off', -}; - -const _$LogLevelEnumMap = { - LogLevel.debug: 'debug', - LogLevel.info: 'info', - LogLevel.warning: 'warning', - LogLevel.error: 'error', - LogLevel.silent: 'silent', -}; - -const _$RouteModeEnumMap = { - RouteMode.bypassPrivate: 'bypassPrivate', - RouteMode.config: 'config', +const _$GroupTypeEnumMap = { + GroupType.Selector: 'Selector', + GroupType.URLTest: 'URLTest', + GroupType.Fallback: 'Fallback', + GroupType.LoadBalance: 'LoadBalance', + GroupType.Relay: 'Relay', }; _$TunImpl _$$TunImplFromJson(Map json) => _$TunImpl( @@ -107,6 +62,10 @@ _$TunImpl _$$TunImplFromJson(Map json) => _$TunImpl( ?.map((e) => e as String) .toList() ?? const ["any:53"], + routeAddress: (json['route-address'] as List?) + ?.map((e) => e as String) + .toList() ?? + const [], ); Map _$$TunImplToJson(_$TunImpl instance) => { @@ -114,6 +73,7 @@ Map _$$TunImplToJson(_$TunImpl instance) => { 'device': instance.device, 'stack': _$TunStackEnumMap[instance.stack]!, 'dns-hijack': instance.dnsHijack, + 'route-address': instance.routeAddress, }; const _$TunStackEnumMap = { @@ -223,3 +183,120 @@ const _$DnsModeEnumMap = { DnsMode.redirHost: 'redir-host', DnsMode.hosts: 'hosts', }; + +_$GeoXUrlImpl _$$GeoXUrlImplFromJson(Map json) => + _$GeoXUrlImpl( + mmdb: json['mmdb'] as String? ?? + "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", + asn: json['asn'] as String? ?? + "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", + geoip: json['geoip'] as String? ?? + "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat", + geosite: json['geosite'] as String? ?? + "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat", + ); + +Map _$$GeoXUrlImplToJson(_$GeoXUrlImpl instance) => + { + 'mmdb': instance.mmdb, + 'asn': instance.asn, + 'geoip': instance.geoip, + 'geosite': instance.geosite, + }; + +_$ClashConfigImpl _$$ClashConfigImplFromJson(Map json) => + _$ClashConfigImpl( + mixedPort: (json['mixed-port'] as num?)?.toInt() ?? defaultMixedPort, + mode: $enumDecodeNullable(_$ModeEnumMap, json['mode']) ?? Mode.rule, + allowLan: json['allow-lan'] as bool? ?? false, + logLevel: $enumDecodeNullable(_$LogLevelEnumMap, json['log-level']) ?? + LogLevel.info, + ipv6: json['ipv6'] as bool? ?? false, + findProcessMode: $enumDecodeNullable( + _$FindProcessModeEnumMap, json['find-process-mode'], + unknownValue: FindProcessMode.off) ?? + FindProcessMode.off, + keepAliveInterval: (json['keep-alive-interval'] as num?)?.toInt() ?? + defaultKeepAliveInterval, + unifiedDelay: json['unified-delay'] as bool? ?? true, + tcpConcurrent: json['tcp-concurrent'] as bool? ?? true, + tun: json['tun'] == null + ? defaultTun + : Tun.safeFormJson(json['tun'] as Map?), + dns: json['dns'] == null + ? defaultDns + : Dns.safeDnsFromJson(json['dns'] as Map), + geoXUrl: json['geox-url'] == null + ? defaultGeoXUrl + : GeoXUrl.safeFormJson(json['geox-url'] as Map?), + geodataLoader: + $enumDecodeNullable(_$GeodataLoaderEnumMap, json['geodata-loader']) ?? + GeodataLoader.memconservative, + proxyGroups: (json['proxy-groups'] as List?) + ?.map((e) => ProxyGroup.fromJson(e as Map)) + .toList() ?? + const [], + rules: + (json['rules'] as List?)?.map((e) => e as String).toList() ?? + const [], + globalUa: json['global-ua'] as String?, + externalController: $enumDecodeNullable( + _$ExternalControllerStatusEnumMap, json['external-controller']) ?? + ExternalControllerStatus.close, + hosts: (json['hosts'] as Map?)?.map( + (k, e) => MapEntry(k, e as String), + ) ?? + const {}, + ); + +Map _$$ClashConfigImplToJson(_$ClashConfigImpl instance) => + { + 'mixed-port': instance.mixedPort, + 'mode': _$ModeEnumMap[instance.mode]!, + 'allow-lan': instance.allowLan, + 'log-level': _$LogLevelEnumMap[instance.logLevel]!, + 'ipv6': instance.ipv6, + 'find-process-mode': _$FindProcessModeEnumMap[instance.findProcessMode]!, + 'keep-alive-interval': instance.keepAliveInterval, + 'unified-delay': instance.unifiedDelay, + 'tcp-concurrent': instance.tcpConcurrent, + 'tun': instance.tun, + 'dns': instance.dns, + 'geox-url': instance.geoXUrl, + 'geodata-loader': _$GeodataLoaderEnumMap[instance.geodataLoader]!, + 'proxy-groups': instance.proxyGroups, + 'rules': instance.rules, + 'global-ua': instance.globalUa, + 'external-controller': + _$ExternalControllerStatusEnumMap[instance.externalController]!, + 'hosts': instance.hosts, + }; + +const _$ModeEnumMap = { + Mode.rule: 'rule', + Mode.global: 'global', + Mode.direct: 'direct', +}; + +const _$LogLevelEnumMap = { + LogLevel.debug: 'debug', + LogLevel.info: 'info', + LogLevel.warning: 'warning', + LogLevel.error: 'error', + LogLevel.silent: 'silent', +}; + +const _$FindProcessModeEnumMap = { + FindProcessMode.always: 'always', + FindProcessMode.off: 'off', +}; + +const _$GeodataLoaderEnumMap = { + GeodataLoader.standard: 'standard', + GeodataLoader.memconservative: 'memconservative', +}; + +const _$ExternalControllerStatusEnumMap = { + ExternalControllerStatus.close: '', + ExternalControllerStatus.open: '127.0.0.1:9090', +}; diff --git a/lib/models/generated/common.freezed.dart b/lib/models/generated/common.freezed.dart index d92ec81..3c96ad5 100644 --- a/lib/models/generated/common.freezed.dart +++ b/lib/models/generated/common.freezed.dart @@ -17,7 +17,7 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$NavigationItem { Icon get icon => throw _privateConstructorUsedError; - String get label => throw _privateConstructorUsedError; + PageLabel get label => throw _privateConstructorUsedError; String? get description => throw _privateConstructorUsedError; Widget get fragment => throw _privateConstructorUsedError; bool get keep => throw _privateConstructorUsedError; @@ -39,7 +39,7 @@ abstract class $NavigationItemCopyWith<$Res> { @useResult $Res call( {Icon icon, - String label, + PageLabel label, String? description, Widget fragment, bool keep, @@ -78,7 +78,7 @@ class _$NavigationItemCopyWithImpl<$Res, $Val extends NavigationItem> label: null == label ? _value.label : label // ignore: cast_nullable_to_non_nullable - as String, + as PageLabel, description: freezed == description ? _value.description : description // ignore: cast_nullable_to_non_nullable @@ -113,7 +113,7 @@ abstract class _$$NavigationItemImplCopyWith<$Res> @useResult $Res call( {Icon icon, - String label, + PageLabel label, String? description, Widget fragment, bool keep, @@ -150,7 +150,7 @@ class __$$NavigationItemImplCopyWithImpl<$Res> label: null == label ? _value.label : label // ignore: cast_nullable_to_non_nullable - as String, + as PageLabel, description: freezed == description ? _value.description : description // ignore: cast_nullable_to_non_nullable @@ -194,7 +194,7 @@ class _$NavigationItemImpl implements _NavigationItem { @override final Icon icon; @override - final String label; + final PageLabel label; @override final String? description; @override @@ -251,7 +251,7 @@ class _$NavigationItemImpl implements _NavigationItem { abstract class _NavigationItem implements NavigationItem { const factory _NavigationItem( {required final Icon icon, - required final String label, + required final PageLabel label, final String? description, required final Widget fragment, final bool keep, @@ -261,7 +261,7 @@ abstract class _NavigationItem implements NavigationItem { @override Icon get icon; @override - String get label; + PageLabel get label; @override String? get description; @override @@ -1984,6 +1984,186 @@ abstract class _VersionInfo implements VersionInfo { throw _privateConstructorUsedError; } +Proxy _$ProxyFromJson(Map json) { + return _Proxy.fromJson(json); +} + +/// @nodoc +mixin _$Proxy { + String get name => throw _privateConstructorUsedError; + String get type => throw _privateConstructorUsedError; + String? get now => throw _privateConstructorUsedError; + + /// Serializes this Proxy to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of Proxy + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ProxyCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ProxyCopyWith<$Res> { + factory $ProxyCopyWith(Proxy value, $Res Function(Proxy) then) = + _$ProxyCopyWithImpl<$Res, Proxy>; + @useResult + $Res call({String name, String type, String? now}); +} + +/// @nodoc +class _$ProxyCopyWithImpl<$Res, $Val extends Proxy> + implements $ProxyCopyWith<$Res> { + _$ProxyCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of Proxy + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? type = null, + Object? now = freezed, + }) { + return _then(_value.copyWith( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as String, + now: freezed == now + ? _value.now + : now // ignore: cast_nullable_to_non_nullable + as String?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ProxyImplCopyWith<$Res> implements $ProxyCopyWith<$Res> { + factory _$$ProxyImplCopyWith( + _$ProxyImpl value, $Res Function(_$ProxyImpl) then) = + __$$ProxyImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String name, String type, String? now}); +} + +/// @nodoc +class __$$ProxyImplCopyWithImpl<$Res> + extends _$ProxyCopyWithImpl<$Res, _$ProxyImpl> + implements _$$ProxyImplCopyWith<$Res> { + __$$ProxyImplCopyWithImpl( + _$ProxyImpl _value, $Res Function(_$ProxyImpl) _then) + : super(_value, _then); + + /// Create a copy of Proxy + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? type = null, + Object? now = freezed, + }) { + return _then(_$ProxyImpl( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as String, + now: freezed == now + ? _value.now + : now // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ProxyImpl implements _Proxy { + const _$ProxyImpl({required this.name, required this.type, this.now}); + + factory _$ProxyImpl.fromJson(Map json) => + _$$ProxyImplFromJson(json); + + @override + final String name; + @override + final String type; + @override + final String? now; + + @override + String toString() { + return 'Proxy(name: $name, type: $type, now: $now)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProxyImpl && + (identical(other.name, name) || other.name == name) && + (identical(other.type, type) || other.type == type) && + (identical(other.now, now) || other.now == now)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, name, type, now); + + /// Create a copy of Proxy + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ProxyImplCopyWith<_$ProxyImpl> get copyWith => + __$$ProxyImplCopyWithImpl<_$ProxyImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ProxyImplToJson( + this, + ); + } +} + +abstract class _Proxy implements Proxy { + const factory _Proxy( + {required final String name, + required final String type, + final String? now}) = _$ProxyImpl; + + factory _Proxy.fromJson(Map json) = _$ProxyImpl.fromJson; + + @override + String get name; + @override + String get type; + @override + String? get now; + + /// Create a copy of Proxy + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ProxyImplCopyWith<_$ProxyImpl> get copyWith => + throw _privateConstructorUsedError; +} + Group _$GroupFromJson(Map json) { return _Group.fromJson(json); } @@ -2270,183 +2450,152 @@ abstract class _Group implements Group { throw _privateConstructorUsedError; } -Proxy _$ProxyFromJson(Map json) { - return _Proxy.fromJson(json); -} - /// @nodoc -mixin _$Proxy { - String get name => throw _privateConstructorUsedError; - String get type => throw _privateConstructorUsedError; - String? get now => throw _privateConstructorUsedError; +mixin _$ColorSchemes { + ColorScheme? get lightColorScheme => throw _privateConstructorUsedError; + ColorScheme? get darkColorScheme => throw _privateConstructorUsedError; - /// Serializes this Proxy to a JSON map. - Map toJson() => throw _privateConstructorUsedError; - - /// Create a copy of Proxy + /// Create a copy of ColorSchemes /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) - $ProxyCopyWith get copyWith => throw _privateConstructorUsedError; + $ColorSchemesCopyWith get copyWith => + throw _privateConstructorUsedError; } /// @nodoc -abstract class $ProxyCopyWith<$Res> { - factory $ProxyCopyWith(Proxy value, $Res Function(Proxy) then) = - _$ProxyCopyWithImpl<$Res, Proxy>; +abstract class $ColorSchemesCopyWith<$Res> { + factory $ColorSchemesCopyWith( + ColorSchemes value, $Res Function(ColorSchemes) then) = + _$ColorSchemesCopyWithImpl<$Res, ColorSchemes>; @useResult - $Res call({String name, String type, String? now}); + $Res call({ColorScheme? lightColorScheme, ColorScheme? darkColorScheme}); } /// @nodoc -class _$ProxyCopyWithImpl<$Res, $Val extends Proxy> - implements $ProxyCopyWith<$Res> { - _$ProxyCopyWithImpl(this._value, this._then); +class _$ColorSchemesCopyWithImpl<$Res, $Val extends ColorSchemes> + implements $ColorSchemesCopyWith<$Res> { + _$ColorSchemesCopyWithImpl(this._value, this._then); // ignore: unused_field final $Val _value; // ignore: unused_field final $Res Function($Val) _then; - /// Create a copy of Proxy + /// Create a copy of ColorSchemes /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ - Object? name = null, - Object? type = null, - Object? now = freezed, + Object? lightColorScheme = freezed, + Object? darkColorScheme = freezed, }) { return _then(_value.copyWith( - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - type: null == type - ? _value.type - : type // ignore: cast_nullable_to_non_nullable - as String, - now: freezed == now - ? _value.now - : now // ignore: cast_nullable_to_non_nullable - as String?, + lightColorScheme: freezed == lightColorScheme + ? _value.lightColorScheme + : lightColorScheme // ignore: cast_nullable_to_non_nullable + as ColorScheme?, + darkColorScheme: freezed == darkColorScheme + ? _value.darkColorScheme + : darkColorScheme // ignore: cast_nullable_to_non_nullable + as ColorScheme?, ) as $Val); } } /// @nodoc -abstract class _$$ProxyImplCopyWith<$Res> implements $ProxyCopyWith<$Res> { - factory _$$ProxyImplCopyWith( - _$ProxyImpl value, $Res Function(_$ProxyImpl) then) = - __$$ProxyImplCopyWithImpl<$Res>; +abstract class _$$ColorSchemesImplCopyWith<$Res> + implements $ColorSchemesCopyWith<$Res> { + factory _$$ColorSchemesImplCopyWith( + _$ColorSchemesImpl value, $Res Function(_$ColorSchemesImpl) then) = + __$$ColorSchemesImplCopyWithImpl<$Res>; @override @useResult - $Res call({String name, String type, String? now}); + $Res call({ColorScheme? lightColorScheme, ColorScheme? darkColorScheme}); } /// @nodoc -class __$$ProxyImplCopyWithImpl<$Res> - extends _$ProxyCopyWithImpl<$Res, _$ProxyImpl> - implements _$$ProxyImplCopyWith<$Res> { - __$$ProxyImplCopyWithImpl( - _$ProxyImpl _value, $Res Function(_$ProxyImpl) _then) +class __$$ColorSchemesImplCopyWithImpl<$Res> + extends _$ColorSchemesCopyWithImpl<$Res, _$ColorSchemesImpl> + implements _$$ColorSchemesImplCopyWith<$Res> { + __$$ColorSchemesImplCopyWithImpl( + _$ColorSchemesImpl _value, $Res Function(_$ColorSchemesImpl) _then) : super(_value, _then); - /// Create a copy of Proxy + /// Create a copy of ColorSchemes /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ - Object? name = null, - Object? type = null, - Object? now = freezed, + Object? lightColorScheme = freezed, + Object? darkColorScheme = freezed, }) { - return _then(_$ProxyImpl( - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - type: null == type - ? _value.type - : type // ignore: cast_nullable_to_non_nullable - as String, - now: freezed == now - ? _value.now - : now // ignore: cast_nullable_to_non_nullable - as String?, + return _then(_$ColorSchemesImpl( + lightColorScheme: freezed == lightColorScheme + ? _value.lightColorScheme + : lightColorScheme // ignore: cast_nullable_to_non_nullable + as ColorScheme?, + darkColorScheme: freezed == darkColorScheme + ? _value.darkColorScheme + : darkColorScheme // ignore: cast_nullable_to_non_nullable + as ColorScheme?, )); } } /// @nodoc -@JsonSerializable() -class _$ProxyImpl implements _Proxy { - const _$ProxyImpl({required this.name, required this.type, this.now}); - factory _$ProxyImpl.fromJson(Map json) => - _$$ProxyImplFromJson(json); +class _$ColorSchemesImpl implements _ColorSchemes { + const _$ColorSchemesImpl({this.lightColorScheme, this.darkColorScheme}); @override - final String name; + final ColorScheme? lightColorScheme; @override - final String type; - @override - final String? now; + final ColorScheme? darkColorScheme; @override String toString() { - return 'Proxy(name: $name, type: $type, now: $now)'; + return 'ColorSchemes(lightColorScheme: $lightColorScheme, darkColorScheme: $darkColorScheme)'; } @override bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && - other is _$ProxyImpl && - (identical(other.name, name) || other.name == name) && - (identical(other.type, type) || other.type == type) && - (identical(other.now, now) || other.now == now)); + other is _$ColorSchemesImpl && + (identical(other.lightColorScheme, lightColorScheme) || + other.lightColorScheme == lightColorScheme) && + (identical(other.darkColorScheme, darkColorScheme) || + other.darkColorScheme == darkColorScheme)); } - @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash(runtimeType, name, type, now); + int get hashCode => + Object.hash(runtimeType, lightColorScheme, darkColorScheme); - /// Create a copy of Proxy + /// Create a copy of ColorSchemes /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') - _$$ProxyImplCopyWith<_$ProxyImpl> get copyWith => - __$$ProxyImplCopyWithImpl<_$ProxyImpl>(this, _$identity); - - @override - Map toJson() { - return _$$ProxyImplToJson( - this, - ); - } + _$$ColorSchemesImplCopyWith<_$ColorSchemesImpl> get copyWith => + __$$ColorSchemesImplCopyWithImpl<_$ColorSchemesImpl>(this, _$identity); } -abstract class _Proxy implements Proxy { - const factory _Proxy( - {required final String name, - required final String type, - final String? now}) = _$ProxyImpl; - - factory _Proxy.fromJson(Map json) = _$ProxyImpl.fromJson; +abstract class _ColorSchemes implements ColorSchemes { + const factory _ColorSchemes( + {final ColorScheme? lightColorScheme, + final ColorScheme? darkColorScheme}) = _$ColorSchemesImpl; @override - String get name; + ColorScheme? get lightColorScheme; @override - String get type; - @override - String? get now; + ColorScheme? get darkColorScheme; - /// Create a copy of Proxy + /// Create a copy of ColorSchemes /// with the given fields replaced by the non-null parameter values. @override @JsonKey(includeFromJson: false, includeToJson: false) - _$$ProxyImplCopyWith<_$ProxyImpl> get copyWith => + _$$ColorSchemesImplCopyWith<_$ColorSchemesImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/lib/models/generated/common.g.dart b/lib/models/generated/common.g.dart index 7f67156..52aa4ef 100644 --- a/lib/models/generated/common.g.dart +++ b/lib/models/generated/common.g.dart @@ -113,6 +113,19 @@ Map _$$VersionInfoImplToJson(_$VersionInfoImpl instance) => 'version': instance.version, }; +_$ProxyImpl _$$ProxyImplFromJson(Map json) => _$ProxyImpl( + name: json['name'] as String, + type: json['type'] as String, + now: json['now'] as String?, + ); + +Map _$$ProxyImplToJson(_$ProxyImpl instance) => + { + 'name': instance.name, + 'type': instance.type, + 'now': instance.now, + }; + _$GroupImpl _$$GroupImplFromJson(Map json) => _$GroupImpl( type: $enumDecode(_$GroupTypeEnumMap, json['type']), all: (json['all'] as List?) @@ -145,19 +158,6 @@ const _$GroupTypeEnumMap = { GroupType.Relay: 'Relay', }; -_$ProxyImpl _$$ProxyImplFromJson(Map json) => _$ProxyImpl( - name: json['name'] as String, - type: json['type'] as String, - now: json['now'] as String?, - ); - -Map _$$ProxyImplToJson(_$ProxyImpl instance) => - { - 'name': instance.name, - 'type': instance.type, - 'now': instance.now, - }; - _$HotKeyActionImpl _$$HotKeyActionImplFromJson(Map json) => _$HotKeyActionImpl( action: $enumDecode(_$HotActionEnumMap, json['action']), diff --git a/lib/models/generated/config.freezed.dart b/lib/models/generated/config.freezed.dart index 1d82785..deca45f 100644 --- a/lib/models/generated/config.freezed.dart +++ b/lib/models/generated/config.freezed.dart @@ -14,14 +14,14 @@ T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); -AppSetting _$AppSettingFromJson(Map json) { - return _AppSetting.fromJson(json); +AppSettingProps _$AppSettingPropsFromJson(Map json) { + return _AppSettingProps.fromJson(json); } /// @nodoc -mixin _$AppSetting { +mixin _$AppSettingProps { String? get locale => throw _privateConstructorUsedError; - @JsonKey(fromJson: dashboardWidgetsRealFormJson) + @JsonKey(fromJson: dashboardWidgetsSafeFormJson) List get dashboardWidgets => throw _privateConstructorUsedError; bool get onlyStatisticsProxy => throw _privateConstructorUsedError; @@ -38,25 +38,25 @@ mixin _$AppSetting { bool get minimizeOnExit => throw _privateConstructorUsedError; bool get hidden => throw _privateConstructorUsedError; - /// Serializes this AppSetting to a JSON map. + /// Serializes this AppSettingProps to a JSON map. Map toJson() => throw _privateConstructorUsedError; - /// Create a copy of AppSetting + /// Create a copy of AppSettingProps /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) - $AppSettingCopyWith get copyWith => + $AppSettingPropsCopyWith get copyWith => throw _privateConstructorUsedError; } /// @nodoc -abstract class $AppSettingCopyWith<$Res> { - factory $AppSettingCopyWith( - AppSetting value, $Res Function(AppSetting) then) = - _$AppSettingCopyWithImpl<$Res, AppSetting>; +abstract class $AppSettingPropsCopyWith<$Res> { + factory $AppSettingPropsCopyWith( + AppSettingProps value, $Res Function(AppSettingProps) then) = + _$AppSettingPropsCopyWithImpl<$Res, AppSettingProps>; @useResult $Res call( {String? locale, - @JsonKey(fromJson: dashboardWidgetsRealFormJson) + @JsonKey(fromJson: dashboardWidgetsSafeFormJson) List dashboardWidgets, bool onlyStatisticsProxy, bool autoLaunch, @@ -74,16 +74,16 @@ abstract class $AppSettingCopyWith<$Res> { } /// @nodoc -class _$AppSettingCopyWithImpl<$Res, $Val extends AppSetting> - implements $AppSettingCopyWith<$Res> { - _$AppSettingCopyWithImpl(this._value, this._then); +class _$AppSettingPropsCopyWithImpl<$Res, $Val extends AppSettingProps> + implements $AppSettingPropsCopyWith<$Res> { + _$AppSettingPropsCopyWithImpl(this._value, this._then); // ignore: unused_field final $Val _value; // ignore: unused_field final $Res Function($Val) _then; - /// Create a copy of AppSetting + /// Create a copy of AppSettingProps /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override @@ -170,16 +170,16 @@ class _$AppSettingCopyWithImpl<$Res, $Val extends AppSetting> } /// @nodoc -abstract class _$$AppSettingImplCopyWith<$Res> - implements $AppSettingCopyWith<$Res> { - factory _$$AppSettingImplCopyWith( - _$AppSettingImpl value, $Res Function(_$AppSettingImpl) then) = - __$$AppSettingImplCopyWithImpl<$Res>; +abstract class _$$AppSettingPropsImplCopyWith<$Res> + implements $AppSettingPropsCopyWith<$Res> { + factory _$$AppSettingPropsImplCopyWith(_$AppSettingPropsImpl value, + $Res Function(_$AppSettingPropsImpl) then) = + __$$AppSettingPropsImplCopyWithImpl<$Res>; @override @useResult $Res call( {String? locale, - @JsonKey(fromJson: dashboardWidgetsRealFormJson) + @JsonKey(fromJson: dashboardWidgetsSafeFormJson) List dashboardWidgets, bool onlyStatisticsProxy, bool autoLaunch, @@ -197,14 +197,14 @@ abstract class _$$AppSettingImplCopyWith<$Res> } /// @nodoc -class __$$AppSettingImplCopyWithImpl<$Res> - extends _$AppSettingCopyWithImpl<$Res, _$AppSettingImpl> - implements _$$AppSettingImplCopyWith<$Res> { - __$$AppSettingImplCopyWithImpl( - _$AppSettingImpl _value, $Res Function(_$AppSettingImpl) _then) +class __$$AppSettingPropsImplCopyWithImpl<$Res> + extends _$AppSettingPropsCopyWithImpl<$Res, _$AppSettingPropsImpl> + implements _$$AppSettingPropsImplCopyWith<$Res> { + __$$AppSettingPropsImplCopyWithImpl( + _$AppSettingPropsImpl _value, $Res Function(_$AppSettingPropsImpl) _then) : super(_value, _then); - /// Create a copy of AppSetting + /// Create a copy of AppSettingProps /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override @@ -225,7 +225,7 @@ class __$$AppSettingImplCopyWithImpl<$Res> Object? minimizeOnExit = null, Object? hidden = null, }) { - return _then(_$AppSettingImpl( + return _then(_$AppSettingPropsImpl( locale: freezed == locale ? _value.locale : locale // ignore: cast_nullable_to_non_nullable @@ -292,10 +292,10 @@ class __$$AppSettingImplCopyWithImpl<$Res> /// @nodoc @JsonSerializable() -class _$AppSettingImpl implements _AppSetting { - const _$AppSettingImpl( +class _$AppSettingPropsImpl implements _AppSettingProps { + const _$AppSettingPropsImpl( {this.locale, - @JsonKey(fromJson: dashboardWidgetsRealFormJson) + @JsonKey(fromJson: dashboardWidgetsSafeFormJson) final List dashboardWidgets = defaultDashboardWidgets, this.onlyStatisticsProxy = false, this.autoLaunch = false, @@ -312,14 +312,14 @@ class _$AppSettingImpl implements _AppSetting { this.hidden = false}) : _dashboardWidgets = dashboardWidgets; - factory _$AppSettingImpl.fromJson(Map json) => - _$$AppSettingImplFromJson(json); + factory _$AppSettingPropsImpl.fromJson(Map json) => + _$$AppSettingPropsImplFromJson(json); @override final String? locale; final List _dashboardWidgets; @override - @JsonKey(fromJson: dashboardWidgetsRealFormJson) + @JsonKey(fromJson: dashboardWidgetsSafeFormJson) List get dashboardWidgets { if (_dashboardWidgets is EqualUnmodifiableListView) return _dashboardWidgets; @@ -369,14 +369,14 @@ class _$AppSettingImpl implements _AppSetting { @override String toString() { - return 'AppSetting(locale: $locale, dashboardWidgets: $dashboardWidgets, onlyStatisticsProxy: $onlyStatisticsProxy, autoLaunch: $autoLaunch, silentLaunch: $silentLaunch, autoRun: $autoRun, openLogs: $openLogs, closeConnections: $closeConnections, testUrl: $testUrl, isAnimateToPage: $isAnimateToPage, autoCheckUpdate: $autoCheckUpdate, showLabel: $showLabel, disclaimerAccepted: $disclaimerAccepted, minimizeOnExit: $minimizeOnExit, hidden: $hidden)'; + return 'AppSettingProps(locale: $locale, dashboardWidgets: $dashboardWidgets, onlyStatisticsProxy: $onlyStatisticsProxy, autoLaunch: $autoLaunch, silentLaunch: $silentLaunch, autoRun: $autoRun, openLogs: $openLogs, closeConnections: $closeConnections, testUrl: $testUrl, isAnimateToPage: $isAnimateToPage, autoCheckUpdate: $autoCheckUpdate, showLabel: $showLabel, disclaimerAccepted: $disclaimerAccepted, minimizeOnExit: $minimizeOnExit, hidden: $hidden)'; } @override bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && - other is _$AppSettingImpl && + other is _$AppSettingPropsImpl && (identical(other.locale, locale) || other.locale == locale) && const DeepCollectionEquality() .equals(other._dashboardWidgets, _dashboardWidgets) && @@ -425,26 +425,27 @@ class _$AppSettingImpl implements _AppSetting { minimizeOnExit, hidden); - /// Create a copy of AppSetting + /// Create a copy of AppSettingProps /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') - _$$AppSettingImplCopyWith<_$AppSettingImpl> get copyWith => - __$$AppSettingImplCopyWithImpl<_$AppSettingImpl>(this, _$identity); + _$$AppSettingPropsImplCopyWith<_$AppSettingPropsImpl> get copyWith => + __$$AppSettingPropsImplCopyWithImpl<_$AppSettingPropsImpl>( + this, _$identity); @override Map toJson() { - return _$$AppSettingImplToJson( + return _$$AppSettingPropsImplToJson( this, ); } } -abstract class _AppSetting implements AppSetting { - const factory _AppSetting( +abstract class _AppSettingProps implements AppSettingProps { + const factory _AppSettingProps( {final String? locale, - @JsonKey(fromJson: dashboardWidgetsRealFormJson) + @JsonKey(fromJson: dashboardWidgetsSafeFormJson) final List dashboardWidgets, final bool onlyStatisticsProxy, final bool autoLaunch, @@ -458,15 +459,15 @@ abstract class _AppSetting implements AppSetting { final bool showLabel, final bool disclaimerAccepted, final bool minimizeOnExit, - final bool hidden}) = _$AppSettingImpl; + final bool hidden}) = _$AppSettingPropsImpl; - factory _AppSetting.fromJson(Map json) = - _$AppSettingImpl.fromJson; + factory _AppSettingProps.fromJson(Map json) = + _$AppSettingPropsImpl.fromJson; @override String? get locale; @override - @JsonKey(fromJson: dashboardWidgetsRealFormJson) + @JsonKey(fromJson: dashboardWidgetsSafeFormJson) List get dashboardWidgets; @override bool get onlyStatisticsProxy; @@ -495,11 +496,11 @@ abstract class _AppSetting implements AppSetting { @override bool get hidden; - /// Create a copy of AppSetting + /// Create a copy of AppSettingProps /// with the given fields replaced by the non-null parameter values. @override @JsonKey(includeFromJson: false, includeToJson: false) - _$$AppSettingImplCopyWith<_$AppSettingImpl> get copyWith => + _$$AppSettingPropsImplCopyWith<_$AppSettingPropsImpl> get copyWith => throw _privateConstructorUsedError; } @@ -509,6 +510,7 @@ AccessControl _$AccessControlFromJson(Map json) { /// @nodoc mixin _$AccessControl { + bool get enable => throw _privateConstructorUsedError; AccessControlMode get mode => throw _privateConstructorUsedError; List get acceptList => throw _privateConstructorUsedError; List get rejectList => throw _privateConstructorUsedError; @@ -532,7 +534,8 @@ abstract class $AccessControlCopyWith<$Res> { _$AccessControlCopyWithImpl<$Res, AccessControl>; @useResult $Res call( - {AccessControlMode mode, + {bool enable, + AccessControlMode mode, List acceptList, List rejectList, AccessSortType sort, @@ -554,6 +557,7 @@ class _$AccessControlCopyWithImpl<$Res, $Val extends AccessControl> @pragma('vm:prefer-inline') @override $Res call({ + Object? enable = null, Object? mode = null, Object? acceptList = null, Object? rejectList = null, @@ -561,6 +565,10 @@ class _$AccessControlCopyWithImpl<$Res, $Val extends AccessControl> Object? isFilterSystemApp = null, }) { return _then(_value.copyWith( + enable: null == enable + ? _value.enable + : enable // ignore: cast_nullable_to_non_nullable + as bool, mode: null == mode ? _value.mode : mode // ignore: cast_nullable_to_non_nullable @@ -594,7 +602,8 @@ abstract class _$$AccessControlImplCopyWith<$Res> @override @useResult $Res call( - {AccessControlMode mode, + {bool enable, + AccessControlMode mode, List acceptList, List rejectList, AccessSortType sort, @@ -614,6 +623,7 @@ class __$$AccessControlImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ + Object? enable = null, Object? mode = null, Object? acceptList = null, Object? rejectList = null, @@ -621,6 +631,10 @@ class __$$AccessControlImplCopyWithImpl<$Res> Object? isFilterSystemApp = null, }) { return _then(_$AccessControlImpl( + enable: null == enable + ? _value.enable + : enable // ignore: cast_nullable_to_non_nullable + as bool, mode: null == mode ? _value.mode : mode // ignore: cast_nullable_to_non_nullable @@ -649,7 +663,8 @@ class __$$AccessControlImplCopyWithImpl<$Res> @JsonSerializable() class _$AccessControlImpl implements _AccessControl { const _$AccessControlImpl( - {this.mode = AccessControlMode.rejectSelected, + {this.enable = false, + this.mode = AccessControlMode.rejectSelected, final List acceptList = const [], final List rejectList = const [], this.sort = AccessSortType.none, @@ -660,6 +675,9 @@ class _$AccessControlImpl implements _AccessControl { factory _$AccessControlImpl.fromJson(Map json) => _$$AccessControlImplFromJson(json); + @override + @JsonKey() + final bool enable; @override @JsonKey() final AccessControlMode mode; @@ -690,7 +708,7 @@ class _$AccessControlImpl implements _AccessControl { @override String toString() { - return 'AccessControl(mode: $mode, acceptList: $acceptList, rejectList: $rejectList, sort: $sort, isFilterSystemApp: $isFilterSystemApp)'; + return 'AccessControl(enable: $enable, mode: $mode, acceptList: $acceptList, rejectList: $rejectList, sort: $sort, isFilterSystemApp: $isFilterSystemApp)'; } @override @@ -698,6 +716,7 @@ class _$AccessControlImpl implements _AccessControl { return identical(this, other) || (other.runtimeType == runtimeType && other is _$AccessControlImpl && + (identical(other.enable, enable) || other.enable == enable) && (identical(other.mode, mode) || other.mode == mode) && const DeepCollectionEquality() .equals(other._acceptList, _acceptList) && @@ -712,6 +731,7 @@ class _$AccessControlImpl implements _AccessControl { @override int get hashCode => Object.hash( runtimeType, + enable, mode, const DeepCollectionEquality().hash(_acceptList), const DeepCollectionEquality().hash(_rejectList), @@ -736,7 +756,8 @@ class _$AccessControlImpl implements _AccessControl { abstract class _AccessControl implements AccessControl { const factory _AccessControl( - {final AccessControlMode mode, + {final bool enable, + final AccessControlMode mode, final List acceptList, final List rejectList, final AccessSortType sort, @@ -745,6 +766,8 @@ abstract class _AccessControl implements AccessControl { factory _AccessControl.fromJson(Map json) = _$AccessControlImpl.fromJson; + @override + bool get enable; @override AccessControlMode get mode; @override @@ -978,6 +1001,7 @@ mixin _$VpnProps { bool get systemProxy => throw _privateConstructorUsedError; bool get ipv6 => throw _privateConstructorUsedError; bool get allowBypass => throw _privateConstructorUsedError; + AccessControl get accessControl => throw _privateConstructorUsedError; /// Serializes this VpnProps to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -994,7 +1018,14 @@ abstract class $VpnPropsCopyWith<$Res> { factory $VpnPropsCopyWith(VpnProps value, $Res Function(VpnProps) then) = _$VpnPropsCopyWithImpl<$Res, VpnProps>; @useResult - $Res call({bool enable, bool systemProxy, bool ipv6, bool allowBypass}); + $Res call( + {bool enable, + bool systemProxy, + bool ipv6, + bool allowBypass, + AccessControl accessControl}); + + $AccessControlCopyWith<$Res> get accessControl; } /// @nodoc @@ -1016,6 +1047,7 @@ class _$VpnPropsCopyWithImpl<$Res, $Val extends VpnProps> Object? systemProxy = null, Object? ipv6 = null, Object? allowBypass = null, + Object? accessControl = null, }) { return _then(_value.copyWith( enable: null == enable @@ -1034,8 +1066,22 @@ class _$VpnPropsCopyWithImpl<$Res, $Val extends VpnProps> ? _value.allowBypass : allowBypass // ignore: cast_nullable_to_non_nullable as bool, + accessControl: null == accessControl + ? _value.accessControl + : accessControl // ignore: cast_nullable_to_non_nullable + as AccessControl, ) as $Val); } + + /// Create a copy of VpnProps + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AccessControlCopyWith<$Res> get accessControl { + return $AccessControlCopyWith<$Res>(_value.accessControl, (value) { + return _then(_value.copyWith(accessControl: value) as $Val); + }); + } } /// @nodoc @@ -1046,7 +1092,15 @@ abstract class _$$VpnPropsImplCopyWith<$Res> __$$VpnPropsImplCopyWithImpl<$Res>; @override @useResult - $Res call({bool enable, bool systemProxy, bool ipv6, bool allowBypass}); + $Res call( + {bool enable, + bool systemProxy, + bool ipv6, + bool allowBypass, + AccessControl accessControl}); + + @override + $AccessControlCopyWith<$Res> get accessControl; } /// @nodoc @@ -1066,6 +1120,7 @@ class __$$VpnPropsImplCopyWithImpl<$Res> Object? systemProxy = null, Object? ipv6 = null, Object? allowBypass = null, + Object? accessControl = null, }) { return _then(_$VpnPropsImpl( enable: null == enable @@ -1084,6 +1139,10 @@ class __$$VpnPropsImplCopyWithImpl<$Res> ? _value.allowBypass : allowBypass // ignore: cast_nullable_to_non_nullable as bool, + accessControl: null == accessControl + ? _value.accessControl + : accessControl // ignore: cast_nullable_to_non_nullable + as AccessControl, )); } } @@ -1095,7 +1154,8 @@ class _$VpnPropsImpl implements _VpnProps { {this.enable = true, this.systemProxy = true, this.ipv6 = false, - this.allowBypass = true}); + this.allowBypass = true, + this.accessControl = defaultAccessControl}); factory _$VpnPropsImpl.fromJson(Map json) => _$$VpnPropsImplFromJson(json); @@ -1112,10 +1172,13 @@ class _$VpnPropsImpl implements _VpnProps { @override @JsonKey() final bool allowBypass; + @override + @JsonKey() + final AccessControl accessControl; @override String toString() { - return 'VpnProps(enable: $enable, systemProxy: $systemProxy, ipv6: $ipv6, allowBypass: $allowBypass)'; + return 'VpnProps(enable: $enable, systemProxy: $systemProxy, ipv6: $ipv6, allowBypass: $allowBypass, accessControl: $accessControl)'; } @override @@ -1128,13 +1191,15 @@ class _$VpnPropsImpl implements _VpnProps { other.systemProxy == systemProxy) && (identical(other.ipv6, ipv6) || other.ipv6 == ipv6) && (identical(other.allowBypass, allowBypass) || - other.allowBypass == allowBypass)); + other.allowBypass == allowBypass) && + (identical(other.accessControl, accessControl) || + other.accessControl == accessControl)); } @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => - Object.hash(runtimeType, enable, systemProxy, ipv6, allowBypass); + int get hashCode => Object.hash( + runtimeType, enable, systemProxy, ipv6, allowBypass, accessControl); /// Create a copy of VpnProps /// with the given fields replaced by the non-null parameter values. @@ -1157,7 +1222,8 @@ abstract class _VpnProps implements VpnProps { {final bool enable, final bool systemProxy, final bool ipv6, - final bool allowBypass}) = _$VpnPropsImpl; + final bool allowBypass, + final AccessControl accessControl}) = _$VpnPropsImpl; factory _VpnProps.fromJson(Map json) = _$VpnPropsImpl.fromJson; @@ -1170,6 +1236,8 @@ abstract class _VpnProps implements VpnProps { bool get ipv6; @override bool get allowBypass; + @override + AccessControl get accessControl; /// Create a copy of VpnProps /// with the given fields replaced by the non-null parameter values. @@ -1187,6 +1255,7 @@ NetworkProps _$NetworkPropsFromJson(Map json) { mixin _$NetworkProps { bool get systemProxy => throw _privateConstructorUsedError; List get bypassDomain => throw _privateConstructorUsedError; + RouteMode get routeMode => throw _privateConstructorUsedError; /// Serializes this NetworkProps to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -1204,7 +1273,7 @@ abstract class $NetworkPropsCopyWith<$Res> { NetworkProps value, $Res Function(NetworkProps) then) = _$NetworkPropsCopyWithImpl<$Res, NetworkProps>; @useResult - $Res call({bool systemProxy, List bypassDomain}); + $Res call({bool systemProxy, List bypassDomain, RouteMode routeMode}); } /// @nodoc @@ -1224,6 +1293,7 @@ class _$NetworkPropsCopyWithImpl<$Res, $Val extends NetworkProps> $Res call({ Object? systemProxy = null, Object? bypassDomain = null, + Object? routeMode = null, }) { return _then(_value.copyWith( systemProxy: null == systemProxy @@ -1234,6 +1304,10 @@ class _$NetworkPropsCopyWithImpl<$Res, $Val extends NetworkProps> ? _value.bypassDomain : bypassDomain // ignore: cast_nullable_to_non_nullable as List, + routeMode: null == routeMode + ? _value.routeMode + : routeMode // ignore: cast_nullable_to_non_nullable + as RouteMode, ) as $Val); } } @@ -1246,7 +1320,7 @@ abstract class _$$NetworkPropsImplCopyWith<$Res> __$$NetworkPropsImplCopyWithImpl<$Res>; @override @useResult - $Res call({bool systemProxy, List bypassDomain}); + $Res call({bool systemProxy, List bypassDomain, RouteMode routeMode}); } /// @nodoc @@ -1264,6 +1338,7 @@ class __$$NetworkPropsImplCopyWithImpl<$Res> $Res call({ Object? systemProxy = null, Object? bypassDomain = null, + Object? routeMode = null, }) { return _then(_$NetworkPropsImpl( systemProxy: null == systemProxy @@ -1274,6 +1349,10 @@ class __$$NetworkPropsImplCopyWithImpl<$Res> ? _value._bypassDomain : bypassDomain // ignore: cast_nullable_to_non_nullable as List, + routeMode: null == routeMode + ? _value.routeMode + : routeMode // ignore: cast_nullable_to_non_nullable + as RouteMode, )); } } @@ -1283,7 +1362,8 @@ class __$$NetworkPropsImplCopyWithImpl<$Res> class _$NetworkPropsImpl implements _NetworkProps { const _$NetworkPropsImpl( {this.systemProxy = true, - final List bypassDomain = defaultBypassDomain}) + final List bypassDomain = defaultBypassDomain, + this.routeMode = RouteMode.bypassPrivate}) : _bypassDomain = bypassDomain; factory _$NetworkPropsImpl.fromJson(Map json) => @@ -1301,9 +1381,13 @@ class _$NetworkPropsImpl implements _NetworkProps { return EqualUnmodifiableListView(_bypassDomain); } + @override + @JsonKey() + final RouteMode routeMode; + @override String toString() { - return 'NetworkProps(systemProxy: $systemProxy, bypassDomain: $bypassDomain)'; + return 'NetworkProps(systemProxy: $systemProxy, bypassDomain: $bypassDomain, routeMode: $routeMode)'; } @override @@ -1314,13 +1398,15 @@ class _$NetworkPropsImpl implements _NetworkProps { (identical(other.systemProxy, systemProxy) || other.systemProxy == systemProxy) && const DeepCollectionEquality() - .equals(other._bypassDomain, _bypassDomain)); + .equals(other._bypassDomain, _bypassDomain) && + (identical(other.routeMode, routeMode) || + other.routeMode == routeMode)); } @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash(runtimeType, systemProxy, - const DeepCollectionEquality().hash(_bypassDomain)); + const DeepCollectionEquality().hash(_bypassDomain), routeMode); /// Create a copy of NetworkProps /// with the given fields replaced by the non-null parameter values. @@ -1341,7 +1427,8 @@ class _$NetworkPropsImpl implements _NetworkProps { abstract class _NetworkProps implements NetworkProps { const factory _NetworkProps( {final bool systemProxy, - final List bypassDomain}) = _$NetworkPropsImpl; + final List bypassDomain, + final RouteMode routeMode}) = _$NetworkPropsImpl; factory _NetworkProps.fromJson(Map json) = _$NetworkPropsImpl.fromJson; @@ -1350,6 +1437,8 @@ abstract class _NetworkProps implements NetworkProps { bool get systemProxy; @override List get bypassDomain; + @override + RouteMode get routeMode; /// Create a copy of NetworkProps /// with the given fields replaced by the non-null parameter values. @@ -1848,3 +1937,538 @@ abstract class _ThemeProps implements ThemeProps { _$$ThemePropsImplCopyWith<_$ThemePropsImpl> get copyWith => throw _privateConstructorUsedError; } + +Config _$ConfigFromJson(Map json) { + return _Config.fromJson(json); +} + +/// @nodoc +mixin _$Config { + @JsonKey(fromJson: AppSettingProps.safeFromJson) + AppSettingProps get appSetting => throw _privateConstructorUsedError; + List get profiles => throw _privateConstructorUsedError; + List get hotKeyActions => throw _privateConstructorUsedError; + String? get currentProfileId => throw _privateConstructorUsedError; + bool get overrideDns => throw _privateConstructorUsedError; + DAV? get dav => throw _privateConstructorUsedError; + NetworkProps get networkProps => throw _privateConstructorUsedError; + VpnProps get vpnProps => throw _privateConstructorUsedError; + @JsonKey(fromJson: ThemeProps.safeFromJson) + ThemeProps get themeProps => throw _privateConstructorUsedError; + ProxiesStyle get proxiesStyle => throw _privateConstructorUsedError; + WindowProps get windowProps => throw _privateConstructorUsedError; + ClashConfig get patchClashConfig => throw _privateConstructorUsedError; + + /// Serializes this Config to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of Config + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ConfigCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ConfigCopyWith<$Res> { + factory $ConfigCopyWith(Config value, $Res Function(Config) then) = + _$ConfigCopyWithImpl<$Res, Config>; + @useResult + $Res call( + {@JsonKey(fromJson: AppSettingProps.safeFromJson) + AppSettingProps appSetting, + List profiles, + List hotKeyActions, + String? currentProfileId, + bool overrideDns, + DAV? dav, + NetworkProps networkProps, + VpnProps vpnProps, + @JsonKey(fromJson: ThemeProps.safeFromJson) ThemeProps themeProps, + ProxiesStyle proxiesStyle, + WindowProps windowProps, + ClashConfig patchClashConfig}); + + $AppSettingPropsCopyWith<$Res> get appSetting; + $DAVCopyWith<$Res>? get dav; + $NetworkPropsCopyWith<$Res> get networkProps; + $VpnPropsCopyWith<$Res> get vpnProps; + $ThemePropsCopyWith<$Res> get themeProps; + $ProxiesStyleCopyWith<$Res> get proxiesStyle; + $WindowPropsCopyWith<$Res> get windowProps; + $ClashConfigCopyWith<$Res> get patchClashConfig; +} + +/// @nodoc +class _$ConfigCopyWithImpl<$Res, $Val extends Config> + implements $ConfigCopyWith<$Res> { + _$ConfigCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of Config + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? appSetting = null, + Object? profiles = null, + Object? hotKeyActions = null, + Object? currentProfileId = freezed, + Object? overrideDns = null, + Object? dav = freezed, + Object? networkProps = null, + Object? vpnProps = null, + Object? themeProps = null, + Object? proxiesStyle = null, + Object? windowProps = null, + Object? patchClashConfig = null, + }) { + return _then(_value.copyWith( + appSetting: null == appSetting + ? _value.appSetting + : appSetting // ignore: cast_nullable_to_non_nullable + as AppSettingProps, + profiles: null == profiles + ? _value.profiles + : profiles // ignore: cast_nullable_to_non_nullable + as List, + hotKeyActions: null == hotKeyActions + ? _value.hotKeyActions + : hotKeyActions // ignore: cast_nullable_to_non_nullable + as List, + currentProfileId: freezed == currentProfileId + ? _value.currentProfileId + : currentProfileId // ignore: cast_nullable_to_non_nullable + as String?, + overrideDns: null == overrideDns + ? _value.overrideDns + : overrideDns // ignore: cast_nullable_to_non_nullable + as bool, + dav: freezed == dav + ? _value.dav + : dav // ignore: cast_nullable_to_non_nullable + as DAV?, + networkProps: null == networkProps + ? _value.networkProps + : networkProps // ignore: cast_nullable_to_non_nullable + as NetworkProps, + vpnProps: null == vpnProps + ? _value.vpnProps + : vpnProps // ignore: cast_nullable_to_non_nullable + as VpnProps, + themeProps: null == themeProps + ? _value.themeProps + : themeProps // ignore: cast_nullable_to_non_nullable + as ThemeProps, + proxiesStyle: null == proxiesStyle + ? _value.proxiesStyle + : proxiesStyle // ignore: cast_nullable_to_non_nullable + as ProxiesStyle, + windowProps: null == windowProps + ? _value.windowProps + : windowProps // ignore: cast_nullable_to_non_nullable + as WindowProps, + patchClashConfig: null == patchClashConfig + ? _value.patchClashConfig + : patchClashConfig // ignore: cast_nullable_to_non_nullable + as ClashConfig, + ) as $Val); + } + + /// Create a copy of Config + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AppSettingPropsCopyWith<$Res> get appSetting { + return $AppSettingPropsCopyWith<$Res>(_value.appSetting, (value) { + return _then(_value.copyWith(appSetting: value) as $Val); + }); + } + + /// Create a copy of Config + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $DAVCopyWith<$Res>? get dav { + if (_value.dav == null) { + return null; + } + + return $DAVCopyWith<$Res>(_value.dav!, (value) { + return _then(_value.copyWith(dav: value) as $Val); + }); + } + + /// Create a copy of Config + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $NetworkPropsCopyWith<$Res> get networkProps { + return $NetworkPropsCopyWith<$Res>(_value.networkProps, (value) { + return _then(_value.copyWith(networkProps: value) as $Val); + }); + } + + /// Create a copy of Config + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $VpnPropsCopyWith<$Res> get vpnProps { + return $VpnPropsCopyWith<$Res>(_value.vpnProps, (value) { + return _then(_value.copyWith(vpnProps: value) as $Val); + }); + } + + /// Create a copy of Config + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $ThemePropsCopyWith<$Res> get themeProps { + return $ThemePropsCopyWith<$Res>(_value.themeProps, (value) { + return _then(_value.copyWith(themeProps: value) as $Val); + }); + } + + /// Create a copy of Config + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $ProxiesStyleCopyWith<$Res> get proxiesStyle { + return $ProxiesStyleCopyWith<$Res>(_value.proxiesStyle, (value) { + return _then(_value.copyWith(proxiesStyle: value) as $Val); + }); + } + + /// Create a copy of Config + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $WindowPropsCopyWith<$Res> get windowProps { + return $WindowPropsCopyWith<$Res>(_value.windowProps, (value) { + return _then(_value.copyWith(windowProps: value) as $Val); + }); + } + + /// Create a copy of Config + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $ClashConfigCopyWith<$Res> get patchClashConfig { + return $ClashConfigCopyWith<$Res>(_value.patchClashConfig, (value) { + return _then(_value.copyWith(patchClashConfig: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$ConfigImplCopyWith<$Res> implements $ConfigCopyWith<$Res> { + factory _$$ConfigImplCopyWith( + _$ConfigImpl value, $Res Function(_$ConfigImpl) then) = + __$$ConfigImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@JsonKey(fromJson: AppSettingProps.safeFromJson) + AppSettingProps appSetting, + List profiles, + List hotKeyActions, + String? currentProfileId, + bool overrideDns, + DAV? dav, + NetworkProps networkProps, + VpnProps vpnProps, + @JsonKey(fromJson: ThemeProps.safeFromJson) ThemeProps themeProps, + ProxiesStyle proxiesStyle, + WindowProps windowProps, + ClashConfig patchClashConfig}); + + @override + $AppSettingPropsCopyWith<$Res> get appSetting; + @override + $DAVCopyWith<$Res>? get dav; + @override + $NetworkPropsCopyWith<$Res> get networkProps; + @override + $VpnPropsCopyWith<$Res> get vpnProps; + @override + $ThemePropsCopyWith<$Res> get themeProps; + @override + $ProxiesStyleCopyWith<$Res> get proxiesStyle; + @override + $WindowPropsCopyWith<$Res> get windowProps; + @override + $ClashConfigCopyWith<$Res> get patchClashConfig; +} + +/// @nodoc +class __$$ConfigImplCopyWithImpl<$Res> + extends _$ConfigCopyWithImpl<$Res, _$ConfigImpl> + implements _$$ConfigImplCopyWith<$Res> { + __$$ConfigImplCopyWithImpl( + _$ConfigImpl _value, $Res Function(_$ConfigImpl) _then) + : super(_value, _then); + + /// Create a copy of Config + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? appSetting = null, + Object? profiles = null, + Object? hotKeyActions = null, + Object? currentProfileId = freezed, + Object? overrideDns = null, + Object? dav = freezed, + Object? networkProps = null, + Object? vpnProps = null, + Object? themeProps = null, + Object? proxiesStyle = null, + Object? windowProps = null, + Object? patchClashConfig = null, + }) { + return _then(_$ConfigImpl( + appSetting: null == appSetting + ? _value.appSetting + : appSetting // ignore: cast_nullable_to_non_nullable + as AppSettingProps, + profiles: null == profiles + ? _value._profiles + : profiles // ignore: cast_nullable_to_non_nullable + as List, + hotKeyActions: null == hotKeyActions + ? _value._hotKeyActions + : hotKeyActions // ignore: cast_nullable_to_non_nullable + as List, + currentProfileId: freezed == currentProfileId + ? _value.currentProfileId + : currentProfileId // ignore: cast_nullable_to_non_nullable + as String?, + overrideDns: null == overrideDns + ? _value.overrideDns + : overrideDns // ignore: cast_nullable_to_non_nullable + as bool, + dav: freezed == dav + ? _value.dav + : dav // ignore: cast_nullable_to_non_nullable + as DAV?, + networkProps: null == networkProps + ? _value.networkProps + : networkProps // ignore: cast_nullable_to_non_nullable + as NetworkProps, + vpnProps: null == vpnProps + ? _value.vpnProps + : vpnProps // ignore: cast_nullable_to_non_nullable + as VpnProps, + themeProps: null == themeProps + ? _value.themeProps + : themeProps // ignore: cast_nullable_to_non_nullable + as ThemeProps, + proxiesStyle: null == proxiesStyle + ? _value.proxiesStyle + : proxiesStyle // ignore: cast_nullable_to_non_nullable + as ProxiesStyle, + windowProps: null == windowProps + ? _value.windowProps + : windowProps // ignore: cast_nullable_to_non_nullable + as WindowProps, + patchClashConfig: null == patchClashConfig + ? _value.patchClashConfig + : patchClashConfig // ignore: cast_nullable_to_non_nullable + as ClashConfig, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ConfigImpl implements _Config { + const _$ConfigImpl( + {@JsonKey(fromJson: AppSettingProps.safeFromJson) + this.appSetting = defaultAppSettingProps, + final List profiles = const [], + final List hotKeyActions = const [], + this.currentProfileId, + this.overrideDns = false, + this.dav, + this.networkProps = defaultNetworkProps, + this.vpnProps = defaultVpnProps, + @JsonKey(fromJson: ThemeProps.safeFromJson) required this.themeProps, + this.proxiesStyle = defaultProxiesStyle, + this.windowProps = defaultWindowProps, + this.patchClashConfig = defaultClashConfig}) + : _profiles = profiles, + _hotKeyActions = hotKeyActions; + + factory _$ConfigImpl.fromJson(Map json) => + _$$ConfigImplFromJson(json); + + @override + @JsonKey(fromJson: AppSettingProps.safeFromJson) + final AppSettingProps appSetting; + final List _profiles; + @override + @JsonKey() + List get profiles { + if (_profiles is EqualUnmodifiableListView) return _profiles; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_profiles); + } + + final List _hotKeyActions; + @override + @JsonKey() + List get hotKeyActions { + if (_hotKeyActions is EqualUnmodifiableListView) return _hotKeyActions; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_hotKeyActions); + } + + @override + final String? currentProfileId; + @override + @JsonKey() + final bool overrideDns; + @override + final DAV? dav; + @override + @JsonKey() + final NetworkProps networkProps; + @override + @JsonKey() + final VpnProps vpnProps; + @override + @JsonKey(fromJson: ThemeProps.safeFromJson) + final ThemeProps themeProps; + @override + @JsonKey() + final ProxiesStyle proxiesStyle; + @override + @JsonKey() + final WindowProps windowProps; + @override + @JsonKey() + final ClashConfig patchClashConfig; + + @override + String toString() { + return 'Config(appSetting: $appSetting, profiles: $profiles, hotKeyActions: $hotKeyActions, currentProfileId: $currentProfileId, overrideDns: $overrideDns, dav: $dav, networkProps: $networkProps, vpnProps: $vpnProps, themeProps: $themeProps, proxiesStyle: $proxiesStyle, windowProps: $windowProps, patchClashConfig: $patchClashConfig)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ConfigImpl && + (identical(other.appSetting, appSetting) || + other.appSetting == appSetting) && + const DeepCollectionEquality().equals(other._profiles, _profiles) && + const DeepCollectionEquality() + .equals(other._hotKeyActions, _hotKeyActions) && + (identical(other.currentProfileId, currentProfileId) || + other.currentProfileId == currentProfileId) && + (identical(other.overrideDns, overrideDns) || + other.overrideDns == overrideDns) && + (identical(other.dav, dav) || other.dav == dav) && + (identical(other.networkProps, networkProps) || + other.networkProps == networkProps) && + (identical(other.vpnProps, vpnProps) || + other.vpnProps == vpnProps) && + (identical(other.themeProps, themeProps) || + other.themeProps == themeProps) && + (identical(other.proxiesStyle, proxiesStyle) || + other.proxiesStyle == proxiesStyle) && + (identical(other.windowProps, windowProps) || + other.windowProps == windowProps) && + (identical(other.patchClashConfig, patchClashConfig) || + other.patchClashConfig == patchClashConfig)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + appSetting, + const DeepCollectionEquality().hash(_profiles), + const DeepCollectionEquality().hash(_hotKeyActions), + currentProfileId, + overrideDns, + dav, + networkProps, + vpnProps, + themeProps, + proxiesStyle, + windowProps, + patchClashConfig); + + /// Create a copy of Config + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ConfigImplCopyWith<_$ConfigImpl> get copyWith => + __$$ConfigImplCopyWithImpl<_$ConfigImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ConfigImplToJson( + this, + ); + } +} + +abstract class _Config implements Config { + const factory _Config( + {@JsonKey(fromJson: AppSettingProps.safeFromJson) + final AppSettingProps appSetting, + final List profiles, + final List hotKeyActions, + final String? currentProfileId, + final bool overrideDns, + final DAV? dav, + final NetworkProps networkProps, + final VpnProps vpnProps, + @JsonKey(fromJson: ThemeProps.safeFromJson) + required final ThemeProps themeProps, + final ProxiesStyle proxiesStyle, + final WindowProps windowProps, + final ClashConfig patchClashConfig}) = _$ConfigImpl; + + factory _Config.fromJson(Map json) = _$ConfigImpl.fromJson; + + @override + @JsonKey(fromJson: AppSettingProps.safeFromJson) + AppSettingProps get appSetting; + @override + List get profiles; + @override + List get hotKeyActions; + @override + String? get currentProfileId; + @override + bool get overrideDns; + @override + DAV? get dav; + @override + NetworkProps get networkProps; + @override + VpnProps get vpnProps; + @override + @JsonKey(fromJson: ThemeProps.safeFromJson) + ThemeProps get themeProps; + @override + ProxiesStyle get proxiesStyle; + @override + WindowProps get windowProps; + @override + ClashConfig get patchClashConfig; + + /// Create a copy of Config + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ConfigImplCopyWith<_$ConfigImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/generated/config.g.dart b/lib/models/generated/config.g.dart index 5c9e27b..9f1a589 100644 --- a/lib/models/generated/config.g.dart +++ b/lib/models/generated/config.g.dart @@ -6,57 +6,13 @@ part of '../config.dart'; // JsonSerializableGenerator // ************************************************************************** -Config _$ConfigFromJson(Map json) => Config() - ..appSetting = - AppSetting.realFromJson(json['appSetting'] as Map?) - ..profiles = (json['profiles'] as List?) - ?.map((e) => Profile.fromJson(e as Map)) - .toList() ?? - [] - ..currentProfileId = json['currentProfileId'] as String? - ..isAccessControl = json['isAccessControl'] as bool? ?? false - ..accessControl = - AccessControl.fromJson(json['accessControl'] as Map) - ..dav = json['dav'] == null - ? null - : DAV.fromJson(json['dav'] as Map) - ..windowProps = - WindowProps.fromJson(json['windowProps'] as Map?) - ..vpnProps = VpnProps.fromJson(json['vpnProps'] as Map?) - ..networkProps = - NetworkProps.fromJson(json['networkProps'] as Map?) - ..overrideDns = json['overrideDns'] as bool? ?? false - ..hotKeyActions = (json['hotKeyActions'] as List?) - ?.map((e) => HotKeyAction.fromJson(e as Map)) - .toList() ?? - [] - ..proxiesStyle = - ProxiesStyle.fromJson(json['proxiesStyle'] as Map?) - ..themeProps = - ThemeProps.realFromJson(json['themeProps'] as Map?); - -Map _$ConfigToJson(Config instance) => { - 'appSetting': instance.appSetting, - 'profiles': instance.profiles, - 'currentProfileId': instance.currentProfileId, - 'isAccessControl': instance.isAccessControl, - 'accessControl': instance.accessControl, - 'dav': instance.dav, - 'windowProps': instance.windowProps, - 'vpnProps': instance.vpnProps, - 'networkProps': instance.networkProps, - 'overrideDns': instance.overrideDns, - 'hotKeyActions': instance.hotKeyActions, - 'proxiesStyle': instance.proxiesStyle, - 'themeProps': instance.themeProps, - }; - -_$AppSettingImpl _$$AppSettingImplFromJson(Map json) => - _$AppSettingImpl( +_$AppSettingPropsImpl _$$AppSettingPropsImplFromJson( + Map json) => + _$AppSettingPropsImpl( locale: json['locale'] as String?, dashboardWidgets: json['dashboardWidgets'] == null ? defaultDashboardWidgets - : dashboardWidgetsRealFormJson(json['dashboardWidgets'] as List?), + : dashboardWidgetsSafeFormJson(json['dashboardWidgets'] as List?), onlyStatisticsProxy: json['onlyStatisticsProxy'] as bool? ?? false, autoLaunch: json['autoLaunch'] as bool? ?? false, silentLaunch: json['silentLaunch'] as bool? ?? false, @@ -72,7 +28,8 @@ _$AppSettingImpl _$$AppSettingImplFromJson(Map json) => hidden: json['hidden'] as bool? ?? false, ); -Map _$$AppSettingImplToJson(_$AppSettingImpl instance) => +Map _$$AppSettingPropsImplToJson( + _$AppSettingPropsImpl instance) => { 'locale': instance.locale, 'dashboardWidgets': instance.dashboardWidgets @@ -106,6 +63,7 @@ const _$DashboardWidgetEnumMap = { _$AccessControlImpl _$$AccessControlImplFromJson(Map json) => _$AccessControlImpl( + enable: json['enable'] as bool? ?? false, mode: $enumDecodeNullable(_$AccessControlModeEnumMap, json['mode']) ?? AccessControlMode.rejectSelected, acceptList: (json['acceptList'] as List?) @@ -123,6 +81,7 @@ _$AccessControlImpl _$$AccessControlImplFromJson(Map json) => Map _$$AccessControlImplToJson(_$AccessControlImpl instance) => { + 'enable': instance.enable, 'mode': _$AccessControlModeEnumMap[instance.mode]!, 'acceptList': instance.acceptList, 'rejectList': instance.rejectList, @@ -163,6 +122,10 @@ _$VpnPropsImpl _$$VpnPropsImplFromJson(Map json) => systemProxy: json['systemProxy'] as bool? ?? true, ipv6: json['ipv6'] as bool? ?? false, allowBypass: json['allowBypass'] as bool? ?? true, + accessControl: json['accessControl'] == null + ? defaultAccessControl + : AccessControl.fromJson( + json['accessControl'] as Map), ); Map _$$VpnPropsImplToJson(_$VpnPropsImpl instance) => @@ -171,6 +134,7 @@ Map _$$VpnPropsImplToJson(_$VpnPropsImpl instance) => 'systemProxy': instance.systemProxy, 'ipv6': instance.ipv6, 'allowBypass': instance.allowBypass, + 'accessControl': instance.accessControl, }; _$NetworkPropsImpl _$$NetworkPropsImplFromJson(Map json) => @@ -180,14 +144,22 @@ _$NetworkPropsImpl _$$NetworkPropsImplFromJson(Map json) => ?.map((e) => e as String) .toList() ?? defaultBypassDomain, + routeMode: $enumDecodeNullable(_$RouteModeEnumMap, json['routeMode']) ?? + RouteMode.bypassPrivate, ); Map _$$NetworkPropsImplToJson(_$NetworkPropsImpl instance) => { 'systemProxy': instance.systemProxy, 'bypassDomain': instance.bypassDomain, + 'routeMode': _$RouteModeEnumMap[instance.routeMode]!, }; +const _$RouteModeEnumMap = { + RouteMode.bypassPrivate: 'bypassPrivate', + RouteMode.config: 'config', +}; + _$ProxiesStyleImpl _$$ProxiesStyleImplFromJson(Map json) => _$ProxiesStyleImpl( type: $enumDecodeNullable(_$ProxiesTypeEnumMap, json['type']) ?? @@ -278,3 +250,59 @@ const _$FontFamilyEnumMap = { FontFamily.twEmoji: 'twEmoji', FontFamily.icon: 'icon', }; + +_$ConfigImpl _$$ConfigImplFromJson(Map json) => _$ConfigImpl( + appSetting: json['appSetting'] == null + ? defaultAppSettingProps + : AppSettingProps.safeFromJson( + json['appSetting'] as Map?), + profiles: (json['profiles'] as List?) + ?.map((e) => Profile.fromJson(e as Map)) + .toList() ?? + const [], + hotKeyActions: (json['hotKeyActions'] as List?) + ?.map((e) => HotKeyAction.fromJson(e as Map)) + .toList() ?? + const [], + currentProfileId: json['currentProfileId'] as String?, + overrideDns: json['overrideDns'] as bool? ?? false, + dav: json['dav'] == null + ? null + : DAV.fromJson(json['dav'] as Map), + networkProps: json['networkProps'] == null + ? defaultNetworkProps + : NetworkProps.fromJson( + json['networkProps'] as Map?), + vpnProps: json['vpnProps'] == null + ? defaultVpnProps + : VpnProps.fromJson(json['vpnProps'] as Map?), + themeProps: + ThemeProps.safeFromJson(json['themeProps'] as Map?), + proxiesStyle: json['proxiesStyle'] == null + ? defaultProxiesStyle + : ProxiesStyle.fromJson( + json['proxiesStyle'] as Map?), + windowProps: json['windowProps'] == null + ? defaultWindowProps + : WindowProps.fromJson(json['windowProps'] as Map?), + patchClashConfig: json['patchClashConfig'] == null + ? defaultClashConfig + : ClashConfig.fromJson( + json['patchClashConfig'] as Map), + ); + +Map _$$ConfigImplToJson(_$ConfigImpl instance) => + { + 'appSetting': instance.appSetting, + 'profiles': instance.profiles, + 'hotKeyActions': instance.hotKeyActions, + 'currentProfileId': instance.currentProfileId, + 'overrideDns': instance.overrideDns, + 'dav': instance.dav, + 'networkProps': instance.networkProps, + 'vpnProps': instance.vpnProps, + 'themeProps': instance.themeProps, + 'proxiesStyle': instance.proxiesStyle, + 'windowProps': instance.windowProps, + 'patchClashConfig': instance.patchClashConfig, + }; diff --git a/lib/models/generated/core.freezed.dart b/lib/models/generated/core.freezed.dart index aa77900..7a6875f 100644 --- a/lib/models/generated/core.freezed.dart +++ b/lib/models/generated/core.freezed.dart @@ -20,14 +20,14 @@ CoreState _$CoreStateFromJson(Map json) { /// @nodoc mixin _$CoreState { - bool get enable => throw _privateConstructorUsedError; - AccessControl? get accessControl => throw _privateConstructorUsedError; + @JsonKey(name: "vpn-props") + VpnProps get vpnProps => throw _privateConstructorUsedError; + @JsonKey(name: "only-statistics-proxy") + bool get onlyStatisticsProxy => throw _privateConstructorUsedError; + @JsonKey(name: "current-profile-name") String get currentProfileName => throw _privateConstructorUsedError; - bool get allowBypass => throw _privateConstructorUsedError; - bool get systemProxy => throw _privateConstructorUsedError; + @JsonKey(name: "bypass-domain") List get bypassDomain => throw _privateConstructorUsedError; - List get routeAddress => throw _privateConstructorUsedError; - bool get ipv6 => throw _privateConstructorUsedError; /// Serializes this CoreState to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -45,16 +45,12 @@ abstract class $CoreStateCopyWith<$Res> { _$CoreStateCopyWithImpl<$Res, CoreState>; @useResult $Res call( - {bool enable, - AccessControl? accessControl, - String currentProfileName, - bool allowBypass, - bool systemProxy, - List bypassDomain, - List routeAddress, - bool ipv6}); + {@JsonKey(name: "vpn-props") VpnProps vpnProps, + @JsonKey(name: "only-statistics-proxy") bool onlyStatisticsProxy, + @JsonKey(name: "current-profile-name") String currentProfileName, + @JsonKey(name: "bypass-domain") List bypassDomain}); - $AccessControlCopyWith<$Res>? get accessControl; + $VpnPropsCopyWith<$Res> get vpnProps; } /// @nodoc @@ -72,48 +68,28 @@ class _$CoreStateCopyWithImpl<$Res, $Val extends CoreState> @pragma('vm:prefer-inline') @override $Res call({ - Object? enable = null, - Object? accessControl = freezed, + Object? vpnProps = null, + Object? onlyStatisticsProxy = null, Object? currentProfileName = null, - Object? allowBypass = null, - Object? systemProxy = null, Object? bypassDomain = null, - Object? routeAddress = null, - Object? ipv6 = null, }) { return _then(_value.copyWith( - enable: null == enable - ? _value.enable - : enable // ignore: cast_nullable_to_non_nullable + vpnProps: null == vpnProps + ? _value.vpnProps + : vpnProps // ignore: cast_nullable_to_non_nullable + as VpnProps, + onlyStatisticsProxy: null == onlyStatisticsProxy + ? _value.onlyStatisticsProxy + : onlyStatisticsProxy // ignore: cast_nullable_to_non_nullable as bool, - accessControl: freezed == accessControl - ? _value.accessControl - : accessControl // ignore: cast_nullable_to_non_nullable - as AccessControl?, currentProfileName: null == currentProfileName ? _value.currentProfileName : currentProfileName // ignore: cast_nullable_to_non_nullable as String, - allowBypass: null == allowBypass - ? _value.allowBypass - : allowBypass // ignore: cast_nullable_to_non_nullable - as bool, - systemProxy: null == systemProxy - ? _value.systemProxy - : systemProxy // ignore: cast_nullable_to_non_nullable - as bool, bypassDomain: null == bypassDomain ? _value.bypassDomain : bypassDomain // ignore: cast_nullable_to_non_nullable as List, - routeAddress: null == routeAddress - ? _value.routeAddress - : routeAddress // ignore: cast_nullable_to_non_nullable - as List, - ipv6: null == ipv6 - ? _value.ipv6 - : ipv6 // ignore: cast_nullable_to_non_nullable - as bool, ) as $Val); } @@ -121,13 +97,9 @@ class _$CoreStateCopyWithImpl<$Res, $Val extends CoreState> /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') - $AccessControlCopyWith<$Res>? get accessControl { - if (_value.accessControl == null) { - return null; - } - - return $AccessControlCopyWith<$Res>(_value.accessControl!, (value) { - return _then(_value.copyWith(accessControl: value) as $Val); + $VpnPropsCopyWith<$Res> get vpnProps { + return $VpnPropsCopyWith<$Res>(_value.vpnProps, (value) { + return _then(_value.copyWith(vpnProps: value) as $Val); }); } } @@ -141,17 +113,13 @@ abstract class _$$CoreStateImplCopyWith<$Res> @override @useResult $Res call( - {bool enable, - AccessControl? accessControl, - String currentProfileName, - bool allowBypass, - bool systemProxy, - List bypassDomain, - List routeAddress, - bool ipv6}); + {@JsonKey(name: "vpn-props") VpnProps vpnProps, + @JsonKey(name: "only-statistics-proxy") bool onlyStatisticsProxy, + @JsonKey(name: "current-profile-name") String currentProfileName, + @JsonKey(name: "bypass-domain") List bypassDomain}); @override - $AccessControlCopyWith<$Res>? get accessControl; + $VpnPropsCopyWith<$Res> get vpnProps; } /// @nodoc @@ -167,48 +135,28 @@ class __$$CoreStateImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? enable = null, - Object? accessControl = freezed, + Object? vpnProps = null, + Object? onlyStatisticsProxy = null, Object? currentProfileName = null, - Object? allowBypass = null, - Object? systemProxy = null, Object? bypassDomain = null, - Object? routeAddress = null, - Object? ipv6 = null, }) { return _then(_$CoreStateImpl( - enable: null == enable - ? _value.enable - : enable // ignore: cast_nullable_to_non_nullable + vpnProps: null == vpnProps + ? _value.vpnProps + : vpnProps // ignore: cast_nullable_to_non_nullable + as VpnProps, + onlyStatisticsProxy: null == onlyStatisticsProxy + ? _value.onlyStatisticsProxy + : onlyStatisticsProxy // ignore: cast_nullable_to_non_nullable as bool, - accessControl: freezed == accessControl - ? _value.accessControl - : accessControl // ignore: cast_nullable_to_non_nullable - as AccessControl?, currentProfileName: null == currentProfileName ? _value.currentProfileName : currentProfileName // ignore: cast_nullable_to_non_nullable as String, - allowBypass: null == allowBypass - ? _value.allowBypass - : allowBypass // ignore: cast_nullable_to_non_nullable - as bool, - systemProxy: null == systemProxy - ? _value.systemProxy - : systemProxy // ignore: cast_nullable_to_non_nullable - as bool, bypassDomain: null == bypassDomain ? _value._bypassDomain : bypassDomain // ignore: cast_nullable_to_non_nullable as List, - routeAddress: null == routeAddress - ? _value._routeAddress - : routeAddress // ignore: cast_nullable_to_non_nullable - as List, - ipv6: null == ipv6 - ? _value.ipv6 - : ipv6 // ignore: cast_nullable_to_non_nullable - as bool, )); } } @@ -217,52 +165,37 @@ class __$$CoreStateImplCopyWithImpl<$Res> @JsonSerializable() class _$CoreStateImpl implements _CoreState { const _$CoreStateImpl( - {required this.enable, - this.accessControl, - required this.currentProfileName, - required this.allowBypass, - required this.systemProxy, - required final List bypassDomain, - required final List routeAddress, - required this.ipv6}) - : _bypassDomain = bypassDomain, - _routeAddress = routeAddress; + {@JsonKey(name: "vpn-props") required this.vpnProps, + @JsonKey(name: "only-statistics-proxy") required this.onlyStatisticsProxy, + @JsonKey(name: "current-profile-name") required this.currentProfileName, + @JsonKey(name: "bypass-domain") + final List bypassDomain = const []}) + : _bypassDomain = bypassDomain; factory _$CoreStateImpl.fromJson(Map json) => _$$CoreStateImplFromJson(json); @override - final bool enable; + @JsonKey(name: "vpn-props") + final VpnProps vpnProps; @override - final AccessControl? accessControl; + @JsonKey(name: "only-statistics-proxy") + final bool onlyStatisticsProxy; @override + @JsonKey(name: "current-profile-name") final String currentProfileName; - @override - final bool allowBypass; - @override - final bool systemProxy; final List _bypassDomain; @override + @JsonKey(name: "bypass-domain") List get bypassDomain { if (_bypassDomain is EqualUnmodifiableListView) return _bypassDomain; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_bypassDomain); } - final List _routeAddress; - @override - List get routeAddress { - if (_routeAddress is EqualUnmodifiableListView) return _routeAddress; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_routeAddress); - } - - @override - final bool ipv6; - @override String toString() { - return 'CoreState(enable: $enable, accessControl: $accessControl, currentProfileName: $currentProfileName, allowBypass: $allowBypass, systemProxy: $systemProxy, bypassDomain: $bypassDomain, routeAddress: $routeAddress, ipv6: $ipv6)'; + return 'CoreState(vpnProps: $vpnProps, onlyStatisticsProxy: $onlyStatisticsProxy, currentProfileName: $currentProfileName, bypassDomain: $bypassDomain)'; } @override @@ -270,34 +203,20 @@ class _$CoreStateImpl implements _CoreState { return identical(this, other) || (other.runtimeType == runtimeType && other is _$CoreStateImpl && - (identical(other.enable, enable) || other.enable == enable) && - (identical(other.accessControl, accessControl) || - other.accessControl == accessControl) && + (identical(other.vpnProps, vpnProps) || + other.vpnProps == vpnProps) && + (identical(other.onlyStatisticsProxy, onlyStatisticsProxy) || + other.onlyStatisticsProxy == onlyStatisticsProxy) && (identical(other.currentProfileName, currentProfileName) || other.currentProfileName == currentProfileName) && - (identical(other.allowBypass, allowBypass) || - other.allowBypass == allowBypass) && - (identical(other.systemProxy, systemProxy) || - other.systemProxy == systemProxy) && const DeepCollectionEquality() - .equals(other._bypassDomain, _bypassDomain) && - const DeepCollectionEquality() - .equals(other._routeAddress, _routeAddress) && - (identical(other.ipv6, ipv6) || other.ipv6 == ipv6)); + .equals(other._bypassDomain, _bypassDomain)); } @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash( - runtimeType, - enable, - accessControl, - currentProfileName, - allowBypass, - systemProxy, - const DeepCollectionEquality().hash(_bypassDomain), - const DeepCollectionEquality().hash(_routeAddress), - ipv6); + int get hashCode => Object.hash(runtimeType, vpnProps, onlyStatisticsProxy, + currentProfileName, const DeepCollectionEquality().hash(_bypassDomain)); /// Create a copy of CoreState /// with the given fields replaced by the non-null parameter values. @@ -317,34 +236,29 @@ class _$CoreStateImpl implements _CoreState { abstract class _CoreState implements CoreState { const factory _CoreState( - {required final bool enable, - final AccessControl? accessControl, - required final String currentProfileName, - required final bool allowBypass, - required final bool systemProxy, - required final List bypassDomain, - required final List routeAddress, - required final bool ipv6}) = _$CoreStateImpl; + {@JsonKey(name: "vpn-props") required final VpnProps vpnProps, + @JsonKey(name: "only-statistics-proxy") + required final bool onlyStatisticsProxy, + @JsonKey(name: "current-profile-name") + required final String currentProfileName, + @JsonKey(name: "bypass-domain") final List bypassDomain}) = + _$CoreStateImpl; factory _CoreState.fromJson(Map json) = _$CoreStateImpl.fromJson; @override - bool get enable; + @JsonKey(name: "vpn-props") + VpnProps get vpnProps; @override - AccessControl? get accessControl; + @JsonKey(name: "only-statistics-proxy") + bool get onlyStatisticsProxy; @override + @JsonKey(name: "current-profile-name") String get currentProfileName; @override - bool get allowBypass; - @override - bool get systemProxy; - @override + @JsonKey(name: "bypass-domain") List get bypassDomain; - @override - List get routeAddress; - @override - bool get ipv6; /// Create a copy of CoreState /// with the given fields replaced by the non-null parameter values. @@ -592,7 +506,7 @@ class _$AndroidVpnOptionsImpl implements _AndroidVpnOptions { required final List bypassDomain, required this.ipv4Address, required this.ipv6Address, - required final List routeAddress, + final List routeAddress = const [], required this.dnsServerAddress}) : _bypassDomain = bypassDomain, _routeAddress = routeAddress; @@ -624,6 +538,7 @@ class _$AndroidVpnOptionsImpl implements _AndroidVpnOptions { final String ipv6Address; final List _routeAddress; @override + @JsonKey() List get routeAddress { if (_routeAddress is EqualUnmodifiableListView) return _routeAddress; // ignore: implicit_dynamic_type @@ -705,7 +620,7 @@ abstract class _AndroidVpnOptions implements AndroidVpnOptions { required final List bypassDomain, required final String ipv4Address, required final String ipv6Address, - required final List routeAddress, + final List routeAddress, required final String dnsServerAddress}) = _$AndroidVpnOptionsImpl; factory _AndroidVpnOptions.fromJson(Map json) = @@ -748,16 +663,12 @@ ConfigExtendedParams _$ConfigExtendedParamsFromJson(Map json) { mixin _$ConfigExtendedParams { @JsonKey(name: "is-patch") bool get isPatch => throw _privateConstructorUsedError; - @JsonKey(name: "is-compatible") - bool get isCompatible => throw _privateConstructorUsedError; @JsonKey(name: "selected-map") Map get selectedMap => throw _privateConstructorUsedError; @JsonKey(name: "override-dns") bool get overrideDns => throw _privateConstructorUsedError; @JsonKey(name: "test-url") String get testUrl => throw _privateConstructorUsedError; - @JsonKey(name: "only-statistics-proxy") - bool get onlyStatisticsProxy => throw _privateConstructorUsedError; /// Serializes this ConfigExtendedParams to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -777,11 +688,9 @@ abstract class $ConfigExtendedParamsCopyWith<$Res> { @useResult $Res call( {@JsonKey(name: "is-patch") bool isPatch, - @JsonKey(name: "is-compatible") bool isCompatible, @JsonKey(name: "selected-map") Map selectedMap, @JsonKey(name: "override-dns") bool overrideDns, - @JsonKey(name: "test-url") String testUrl, - @JsonKey(name: "only-statistics-proxy") bool onlyStatisticsProxy}); + @JsonKey(name: "test-url") String testUrl}); } /// @nodoc @@ -801,21 +710,15 @@ class _$ConfigExtendedParamsCopyWithImpl<$Res, @override $Res call({ Object? isPatch = null, - Object? isCompatible = null, Object? selectedMap = null, Object? overrideDns = null, Object? testUrl = null, - Object? onlyStatisticsProxy = null, }) { return _then(_value.copyWith( isPatch: null == isPatch ? _value.isPatch : isPatch // ignore: cast_nullable_to_non_nullable as bool, - isCompatible: null == isCompatible - ? _value.isCompatible - : isCompatible // ignore: cast_nullable_to_non_nullable - as bool, selectedMap: null == selectedMap ? _value.selectedMap : selectedMap // ignore: cast_nullable_to_non_nullable @@ -828,10 +731,6 @@ class _$ConfigExtendedParamsCopyWithImpl<$Res, ? _value.testUrl : testUrl // ignore: cast_nullable_to_non_nullable as String, - onlyStatisticsProxy: null == onlyStatisticsProxy - ? _value.onlyStatisticsProxy - : onlyStatisticsProxy // ignore: cast_nullable_to_non_nullable - as bool, ) as $Val); } } @@ -846,11 +745,9 @@ abstract class _$$ConfigExtendedParamsImplCopyWith<$Res> @useResult $Res call( {@JsonKey(name: "is-patch") bool isPatch, - @JsonKey(name: "is-compatible") bool isCompatible, @JsonKey(name: "selected-map") Map selectedMap, @JsonKey(name: "override-dns") bool overrideDns, - @JsonKey(name: "test-url") String testUrl, - @JsonKey(name: "only-statistics-proxy") bool onlyStatisticsProxy}); + @JsonKey(name: "test-url") String testUrl}); } /// @nodoc @@ -867,21 +764,15 @@ class __$$ConfigExtendedParamsImplCopyWithImpl<$Res> @override $Res call({ Object? isPatch = null, - Object? isCompatible = null, Object? selectedMap = null, Object? overrideDns = null, Object? testUrl = null, - Object? onlyStatisticsProxy = null, }) { return _then(_$ConfigExtendedParamsImpl( isPatch: null == isPatch ? _value.isPatch : isPatch // ignore: cast_nullable_to_non_nullable as bool, - isCompatible: null == isCompatible - ? _value.isCompatible - : isCompatible // ignore: cast_nullable_to_non_nullable - as bool, selectedMap: null == selectedMap ? _value._selectedMap : selectedMap // ignore: cast_nullable_to_non_nullable @@ -894,10 +785,6 @@ class __$$ConfigExtendedParamsImplCopyWithImpl<$Res> ? _value.testUrl : testUrl // ignore: cast_nullable_to_non_nullable as String, - onlyStatisticsProxy: null == onlyStatisticsProxy - ? _value.onlyStatisticsProxy - : onlyStatisticsProxy // ignore: cast_nullable_to_non_nullable - as bool, )); } } @@ -907,13 +794,10 @@ class __$$ConfigExtendedParamsImplCopyWithImpl<$Res> class _$ConfigExtendedParamsImpl implements _ConfigExtendedParams { const _$ConfigExtendedParamsImpl( {@JsonKey(name: "is-patch") required this.isPatch, - @JsonKey(name: "is-compatible") required this.isCompatible, @JsonKey(name: "selected-map") required final Map selectedMap, @JsonKey(name: "override-dns") required this.overrideDns, - @JsonKey(name: "test-url") required this.testUrl, - @JsonKey(name: "only-statistics-proxy") - required this.onlyStatisticsProxy}) + @JsonKey(name: "test-url") required this.testUrl}) : _selectedMap = selectedMap; factory _$ConfigExtendedParamsImpl.fromJson(Map json) => @@ -922,9 +806,6 @@ class _$ConfigExtendedParamsImpl implements _ConfigExtendedParams { @override @JsonKey(name: "is-patch") final bool isPatch; - @override - @JsonKey(name: "is-compatible") - final bool isCompatible; final Map _selectedMap; @override @JsonKey(name: "selected-map") @@ -940,13 +821,10 @@ class _$ConfigExtendedParamsImpl implements _ConfigExtendedParams { @override @JsonKey(name: "test-url") final String testUrl; - @override - @JsonKey(name: "only-statistics-proxy") - final bool onlyStatisticsProxy; @override String toString() { - return 'ConfigExtendedParams(isPatch: $isPatch, isCompatible: $isCompatible, selectedMap: $selectedMap, overrideDns: $overrideDns, testUrl: $testUrl, onlyStatisticsProxy: $onlyStatisticsProxy)'; + return 'ConfigExtendedParams(isPatch: $isPatch, selectedMap: $selectedMap, overrideDns: $overrideDns, testUrl: $testUrl)'; } @override @@ -955,27 +833,17 @@ class _$ConfigExtendedParamsImpl implements _ConfigExtendedParams { (other.runtimeType == runtimeType && other is _$ConfigExtendedParamsImpl && (identical(other.isPatch, isPatch) || other.isPatch == isPatch) && - (identical(other.isCompatible, isCompatible) || - other.isCompatible == isCompatible) && const DeepCollectionEquality() .equals(other._selectedMap, _selectedMap) && (identical(other.overrideDns, overrideDns) || other.overrideDns == overrideDns) && - (identical(other.testUrl, testUrl) || other.testUrl == testUrl) && - (identical(other.onlyStatisticsProxy, onlyStatisticsProxy) || - other.onlyStatisticsProxy == onlyStatisticsProxy)); + (identical(other.testUrl, testUrl) || other.testUrl == testUrl)); } @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash( - runtimeType, - isPatch, - isCompatible, - const DeepCollectionEquality().hash(_selectedMap), - overrideDns, - testUrl, - onlyStatisticsProxy); + int get hashCode => Object.hash(runtimeType, isPatch, + const DeepCollectionEquality().hash(_selectedMap), overrideDns, testUrl); /// Create a copy of ConfigExtendedParams /// with the given fields replaced by the non-null parameter values. @@ -997,14 +865,12 @@ class _$ConfigExtendedParamsImpl implements _ConfigExtendedParams { abstract class _ConfigExtendedParams implements ConfigExtendedParams { const factory _ConfigExtendedParams( - {@JsonKey(name: "is-patch") required final bool isPatch, - @JsonKey(name: "is-compatible") required final bool isCompatible, - @JsonKey(name: "selected-map") - required final Map selectedMap, - @JsonKey(name: "override-dns") required final bool overrideDns, - @JsonKey(name: "test-url") required final String testUrl, - @JsonKey(name: "only-statistics-proxy") - required final bool onlyStatisticsProxy}) = _$ConfigExtendedParamsImpl; + {@JsonKey(name: "is-patch") required final bool isPatch, + @JsonKey(name: "selected-map") + required final Map selectedMap, + @JsonKey(name: "override-dns") required final bool overrideDns, + @JsonKey(name: "test-url") required final String testUrl}) = + _$ConfigExtendedParamsImpl; factory _ConfigExtendedParams.fromJson(Map json) = _$ConfigExtendedParamsImpl.fromJson; @@ -1013,9 +879,6 @@ abstract class _ConfigExtendedParams implements ConfigExtendedParams { @JsonKey(name: "is-patch") bool get isPatch; @override - @JsonKey(name: "is-compatible") - bool get isCompatible; - @override @JsonKey(name: "selected-map") Map get selectedMap; @override @@ -1024,9 +887,6 @@ abstract class _ConfigExtendedParams implements ConfigExtendedParams { @override @JsonKey(name: "test-url") String get testUrl; - @override - @JsonKey(name: "only-statistics-proxy") - bool get onlyStatisticsProxy; /// Create a copy of ConfigExtendedParams /// with the given fields replaced by the non-null parameter values. @@ -1068,6 +928,7 @@ abstract class $UpdateConfigParamsCopyWith<$Res> { ClashConfig config, ConfigExtendedParams params}); + $ClashConfigCopyWith<$Res> get config; $ConfigExtendedParamsCopyWith<$Res> get params; } @@ -1106,6 +967,16 @@ class _$UpdateConfigParamsCopyWithImpl<$Res, $Val extends UpdateConfigParams> ) as $Val); } + /// Create a copy of UpdateConfigParams + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $ClashConfigCopyWith<$Res> get config { + return $ClashConfigCopyWith<$Res>(_value.config, (value) { + return _then(_value.copyWith(config: value) as $Val); + }); + } + /// Create a copy of UpdateConfigParams /// with the given fields replaced by the non-null parameter values. @override @@ -1130,6 +1001,8 @@ abstract class _$$UpdateConfigParamsImplCopyWith<$Res> ClashConfig config, ConfigExtendedParams params}); + @override + $ClashConfigCopyWith<$Res> get config; @override $ConfigExtendedParamsCopyWith<$Res> get params; } diff --git a/lib/models/generated/core.g.dart b/lib/models/generated/core.g.dart index 0d01bf4..3dd83ad 100644 --- a/lib/models/generated/core.g.dart +++ b/lib/models/generated/core.g.dart @@ -8,33 +8,21 @@ part of '../core.dart'; _$CoreStateImpl _$$CoreStateImplFromJson(Map json) => _$CoreStateImpl( - enable: json['enable'] as bool, - accessControl: json['accessControl'] == null - ? null - : AccessControl.fromJson( - json['accessControl'] as Map), - currentProfileName: json['currentProfileName'] as String, - allowBypass: json['allowBypass'] as bool, - systemProxy: json['systemProxy'] as bool, - bypassDomain: (json['bypassDomain'] as List) - .map((e) => e as String) - .toList(), - routeAddress: (json['routeAddress'] as List) - .map((e) => e as String) - .toList(), - ipv6: json['ipv6'] as bool, + vpnProps: VpnProps.fromJson(json['vpn-props'] as Map?), + onlyStatisticsProxy: json['only-statistics-proxy'] as bool, + currentProfileName: json['current-profile-name'] as String, + bypassDomain: (json['bypass-domain'] as List?) + ?.map((e) => e as String) + .toList() ?? + const [], ); Map _$$CoreStateImplToJson(_$CoreStateImpl instance) => { - 'enable': instance.enable, - 'accessControl': instance.accessControl, - 'currentProfileName': instance.currentProfileName, - 'allowBypass': instance.allowBypass, - 'systemProxy': instance.systemProxy, - 'bypassDomain': instance.bypassDomain, - 'routeAddress': instance.routeAddress, - 'ipv6': instance.ipv6, + 'vpn-props': instance.vpnProps, + 'only-statistics-proxy': instance.onlyStatisticsProxy, + 'current-profile-name': instance.currentProfileName, + 'bypass-domain': instance.bypassDomain, }; _$AndroidVpnOptionsImpl _$$AndroidVpnOptionsImplFromJson( @@ -53,9 +41,10 @@ _$AndroidVpnOptionsImpl _$$AndroidVpnOptionsImplFromJson( .toList(), ipv4Address: json['ipv4Address'] as String, ipv6Address: json['ipv6Address'] as String, - routeAddress: (json['routeAddress'] as List) - .map((e) => e as String) - .toList(), + routeAddress: (json['routeAddress'] as List?) + ?.map((e) => e as String) + .toList() ?? + const [], dnsServerAddress: json['dnsServerAddress'] as String, ); @@ -78,22 +67,18 @@ _$ConfigExtendedParamsImpl _$$ConfigExtendedParamsImplFromJson( Map json) => _$ConfigExtendedParamsImpl( isPatch: json['is-patch'] as bool, - isCompatible: json['is-compatible'] as bool, selectedMap: Map.from(json['selected-map'] as Map), overrideDns: json['override-dns'] as bool, testUrl: json['test-url'] as String, - onlyStatisticsProxy: json['only-statistics-proxy'] as bool, ); Map _$$ConfigExtendedParamsImplToJson( _$ConfigExtendedParamsImpl instance) => { 'is-patch': instance.isPatch, - 'is-compatible': instance.isCompatible, 'selected-map': instance.selectedMap, 'override-dns': instance.overrideDns, 'test-url': instance.testUrl, - 'only-statistics-proxy': instance.onlyStatisticsProxy, }; _$UpdateConfigParamsImpl _$$UpdateConfigParamsImplFromJson( @@ -345,6 +330,7 @@ const _$ActionMethodEnumMap = { ActionMethod.stopListener: 'stopListener', ActionMethod.getCountryCode: 'getCountryCode', ActionMethod.getMemory: 'getMemory', + ActionMethod.getProfile: 'getProfile', ActionMethod.setFdMap: 'setFdMap', ActionMethod.setProcessMap: 'setProcessMap', ActionMethod.setState: 'setState', diff --git a/lib/models/generated/selector.freezed.dart b/lib/models/generated/selector.freezed.dart index 43c96ed..cd8a298 100644 --- a/lib/models/generated/selector.freezed.dart +++ b/lib/models/generated/selector.freezed.dart @@ -167,326 +167,6 @@ abstract class _StartButtonSelectorState implements StartButtonSelectorState { get copyWith => throw _privateConstructorUsedError; } -/// @nodoc -mixin _$CheckIpSelectorState { - String? get currentProfileId => throw _privateConstructorUsedError; - Map get selectedMap => throw _privateConstructorUsedError; - - /// Create a copy of CheckIpSelectorState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $CheckIpSelectorStateCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $CheckIpSelectorStateCopyWith<$Res> { - factory $CheckIpSelectorStateCopyWith(CheckIpSelectorState value, - $Res Function(CheckIpSelectorState) then) = - _$CheckIpSelectorStateCopyWithImpl<$Res, CheckIpSelectorState>; - @useResult - $Res call({String? currentProfileId, Map selectedMap}); -} - -/// @nodoc -class _$CheckIpSelectorStateCopyWithImpl<$Res, - $Val extends CheckIpSelectorState> - implements $CheckIpSelectorStateCopyWith<$Res> { - _$CheckIpSelectorStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of CheckIpSelectorState - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? currentProfileId = freezed, - Object? selectedMap = null, - }) { - return _then(_value.copyWith( - currentProfileId: freezed == currentProfileId - ? _value.currentProfileId - : currentProfileId // ignore: cast_nullable_to_non_nullable - as String?, - selectedMap: null == selectedMap - ? _value.selectedMap - : selectedMap // ignore: cast_nullable_to_non_nullable - as Map, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$CheckIpSelectorStateImplCopyWith<$Res> - implements $CheckIpSelectorStateCopyWith<$Res> { - factory _$$CheckIpSelectorStateImplCopyWith(_$CheckIpSelectorStateImpl value, - $Res Function(_$CheckIpSelectorStateImpl) then) = - __$$CheckIpSelectorStateImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({String? currentProfileId, Map selectedMap}); -} - -/// @nodoc -class __$$CheckIpSelectorStateImplCopyWithImpl<$Res> - extends _$CheckIpSelectorStateCopyWithImpl<$Res, _$CheckIpSelectorStateImpl> - implements _$$CheckIpSelectorStateImplCopyWith<$Res> { - __$$CheckIpSelectorStateImplCopyWithImpl(_$CheckIpSelectorStateImpl _value, - $Res Function(_$CheckIpSelectorStateImpl) _then) - : super(_value, _then); - - /// Create a copy of CheckIpSelectorState - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? currentProfileId = freezed, - Object? selectedMap = null, - }) { - return _then(_$CheckIpSelectorStateImpl( - currentProfileId: freezed == currentProfileId - ? _value.currentProfileId - : currentProfileId // ignore: cast_nullable_to_non_nullable - as String?, - selectedMap: null == selectedMap - ? _value._selectedMap - : selectedMap // ignore: cast_nullable_to_non_nullable - as Map, - )); - } -} - -/// @nodoc - -class _$CheckIpSelectorStateImpl implements _CheckIpSelectorState { - const _$CheckIpSelectorStateImpl( - {required this.currentProfileId, - required final Map selectedMap}) - : _selectedMap = selectedMap; - - @override - final String? currentProfileId; - final Map _selectedMap; - @override - Map get selectedMap { - if (_selectedMap is EqualUnmodifiableMapView) return _selectedMap; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_selectedMap); - } - - @override - String toString() { - return 'CheckIpSelectorState(currentProfileId: $currentProfileId, selectedMap: $selectedMap)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$CheckIpSelectorStateImpl && - (identical(other.currentProfileId, currentProfileId) || - other.currentProfileId == currentProfileId) && - const DeepCollectionEquality() - .equals(other._selectedMap, _selectedMap)); - } - - @override - int get hashCode => Object.hash(runtimeType, currentProfileId, - const DeepCollectionEquality().hash(_selectedMap)); - - /// Create a copy of CheckIpSelectorState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$CheckIpSelectorStateImplCopyWith<_$CheckIpSelectorStateImpl> - get copyWith => - __$$CheckIpSelectorStateImplCopyWithImpl<_$CheckIpSelectorStateImpl>( - this, _$identity); -} - -abstract class _CheckIpSelectorState implements CheckIpSelectorState { - const factory _CheckIpSelectorState( - {required final String? currentProfileId, - required final Map selectedMap}) = - _$CheckIpSelectorStateImpl; - - @override - String? get currentProfileId; - @override - Map get selectedMap; - - /// Create a copy of CheckIpSelectorState - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$CheckIpSelectorStateImplCopyWith<_$CheckIpSelectorStateImpl> - get copyWith => throw _privateConstructorUsedError; -} - -/// @nodoc -mixin _$NetworkDetectionSelectorState { - String? get currentProxyName => throw _privateConstructorUsedError; - int? get delay => throw _privateConstructorUsedError; - - /// Create a copy of NetworkDetectionSelectorState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $NetworkDetectionSelectorStateCopyWith - get copyWith => throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $NetworkDetectionSelectorStateCopyWith<$Res> { - factory $NetworkDetectionSelectorStateCopyWith( - NetworkDetectionSelectorState value, - $Res Function(NetworkDetectionSelectorState) then) = - _$NetworkDetectionSelectorStateCopyWithImpl<$Res, - NetworkDetectionSelectorState>; - @useResult - $Res call({String? currentProxyName, int? delay}); -} - -/// @nodoc -class _$NetworkDetectionSelectorStateCopyWithImpl<$Res, - $Val extends NetworkDetectionSelectorState> - implements $NetworkDetectionSelectorStateCopyWith<$Res> { - _$NetworkDetectionSelectorStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of NetworkDetectionSelectorState - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? currentProxyName = freezed, - Object? delay = freezed, - }) { - return _then(_value.copyWith( - currentProxyName: freezed == currentProxyName - ? _value.currentProxyName - : currentProxyName // ignore: cast_nullable_to_non_nullable - as String?, - delay: freezed == delay - ? _value.delay - : delay // ignore: cast_nullable_to_non_nullable - as int?, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$NetworkDetectionSelectorStateImplCopyWith<$Res> - implements $NetworkDetectionSelectorStateCopyWith<$Res> { - factory _$$NetworkDetectionSelectorStateImplCopyWith( - _$NetworkDetectionSelectorStateImpl value, - $Res Function(_$NetworkDetectionSelectorStateImpl) then) = - __$$NetworkDetectionSelectorStateImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({String? currentProxyName, int? delay}); -} - -/// @nodoc -class __$$NetworkDetectionSelectorStateImplCopyWithImpl<$Res> - extends _$NetworkDetectionSelectorStateCopyWithImpl<$Res, - _$NetworkDetectionSelectorStateImpl> - implements _$$NetworkDetectionSelectorStateImplCopyWith<$Res> { - __$$NetworkDetectionSelectorStateImplCopyWithImpl( - _$NetworkDetectionSelectorStateImpl _value, - $Res Function(_$NetworkDetectionSelectorStateImpl) _then) - : super(_value, _then); - - /// Create a copy of NetworkDetectionSelectorState - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? currentProxyName = freezed, - Object? delay = freezed, - }) { - return _then(_$NetworkDetectionSelectorStateImpl( - currentProxyName: freezed == currentProxyName - ? _value.currentProxyName - : currentProxyName // ignore: cast_nullable_to_non_nullable - as String?, - delay: freezed == delay - ? _value.delay - : delay // ignore: cast_nullable_to_non_nullable - as int?, - )); - } -} - -/// @nodoc - -class _$NetworkDetectionSelectorStateImpl - implements _NetworkDetectionSelectorState { - const _$NetworkDetectionSelectorStateImpl( - {required this.currentProxyName, required this.delay}); - - @override - final String? currentProxyName; - @override - final int? delay; - - @override - String toString() { - return 'NetworkDetectionSelectorState(currentProxyName: $currentProxyName, delay: $delay)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$NetworkDetectionSelectorStateImpl && - (identical(other.currentProxyName, currentProxyName) || - other.currentProxyName == currentProxyName) && - (identical(other.delay, delay) || other.delay == delay)); - } - - @override - int get hashCode => Object.hash(runtimeType, currentProxyName, delay); - - /// Create a copy of NetworkDetectionSelectorState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$NetworkDetectionSelectorStateImplCopyWith< - _$NetworkDetectionSelectorStateImpl> - get copyWith => __$$NetworkDetectionSelectorStateImplCopyWithImpl< - _$NetworkDetectionSelectorStateImpl>(this, _$identity); -} - -abstract class _NetworkDetectionSelectorState - implements NetworkDetectionSelectorState { - const factory _NetworkDetectionSelectorState( - {required final String? currentProxyName, - required final int? delay}) = _$NetworkDetectionSelectorStateImpl; - - @override - String? get currentProxyName; - @override - int? get delay; - - /// Create a copy of NetworkDetectionSelectorState - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$NetworkDetectionSelectorStateImplCopyWith< - _$NetworkDetectionSelectorStateImpl> - get copyWith => throw _privateConstructorUsedError; -} - /// @nodoc mixin _$ProfilesSelectorState { List get profiles => throw _privateConstructorUsedError; @@ -821,228 +501,6 @@ abstract class _NetworkDetectionState implements NetworkDetectionState { get copyWith => throw _privateConstructorUsedError; } -/// @nodoc -mixin _$ApplicationSelectorState { - String? get locale => throw _privateConstructorUsedError; - ThemeMode? get themeMode => throw _privateConstructorUsedError; - int? get primaryColor => throw _privateConstructorUsedError; - bool get prueBlack => throw _privateConstructorUsedError; - FontFamily get fontFamily => throw _privateConstructorUsedError; - - /// Create a copy of ApplicationSelectorState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $ApplicationSelectorStateCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $ApplicationSelectorStateCopyWith<$Res> { - factory $ApplicationSelectorStateCopyWith(ApplicationSelectorState value, - $Res Function(ApplicationSelectorState) then) = - _$ApplicationSelectorStateCopyWithImpl<$Res, ApplicationSelectorState>; - @useResult - $Res call( - {String? locale, - ThemeMode? themeMode, - int? primaryColor, - bool prueBlack, - FontFamily fontFamily}); -} - -/// @nodoc -class _$ApplicationSelectorStateCopyWithImpl<$Res, - $Val extends ApplicationSelectorState> - implements $ApplicationSelectorStateCopyWith<$Res> { - _$ApplicationSelectorStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of ApplicationSelectorState - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? locale = freezed, - Object? themeMode = freezed, - Object? primaryColor = freezed, - Object? prueBlack = null, - Object? fontFamily = null, - }) { - return _then(_value.copyWith( - locale: freezed == locale - ? _value.locale - : locale // ignore: cast_nullable_to_non_nullable - as String?, - themeMode: freezed == themeMode - ? _value.themeMode - : themeMode // ignore: cast_nullable_to_non_nullable - as ThemeMode?, - primaryColor: freezed == primaryColor - ? _value.primaryColor - : primaryColor // ignore: cast_nullable_to_non_nullable - as int?, - prueBlack: null == prueBlack - ? _value.prueBlack - : prueBlack // ignore: cast_nullable_to_non_nullable - as bool, - fontFamily: null == fontFamily - ? _value.fontFamily - : fontFamily // ignore: cast_nullable_to_non_nullable - as FontFamily, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$ApplicationSelectorStateImplCopyWith<$Res> - implements $ApplicationSelectorStateCopyWith<$Res> { - factory _$$ApplicationSelectorStateImplCopyWith( - _$ApplicationSelectorStateImpl value, - $Res Function(_$ApplicationSelectorStateImpl) then) = - __$$ApplicationSelectorStateImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String? locale, - ThemeMode? themeMode, - int? primaryColor, - bool prueBlack, - FontFamily fontFamily}); -} - -/// @nodoc -class __$$ApplicationSelectorStateImplCopyWithImpl<$Res> - extends _$ApplicationSelectorStateCopyWithImpl<$Res, - _$ApplicationSelectorStateImpl> - implements _$$ApplicationSelectorStateImplCopyWith<$Res> { - __$$ApplicationSelectorStateImplCopyWithImpl( - _$ApplicationSelectorStateImpl _value, - $Res Function(_$ApplicationSelectorStateImpl) _then) - : super(_value, _then); - - /// Create a copy of ApplicationSelectorState - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? locale = freezed, - Object? themeMode = freezed, - Object? primaryColor = freezed, - Object? prueBlack = null, - Object? fontFamily = null, - }) { - return _then(_$ApplicationSelectorStateImpl( - locale: freezed == locale - ? _value.locale - : locale // ignore: cast_nullable_to_non_nullable - as String?, - themeMode: freezed == themeMode - ? _value.themeMode - : themeMode // ignore: cast_nullable_to_non_nullable - as ThemeMode?, - primaryColor: freezed == primaryColor - ? _value.primaryColor - : primaryColor // ignore: cast_nullable_to_non_nullable - as int?, - prueBlack: null == prueBlack - ? _value.prueBlack - : prueBlack // ignore: cast_nullable_to_non_nullable - as bool, - fontFamily: null == fontFamily - ? _value.fontFamily - : fontFamily // ignore: cast_nullable_to_non_nullable - as FontFamily, - )); - } -} - -/// @nodoc - -class _$ApplicationSelectorStateImpl implements _ApplicationSelectorState { - const _$ApplicationSelectorStateImpl( - {required this.locale, - required this.themeMode, - required this.primaryColor, - required this.prueBlack, - required this.fontFamily}); - - @override - final String? locale; - @override - final ThemeMode? themeMode; - @override - final int? primaryColor; - @override - final bool prueBlack; - @override - final FontFamily fontFamily; - - @override - String toString() { - return 'ApplicationSelectorState(locale: $locale, themeMode: $themeMode, primaryColor: $primaryColor, prueBlack: $prueBlack, fontFamily: $fontFamily)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$ApplicationSelectorStateImpl && - (identical(other.locale, locale) || other.locale == locale) && - (identical(other.themeMode, themeMode) || - other.themeMode == themeMode) && - (identical(other.primaryColor, primaryColor) || - other.primaryColor == primaryColor) && - (identical(other.prueBlack, prueBlack) || - other.prueBlack == prueBlack) && - (identical(other.fontFamily, fontFamily) || - other.fontFamily == fontFamily)); - } - - @override - int get hashCode => Object.hash( - runtimeType, locale, themeMode, primaryColor, prueBlack, fontFamily); - - /// Create a copy of ApplicationSelectorState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$ApplicationSelectorStateImplCopyWith<_$ApplicationSelectorStateImpl> - get copyWith => __$$ApplicationSelectorStateImplCopyWithImpl< - _$ApplicationSelectorStateImpl>(this, _$identity); -} - -abstract class _ApplicationSelectorState implements ApplicationSelectorState { - const factory _ApplicationSelectorState( - {required final String? locale, - required final ThemeMode? themeMode, - required final int? primaryColor, - required final bool prueBlack, - required final FontFamily fontFamily}) = _$ApplicationSelectorStateImpl; - - @override - String? get locale; - @override - ThemeMode? get themeMode; - @override - int? get primaryColor; - @override - bool get prueBlack; - @override - FontFamily get fontFamily; - - /// Create a copy of ApplicationSelectorState - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$ApplicationSelectorStateImplCopyWith<_$ApplicationSelectorStateImpl> - get copyWith => throw _privateConstructorUsedError; -} - /// @nodoc mixin _$TrayState { Mode get mode => throw _privateConstructorUsedError; @@ -1054,7 +512,7 @@ mixin _$TrayState { String? get locale => throw _privateConstructorUsedError; Brightness? get brightness => throw _privateConstructorUsedError; List get groups => throw _privateConstructorUsedError; - Map get map => throw _privateConstructorUsedError; + Map get selectedMap => throw _privateConstructorUsedError; /// Create a copy of TrayState /// with the given fields replaced by the non-null parameter values. @@ -1078,7 +536,7 @@ abstract class $TrayStateCopyWith<$Res> { String? locale, Brightness? brightness, List groups, - Map map}); + Map selectedMap}); } /// @nodoc @@ -1105,7 +563,7 @@ class _$TrayStateCopyWithImpl<$Res, $Val extends TrayState> Object? locale = freezed, Object? brightness = freezed, Object? groups = null, - Object? map = null, + Object? selectedMap = null, }) { return _then(_value.copyWith( mode: null == mode @@ -1144,9 +602,9 @@ class _$TrayStateCopyWithImpl<$Res, $Val extends TrayState> ? _value.groups : groups // ignore: cast_nullable_to_non_nullable as List, - map: null == map - ? _value.map - : map // ignore: cast_nullable_to_non_nullable + selectedMap: null == selectedMap + ? _value.selectedMap + : selectedMap // ignore: cast_nullable_to_non_nullable as Map, ) as $Val); } @@ -1170,7 +628,7 @@ abstract class _$$TrayStateImplCopyWith<$Res> String? locale, Brightness? brightness, List groups, - Map map}); + Map selectedMap}); } /// @nodoc @@ -1195,7 +653,7 @@ class __$$TrayStateImplCopyWithImpl<$Res> Object? locale = freezed, Object? brightness = freezed, Object? groups = null, - Object? map = null, + Object? selectedMap = null, }) { return _then(_$TrayStateImpl( mode: null == mode @@ -1234,9 +692,9 @@ class __$$TrayStateImplCopyWithImpl<$Res> ? _value._groups : groups // ignore: cast_nullable_to_non_nullable as List, - map: null == map - ? _value._map - : map // ignore: cast_nullable_to_non_nullable + selectedMap: null == selectedMap + ? _value._selectedMap + : selectedMap // ignore: cast_nullable_to_non_nullable as Map, )); } @@ -1255,9 +713,9 @@ class _$TrayStateImpl implements _TrayState { required this.locale, required this.brightness, required final List groups, - required final Map map}) + required final Map selectedMap}) : _groups = groups, - _map = map; + _selectedMap = selectedMap; @override final Mode mode; @@ -1283,17 +741,17 @@ class _$TrayStateImpl implements _TrayState { return EqualUnmodifiableListView(_groups); } - final Map _map; + final Map _selectedMap; @override - Map get map { - if (_map is EqualUnmodifiableMapView) return _map; + Map get selectedMap { + if (_selectedMap is EqualUnmodifiableMapView) return _selectedMap; // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_map); + return EqualUnmodifiableMapView(_selectedMap); } @override String toString() { - return 'TrayState(mode: $mode, port: $port, autoLaunch: $autoLaunch, systemProxy: $systemProxy, tunEnable: $tunEnable, isStart: $isStart, locale: $locale, brightness: $brightness, groups: $groups, map: $map)'; + return 'TrayState(mode: $mode, port: $port, autoLaunch: $autoLaunch, systemProxy: $systemProxy, tunEnable: $tunEnable, isStart: $isStart, locale: $locale, brightness: $brightness, groups: $groups, selectedMap: $selectedMap)'; } @override @@ -1314,7 +772,8 @@ class _$TrayStateImpl implements _TrayState { (identical(other.brightness, brightness) || other.brightness == brightness) && const DeepCollectionEquality().equals(other._groups, _groups) && - const DeepCollectionEquality().equals(other._map, _map)); + const DeepCollectionEquality() + .equals(other._selectedMap, _selectedMap)); } @override @@ -1329,7 +788,7 @@ class _$TrayStateImpl implements _TrayState { locale, brightness, const DeepCollectionEquality().hash(_groups), - const DeepCollectionEquality().hash(_map)); + const DeepCollectionEquality().hash(_selectedMap)); /// Create a copy of TrayState /// with the given fields replaced by the non-null parameter values. @@ -1351,7 +810,7 @@ abstract class _TrayState implements TrayState { required final String? locale, required final Brightness? brightness, required final List groups, - required final Map map}) = _$TrayStateImpl; + required final Map selectedMap}) = _$TrayStateImpl; @override Mode get mode; @@ -1372,7 +831,7 @@ abstract class _TrayState implements TrayState { @override List get groups; @override - Map get map; + Map get selectedMap; /// Create a copy of TrayState /// with the given fields replaced by the non-null parameter values. @@ -1382,163 +841,9 @@ abstract class _TrayState implements TrayState { throw _privateConstructorUsedError; } -/// @nodoc -mixin _$UpdateNavigationsSelector { - bool get openLogs => throw _privateConstructorUsedError; - bool get hasProxies => throw _privateConstructorUsedError; - - /// Create a copy of UpdateNavigationsSelector - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $UpdateNavigationsSelectorCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $UpdateNavigationsSelectorCopyWith<$Res> { - factory $UpdateNavigationsSelectorCopyWith(UpdateNavigationsSelector value, - $Res Function(UpdateNavigationsSelector) then) = - _$UpdateNavigationsSelectorCopyWithImpl<$Res, UpdateNavigationsSelector>; - @useResult - $Res call({bool openLogs, bool hasProxies}); -} - -/// @nodoc -class _$UpdateNavigationsSelectorCopyWithImpl<$Res, - $Val extends UpdateNavigationsSelector> - implements $UpdateNavigationsSelectorCopyWith<$Res> { - _$UpdateNavigationsSelectorCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of UpdateNavigationsSelector - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? openLogs = null, - Object? hasProxies = null, - }) { - return _then(_value.copyWith( - openLogs: null == openLogs - ? _value.openLogs - : openLogs // ignore: cast_nullable_to_non_nullable - as bool, - hasProxies: null == hasProxies - ? _value.hasProxies - : hasProxies // ignore: cast_nullable_to_non_nullable - as bool, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$UpdateNavigationsSelectorImplCopyWith<$Res> - implements $UpdateNavigationsSelectorCopyWith<$Res> { - factory _$$UpdateNavigationsSelectorImplCopyWith( - _$UpdateNavigationsSelectorImpl value, - $Res Function(_$UpdateNavigationsSelectorImpl) then) = - __$$UpdateNavigationsSelectorImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({bool openLogs, bool hasProxies}); -} - -/// @nodoc -class __$$UpdateNavigationsSelectorImplCopyWithImpl<$Res> - extends _$UpdateNavigationsSelectorCopyWithImpl<$Res, - _$UpdateNavigationsSelectorImpl> - implements _$$UpdateNavigationsSelectorImplCopyWith<$Res> { - __$$UpdateNavigationsSelectorImplCopyWithImpl( - _$UpdateNavigationsSelectorImpl _value, - $Res Function(_$UpdateNavigationsSelectorImpl) _then) - : super(_value, _then); - - /// Create a copy of UpdateNavigationsSelector - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? openLogs = null, - Object? hasProxies = null, - }) { - return _then(_$UpdateNavigationsSelectorImpl( - openLogs: null == openLogs - ? _value.openLogs - : openLogs // ignore: cast_nullable_to_non_nullable - as bool, - hasProxies: null == hasProxies - ? _value.hasProxies - : hasProxies // ignore: cast_nullable_to_non_nullable - as bool, - )); - } -} - -/// @nodoc - -class _$UpdateNavigationsSelectorImpl implements _UpdateNavigationsSelector { - const _$UpdateNavigationsSelectorImpl( - {required this.openLogs, required this.hasProxies}); - - @override - final bool openLogs; - @override - final bool hasProxies; - - @override - String toString() { - return 'UpdateNavigationsSelector(openLogs: $openLogs, hasProxies: $hasProxies)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$UpdateNavigationsSelectorImpl && - (identical(other.openLogs, openLogs) || - other.openLogs == openLogs) && - (identical(other.hasProxies, hasProxies) || - other.hasProxies == hasProxies)); - } - - @override - int get hashCode => Object.hash(runtimeType, openLogs, hasProxies); - - /// Create a copy of UpdateNavigationsSelector - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$UpdateNavigationsSelectorImplCopyWith<_$UpdateNavigationsSelectorImpl> - get copyWith => __$$UpdateNavigationsSelectorImplCopyWithImpl< - _$UpdateNavigationsSelectorImpl>(this, _$identity); -} - -abstract class _UpdateNavigationsSelector implements UpdateNavigationsSelector { - const factory _UpdateNavigationsSelector( - {required final bool openLogs, - required final bool hasProxies}) = _$UpdateNavigationsSelectorImpl; - - @override - bool get openLogs; - @override - bool get hasProxies; - - /// Create a copy of UpdateNavigationsSelector - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$UpdateNavigationsSelectorImplCopyWith<_$UpdateNavigationsSelectorImpl> - get copyWith => throw _privateConstructorUsedError; -} - /// @nodoc mixin _$HomeState { - String get currentLabel => throw _privateConstructorUsedError; + PageLabel get pageLabel => throw _privateConstructorUsedError; List get navigationItems => throw _privateConstructorUsedError; ViewMode get viewMode => throw _privateConstructorUsedError; @@ -1557,7 +862,7 @@ abstract class $HomeStateCopyWith<$Res> { _$HomeStateCopyWithImpl<$Res, HomeState>; @useResult $Res call( - {String currentLabel, + {PageLabel pageLabel, List navigationItems, ViewMode viewMode, String? locale}); @@ -1578,16 +883,16 @@ class _$HomeStateCopyWithImpl<$Res, $Val extends HomeState> @pragma('vm:prefer-inline') @override $Res call({ - Object? currentLabel = null, + Object? pageLabel = null, Object? navigationItems = null, Object? viewMode = null, Object? locale = freezed, }) { return _then(_value.copyWith( - currentLabel: null == currentLabel - ? _value.currentLabel - : currentLabel // ignore: cast_nullable_to_non_nullable - as String, + pageLabel: null == pageLabel + ? _value.pageLabel + : pageLabel // ignore: cast_nullable_to_non_nullable + as PageLabel, navigationItems: null == navigationItems ? _value.navigationItems : navigationItems // ignore: cast_nullable_to_non_nullable @@ -1613,7 +918,7 @@ abstract class _$$HomeStateImplCopyWith<$Res> @override @useResult $Res call( - {String currentLabel, + {PageLabel pageLabel, List navigationItems, ViewMode viewMode, String? locale}); @@ -1632,16 +937,16 @@ class __$$HomeStateImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? currentLabel = null, + Object? pageLabel = null, Object? navigationItems = null, Object? viewMode = null, Object? locale = freezed, }) { return _then(_$HomeStateImpl( - currentLabel: null == currentLabel - ? _value.currentLabel - : currentLabel // ignore: cast_nullable_to_non_nullable - as String, + pageLabel: null == pageLabel + ? _value.pageLabel + : pageLabel // ignore: cast_nullable_to_non_nullable + as PageLabel, navigationItems: null == navigationItems ? _value._navigationItems : navigationItems // ignore: cast_nullable_to_non_nullable @@ -1662,14 +967,14 @@ class __$$HomeStateImplCopyWithImpl<$Res> class _$HomeStateImpl implements _HomeState { const _$HomeStateImpl( - {required this.currentLabel, + {required this.pageLabel, required final List navigationItems, required this.viewMode, required this.locale}) : _navigationItems = navigationItems; @override - final String currentLabel; + final PageLabel pageLabel; final List _navigationItems; @override List get navigationItems { @@ -1685,7 +990,7 @@ class _$HomeStateImpl implements _HomeState { @override String toString() { - return 'HomeState(currentLabel: $currentLabel, navigationItems: $navigationItems, viewMode: $viewMode, locale: $locale)'; + return 'HomeState(pageLabel: $pageLabel, navigationItems: $navigationItems, viewMode: $viewMode, locale: $locale)'; } @override @@ -1693,8 +998,8 @@ class _$HomeStateImpl implements _HomeState { return identical(this, other) || (other.runtimeType == runtimeType && other is _$HomeStateImpl && - (identical(other.currentLabel, currentLabel) || - other.currentLabel == currentLabel) && + (identical(other.pageLabel, pageLabel) || + other.pageLabel == pageLabel) && const DeepCollectionEquality() .equals(other._navigationItems, _navigationItems) && (identical(other.viewMode, viewMode) || @@ -1703,7 +1008,7 @@ class _$HomeStateImpl implements _HomeState { } @override - int get hashCode => Object.hash(runtimeType, currentLabel, + int get hashCode => Object.hash(runtimeType, pageLabel, const DeepCollectionEquality().hash(_navigationItems), viewMode, locale); /// Create a copy of HomeState @@ -1717,13 +1022,13 @@ class _$HomeStateImpl implements _HomeState { abstract class _HomeState implements HomeState { const factory _HomeState( - {required final String currentLabel, + {required final PageLabel pageLabel, required final List navigationItems, required final ViewMode viewMode, required final String? locale}) = _$HomeStateImpl; @override - String get currentLabel; + PageLabel get pageLabel; @override List get navigationItems; @override @@ -1739,141 +1044,6 @@ abstract class _HomeState implements HomeState { throw _privateConstructorUsedError; } -/// @nodoc -mixin _$ProxiesCardSelectorState { - bool get isSelected => throw _privateConstructorUsedError; - - /// Create a copy of ProxiesCardSelectorState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $ProxiesCardSelectorStateCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $ProxiesCardSelectorStateCopyWith<$Res> { - factory $ProxiesCardSelectorStateCopyWith(ProxiesCardSelectorState value, - $Res Function(ProxiesCardSelectorState) then) = - _$ProxiesCardSelectorStateCopyWithImpl<$Res, ProxiesCardSelectorState>; - @useResult - $Res call({bool isSelected}); -} - -/// @nodoc -class _$ProxiesCardSelectorStateCopyWithImpl<$Res, - $Val extends ProxiesCardSelectorState> - implements $ProxiesCardSelectorStateCopyWith<$Res> { - _$ProxiesCardSelectorStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of ProxiesCardSelectorState - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? isSelected = null, - }) { - return _then(_value.copyWith( - isSelected: null == isSelected - ? _value.isSelected - : isSelected // ignore: cast_nullable_to_non_nullable - as bool, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$ProxiesCardSelectorStateImplCopyWith<$Res> - implements $ProxiesCardSelectorStateCopyWith<$Res> { - factory _$$ProxiesCardSelectorStateImplCopyWith( - _$ProxiesCardSelectorStateImpl value, - $Res Function(_$ProxiesCardSelectorStateImpl) then) = - __$$ProxiesCardSelectorStateImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({bool isSelected}); -} - -/// @nodoc -class __$$ProxiesCardSelectorStateImplCopyWithImpl<$Res> - extends _$ProxiesCardSelectorStateCopyWithImpl<$Res, - _$ProxiesCardSelectorStateImpl> - implements _$$ProxiesCardSelectorStateImplCopyWith<$Res> { - __$$ProxiesCardSelectorStateImplCopyWithImpl( - _$ProxiesCardSelectorStateImpl _value, - $Res Function(_$ProxiesCardSelectorStateImpl) _then) - : super(_value, _then); - - /// Create a copy of ProxiesCardSelectorState - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? isSelected = null, - }) { - return _then(_$ProxiesCardSelectorStateImpl( - isSelected: null == isSelected - ? _value.isSelected - : isSelected // ignore: cast_nullable_to_non_nullable - as bool, - )); - } -} - -/// @nodoc - -class _$ProxiesCardSelectorStateImpl implements _ProxiesCardSelectorState { - const _$ProxiesCardSelectorStateImpl({required this.isSelected}); - - @override - final bool isSelected; - - @override - String toString() { - return 'ProxiesCardSelectorState(isSelected: $isSelected)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$ProxiesCardSelectorStateImpl && - (identical(other.isSelected, isSelected) || - other.isSelected == isSelected)); - } - - @override - int get hashCode => Object.hash(runtimeType, isSelected); - - /// Create a copy of ProxiesCardSelectorState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$ProxiesCardSelectorStateImplCopyWith<_$ProxiesCardSelectorStateImpl> - get copyWith => __$$ProxiesCardSelectorStateImplCopyWithImpl< - _$ProxiesCardSelectorStateImpl>(this, _$identity); -} - -abstract class _ProxiesCardSelectorState implements ProxiesCardSelectorState { - const factory _ProxiesCardSelectorState({required final bool isSelected}) = - _$ProxiesCardSelectorStateImpl; - - @override - bool get isSelected; - - /// Create a copy of ProxiesCardSelectorState - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$ProxiesCardSelectorStateImplCopyWith<_$ProxiesCardSelectorStateImpl> - get copyWith => throw _privateConstructorUsedError; -} - /// @nodoc mixin _$ProxiesSelectorState { List get groupNames => throw _privateConstructorUsedError; @@ -2034,6 +1204,418 @@ abstract class _ProxiesSelectorState implements ProxiesSelectorState { get copyWith => throw _privateConstructorUsedError; } +/// @nodoc +mixin _$GroupNamesState { + List get groupNames => throw _privateConstructorUsedError; + + /// Create a copy of GroupNamesState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $GroupNamesStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $GroupNamesStateCopyWith<$Res> { + factory $GroupNamesStateCopyWith( + GroupNamesState value, $Res Function(GroupNamesState) then) = + _$GroupNamesStateCopyWithImpl<$Res, GroupNamesState>; + @useResult + $Res call({List groupNames}); +} + +/// @nodoc +class _$GroupNamesStateCopyWithImpl<$Res, $Val extends GroupNamesState> + implements $GroupNamesStateCopyWith<$Res> { + _$GroupNamesStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of GroupNamesState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? groupNames = null, + }) { + return _then(_value.copyWith( + groupNames: null == groupNames + ? _value.groupNames + : groupNames // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$GroupNamesStateImplCopyWith<$Res> + implements $GroupNamesStateCopyWith<$Res> { + factory _$$GroupNamesStateImplCopyWith(_$GroupNamesStateImpl value, + $Res Function(_$GroupNamesStateImpl) then) = + __$$GroupNamesStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({List groupNames}); +} + +/// @nodoc +class __$$GroupNamesStateImplCopyWithImpl<$Res> + extends _$GroupNamesStateCopyWithImpl<$Res, _$GroupNamesStateImpl> + implements _$$GroupNamesStateImplCopyWith<$Res> { + __$$GroupNamesStateImplCopyWithImpl( + _$GroupNamesStateImpl _value, $Res Function(_$GroupNamesStateImpl) _then) + : super(_value, _then); + + /// Create a copy of GroupNamesState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? groupNames = null, + }) { + return _then(_$GroupNamesStateImpl( + groupNames: null == groupNames + ? _value._groupNames + : groupNames // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$GroupNamesStateImpl implements _GroupNamesState { + const _$GroupNamesStateImpl({required final List groupNames}) + : _groupNames = groupNames; + + final List _groupNames; + @override + List get groupNames { + if (_groupNames is EqualUnmodifiableListView) return _groupNames; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_groupNames); + } + + @override + String toString() { + return 'GroupNamesState(groupNames: $groupNames)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$GroupNamesStateImpl && + const DeepCollectionEquality() + .equals(other._groupNames, _groupNames)); + } + + @override + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(_groupNames)); + + /// Create a copy of GroupNamesState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$GroupNamesStateImplCopyWith<_$GroupNamesStateImpl> get copyWith => + __$$GroupNamesStateImplCopyWithImpl<_$GroupNamesStateImpl>( + this, _$identity); +} + +abstract class _GroupNamesState implements GroupNamesState { + const factory _GroupNamesState({required final List groupNames}) = + _$GroupNamesStateImpl; + + @override + List get groupNames; + + /// Create a copy of GroupNamesState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$GroupNamesStateImplCopyWith<_$GroupNamesStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$GroupsState { + List get value => throw _privateConstructorUsedError; + + /// Create a copy of GroupsState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $GroupsStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $GroupsStateCopyWith<$Res> { + factory $GroupsStateCopyWith( + GroupsState value, $Res Function(GroupsState) then) = + _$GroupsStateCopyWithImpl<$Res, GroupsState>; + @useResult + $Res call({List value}); +} + +/// @nodoc +class _$GroupsStateCopyWithImpl<$Res, $Val extends GroupsState> + implements $GroupsStateCopyWith<$Res> { + _$GroupsStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of GroupsState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? value = null, + }) { + return _then(_value.copyWith( + value: null == value + ? _value.value + : value // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$GroupsStateImplCopyWith<$Res> + implements $GroupsStateCopyWith<$Res> { + factory _$$GroupsStateImplCopyWith( + _$GroupsStateImpl value, $Res Function(_$GroupsStateImpl) then) = + __$$GroupsStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({List value}); +} + +/// @nodoc +class __$$GroupsStateImplCopyWithImpl<$Res> + extends _$GroupsStateCopyWithImpl<$Res, _$GroupsStateImpl> + implements _$$GroupsStateImplCopyWith<$Res> { + __$$GroupsStateImplCopyWithImpl( + _$GroupsStateImpl _value, $Res Function(_$GroupsStateImpl) _then) + : super(_value, _then); + + /// Create a copy of GroupsState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? value = null, + }) { + return _then(_$GroupsStateImpl( + value: null == value + ? _value._value + : value // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$GroupsStateImpl implements _GroupsState { + const _$GroupsStateImpl({required final List value}) : _value = value; + + final List _value; + @override + List get value { + if (_value is EqualUnmodifiableListView) return _value; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_value); + } + + @override + String toString() { + return 'GroupsState(value: $value)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$GroupsStateImpl && + const DeepCollectionEquality().equals(other._value, _value)); + } + + @override + int get hashCode => + Object.hash(runtimeType, const DeepCollectionEquality().hash(_value)); + + /// Create a copy of GroupsState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$GroupsStateImplCopyWith<_$GroupsStateImpl> get copyWith => + __$$GroupsStateImplCopyWithImpl<_$GroupsStateImpl>(this, _$identity); +} + +abstract class _GroupsState implements GroupsState { + const factory _GroupsState({required final List value}) = + _$GroupsStateImpl; + + @override + List get value; + + /// Create a copy of GroupsState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$GroupsStateImplCopyWith<_$GroupsStateImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$NavigationItemsState { + List get value => throw _privateConstructorUsedError; + + /// Create a copy of NavigationItemsState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $NavigationItemsStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $NavigationItemsStateCopyWith<$Res> { + factory $NavigationItemsStateCopyWith(NavigationItemsState value, + $Res Function(NavigationItemsState) then) = + _$NavigationItemsStateCopyWithImpl<$Res, NavigationItemsState>; + @useResult + $Res call({List value}); +} + +/// @nodoc +class _$NavigationItemsStateCopyWithImpl<$Res, + $Val extends NavigationItemsState> + implements $NavigationItemsStateCopyWith<$Res> { + _$NavigationItemsStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of NavigationItemsState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? value = null, + }) { + return _then(_value.copyWith( + value: null == value + ? _value.value + : value // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$NavigationItemsStateImplCopyWith<$Res> + implements $NavigationItemsStateCopyWith<$Res> { + factory _$$NavigationItemsStateImplCopyWith(_$NavigationItemsStateImpl value, + $Res Function(_$NavigationItemsStateImpl) then) = + __$$NavigationItemsStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({List value}); +} + +/// @nodoc +class __$$NavigationItemsStateImplCopyWithImpl<$Res> + extends _$NavigationItemsStateCopyWithImpl<$Res, _$NavigationItemsStateImpl> + implements _$$NavigationItemsStateImplCopyWith<$Res> { + __$$NavigationItemsStateImplCopyWithImpl(_$NavigationItemsStateImpl _value, + $Res Function(_$NavigationItemsStateImpl) _then) + : super(_value, _then); + + /// Create a copy of NavigationItemsState + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? value = null, + }) { + return _then(_$NavigationItemsStateImpl( + value: null == value + ? _value._value + : value // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$NavigationItemsStateImpl implements _NavigationItemsState { + const _$NavigationItemsStateImpl({required final List value}) + : _value = value; + + final List _value; + @override + List get value { + if (_value is EqualUnmodifiableListView) return _value; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_value); + } + + @override + String toString() { + return 'NavigationItemsState(value: $value)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$NavigationItemsStateImpl && + const DeepCollectionEquality().equals(other._value, _value)); + } + + @override + int get hashCode => + Object.hash(runtimeType, const DeepCollectionEquality().hash(_value)); + + /// Create a copy of NavigationItemsState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$NavigationItemsStateImplCopyWith<_$NavigationItemsStateImpl> + get copyWith => + __$$NavigationItemsStateImplCopyWithImpl<_$NavigationItemsStateImpl>( + this, _$identity); +} + +abstract class _NavigationItemsState implements NavigationItemsState { + const factory _NavigationItemsState( + {required final List value}) = _$NavigationItemsStateImpl; + + @override + List get value; + + /// Create a copy of NavigationItemsState + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$NavigationItemsStateImplCopyWith<_$NavigationItemsStateImpl> + get copyWith => throw _privateConstructorUsedError; +} + /// @nodoc mixin _$ProxiesListSelectorState { List get groupNames => throw _privateConstructorUsedError; @@ -2720,7 +2302,6 @@ abstract class _MoreToolsSelectorState implements MoreToolsSelectorState { mixin _$PackageListSelectorState { List get packages => throw _privateConstructorUsedError; AccessControl get accessControl => throw _privateConstructorUsedError; - bool get isAccessControl => throw _privateConstructorUsedError; /// Create a copy of PackageListSelectorState /// with the given fields replaced by the non-null parameter values. @@ -2735,10 +2316,7 @@ abstract class $PackageListSelectorStateCopyWith<$Res> { $Res Function(PackageListSelectorState) then) = _$PackageListSelectorStateCopyWithImpl<$Res, PackageListSelectorState>; @useResult - $Res call( - {List packages, - AccessControl accessControl, - bool isAccessControl}); + $Res call({List packages, AccessControl accessControl}); $AccessControlCopyWith<$Res> get accessControl; } @@ -2761,7 +2339,6 @@ class _$PackageListSelectorStateCopyWithImpl<$Res, $Res call({ Object? packages = null, Object? accessControl = null, - Object? isAccessControl = null, }) { return _then(_value.copyWith( packages: null == packages @@ -2772,10 +2349,6 @@ class _$PackageListSelectorStateCopyWithImpl<$Res, ? _value.accessControl : accessControl // ignore: cast_nullable_to_non_nullable as AccessControl, - isAccessControl: null == isAccessControl - ? _value.isAccessControl - : isAccessControl // ignore: cast_nullable_to_non_nullable - as bool, ) as $Val); } @@ -2799,10 +2372,7 @@ abstract class _$$PackageListSelectorStateImplCopyWith<$Res> __$$PackageListSelectorStateImplCopyWithImpl<$Res>; @override @useResult - $Res call( - {List packages, - AccessControl accessControl, - bool isAccessControl}); + $Res call({List packages, AccessControl accessControl}); @override $AccessControlCopyWith<$Res> get accessControl; @@ -2825,7 +2395,6 @@ class __$$PackageListSelectorStateImplCopyWithImpl<$Res> $Res call({ Object? packages = null, Object? accessControl = null, - Object? isAccessControl = null, }) { return _then(_$PackageListSelectorStateImpl( packages: null == packages @@ -2836,10 +2405,6 @@ class __$$PackageListSelectorStateImplCopyWithImpl<$Res> ? _value.accessControl : accessControl // ignore: cast_nullable_to_non_nullable as AccessControl, - isAccessControl: null == isAccessControl - ? _value.isAccessControl - : isAccessControl // ignore: cast_nullable_to_non_nullable - as bool, )); } } @@ -2848,9 +2413,7 @@ class __$$PackageListSelectorStateImplCopyWithImpl<$Res> class _$PackageListSelectorStateImpl implements _PackageListSelectorState { const _$PackageListSelectorStateImpl( - {required final List packages, - required this.accessControl, - required this.isAccessControl}) + {required final List packages, required this.accessControl}) : _packages = packages; final List _packages; @@ -2863,12 +2426,10 @@ class _$PackageListSelectorStateImpl implements _PackageListSelectorState { @override final AccessControl accessControl; - @override - final bool isAccessControl; @override String toString() { - return 'PackageListSelectorState(packages: $packages, accessControl: $accessControl, isAccessControl: $isAccessControl)'; + return 'PackageListSelectorState(packages: $packages, accessControl: $accessControl)'; } @override @@ -2878,17 +2439,12 @@ class _$PackageListSelectorStateImpl implements _PackageListSelectorState { other is _$PackageListSelectorStateImpl && const DeepCollectionEquality().equals(other._packages, _packages) && (identical(other.accessControl, accessControl) || - other.accessControl == accessControl) && - (identical(other.isAccessControl, isAccessControl) || - other.isAccessControl == isAccessControl)); + other.accessControl == accessControl)); } @override - int get hashCode => Object.hash( - runtimeType, - const DeepCollectionEquality().hash(_packages), - accessControl, - isAccessControl); + int get hashCode => Object.hash(runtimeType, + const DeepCollectionEquality().hash(_packages), accessControl); /// Create a copy of PackageListSelectorState /// with the given fields replaced by the non-null parameter values. @@ -2902,16 +2458,14 @@ class _$PackageListSelectorStateImpl implements _PackageListSelectorState { abstract class _PackageListSelectorState implements PackageListSelectorState { const factory _PackageListSelectorState( - {required final List packages, - required final AccessControl accessControl, - required final bool isAccessControl}) = _$PackageListSelectorStateImpl; + {required final List packages, + required final AccessControl accessControl}) = + _$PackageListSelectorStateImpl; @override List get packages; @override AccessControl get accessControl; - @override - bool get isAccessControl; /// Create a copy of PackageListSelectorState /// with the given fields replaced by the non-null parameter values. @@ -3082,8 +2636,9 @@ abstract class _ProxiesListHeaderSelectorState /// @nodoc mixin _$ProxiesActionsState { - bool get isCurrent => throw _privateConstructorUsedError; - bool get hasProvider => throw _privateConstructorUsedError; + PageLabel get pageLabel => throw _privateConstructorUsedError; + ProxiesType get type => throw _privateConstructorUsedError; + bool get hasProviders => throw _privateConstructorUsedError; /// Create a copy of ProxiesActionsState /// with the given fields replaced by the non-null parameter values. @@ -3098,7 +2653,7 @@ abstract class $ProxiesActionsStateCopyWith<$Res> { ProxiesActionsState value, $Res Function(ProxiesActionsState) then) = _$ProxiesActionsStateCopyWithImpl<$Res, ProxiesActionsState>; @useResult - $Res call({bool isCurrent, bool hasProvider}); + $Res call({PageLabel pageLabel, ProxiesType type, bool hasProviders}); } /// @nodoc @@ -3116,17 +2671,22 @@ class _$ProxiesActionsStateCopyWithImpl<$Res, $Val extends ProxiesActionsState> @pragma('vm:prefer-inline') @override $Res call({ - Object? isCurrent = null, - Object? hasProvider = null, + Object? pageLabel = null, + Object? type = null, + Object? hasProviders = null, }) { return _then(_value.copyWith( - isCurrent: null == isCurrent - ? _value.isCurrent - : isCurrent // ignore: cast_nullable_to_non_nullable - as bool, - hasProvider: null == hasProvider - ? _value.hasProvider - : hasProvider // ignore: cast_nullable_to_non_nullable + pageLabel: null == pageLabel + ? _value.pageLabel + : pageLabel // ignore: cast_nullable_to_non_nullable + as PageLabel, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as ProxiesType, + hasProviders: null == hasProviders + ? _value.hasProviders + : hasProviders // ignore: cast_nullable_to_non_nullable as bool, ) as $Val); } @@ -3140,7 +2700,7 @@ abstract class _$$ProxiesActionsStateImplCopyWith<$Res> __$$ProxiesActionsStateImplCopyWithImpl<$Res>; @override @useResult - $Res call({bool isCurrent, bool hasProvider}); + $Res call({PageLabel pageLabel, ProxiesType type, bool hasProviders}); } /// @nodoc @@ -3156,17 +2716,22 @@ class __$$ProxiesActionsStateImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? isCurrent = null, - Object? hasProvider = null, + Object? pageLabel = null, + Object? type = null, + Object? hasProviders = null, }) { return _then(_$ProxiesActionsStateImpl( - isCurrent: null == isCurrent - ? _value.isCurrent - : isCurrent // ignore: cast_nullable_to_non_nullable - as bool, - hasProvider: null == hasProvider - ? _value.hasProvider - : hasProvider // ignore: cast_nullable_to_non_nullable + pageLabel: null == pageLabel + ? _value.pageLabel + : pageLabel // ignore: cast_nullable_to_non_nullable + as PageLabel, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as ProxiesType, + hasProviders: null == hasProviders + ? _value.hasProviders + : hasProviders // ignore: cast_nullable_to_non_nullable as bool, )); } @@ -3176,16 +2741,20 @@ class __$$ProxiesActionsStateImplCopyWithImpl<$Res> class _$ProxiesActionsStateImpl implements _ProxiesActionsState { const _$ProxiesActionsStateImpl( - {required this.isCurrent, required this.hasProvider}); + {required this.pageLabel, + required this.type, + required this.hasProviders}); @override - final bool isCurrent; + final PageLabel pageLabel; @override - final bool hasProvider; + final ProxiesType type; + @override + final bool hasProviders; @override String toString() { - return 'ProxiesActionsState(isCurrent: $isCurrent, hasProvider: $hasProvider)'; + return 'ProxiesActionsState(pageLabel: $pageLabel, type: $type, hasProviders: $hasProviders)'; } @override @@ -3193,14 +2762,15 @@ class _$ProxiesActionsStateImpl implements _ProxiesActionsState { return identical(this, other) || (other.runtimeType == runtimeType && other is _$ProxiesActionsStateImpl && - (identical(other.isCurrent, isCurrent) || - other.isCurrent == isCurrent) && - (identical(other.hasProvider, hasProvider) || - other.hasProvider == hasProvider)); + (identical(other.pageLabel, pageLabel) || + other.pageLabel == pageLabel) && + (identical(other.type, type) || other.type == type) && + (identical(other.hasProviders, hasProviders) || + other.hasProviders == hasProviders)); } @override - int get hashCode => Object.hash(runtimeType, isCurrent, hasProvider); + int get hashCode => Object.hash(runtimeType, pageLabel, type, hasProviders); /// Create a copy of ProxiesActionsState /// with the given fields replaced by the non-null parameter values. @@ -3214,13 +2784,16 @@ class _$ProxiesActionsStateImpl implements _ProxiesActionsState { abstract class _ProxiesActionsState implements ProxiesActionsState { const factory _ProxiesActionsState( - {required final bool isCurrent, - required final bool hasProvider}) = _$ProxiesActionsStateImpl; + {required final PageLabel pageLabel, + required final ProxiesType type, + required final bool hasProviders}) = _$ProxiesActionsStateImpl; @override - bool get isCurrent; + PageLabel get pageLabel; @override - bool get hasProvider; + ProxiesType get type; + @override + bool get hasProviders; /// Create a copy of ProxiesActionsState /// with the given fields replaced by the non-null parameter values. @@ -3426,173 +2999,10 @@ abstract class _ProxyState implements ProxyState { throw _privateConstructorUsedError; } -/// @nodoc -mixin _$HttpOverridesState { - bool get isStart => throw _privateConstructorUsedError; - int get port => throw _privateConstructorUsedError; - - /// Create a copy of HttpOverridesState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $HttpOverridesStateCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $HttpOverridesStateCopyWith<$Res> { - factory $HttpOverridesStateCopyWith( - HttpOverridesState value, $Res Function(HttpOverridesState) then) = - _$HttpOverridesStateCopyWithImpl<$Res, HttpOverridesState>; - @useResult - $Res call({bool isStart, int port}); -} - -/// @nodoc -class _$HttpOverridesStateCopyWithImpl<$Res, $Val extends HttpOverridesState> - implements $HttpOverridesStateCopyWith<$Res> { - _$HttpOverridesStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of HttpOverridesState - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? isStart = null, - Object? port = null, - }) { - return _then(_value.copyWith( - isStart: null == isStart - ? _value.isStart - : isStart // ignore: cast_nullable_to_non_nullable - as bool, - port: null == port - ? _value.port - : port // ignore: cast_nullable_to_non_nullable - as int, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$HttpOverridesStateImplCopyWith<$Res> - implements $HttpOverridesStateCopyWith<$Res> { - factory _$$HttpOverridesStateImplCopyWith(_$HttpOverridesStateImpl value, - $Res Function(_$HttpOverridesStateImpl) then) = - __$$HttpOverridesStateImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({bool isStart, int port}); -} - -/// @nodoc -class __$$HttpOverridesStateImplCopyWithImpl<$Res> - extends _$HttpOverridesStateCopyWithImpl<$Res, _$HttpOverridesStateImpl> - implements _$$HttpOverridesStateImplCopyWith<$Res> { - __$$HttpOverridesStateImplCopyWithImpl(_$HttpOverridesStateImpl _value, - $Res Function(_$HttpOverridesStateImpl) _then) - : super(_value, _then); - - /// Create a copy of HttpOverridesState - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? isStart = null, - Object? port = null, - }) { - return _then(_$HttpOverridesStateImpl( - isStart: null == isStart - ? _value.isStart - : isStart // ignore: cast_nullable_to_non_nullable - as bool, - port: null == port - ? _value.port - : port // ignore: cast_nullable_to_non_nullable - as int, - )); - } -} - -/// @nodoc - -class _$HttpOverridesStateImpl implements _HttpOverridesState { - const _$HttpOverridesStateImpl({required this.isStart, required this.port}); - - @override - final bool isStart; - @override - final int port; - - @override - String toString() { - return 'HttpOverridesState(isStart: $isStart, port: $port)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$HttpOverridesStateImpl && - (identical(other.isStart, isStart) || other.isStart == isStart) && - (identical(other.port, port) || other.port == port)); - } - - @override - int get hashCode => Object.hash(runtimeType, isStart, port); - - /// Create a copy of HttpOverridesState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$HttpOverridesStateImplCopyWith<_$HttpOverridesStateImpl> get copyWith => - __$$HttpOverridesStateImplCopyWithImpl<_$HttpOverridesStateImpl>( - this, _$identity); -} - -abstract class _HttpOverridesState implements HttpOverridesState { - const factory _HttpOverridesState( - {required final bool isStart, - required final int port}) = _$HttpOverridesStateImpl; - - @override - bool get isStart; - @override - int get port; - - /// Create a copy of HttpOverridesState - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$HttpOverridesStateImplCopyWith<_$HttpOverridesStateImpl> get copyWith => - throw _privateConstructorUsedError; -} - /// @nodoc 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; - Mode get mode => throw _privateConstructorUsedError; - FindProcessMode get findProcessMode => throw _privateConstructorUsedError; - int get keepAliveInterval => throw _privateConstructorUsedError; - bool get unifiedDelay => throw _privateConstructorUsedError; - bool get tcpConcurrent => throw _privateConstructorUsedError; - Map get hosts => throw _privateConstructorUsedError; - Tun get tun => throw _privateConstructorUsedError; - Dns get dns => throw _privateConstructorUsedError; - Map get geoXUrl => throw _privateConstructorUsedError; - List get rules => throw _privateConstructorUsedError; - String? get globalRealUa => throw _privateConstructorUsedError; + ClashConfig get clashConfig => throw _privateConstructorUsedError; /// Create a copy of ClashConfigState /// with the given fields replaced by the non-null parameter values. @@ -3607,28 +3017,9 @@ abstract class $ClashConfigStateCopyWith<$Res> { ClashConfigState value, $Res Function(ClashConfigState) then) = _$ClashConfigStateCopyWithImpl<$Res, ClashConfigState>; @useResult - $Res call( - {int mixedPort, - bool allowLan, - bool ipv6, - bool overrideDns, - String geodataLoader, - LogLevel logLevel, - String externalController, - Mode mode, - FindProcessMode findProcessMode, - int keepAliveInterval, - bool unifiedDelay, - bool tcpConcurrent, - Map hosts, - Tun tun, - Dns dns, - Map geoXUrl, - List rules, - String? globalRealUa}); + $Res call({bool overrideDns, ClashConfig clashConfig}); - $TunCopyWith<$Res> get tun; - $DnsCopyWith<$Res> get dns; + $ClashConfigCopyWith<$Res> get clashConfig; } /// @nodoc @@ -3646,98 +3037,18 @@ class _$ClashConfigStateCopyWithImpl<$Res, $Val extends ClashConfigState> @pragma('vm:prefer-inline') @override $Res call({ - Object? mixedPort = null, - Object? allowLan = null, - Object? ipv6 = null, Object? overrideDns = null, - Object? geodataLoader = null, - Object? logLevel = null, - Object? externalController = null, - Object? mode = null, - Object? findProcessMode = null, - Object? keepAliveInterval = null, - Object? unifiedDelay = null, - Object? tcpConcurrent = null, - Object? hosts = null, - Object? tun = null, - Object? dns = null, - Object? geoXUrl = null, - Object? rules = null, - Object? globalRealUa = freezed, + Object? clashConfig = null, }) { return _then(_value.copyWith( - mixedPort: null == mixedPort - ? _value.mixedPort - : mixedPort // ignore: cast_nullable_to_non_nullable - as int, - allowLan: null == allowLan - ? _value.allowLan - : allowLan // ignore: cast_nullable_to_non_nullable - as bool, - ipv6: null == ipv6 - ? _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 - as String, - logLevel: null == logLevel - ? _value.logLevel - : logLevel // ignore: cast_nullable_to_non_nullable - as LogLevel, - externalController: null == externalController - ? _value.externalController - : externalController // ignore: cast_nullable_to_non_nullable - as String, - mode: null == mode - ? _value.mode - : mode // ignore: cast_nullable_to_non_nullable - as Mode, - findProcessMode: null == findProcessMode - ? _value.findProcessMode - : findProcessMode // ignore: cast_nullable_to_non_nullable - as FindProcessMode, - keepAliveInterval: null == keepAliveInterval - ? _value.keepAliveInterval - : keepAliveInterval // ignore: cast_nullable_to_non_nullable - as int, - unifiedDelay: null == unifiedDelay - ? _value.unifiedDelay - : unifiedDelay // ignore: cast_nullable_to_non_nullable - as bool, - tcpConcurrent: null == tcpConcurrent - ? _value.tcpConcurrent - : tcpConcurrent // ignore: cast_nullable_to_non_nullable - as bool, - hosts: null == hosts - ? _value.hosts - : hosts // ignore: cast_nullable_to_non_nullable - as Map, - tun: null == tun - ? _value.tun - : tun // ignore: cast_nullable_to_non_nullable - as Tun, - dns: null == dns - ? _value.dns - : dns // ignore: cast_nullable_to_non_nullable - as Dns, - geoXUrl: null == geoXUrl - ? _value.geoXUrl - : geoXUrl // ignore: cast_nullable_to_non_nullable - as Map, - rules: null == rules - ? _value.rules - : rules // ignore: cast_nullable_to_non_nullable - as List, - globalRealUa: freezed == globalRealUa - ? _value.globalRealUa - : globalRealUa // ignore: cast_nullable_to_non_nullable - as String?, + clashConfig: null == clashConfig + ? _value.clashConfig + : clashConfig // ignore: cast_nullable_to_non_nullable + as ClashConfig, ) as $Val); } @@ -3745,19 +3056,9 @@ class _$ClashConfigStateCopyWithImpl<$Res, $Val extends ClashConfigState> /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') - $TunCopyWith<$Res> get tun { - return $TunCopyWith<$Res>(_value.tun, (value) { - return _then(_value.copyWith(tun: value) as $Val); - }); - } - - /// Create a copy of ClashConfigState - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $DnsCopyWith<$Res> get dns { - return $DnsCopyWith<$Res>(_value.dns, (value) { - return _then(_value.copyWith(dns: value) as $Val); + $ClashConfigCopyWith<$Res> get clashConfig { + return $ClashConfigCopyWith<$Res>(_value.clashConfig, (value) { + return _then(_value.copyWith(clashConfig: value) as $Val); }); } } @@ -3770,30 +3071,10 @@ abstract class _$$ClashConfigStateImplCopyWith<$Res> __$$ClashConfigStateImplCopyWithImpl<$Res>; @override @useResult - $Res call( - {int mixedPort, - bool allowLan, - bool ipv6, - bool overrideDns, - String geodataLoader, - LogLevel logLevel, - String externalController, - Mode mode, - FindProcessMode findProcessMode, - int keepAliveInterval, - bool unifiedDelay, - bool tcpConcurrent, - Map hosts, - Tun tun, - Dns dns, - Map geoXUrl, - List rules, - String? globalRealUa}); + $Res call({bool overrideDns, ClashConfig clashConfig}); @override - $TunCopyWith<$Res> get tun; - @override - $DnsCopyWith<$Res> get dns; + $ClashConfigCopyWith<$Res> get clashConfig; } /// @nodoc @@ -3809,98 +3090,18 @@ class __$$ClashConfigStateImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? mixedPort = null, - Object? allowLan = null, - Object? ipv6 = null, Object? overrideDns = null, - Object? geodataLoader = null, - Object? logLevel = null, - Object? externalController = null, - Object? mode = null, - Object? findProcessMode = null, - Object? keepAliveInterval = null, - Object? unifiedDelay = null, - Object? tcpConcurrent = null, - Object? hosts = null, - Object? tun = null, - Object? dns = null, - Object? geoXUrl = null, - Object? rules = null, - Object? globalRealUa = freezed, + Object? clashConfig = null, }) { return _then(_$ClashConfigStateImpl( - mixedPort: null == mixedPort - ? _value.mixedPort - : mixedPort // ignore: cast_nullable_to_non_nullable - as int, - allowLan: null == allowLan - ? _value.allowLan - : allowLan // ignore: cast_nullable_to_non_nullable - as bool, - ipv6: null == ipv6 - ? _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 - as String, - logLevel: null == logLevel - ? _value.logLevel - : logLevel // ignore: cast_nullable_to_non_nullable - as LogLevel, - externalController: null == externalController - ? _value.externalController - : externalController // ignore: cast_nullable_to_non_nullable - as String, - mode: null == mode - ? _value.mode - : mode // ignore: cast_nullable_to_non_nullable - as Mode, - findProcessMode: null == findProcessMode - ? _value.findProcessMode - : findProcessMode // ignore: cast_nullable_to_non_nullable - as FindProcessMode, - keepAliveInterval: null == keepAliveInterval - ? _value.keepAliveInterval - : keepAliveInterval // ignore: cast_nullable_to_non_nullable - as int, - unifiedDelay: null == unifiedDelay - ? _value.unifiedDelay - : unifiedDelay // ignore: cast_nullable_to_non_nullable - as bool, - tcpConcurrent: null == tcpConcurrent - ? _value.tcpConcurrent - : tcpConcurrent // ignore: cast_nullable_to_non_nullable - as bool, - hosts: null == hosts - ? _value._hosts - : hosts // ignore: cast_nullable_to_non_nullable - as Map, - tun: null == tun - ? _value.tun - : tun // ignore: cast_nullable_to_non_nullable - as Tun, - dns: null == dns - ? _value.dns - : dns // ignore: cast_nullable_to_non_nullable - as Dns, - geoXUrl: null == geoXUrl - ? _value._geoXUrl - : geoXUrl // ignore: cast_nullable_to_non_nullable - as Map, - rules: null == rules - ? _value._rules - : rules // ignore: cast_nullable_to_non_nullable - as List, - globalRealUa: freezed == globalRealUa - ? _value.globalRealUa - : globalRealUa // ignore: cast_nullable_to_non_nullable - as String?, + clashConfig: null == clashConfig + ? _value.clashConfig + : clashConfig // ignore: cast_nullable_to_non_nullable + as ClashConfig, )); } } @@ -3909,86 +3110,16 @@ class __$$ClashConfigStateImplCopyWithImpl<$Res> class _$ClashConfigStateImpl implements _ClashConfigState { const _$ClashConfigStateImpl( - {required this.mixedPort, - required this.allowLan, - required this.ipv6, - required this.overrideDns, - required this.geodataLoader, - required this.logLevel, - required this.externalController, - required this.mode, - required this.findProcessMode, - required this.keepAliveInterval, - required this.unifiedDelay, - required this.tcpConcurrent, - required final Map hosts, - required this.tun, - required this.dns, - required final Map geoXUrl, - required final List rules, - required this.globalRealUa}) - : _hosts = hosts, - _geoXUrl = geoXUrl, - _rules = rules; + {required this.overrideDns, required this.clashConfig}); - @override - final int mixedPort; - @override - final bool allowLan; - @override - final bool ipv6; @override final bool overrideDns; @override - final String geodataLoader; - @override - final LogLevel logLevel; - @override - final String externalController; - @override - final Mode mode; - @override - final FindProcessMode findProcessMode; - @override - final int keepAliveInterval; - @override - final bool unifiedDelay; - @override - final bool tcpConcurrent; - final Map _hosts; - @override - Map get hosts { - if (_hosts is EqualUnmodifiableMapView) return _hosts; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_hosts); - } - - @override - final Tun tun; - @override - final Dns dns; - final Map _geoXUrl; - @override - Map get geoXUrl { - if (_geoXUrl is EqualUnmodifiableMapView) return _geoXUrl; - // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_geoXUrl); - } - - final List _rules; - @override - List get rules { - if (_rules is EqualUnmodifiableListView) return _rules; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_rules); - } - - @override - final String? globalRealUa; + final ClashConfig clashConfig; @override String toString() { - 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)'; + return 'ClashConfigState(overrideDns: $overrideDns, clashConfig: $clashConfig)'; } @override @@ -3996,58 +3127,14 @@ class _$ClashConfigStateImpl implements _ClashConfigState { return identical(this, other) || (other.runtimeType == runtimeType && other is _$ClashConfigStateImpl && - (identical(other.mixedPort, mixedPort) || - other.mixedPort == mixedPort) && - (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) || - other.logLevel == logLevel) && - (identical(other.externalController, externalController) || - other.externalController == externalController) && - (identical(other.mode, mode) || other.mode == mode) && - (identical(other.findProcessMode, findProcessMode) || - other.findProcessMode == findProcessMode) && - (identical(other.keepAliveInterval, keepAliveInterval) || - other.keepAliveInterval == keepAliveInterval) && - (identical(other.unifiedDelay, unifiedDelay) || - other.unifiedDelay == unifiedDelay) && - (identical(other.tcpConcurrent, tcpConcurrent) || - other.tcpConcurrent == tcpConcurrent) && - const DeepCollectionEquality().equals(other._hosts, _hosts) && - (identical(other.tun, tun) || other.tun == tun) && - (identical(other.dns, dns) || other.dns == dns) && - const DeepCollectionEquality().equals(other._geoXUrl, _geoXUrl) && - const DeepCollectionEquality().equals(other._rules, _rules) && - (identical(other.globalRealUa, globalRealUa) || - other.globalRealUa == globalRealUa)); + (identical(other.clashConfig, clashConfig) || + other.clashConfig == clashConfig)); } @override - int get hashCode => Object.hash( - runtimeType, - mixedPort, - allowLan, - ipv6, - overrideDns, - geodataLoader, - logLevel, - externalController, - mode, - findProcessMode, - keepAliveInterval, - unifiedDelay, - tcpConcurrent, - const DeepCollectionEquality().hash(_hosts), - tun, - dns, - const DeepCollectionEquality().hash(_geoXUrl), - const DeepCollectionEquality().hash(_rules), - globalRealUa); + int get hashCode => Object.hash(runtimeType, overrideDns, clashConfig); /// Create a copy of ClashConfigState /// with the given fields replaced by the non-null parameter values. @@ -4061,61 +3148,13 @@ class _$ClashConfigStateImpl implements _ClashConfigState { abstract class _ClashConfigState implements ClashConfigState { const factory _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, - required final Mode mode, - required final FindProcessMode findProcessMode, - required final int keepAliveInterval, - required final bool unifiedDelay, - required final bool tcpConcurrent, - required final Map hosts, - required final Tun tun, - required final Dns dns, - required final Map geoXUrl, - required final List rules, - required final String? globalRealUa}) = _$ClashConfigStateImpl; + {required final bool overrideDns, + required final ClashConfig clashConfig}) = _$ClashConfigStateImpl; - @override - int get mixedPort; - @override - bool get allowLan; - @override - bool get ipv6; @override bool get overrideDns; @override - String get geodataLoader; - @override - LogLevel get logLevel; - @override - String get externalController; - @override - Mode get mode; - @override - FindProcessMode get findProcessMode; - @override - int get keepAliveInterval; - @override - bool get unifiedDelay; - @override - bool get tcpConcurrent; - @override - Map get hosts; - @override - Tun get tun; - @override - Dns get dns; - @override - Map get geoXUrl; - @override - List get rules; - @override - String? get globalRealUa; + ClashConfig get clashConfig; /// Create a copy of ClashConfigState /// with the given fields replaced by the non-null parameter values. @@ -4287,53 +3326,46 @@ abstract class _DashboardState implements DashboardState { } /// @nodoc -mixin _$VPNState { - AccessControl? get accessControl => throw _privateConstructorUsedError; +mixin _$VpnState { TunStack get stack => throw _privateConstructorUsedError; VpnProps get vpnProps => throw _privateConstructorUsedError; - /// Create a copy of VPNState + /// Create a copy of VpnState /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) - $VPNStateCopyWith get copyWith => + $VpnStateCopyWith get copyWith => throw _privateConstructorUsedError; } /// @nodoc -abstract class $VPNStateCopyWith<$Res> { - factory $VPNStateCopyWith(VPNState value, $Res Function(VPNState) then) = - _$VPNStateCopyWithImpl<$Res, VPNState>; +abstract class $VpnStateCopyWith<$Res> { + factory $VpnStateCopyWith(VpnState value, $Res Function(VpnState) then) = + _$VpnStateCopyWithImpl<$Res, VpnState>; @useResult - $Res call({AccessControl? accessControl, TunStack stack, VpnProps vpnProps}); + $Res call({TunStack stack, VpnProps vpnProps}); - $AccessControlCopyWith<$Res>? get accessControl; $VpnPropsCopyWith<$Res> get vpnProps; } /// @nodoc -class _$VPNStateCopyWithImpl<$Res, $Val extends VPNState> - implements $VPNStateCopyWith<$Res> { - _$VPNStateCopyWithImpl(this._value, this._then); +class _$VpnStateCopyWithImpl<$Res, $Val extends VpnState> + implements $VpnStateCopyWith<$Res> { + _$VpnStateCopyWithImpl(this._value, this._then); // ignore: unused_field final $Val _value; // ignore: unused_field final $Res Function($Val) _then; - /// Create a copy of VPNState + /// Create a copy of VpnState /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ - Object? accessControl = freezed, Object? stack = null, Object? vpnProps = null, }) { return _then(_value.copyWith( - accessControl: freezed == accessControl - ? _value.accessControl - : accessControl // ignore: cast_nullable_to_non_nullable - as AccessControl?, stack: null == stack ? _value.stack : stack // ignore: cast_nullable_to_non_nullable @@ -4345,21 +3377,7 @@ class _$VPNStateCopyWithImpl<$Res, $Val extends VPNState> ) as $Val); } - /// Create a copy of VPNState - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $AccessControlCopyWith<$Res>? get accessControl { - if (_value.accessControl == null) { - return null; - } - - return $AccessControlCopyWith<$Res>(_value.accessControl!, (value) { - return _then(_value.copyWith(accessControl: value) as $Val); - }); - } - - /// Create a copy of VPNState + /// Create a copy of VpnState /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') @@ -4371,43 +3389,36 @@ class _$VPNStateCopyWithImpl<$Res, $Val extends VPNState> } /// @nodoc -abstract class _$$VPNStateImplCopyWith<$Res> - implements $VPNStateCopyWith<$Res> { - factory _$$VPNStateImplCopyWith( - _$VPNStateImpl value, $Res Function(_$VPNStateImpl) then) = - __$$VPNStateImplCopyWithImpl<$Res>; +abstract class _$$VpnStateImplCopyWith<$Res> + implements $VpnStateCopyWith<$Res> { + factory _$$VpnStateImplCopyWith( + _$VpnStateImpl value, $Res Function(_$VpnStateImpl) then) = + __$$VpnStateImplCopyWithImpl<$Res>; @override @useResult - $Res call({AccessControl? accessControl, TunStack stack, VpnProps vpnProps}); + $Res call({TunStack stack, VpnProps vpnProps}); - @override - $AccessControlCopyWith<$Res>? get accessControl; @override $VpnPropsCopyWith<$Res> get vpnProps; } /// @nodoc -class __$$VPNStateImplCopyWithImpl<$Res> - extends _$VPNStateCopyWithImpl<$Res, _$VPNStateImpl> - implements _$$VPNStateImplCopyWith<$Res> { - __$$VPNStateImplCopyWithImpl( - _$VPNStateImpl _value, $Res Function(_$VPNStateImpl) _then) +class __$$VpnStateImplCopyWithImpl<$Res> + extends _$VpnStateCopyWithImpl<$Res, _$VpnStateImpl> + implements _$$VpnStateImplCopyWith<$Res> { + __$$VpnStateImplCopyWithImpl( + _$VpnStateImpl _value, $Res Function(_$VpnStateImpl) _then) : super(_value, _then); - /// Create a copy of VPNState + /// Create a copy of VpnState /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ - Object? accessControl = freezed, Object? stack = null, Object? vpnProps = null, }) { - return _then(_$VPNStateImpl( - accessControl: freezed == accessControl - ? _value.accessControl - : accessControl // ignore: cast_nullable_to_non_nullable - as AccessControl?, + return _then(_$VpnStateImpl( stack: null == stack ? _value.stack : stack // ignore: cast_nullable_to_non_nullable @@ -4422,14 +3433,9 @@ class __$$VPNStateImplCopyWithImpl<$Res> /// @nodoc -class _$VPNStateImpl implements _VPNState { - const _$VPNStateImpl( - {required this.accessControl, - required this.stack, - required this.vpnProps}); +class _$VpnStateImpl implements _VpnState { + const _$VpnStateImpl({required this.stack, required this.vpnProps}); - @override - final AccessControl? accessControl; @override final TunStack stack; @override @@ -4437,50 +3443,45 @@ class _$VPNStateImpl implements _VPNState { @override String toString() { - return 'VPNState(accessControl: $accessControl, stack: $stack, vpnProps: $vpnProps)'; + return 'VpnState(stack: $stack, vpnProps: $vpnProps)'; } @override bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && - other is _$VPNStateImpl && - (identical(other.accessControl, accessControl) || - other.accessControl == accessControl) && + other is _$VpnStateImpl && (identical(other.stack, stack) || other.stack == stack) && (identical(other.vpnProps, vpnProps) || other.vpnProps == vpnProps)); } @override - int get hashCode => Object.hash(runtimeType, accessControl, stack, vpnProps); + int get hashCode => Object.hash(runtimeType, stack, vpnProps); - /// Create a copy of VPNState + /// Create a copy of VpnState /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') - _$$VPNStateImplCopyWith<_$VPNStateImpl> get copyWith => - __$$VPNStateImplCopyWithImpl<_$VPNStateImpl>(this, _$identity); + _$$VpnStateImplCopyWith<_$VpnStateImpl> get copyWith => + __$$VpnStateImplCopyWithImpl<_$VpnStateImpl>(this, _$identity); } -abstract class _VPNState implements VPNState { - const factory _VPNState( - {required final AccessControl? accessControl, - required final TunStack stack, - required final VpnProps vpnProps}) = _$VPNStateImpl; +abstract class _VpnState implements VpnState { + const factory _VpnState( + {required final TunStack stack, + required final VpnProps vpnProps}) = _$VpnStateImpl; - @override - AccessControl? get accessControl; @override TunStack get stack; @override VpnProps get vpnProps; - /// Create a copy of VPNState + /// Create a copy of VpnState /// with the given fields replaced by the non-null parameter values. @override @JsonKey(includeFromJson: false, includeToJson: false) - _$$VPNStateImplCopyWith<_$VPNStateImpl> get copyWith => + _$$VpnStateImplCopyWith<_$VpnStateImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/lib/models/profile.dart b/lib/models/profile.dart index 112ad23..0653c42 100644 --- a/lib/models/profile.dart +++ b/lib/models/profile.dart @@ -76,6 +76,14 @@ class Profile with _$Profile { } } + +extension ProfilesExt on List { + Profile? getProfile(String? profileId) { + final index = indexWhere((profile) => profile.id == profileId); + return index == -1 ? null : this[index]; + } +} + extension ProfileExtension on Profile { ProfileType get type => url.isEmpty == true ? ProfileType.file : ProfileType.url; diff --git a/lib/models/selector.dart b/lib/models/selector.dart index c928c2a..6169225 100644 --- a/lib/models/selector.dart +++ b/lib/models/selector.dart @@ -15,22 +15,6 @@ class StartButtonSelectorState with _$StartButtonSelectorState { }) = _StartButtonSelectorState; } -@freezed -class CheckIpSelectorState with _$CheckIpSelectorState { - const factory CheckIpSelectorState({ - required String? currentProfileId, - required SelectedMap selectedMap, - }) = _CheckIpSelectorState; -} - -@freezed -class NetworkDetectionSelectorState with _$NetworkDetectionSelectorState { - const factory NetworkDetectionSelectorState({ - required String? currentProxyName, - required int? delay, - }) = _NetworkDetectionSelectorState; -} - @freezed class ProfilesSelectorState with _$ProfilesSelectorState { const factory ProfilesSelectorState({ @@ -48,17 +32,6 @@ class NetworkDetectionState with _$NetworkDetectionState { }) = _NetworkDetectionState; } -@freezed -class ApplicationSelectorState with _$ApplicationSelectorState { - const factory ApplicationSelectorState({ - required String? locale, - required ThemeMode? themeMode, - required int? primaryColor, - required bool prueBlack, - required FontFamily fontFamily, - }) = _ApplicationSelectorState; -} - @freezed class TrayState with _$TrayState { const factory TrayState({ @@ -71,35 +44,20 @@ class TrayState with _$TrayState { required String? locale, required Brightness? brightness, required List groups, - required SelectedMap map, + required SelectedMap selectedMap, }) = _TrayState; } -@freezed -class UpdateNavigationsSelector with _$UpdateNavigationsSelector { - const factory UpdateNavigationsSelector({ - required bool openLogs, - required bool hasProxies, - }) = _UpdateNavigationsSelector; -} - @freezed class HomeState with _$HomeState { const factory HomeState({ - required String currentLabel, + required PageLabel pageLabel, required List navigationItems, required ViewMode viewMode, required String? locale, }) = _HomeState; } -@freezed -class ProxiesCardSelectorState with _$ProxiesCardSelectorState { - const factory ProxiesCardSelectorState({ - required bool isSelected, - }) = _ProxiesCardSelectorState; -} - @freezed class ProxiesSelectorState with _$ProxiesSelectorState { const factory ProxiesSelectorState({ @@ -108,6 +66,27 @@ class ProxiesSelectorState with _$ProxiesSelectorState { }) = _ProxiesSelectorState; } +@freezed +class GroupNamesState with _$GroupNamesState { + const factory GroupNamesState({ + required List groupNames, + }) = _GroupNamesState; +} + +@freezed +class GroupsState with _$GroupsState { + const factory GroupsState({ + required List value, + }) = _GroupsState; +} + +@freezed +class NavigationItemsState with _$NavigationItemsState { + const factory NavigationItemsState({ + required List value, + }) = _NavigationItemsState; +} + @freezed class ProxiesListSelectorState with _$ProxiesListSelectorState { const factory ProxiesListSelectorState({ @@ -145,7 +124,6 @@ class PackageListSelectorState with _$PackageListSelectorState { const factory PackageListSelectorState({ required List packages, required AccessControl accessControl, - required bool isAccessControl, }) = _PackageListSelectorState; } @@ -163,8 +141,7 @@ extension PackageListSelectorStateExt on PackageListSelectorState { other.getPinyin(a.label), other.getPinyin(b.label), ), - AccessSortType.time => - b.lastUpdateTime.compareTo(a.lastUpdateTime), + AccessSortType.time => b.lastUpdateTime.compareTo(a.lastUpdateTime), }; }, ).sorted( @@ -191,8 +168,9 @@ class ProxiesListHeaderSelectorState with _$ProxiesListHeaderSelectorState { @freezed class ProxiesActionsState with _$ProxiesActionsState { const factory ProxiesActionsState({ - required bool isCurrent, - required bool hasProvider, + required PageLabel pageLabel, + required ProxiesType type, + required bool hasProviders, }) = _ProxiesActionsState; } @@ -206,35 +184,11 @@ class ProxyState with _$ProxyState { }) = _ProxyState; } -@freezed -class HttpOverridesState with _$HttpOverridesState { - const factory HttpOverridesState({ - required bool isStart, - required int port, - }) = _HttpOverridesState; -} - @freezed class ClashConfigState with _$ClashConfigState { const factory ClashConfigState({ - required int mixedPort, - required bool allowLan, - required bool ipv6, required bool overrideDns, - required String geodataLoader, - required LogLevel logLevel, - required String externalController, - required Mode mode, - required FindProcessMode findProcessMode, - required int keepAliveInterval, - required bool unifiedDelay, - required bool tcpConcurrent, - required HostsMap hosts, - required Tun tun, - required Dns dns, - required GeoXMap geoXUrl, - required List rules, - required String? globalRealUa, + required ClashConfig clashConfig, }) = _ClashConfigState; } @@ -247,10 +201,9 @@ class DashboardState with _$DashboardState { } @freezed -class VPNState with _$VPNState { - const factory VPNState({ - required AccessControl? accessControl, +class VpnState with _$VpnState { + const factory VpnState({ required TunStack stack, required VpnProps vpnProps, - }) = _VPNState; + }) = _VpnState; } diff --git a/lib/pages/home.dart b/lib/pages/home.dart index aeafb58..29813f7 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -1,85 +1,29 @@ 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/providers/providers.dart'; import 'package:fl_clash/state.dart'; +import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; - -import '../enum/enum.dart'; -import '../widgets/widgets.dart'; typedef OnSelected = void Function(int index); class HomePage extends StatelessWidget { const HomePage({super.key}); - _updatePageController(List navigationItems) { - final currentLabel = globalState.appController.appState.currentLabel; - final index = navigationItems.lastIndexWhere( - (element) => element.label == currentLabel, - ); - final currentIndex = index == -1 ? 0 : index; - if (globalState.pageController != null) { - WidgetsBinding.instance.addPostFrameCallback((_) { - globalState.appController.toPage( - currentIndex, - hasAnimate: true, - ); - }); - } else { - globalState.pageController = PageController( - initialPage: currentIndex, - keepPage: true, - ); - } - } - - Widget _buildPageView() { - return Selector>( - selector: (_, appState) => appState.currentNavigationItems, - shouldRebuild: (prev, next) { - return prev.length != next.length; - }, - builder: (_, navigationItems, __) { - _updatePageController(navigationItems); - return PageView.builder( - controller: globalState.pageController, - physics: const NeverScrollableScrollPhysics(), - itemCount: navigationItems.length, - itemBuilder: (_, index) { - final navigationItem = navigationItems[index]; - return KeepScope( - keep: navigationItem.keep, - key: Key(navigationItem.label), - child: navigationItem.fragment, - ); - }, - ); - }, - ); - } - @override Widget build(BuildContext context) { return BackScope( - child: Selector2( - selector: (_, appState, config) { - return HomeState( - currentLabel: appState.currentLabel, - navigationItems: appState.currentNavigationItems, - viewMode: appState.viewMode, - locale: config.appSetting.locale, - ); - }, - shouldRebuild: (prev, next) { - return prev != next; - }, - builder: (_, state, child) { + child: Consumer( + builder: (_, ref, child) { + final state = ref.watch(homeStateProvider); final viewMode = state.viewMode; final navigationItems = state.navigationItems; - final currentLabel = state.currentLabel; + final pageLabel = state.pageLabel; final index = navigationItems.lastIndexWhere( - (element) => element.label == currentLabel, + (element) => element.label == pageLabel, ); final currentIndex = index == -1 ? 0 : index; final navigationBar = CommonNavigationBar( @@ -88,26 +32,97 @@ class HomePage extends StatelessWidget { currentIndex: currentIndex, ); final bottomNavigationBar = - viewMode == ViewMode.mobile ? navigationBar : null; + viewMode == ViewMode.mobile ? navigationBar : null; final sideNavigationBar = - viewMode != ViewMode.mobile ? navigationBar : null; + viewMode != ViewMode.mobile ? navigationBar : null; return CommonScaffold( key: globalState.homeScaffoldKey, title: Intl.message( - currentLabel, + pageLabel.name, ), sideNavigationBar: sideNavigationBar, body: child!, bottomNavigationBar: bottomNavigationBar, ); }, - child: _buildPageView(), + child: _HomePageView(), ), ); } } -class CommonNavigationBar extends StatelessWidget { +class _HomePageView extends ConsumerStatefulWidget { + const _HomePageView(); + + @override + ConsumerState createState() => _HomePageViewState(); +} + +class _HomePageViewState extends ConsumerState<_HomePageView> { + _updatePageController(List navigationItems) { + final pageLabel = globalState.appState.pageLabel; + final index = navigationItems.lastIndexWhere( + (element) => element.label == pageLabel, + ); + final pageIndex = index == -1 ? 0 : index; + if (globalState.pageController != null) { + Future.delayed(Duration(milliseconds: 200), () { + globalState.appController.toPage( + pageIndex, + hasAnimate: true, + ); + }); + } else { + globalState.pageController = PageController( + initialPage: pageIndex, + keepPage: true, + ); + } + } + + // _handlePageChanged(PageLabel next) { + // debouncer.call(DebounceTag.pageChange, () { + // if (_prevPageLabel == next) { + // return; + // } + // if (_prevPageLabel != null) { + // final prevTabPageKey = GlobalObjectKey(_prevPageLabel!); + // if (prevTabPageKey.currentState is PageMixin) { + // (prevTabPageKey.currentState as PageMixin).onPageHidden(); + // } + // } + // final nextTabPageKey = GlobalObjectKey(next); + // if (nextTabPageKey.currentState is PageMixin) { + // (nextTabPageKey.currentState as PageMixin).onPageShow(); + // } + // _prevPageLabel = next; + // }, duration: commonDuration); + // } + + @override + Widget build(BuildContext context) { + final navigationItems = ref.watch(currentNavigationsStateProvider).value; + _updatePageController(navigationItems); + return PageView.builder( + controller: globalState.pageController, + physics: const NeverScrollableScrollPhysics(), + itemCount: navigationItems.length, + // onPageChanged: (index) { + // _handlePageChanged(navigationItems[index].label); + // }, + itemBuilder: (_, index) { + final navigationItem = navigationItems[index]; + return KeepScope( + keep: navigationItem.keep, + key: Key(navigationItem.label.name), + child: navigationItem.fragment, + ); + }, + ); + } +} + +class CommonNavigationBar extends ConsumerWidget { final ViewMode viewMode; final List navigationItems; final int currentIndex; @@ -137,22 +152,23 @@ class CommonNavigationBar extends StatelessWidget { } @override - Widget build(BuildContext context) { + Widget build(BuildContext context, ref) { _updateSafeMessageOffset(context); if (viewMode == ViewMode.mobile) { return NavigationBar( destinations: navigationItems .map( (e) => NavigationDestination( - icon: e.icon, - label: Intl.message(e.label), - ), - ) + icon: e.icon, + label: Intl.message(e.label.name), + ), + ) .toList(), onDestinationSelected: globalState.appController.toPage, selectedIndex: currentIndex, ); } + final showLabel = ref.watch(appSettingProvider).showLabel; return Material( color: context.colorScheme.surfaceContainer, child: Column( @@ -160,43 +176,38 @@ class CommonNavigationBar extends StatelessWidget { Expanded( child: SingleChildScrollView( child: IntrinsicHeight( - child: Selector( - selector: (_, config) => config.appSetting.showLabel, - builder: (_, showLabel, __) { - return NavigationRail( - backgroundColor: context.colorScheme.surfaceContainer, - selectedIconTheme: IconThemeData( - color: context.colorScheme.onSurfaceVariant, + child: NavigationRail( + backgroundColor: context.colorScheme.surfaceContainer, + selectedIconTheme: IconThemeData( + color: context.colorScheme.onSurfaceVariant, + ), + unselectedIconTheme: IconThemeData( + color: context.colorScheme.onSurfaceVariant, + ), + selectedLabelTextStyle: + context.textTheme.labelLarge!.copyWith( + color: context.colorScheme.onSurface, + ), + unselectedLabelTextStyle: + context.textTheme.labelLarge!.copyWith( + color: context.colorScheme.onSurface, + ), + destinations: navigationItems + .map( + (e) => NavigationRailDestination( + icon: e.icon, + label: Text( + Intl.message(e.label.name), ), - unselectedIconTheme: IconThemeData( - color: context.colorScheme.onSurfaceVariant, - ), - selectedLabelTextStyle: - context.textTheme.labelLarge!.copyWith( - color: context.colorScheme.onSurface, - ), - unselectedLabelTextStyle: - context.textTheme.labelLarge!.copyWith( - color: context.colorScheme.onSurface, - ), - destinations: navigationItems - .map( - (e) => NavigationRailDestination( - icon: e.icon, - label: Text( - Intl.message(e.label), - ), - ), - ) - .toList(), - onDestinationSelected: globalState.appController.toPage, - extended: false, - selectedIndex: currentIndex, - labelType: showLabel - ? NavigationRailLabelType.all - : NavigationRailLabelType.none, - ); - }, + ), + ) + .toList(), + onDestinationSelected: globalState.appController.toPage, + extended: false, + selectedIndex: currentIndex, + labelType: showLabel + ? NavigationRailLabelType.all + : NavigationRailLabelType.none, ), ), ), @@ -206,10 +217,10 @@ class CommonNavigationBar extends StatelessWidget { ), IconButton( onPressed: () { - final config = globalState.appController.config; - final appSetting = config.appSetting; - config.appSetting = appSetting.copyWith( - showLabel: !appSetting.showLabel, + ref.read(appSettingProvider.notifier).updateState( + (state) => state.copyWith( + showLabel: !state.showLabel, + ), ); }, icon: const Icon(Icons.menu), diff --git a/lib/plugins/service.dart b/lib/plugins/service.dart index f324601..3b2f3c9 100644 --- a/lib/plugins/service.dart +++ b/lib/plugins/service.dart @@ -31,6 +31,7 @@ class Service { Future startVpn() async { final options = await clashLib?.getAndroidVpnOptions(); + // commonPrint.log("$options"); return await methodChannel.invokeMethod("startVpn", { 'data': json.encode(options), }); diff --git a/lib/providers/app.dart b/lib/providers/app.dart new file mode 100644 index 0000000..7f76fe9 --- /dev/null +++ b/lib/providers/app.dart @@ -0,0 +1,339 @@ +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'; +import 'package:flutter/material.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'generated/app.g.dart'; + + +@riverpod +class Logs extends _$Logs with AutoDisposeNotifierMixin { + @override + FixedList build() { + return globalState.appState.logs; + } + + addLog(Log value) { + state = state.copyWith()..add(value); + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + logs: value, + ); + } +} + +@riverpod +class Requests extends _$Requests with AutoDisposeNotifierMixin { + @override + FixedList build() { + return globalState.appState.requests; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + requests: value, + ); + } + + addRequest(Connection value) { + state = state.copyWith()..add(value); + } +} + +@riverpod +class Providers extends _$Providers with AutoDisposeNotifierMixin { + @override + List build() { + return globalState.appState.providers; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + providers: value, + ); + } + + setProvider(ExternalProvider? provider) { + if (provider == null) return; + final index = state.indexWhere((item) => item.name == provider.name); + if (index == -1) return; + state = List.from(state)..[index] = provider; + } +} + +@riverpod +class Packages extends _$Packages with AutoDisposeNotifierMixin { + @override + List build() { + return globalState.appState.packages; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + packages: value, + ); + } +} + +@riverpod +class AppBrightness extends _$AppBrightness with AutoDisposeNotifierMixin { + @override + Brightness? build() { + return globalState.appState.brightness; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + brightness: value, + ); + } + + setState(Brightness? value) { + state = value; + } +} + +@riverpod +class Traffics extends _$Traffics with AutoDisposeNotifierMixin { + @override + FixedList build() { + return globalState.appState.traffics; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + traffics: value, + ); + } + + addTraffic(Traffic value) { + state = state.copyWith()..add(value); + } + + clear() { + state = state.copyWith()..clear(); + } +} + +@riverpod +class TotalTraffic extends _$TotalTraffic with AutoDisposeNotifierMixin { + @override + Traffic build() { + return globalState.appState.totalTraffic; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + totalTraffic: value, + ); + } +} + +@riverpod +class LocalIp extends _$LocalIp with AutoDisposeNotifierMixin { + @override + String? build() { + return globalState.appState.localIp; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + localIp: value, + ); + } + + @override + set state(String? value) { + super.state = value; + globalState.appState = globalState.appState.copyWith( + localIp: state, + ); + } +} + +@riverpod +class RunTime extends _$RunTime with AutoDisposeNotifierMixin { + @override + int? build() { + return globalState.appState.runTime; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + runTime: value, + ); + } + + bool get isStart { + return state != null; + } +} + +@riverpod +class ViewWidth extends _$ViewWidth with AutoDisposeNotifierMixin { + @override + double build() { + return globalState.appState.viewWidth; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + viewWidth: value, + ); + } + + ViewMode get viewMode => other.getViewMode(state); + + bool get isMobileView => viewMode == ViewMode.mobile; +} + +@riverpod +class Init extends _$Init with AutoDisposeNotifierMixin { + @override + bool build() { + return globalState.appState.isInit; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + isInit: value, + ); + } +} + +@riverpod +class CurrentPageLabel extends _$CurrentPageLabel + with AutoDisposeNotifierMixin { + @override + PageLabel build() { + return globalState.appState.pageLabel; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + pageLabel: value, + ); + } +} + +@riverpod +class AppSchemes extends _$AppSchemes with AutoDisposeNotifierMixin { + @override + ColorSchemes build() { + return globalState.appState.colorSchemes; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + colorSchemes: value, + ); + } +} + +@riverpod +class SortNum extends _$SortNum with AutoDisposeNotifierMixin { + @override + int build() { + return globalState.appState.sortNum; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + sortNum: value, + ); + } + + add() => state++; +} + +@riverpod +class CheckIpNum extends _$CheckIpNum with AutoDisposeNotifierMixin { + @override + int build() { + return globalState.appState.checkIpNum; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + checkIpNum: value, + ); + } + + add() => state++; +} + +@riverpod +class Version extends _$Version with AutoDisposeNotifierMixin { + @override + int build() { + return globalState.appState.version; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + version: value, + ); + } +} + +@riverpod +class Groups extends _$Groups with AutoDisposeNotifierMixin { + @override + List build() { + return globalState.appState.groups; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + groups: value, + ); + } +} + +@riverpod +class DelayDataSource extends _$DelayDataSource with AutoDisposeNotifierMixin { + @override + DelayMap build() { + return globalState.appState.delayMap; + } + + @override + onUpdate(value) { + globalState.appState = globalState.appState.copyWith( + delayMap: value, + ); + } + + setDelay(Delay delay) { + if (state[delay.url]?[delay.name] != delay.value) { + final DelayMap newDelayMap = Map.from(state); + if (newDelayMap[delay.url] == null) { + newDelayMap[delay.url] = {}; + } + newDelayMap[delay.url]![delay.name] = delay.value; + state = newDelayMap; + } + } +} + diff --git a/lib/providers/config.dart b/lib/providers/config.dart new file mode 100644 index 0000000..df5a244 --- /dev/null +++ b/lib/providers/config.dart @@ -0,0 +1,256 @@ +import 'package:fl_clash/common/common.dart'; +import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/state.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'generated/config.g.dart'; + +@riverpod +class AppSetting extends _$AppSetting with AutoDisposeNotifierMixin { + @override + AppSettingProps build() { + return globalState.config.appSetting; + } + + @override + onUpdate(value) { + globalState.config = globalState.config.copyWith( + appSetting: value, + ); + } + + updateState(AppSettingProps Function(AppSettingProps state) builder) { + state = builder(state); + } +} + +@riverpod +class WindowSetting extends _$WindowSetting with AutoDisposeNotifierMixin { + @override + WindowProps build() { + return globalState.config.windowProps; + } + + @override + onUpdate(value) { + globalState.config = globalState.config.copyWith( + windowProps: value, + ); + } + + updateState(WindowProps Function(WindowProps state) builder) { + state = builder(state); + } +} + +@riverpod +class VpnSetting extends _$VpnSetting with AutoDisposeNotifierMixin { + @override + VpnProps build() { + return globalState.config.vpnProps; + } + + @override + onUpdate(value) { + globalState.config = globalState.config.copyWith( + vpnProps: value, + ); + } + + updateState(VpnProps Function(VpnProps state) builder) { + state = builder(state); + } +} + +@riverpod +class NetworkSetting extends _$NetworkSetting with AutoDisposeNotifierMixin { + @override + NetworkProps build() { + return globalState.config.networkProps; + } + + @override + onUpdate(value) { + globalState.config = globalState.config.copyWith( + networkProps: value, + ); + } + + updateState(NetworkProps Function(NetworkProps state) builder) { + state = builder(state); + } +} + +@riverpod +class ThemeSetting extends _$ThemeSetting with AutoDisposeNotifierMixin { + @override + ThemeProps build() { + return globalState.config.themeProps; + } + + @override + onUpdate(value) { + globalState.config = globalState.config.copyWith( + themeProps: value, + ); + } + + updateState(ThemeProps Function(ThemeProps state) builder) { + state = builder(state); + } +} + +@riverpod +class Profiles extends _$Profiles with AutoDisposeNotifierMixin { + @override + List build() { + return globalState.config.profiles; + } + + @override + onUpdate(value) { + globalState.config = globalState.config.copyWith( + profiles: value, + ); + } + + String? _getLabel(String? label, String id) { + final realLabel = label ?? id; + final hasDup = state.indexWhere( + (element) => element.label == realLabel && element.id != id) != + -1; + if (hasDup) { + return _getLabel(other.getOverwriteLabel(realLabel), id); + } else { + return label; + } + } + + setProfile(Profile profile) { + final List profilesTemp = List.from(state); + final index = + profilesTemp.indexWhere((element) => element.id == profile.id); + final updateProfile = profile.copyWith( + label: _getLabel(profile.label, profile.id), + ); + if (index == -1) { + profilesTemp.add(updateProfile); + } else { + profilesTemp[index] = updateProfile; + } + state = profilesTemp; + } + + deleteProfileById(String id) { + state = state.where((element) => element.id != id).toList(); + } +} + +@riverpod +class CurrentProfileId extends _$CurrentProfileId + with AutoDisposeNotifierMixin { + @override + String? build() { + return globalState.config.currentProfileId; + } + + @override + onUpdate(value) { + globalState.config = globalState.config.copyWith( + currentProfileId: value, + ); + } +} + +@riverpod +class AppDAVSetting extends _$AppDAVSetting with AutoDisposeNotifierMixin { + @override + DAV? build() { + return globalState.config.dav; + } + + @override + onUpdate(value) { + globalState.config = globalState.config.copyWith( + dav: value, + ); + } + + updateState(DAV? Function(DAV? state) builder) { + state = builder(state); + } +} + +@riverpod +class OverrideDns extends _$OverrideDns with AutoDisposeNotifierMixin { + @override + bool build() { + return globalState.config.overrideDns; + } + + @override + onUpdate(value) { + globalState.config = globalState.config.copyWith( + overrideDns: value, + ); + } +} + +@riverpod +class HotKeyActions extends _$HotKeyActions with AutoDisposeNotifierMixin { + @override + List build() { + return globalState.config.hotKeyActions; + } + + @override + onUpdate(value) { + globalState.config = globalState.config.copyWith( + hotKeyActions: value, + ); + } +} + +@riverpod +class ProxiesStyleSetting extends _$ProxiesStyleSetting + with AutoDisposeNotifierMixin { + @override + ProxiesStyle build() { + return globalState.config.proxiesStyle; + } + + @override + onUpdate(value) { + globalState.config = globalState.config.copyWith( + proxiesStyle: value, + ); + } + + updateState(ProxiesStyle Function(ProxiesStyle state) builder) { + state = builder(state); + } +} + +@riverpod +class PatchClashConfig extends _$PatchClashConfig + with AutoDisposeNotifierMixin { + @override + ClashConfig build() { + return globalState.config.patchClashConfig; + } + + updateState(ClashConfig? Function(ClashConfig state) builder) { + final newState = builder(state); + if (newState == null) { + return; + } + state = newState; + } + + @override + onUpdate(value) { + globalState.config = globalState.config.copyWith( + patchClashConfig: value, + ); + } +} diff --git a/lib/providers/generated/app.g.dart b/lib/providers/generated/app.g.dart new file mode 100644 index 0000000..75d4dc2 --- /dev/null +++ b/lib/providers/generated/app.g.dart @@ -0,0 +1,277 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../app.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$logsHash() => r'56fb8aa9d62a97b026b749d204576a7384084737'; + +/// See also [Logs]. +@ProviderFor(Logs) +final logsProvider = AutoDisposeNotifierProvider>.internal( + Logs.new, + name: r'logsProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$logsHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$Logs = AutoDisposeNotifier>; +String _$requestsHash() => r'51c9dbba18649206b22dd0ba86c58ab986fc0939'; + +/// See also [Requests]. +@ProviderFor(Requests) +final requestsProvider = + AutoDisposeNotifierProvider>.internal( + Requests.new, + name: r'requestsProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$requestsHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$Requests = AutoDisposeNotifier>; +String _$providersHash() => r'69e480ef409837596937d233e45b9995a83b3949'; + +/// See also [Providers]. +@ProviderFor(Providers) +final providersProvider = + AutoDisposeNotifierProvider>.internal( + Providers.new, + name: r'providersProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$providersHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$Providers = AutoDisposeNotifier>; +String _$packagesHash() => r'84bff9f5271622ed4199ecafacda8e74fa444fe2'; + +/// See also [Packages]. +@ProviderFor(Packages) +final packagesProvider = + AutoDisposeNotifierProvider>.internal( + Packages.new, + name: r'packagesProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$packagesHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$Packages = AutoDisposeNotifier>; +String _$appBrightnessHash() => r'bc893bacdc2645c985037d3754bad4e651587771'; + +/// See also [AppBrightness]. +@ProviderFor(AppBrightness) +final appBrightnessProvider = + AutoDisposeNotifierProvider.internal( + AppBrightness.new, + name: r'appBrightnessProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$appBrightnessHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$AppBrightness = AutoDisposeNotifier; +String _$trafficsHash() => r'c3f33e9be5ae399562a380156280406fdeeb72aa'; + +/// See also [Traffics]. +@ProviderFor(Traffics) +final trafficsProvider = + AutoDisposeNotifierProvider>.internal( + Traffics.new, + name: r'trafficsProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$trafficsHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$Traffics = AutoDisposeNotifier>; +String _$totalTrafficHash() => r'cc993ec58fa4c8ee0dbbf2e8a146f7039e818d7e'; + +/// See also [TotalTraffic]. +@ProviderFor(TotalTraffic) +final totalTrafficProvider = + AutoDisposeNotifierProvider.internal( + TotalTraffic.new, + name: r'totalTrafficProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$totalTrafficHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$TotalTraffic = AutoDisposeNotifier; +String _$localIpHash() => r'2dd4afdb29db4791ebd80d976f9ea31c62959199'; + +/// See also [LocalIp]. +@ProviderFor(LocalIp) +final localIpProvider = AutoDisposeNotifierProvider.internal( + LocalIp.new, + name: r'localIpProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$localIpHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$LocalIp = AutoDisposeNotifier; +String _$runTimeHash() => r'9aab44f2234590a70cbf0ff7394e496c2c97c00e'; + +/// See also [RunTime]. +@ProviderFor(RunTime) +final runTimeProvider = AutoDisposeNotifierProvider.internal( + RunTime.new, + name: r'runTimeProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$runTimeHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$RunTime = AutoDisposeNotifier; +String _$viewWidthHash() => r'2d492c97b26c9634ee945a8d7da1563d98b830bd'; + +/// See also [ViewWidth]. +@ProviderFor(ViewWidth) +final viewWidthProvider = + AutoDisposeNotifierProvider.internal( + ViewWidth.new, + name: r'viewWidthProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$viewWidthHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$ViewWidth = AutoDisposeNotifier; +String _$initHash() => r'7d3f11c8aff7a1924c5ec8886b2cd2cbdda57c3f'; + +/// See also [Init]. +@ProviderFor(Init) +final initProvider = AutoDisposeNotifierProvider.internal( + Init.new, + name: r'initProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$initHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$Init = AutoDisposeNotifier; +String _$currentPageLabelHash() => r'a4ed13348bcd406ec3be52138cf1083106d31215'; + +/// See also [CurrentPageLabel]. +@ProviderFor(CurrentPageLabel) +final currentPageLabelProvider = + AutoDisposeNotifierProvider.internal( + CurrentPageLabel.new, + name: r'currentPageLabelProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$currentPageLabelHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$CurrentPageLabel = AutoDisposeNotifier; +String _$appSchemesHash() => r'748f48f23539a879a92f318a21e1266b1df56aae'; + +/// See also [AppSchemes]. +@ProviderFor(AppSchemes) +final appSchemesProvider = + AutoDisposeNotifierProvider.internal( + AppSchemes.new, + name: r'appSchemesProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$appSchemesHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$AppSchemes = AutoDisposeNotifier; +String _$sortNumHash() => r'0f85ebbc77124020eaccf988c6ac9d86a7f34d7e'; + +/// See also [SortNum]. +@ProviderFor(SortNum) +final sortNumProvider = AutoDisposeNotifierProvider.internal( + SortNum.new, + name: r'sortNumProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$sortNumHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$SortNum = AutoDisposeNotifier; +String _$checkIpNumHash() => r'794de8e31e98ee4fde10509dc8f433699bff18b4'; + +/// See also [CheckIpNum]. +@ProviderFor(CheckIpNum) +final checkIpNumProvider = + AutoDisposeNotifierProvider.internal( + CheckIpNum.new, + name: r'checkIpNumProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$checkIpNumHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$CheckIpNum = AutoDisposeNotifier; +String _$versionHash() => r'8c0ee019d20df3f112c38ae4dc4abd61148d3809'; + +/// See also [Version]. +@ProviderFor(Version) +final versionProvider = AutoDisposeNotifierProvider.internal( + Version.new, + name: r'versionProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$versionHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$Version = AutoDisposeNotifier; +String _$groupsHash() => r'fbff504e0bcdb5a2770a902f2867aabd921fbadc'; + +/// See also [Groups]. +@ProviderFor(Groups) +final groupsProvider = + AutoDisposeNotifierProvider>.internal( + Groups.new, + name: r'groupsProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$groupsHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$Groups = AutoDisposeNotifier>; +String _$delayDataSourceHash() => r'9731553fb48dd89840767bf5508547d90562eb55'; + +/// See also [DelayDataSource]. +@ProviderFor(DelayDataSource) +final delayDataSourceProvider = + AutoDisposeNotifierProvider.internal( + DelayDataSource.new, + name: r'delayDataSourceProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$delayDataSourceHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$DelayDataSource = AutoDisposeNotifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/providers/generated/config.g.dart b/lib/providers/generated/config.g.dart new file mode 100644 index 0000000..d2cb84f --- /dev/null +++ b/lib/providers/generated/config.g.dart @@ -0,0 +1,198 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../config.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$appSettingHash() => r'99236f2cd5498f9af70b43e41faeb361d344f866'; + +/// See also [AppSetting]. +@ProviderFor(AppSetting) +final appSettingProvider = + AutoDisposeNotifierProvider.internal( + AppSetting.new, + name: r'appSettingProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$appSettingHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$AppSetting = AutoDisposeNotifier; +String _$windowSettingHash() => r'3dbbf3e169023b49e79b2fb983002687ce077e23'; + +/// See also [WindowSetting]. +@ProviderFor(WindowSetting) +final windowSettingProvider = + AutoDisposeNotifierProvider.internal( + WindowSetting.new, + name: r'windowSettingProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$windowSettingHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$WindowSetting = AutoDisposeNotifier; +String _$vpnSettingHash() => r'e660cc71ed6677f136eb98885680aae66be74881'; + +/// See also [VpnSetting]. +@ProviderFor(VpnSetting) +final vpnSettingProvider = + AutoDisposeNotifierProvider.internal( + VpnSetting.new, + name: r'vpnSettingProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$vpnSettingHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$VpnSetting = AutoDisposeNotifier; +String _$networkSettingHash() => r'689ce908662dfe64660557153a4244ae1fdf696e'; + +/// See also [NetworkSetting]. +@ProviderFor(NetworkSetting) +final networkSettingProvider = + AutoDisposeNotifierProvider.internal( + NetworkSetting.new, + name: r'networkSettingProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$networkSettingHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$NetworkSetting = AutoDisposeNotifier; +String _$themeSettingHash() => r'ae5eeaad9729627eaa1b3ccf0266c13bf2ce68d4'; + +/// See also [ThemeSetting]. +@ProviderFor(ThemeSetting) +final themeSettingProvider = + AutoDisposeNotifierProvider.internal( + ThemeSetting.new, + name: r'themeSettingProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$themeSettingHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$ThemeSetting = AutoDisposeNotifier; +String _$profilesHash() => r'c2bc502d31321274a44901b675fbbab60b4519c3'; + +/// See also [Profiles]. +@ProviderFor(Profiles) +final profilesProvider = + AutoDisposeNotifierProvider>.internal( + Profiles.new, + name: r'profilesProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$profilesHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$Profiles = AutoDisposeNotifier>; +String _$currentProfileIdHash() => r'0c3e324e751aac1164da479e1796e826615bdcbe'; + +/// See also [CurrentProfileId]. +@ProviderFor(CurrentProfileId) +final currentProfileIdProvider = + AutoDisposeNotifierProvider.internal( + CurrentProfileId.new, + name: r'currentProfileIdProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$currentProfileIdHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$CurrentProfileId = AutoDisposeNotifier; +String _$appDAVSettingHash() => r'20439d1f8cc0843a092766dc1cad68e8e8273dbb'; + +/// See also [AppDAVSetting]. +@ProviderFor(AppDAVSetting) +final appDAVSettingProvider = + AutoDisposeNotifierProvider.internal( + AppDAVSetting.new, + name: r'appDAVSettingProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$appDAVSettingHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$AppDAVSetting = AutoDisposeNotifier; +String _$overrideDnsHash() => r'1fc914de471319bf1e003edf9627b8c646b641bf'; + +/// See also [OverrideDns]. +@ProviderFor(OverrideDns) +final overrideDnsProvider = + AutoDisposeNotifierProvider.internal( + OverrideDns.new, + name: r'overrideDnsProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$overrideDnsHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$OverrideDns = AutoDisposeNotifier; +String _$hotKeyActionsHash() => r'1d308d61b74accebbb11b1771a55975760503691'; + +/// See also [HotKeyActions]. +@ProviderFor(HotKeyActions) +final hotKeyActionsProvider = + AutoDisposeNotifierProvider>.internal( + HotKeyActions.new, + name: r'hotKeyActionsProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$hotKeyActionsHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$HotKeyActions = AutoDisposeNotifier>; +String _$proxiesStyleSettingHash() => + r'162e7320dff8063e7a2deca5071ef5024f4d3d04'; + +/// See also [ProxiesStyleSetting]. +@ProviderFor(ProxiesStyleSetting) +final proxiesStyleSettingProvider = + AutoDisposeNotifierProvider.internal( + ProxiesStyleSetting.new, + name: r'proxiesStyleSettingProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$proxiesStyleSettingHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$ProxiesStyleSetting = AutoDisposeNotifier; +String _$patchClashConfigHash() => r'52906195d85525d6688aec231da8b38c24364494'; + +/// See also [PatchClashConfig]. +@ProviderFor(PatchClashConfig) +final patchClashConfigProvider = + AutoDisposeNotifierProvider.internal( + PatchClashConfig.new, + name: r'patchClashConfigProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$patchClashConfigHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$PatchClashConfig = AutoDisposeNotifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/providers/generated/state.g.dart b/lib/providers/generated/state.g.dart new file mode 100644 index 0000000..3d2db5f --- /dev/null +++ b/lib/providers/generated/state.g.dart @@ -0,0 +1,1633 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../state.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$currentGroupsStateHash() => + r'6222c006e1970e7435268d32903b9019cf1a4351'; + +/// See also [currentGroupsState]. +@ProviderFor(currentGroupsState) +final currentGroupsStateProvider = AutoDisposeProvider.internal( + currentGroupsState, + name: r'currentGroupsStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$currentGroupsStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef CurrentGroupsStateRef = AutoDisposeProviderRef; +String _$navigationsStateHash() => r'3c57f9161625f0376679cfe8b1cce0beadd709a7'; + +/// See also [navigationsState]. +@ProviderFor(navigationsState) +final navigationsStateProvider = + AutoDisposeProvider.internal( + navigationsState, + name: r'navigationsStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$navigationsStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef NavigationsStateRef = AutoDisposeProviderRef; +String _$currentNavigationsStateHash() => + r'0eecc0ffef6e000ae45e069d1ad79f4da4a8f082'; + +/// See also [currentNavigationsState]. +@ProviderFor(currentNavigationsState) +final currentNavigationsStateProvider = + AutoDisposeProvider.internal( + currentNavigationsState, + name: r'currentNavigationsStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$currentNavigationsStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef CurrentNavigationsStateRef + = AutoDisposeProviderRef; +String _$coreStateHash() => r'33f01ee9173525862c89522bf73b3174beb63daa'; + +/// See also [coreState]. +@ProviderFor(coreState) +final coreStateProvider = AutoDisposeProvider.internal( + coreState, + name: r'coreStateProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$coreStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef CoreStateRef = AutoDisposeProviderRef; +String _$clashConfigStateHash() => r'0708f81450e740a471c65d1dd5db0ed0dc702b3c'; + +/// See also [clashConfigState]. +@ProviderFor(clashConfigState) +final clashConfigStateProvider = AutoDisposeProvider.internal( + clashConfigState, + name: r'clashConfigStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$clashConfigStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef ClashConfigStateRef = AutoDisposeProviderRef; +String _$proxyStateHash() => r'418464d2ab29bb701ff001ca80396526fd2c8d3a'; + +/// See also [proxyState]. +@ProviderFor(proxyState) +final proxyStateProvider = AutoDisposeProvider.internal( + proxyState, + name: r'proxyStateProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$proxyStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef ProxyStateRef = AutoDisposeProviderRef; +String _$trayStateHash() => r'06ff742a92893667a30bc6a25d13594d83dd74fc'; + +/// See also [trayState]. +@ProviderFor(trayState) +final trayStateProvider = AutoDisposeProvider.internal( + trayState, + name: r'trayStateProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$trayStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef TrayStateRef = AutoDisposeProviderRef; +String _$vpnStateHash() => r'128ddad03ce045ad1f8204e47aec3cb6cfa29f6e'; + +/// See also [vpnState]. +@ProviderFor(vpnState) +final vpnStateProvider = AutoDisposeProvider.internal( + vpnState, + name: r'vpnStateProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$vpnStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef VpnStateRef = AutoDisposeProviderRef; +String _$homeStateHash() => r'4c8a996c43a705f6d089a727563c20ff87e13a97'; + +/// See also [homeState]. +@ProviderFor(homeState) +final homeStateProvider = AutoDisposeProvider.internal( + homeState, + name: r'homeStateProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$homeStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef HomeStateRef = AutoDisposeProviderRef; +String _$dashboardStateHash() => r'4434206df2753d7df9eb5223c07ddead4ed170fa'; + +/// See also [dashboardState]. +@ProviderFor(dashboardState) +final dashboardStateProvider = AutoDisposeProvider.internal( + dashboardState, + name: r'dashboardStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$dashboardStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef DashboardStateRef = AutoDisposeProviderRef; +String _$proxiesActionsStateHash() => + r'84f8a94706233ff5d4b8a456291a4e66c1381c62'; + +/// See also [proxiesActionsState]. +@ProviderFor(proxiesActionsState) +final proxiesActionsStateProvider = + AutoDisposeProvider.internal( + proxiesActionsState, + name: r'proxiesActionsStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$proxiesActionsStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef ProxiesActionsStateRef = AutoDisposeProviderRef; +String _$startButtonSelectorStateHash() => + r'537aff93c98b0a689cf8cabd080c610c9c58e611'; + +/// See also [startButtonSelectorState]. +@ProviderFor(startButtonSelectorState) +final startButtonSelectorStateProvider = + AutoDisposeProvider.internal( + startButtonSelectorState, + name: r'startButtonSelectorStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$startButtonSelectorStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef StartButtonSelectorStateRef + = AutoDisposeProviderRef; +String _$profilesSelectorStateHash() => + r'9fa4447dace0322e888efb38cbee1dabd33e0e71'; + +/// See also [profilesSelectorState]. +@ProviderFor(profilesSelectorState) +final profilesSelectorStateProvider = + AutoDisposeProvider.internal( + profilesSelectorState, + name: r'profilesSelectorStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$profilesSelectorStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef ProfilesSelectorStateRef + = AutoDisposeProviderRef; +String _$proxiesListSelectorStateHash() => + r'0e63ea2fb141e086156a2ed8452584e2375c5aa5'; + +/// See also [proxiesListSelectorState]. +@ProviderFor(proxiesListSelectorState) +final proxiesListSelectorStateProvider = + AutoDisposeProvider.internal( + proxiesListSelectorState, + name: r'proxiesListSelectorStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$proxiesListSelectorStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef ProxiesListSelectorStateRef + = AutoDisposeProviderRef; +String _$proxiesSelectorStateHash() => + r'4b96e83c09efd17de6caede484e71c904273c9f8'; + +/// See also [proxiesSelectorState]. +@ProviderFor(proxiesSelectorState) +final proxiesSelectorStateProvider = + AutoDisposeProvider.internal( + proxiesSelectorState, + name: r'proxiesSelectorStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$proxiesSelectorStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef ProxiesSelectorStateRef = AutoDisposeProviderRef; +String _$groupNamesStateHash() => r'd4ba8f2fd72a0db7186ab5d96aa1548bd5a7cdcb'; + +/// See also [groupNamesState]. +@ProviderFor(groupNamesState) +final groupNamesStateProvider = AutoDisposeProvider.internal( + groupNamesState, + name: r'groupNamesStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$groupNamesStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef GroupNamesStateRef = AutoDisposeProviderRef; +String _$proxyGroupSelectorStateHash() => + r'b76f5ad536469e11a4ffa6a262dd4df61d280823'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +/// See also [proxyGroupSelectorState]. +@ProviderFor(proxyGroupSelectorState) +const proxyGroupSelectorStateProvider = ProxyGroupSelectorStateFamily(); + +/// See also [proxyGroupSelectorState]. +class ProxyGroupSelectorStateFamily extends Family { + /// See also [proxyGroupSelectorState]. + const ProxyGroupSelectorStateFamily(); + + /// See also [proxyGroupSelectorState]. + ProxyGroupSelectorStateProvider call( + String groupName, + ) { + return ProxyGroupSelectorStateProvider( + groupName, + ); + } + + @override + ProxyGroupSelectorStateProvider getProviderOverride( + covariant ProxyGroupSelectorStateProvider provider, + ) { + return call( + provider.groupName, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'proxyGroupSelectorStateProvider'; +} + +/// See also [proxyGroupSelectorState]. +class ProxyGroupSelectorStateProvider + extends AutoDisposeProvider { + /// See also [proxyGroupSelectorState]. + ProxyGroupSelectorStateProvider( + String groupName, + ) : this._internal( + (ref) => proxyGroupSelectorState( + ref as ProxyGroupSelectorStateRef, + groupName, + ), + from: proxyGroupSelectorStateProvider, + name: r'proxyGroupSelectorStateProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$proxyGroupSelectorStateHash, + dependencies: ProxyGroupSelectorStateFamily._dependencies, + allTransitiveDependencies: + ProxyGroupSelectorStateFamily._allTransitiveDependencies, + groupName: groupName, + ); + + ProxyGroupSelectorStateProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.groupName, + }) : super.internal(); + + final String groupName; + + @override + Override overrideWith( + ProxyGroupSelectorState Function(ProxyGroupSelectorStateRef provider) + create, + ) { + return ProviderOverride( + origin: this, + override: ProxyGroupSelectorStateProvider._internal( + (ref) => create(ref as ProxyGroupSelectorStateRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + groupName: groupName, + ), + ); + } + + @override + AutoDisposeProviderElement createElement() { + return _ProxyGroupSelectorStateProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is ProxyGroupSelectorStateProvider && + other.groupName == groupName; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, groupName.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin ProxyGroupSelectorStateRef + on AutoDisposeProviderRef { + /// The parameter `groupName` of this provider. + String get groupName; +} + +class _ProxyGroupSelectorStateProviderElement + extends AutoDisposeProviderElement + with ProxyGroupSelectorStateRef { + _ProxyGroupSelectorStateProviderElement(super.provider); + + @override + String get groupName => (origin as ProxyGroupSelectorStateProvider).groupName; +} + +String _$packageListSelectorStateHash() => + r'26ad58fec2cb0136ece373c7f3ec89b5aafd9324'; + +/// See also [packageListSelectorState]. +@ProviderFor(packageListSelectorState) +final packageListSelectorStateProvider = + AutoDisposeProvider.internal( + packageListSelectorState, + name: r'packageListSelectorStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$packageListSelectorStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef PackageListSelectorStateRef + = AutoDisposeProviderRef; +String _$moreToolsSelectorStateHash() => + r'82837b45198a75af9a9ce49b9c3ef97c6f8e9f87'; + +/// See also [moreToolsSelectorState]. +@ProviderFor(moreToolsSelectorState) +final moreToolsSelectorStateProvider = + AutoDisposeProvider.internal( + moreToolsSelectorState, + name: r'moreToolsSelectorStateProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$moreToolsSelectorStateHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef MoreToolsSelectorStateRef + = AutoDisposeProviderRef; +String _$isCurrentPageHash() => r'562702367f009c7b324395ab0a2ad3464784be8c'; + +/// See also [isCurrentPage]. +@ProviderFor(isCurrentPage) +const isCurrentPageProvider = IsCurrentPageFamily(); + +/// See also [isCurrentPage]. +class IsCurrentPageFamily extends Family { + /// See also [isCurrentPage]. + const IsCurrentPageFamily(); + + /// See also [isCurrentPage]. + IsCurrentPageProvider call( + PageLabel pageLabel, { + bool Function(PageLabel, ViewMode)? handler, + }) { + return IsCurrentPageProvider( + pageLabel, + handler: handler, + ); + } + + @override + IsCurrentPageProvider getProviderOverride( + covariant IsCurrentPageProvider provider, + ) { + return call( + provider.pageLabel, + handler: provider.handler, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'isCurrentPageProvider'; +} + +/// See also [isCurrentPage]. +class IsCurrentPageProvider extends AutoDisposeProvider { + /// See also [isCurrentPage]. + IsCurrentPageProvider( + PageLabel pageLabel, { + bool Function(PageLabel, ViewMode)? handler, + }) : this._internal( + (ref) => isCurrentPage( + ref as IsCurrentPageRef, + pageLabel, + handler: handler, + ), + from: isCurrentPageProvider, + name: r'isCurrentPageProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$isCurrentPageHash, + dependencies: IsCurrentPageFamily._dependencies, + allTransitiveDependencies: + IsCurrentPageFamily._allTransitiveDependencies, + pageLabel: pageLabel, + handler: handler, + ); + + IsCurrentPageProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.pageLabel, + required this.handler, + }) : super.internal(); + + final PageLabel pageLabel; + final bool Function(PageLabel, ViewMode)? handler; + + @override + Override overrideWith( + bool Function(IsCurrentPageRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: IsCurrentPageProvider._internal( + (ref) => create(ref as IsCurrentPageRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + pageLabel: pageLabel, + handler: handler, + ), + ); + } + + @override + AutoDisposeProviderElement createElement() { + return _IsCurrentPageProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is IsCurrentPageProvider && + other.pageLabel == pageLabel && + other.handler == handler; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, pageLabel.hashCode); + hash = _SystemHash.combine(hash, handler.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin IsCurrentPageRef on AutoDisposeProviderRef { + /// The parameter `pageLabel` of this provider. + PageLabel get pageLabel; + + /// The parameter `handler` of this provider. + bool Function(PageLabel, ViewMode)? get handler; +} + +class _IsCurrentPageProviderElement extends AutoDisposeProviderElement + with IsCurrentPageRef { + _IsCurrentPageProviderElement(super.provider); + + @override + PageLabel get pageLabel => (origin as IsCurrentPageProvider).pageLabel; + @override + bool Function(PageLabel, ViewMode)? get handler => + (origin as IsCurrentPageProvider).handler; +} + +String _$getRealTestUrlHash() => r'5c6513cabb53e5e6689cba5919f49aeaeff90247'; + +/// See also [getRealTestUrl]. +@ProviderFor(getRealTestUrl) +const getRealTestUrlProvider = GetRealTestUrlFamily(); + +/// See also [getRealTestUrl]. +class GetRealTestUrlFamily extends Family { + /// See also [getRealTestUrl]. + const GetRealTestUrlFamily(); + + /// See also [getRealTestUrl]. + GetRealTestUrlProvider call([ + String? testUrl, + ]) { + return GetRealTestUrlProvider( + testUrl, + ); + } + + @override + GetRealTestUrlProvider getProviderOverride( + covariant GetRealTestUrlProvider provider, + ) { + return call( + provider.testUrl, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'getRealTestUrlProvider'; +} + +/// See also [getRealTestUrl]. +class GetRealTestUrlProvider extends AutoDisposeProvider { + /// See also [getRealTestUrl]. + GetRealTestUrlProvider([ + String? testUrl, + ]) : this._internal( + (ref) => getRealTestUrl( + ref as GetRealTestUrlRef, + testUrl, + ), + from: getRealTestUrlProvider, + name: r'getRealTestUrlProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$getRealTestUrlHash, + dependencies: GetRealTestUrlFamily._dependencies, + allTransitiveDependencies: + GetRealTestUrlFamily._allTransitiveDependencies, + testUrl: testUrl, + ); + + GetRealTestUrlProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.testUrl, + }) : super.internal(); + + final String? testUrl; + + @override + Override overrideWith( + String Function(GetRealTestUrlRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: GetRealTestUrlProvider._internal( + (ref) => create(ref as GetRealTestUrlRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + testUrl: testUrl, + ), + ); + } + + @override + AutoDisposeProviderElement createElement() { + return _GetRealTestUrlProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is GetRealTestUrlProvider && other.testUrl == testUrl; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, testUrl.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin GetRealTestUrlRef on AutoDisposeProviderRef { + /// The parameter `testUrl` of this provider. + String? get testUrl; +} + +class _GetRealTestUrlProviderElement extends AutoDisposeProviderElement + with GetRealTestUrlRef { + _GetRealTestUrlProviderElement(super.provider); + + @override + String? get testUrl => (origin as GetRealTestUrlProvider).testUrl; +} + +String _$getDelayHash() => r'dbc584d16f24abbc548d4c560ef50d172db23818'; + +/// See also [getDelay]. +@ProviderFor(getDelay) +const getDelayProvider = GetDelayFamily(); + +/// See also [getDelay]. +class GetDelayFamily extends Family { + /// See also [getDelay]. + const GetDelayFamily(); + + /// See also [getDelay]. + GetDelayProvider call({ + required String proxyName, + String? testUrl, + }) { + return GetDelayProvider( + proxyName: proxyName, + testUrl: testUrl, + ); + } + + @override + GetDelayProvider getProviderOverride( + covariant GetDelayProvider provider, + ) { + return call( + proxyName: provider.proxyName, + testUrl: provider.testUrl, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'getDelayProvider'; +} + +/// See also [getDelay]. +class GetDelayProvider extends AutoDisposeProvider { + /// See also [getDelay]. + GetDelayProvider({ + required String proxyName, + String? testUrl, + }) : this._internal( + (ref) => getDelay( + ref as GetDelayRef, + proxyName: proxyName, + testUrl: testUrl, + ), + from: getDelayProvider, + name: r'getDelayProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$getDelayHash, + dependencies: GetDelayFamily._dependencies, + allTransitiveDependencies: GetDelayFamily._allTransitiveDependencies, + proxyName: proxyName, + testUrl: testUrl, + ); + + GetDelayProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.proxyName, + required this.testUrl, + }) : super.internal(); + + final String proxyName; + final String? testUrl; + + @override + Override overrideWith( + int? Function(GetDelayRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: GetDelayProvider._internal( + (ref) => create(ref as GetDelayRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + proxyName: proxyName, + testUrl: testUrl, + ), + ); + } + + @override + AutoDisposeProviderElement createElement() { + return _GetDelayProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is GetDelayProvider && + other.proxyName == proxyName && + other.testUrl == testUrl; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, proxyName.hashCode); + hash = _SystemHash.combine(hash, testUrl.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin GetDelayRef on AutoDisposeProviderRef { + /// The parameter `proxyName` of this provider. + String get proxyName; + + /// The parameter `testUrl` of this provider. + String? get testUrl; +} + +class _GetDelayProviderElement extends AutoDisposeProviderElement + with GetDelayRef { + _GetDelayProviderElement(super.provider); + + @override + String get proxyName => (origin as GetDelayProvider).proxyName; + @override + String? get testUrl => (origin as GetDelayProvider).testUrl; +} + +String _$selectedMapHash() => r'0d7a3610d9005e74e1a88595d7e22897dc8240a5'; + +/// See also [selectedMap]. +@ProviderFor(selectedMap) +final selectedMapProvider = AutoDisposeProvider.internal( + selectedMap, + name: r'selectedMapProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$selectedMapHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef SelectedMapRef = AutoDisposeProviderRef; +String _$unfoldSetHash() => r'59a5b417611533069462ddf31eca080ab2f74ac9'; + +/// See also [unfoldSet]. +@ProviderFor(unfoldSet) +final unfoldSetProvider = AutoDisposeProvider>.internal( + unfoldSet, + name: r'unfoldSetProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$unfoldSetHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef UnfoldSetRef = AutoDisposeProviderRef>; +String _$getHotKeyActionHash() => r'4dc74ea7ffb25624ce70c7c8214806f3ef022223'; + +/// See also [getHotKeyAction]. +@ProviderFor(getHotKeyAction) +const getHotKeyActionProvider = GetHotKeyActionFamily(); + +/// See also [getHotKeyAction]. +class GetHotKeyActionFamily extends Family { + /// See also [getHotKeyAction]. + const GetHotKeyActionFamily(); + + /// See also [getHotKeyAction]. + GetHotKeyActionProvider call( + HotAction hotAction, + ) { + return GetHotKeyActionProvider( + hotAction, + ); + } + + @override + GetHotKeyActionProvider getProviderOverride( + covariant GetHotKeyActionProvider provider, + ) { + return call( + provider.hotAction, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'getHotKeyActionProvider'; +} + +/// See also [getHotKeyAction]. +class GetHotKeyActionProvider extends AutoDisposeProvider { + /// See also [getHotKeyAction]. + GetHotKeyActionProvider( + HotAction hotAction, + ) : this._internal( + (ref) => getHotKeyAction( + ref as GetHotKeyActionRef, + hotAction, + ), + from: getHotKeyActionProvider, + name: r'getHotKeyActionProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$getHotKeyActionHash, + dependencies: GetHotKeyActionFamily._dependencies, + allTransitiveDependencies: + GetHotKeyActionFamily._allTransitiveDependencies, + hotAction: hotAction, + ); + + GetHotKeyActionProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.hotAction, + }) : super.internal(); + + final HotAction hotAction; + + @override + Override overrideWith( + HotKeyAction Function(GetHotKeyActionRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: GetHotKeyActionProvider._internal( + (ref) => create(ref as GetHotKeyActionRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + hotAction: hotAction, + ), + ); + } + + @override + AutoDisposeProviderElement createElement() { + return _GetHotKeyActionProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is GetHotKeyActionProvider && other.hotAction == hotAction; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, hotAction.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin GetHotKeyActionRef on AutoDisposeProviderRef { + /// The parameter `hotAction` of this provider. + HotAction get hotAction; +} + +class _GetHotKeyActionProviderElement + extends AutoDisposeProviderElement with GetHotKeyActionRef { + _GetHotKeyActionProviderElement(super.provider); + + @override + HotAction get hotAction => (origin as GetHotKeyActionProvider).hotAction; +} + +String _$currentProfileHash() => r'55f3cb9570a0aa6b9e0b83a36693b69d52e753ab'; + +/// See also [currentProfile]. +@ProviderFor(currentProfile) +final currentProfileProvider = AutoDisposeProvider.internal( + currentProfile, + name: r'currentProfileProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$currentProfileHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef CurrentProfileRef = AutoDisposeProviderRef; +String _$getProxiesColumnsHash() => r'895705381fe361fa40f16da2f9cb26e8da3293e8'; + +/// See also [getProxiesColumns]. +@ProviderFor(getProxiesColumns) +final getProxiesColumnsProvider = AutoDisposeProvider.internal( + getProxiesColumns, + name: r'getProxiesColumnsProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$getProxiesColumnsHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef GetProxiesColumnsRef = AutoDisposeProviderRef; +String _$getRealProxyNameHash() => r'47be6d115aa170f9bff610ec2cf7669e168bf472'; + +/// See also [getRealProxyName]. +@ProviderFor(getRealProxyName) +const getRealProxyNameProvider = GetRealProxyNameFamily(); + +/// See also [getRealProxyName]. +class GetRealProxyNameFamily extends Family { + /// See also [getRealProxyName]. + const GetRealProxyNameFamily(); + + /// See also [getRealProxyName]. + GetRealProxyNameProvider call( + String proxyName, + ) { + return GetRealProxyNameProvider( + proxyName, + ); + } + + @override + GetRealProxyNameProvider getProviderOverride( + covariant GetRealProxyNameProvider provider, + ) { + return call( + provider.proxyName, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'getRealProxyNameProvider'; +} + +/// See also [getRealProxyName]. +class GetRealProxyNameProvider extends AutoDisposeProvider { + /// See also [getRealProxyName]. + GetRealProxyNameProvider( + String proxyName, + ) : this._internal( + (ref) => getRealProxyName( + ref as GetRealProxyNameRef, + proxyName, + ), + from: getRealProxyNameProvider, + name: r'getRealProxyNameProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$getRealProxyNameHash, + dependencies: GetRealProxyNameFamily._dependencies, + allTransitiveDependencies: + GetRealProxyNameFamily._allTransitiveDependencies, + proxyName: proxyName, + ); + + GetRealProxyNameProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.proxyName, + }) : super.internal(); + + final String proxyName; + + @override + Override overrideWith( + String Function(GetRealProxyNameRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: GetRealProxyNameProvider._internal( + (ref) => create(ref as GetRealProxyNameRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + proxyName: proxyName, + ), + ); + } + + @override + AutoDisposeProviderElement createElement() { + return _GetRealProxyNameProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is GetRealProxyNameProvider && other.proxyName == proxyName; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, proxyName.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin GetRealProxyNameRef on AutoDisposeProviderRef { + /// The parameter `proxyName` of this provider. + String get proxyName; +} + +class _GetRealProxyNameProviderElement + extends AutoDisposeProviderElement with GetRealProxyNameRef { + _GetRealProxyNameProviderElement(super.provider); + + @override + String get proxyName => (origin as GetRealProxyNameProvider).proxyName; +} + +String _$getProxyNameHash() => r'204a477ea18c8e1eeef55b3efd3d47e45b0d2350'; + +/// See also [getProxyName]. +@ProviderFor(getProxyName) +const getProxyNameProvider = GetProxyNameFamily(); + +/// See also [getProxyName]. +class GetProxyNameFamily extends Family { + /// See also [getProxyName]. + const GetProxyNameFamily(); + + /// See also [getProxyName]. + GetProxyNameProvider call( + String groupName, + ) { + return GetProxyNameProvider( + groupName, + ); + } + + @override + GetProxyNameProvider getProviderOverride( + covariant GetProxyNameProvider provider, + ) { + return call( + provider.groupName, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'getProxyNameProvider'; +} + +/// See also [getProxyName]. +class GetProxyNameProvider extends AutoDisposeProvider { + /// See also [getProxyName]. + GetProxyNameProvider( + String groupName, + ) : this._internal( + (ref) => getProxyName( + ref as GetProxyNameRef, + groupName, + ), + from: getProxyNameProvider, + name: r'getProxyNameProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$getProxyNameHash, + dependencies: GetProxyNameFamily._dependencies, + allTransitiveDependencies: + GetProxyNameFamily._allTransitiveDependencies, + groupName: groupName, + ); + + GetProxyNameProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.groupName, + }) : super.internal(); + + final String groupName; + + @override + Override overrideWith( + String? Function(GetProxyNameRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: GetProxyNameProvider._internal( + (ref) => create(ref as GetProxyNameRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + groupName: groupName, + ), + ); + } + + @override + AutoDisposeProviderElement createElement() { + return _GetProxyNameProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is GetProxyNameProvider && other.groupName == groupName; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, groupName.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin GetProxyNameRef on AutoDisposeProviderRef { + /// The parameter `groupName` of this provider. + String get groupName; +} + +class _GetProxyNameProviderElement extends AutoDisposeProviderElement + with GetProxyNameRef { + _GetProxyNameProviderElement(super.provider); + + @override + String get groupName => (origin as GetProxyNameProvider).groupName; +} + +String _$getSelectedProxyNameHash() => + r'13aeae1fede234983d262d824a85c7375f9e4e78'; + +/// See also [getSelectedProxyName]. +@ProviderFor(getSelectedProxyName) +const getSelectedProxyNameProvider = GetSelectedProxyNameFamily(); + +/// See also [getSelectedProxyName]. +class GetSelectedProxyNameFamily extends Family { + /// See also [getSelectedProxyName]. + const GetSelectedProxyNameFamily(); + + /// See also [getSelectedProxyName]. + GetSelectedProxyNameProvider call( + String groupName, + ) { + return GetSelectedProxyNameProvider( + groupName, + ); + } + + @override + GetSelectedProxyNameProvider getProviderOverride( + covariant GetSelectedProxyNameProvider provider, + ) { + return call( + provider.groupName, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'getSelectedProxyNameProvider'; +} + +/// See also [getSelectedProxyName]. +class GetSelectedProxyNameProvider extends AutoDisposeProvider { + /// See also [getSelectedProxyName]. + GetSelectedProxyNameProvider( + String groupName, + ) : this._internal( + (ref) => getSelectedProxyName( + ref as GetSelectedProxyNameRef, + groupName, + ), + from: getSelectedProxyNameProvider, + name: r'getSelectedProxyNameProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$getSelectedProxyNameHash, + dependencies: GetSelectedProxyNameFamily._dependencies, + allTransitiveDependencies: + GetSelectedProxyNameFamily._allTransitiveDependencies, + groupName: groupName, + ); + + GetSelectedProxyNameProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.groupName, + }) : super.internal(); + + final String groupName; + + @override + Override overrideWith( + String? Function(GetSelectedProxyNameRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: GetSelectedProxyNameProvider._internal( + (ref) => create(ref as GetSelectedProxyNameRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + groupName: groupName, + ), + ); + } + + @override + AutoDisposeProviderElement createElement() { + return _GetSelectedProxyNameProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is GetSelectedProxyNameProvider && + other.groupName == groupName; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, groupName.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin GetSelectedProxyNameRef on AutoDisposeProviderRef { + /// The parameter `groupName` of this provider. + String get groupName; +} + +class _GetSelectedProxyNameProviderElement + extends AutoDisposeProviderElement with GetSelectedProxyNameRef { + _GetSelectedProxyNameProviderElement(super.provider); + + @override + String get groupName => (origin as GetSelectedProxyNameProvider).groupName; +} + +String _$getProxyDescHash() => r'7c06402957387c35d9dc515ca109f8f7dbb481b0'; + +/// See also [getProxyDesc]. +@ProviderFor(getProxyDesc) +const getProxyDescProvider = GetProxyDescFamily(); + +/// See also [getProxyDesc]. +class GetProxyDescFamily extends Family { + /// See also [getProxyDesc]. + const GetProxyDescFamily(); + + /// See also [getProxyDesc]. + GetProxyDescProvider call( + Proxy proxy, + ) { + return GetProxyDescProvider( + proxy, + ); + } + + @override + GetProxyDescProvider getProviderOverride( + covariant GetProxyDescProvider provider, + ) { + return call( + provider.proxy, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'getProxyDescProvider'; +} + +/// See also [getProxyDesc]. +class GetProxyDescProvider extends AutoDisposeProvider { + /// See also [getProxyDesc]. + GetProxyDescProvider( + Proxy proxy, + ) : this._internal( + (ref) => getProxyDesc( + ref as GetProxyDescRef, + proxy, + ), + from: getProxyDescProvider, + name: r'getProxyDescProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$getProxyDescHash, + dependencies: GetProxyDescFamily._dependencies, + allTransitiveDependencies: + GetProxyDescFamily._allTransitiveDependencies, + proxy: proxy, + ); + + GetProxyDescProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.proxy, + }) : super.internal(); + + final Proxy proxy; + + @override + Override overrideWith( + String Function(GetProxyDescRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: GetProxyDescProvider._internal( + (ref) => create(ref as GetProxyDescRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + proxy: proxy, + ), + ); + } + + @override + AutoDisposeProviderElement createElement() { + return _GetProxyDescProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is GetProxyDescProvider && other.proxy == proxy; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, proxy.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin GetProxyDescRef on AutoDisposeProviderRef { + /// The parameter `proxy` of this provider. + Proxy get proxy; +} + +class _GetProxyDescProviderElement extends AutoDisposeProviderElement + with GetProxyDescRef { + _GetProxyDescProviderElement(super.provider); + + @override + Proxy get proxy => (origin as GetProxyDescProvider).proxy; +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/providers/providers.dart b/lib/providers/providers.dart new file mode 100644 index 0000000..e88ed2b --- /dev/null +++ b/lib/providers/providers.dart @@ -0,0 +1,3 @@ +export 'app.dart'; +export 'config.dart'; +export 'state.dart'; \ No newline at end of file diff --git a/lib/providers/state.dart b/lib/providers/state.dart new file mode 100644 index 0000000..6857628 --- /dev/null +++ b/lib/providers/state.dart @@ -0,0 +1,450 @@ +import 'package:fl_clash/common/common.dart'; +import 'package:fl_clash/enum/enum.dart'; +import 'package:fl_clash/models/models.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +import 'app.dart'; +import 'config.dart'; + +part 'generated/state.g.dart'; + +@riverpod +GroupsState currentGroupsState(Ref ref) { + final mode = + ref.watch(patchClashConfigProvider.select((state) => state.mode)); + final groups = ref.watch(groupsProvider); + return GroupsState( + value: switch (mode) { + Mode.direct => [], + Mode.global => groups.toList(), + Mode.rule => groups + .where((item) => item.hidden == false) + .where((element) => element.name != GroupName.GLOBAL.name) + .toList(), + }, + ); +} + +@riverpod +NavigationItemsState navigationsState(Ref ref) { + final openLogs = ref.watch(appSettingProvider).openLogs; + final hasProxies = ref.watch(currentGroupsStateProvider.select((state)=>state.value.isNotEmpty)); + return NavigationItemsState( + value: navigation.getItems( + openLogs: openLogs, + hasProxies: hasProxies, + ), + ); +} + +@riverpod +NavigationItemsState currentNavigationsState(Ref ref) { + final viewWidth = ref.watch(viewWidthProvider); + final navigationItemsState = ref.watch(navigationsStateProvider); + final navigationItemMode = switch (viewWidth <= maxMobileWidth) { + true => NavigationItemMode.mobile, + false => NavigationItemMode.desktop, + }; + return NavigationItemsState( + value: navigationItemsState.value + .where( + (element) => element.modes.contains(navigationItemMode), + ) + .toList(), + ); +} + +@riverpod +CoreState coreState(Ref ref) { + final vpnProps = ref.watch(vpnSettingProvider); + final currentProfile = ref.watch(currentProfileProvider); + final onlyStatisticsProxy = ref.watch(appSettingProvider).onlyStatisticsProxy; + return CoreState( + vpnProps: vpnProps, + onlyStatisticsProxy: onlyStatisticsProxy, + currentProfileName: currentProfile?.label ?? currentProfile?.id ?? "", + ); +} + +@riverpod +ClashConfigState clashConfigState(Ref ref) { + final clashConfig = ref.watch(patchClashConfigProvider); + final overrideDns = ref.watch(overrideDnsProvider); + return ClashConfigState( + overrideDns: overrideDns, + clashConfig: clashConfig, + ); +} + +@riverpod +ProxyState proxyState(Ref ref) { + final isStart = ref.watch(runTimeProvider.select((state)=>state != null)); + final networkProps = ref.watch(networkSettingProvider); + final mixedPort = ref.watch( + patchClashConfigProvider.select((state) => state.mixedPort), + ); + return ProxyState( + isStart: isStart, + systemProxy: networkProps.systemProxy, + bassDomain: networkProps.bypassDomain, + port: mixedPort, + ); +} + +@riverpod +TrayState trayState(Ref ref) { + final isStart = ref.watch(runTimeProvider.select((state)=>state != null)); + final networkProps = ref.watch(networkSettingProvider); + final clashConfig = ref.watch( + patchClashConfigProvider, + ); + final appSetting = ref.watch( + appSettingProvider, + ); + final groups = ref.watch( + groupsProvider, + ); + final brightness = ref.watch( + appBrightnessProvider, + ); + + final selectedMap = ref.watch(selectedMapProvider); + + return TrayState( + mode: clashConfig.mode, + port: clashConfig.mixedPort, + autoLaunch: appSetting.autoRun, + systemProxy: networkProps.systemProxy, + tunEnable: clashConfig.tun.enable, + isStart: isStart, + locale: appSetting.locale, + brightness: brightness, + groups: groups, + selectedMap: selectedMap, + ); +} + +@riverpod +VpnState vpnState(Ref ref) { + final vpnProps = ref.watch(vpnSettingProvider); + final stack = ref.watch( + patchClashConfigProvider.select((state) => state.tun.stack), + ); + + return VpnState( + stack: stack, + vpnProps: vpnProps, + ); +} + +@riverpod +HomeState homeState(Ref ref) { + final pageLabel = ref.watch(currentPageLabelProvider); + final navigationItems = ref.watch(currentNavigationsStateProvider).value; + final viewMode = ref.watch(viewWidthProvider.notifier).viewMode; + final locale = ref.watch(appSettingProvider).locale; + return HomeState( + pageLabel: pageLabel, + navigationItems: navigationItems, + viewMode: viewMode, + locale: locale, + ); +} + +@riverpod +DashboardState dashboardState(Ref ref) { + final dashboardWidgets = + ref.watch(appSettingProvider.select((state) => state.dashboardWidgets)); + final viewWidth = ref.watch(viewWidthProvider); + return DashboardState( + dashboardWidgets: dashboardWidgets, + viewWidth: viewWidth, + ); +} + +@riverpod +ProxiesActionsState proxiesActionsState(Ref ref) { + final pageLabel = ref.watch(currentPageLabelProvider); + final hasProviders = ref.watch(providersProvider.select( + (state) => state.isNotEmpty, + )); + final type = ref.watch(proxiesStyleSettingProvider.select( + (state) => state.type, + )); + return ProxiesActionsState( + pageLabel: pageLabel, + hasProviders: hasProviders, + type: type, + ); +} + +@riverpod +StartButtonSelectorState startButtonSelectorState(Ref ref) { + final isInit = ref.watch(initProvider); + final hasProfile = + ref.watch(profilesProvider.select((state) => state.isNotEmpty)); + return StartButtonSelectorState( + isInit: isInit, + hasProfile: hasProfile, + ); +} + +@riverpod +ProfilesSelectorState profilesSelectorState(Ref ref) { + final currentProfileId = ref.watch(currentProfileIdProvider); + final profiles = ref.watch(profilesProvider); + final columns = ref.watch( + viewWidthProvider.select((state) => other.getProfilesColumns(state))); + return ProfilesSelectorState( + profiles: profiles, + currentProfileId: currentProfileId, + columns: columns, + ); +} + +@riverpod +ProxiesListSelectorState proxiesListSelectorState(Ref ref) { + final groupNames = ref.watch(currentGroupsStateProvider.select((state) { + return state.value.map((e) => e.name).toList(); + })); + final currentUnfoldSet = ref.watch(unfoldSetProvider); + final proxiesStyle = ref.watch(proxiesStyleSettingProvider); + final sortNum = ref.watch(sortNumProvider); + final columns = ref.watch(getProxiesColumnsProvider); + return ProxiesListSelectorState( + groupNames: groupNames, + currentUnfoldSet: currentUnfoldSet, + proxiesSortType: proxiesStyle.sortType, + proxyCardType: proxiesStyle.cardType, + sortNum: sortNum, + columns: columns, + ); +} + +@riverpod +ProxiesSelectorState proxiesSelectorState(Ref ref) { + final groupNames = ref.watch( + currentGroupsStateProvider.select( + (state) { + return state.value.map((e) => e.name).toList(); + }, + ), + ); + final currentGroupName = ref.watch(currentProfileProvider.select( + (state) => state?.currentGroupName, + )); + return ProxiesSelectorState( + groupNames: groupNames, + currentGroupName: currentGroupName, + ); +} + +@riverpod +GroupNamesState groupNamesState(Ref ref) { + return GroupNamesState( + groupNames: ref.watch( + currentGroupsStateProvider.select( + (state) { + return state.value.map((e) => e.name).toList(); + }, + ), + ), + ); +} + +@riverpod +ProxyGroupSelectorState proxyGroupSelectorState(Ref ref, String groupName) { + final testUrl = ref.watch(appSettingProvider.select( + (state) => state.testUrl, + )); + final proxiesStyle = ref.watch( + proxiesStyleSettingProvider, + ); + final group = ref.watch( + currentGroupsStateProvider.select( + (state) => state.value.getGroup(groupName), + ), + ); + final sortNum = ref.watch(sortNumProvider); + final columns = ref.watch(getProxiesColumnsProvider); + return ProxyGroupSelectorState( + testUrl: testUrl, + proxiesSortType: proxiesStyle.sortType, + proxyCardType: proxiesStyle.cardType, + sortNum: sortNum, + groupType: group?.type ?? GroupType.Selector, + proxies: group?.all ?? [], + columns: columns, + ); +} + +@riverpod +PackageListSelectorState packageListSelectorState(Ref ref) { + final packages = ref.watch(packagesProvider); + final accessControl = + ref.watch(vpnSettingProvider.select((state) => state.accessControl)); + return PackageListSelectorState( + packages: packages, + accessControl: accessControl, + ); +} + +@riverpod +MoreToolsSelectorState moreToolsSelectorState(Ref ref) { + final viewMode = ref.watch(viewWidthProvider.notifier).viewMode; + final navigationItems = ref.watch(navigationsStateProvider.select((state) { + return state.value.where((element) { + final isMore = element.modes.contains(NavigationItemMode.more); + final isDesktop = element.modes.contains(NavigationItemMode.desktop); + if (isMore && !isDesktop) return true; + if (viewMode != ViewMode.mobile || !isMore) { + return false; + } + return true; + }).toList(); + })); + + return MoreToolsSelectorState(navigationItems: navigationItems); +} + +@riverpod +bool isCurrentPage( + Ref ref, + PageLabel pageLabel, { + bool Function(PageLabel pageLabel, ViewMode viewMode)? handler, +}) { + final currentPageLabel = ref.watch(currentPageLabelProvider); + if (pageLabel == currentPageLabel) { + return true; + } + if (handler != null) { + final viewMode = ref.watch(viewWidthProvider.notifier).viewMode; + return handler(currentPageLabel, viewMode); + } + return false; +} + +@riverpod +String getRealTestUrl(Ref ref, [String? testUrl]) { + final currentTestUrl = ref.watch(appSettingProvider).testUrl; + return testUrl.getSafeValue(currentTestUrl); +} + +@riverpod +int? getDelay( + Ref ref, { + required String proxyName, + String? testUrl, +}) { + final currentTestUrl = ref.watch(getRealTestUrlProvider(testUrl)); + return ref.watch( + delayDataSourceProvider.select( + (state) => state[currentTestUrl]?[proxyName], + ), + ); +} + +@riverpod +SelectedMap selectedMap(Ref ref) { + final selectedMap = ref.watch( + currentProfileProvider.select((state) => state?.selectedMap ?? {}), + ); + return selectedMap; +} + +@riverpod +Set unfoldSet(Ref ref) { + final unfoldSet = ref.watch( + currentProfileProvider.select((state) => state?.unfoldSet ?? {}), + ); + return unfoldSet; +} + +@riverpod +HotKeyAction getHotKeyAction(Ref ref, HotAction hotAction) { + return ref.watch( + hotKeyActionsProvider.select( + (state) { + final index = state.indexWhere((item) => item.action == hotAction); + return index != -1 + ? state[index] + : HotKeyAction( + action: hotAction, + ); + }, + ), + ); +} + +@riverpod +Profile? currentProfile(Ref ref) { + final profileId = ref.watch(currentProfileIdProvider); + return ref + .watch(profilesProvider.select((state) => state.getProfile(profileId))); +} + +@riverpod +int getProxiesColumns(Ref ref) { + final viewWidth = ref.watch(viewWidthProvider); + final proxiesLayout = + ref.watch(proxiesStyleSettingProvider.select((state) => state.layout)); + return other.getProxiesColumns(viewWidth, proxiesLayout); +} + +String _getRealProxyName( + List groups, + SelectedMap selectedMap, + String proxyName, +) { + if (proxyName.isEmpty) return proxyName; + final index = groups.indexWhere((element) => element.name == proxyName); + if (index == -1) return proxyName; + final group = groups[index]; + final currentSelectedName = + group.getCurrentSelectedName(selectedMap[proxyName] ?? ''); + if (currentSelectedName.isEmpty) return proxyName; + return _getRealProxyName( + groups, + selectedMap, + proxyName, + ); +} + +@riverpod +String getRealProxyName(Ref ref, String proxyName) { + final groups = ref.watch(groupsProvider); + final selectedMap = ref.watch(selectedMapProvider); + return _getRealProxyName(groups, selectedMap, proxyName); +} + +@riverpod +String? getProxyName(Ref ref, String groupName) { + final proxyName = + ref.watch(selectedMapProvider.select((state) => state[groupName])); + return proxyName; +} + +@riverpod +String? getSelectedProxyName(Ref ref, String groupName) { + final proxyName = ref.watch(getProxyNameProvider(groupName)); + final group = ref.watch( + groupsProvider.select( + (state) => state.getGroup(groupName), + ), + ); + return group?.getCurrentSelectedName(proxyName ?? ''); +} + +@riverpod +String getProxyDesc(Ref ref, Proxy proxy) { + final groupTypeNamesList = GroupType.values.map((e) => e.name).toList(); + if (!groupTypeNamesList.contains(proxy.type)) { + return proxy.type; + } else { + final groups = ref.watch(groupsProvider); + final index = groups.indexWhere((element) => element.name == proxy.name); + if (index == -1) return proxy.type; + return "${proxy.type}(${groups[index].now ?? '*'})"; + } +} diff --git a/lib/state.dart b/lib/state.dart index 5bd144c..9d3e692 100644 --- a/lib/state.dart +++ b/lib/state.dart @@ -1,9 +1,9 @@ import 'dart:async'; -import 'dart:io'; import 'package:animations/animations.dart'; import 'package:fl_clash/clash/clash.dart'; import 'package:fl_clash/enum/enum.dart'; +import 'package:fl_clash/l10n/l10n.dart'; import 'package:fl_clash/plugins/service.dart'; import 'package:fl_clash/widgets/scaffold.dart'; import 'package:flutter/material.dart'; @@ -17,9 +17,12 @@ import 'models/models.dart'; typedef UpdateTasks = List; class GlobalState { + static GlobalState? _instance; bool isService = false; Timer? timer; Timer? groupsUpdateTimer; + late Config config; + late AppState appState; late PackageInfo packageInfo; Function? updateCurrentDelayDebounce; PageController? pageController; @@ -30,11 +33,43 @@ class GlobalState { final navigatorKey = GlobalKey(); late AppController appController; GlobalKey homeScaffoldKey = GlobalKey(); - bool lastTunEnable = false; - int? lastProfileModified; bool get isStart => startTime != null && startTime!.isBeforeNow; + GlobalState._internal(); + + factory GlobalState() { + _instance ??= GlobalState._internal(); + return _instance!; + } + + initApp(int version) async { + appState = AppState( + version: version, + viewWidth: other.getScreenSize().width, + requests: FixedList(1000), + logs: FixedList(1000), + traffics: FixedList(30), + totalTraffic: Traffic(), + ); + await init(); + } + + init() async { + packageInfo = await PackageInfo.fromPlatform(); + config = await preferences.getConfig() ?? + Config( + themeProps: defaultThemeProps, + ); + await globalState.migrateOldData(config); + await AppLocalizations.load( + other.getLocaleForString(config.appSetting.locale) ?? + WidgetsBinding.instance.platformDispatcher.locale, + ); + } + + String get ua => config.patchClashConfig.globalUa ?? packageInfo.ua; + startUpdateTasks([UpdateTasks? tasks]) async { if (timer != null && timer!.isActive == true) return; if (tasks != null) { @@ -47,10 +82,10 @@ class GlobalState { } executorUpdateTask() async { - if (timer != null && timer!.isActive == true) return; for (final task in tasks) { await task(); } + timer = null; } stopUpdateTasks() { @@ -59,88 +94,11 @@ class GlobalState { timer = null; } - Future initCore({ - required AppState appState, - required ClashConfig clashConfig, - required Config config, - }) async { - await globalState.init( - appState: appState, - config: config, - clashConfig: clashConfig, - ); - await applyProfile( - appState: appState, - config: config, - clashConfig: clashConfig, - ); - } - - Future updateClashConfig({ - required AppState appState, - required ClashConfig clashConfig, - required Config config, - bool isPatch = true, - }) async { - await config.currentProfile?.checkAndUpdate(); - final useClashConfig = clashConfig.copyWith(); - if (clashConfig.tun.enable != lastTunEnable && - lastTunEnable == false && - !Platform.isAndroid) { - final code = await system.authorizeCore(); - switch (code) { - case AuthorizeCode.none: - break; - case AuthorizeCode.success: - lastTunEnable = useClashConfig.tun.enable; - await restartCore( - appState: appState, - clashConfig: clashConfig, - config: config, - ); - return; - case AuthorizeCode.error: - useClashConfig.tun = useClashConfig.tun.copyWith( - enable: false, - ); - } - } - if (config.appSetting.openLogs) { - clashCore.startLog(); - } else { - clashCore.stopLog(); - } - final res = await clashCore.updateConfig( - getUpdateConfigParams(config, clashConfig, isPatch), - ); - if (res.isNotEmpty) throw res; - lastTunEnable = useClashConfig.tun.enable; - lastProfileModified = await config.getCurrentProfile()?.profileLastModified; - } - handleStart([UpdateTasks? tasks]) async { + startTime ??= DateTime.now(); await clashCore.startListener(); await service?.startVpn(); startUpdateTasks(tasks); - startTime ??= DateTime.now(); - } - - restartCore({ - required AppState appState, - required ClashConfig clashConfig, - required Config config, - bool isPatch = true, - }) async { - await clashService?.reStart(); - await initCore( - appState: appState, - clashConfig: clashConfig, - config: config, - ); - - if (isStart) { - await handleStart(); - } } Future updateStartTime() async { @@ -150,85 +108,16 @@ class GlobalState { Future handleStop() async { startTime = null; await clashCore.stopListener(); - clashLib?.stopTun(); + await clashLib?.stopTun(); await service?.stopVpn(); stopUpdateTasks(); } - Future applyProfile({ - required AppState appState, - required Config config, - required ClashConfig clashConfig, - }) async { - clashCore.requestGc(); - await updateClashConfig( - appState: appState, - clashConfig: clashConfig, - config: config, - isPatch: false, - ); - await updateGroups(appState); - await updateProviders(appState); - } - - updateProviders(AppState appState) async { - appState.providers = await clashCore.getExternalProviders(); - } - - CoreState getCoreState(Config config, ClashConfig clashConfig) { - return CoreState( - enable: config.vpnProps.enable, - accessControl: config.isAccessControl ? config.accessControl : null, - ipv6: config.vpnProps.ipv6, - allowBypass: config.vpnProps.allowBypass, - bypassDomain: config.networkProps.bypassDomain, - systemProxy: config.vpnProps.systemProxy, - currentProfileName: - config.currentProfile?.label ?? config.currentProfileId ?? "", - routeAddress: clashConfig.routeAddress, - ); - } - - getUpdateConfigParams(Config config, ClashConfig clashConfig, bool isPatch) { - return UpdateConfigParams( - profileId: config.currentProfileId ?? "", - config: clashConfig, - params: ConfigExtendedParams( - isPatch: isPatch, - isCompatible: true, - selectedMap: config.currentSelectedMap, - overrideDns: config.overrideDns, - testUrl: config.appSetting.testUrl, - onlyStatisticsProxy: config.appSetting.onlyStatisticsProxy, - ), - ); - } - - init({ - required AppState appState, - required Config config, - required ClashConfig clashConfig, - }) async { - appState.isInit = await clashCore.isInit; - if (!appState.isInit) { - appState.isInit = await clashCore.init( - config: config, - clashConfig: clashConfig, - ); - clashLib?.setState( - getCoreState(config, clashConfig), - ); - } - } - - Future updateGroups(AppState appState) async { - appState.groups = await clashCore.getProxiesGroups(); - } - - Future showMessage({ + Future showMessage({ required String title, required InlineSpan message, String? confirmText, + bool cancelable = true, }) async { return await showCommonDialog( child: Builder( @@ -251,12 +140,13 @@ class GlobalState { ), ), actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(false); - }, - child: Text(appLocalizations.cancel), - ), + if (cancelable) + TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text(appLocalizations.cancel), + ), TextButton( onPressed: () { Navigator.of(context).pop(true); @@ -270,22 +160,6 @@ class GlobalState { ); } - changeProxy({ - required Config config, - required String groupName, - required String proxyName, - }) async { - await clashCore.changeProxy( - ChangeProxyParams( - groupName: groupName, - proxyName: proxyName, - ), - ); - if (config.appSetting.closeConnections) { - clashCore.closeConnections(); - } - } - Future showCommonDialog({ required Widget child, bool dismissible = true, @@ -301,17 +175,6 @@ class GlobalState { ); } - updateTraffic({ - required Config config, - AppFlowingState? appFlowingState, - }) async { - final traffic = await clashCore.getTraffic(); - if (appFlowingState != null) { - appFlowingState.addTraffic(traffic); - appFlowingState.totalTraffic = await clashCore.getTotalTraffic(); - } - } - Future safeRun( FutureOr Function() futureFunction, { String? title, @@ -321,6 +184,7 @@ class GlobalState { final res = await futureFunction(); return res; } catch (e) { + commonPrint.log("$e"); if (silence) { showNotifier(e.toString()); } else { @@ -353,6 +217,49 @@ class GlobalState { } launchUrl(Uri.parse(url)); } + + Future migrateOldData(Config config) async { + final clashConfig = await preferences.getClashConfig(); + if (clashConfig != null) { + config = config.copyWith( + patchClashConfig: clashConfig, + ); + preferences.clearClashConfig(); + preferences.saveConfig(config); + } + } + + CoreState getCoreState() { + final currentProfile = config.currentProfile; + return CoreState( + vpnProps: config.vpnProps, + onlyStatisticsProxy: config.appSetting.onlyStatisticsProxy, + currentProfileName: currentProfile?.label ?? currentProfile?.id ?? "", + bypassDomain: config.networkProps.bypassDomain, + ); + } + + getUpdateConfigParams([bool? isPatch]) { + final currentProfile = config.currentProfile; + final clashConfig = config.patchClashConfig; + return UpdateConfigParams( + profileId: config.currentProfileId ?? "", + config: clashConfig.copyWith( + globalUa: ua, + tun: clashConfig.tun.copyWith( + routeAddress: config.networkProps.routeMode == RouteMode.bypassPrivate + ? defaultBypassPrivateRouteAddress + : clashConfig.tun.routeAddress, + ), + ), + params: ConfigExtendedParams( + isPatch: isPatch ?? false, + selectedMap: currentProfile?.selectedMap ?? {}, + overrideDns: config.overrideDns, + testUrl: config.appSetting.testUrl, + ), + ); + } } final globalState = GlobalState(); diff --git a/lib/widgets/builder.dart b/lib/widgets/builder.dart index 5294f84..0cf5845 100644 --- a/lib/widgets/builder.dart +++ b/lib/widgets/builder.dart @@ -1,6 +1,4 @@ -import 'package:fl_clash/models/models.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; class ScrollOverBuilder extends StatefulWidget { final Widget Function(bool isOver) builder; @@ -40,97 +38,59 @@ class _ScrollOverBuilderState extends State { } } -class ProxiesActionsBuilder extends StatelessWidget { - final Widget? child; - final Widget Function( - ProxiesActionsState state, - Widget? child, - ) builder; +// class ProxiesActionsBuilder extends StatelessWidget { +// final Widget? child; +// final Widget Function( +// ProxiesActionsState state, +// Widget? child, +// ) builder; +// +// const ProxiesActionsBuilder({ +// super.key, +// required this.child, +// required this.builder, +// }); +// +// @override +// Widget build(BuildContext context) { +// return Selector( +// selector: (_, appState) => ProxiesActionsState( +// isCurrent: appState.currentLabel == "proxies", +// hasProvider: appState.providers.isNotEmpty, +// ), +// builder: (_, state, child) => builder(state, child), +// child: child, +// ); +// } +// } - const ProxiesActionsBuilder({ - super.key, - required this.child, - required this.builder, - }); - - @override - Widget build(BuildContext context) { - return Selector( - selector: (_, appState) => ProxiesActionsState( - isCurrent: appState.currentLabel == "proxies", - hasProvider: appState.providers.isNotEmpty, - ), - builder: (_, state, child) => builder(state, child), - child: child, - ); - } -} +// class ActiveBuilder extends StatelessWidget { +// final String label; +// final StateAndChildWidgetBuilder builder; +// final Widget? child; +// +// const ActiveBuilder({ +// super.key, +// required this.label, +// required this.builder, +// required this.child, +// }); +// +// @override +// Widget build(BuildContext context) { +// return Selector( +// selector: (_, appState) => appState.currentLabel == label, +// builder: (_, state, child) { +// return builder( +// state, +// child, +// ); +// }, +// child: child, +// ); +// } +// } typedef StateWidgetBuilder = Widget Function(T state); typedef StateAndChildWidgetBuilder = Widget Function(T state, Widget? child); - -class LocaleBuilder extends StatelessWidget { - final StateWidgetBuilder builder; - - const LocaleBuilder({ - super.key, - required this.builder, - }); - - @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.appSetting.locale, - builder: (_, state, __) { - return builder(state); - }, - ); - } -} - -class ActiveBuilder extends StatelessWidget { - final String label; - final StateAndChildWidgetBuilder builder; - final Widget? child; - - const ActiveBuilder({ - super.key, - required this.label, - required this.builder, - required this.child, - }); - - @override - Widget build(BuildContext context) { - return Selector( - selector: (_, appState) => appState.currentLabel == label, - builder: (_, state, child) { - return builder( - state, - child, - ); - }, - child: child, - ); - } -} - -class ThemeModeBuilder extends StatelessWidget { - final StateWidgetBuilder builder; - - const ThemeModeBuilder({ - super.key, - required this.builder, - }); - - @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.themeProps.themeMode, - builder: (_, state, __) { - return builder(state); - }, - ); - } -} diff --git a/lib/widgets/card.dart b/lib/widgets/card.dart index 79da102..9879140 100644 --- a/lib/widgets/card.dart +++ b/lib/widgets/card.dart @@ -1,5 +1,6 @@ import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/enum/enum.dart'; +import 'package:fl_clash/widgets/fade_box.dart'; import 'package:flutter/material.dart'; import 'text.dart'; @@ -56,8 +57,8 @@ class InfoHeader extends StatelessWidget { maxLines: 1, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.titleSmall?.copyWith( - color: context.colorScheme.onSurfaceVariant, - ), + color: context.colorScheme.onSurfaceVariant, + ), ), ), ), @@ -90,9 +91,12 @@ class CommonCard extends StatelessWidget { this.backgroundColor, this.radius = 12, required this.child, + this.enterAnimated = false, + this.borderSide, this.info, }) : isSelected = isSelected ?? false; + final bool enterAnimated; final bool isSelected; final void Function()? onPressed; final Widget? selectWidget; @@ -101,6 +105,7 @@ class CommonCard extends StatelessWidget { final CommonCardType type; final double radius; final WidgetStateProperty? backgroundColor; + final WidgetStateProperty? borderSide; BorderSide getBorderSide(BuildContext context, Set states) { final colorScheme = context.colorScheme; @@ -166,7 +171,7 @@ class CommonCard extends StatelessWidget { ], ); } - + if (selectWidget != null && isSelected) { final List children = []; children.add(childWidget); @@ -180,7 +185,7 @@ class CommonCard extends StatelessWidget { ); } - return OutlinedButton( + final card = OutlinedButton( clipBehavior: Clip.antiAlias, style: ButtonStyle( padding: const WidgetStatePropertyAll(EdgeInsets.zero), @@ -195,13 +200,21 @@ class CommonCard extends StatelessWidget { WidgetStateProperty.resolveWith( (states) => getBackgroundColor(context, states), ), - side: WidgetStateProperty.resolveWith( - (states) => getBorderSide(context, states), - ), + side: borderSide ?? + WidgetStateProperty.resolveWith( + (states) => getBorderSide(context, states), + ), ), onPressed: onPressed, child: childWidget, ); + + return switch (enterAnimated) { + true => FadeScaleEnterBox( + child: card, + ), + false => card, + }; } } diff --git a/lib/widgets/color_scheme_box.dart b/lib/widgets/color_scheme_box.dart index 6714f3d..ce6c17f 100644 --- a/lib/widgets/color_scheme_box.dart +++ b/lib/widgets/color_scheme_box.dart @@ -1,3 +1,4 @@ +import 'package:fl_clash/models/models.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; import 'card.dart'; @@ -25,15 +26,16 @@ class ColorSchemeBox extends StatelessWidget { ); } else { return Theme.of(context).copyWith( - colorScheme: globalState.appController.appState.systemColorSchemes - .getSystemColorSchemeForBrightness(Theme.of(context).brightness), + colorScheme: globalState.appState.colorSchemes + .getColorSchemeForBrightness(Theme.of(context).brightness), ); } } @override Widget build(BuildContext context) { - return AspectRatio(aspectRatio: 1, + return AspectRatio( + aspectRatio: 1, child: Theme( data: _getTheme(context), child: Builder( diff --git a/lib/widgets/fade_box.dart b/lib/widgets/fade_box.dart index 23d5f37..06ff0dc 100644 --- a/lib/widgets/fade_box.dart +++ b/lib/widgets/fade_box.dart @@ -1,4 +1,5 @@ import 'package:animations/animations.dart'; +import 'package:fl_clash/common/common.dart'; import 'package:flutter/material.dart'; class FadeBox extends StatelessWidget { @@ -60,3 +61,88 @@ class FadeScaleBox extends StatelessWidget { ); } } + +class FadeScaleEnterBox extends StatefulWidget { + final Widget child; + + const FadeScaleEnterBox({ + super.key, + required this.child, + }); + + @override + State createState() => _FadeScaleEnterBoxState(); +} + +class _FadeScaleEnterBoxState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _animation; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + vsync: this, + duration: commonDuration, + ); + _animation = Tween( + begin: 0, + end: 1, + ).animate(CurvedAnimation( + parent: _controller, + curve: Curves.easeInOut, + )); + _controller.forward(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: _controller.view, + builder: (_, child) { + return FadeScaleEnterTransition( + animation: _animation, + child: child!, + ); + }, + child: widget.child, + ); + } +} + +class FadeScaleEnterTransition extends StatelessWidget { + const FadeScaleEnterTransition({ + super.key, + required this.animation, + this.child, + }); + + final Animation animation; + final Widget? child; + + static final Animatable _fadeInTransition = CurveTween( + curve: const Interval(0.0, 0.3), + ); + static final Animatable _scaleInTransition = Tween( + begin: 0.70, + end: 1.00, + ).chain(CurveTween(curve: Easing.legacyDecelerate)); + + @override + Widget build(BuildContext context) { + return FadeTransition( + opacity: _fadeInTransition.animate(animation), + child: ScaleTransition( + scale: _scaleInTransition.animate(animation), + child: child, + ), + ); + } +} diff --git a/lib/widgets/input.dart b/lib/widgets/input.dart index 0a619d5..e6115a8 100644 --- a/lib/widgets/input.dart +++ b/lib/widgets/input.dart @@ -91,7 +91,6 @@ class _InputDialogState extends State { _handleUpdate() async { final text = textController.value.text; - if (text.isEmpty) return; Navigator.of(context).pop(text); } @@ -119,6 +118,9 @@ class _InputDialogState extends State { border: const OutlineInputBorder(), suffixText: suffixText, ), + onSubmitted: (_){ + _handleUpdate(); + }, ), ], ), diff --git a/lib/widgets/list.dart b/lib/widgets/list.dart index fb2dd56..a78940e 100644 --- a/lib/widgets/list.dart +++ b/lib/widgets/list.dart @@ -1,5 +1,6 @@ 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'; import 'package:fl_clash/widgets/open_container.dart'; import 'package:flutter/material.dart'; @@ -283,8 +284,7 @@ class ListItem extends StatelessWidget { return OpenContainer( closedBuilder: (_, action) { openAction() { - final isMobile = - globalState.appController.appState.viewMode == ViewMode.mobile; + final isMobile = globalState.appState.viewMode == ViewMode.mobile; if (!isMobile) { showExtendPage( context, @@ -349,8 +349,7 @@ class ListItem extends StatelessWidget { final nextDelegate = delegate as NextDelegate; return _buildListTile( onTap: () { - final isMobile = - globalState.appController.appState.viewMode == ViewMode.mobile; + final isMobile = globalState.appState.viewMode == ViewMode.mobile; if (!isMobile) { showExtendPage( context, diff --git a/lib/widgets/open_container.dart b/lib/widgets/open_container.dart index 31ad601..f0dbfa2 100644 --- a/lib/widgets/open_container.dart +++ b/lib/widgets/open_container.dart @@ -1,8 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; -import 'package:provider/provider.dart'; - -import '../models/models.dart'; typedef CloseContainerActionCallback = void Function({S? returnValue}); typedef OpenContainerBuilder = Widget Function( @@ -426,141 +423,131 @@ class _OpenContainerRoute extends ModalRoute { Animation animation, Animation secondaryAnimation, ) { - return Selector( - selector: (_, config) => config.themeProps.themeMode, - builder: (_, __, ___) { - _colorTween = _getColorTween( - transitionType: transitionType, - closedColor: Theme.of(context).colorScheme.surface, - openColor: Theme.of(context).colorScheme.surface, - middleColor: middleColor, - ); - return Align( - alignment: Alignment.topLeft, - child: AnimatedBuilder( - animation: animation, - builder: (BuildContext context, Widget? child) { - if (animation.isCompleted) { - return SizedBox.expand( + _colorTween = _getColorTween( + transitionType: transitionType, + closedColor: Theme.of(context).colorScheme.surface, + openColor: Theme.of(context).colorScheme.surface, + middleColor: middleColor, + ); + return Align( + alignment: Alignment.topLeft, + child: AnimatedBuilder( + animation: animation, + builder: (BuildContext context, Widget? child) { + if (animation.isCompleted) { + return SizedBox.expand( + child: Material( + child: Builder( + key: _openBuilderKey, + builder: (BuildContext context) { + return openBuilder(context, closeContainer); + }, + ), + ), + ); + } + + final Animation curvedAnimation = CurvedAnimation( + parent: animation, + curve: Curves.fastOutSlowIn, + reverseCurve: + _transitionWasInterrupted ? null : Curves.fastOutSlowIn.flipped, + ); + TweenSequence? colorTween; + TweenSequence? closedOpacityTween, openOpacityTween; + switch (animation.status) { + case AnimationStatus.dismissed: + case AnimationStatus.forward: + closedOpacityTween = _closedOpacityTween; + openOpacityTween = _openOpacityTween; + colorTween = _colorTween; + break; + case AnimationStatus.reverse: + if (_transitionWasInterrupted) { + closedOpacityTween = _closedOpacityTween; + openOpacityTween = _openOpacityTween; + colorTween = _colorTween; + break; + } + closedOpacityTween = _closedOpacityTween.flipped; + openOpacityTween = _openOpacityTween.flipped; + colorTween = _colorTween.flipped; + break; + case AnimationStatus.completed: + assert(false); // Unreachable. + break; + } + assert(colorTween != null); + assert(closedOpacityTween != null); + assert(openOpacityTween != null); + + final Rect rect = _rectTween.evaluate(curvedAnimation)!; + return SizedBox.expand( + child: Align( + alignment: Alignment.topLeft, + child: Transform.translate( + offset: Offset(rect.left, rect.top), + child: SizedBox( + width: rect.width, + height: rect.height, child: Material( - child: Builder( - key: _openBuilderKey, - builder: (BuildContext context) { - return openBuilder(context, closeContainer); - }, - ), - ), - ); - } - - final Animation curvedAnimation = CurvedAnimation( - parent: animation, - curve: Curves.fastOutSlowIn, - reverseCurve: _transitionWasInterrupted - ? null - : Curves.fastOutSlowIn.flipped, - ); - TweenSequence? colorTween; - TweenSequence? closedOpacityTween, openOpacityTween; - switch (animation.status) { - case AnimationStatus.dismissed: - case AnimationStatus.forward: - closedOpacityTween = _closedOpacityTween; - openOpacityTween = _openOpacityTween; - colorTween = _colorTween; - break; - case AnimationStatus.reverse: - if (_transitionWasInterrupted) { - closedOpacityTween = _closedOpacityTween; - openOpacityTween = _openOpacityTween; - colorTween = _colorTween; - break; - } - closedOpacityTween = _closedOpacityTween.flipped; - openOpacityTween = _openOpacityTween.flipped; - colorTween = _colorTween.flipped; - break; - case AnimationStatus.completed: - assert(false); // Unreachable. - break; - } - assert(colorTween != null); - assert(closedOpacityTween != null); - assert(openOpacityTween != null); - - final Rect rect = _rectTween.evaluate(curvedAnimation)!; - return SizedBox.expand( - child: Align( - alignment: Alignment.topLeft, - child: Transform.translate( - offset: Offset(rect.left, rect.top), - child: SizedBox( - width: rect.width, - height: rect.height, - child: Material( - clipBehavior: Clip.antiAlias, - animationDuration: Duration.zero, - color: colorTween!.evaluate(animation), - child: Stack( - fit: StackFit.passthrough, - children: [ - // Closed child fading out. - FittedBox( - fit: BoxFit.fitWidth, - alignment: Alignment.topLeft, - child: SizedBox( - width: _rectTween.begin!.width, - height: _rectTween.begin!.height, - child: (hideableKey.currentState?.isInTree ?? - false) - ? null - : FadeTransition( - opacity: closedOpacityTween! - .animate(animation), - child: Builder( - key: closedBuilderKey, - builder: (BuildContext context) { - // Use dummy "open container" callback - // since we are in the process of opening. - return closedBuilder( - context, () {}); - }, - ), - ), - ), - ), - - // Open child fading in. - FittedBox( - fit: BoxFit.fitWidth, - alignment: Alignment.topLeft, - child: SizedBox( - width: _rectTween.end!.width, - height: _rectTween.end!.height, - child: FadeTransition( - opacity: - openOpacityTween!.animate(animation), - child: Builder( - key: _openBuilderKey, - builder: (BuildContext context) { - return openBuilder( - context, closeContainer); - }, + clipBehavior: Clip.antiAlias, + animationDuration: Duration.zero, + color: colorTween!.evaluate(animation), + child: Stack( + fit: StackFit.passthrough, + children: [ + // Closed child fading out. + FittedBox( + fit: BoxFit.fitWidth, + alignment: Alignment.topLeft, + child: SizedBox( + width: _rectTween.begin!.width, + height: _rectTween.begin!.height, + child: (hideableKey.currentState?.isInTree ?? false) + ? null + : FadeTransition( + opacity: + closedOpacityTween!.animate(animation), + child: Builder( + key: closedBuilderKey, + builder: (BuildContext context) { + // Use dummy "open container" callback + // since we are in the process of opening. + return closedBuilder(context, () {}); + }, + ), ), - ), + ), + ), + + // Open child fading in. + FittedBox( + fit: BoxFit.fitWidth, + alignment: Alignment.topLeft, + child: SizedBox( + width: _rectTween.end!.width, + height: _rectTween.end!.height, + child: FadeTransition( + opacity: openOpacityTween!.animate(animation), + child: Builder( + key: _openBuilderKey, + builder: (BuildContext context) { + return openBuilder(context, closeContainer); + }, ), ), - ], + ), ), - ), + ], ), ), ), - ); - }, - ), - ); - }, + ), + ), + ); + }, + ), ); } diff --git a/lib/widgets/scaffold.dart b/lib/widgets/scaffold.dart index 6dac425..3df2869 100644 --- a/lib/widgets/scaffold.dart +++ b/lib/widgets/scaffold.dart @@ -296,10 +296,14 @@ class CommonScaffoldState extends State { icon: Icon(Icons.close), ) else - ...realActions.separated( - SizedBox( - width: 4, - ), + Row( + children: [ + ...realActions.separated( + SizedBox( + width: 4, + ), + ) + ], ), SizedBox( width: 8, diff --git a/lib/widgets/sheet.dart b/lib/widgets/sheet.dart index e45f55a..5abeb70 100644 --- a/lib/widgets/sheet.dart +++ b/lib/widgets/sheet.dart @@ -1,5 +1,6 @@ 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'; import 'package:fl_clash/widgets/scaffold.dart'; import 'package:flutter/material.dart'; @@ -21,8 +22,7 @@ showExtendPage( key: globalKey, child: body, ); - final isMobile = - globalState.appController.appState.viewMode == ViewMode.mobile; + final isMobile = globalState.appState.viewMode == ViewMode.mobile; if (isMobile) { BaseNavigator.push( context, @@ -63,17 +63,16 @@ showExtendPage( ); } -showSheet({ +Future showSheet({ required BuildContext context, required Widget body, required String title, bool isScrollControlled = true, double width = 320, }) { - final viewMode = globalState.appController.appState.viewMode; - final isMobile = viewMode == ViewMode.mobile; + final isMobile = globalState.appState.viewMode == ViewMode.mobile; if (isMobile) { - showModalBottomSheet( + return showModalBottomSheet( context: context, isScrollControlled: isScrollControlled, builder: (context) { @@ -85,7 +84,7 @@ showSheet({ useSafeArea: true, ); } else { - showModalSideSheet( + return showModalSideSheet( useSafeArea: true, isScrollControlled: isScrollControlled, context: context, diff --git a/macos/Podfile.lock b/macos/Podfile.lock index f190719..40b439d 100755 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -99,24 +99,24 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos SPEC CHECKSUMS: - app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a - connectivity_plus: 18382e7311ba19efcaee94442b23b32507b20695 - device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720 - dynamic_color: 2eaa27267de1ca20d879fbd6e01259773fb1670f - file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d + app_links: 9028728e32c83a0831d9db8cf91c526d16cc5468 + connectivity_plus: 2256d3e20624a7749ed21653aafe291a46446fee + device_info_plus: a56e6e74dbbd2bb92f2da12c64ddd4f67a749041 + dynamic_color: b820c000cc68df65e7ba7ff177cb98404ce56651 + file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 HotKey: e96d8a2ddbf4591131e2bb3f54e69554d90cdca6 - hotkey_manager_macos: 1e2edb0c7ae4fe67108af44a9d3445de41404160 - mobile_scanner: 07710d6b9b2c220ae899de2d7ecf5d77ffa56333 - package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161 - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d - tray_manager: 9064e219c56d75c476e46b9a21182087930baf90 - url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404 - window_ext: cbf41f054296dcfb15a1cb53610ef3eab6311f13 - window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 + hotkey_manager_macos: a4317849af96d2430fa89944d3c58977ca089fbe + mobile_scanner: 0e365ed56cad24f28c0fd858ca04edefb40dfac3 + package_info_plus: f0052d280d17aa382b932f399edf32507174e870 + path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 + screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f + shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 + sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 + tray_manager: a104b5c81b578d83f3c3d0f40a997c8b10810166 + url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673 + window_ext: 4afef727fe428b30c68ce800ba92e890fd329f63 + window_manager: 1d01fa7ac65a6e6f83b965471b1a7fdd3f06166c PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 diff --git a/pubspec.lock b/pubspec.lock index b3e4813..288939d 100755 --- a/pubspec.lock +++ b/pubspec.lock @@ -22,6 +22,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.7.0" + analyzer_plugin: + dependency: transitive + description: + name: analyzer_plugin + sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161" + url: "https://pub.dev" + source: hosted + version: "0.11.3" animations: dependency: "direct main" description: @@ -174,6 +182,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + ci: + dependency: transitive + description: + name: ci + sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13" + url: "https://pub.dev" + source: hosted + version: "0.1.0" cli_util: dependency: transitive description: @@ -246,6 +262,38 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.6" + custom_lint: + dependency: "direct dev" + description: + name: custom_lint + sha256: "3486c470bb93313a9417f926c7dd694a2e349220992d7b9d14534dc49c15bba9" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + custom_lint_builder: + dependency: transitive + description: + name: custom_lint_builder + sha256: "42cdc41994eeeddab0d7a722c7093ec52bd0761921eeb2cbdbf33d192a234759" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + custom_lint_core: + dependency: transitive + description: + name: custom_lint_core + sha256: "02450c3e45e2a6e8b26c4d16687596ab3c4644dd5792e3313aa9ceba5a49b7f5" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + custom_lint_visitor: + dependency: transitive + description: + name: custom_lint_visitor + sha256: "8aeb3b6ae2bb765e7716b93d1d10e8356d04e0ff6d7592de6ee04e0dd7d6587d" + url: "https://pub.dev" + source: hosted + version: "1.0.0+6.7.0" dart_style: dependency: transitive description: @@ -440,6 +488,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.23" + flutter_riverpod: + dependency: "direct main" + description: + name: flutter_riverpod + sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1" + url: "https://pub.dev" + source: hosted + version: "2.6.1" flutter_test: dependency: "direct dev" description: flutter @@ -538,6 +594,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.0" + hotreloader: + dependency: transitive + description: + name: hotreloader + sha256: bc167a1163807b03bada490bfe2df25b0d744df359227880220a5cbd04e5734b + url: "https://pub.dev" + source: hosted + version: "4.3.0" http: dependency: transitive description: @@ -794,14 +858,6 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.2" - nested: - dependency: transitive - description: - name: nested - sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" - source: hosted - version: "1.0.0" nm: dependency: transitive description: @@ -938,14 +994,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.2+1" - provider: - dependency: "direct main" - description: - name: provider - sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c - url: "https://pub.dev" - source: hosted - version: "6.1.2" proxy: dependency: "direct main" description: @@ -993,6 +1041,46 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.3" + riverpod: + dependency: "direct main" + description: + name: riverpod + sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959" + url: "https://pub.dev" + source: hosted + version: "2.6.1" + riverpod_analyzer_utils: + dependency: transitive + description: + name: riverpod_analyzer_utils + sha256: c6b8222b2b483cb87ae77ad147d6408f400c64f060df7a225b127f4afef4f8c8 + url: "https://pub.dev" + source: hosted + version: "0.5.8" + riverpod_annotation: + dependency: "direct main" + description: + name: riverpod_annotation + sha256: e14b0bf45b71326654e2705d462f21b958f987087be850afd60578fcd502d1b8 + url: "https://pub.dev" + source: hosted + version: "2.6.1" + riverpod_generator: + dependency: "direct dev" + description: + name: riverpod_generator + sha256: "63546d70952015f0981361636bf8f356d9cfd9d7f6f0815e3c07789a41233188" + url: "https://pub.dev" + source: hosted + version: "2.6.3" + riverpod_lint: + dependency: "direct dev" + description: + name: riverpod_lint + sha256: "83e4caa337a9840469b7b9bd8c2351ce85abad80f570d84146911b32086fbd99" + url: "https://pub.dev" + source: hosted + version: "2.6.3" rxdart: dependency: transitive description: @@ -1206,6 +1294,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.11.1" + state_notifier: + dependency: transitive + description: + name: state_notifier + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb + url: "https://pub.dev" + source: hosted + version: "1.0.0" stream_channel: dependency: transitive description: @@ -1266,10 +1362,10 @@ packages: dependency: "direct main" description: name: tray_manager - sha256: bdc3ac6c36f3d12d871459e4a9822705ce5a1165a17fa837103bc842719bf3f7 + sha256: "80be6c508159a6f3c57983de795209ac13453e9832fd574143b06dceee188ed2" url: "https://pub.dev" source: hosted - version: "0.2.4" + version: "0.3.2" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b2f3c0d..88f10f4 100755 --- 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.76+202502092 +version: 0.8.77+202503051 environment: sdk: '>=3.1.0 <4.0.0' @@ -14,7 +14,7 @@ dependencies: path_provider: ^2.1.0 path: ^1.9.0 shared_preferences: ^2.5.1 - provider: ^6.0.5 +# provider: ^6.0.5 window_manager: ^0.4.3 dynamic_color: ^1.7.0 proxy: @@ -28,7 +28,7 @@ dependencies: mobile_scanner: ^6.0.2 app_links: ^3.5.0 win32_registry: ^1.1.5 - tray_manager: ^0.2.1 + tray_manager: ^0.3.2 collection: ^1.18.0 animations: ^2.0.11 package_info_plus: ^8.0.0 @@ -52,15 +52,21 @@ dependencies: connectivity_plus: ^6.1.0 screen_retriever: ^0.2.0 defer_pointer: ^0.0.2 + flutter_riverpod: ^2.6.1 + riverpod_annotation: ^2.6.1 + riverpod: ^2.6.1 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^5.0.0 ffigen: ^15.0.0 json_serializable: ^6.7.1 - build_runner: ^2.4.9 + build_runner: ^2.4.13 args: ^2.4.2 freezed: ^2.5.1 + riverpod_generator: ^2.6.3 + custom_lint: ^0.7.0 + riverpod_lint: ^2.6.3 flutter: uses-material-design: true