From e6da643186d6b4917d72314dac9050f6136691db Mon Sep 17 00:00:00 2001 From: chen08209 Date: Sun, 8 Sep 2024 21:21:21 +0800 Subject: [PATCH] Support desktop hotkey Support android ipv6 inbound Support android system dns fix some bugs --- .gitmodules | 2 +- .../com/follow/clash/BaseServiceInterface.kt | 3 +- .../kotlin/com/follow/clash/GlobalState.kt | 3 +- .../kotlin/com/follow/clash/extensions/Ext.kt | 53 +- .../kotlin/com/follow/clash/models/Dns.kt | 26 + .../kotlin/com/follow/clash/models/Package.kt | 2 - .../kotlin/com/follow/clash/models/Props.kt | 10 + .../com/follow/clash/plugins/AppPlugin.kt | 58 +- .../com/follow/clash/plugins/ServicePlugin.kt | 2 + .../com/follow/clash/plugins/VpnPlugin.kt | 203 +- .../follow/clash/services/FlClashService.kt | 2 +- .../clash/services/FlClashVpnService.kt | 84 +- assets/images/icon_black.ico | Bin 0 -> 3939 bytes assets/images/icon_black.png | Bin 0 -> 13452 bytes assets/images/icon_white.ico | Bin 0 -> 4031 bytes .../{icon_monochrome.png => icon_white.png} | Bin core/Clash.Meta | 2 +- core/dns.go | 20 + core/go.mod | 15 +- core/go.sum | 19 +- core/hub.go | 9 +- core/tun.go | 54 +- core/tun/dns.go | 33 - core/tun/tcp.go | 20 - core/tun/tun.go | 209 +- core/tun/udp.go | 28 - lib/application.dart | 46 +- lib/clash/core.dart | 15 +- lib/clash/generated/clash_ffi.dart | 27 +- lib/common/common.dart | 3 +- lib/common/constant.dart | 7 +- lib/common/keyboard.dart | 106 + lib/common/other.dart | 20 +- lib/common/request.dart | 2 +- lib/common/system.dart | 12 + lib/common/window.dart | 16 +- lib/controller.dart | 91 +- lib/enum/enum.dart | 52 +- lib/fragments/backup_and_recovery.dart | 3 +- lib/fragments/config/app.dart | 26 - lib/fragments/config/dns.dart | 59 +- lib/fragments/dashboard/status_switch.dart | 36 +- lib/fragments/hotkey.dart | 250 ++ lib/fragments/profiles/profiles.dart | 6 +- lib/fragments/proxies/card.dart | 37 +- lib/fragments/proxies/common.dart | 24 +- lib/fragments/proxies/list.dart | 146 +- lib/fragments/proxies/tab.dart | 62 +- lib/fragments/tools.dart | 48 +- lib/l10n/arb/intl_en.arb | 17 +- lib/l10n/arb/intl_zh_CN.arb | 21 +- lib/l10n/intl/messages_en.dart | 21 + lib/l10n/intl/messages_zh_CN.dart | 21 +- lib/l10n/l10n.dart | 150 + lib/main.dart | 13 +- .../android_manager.dart} | 36 +- .../app_state_manager.dart} | 38 +- .../clash_manager.dart} | 26 +- lib/manager/hotkey_manager.dart | 75 + lib/manager/manager.dart | 9 + lib/manager/media_manager.dart | 41 + .../proxy_manager.dart} | 4 +- .../tile_manager.dart} | 8 +- lib/manager/tray_manager.dart | 177 ++ .../vpn_manager.dart} | 10 +- .../window_manager.dart} | 63 +- lib/models/app.dart | 36 +- lib/models/common.dart | 438 +++ lib/models/config.dart | 38 +- lib/models/connection.dart | 58 - lib/models/dav.dart | 19 - lib/models/ffi.dart | 16 + lib/models/file.dart | 21 - lib/models/generated/common.freezed.dart | 2470 +++++++++++++++++ lib/models/generated/common.g.dart | 232 ++ lib/models/generated/config.g.dart | 9 +- lib/models/generated/connection.freezed.dart | 772 ------ lib/models/generated/connection.g.dart | 74 - lib/models/generated/dav.freezed.dart | 202 -- lib/models/generated/dav.g.dart | 21 - lib/models/generated/ffi.freezed.dart | 261 ++ lib/models/generated/ffi.g.dart | 22 + lib/models/generated/file.freezed.dart | 150 - lib/models/generated/log.freezed.dart | 189 -- lib/models/generated/log.g.dart | 45 - lib/models/generated/navigation.freezed.dart | 271 -- lib/models/generated/package.freezed.dart | 209 -- lib/models/generated/package.g.dart | 23 - lib/models/generated/proxy.freezed.dart | 428 --- lib/models/generated/proxy.g.dart | 50 - lib/models/generated/selector.freezed.dart | 445 +-- lib/models/generated/version.freezed.dart | 171 -- lib/models/generated/version.g.dart | 19 - lib/models/ip.dart | 70 - lib/models/log.dart | 56 - lib/models/models.dart | 12 +- lib/models/navigation.dart | 19 - lib/models/package.dart | 17 - lib/models/proxy.dart | 45 - lib/models/selector.dart | 28 +- lib/models/system_color_scheme.dart | 30 - lib/models/traffic.dart | 112 - lib/models/version.dart | 16 - lib/pages/home.dart | 125 +- lib/plugins/app.dart | 9 +- lib/plugins/service.dart | 4 +- lib/plugins/vpn.dart | 25 +- lib/state.dart | 127 +- .../{pop_container.dart => back_scope.dart} | 8 +- lib/widgets/builder.dart | 44 + .../{keep_container.dart => keep_scope.dart} | 8 +- lib/widgets/media_container.dart | 35 - lib/widgets/tray_container.dart | 72 - lib/widgets/widgets.dart | 12 +- linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugin_registrant.h | 0 linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 4 + plugins/flutter_distributor | 2 +- pubspec.lock | 66 +- pubspec.yaml | 5 +- setup.dart | 3 + .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugin_registrant.h | 0 windows/flutter/generated_plugins.cmake | 1 + 125 files changed, 5898 insertions(+), 4435 deletions(-) create mode 100644 android/app/src/main/kotlin/com/follow/clash/models/Dns.kt create mode 100644 assets/images/icon_black.ico create mode 100644 assets/images/icon_black.png create mode 100644 assets/images/icon_white.ico rename assets/images/{icon_monochrome.png => icon_white.png} (100%) create mode 100644 core/dns.go delete mode 100644 core/tun/dns.go delete mode 100644 core/tun/tcp.go delete mode 100644 core/tun/udp.go create mode 100644 lib/common/keyboard.dart mode change 100644 => 100755 lib/common/window.dart create mode 100644 lib/fragments/hotkey.dart rename lib/{widgets/android_container.dart => manager/android_manager.dart} (68%) rename lib/{widgets/app_state_container.dart => manager/app_state_manager.dart} (57%) rename lib/{widgets/clash_container.dart => manager/clash_manager.dart} (88%) create mode 100644 lib/manager/hotkey_manager.dart create mode 100644 lib/manager/manager.dart create mode 100644 lib/manager/media_manager.dart rename lib/{widgets/proxy_container.dart => manager/proxy_manager.dart} (89%) rename lib/{widgets/tile_container.dart => manager/tile_manager.dart} (76%) create mode 100755 lib/manager/tray_manager.dart rename lib/{widgets/vpn_container.dart => manager/vpn_manager.dart} (84%) rename lib/{widgets/window_container.dart => manager/window_manager.dart} (85%) create mode 100644 lib/models/common.dart delete mode 100644 lib/models/connection.dart delete mode 100644 lib/models/dav.dart delete mode 100644 lib/models/file.dart create mode 100644 lib/models/generated/common.freezed.dart create mode 100644 lib/models/generated/common.g.dart delete mode 100644 lib/models/generated/connection.freezed.dart delete mode 100644 lib/models/generated/connection.g.dart delete mode 100644 lib/models/generated/dav.freezed.dart delete mode 100644 lib/models/generated/dav.g.dart delete mode 100644 lib/models/generated/file.freezed.dart delete mode 100644 lib/models/generated/log.freezed.dart delete mode 100644 lib/models/generated/log.g.dart delete mode 100644 lib/models/generated/navigation.freezed.dart delete mode 100644 lib/models/generated/package.freezed.dart delete mode 100644 lib/models/generated/package.g.dart delete mode 100644 lib/models/generated/proxy.freezed.dart delete mode 100644 lib/models/generated/proxy.g.dart delete mode 100644 lib/models/generated/version.freezed.dart delete mode 100644 lib/models/generated/version.g.dart delete mode 100644 lib/models/ip.dart delete mode 100644 lib/models/log.dart delete mode 100644 lib/models/navigation.dart delete mode 100644 lib/models/package.dart delete mode 100644 lib/models/proxy.dart delete mode 100644 lib/models/system_color_scheme.dart delete mode 100644 lib/models/traffic.dart delete mode 100644 lib/models/version.dart rename lib/widgets/{pop_container.dart => back_scope.dart} (73%) rename lib/widgets/{keep_container.dart => keep_scope.dart} (66%) delete mode 100644 lib/widgets/media_container.dart delete mode 100644 lib/widgets/tray_container.dart mode change 100644 => 100755 linux/flutter/generated_plugin_registrant.cc mode change 100644 => 100755 linux/flutter/generated_plugin_registrant.h mode change 100644 => 100755 linux/flutter/generated_plugins.cmake mode change 100644 => 100755 macos/Flutter/GeneratedPluginRegistrant.swift mode change 100644 => 100755 pubspec.lock mode change 100644 => 100755 pubspec.yaml mode change 100644 => 100755 setup.dart mode change 100644 => 100755 windows/flutter/generated_plugin_registrant.cc mode change 100644 => 100755 windows/flutter/generated_plugin_registrant.h mode change 100644 => 100755 windows/flutter/generated_plugins.cmake diff --git a/.gitmodules b/.gitmodules index ecedb42..cc523a9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "core/Clash.Meta"] path = core/Clash.Meta url = git@github.com:chen08209/Clash.Meta.git - branch = FlClash + branch = FlClash-Alpha [submodule "plugins/flutter_distributor"] path = plugins/flutter_distributor url = git@github.com:chen08209/flutter_distributor.git diff --git a/android/app/src/main/kotlin/com/follow/clash/BaseServiceInterface.kt b/android/app/src/main/kotlin/com/follow/clash/BaseServiceInterface.kt index f616424..85176e7 100644 --- a/android/app/src/main/kotlin/com/follow/clash/BaseServiceInterface.kt +++ b/android/app/src/main/kotlin/com/follow/clash/BaseServiceInterface.kt @@ -1,9 +1,10 @@ package com.follow.clash import com.follow.clash.models.Props +import com.follow.clash.models.TunProps interface BaseServiceInterface { - fun start(port: Int, props: Props?): Int? + fun start(port: Int, props: Props?): TunProps? fun stop() fun startForeground(title: String, content: String) } \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt b/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt index f1d815e..084a4ae 100644 --- a/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt +++ b/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt @@ -39,8 +39,7 @@ object GlobalState { } fun getCurrentVPNPlugin(): VpnPlugin? { - val currentEngine = if (serviceEngine != null) serviceEngine else flutterEngine - return currentEngine?.plugins?.get(VpnPlugin::class.java) as VpnPlugin? + return serviceEngine?.plugins?.get(VpnPlugin::class.java) as VpnPlugin? } fun destroyServiceEngine() { diff --git a/android/app/src/main/kotlin/com/follow/clash/extensions/Ext.kt b/android/app/src/main/kotlin/com/follow/clash/extensions/Ext.kt index cf607c1..5635249 100644 --- a/android/app/src/main/kotlin/com/follow/clash/extensions/Ext.kt +++ b/android/app/src/main/kotlin/com/follow/clash/extensions/Ext.kt @@ -1,28 +1,20 @@ package com.follow.clash.extensions -import android.annotation.SuppressLint -import android.app.Notification.FOREGROUND_SERVICE_IMMEDIATE -import android.app.NotificationChannel -import android.app.NotificationManager -import android.app.PendingIntent -import android.app.Service -import android.content.Context -import android.content.Intent -import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE import android.graphics.Bitmap import android.graphics.drawable.Drawable -import android.os.Build +import android.net.ConnectivityManager +import android.net.Network import android.system.OsConstants.IPPROTO_TCP import android.system.OsConstants.IPPROTO_UDP import android.util.Base64 -import androidx.core.app.NotificationCompat import androidx.core.graphics.drawable.toBitmap -import com.follow.clash.MainActivity -import com.follow.clash.R import com.follow.clash.models.Metadata import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.io.ByteArrayOutputStream +import java.net.Inet4Address +import java.net.Inet6Address +import java.net.InetAddress suspend fun Drawable.getBase64(): String { @@ -41,6 +33,37 @@ fun Metadata.getProtocol(): Int? { return null } -private val CHANNEL = "FlClash" -private val notificationId: Int = 1 +fun ConnectivityManager.resolvePrimaryDns(network: Network?): String? { + val properties = getLinkProperties(network) ?: return null + return properties.dnsServers.firstOrNull()?.asSocketAddressText(53) +} + +fun InetAddress.asSocketAddressText(port: Int): String { + return when (this) { + is Inet6Address -> + "[${numericToTextFormat(this.address)}]:$port" + + is Inet4Address -> + "${this.hostAddress}:$port" + + else -> throw IllegalArgumentException("Unsupported Inet type ${this.javaClass}") + } +} + + +private fun numericToTextFormat(src: ByteArray): String { + val sb = StringBuilder(39) + for (i in 0 until 8) { + sb.append( + Integer.toHexString( + src[i shl 1].toInt() shl 8 and 0xff00 + or (src[(i shl 1) + 1].toInt() and 0xff) + ) + ) + if (i < 7) { + sb.append(":") + } + } + return sb.toString() +} diff --git a/android/app/src/main/kotlin/com/follow/clash/models/Dns.kt b/android/app/src/main/kotlin/com/follow/clash/models/Dns.kt new file mode 100644 index 0000000..0548c2f --- /dev/null +++ b/android/app/src/main/kotlin/com/follow/clash/models/Dns.kt @@ -0,0 +1,26 @@ +package com.follow.clash.models + +import android.net.NetworkCapabilities +import android.os.Build + +val TRANSPORT_PRIORITY = sequence { + yield(NetworkCapabilities.TRANSPORT_CELLULAR) + + if (Build.VERSION.SDK_INT >= 27) { + yield(NetworkCapabilities.TRANSPORT_LOWPAN) + } + + yield(NetworkCapabilities.TRANSPORT_BLUETOOTH) + + if (Build.VERSION.SDK_INT >= 26) { + yield(NetworkCapabilities.TRANSPORT_WIFI_AWARE) + } + + yield(NetworkCapabilities.TRANSPORT_WIFI) + + if (Build.VERSION.SDK_INT >= 31) { + yield(NetworkCapabilities.TRANSPORT_USB) + } + + yield(NetworkCapabilities.TRANSPORT_ETHERNET) +}.toList() \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/follow/clash/models/Package.kt b/android/app/src/main/kotlin/com/follow/clash/models/Package.kt index 7240c3b..dbacf0f 100644 --- a/android/app/src/main/kotlin/com/follow/clash/models/Package.kt +++ b/android/app/src/main/kotlin/com/follow/clash/models/Package.kt @@ -1,7 +1,5 @@ package com.follow.clash.models -import java.util.Date - data class Package( val packageName: String, val label: String, 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 082483f..7e7784f 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 @@ -17,3 +17,13 @@ data class Props( val allowBypass: Boolean?, val systemProxy: Boolean?, ) + +data class TunProps( + val fd: Int, + val gateway: String, + val gateway6: String, + val portal: String, + val portal6: String, + val dns: String, + val dns6: String +) \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/follow/clash/plugins/AppPlugin.kt b/android/app/src/main/kotlin/com/follow/clash/plugins/AppPlugin.kt index 5ff83cb..b866c84 100644 --- a/android/app/src/main/kotlin/com/follow/clash/plugins/AppPlugin.kt +++ b/android/app/src/main/kotlin/com/follow/clash/plugins/AppPlugin.kt @@ -8,7 +8,6 @@ import android.content.Intent import android.content.pm.ApplicationInfo import android.content.pm.ComponentInfo import android.content.pm.PackageManager -import android.net.ConnectivityManager import android.net.VpnService import android.os.Build import android.widget.Toast @@ -17,12 +16,9 @@ import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat.getSystemService import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile import androidx.core.content.FileProvider -import androidx.core.content.getSystemService import com.follow.clash.GlobalState import com.follow.clash.extensions.getBase64 -import com.follow.clash.extensions.getProtocol import com.follow.clash.models.Package -import com.follow.clash.models.Process import com.google.gson.Gson import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.plugins.FlutterPlugin @@ -37,7 +33,6 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File -import java.net.InetSocketAddress import java.util.zip.ZipFile class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware { @@ -52,11 +47,10 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware private lateinit var scope: CoroutineScope - private var connectivity: ConnectivityManager? = null - private var vpnCallBack: (() -> Unit)? = null private val iconMap = mutableMapOf() + private val packages = mutableListOf() private val skipPrefixList = listOf( @@ -114,7 +108,6 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware ("(" + chinaAppPrefixList.joinToString("|").replace(".", "\\.") + ").*").toRegex() } - val VPN_PERMISSION_REQUEST_CODE = 1001 val NOTIFICATION_PERMISSION_REQUEST_CODE = 1002 @@ -191,48 +184,6 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware } } - "resolverProcess" -> { - val data = call.argument("data") - val process = - if (data != null) Gson().fromJson( - data, - Process::class.java - ) else null - val metadata = process?.metadata - val protocol = metadata?.getProtocol() - if (protocol == null) { - result.success(null) - return - } - scope.launch { - withContext(Dispatchers.Default) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - result.success(null) - return@withContext - } - if (connectivity == null) { - connectivity = context.getSystemService() - } - val src = InetSocketAddress(metadata.sourceIP, metadata.sourcePort) - val dst = InetSocketAddress( - metadata.destinationIP.ifEmpty { metadata.host }, - metadata.destinationPort - ) - val uid = try { - connectivity?.getConnectionOwnerUid(protocol, src, dst) - } catch (_: Exception) { - null - } - if (uid == null || uid == -1) { - result.success(null) - return@withContext - } - val packages = context.packageManager?.getPackagesForUid(uid) - result.success(packages?.first()) - } - } - } - "tip" -> { val message = call.argument("message") tip(message) @@ -379,7 +330,6 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware } } - private fun isChinaPackage(packageName: String): Boolean { val packageManager = context.packageManager ?: return false skipPrefixList.forEach { @@ -447,10 +397,6 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware return false } - fun requestGc() { - channel.invokeMethod("gc", null) - } - override fun onAttachedToActivity(binding: ActivityPluginBinding) { activity = binding.activity; binding.addActivityResultListener(::onActivityResult) @@ -490,4 +436,4 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware } return true } -} \ No newline at end of file +} diff --git a/android/app/src/main/kotlin/com/follow/clash/plugins/ServicePlugin.kt b/android/app/src/main/kotlin/com/follow/clash/plugins/ServicePlugin.kt index 2e0c8eb..fc2c9be 100644 --- a/android/app/src/main/kotlin/com/follow/clash/plugins/ServicePlugin.kt +++ b/android/app/src/main/kotlin/com/follow/clash/plugins/ServicePlugin.kt @@ -1,6 +1,8 @@ package com.follow.clash.plugins import android.content.Context +import android.net.ConnectivityManager +import androidx.core.content.getSystemService import com.follow.clash.GlobalState import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.plugin.common.MethodCall 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 4d60bde..b1a0120 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 @@ -5,19 +5,33 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.ServiceConnection +import android.net.ConnectivityManager +import android.net.Network +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.BaseServiceInterface import com.follow.clash.GlobalState import com.follow.clash.RunState +import com.follow.clash.extensions.getProtocol +import com.follow.clash.extensions.resolvePrimaryDns import com.follow.clash.models.Props +import com.follow.clash.models.TunProps import com.follow.clash.services.FlClashService import com.follow.clash.services.FlClashVpnService import com.google.gson.Gson import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.net.InetSocketAddress import kotlin.concurrent.withLock +import com.follow.clash.models.Process class VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler { @@ -26,6 +40,11 @@ class VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler { private var flClashService: BaseServiceInterface? = null private var port: Int = 7890 private var props: Props? = null + private lateinit var scope: CoroutineScope + + private val connectivity by lazy { + context.getSystemService() + } private val connection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { @@ -43,55 +62,104 @@ class VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler { } override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + scope = CoroutineScope(Dispatchers.Default) context = flutterPluginBinding.applicationContext + scope.launch { + registerNetworkCallback() + } flutterMethodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "vpn") flutterMethodChannel.setMethodCallHandler(this) } override fun onDetachedFromEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + unRegisterNetworkCallback() flutterMethodChannel.setMethodCallHandler(null) } - override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) = when (call.method) { - - "start" -> { - port = call.argument("port")!! - val args = call.argument("args") - props = - if (args != null) Gson().fromJson(args, Props::class.java) else null - when (props?.enable == true) { - true -> handleStartVpn() - false -> start() - } - result.success(true) - } - - "stop" -> { - stop() - result.success(true) - } - - "setProtect" -> { - val fd = call.argument("fd") - if (fd != null) { - if (flClashService is FlClashVpnService) { - (flClashService as FlClashVpnService).protect(fd) + override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { + when (call.method) { + "start" -> { + port = call.argument("port")!! + val args = call.argument("args") + props = + if (args != null) Gson().fromJson(args, Props::class.java) else null + when (props?.enable == true) { + true -> handleStartVpn() + false -> start() } result.success(true) - } else { - result.success(false) } - } - "startForeground" -> { - val title = call.argument("title") as String - val content = call.argument("content") as String - startForeground(title, content) - result.success(true) - } + "stop" -> { + stop() + result.success(true) + } - else -> { - result.notImplemented() + "setProtect" -> { + val fd = call.argument("fd") + if (fd != null) { + if (flClashService is FlClashVpnService) { + (flClashService as FlClashVpnService).protect(fd) + } + result.success(true) + } else { + result.success(false) + } + } + + "startForeground" -> { + val title = call.argument("title") as String + val content = call.argument("content") as String + startForeground(title, content) + result.success(true) + } + + "resolverProcess" -> { + val data = call.argument("data") + val process = + if (data != null) Gson().fromJson( + data, + Process::class.java + ) else null + val metadata = process?.metadata + if (metadata == null) { + result.success(null) + return + } + val protocol = metadata.getProtocol() + if (protocol == null) { + result.success(null) + return + } + scope.launch { + withContext(Dispatchers.Default) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + result.success(null) + return@withContext + } + val src = InetSocketAddress(metadata.sourceIP, metadata.sourcePort) + val dst = InetSocketAddress( + metadata.destinationIP.ifEmpty { metadata.host }, + metadata.destinationPort + ) + val uid = try { + connectivity?.getConnectionOwnerUid(protocol, src, dst) + } catch (_: Exception) { + null + } + if (uid == null || uid == -1) { + result.success(null) + return@withContext + } + val packages = context.packageManager?.getPackagesForUid(uid) + result.success(packages?.first()) + } + } + } + + else -> { + result.notImplemented() + } } } @@ -102,6 +170,62 @@ class VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler { } } + fun requestGc() { + flutterMethodChannel.invokeMethod("gc", null) + } + + val networks = mutableSetOf() + + fun onUpdateNetwork() { + val dns = networks.mapNotNull { + connectivity?.resolvePrimaryDns(it) + }.joinToString(separator = ",") + scope.launch { + withContext(Dispatchers.Main) { + flutterMethodChannel.invokeMethod("dnsChanged", dns) + } + } +// if (flClashService is FlClashVpnService) { +// val network = networks.maxByOrNull { net -> +// connectivity?.getNetworkCapabilities(net)?.let { cap -> +// TRANSPORT_PRIORITY.indexOfFirst { cap.hasTransport(it) } +// } ?: -1 +// } +// network?.let { +// (flClashService as FlClashVpnService).updateUnderlyingNetworks(arrayOf(network)) +// } +// } + } + + private val callback = object : ConnectivityManager.NetworkCallback() { + override fun onAvailable(network: Network) { + networks.add(network) + onUpdateNetwork() + } + + override fun onLost(network: Network) { + networks.remove(network) + onUpdateNetwork() + } + } + + private val request = NetworkRequest.Builder().apply { + addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + }.build() + + private fun registerNetworkCallback() { + networks.clear() + connectivity?.registerNetworkCallback(request, callback) + } + + private fun unRegisterNetworkCallback() { + connectivity?.unregisterNetworkCallback(callback) + networks.clear() + onUpdateNetwork() + } + @SuppressLint("ForegroundServiceType") private fun startForeground(title: String, content: String) { GlobalState.runLock.withLock { @@ -118,8 +242,11 @@ class VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler { GlobalState.runLock.withLock { if (GlobalState.runState.value == RunState.START) return GlobalState.runState.value = RunState.START - val fd = flClashService?.start(port, props) - flutterMethodChannel.invokeMethod("started", fd) + val tunProps = flClashService?.start(port, props) + flutterMethodChannel.invokeMethod( + "started", + Gson().toJson(tunProps, TunProps::class.java) + ) } } diff --git a/android/app/src/main/kotlin/com/follow/clash/services/FlClashService.kt b/android/app/src/main/kotlin/com/follow/clash/services/FlClashService.kt index 47e0492..481dc5a 100644 --- a/android/app/src/main/kotlin/com/follow/clash/services/FlClashService.kt +++ b/android/app/src/main/kotlin/com/follow/clash/services/FlClashService.kt @@ -73,7 +73,7 @@ class FlClashService : Service(), BaseServiceInterface { } } - override fun start(port: Int, props: Props?): Int? = null + override fun start(port: Int, props: Props?) = null override fun stop() { stopSelf() 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 4616b1b..8458138 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 @@ -7,6 +7,7 @@ import android.app.NotificationManager import android.app.PendingIntent import android.content.Intent import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE +import android.net.Network import android.net.ProxyInfo import android.net.VpnService import android.os.Binder @@ -22,6 +23,7 @@ import com.follow.clash.MainActivity import com.follow.clash.R import com.follow.clash.models.AccessControlMode import com.follow.clash.models.Props +import com.follow.clash.models.TunProps import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -30,36 +32,53 @@ import kotlinx.coroutines.launch @SuppressLint("WrongConstant") class FlClashVpnService : VpnService(), BaseServiceInterface { - private val passList = listOf( - "*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.*" - ) + companion object { + private val passList = listOf( + "*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.*" + ) + private const val TUN_MTU = 9000 + private const val TUN_SUBNET_PREFIX = 30 + private const val TUN_GATEWAY = "172.19.0.1" + private const val TUN_SUBNET_PREFIX6 = 126 + private const val TUN_GATEWAY6 = "fdfe:dcba:9876::1" + private const val TUN_PORTAL = "172.19.0.2" + private const val TUN_PORTAL6 = "fdfe:dcba:9876::2" + private const val TUN_DNS = TUN_PORTAL + private const val TUN_DNS6 = TUN_PORTAL6 + private const val NET_ANY = "0.0.0.0" + private const val NET_ANY6 = "::" + } override fun onCreate() { super.onCreate() GlobalState.initServiceEngine(applicationContext) } - override fun start(port: Int, props: Props?): Int? { + override fun start(port: Int, props: Props?): TunProps { return with(Builder()) { - addAddress("172.16.0.1", 30) - setMtu(9000) - addRoute("0.0.0.0", 0) + addAddress(TUN_GATEWAY, TUN_SUBNET_PREFIX) + addAddress(TUN_GATEWAY6, TUN_SUBNET_PREFIX6) + addRoute(NET_ANY, 0) + addRoute(NET_ANY6, 0) + addDnsServer(TUN_DNS) + addDnsServer(TUN_DNS6) + setMtu(TUN_MTU) props?.accessControl?.let { accessControl -> when (accessControl.mode) { AccessControlMode.acceptSelected -> { @@ -75,7 +94,6 @@ class FlClashVpnService : VpnService(), BaseServiceInterface { } } } - addDnsServer("172.16.0.2") setSession("FlClash") setBlocking(false) if (Build.VERSION.SDK_INT >= 29) { @@ -93,10 +111,24 @@ class FlClashVpnService : VpnService(), BaseServiceInterface { ) ) } - establish()?.detachFd() + TunProps( + fd = establish()?.detachFd() + ?: throw NullPointerException("Establish VPN rejected by system"), + gateway = "$TUN_GATEWAY/$TUN_SUBNET_PREFIX", + gateway6 = "$TUN_GATEWAY6/$TUN_SUBNET_PREFIX6", + portal = TUN_PORTAL, + portal6 = TUN_PORTAL6, + dns = TUN_DNS, + dns6 = TUN_DNS6 + ) } } + fun updateUnderlyingNetworks( networks: Array){ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { + this.setUnderlyingNetworks(networks) + } + } override fun stop() { stopSelf() @@ -165,7 +197,7 @@ class FlClashVpnService : VpnService(), BaseServiceInterface { override fun onTrimMemory(level: Int) { super.onTrimMemory(level) - GlobalState.getCurrentAppPlugin()?.requestGc() + GlobalState.getCurrentVPNPlugin()?.requestGc() } private val binder = LocalBinder() diff --git a/assets/images/icon_black.ico b/assets/images/icon_black.ico new file mode 100644 index 0000000000000000000000000000000000000000..76cb61ce0360149e1b40489132f3249bafe08014 GIT binary patch literal 3939 zcmV-p51jA-00962000000096X08I}702TlM0EtjeM-2)Z3IG5A4M|8uQUCw}00001 z00;yC008!TVC?_^00D1uPE-NUqIa4A01pRAL_t(|+U=crn9k)I$3HXE%rM3}DTELu zyO1TNv^hc{tx_pkEGJwjN+KMjjgmG=B1aoX2ua!yEmTsLlBKZ^hB3^X=RI?st5c`) zd*9#oJkNW7?#tEHU*-8e@9$ae=lbrWIFm1((o(s$`HL17kmBmD~^V zCac)aK@M|7MK=4`#79h~rv))IGHkX`he?jb|24i*UxE@cc&2k2gV-3g_yuuP?G+lx5SmL-I-ofGYS*jiEph})66f{3ng}EFo7r`SaD3JXPfJmqZ#fjVuktkHin0E)w}k6-My0rs7B9d&-MQeo>0M zSfjD{vIO`@Dy>-%SZX)+SV1un%WD#-&-3inUi?VBO(7A?TPiSw%|?hHiO1z4$V-ZG zGb=+$?Zy_z<%zg=By$O~Ic$vhk=RW$5zZTGGJ#!2i64oNBM~$jQurJ1kYkDbKhs7ejfQ$WYe;I>No=8mNa~#O4362FQO8(MI}z0>#kh$T zhFx48q@qsVajA6wN9^p(8*4ZU*Gp74!%@}+fWG2l?5^0@KmCPvG-XVl@DkgXZL zjU49FTAcr#QI7lAVAXN&OS)51gmpqXH}a`fsokxNpo$3Vgd|$~1u(W=z$XWS}2{>})m>z-fnqngeYMOY^!tB>Ry ztLk_5sfFwuN$onLR_I;#yp5y0tG2O{+I2)(ExPV`8Ed$cQX;Gq(z(u9YsNp0ZTy2X zL|7;2)^*Q|)b6V^mDH{?&NAGZ@%M3zrF4?MeaDS|oh&AJTR;6|` zd7QIFSZ6e3ss+}JzeYB1a-pPlosq!+t1fwuvz*Qp6=9uGkAGQZ*RX+m#iz%4ey=TS zElcgz5m}wff4xP94M&*E7af$-jxglG^o>iUu`f-ovxh_2h3|lqzcJyIE}^hcSwWxt}{|M;%JX z-(j+WAv=H^=5e_PRl6BnszhJFX0m?cR(_0ZGS%Yp0$r#UPrHjNjIeM0f^HsIGghNN z%T8!vlgmc+rMV8W+GR~9dGuIu`p zQryW`Fhrwo zP3}(m*z6E`lZKspyy?1Efgx(I?@dX`NPD-0tu=G{IK&JOy6zQMXZ)2OE^axDvbC7B zo<`kzkMpqyUH6h{$!yQ3^%3r~^OEQ^ZJvVuz(5bW?$z|I0reiPv2g;VsPk_4;ztf# zwOs#Q$})iOeJw1vvc{;N2G)%3yY3ZHi^oU4S2Vt2<7Tj_`nZKxzq3MZ*W6k&Mht9b z24Y~7O=tTiKv5QimfH2A>)x5_&={P7%`!^cHwEqr;WB71&wJ2yuQa^^e$alD+wGeG zl>+YKouj@v?z`?4;wqMekjh$YqnmL505bw#d0@?$KqFob$-rix+Ok?l1wIR8@U}A2 zgRXm(c$h6Ao?FJ*SbBQB@4bGqm_`%VnYEH?4gNgjgX^a@n#&gASzqgSme9fVZF-8@ zIn2}G1=CJ7ku9XMI^y^_%8Ht>yzCQ;wFIHI=AMGZRXviqmI(Su|$(u_2 z4A=j~s*Ewhs&-a9^%kv2Cnl+FPbRs)OBo&KkXk5aGk|kFcsYMEJ&m!celp&=4JA^V z`dm#P#;VEiB9nQ7q1;9b^_%tLKvamfEHbD!NiPJ?NKgySWcC|mQjx`_BAZv7&ahBZ zyRp3vmL9{NP=c;THlUs&JqX;BLMz@e!kps&Uj=p%`P@>QiJGK#qmMPR0J!5c1{rKk zo6m5OFm}?pflrNYK)peIy@Z&Eq;_97ya9C{4~menaW+qoX|(tSX<%9ZW8f6}sIzmv z@v)byM9gSOqZ1!k(SZ6GBjx-bEp?fyeQMWfyy}5fWn58&o<6)X4lCwKAHwJ;$3!FV z`TjWOdQi|7SDdAOF}8@GtClg@`$t6$mRKYIE_L!RA(BQzB^FyEejdwcEsbfSqa@QT zk$*EoJg9AmGZJ|~>*w6gO&}(7jx?Z-o{IytYw|DOzmT@B4Q%3)3^jD7%O5eY$q*@H zqq~OA!rALkQppr{Dv73BkV8+I2P86*v;y`>3z z4H17g6YcE#5iVC5kpak2CzZ?PU7sKH(7wbok5$|znSH+)thxMK7$&cJ{Ny2x#ox~q z8cAx`UxsV@o^KIX+U)A73j?*3e=WUSH=q_A(M`Ke;5NokO@s-GHdFym@n+-} zF7>r}3U-WTbduC=(3Apfg3>W;Th`6!0STsK%a%?FppO8#P2yB$cqaZKX3|`$c1@!!FL>}m;20lqT|D&Yw2@*A zby+O3p8jIeWHQOLXJyQ(-3io`AvB-LjE=e~+yQ3MQtEeXA(4hW#YTtcg1x*&J6ZK@ zBZ=y2J%5+&e{n;Q#cIaVf^-=!TS=!rT^Y{;R5ClOG1VK0n5UhaCxzlF4$$(OO(VY@`G?Fo#`^>>)m)w|IitL?Jq|fWuLF z0e{Y&l#-#dfwOrori!DZ%%i#N3Ct#u_N;Yf5ZPNQ3CyK1eO0#IWP92nWUTZ8HHj

A8929Wtz@P?gm_l$ZWU zV;Nc#NM)i=1?F#1Oomr~TKU$0=m=e9cy*^JZ~N#l@-e5%5bI5AUyY`6=`KU8Gbv2* z*;rVhf5X|mw3K1im+rp!3;i}m$}sCnGSdU_8C)uhfUcAYqyzCb>d8>+Ni#=J zzTC!9I?7P%$+ZFO03tC!hFVYh1Y|Y+l$g!x$>@M4z;r1j(UAn63}^zpBYg&RB$1~B zngH`<0_gb#cp{()Fh@-2^yDGg1H?DI0-6Bhq+CQ#+IjX4_^+dn47HxrXImg$M%&6z z>q!PH0+;}ssV+mU>p^fr025$=coFN%wdD9d0S3x2>q`aS6T+EN9iaDR&={X5z$_^j z*PBLc_4NeMNrqT&PGY=|6JQ=CWQg^@4cO#c<5{@@FoM41`Z56~QAh^Y1WGZ-2l-c1 zRfg6S>bbIp`s4Pq^7%K4c1kiY?IG@#44`Q@0$p4?g#Froc(546m^cM)@#HIz#XynY z)G5%GZ(Pd1g>Lc!&}15@6G7~U!evqmY(5$46TUeH@wYRQ@-lpOECqELAJuE2T}+`l zNiuZya1xEwFM7=hUk&E+9TT`fwtaR|fet*y$806%H-)5m>fd*;l1bc16{-BQeL*Nm xZCb0{{Se0R7~|AGd(cKL6Q$*{M-YT~ literal 0 HcmV?d00001 diff --git a/assets/images/icon_black.png b/assets/images/icon_black.png new file mode 100644 index 0000000000000000000000000000000000000000..910ad69fc0beb40af1ada606f615510f65cd56bf GIT binary patch literal 13452 zcmch82|U!@_x~)G?1{+E7=(;{43Ww-F#T^m=CQ+=-{I;YCM++E zKp?~*qAdx5Kxy*+t`Ptufj!&o!T*Hl#Jy1n1Wujz7a4!iIu?NtI7Rc=6TQd9*@6-g zhV%80@T215!{}f(0%2(#PxqySP@`4-sDZR_E6k^+R*Wjm-wLza)WyJsZbJ>C5fdY+ zI}=?!D2X8ybAOEW7FEl53qT-@8ttnZ9~K%OWf51O+jtwQ z?s3_nY7-GjRW-*M>QM{~j8x6calUw8ys}}?@QM=#2N5p zTAk=m`DY$ICNgw&bAO6HHIy1g4Udija}EEQOAm^Oj))41_)kdx^Yg#k0O;1m<)1zN zLtetd{@Efb+AbD|@mnGP;p`}n1UglpM2(7wiKI~NVgZ}#JZb0_Hjz}{=!i& zuc;-WZC7)unYpilxse{# zk6@%1U}j>Z=S!d(>f!O`W_WW`g1M==+27RMB5A*fQ1tvL zroMXS1QWcTufHil&%l^~H!<@wH1_xRwm_h}{}x>O{~7a9 zzOnx`>&E`RriQ*I{(45H{)T#{W+ujZe$)Vho*~dB)x;lfLZDFp7X4pY{|~|VKV#h# zXa28t@oNz!$TvKY3OuJi=Kn#M{}C>KZTSCD7=50<{Dm<6{~dg*zx|7E1qZo01ROT+ z<3Cpg`0~$XLk$OdiUe0l@>GWz0-;w5*>3ZQFa7v3p~i=r{Aunx6v@gxYH$=H{-J8K z0VSX2yKWn1M`+^5tMSdvI?w9}9{hUGs=RF5gb%N|VmEYc*L5X~pN7X)0lW4M6A8+H zSYr9soNO z*=4s-@#698ibO0$yJnu;Lxp%g94I2Pm0oVlK4179!piD3maU@Ro8@A!e)F6e6y&zESt-pv9l`}@pD*6r-#W_YBLj-oYb(o z{aH*IVjXr-t!hXM7w^n#NF-jDa}PG3b+G?xd= zipqYO&(todfl?yNWTP=L;*70N-!$t4(bx@4K*S2*v{tqs=&(%NKj_5jD{x_afmE(# zv@l+n$Gthc2V(WpHqfPK*Uia(^!lto4l+KX4v}2NHDBI$@VOGzMRUo_!9sfnkVVka zL-Tj@C>5H?4i@(L;0CTVS!hl+0DS}9^wo?EhI-d>rPyEEd@{SI8Zv5pGQqMUff45= z{()EEfseNS-`$l?eh1tia z+sVd#yLyUO-=Ie*EQ?at0<8@*rB^UjcSnGXvIe^23< zd6esCYvP}|4-b5WNR(l;G4mSp@%`G3uYBx*1#~_O;!1OrWqRW#FInyt4m~;a$HN<} z`B)o<8>$txQdCoIoA_)8XJ7vQa*;}Pm2o0x>J@qfv9xvoQ!i8a!nc>7$eIe%%^-@&hdAB|MBDMACU(Q#SL!E^KD40szaijzCGE1hx@$Ahozz+qCiHl>Z)CR5U z#m74|>&exIc^*_L;_xG%BQEKFnGdSWgvaj}c-U1i-w;C}dx002u&s-+*}~ikMaYxG zpR|D>QnbMtaSM5fFMD(NZvcG=D1je$Q7vk;8x0iHWWSZ+Cf~0mqNx;;>UYCD=}LtKMY?dy;Q8QvLYb&jwz4EyAci#6f~N4p z`^a>zz?+0nN8xe6@!2|c1Cjc5CF?v#N8Y2R+JTPG-d3Yy=%NOgnst=~H+$I~Wh5Qe2Yp9`$7b|dm|6V43z8F)(e!Zdp_I^c+R>Z z;-tgb$c^Xnk^SjdDw<qoj;B)<9Fq62M1uc*Lku1nL_We zzAT_4u{Kf8bn7tx3pKkY#S&KCta~;b;EckdarZCTqUs5ajK)9V0 z9XKVih!&)xq<5N!pBw5E-!7o#-M~WS(TXCaYckhV+vzlY^4rPbS?v#bRFdd|3{9;J zUeN=&+?NWGO5;Fh*s}R_O}4)yU5Qk<#0OZ7YPaot63_hv8EdTkb-MWOh5?~?oyOco z-uQ!!ToE<|n`*EGCN_mSTKutDvvMT>@eVo6_d?C{c?Nv9|3C%~D;N&xKYt<3wcy}C z54WAdcnRf7$Ajs??+^>PKZ`(pl79fs6>RTr|KBs>t!m%6B%y4 zJ2~!nO_G(f7LeGyac!l2i@=Dyw{3V*fx73gD|?Xr8h9MjDBYV9w0>Kqw_gG)i}9La zS;-Q34N|X6{D)$}FJC{%<5GwDL;o+dmY!y&W!(n#=(lPf`7Q}BJidG|K zofTf%)Rjtmw0I(LHUb1W18UqEyvo-4o=!La-jf>-%>3!yJ82QXr1GK`O#=*Knb+PtsYB4V&4{WXx4PfR%|4c8k^BE#RQfH1ZSV>kS*%)}98oyga3pKl13M;%q*OabNL}#w4vh94f zojc4ngKnUlNT-hHZu$JxaxU&<``e=RaE^C)b{}7$vq#`3^^Xpps|SqWP;aN=i}%#) zM4^+W=b}&aJ1xB|H#DEn<~Uz8Yn3tPZ3eDSQ4iI_*MpD&9t-kqBwkx8 zQ(bZGEmC~ulsFs~0&k0KxAnZMMSIb|48%2x(FOkT>-`ua=}KH~Y^K+?UzGQ9dLG;4 z0!i~*D(7_Ov;ruRT}GTu<9o2$QN|31G;2d}Z~@3qwk#tvq58~){M&{N6DiyrAb6N_ zvC)j$N?WLN_8Eu7XbW)o0|uP(M%i@UB1$4Ljo*d-f1jc=ix?U8p0x<}Ok&H(dN&nw}kNEK^-C)Z2Aw zz80JXmGejc1tO`v5z>0V{|hcph-Ul>s-8t5&K^f6VW~0PDppTMQ|La?Y8*1~C`WEd z&HAtlfze1R^KDs^geX}D$qlE?PrWAn0_zv(23Nv?WrROkleLubi>xlOL^}MW$Ifa) z_dDXK9%QTp55N&j3Zv=pbS}I@3W^KrA)*|BM}%o%jmqOKJZ_6^hH~Cs0vFxJ848A>2Yf}q zsvczs>xz!Mq{Eq24*P6A%g;S~0ibIKn_{Qcg=XDddjfKmheH*3uEL3_kIHe7#T0_r z;PaPo?!Mn@M1N9$smSvd{REEagUVUi34!-yI9EKR97*y*S=AE00D_Lw8O71 z<=5qnn%0YJ@7|qPm)B}mFAfRUs?&VE=g*b{{B7grS}67J%ENEwK^`P4;CrjDKK#|mw}YVD@s3~ z*_OB**Tl7ey}TV84dXX8u7yt47}L#HJw)+e4B&%S&Fp~d>Qdtz6B{Gos#eYH^r~(C zGP7;KI+f~67NqU~?dXurfSGO1{m0BOz|1P)B;Cu#?T8MP7D^o;BC=-f0)EzobB)b% z>}-dZ0}wwEnK?My&K>%*##{pT7>T!&~8Ng_0^)!umriWu(7#@Uj-j07~q zd&6!QMnM!R{hG!ll2w4kbRKMn!8P#{rKk+>aKVgW%(%mN2<$jGFAF*ti&~K?lJ+`L zP*TXY1A&$sxS(jcNd-GWwxMzpTq_^(Tm)Ag0Hu~pF(P=gY3v)bx-d!0N-$|%k+7Ev zIEKRQvUKG+1$(*tou~3z^v1IoJma9b$j(}EqX3HK8l(vV@g@K*Vg3{&x()NE;F28( zXmHAi7Ev!5?=<*ZRMum5G}0PGUsFdD*zcH+!G?nyWW2XNOj24H?X@GC-c?+Xq^|>) zwI0i&%fY;RGipJ?GJv$%+h(6bWE@?IbvQmRtmgo@e6Ij=DNf{D*vx$gHa|(Fa0d9u z;x|DoLlSEiNJ0}%%`>*F5WF#lJu~OFM!pb*CkeMN3vVk`0gVflbk`R0Bj03DS?|42k`ZL?9_Zj zoG^%wu1)00)VV$cK2ikGep$y}W~YIvCnu3Tg02DwctnmhwEM>dl6PXn`aD4p^4(4r zQ@IExQvGBW zcmy=FpE4*+S)SxOdy25B=`QJgWuvTDbq%`UyiDI^LW$HxUvd-RU|pgxA$=a)-@%&$ zow*1guxT^0l)qGb6G+ua_My&Pw+fM5M}G~vBuy!O_>t38{fNqVG|~+r1@ehbvN*Wu zvVcSH+%vPE^XZsN`uwI@8aV>Q2mDW#-LrEJ7Tlq-C5RdOeL$?mLMY@vC>O~+yrf7t zH@|Tw%TfKEsb&R}f1p%bKQ6aF&r4zdacq@$Pl)p+zn$etU0SBtL%usPm2HtN2A`C? z8GT4A_7C=M$oQzvtF@fiWtMPm6vard5mDJ)jp=5MD0n#(RtbI(cAohw26I!$U`DSs zJO0ThALpUmYT5X6HOB*SG{Kh*u)fi#*rrd!uO$BQd+q)>1GUCAm14hvOXLqjD+()$ z-pi=bo&WRjPlXJ|e&!(C1>Rj#roYgt=DDjn3o@JRx%6HtTbhQXiTsFST)a@|(Lv`f z!vSv%$fT`e&FpTrJ~M;afeOx*4&BV@A8zkc(8U zaq+cA;ZtT?SyHAprWO5dYxf=r!n*qGg@YlQPDHVHeX)w7(D-MeF*l2LQBAkJ73Ft} zgjiL3gb&|2^^}o)-7aiN!Yfi(^05V}EW;{)waHJPhtgq3hd`xVJV_$_o^&AsQ(n3A2ur}@2Gl~z&DUOdtwI(R#}^BWEkMRSGZIp z(=JO?Fk9e&M#>20nN6atRTBNgPEvu2WGcomAnc6YP@qHBvfS4L4jjku`$|=w2OC@^ zZ=~V2?t9=3hy5AI?J3LpAnGOV#TTmJfU+W#ozBOY1Jw*|OEctXixso>h<%~tTk;*#_BAg>!v8tbTXoaApgUUC~M zoQ1~RkS{fyo)Ta?MB0AE8iEgf7kAWqd}rCCEoi-G);(>GIET5hSa zebC^T!()0LcZ;XNJ%@@H@{d+V1mp)y^zCsSeso%`EHr!%HfD(0R;KE_{8@T3qpn4$ zcOagVNz$Ktb84py`jDyN7E+qmcSB|k$493V!xiOB_{g$wh<#1&Y$5hC+>8$$vk1Y? zijbeZ-;S-CdDAx9P?YE|b5krB&Y0iDk!s6111dkh%VI@v&(OIAsUwxK6NtYq1UU1D ztEO~yP5nqrJ)&9pMHz&a0nyT|>-(~OriqSI^}Y2E z;7Mx<#EA-!iKnsS0=YRosBiC-Mqgz@kPWO}}nQ(58OXqX;%oVv$f-{(uF6UbfDCpv> z(wN&CO`JqNer2`hm9Ap^tmU2r^g333#h+|Zc8skJ>oq=a?S(1heshcOEU<-#n@AJ+ z>)AOBy&dYH`h|QdX&rtk>YxLql22RT3!D@Vyg z`Inh)+|!{Yx7JUJJZ=WcN`H(Y+hC8CxB|wdQx97y?NKqktxQMFTFku(82ciJE&L-Q z-CC{4&q!oI#*`v3OPHesbmp5Ab&f6b#_x~s;x>nfU+)hVp47{HZ)iN8`Pbr=H^*&d zcWi%ww$8$B*E=JqXtS?oQa5K=!C{f~S%uhLUxQc4#BC)RiN~K?Xj=cw>r@`@w!-x= zgWBS7ZV(v>w(cw&RjV{vI__#3sd4j(Mf;9xCE_Da;3TH}7_w<9W;>Thj>8=D^o4wzo(6$|iq{*3xT;*&v5u}jEhmOAQKt~M z)OW~sf;F@Be1H$&eZJ^SV!%3LcWHHEWA|pI#IrS7R7YE4>>45t>g&(qYFUKFjS(P(|<$^PAmliMUe%h#X1l0L@R9N8rwZB9m^p z~hW+>OzOk5U=L?vcIQWClr`|A?9F?*CjHHZ)=0=v`MVw zHr0fs^UevbmFm^Xz3neY$KQOdnoYy;oR%(7wPDDU4OmZ3I2_?*TV`7xrEzmwHHV73 zg#NzPI-q_2v?THB^>9vjskv*1_0c9C2ArU?@myg_rNB4-830yJ`aM+AnZAO` zR0Y)Kd>LtbK(^c8oE1#jFuRwVFy@B)_=vGa{jAY6YWz;HT?a^90 z%3N-P2r!_@J5R8(U7T-*_bW|9U$wHXj<2V@F~Vma@iS8ly3?L7Uw>e%qo-(>u^?1y zCchv`*Pqim8vs0;NX2l?>pgwF8#$==58HCi8XoDkBX-)$PR8_#Fn_d_F>K47JCrTc zcRe}ImL_9v#`tKW_UH9qzt=#WUrR=F7LO-HJa$TMDC^4{aoKnDTED1PvvA6$TU%i<3QbI$Nb zL>FK6AD3(sn)piA#T4a4!k+(@RCIF3-lGasKyjWnF-u|JB|htCktJ`^MsJWh2$b@X ze=3ZFOY$Y__(8!h()8T?>$VUO8~0B*03O}8bh?MzBYhCAe$QoASi8QjnH=^?F>_LS zSD`rWFF;qm=>p>U!DLym{9wDSdC~Tv+L)ib05|^Zd|2u33K92nUX*f+;luN#N#Y>L zy_0g-B^_lBh7zL`e(Yr40{MvN?V|Y$oejOmHu`|n`sF{x#ltNipE(TXHVz086bP2! zdM`hKNzT6CK@c97m-2jR4;nAE(4~^AF4_+ehS&!TJ9s`?!+O4O7JVBg*+#m-^lUm=A zhfq!+@_+TVLa}hK?Ce2sy#~-&C+{c{KwZ2Ll<+%)t+|Ti8z5(Fw2-OSXj}v7G|jPF zSu$^{OxkNSthefDzbLx0sgW2VP|ANDWKAA{t%6$+n=){=`xF$U3h#eoTO$PpUZ_2P zNnx9C#{r8mb1}Yl^5Uh=L$zPo10;CpkT^jU>{goLvz}^6H#9H>=^xq+Er^x?`MoKx z0`ozlYc+*xU~gmF0Fk?I8oFOrvKwl6o(#d?4uMxQ%XQvqeVY`dVmb}DCqQIYtHBzY z#&bTrrGV*ZUrM>_dw~_D1rLxcX|9OH>(j#0J+$$f!FON75}%g$f?2R(!(5c1iKz21a7J-ot+mDerdJss6 zx~&A4#AcrW8Os6wVhQpKp;a!;mN0JtPEF@UXHyxeYTZS|+PB_SCyhiGgm|^(Q%GxsE9wA9Ac8k5NUb0DU;38i zQR4*VgpD+N4uUfONrPkaYc6jF^fYG#Tll;{F}aThN`v?1g}lIvk;l;=Y(us`uuW~1 z@t~Won6MAn$`~v5cjgVGh@VrQA3(;DTkB`n8t4ELe^g_v>Ke4bC()#Wiu(kyl694y z5@;3V76!;}Mgb77X`=6)5!Gw(g|4ZQ4xtqK>PG<@d*6zDl2FD2G?AEenK ziQ)?;H_gDR^FTQC+-2}&r@=v&N-X(sYXM(FKx@UOeDMMU7$7JgPNR9{uOMLUA3+7T zdq|>W-6WDrCkp`W?;j|-vUf|nd(T9E08tZt`r#?e^O6wfzUwx?o1r!dt{@lWE6wxz z0)QnNx1(-wMN2+Mn$Bu)X8;mP<1e@yUwS>de*BFjSDhUVw3Gb>?0hRO8c7no2NKOB zsXgGGpg>PS%9OGX3@TLdt?(0+m;>^iauQeqlUg90RUrp9mm&I|dNlhU0HRSW0@GfKwKP zugIU-;LR{0@@kHCd8wE>X($WGm^TMhq?d?X&?W28y+J{u7`O#fBa21^jgiRs!pvvx z2KltfR=|^gd^D1S@Ulx>{@wz@?%H+-^I&*0NJ51qP%3;pn0U~7imph4YIDF1L?B`m zd5Zr9rV;^`g15{*uoSO((%=LrHSz#4wF&sA zJXtVp*ExYL0?rRE*>3QXV3yhnLB-9>*w2LOLunUj@X3|tDPTRkinzkVS(RGZb=emAmD)a(vP z@)U9u?W$3=p9S9q_E2o7{5|hau9sc0Mgy;|sIf|pwp4I$-)MY z>FnJKuxsA9=2#W#D@gJ@CB1ly72;rUK7^`I&GsSR5)M9vLj>4cfgZk&_d_sr{n zR+zfApB_aUBIzmGFY&*aFI&$(#-5noU<0v&$G4B^w*-7_kSnU2xsZ>oOu-}1X{=yE zcZ~~i%)+oxCua+L-I)HPhIeAz=n?w^EbJDWrDNtVc*W={g>29aBlp8$OrO&*zKdf9 z8X-9Hjm%N0)LT7jPf-r9K{W~cHDo7Oc}#yKrrU_?MGn1##z3SQJbDJ~a^P+k>XkX; zAn2+|#tVY*((k~D5s9T zhi++*WFY9t!q$d|aMUy2Us5${hV_jj3?Bgnv4sBwS7Ef;oXhsh#tH+6KrMoWT_3jY zM<~Twc41?sc0Lx;_@>51j+LB<_1`kPp6uZ+=mcnu8gSm6eU}!YdGgUTdy;*eUs)Zn z;yaB_6|uBWis}uv`TU*TZl|&VVo3+CF*rLv*QoO$HBukErBy2l+JJ7Jj%v0Xob{+& zA@^VS^=8l?wq@!0l9U)TOlnbH_yZyo?VRLP=lguRk@8oH3M`kK5b{=obL~kSONRR` z76u#q-OluX_n{HEYY+KhL=$R1vSgm>Cqdxmgo~yZUb5mKTFNbWV9} z2C?h8Sfn^AR!}ovo^^|VdC(1QhBiaqVGc7Mf^RHrr2rnWBD&zfx!&F>9w0|onx&G5 zV}G6pzm)Qx(Qh!7Erv7aPY*Nl8A`+7E1X#H?Ey)G5=c@tVfSjmY{c=paUzig8~laZ zy>2wLhIN8T*%*E{1GKLg$rV9KQSP=A;4MjA#A-XB`7xFsCy0e^dmF@Z zjKI?6C&Ny^7bt&uM(o4hE?;oYcEhsuISa=x(>6HD(exrZb0 zAzu-I|A|agfMn|H8{3s1#%KZfbO&+e$MhFGJ9XK8yTt1N_RUII{h+ZYgzezP!d5*O zU}v@YaIcl_W@w|WWEw$sw9?DAJu-A+ zdMikPcWK^DZuB{Z>=!M0MqYeL>f9HY0~~9g9Oy!8PmRjcL_9^`wUq@vpe7?NwbYlp zm)tBs(a_F~iy-~wf^NwYIq-y>Ojf2xMXRy;d!#P*rMy7?D>n=5+I&{z zKK#uBQNp@CsJM_6Ey=>#fu5~K;V<9riDu3Oj$nByMsQgbL&8q>Lan^RVp=)O0^N8+ z@4jq}i8- zwH+tQMRx4WZtDmmRf0~ThtmQ9wz3y4g`T_-<#f@Hf?5A*EBVcPOkWL%<8o_Gf_8{| zVCVBl^G%Hi=-R@rY>#^<7)l^ne71}Atu%pG%?JG)b_#-_D&9v0U=acqWCQ77+4b*S zXaDuh`e51W*JQA-lcs~Lsy5*MWGx7Ef*)72|9p?Z4ubW=>Wzq6e=AUW|Mh)ePL1#B ztF*iCQL8@}r-}Gn>jF&?NCl}%!hQ$Y^VO-|OEfd#)2_XB3PfgK## zV0O=y_b8K%CAPAvkHI$**i&8_=w#hZz=5%4BSNh6(eDi++u@;8pb3&Uk7ca+ydT6K ztMou3^yhg31yjfXGL#=W`X!h4ULB=bfT_eCMA86(n+k{f)6|fE&{hHi6laAY}w--60;C+-wC@2nydTK=M zp5*WEfUpUOsD7z*npxOu7sL+F28Ax((M>0Cd){MA$lyRUe0fLt8Hlg?6eVFVtG253 zI6I($T%WNOV-k&b_)W-oy~Z`BA3?^9t>RI*A-E6|Eg9Tt$^8zVq4qrl(92N)8ojh6 zyhqvlDC`M%{#Gv^ZwXe-M}WX^-&xSsq1?>QsmR#TI-_Np%W`bv;Z-HC<$ihOA};*6 z7S!35%EF~w@=D;}aA(FhUm8U8mCddXn?4&Ys@*gIaA9GV4ll@|?&xGN)0eZ0u#jn; zF0Bfh=O2VidwXq(hN z2kHksi2?)C;Q2~TEmD+$7d zWqH97Xz5ss;~5F(uyHc*yX|FwSscUyX4o-2MC3&~$U$ZnMy-C#QrOYS5~ zz`T}NNw!m)nb6rTBW^S~9@znUQrCY_Vmp6cKybgZVL$N_EEIgXnK_*np*)n=!E}55 zf~f&rEuCb)Y%`Oxd#ep#=Z5K0!2krqK% zd?L(sQ2d0tET}hz`UH)RXiG+gDu__D}xyyC1cH@E7aMX|jV)m>SV_l6$uo z%bCj*jm)TckZO5t%aw1A=Wj_e`>2-?xGnXYBUgyyH*$!fz!=R_)`dtmpjA&bxi|iI zMGHw`<|VgYR@h)uj6C!G)IHIAYb>`0+aLHue))ey4G$N7zPs_}C$&HzhxhM=AUjvv J>h0vi{|k(zSPlRH literal 0 HcmV?d00001 diff --git a/assets/images/icon_white.ico b/assets/images/icon_white.ico new file mode 100644 index 0000000000000000000000000000000000000000..9a0a5c0d50188fc6807ab9054c788269fa1919b1 GIT binary patch literal 4031 zcmV;w4?yq$00962000000096X0I3fE02TlM0EtjeM-2)Z3IG5A4M|8uQUCw}00001 z00;yC008!TVC?_^00D1uPE-NUqIa4A01snHL_t(|+U=ctl+M)}$LE4^XF>?cCAyGO zu9NN}l}aeI9F&Tqi<79;nX*o&NwuOnxjP*ZA{{9eD@CFtO-Y3=a!YQb!o*}|K4<^t z?VTwn@8x%Ue|yjK{rzLjvY7Y%eD||2zx_NIigkNHUC7eyNSU_j^<>|`n*w;?(5)0^yzmuBH58+IQm_Q@3 zfPPE9#yrF}+|ja-1;hlp;IGIve2$x1CQ(2a_+{wM8yv=MEu+3zAo%#3@i@QWjYeC` zK~ZqwpG+28@J_khE-@ge@T<^^m3Xam7!VBj6}X8N9K~<_#6=PV5{*BZbC^m#iP58CfW(gd(;3e$5~oi% zK@5;6_%*nhbtF~?xLgd72>2u4|y+R;U7}9gRhxtp(+4f!QVv9`n%9gcgf2jH{e&ICtsnT_LCv_ox)G! zS{8Ez9koi9fKF%q<~;4wHEu8TkW2v1X8kd~-{f^uyE#t`U>AN>db0+-H9;~2?FRm{ zc!OUx$G?ZxGXCx0Z^<}zqQ7MP+kju4TlgLmw3d1@{^NsRh5oEeK>m&w+ROEVKOXqW zYQCHqh-=*L=uW{O-;!^F+A^7=7p;6CF+gniYpPj)BN&ChhTxA4ekvKPGAQs1{y6Zb z(1GX3F$(@(MyiM=_+uFRwbfU(AG7osy`@BCY_t9_J_%UP&(T2eM~7dQPAoEP zDwWQG=ff<7|*G`g|gF!+0z z#Cf5PL88dBerM)uk-`zX@>#`&q2>^RKk}^KkTIHF4}Wj;A9m=4_euW100&W2*MoxQ|`(E#W#9(*%B0 z_{~+2+-_Ll|BlQse8C?He^qYeGsEB?W)e*VesuWBoXb+f0)MXBz+OoOK_3l&GOc); z9}FA&U#WOjUPgZOv7gQz8rJHF2LAz05%|&JS7!jL49VXK>mYMw){g~#ikkK38+M!T zu=+%oS%sVgezfggYbFP(62BYzg1=g=-2{I${I$4M?TyXS0kT3FyaGQm{8TPxjbZsa zKQW67DI@5k;ZLO_|1s?CULl{*B?MpaN1pZTFxs$d+*T*QVbm7*(ec;jPSzQ=;?H4{ zGPTV5QQ?GV9guNA!_v+_B)V&q($dHum>&PxvOU zC=&cMdhn%T@OLwjb3)mPOSKwvC1g;TN%S?0zX##HCbWQot{@YLuUQh@u%{4W8UuP@g~}5j@mEzFCH{YCnI6l54I_=*pw&$zl@Id8FviV;DutQkE8~KImQAya3AKDQelnLrFqw zN44g8iQUJs{eHe+yfQ~=SzV})I8_t;b7^aL)-P^Kb*ozM?2F<5I>LH}tJs)gyb09D zo2peY+afPe5;aFgBqo#IsX zOIYh#9fNF6HZleT(g5F+X}1SQ@!?J^GbrY71wU0Zw6KAn#86b&y35UOhESfvq?w!I5KGZST721}XWr2GW3jZ)K(ai42dog_fT2Vf0*oIJj zedqFH!r;G7cPcu9UxDj&?w(x_J-~}xY&U%#q-u0#xw(@G2W9eYdtqQ zT=G?+56c6UznpDVA4xLK0+pHQ@)xzA5!7`AKbfiGbWIUD<4_smq~_NV1f(BD}}tr`3?hrIsC@1EI=Qa^8Pzs)iw zv1W=^eMsk6pSjeC7#;`zZr!3*lzQn_DNN&zsmjuoPti>U^b`Ef@t5HuOL`6>1z;b48kh55tveHZU=^$o*&F*!c}b(HWPhf7 zZkF+H4}T*v4QNHVTE@Q}_!ZQ=`3?H(AUDbQj~9Ohy0gfT9>h}(EfwS8tbZy~jA=%- zICQUB6f6G9Jj51EQ4Spie?0ixur$zjdg9Z5>-bj;5G(#+Nzl}k2{|dTnyouByvch!?1b;l^Kg0K0L+7{1ktvV+X}PR4(GjmQ5&6}_Yfu|oq4*Al(eigE}i z2z=)gz+x?5@QyIJA(XEMXvmkE!QaO;+Q~VeTL!pPt2h7otW-jA$fE{Yq zuO{$IrvY~Gq*c;Q;Fm@NHD$#aQXf|eKfiMPN%699h$_sX4~pctT;&oSTtnKTgi zr85SET2ZD5{-DJGe|meamE^6UT3`@)9$({L$K7^YQHs1bKqcmRn!ocjbp(E}El``4 z9^s!yN6FvO!2(yi-uA6f&HA^?ogRHG(8E;=>|q$S1inrNaL)pvZiI5ktDyzDvCMJ) z&QklWC`F04z=^!bVcYmWWuRp3>TZIHT*W&!;QzogQk>D0IB*h~Y>K0Hm<7L;WbK+| zf=2Y^CBBPjgF^CnpWDLl1;1Gque|+{+9$v7z|c z$cJPyg0@r@8<-2fg@U}C9T8H|b9h(%opZxB5Sau2OrBKeW7AK(O>e0VVh;Xz;Fr_~ zdWX(p0sY}u;wCoRyi~HA$EYkO&>4R^&r;y%V%c?n;F8C`rUi$r+riD%hM8P+}^&Taej}`;y zfWI-DJjyTro=e06!8gEz9#$B5O-(QIH3xkBf8%LI!7C*Ol-}`g=~b(ypeU&Ln|M0@ zL+gNM5(9#3fWbc07<*U@5L5%CvCsztd~9_O69v%#>8$g?0NXfI3=m8MbaPNpA|CaX zNg$XjfZje8ntjSjK^Fzh0LlEzCj+dqn#zcRW`J_6@W}x0i2;IXfaPKUF@P9A3?K#& z1Bd~{0Ac_!fEb{Z9Rxk#lL1zU0ZR8t;QewG983$GPmV7J=qCmUrU5FE?F0TCG6a7x z4Uoz-UzUIs#Q;HF1>8Ws=LWb}CV=2tpeCz5#=j@jf<_e77;uZnF<`RQghmux1Jv*| z2JDsbuR{zd@XP>HWc&x;0yS*)8H%kDmE;6y5d+$>-vj)I7$Erdus{k!IOw_orc3zO zCkCW2!)5$$(NM;}P8MjuVps8>Eco>@Koa#`v%qio#Q?flpaGLO;J5?vV!^Mo35KxC zQ9+2|qzinVEs#trmhh`B{A=hP>OL;gI|@|g20o4x{&t?Av4nneOwf$Myd6{dxFgCe zPjH67H_ZZ8yO_?5Re}A;pH2zCs-J(vI4%#(`hwp~6IkyGIw{B#n9H2vXRg{Wbm4-M l_R|92bQ?$?Vv(ps{{u^_Yk2)9 ./Clash.Meta -require ( - github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34 - github.com/metacubex/mihomo v1.17.1 - github.com/miekg/dns v1.1.62 - golang.org/x/sync v0.8.0 -) +require github.com/metacubex/mihomo v1.17.1 + +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240724044459-6f3cf5896297 require ( github.com/3andne/restls-client-go v0.1.6 // indirect @@ -54,7 +51,7 @@ require ( github.com/metacubex/chacha v0.1.0 // indirect github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec // indirect - github.com/metacubex/quic-go v0.46.1-0.20240807232329-1c6cb2d67f58 // indirect + github.com/metacubex/quic-go v0.47.1-0.20240909010619-6b38f24bfcc4 // indirect github.com/metacubex/randv2 v0.2.0 // indirect github.com/metacubex/sing-quic v0.0.0-20240827003841-cd97758ed8b4 // indirect github.com/metacubex/sing-shadowsocks v0.2.8 // indirect @@ -64,6 +61,7 @@ require ( github.com/metacubex/sing-wireguard v0.0.0-20240826061955-1e4e67afe5cd // indirect github.com/metacubex/tfo-go v0.0.0-20240830120620-c5e019b67785 // indirect github.com/metacubex/utls v1.6.6 // indirect + github.com/miekg/dns v1.1.62 // 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 @@ -103,11 +101,12 @@ require ( golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect golang.org/x/mod v0.20.0 // indirect golang.org/x/net v0.28.0 // indirect + golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.24.0 // indirect golang.org/x/text v0.17.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.24.0 // indirect google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect; indirect` lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/core/go.sum b/core/go.sum index 2e80016..18840e6 100644 --- a/core/go.sum +++ b/core/go.sum @@ -1,7 +1,5 @@ github.com/3andne/restls-client-go v0.1.6 h1:tRx/YilqW7iHpgmEL4E1D8dAsuB0tFF3uvncS+B6I08= github.com/3andne/restls-client-go v0.1.6/go.mod h1:iEdTZNt9kzPIxjIGSMScUFSBrUH6bFRNg0BWlP4orEY= -github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34 h1:USCTqih5d1bUXUxWNS9ZD5Tx/lb0jXHEtRIIx/F9dMc= -github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34/go.mod h1:YR9wK13TgI5ww8iKWm91MHiSoHC7Oz0U4beCCmtXqLw= github.com/RyuaNerin/elliptic2 v1.0.0/go.mod h1:wWB8fWrJI/6EPJkyV/r1Rj0hxUgrusmqSj8JN6yNf/A= github.com/RyuaNerin/go-krypto v1.2.4 h1:mXuNdK6M317aPV0llW6Xpjbo4moOlPF7Yxz4tb4b4Go= github.com/RyuaNerin/go-krypto v1.2.4/go.mod h1:QqCYkoutU3yInyD9INt2PGolVRsc3W4oraQadVGXJ/8= @@ -106,10 +104,12 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec h1:HxreOiFTUrJXJautEo8rnE1uKTVGY8wtZepY1Tii/Nc= github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec/go.mod h1:8BVmQ+3cxjqzWElafm24rb2Ae4jRI6vAXNXWqWjfrXw= -github.com/metacubex/quic-go v0.46.1-0.20240807232329-1c6cb2d67f58 h1:T6OxROLZBr9SOQxN5TzUslv81hEREy/dEgaUKVjaG7U= -github.com/metacubex/quic-go v0.46.1-0.20240807232329-1c6cb2d67f58/go.mod h1:Yza2H7Ax1rxWPUcJx0vW+oAt9EsPuSiyQFhFabUPzwU= +github.com/metacubex/quic-go v0.47.1-0.20240909010619-6b38f24bfcc4 h1:CgdUBRxmNlxEGkp35HwvgQ10jwOOUJKWdOxpi8yWi8o= +github.com/metacubex/quic-go v0.47.1-0.20240909010619-6b38f24bfcc4/go.mod h1:Y7yRGqFE6UQL/3aKPYmiYdjfVkeujJaStP4+jiZMcN8= github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs= github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY= +github.com/metacubex/sing v0.0.0-20240724044459-6f3cf5896297 h1:YG/JkwGPbca5rUtEMHIu8ZuqzR7BSVm1iqY8hNoMeMA= +github.com/metacubex/sing v0.0.0-20240724044459-6f3cf5896297/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/metacubex/sing-quic v0.0.0-20240827003841-cd97758ed8b4 h1:HobpULaPK6OoxrHMmgcwLkwwIduXVmwdcznwUfH1GQM= github.com/metacubex/sing-quic v0.0.0-20240827003841-cd97758ed8b4/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8= github.com/metacubex/sing-shadowsocks v0.2.8 h1:wIhlaigswzjPw4hej75sEvWte3QR0+AJRafgwBHO5B4= @@ -162,9 +162,6 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= 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.0-alpha.13 h1:fpR4TFZfu/9V3LbHSAnnnwcaXGMF8ijmAAPoY2WHSKw= -github.com/sagernet/sing v0.5.0-alpha.13/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6 h1:5bCAkvDDzSMITiHFjolBwpdqYsvycdTu71FsMEFXQ14= github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= @@ -190,9 +187,15 @@ github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e/go.mod h1:+e github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= @@ -250,7 +253,7 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= diff --git a/core/hub.go b/core/hub.go index d18b258..f393935 100644 --- a/core/hub.go +++ b/core/hub.go @@ -378,27 +378,28 @@ func updateGeoData(geoType *C.char, geoName *C.char, port C.longlong) { geoTypeString := C.GoString(geoType) geoNameString := C.GoString(geoName) go func() { + path := constant.Path.Resolve(geoNameString) switch geoTypeString { case "MMDB": - err := updater.UpdateMMDB(constant.Path.Resolve(geoNameString)) + err := updater.UpdateMMDBWithPath(path) if err != nil { bridge.SendToPort(i, err.Error()) return } case "ASN": - err := updater.UpdateASN(constant.Path.Resolve(geoNameString)) + err := updater.UpdateASNWithPath(path) if err != nil { bridge.SendToPort(i, err.Error()) return } case "GeoIp": - err := updater.UpdateGeoIp(constant.Path.Resolve(geoNameString)) + err := updater.UpdateGeoIpWithPath(path) if err != nil { bridge.SendToPort(i, err.Error()) return } case "GeoSite": - err := updater.UpdateGeoSite(constant.Path.Resolve(geoNameString)) + err := updater.UpdateGeoSiteWithPath(path) if err != nil { bridge.SendToPort(i, err.Error()) return diff --git a/core/tun.go b/core/tun.go index fc4c7cf..8e0656d 100644 --- a/core/tun.go +++ b/core/tun.go @@ -6,7 +6,9 @@ import "C" import ( "core/platform" t "core/tun" + "encoding/json" "errors" + "github.com/metacubex/mihomo/listener/sing_tun" "strconv" "sync" "sync/atomic" @@ -15,11 +17,9 @@ import ( "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/log" - "golang.org/x/sync/semaphore" ) var tunLock sync.Mutex -var tun *t.Tun var runTime *time.Time type FdMap struct { @@ -35,13 +35,18 @@ func (cm *FdMap) Load(key int64) bool { return ok } -var fdMap FdMap +var ( + tunListener *sing_tun.Listener + fdMap FdMap + fdCounter int64 = 0 +) //export startTUN -func startTUN(fd C.int, port C.longlong) { +func startTUN(s *C.char, port C.longlong) { i := int64(port) ServicePort = i - if fd == 0 { + paramsString := C.GoString(s) + if paramsString == "" { tunLock.Lock() defer tunLock.Unlock() now := time.Now() @@ -57,28 +62,22 @@ func startTUN(fd C.int, port C.longlong) { tunLock.Lock() defer tunLock.Unlock() - if tun != nil { - tun.Close() - tun = nil - } - - f := int(fd) - gateway := "172.16.0.1/30" - portal := "172.16.0.2" - dns := "0.0.0.0" - - tempTun := &t.Tun{Closed: false, Limit: semaphore.NewWeighted(4)} - - closer, err := t.Start(f, gateway, portal, dns) - + var tunProps = &t.Props{} + err := json.Unmarshal([]byte(paramsString), tunProps) if err != nil { log.Errorln("startTUN error: %v", err) - tempTun.Close() + return } - tempTun.Closer = closer + tunListener, err = t.Start(*tunProps) - tun = tempTun + if err != nil { + return + } + + if tunListener != nil { + log.Infoln("TUN address: %v", tunListener.Address()) + } now := time.Now() @@ -108,9 +107,8 @@ func stopTun() { runTime = nil - if tun != nil { - tun.Close() - tun = nil + if tunListener != nil { + _ = tunListener.Close() } }() } @@ -137,18 +135,12 @@ func markSocket(fd Fd) { }) } -var fdCounter int64 = 0 - func initSocketHook() { dialer.DefaultSocketHook = func(network, address string, conn syscall.RawConn) error { if platform.ShouldBlockConnection() { return errBlocked } return conn.Control(func(fd uintptr) { - if tun == nil { - return - } - fdInt := int64(fd) timeout := time.After(100 * time.Millisecond) id := atomic.AddInt64(&fdCounter, 1) diff --git a/core/tun/dns.go b/core/tun/dns.go deleted file mode 100644 index 2210ce4..0000000 --- a/core/tun/dns.go +++ /dev/null @@ -1,33 +0,0 @@ -//go:build android - -package tun - -import ( - "github.com/metacubex/mihomo/dns" - D "github.com/miekg/dns" - "net" -) - -func shouldHijackDns(dns net.IP, target net.IP, targetPort int) bool { - if targetPort != 53 { - return false - } - - return net.IPv4zero.Equal(dns) || target.Equal(dns) -} - -func relayDns(payload []byte) ([]byte, error) { - msg := &D.Msg{} - if err := msg.Unpack(payload); err != nil { - return nil, err - } - - r, err := dns.ServeDNSWithDefaultServer(msg) - if err != nil { - return nil, err - } - - r.SetRcode(msg, r.Rcode) - - return r.Pack() -} diff --git a/core/tun/tcp.go b/core/tun/tcp.go deleted file mode 100644 index b8bd143..0000000 --- a/core/tun/tcp.go +++ /dev/null @@ -1,20 +0,0 @@ -//go:build android - -package tun - -import ( - "github.com/metacubex/mihomo/constant" - "net" -) - -func createMetadata(lAddr, rAddr *net.TCPAddr) *constant.Metadata { - return &constant.Metadata{ - NetWork: constant.TCP, - Type: constant.SOCKS5, - SrcIP: lAddr.AddrPort().Addr(), - DstIP: rAddr.AddrPort().Addr(), - SrcPort: uint16(lAddr.Port), - DstPort: uint16(rAddr.Port), - Host: "", - } -} diff --git a/core/tun/tun.go b/core/tun/tun.go index 33a9492..4ebb7db 100644 --- a/core/tun/tun.go +++ b/core/tun/tun.go @@ -4,182 +4,65 @@ package tun import "C" import ( - "context" - "encoding/binary" - "github.com/Kr328/tun2socket" - "github.com/Kr328/tun2socket/nat" - "github.com/metacubex/mihomo/adapter/inbound" - "github.com/metacubex/mihomo/common/pool" "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing_tun" "github.com/metacubex/mihomo/log" - "github.com/metacubex/mihomo/transport/socks5" "github.com/metacubex/mihomo/tunnel" - "golang.org/x/sync/semaphore" - "io" "net" - "os" - "time" + "net/netip" ) -type Tun struct { - Closer io.Closer - - Closed bool - Limit *semaphore.Weighted +type Props struct { + Fd int `json:"fd"` + Gateway string `json:"gateway"` + Gateway6 string `json:"gateway6"` + Portal string `json:"portal"` + Portal6 string `json:"portal6"` + Dns string `json:"dns"` + Dns6 string `json:"dns6"` } -func (t *Tun) Close() { - _ = t.Limit.Acquire(context.TODO(), 4) - defer t.Limit.Release(4) - - t.Closed = true - - if t.Closer != nil { - _ = t.Closer.Close() - } -} - -var _, ipv4LoopBack, _ = net.ParseCIDR("127.0.0.0/8") - -func Start(fd int, gateway, portal, dns string) (io.Closer, error) { - device := os.NewFile(uintptr(fd), "/dev/tun") - ip, network, err := net.ParseCIDR(gateway) +func Start(tunProps Props) (*sing_tun.Listener, error) { + var prefix4 []netip.Prefix + tempPrefix4, err := netip.ParsePrefix(tunProps.Gateway) if err != nil { - panic(err.Error()) - } else { - network.IP = ip + log.Errorln("startTUN error:", err) + return nil, err } - stack, err := tun2socket.StartTun2Socket(device, network, net.ParseIP(portal)) + prefix4 = append(prefix4, tempPrefix4) + + var prefix6 []netip.Prefix + tempPrefix6, err := netip.ParsePrefix(tunProps.Gateway6) + if err != nil { + log.Errorln("startTUN error:", err) + return nil, err + } + prefix6 = append(prefix6, tempPrefix6) + + var dnsHijack []string + dnsHijack = append(dnsHijack, net.JoinHostPort(tunProps.Dns, "53")) + dnsHijack = append(dnsHijack, net.JoinHostPort(tunProps.Dns6, "53")) + + options := LC.Tun{ + Enable: true, + Device: sing_tun.InterfaceName, + Stack: constant.TunSystem, + DNSHijack: dnsHijack, + AutoRoute: false, + AutoDetectInterface: false, + Inet4Address: prefix4, + Inet6Address: prefix6, + MTU: 9000, + FileDescriptor: tunProps.Fd, + } + + listener, err := sing_tun.New(options, tunnel.Tunnel) if err != nil { - _ = device.Close() + log.Errorln("startTUN error:", err) return nil, err } - dnsAddr := net.ParseIP(dns) - - tcp := func() { - defer func(tcp *nat.TCP) { - _ = tcp.Close() - }(stack.TCP()) - defer log.Debugln("TCP: closed") - - for stack.TCP().SetDeadline(time.Time{}) == nil { - conn, err := stack.TCP().Accept() - if err != nil { - continue - } - lAddr := conn.LocalAddr().(*net.TCPAddr) - rAddr := conn.RemoteAddr().(*net.TCPAddr) - - if ipv4LoopBack.Contains(rAddr.IP) { - _ = conn.Close() - - continue - } - - if shouldHijackDns(dnsAddr, rAddr.IP, rAddr.Port) { - go func() { - defer func(conn net.Conn) { - _ = conn.Close() - }(conn) - - buf := pool.Get(pool.UDPBufferSize) - defer func(buf []byte) { - _ = pool.Put(buf) - }(buf) - - for { - _ = conn.SetReadDeadline(time.Now().Add(constant.DefaultTCPTimeout)) - - length := uint16(0) - if err := binary.Read(conn, binary.BigEndian, &length); err != nil { - return - } - - if int(length) > len(buf) { - return - } - - n, err := conn.Read(buf[:length]) - if err != nil { - return - } - - msg, err := relayDns(buf[:n]) - if err != nil { - return - } - - _, _ = conn.Write(msg) - } - }() - - continue - } - - go tunnel.Tunnel.HandleTCPConn(conn, createMetadata(lAddr, rAddr)) - } - } - - udp := func() { - defer func(udp *nat.UDP) { - _ = udp.Close() - }(stack.UDP()) - defer log.Debugln("UDP: closed") - - for { - buf := pool.Get(pool.UDPBufferSize) - - n, lRAddr, rRAddr, err := stack.UDP().ReadFrom(buf) - if err != nil { - return - } - - raw := buf[:n] - lAddr := lRAddr.(*net.UDPAddr) - rAddr := rRAddr.(*net.UDPAddr) - - if ipv4LoopBack.Contains(rAddr.IP) { - _ = pool.Put(buf) - - continue - } - - if shouldHijackDns(dnsAddr, rAddr.IP, rAddr.Port) { - go func() { - defer func(buf []byte) { - _ = pool.Put(buf) - }(buf) - - msg, err := relayDns(raw) - if err != nil { - return - } - - _, _ = stack.UDP().WriteTo(msg, rAddr, lAddr) - }() - - continue - } - - pkt := &packet{ - local: lAddr, - data: raw, - writeBack: func(b []byte, addr net.Addr) (int, error) { - return stack.UDP().WriteTo(b, addr, lAddr) - }, - drop: func() { - _ = pool.Put(buf) - }, - } - - tunnel.Tunnel.HandleUDPPacket(inbound.NewPacket(socks5.ParseAddrToSocksAddr(rAddr), pkt, constant.SOCKS5)) - } - } - - go tcp() - go udp() - - return stack, nil + return listener, nil } diff --git a/core/tun/udp.go b/core/tun/udp.go deleted file mode 100644 index c491f24..0000000 --- a/core/tun/udp.go +++ /dev/null @@ -1,28 +0,0 @@ -//go:build android - -package tun - -import "net" - -type packet struct { - local *net.UDPAddr - data []byte - writeBack func(b []byte, addr net.Addr) (int, error) - drop func() -} - -func (pkt *packet) Data() []byte { - return pkt.data -} - -func (pkt *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { - return pkt.writeBack(b, addr) -} - -func (pkt *packet) Drop() { - pkt.drop() -} - -func (pkt *packet) LocalAddr() net.Addr { - return pkt.local -} diff --git a/lib/application.dart b/lib/application.dart index cde7185..75d3aba 100644 --- a/lib/application.dart +++ b/lib/application.dart @@ -1,11 +1,12 @@ import 'dart:async'; +import 'dart:io'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:fl_clash/l10n/l10n.dart'; import 'package:fl_clash/common/common.dart'; +import 'package:fl_clash/manager/hotkey_manager.dart'; +import 'package:fl_clash/manager/manager.dart'; import 'package:fl_clash/state.dart'; -import 'package:fl_clash/widgets/proxy_container.dart'; -import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; @@ -53,6 +54,7 @@ class Application extends StatefulWidget { class ApplicationState extends State { late SystemColorSchemes systemColorSchemes; + Timer? timer; final _pageTransitionsTheme = const PageTransitionsTheme( builders: { @@ -81,6 +83,7 @@ class ApplicationState extends State { @override void initState() { super.initState(); + _initTimer(); globalState.appController = AppController(context); WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { final currentContext = globalState.navigatorKey.currentContext; @@ -92,18 +95,36 @@ class ApplicationState extends State { }); } + _initTimer() { + _cancelTimer(); + timer = Timer.periodic(const Duration(milliseconds: 20000), (_) { + WidgetsBinding.instance.addPostFrameCallback((_) { + globalState.appController.updateGroupDebounce(); + }); + }); + } + + _cancelTimer() { + if (timer != null) { + timer?.cancel(); + timer = null; + } + } + _buildApp(Widget app) { if (system.isDesktop) { - return WindowContainer( - child: TrayContainer( - child: ProxyContainer( - child: app, + return WindowManager( + child: TrayManager( + child: HotKeyManager( + child: ProxyManager( + child: app, + ), ), ), ); } - return AndroidContainer( - child: TileContainer( + return AndroidManager( + child: TileManager( child: app, ), ); @@ -115,7 +136,7 @@ class ApplicationState extends State { child: page, ); } - return VpnContainer( + return VpnManager( child: page, ); } @@ -136,8 +157,8 @@ class ApplicationState extends State { @override Widget build(context) { return _buildApp( - AppStateContainer( - child: ClashContainer( + AppStateManager( + child: ClashManager( child: Selector2( selector: (_, appState, config) => ApplicationSelectorState( locale: config.locale, @@ -158,7 +179,7 @@ class ApplicationState extends State { GlobalWidgetsLocalizations.delegate ], builder: (_, child) { - return MediaContainer( + return MediaManager( child: _buildPage(child!), ); }, @@ -203,5 +224,6 @@ class ApplicationState extends State { linkManager.destroy(); await globalState.appController.savePreferences(); super.dispose(); + _cancelTimer(); } } diff --git a/lib/clash/core.dart b/lib/clash/core.dart index 6c40d3f..69b1030 100644 --- a/lib/clash/core.dart +++ b/lib/clash/core.dart @@ -158,7 +158,7 @@ class ClashCore { final externalProviderRawString = externalProviderRaw.cast().toDartString(); clashFFI.freeCString(externalProviderRaw); - if(externalProviderRawString.isEmpty) return null; + if (externalProviderRawString.isEmpty) return null; return ExternalProvider.fromJson(json.decode(externalProviderRawString)); } @@ -322,9 +322,18 @@ class ClashCore { clashFFI.stopLog(); } - startTun(int fd, int port) { + startTun(TunProps? tunProps, int port) { if (!Platform.isAndroid) return; - clashFFI.startTUN(fd, port); + final tunPropsChar = json.encode(tunProps).toNativeUtf8().cast(); + clashFFI.startTUN(tunPropsChar, port); + malloc.free(tunPropsChar); + } + + updateDns(String dns) { + if (!Platform.isAndroid) return; + final dnsChar = dns.toNativeUtf8().cast(); + clashFFI.updateDns(dnsChar); + malloc.free(dnsChar); } requestGc() { diff --git a/lib/clash/generated/clash_ffi.dart b/lib/clash/generated/clash_ffi.dart index 236f435..95ccc9c 100644 --- a/lib/clash/generated/clash_ffi.dart +++ b/lib/clash/generated/clash_ffi.dart @@ -5264,6 +5264,20 @@ class ClashFFI { late final _getProxies = _getProxiesPtr.asFunction Function()>(); + void updateDns( + ffi.Pointer s, + ) { + return _updateDns( + s, + ); + } + + late final _updateDnsPtr = + _lookup)>>( + 'updateDns'); + late final _updateDns = + _updateDnsPtr.asFunction)>(); + void changeProxy( ffi.Pointer s, ) { @@ -5567,19 +5581,20 @@ class ClashFFI { _setStatePtr.asFunction)>(); void startTUN( - int fd, + ffi.Pointer s, int port, ) { return _startTUN( - fd, + s, port, ); } - late final _startTUNPtr = - _lookup>( - 'startTUN'); - late final _startTUN = _startTUNPtr.asFunction(); + late final _startTUNPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function(ffi.Pointer, ffi.LongLong)>>('startTUN'); + late final _startTUN = + _startTUNPtr.asFunction, int)>(); ffi.Pointer getRunTime() { return _getRunTime(); diff --git a/lib/common/common.dart b/lib/common/common.dart index 7a88639..1be1447 100644 --- a/lib/common/common.dart +++ b/lib/common/common.dart @@ -27,4 +27,5 @@ export 'windows.dart'; export 'iterable.dart'; export 'scroll.dart'; export 'icons.dart'; -export 'http.dart'; \ No newline at end of file +export 'http.dart'; +export 'keyboard.dart'; \ No newline at end of file diff --git a/lib/common/constant.dart b/lib/common/constant.dart index d9ce9c6..5fce4fc 100644 --- a/lib/common/constant.dart +++ b/lib/common/constant.dart @@ -1,3 +1,4 @@ +import 'dart:io'; import 'dart:ui'; import 'package:fl_clash/enum/enum.dart'; @@ -16,7 +17,11 @@ const mmdbFileName = "geoip.metadb"; const asnFileName = "ASN.mmdb"; const geoIpFileName = "GeoIP.dat"; const geoSiteFileName = "GeoSite.dat"; -final double kHeaderHeight = system.isDesktop ? 40 : 0; +final double kHeaderHeight = system.isDesktop + ? !Platform.isMacOS + ? 40 + : 26 + : 0; const GeoXMap defaultGeoXMap = { "mmdb": "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", diff --git a/lib/common/keyboard.dart b/lib/common/keyboard.dart new file mode 100644 index 0000000..6572767 --- /dev/null +++ b/lib/common/keyboard.dart @@ -0,0 +1,106 @@ +import 'dart:io'; + +import 'package:flutter/services.dart'; +import 'package:uni_platform/uni_platform.dart'; + +final Map _knownKeyLabels = + { + PhysicalKeyboardKey.keyA: 'A', + PhysicalKeyboardKey.keyB: 'B', + PhysicalKeyboardKey.keyC: 'C', + PhysicalKeyboardKey.keyD: 'D', + PhysicalKeyboardKey.keyE: 'E', + PhysicalKeyboardKey.keyF: 'F', + PhysicalKeyboardKey.keyG: 'G', + PhysicalKeyboardKey.keyH: 'H', + PhysicalKeyboardKey.keyI: 'I', + PhysicalKeyboardKey.keyJ: 'J', + PhysicalKeyboardKey.keyK: 'K', + PhysicalKeyboardKey.keyL: 'L', + PhysicalKeyboardKey.keyM: 'M', + PhysicalKeyboardKey.keyN: 'N', + PhysicalKeyboardKey.keyO: 'O', + PhysicalKeyboardKey.keyP: 'P', + PhysicalKeyboardKey.keyQ: 'Q', + PhysicalKeyboardKey.keyR: 'R', + PhysicalKeyboardKey.keyS: 'S', + PhysicalKeyboardKey.keyT: 'T', + PhysicalKeyboardKey.keyU: 'U', + PhysicalKeyboardKey.keyV: 'V', + PhysicalKeyboardKey.keyW: 'W', + PhysicalKeyboardKey.keyX: 'X', + PhysicalKeyboardKey.keyY: 'Y', + PhysicalKeyboardKey.keyZ: 'Z', + PhysicalKeyboardKey.digit1: '1', + PhysicalKeyboardKey.digit2: '2', + PhysicalKeyboardKey.digit3: '3', + PhysicalKeyboardKey.digit4: '4', + PhysicalKeyboardKey.digit5: '5', + PhysicalKeyboardKey.digit6: '6', + PhysicalKeyboardKey.digit7: '7', + PhysicalKeyboardKey.digit8: '8', + PhysicalKeyboardKey.digit9: '9', + PhysicalKeyboardKey.digit0: '0', + PhysicalKeyboardKey.enter: 'ENTER', + PhysicalKeyboardKey.escape: 'ESCAPE', + PhysicalKeyboardKey.backspace: 'BACKSPACE', + PhysicalKeyboardKey.tab: 'TAB', + PhysicalKeyboardKey.space: 'SPACE', + PhysicalKeyboardKey.minus: '-', + PhysicalKeyboardKey.equal: '=', + PhysicalKeyboardKey.bracketLeft: '[', + PhysicalKeyboardKey.bracketRight: ']', + PhysicalKeyboardKey.backslash: '\\', + PhysicalKeyboardKey.semicolon: ';', + PhysicalKeyboardKey.quote: '"', + PhysicalKeyboardKey.backquote: '`', + PhysicalKeyboardKey.comma: ',', + PhysicalKeyboardKey.period: '.', + PhysicalKeyboardKey.slash: '/', + PhysicalKeyboardKey.capsLock: 'CAPSLOCK', + PhysicalKeyboardKey.f1: 'F1', + PhysicalKeyboardKey.f2: 'F2', + PhysicalKeyboardKey.f3: 'F3', + PhysicalKeyboardKey.f4: 'F4', + PhysicalKeyboardKey.f5: 'F5', + PhysicalKeyboardKey.f6: 'F6', + PhysicalKeyboardKey.f7: 'F7', + PhysicalKeyboardKey.f8: 'F8', + PhysicalKeyboardKey.f9: 'F9', + PhysicalKeyboardKey.f10: 'F10', + PhysicalKeyboardKey.f11: 'F11', + PhysicalKeyboardKey.f12: 'F12', + PhysicalKeyboardKey.home: 'HOME', + PhysicalKeyboardKey.pageUp: 'PAGEUP', + PhysicalKeyboardKey.delete: 'DELETE', + PhysicalKeyboardKey.end: 'END', + PhysicalKeyboardKey.pageDown: 'PAGEDOWN', + PhysicalKeyboardKey.arrowRight: '→', + PhysicalKeyboardKey.arrowLeft: '←', + PhysicalKeyboardKey.arrowDown: '↓', + PhysicalKeyboardKey.arrowUp: '↑', + PhysicalKeyboardKey.controlLeft: "CTRL", + PhysicalKeyboardKey.shiftLeft: 'SHIFT', + PhysicalKeyboardKey.altLeft: "ALT", + PhysicalKeyboardKey.metaLeft: Platform.isMacOS ? '⌘' : 'WIN', + PhysicalKeyboardKey.controlRight: "CTRL", + PhysicalKeyboardKey.shiftRight: 'SHIFT', + PhysicalKeyboardKey.altRight: "ALT", + PhysicalKeyboardKey.metaRight: Platform.isMacOS ? '⌘' : 'WIN', + PhysicalKeyboardKey.fn: 'FN', +}; + +extension KeyboardKeyExt on KeyboardKey { + String get label { + PhysicalKeyboardKey? physicalKey; + if (this is LogicalKeyboardKey) { + physicalKey = (this as LogicalKeyboardKey).physicalKey; + } else if (this is PhysicalKeyboardKey) { + physicalKey = this as PhysicalKeyboardKey; + } + return _knownKeyLabels[physicalKey] ?? physicalKey?.debugName ?? 'Unknown'; + } +} + + + diff --git a/lib/common/other.dart b/lib/common/other.dart index 393a861..a1db0a1 100644 --- a/lib/common/other.dart +++ b/lib/common/other.dart @@ -100,12 +100,18 @@ class Other { } } - String getTrayIconPath() { - if (Platform.isWindows) { - return "assets/images/icon.ico"; - } else { - return "assets/images/icon_monochrome.png"; + String getTrayIconPath({ + required bool isStart, + required Brightness brightness, + }) { + final suffix = Platform.isWindows ? "ico" : "png"; + if (!isStart && Platform.isWindows) { + return switch (brightness) { + Brightness.dark => "assets/images/icon_white.$suffix", + Brightness.light => "assets/images/icon_black.$suffix", + }; } + return "assets/images/icon.$suffix"; } int compareVersions(String version1, String version2) { @@ -201,9 +207,9 @@ class Other { int getProxiesColumns(double viewWidth, ProxiesLayout proxiesLayout) { final columns = max((viewWidth / 300).ceil(), 2); return switch (proxiesLayout) { - ProxiesLayout.tight => columns - 1, + ProxiesLayout.tight => columns + 1, ProxiesLayout.standard => columns, - ProxiesLayout.loose => columns + 1, + ProxiesLayout.loose => columns - 1, }; } diff --git a/lib/common/request.dart b/lib/common/request.dart index 1c4a62d..03840dc 100644 --- a/lib/common/request.dart +++ b/lib/common/request.dart @@ -3,7 +3,7 @@ import 'dart:typed_data'; import 'package:dio/dio.dart'; import 'package:fl_clash/common/common.dart'; -import 'package:fl_clash/models/ip.dart'; +import 'package:fl_clash/models/models.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/cupertino.dart'; diff --git a/lib/common/system.dart b/lib/common/system.dart index 9d61071..e4abafe 100644 --- a/lib/common/system.dart +++ b/lib/common/system.dart @@ -1,7 +1,9 @@ import 'dart:io'; +import 'package:device_info_plus/device_info_plus.dart'; import 'package:fl_clash/plugins/app.dart'; import 'package:flutter/services.dart'; +import 'package:window_manager/window_manager.dart'; import 'window.dart'; @@ -24,6 +26,16 @@ class System { return result.exitCode == 0; } + Future get version async { + final deviceInfo = await DeviceInfoPlugin().deviceInfo; + return switch (Platform.operatingSystem) { + "macos" => (deviceInfo as MacOsDeviceInfo).majorVersion, + "android" => (deviceInfo as AndroidDeviceInfo).version.sdkInt, + "windows" => (deviceInfo as WindowsDeviceInfo).majorVersion, + String() => 0 + }; + } + back() async { await app?.moveTaskToBack(); await window?.hide(); diff --git a/lib/common/window.dart b/lib/common/window.dart old mode 100644 new mode 100755 index c4aa637..c233807 --- a/lib/common/window.dart +++ b/lib/common/window.dart @@ -9,7 +9,7 @@ import 'protocol.dart'; import 'system.dart'; class Window { - init(WindowProps props) async { + init(WindowProps props, int version) async { if (Platform.isWindows) { await WindowsSingleInstance.ensureSingleInstance([], "FlClash"); protocol.register("clash"); @@ -20,8 +20,6 @@ class Window { WindowOptions windowOptions = WindowOptions( size: Size(props.width, props.height), minimumSize: const Size(380, 500), - windowButtonVisibility: false, - titleBarStyle: TitleBarStyle.hidden, ); if (props.left != null || props.top != null) { await windowManager.setPosition( @@ -30,9 +28,9 @@ class Window { } else { await windowManager.setAlignment(Alignment.center); } - // if(Platform.isWindows){ - // await windowManager.setTitleBarStyle(TitleBarStyle.hidden); - // } + if(!Platform.isMacOS || version > 10){ + await windowManager.setTitleBarStyle(TitleBarStyle.hidden); + } await windowManager.waitUntilReadyToShow(windowOptions, () async { await windowManager.setPreventClose(true); }); @@ -41,6 +39,11 @@ class Window { show() async { await windowManager.show(); await windowManager.focus(); + await windowManager.setSkipTaskbar(false); + } + + Future isVisible() async { + return await windowManager.isVisible(); } close() async { @@ -49,6 +52,7 @@ class Window { hide() async { await windowManager.hide(); + await windowManager.setSkipTaskbar(true); } } diff --git a/lib/controller.dart b/lib/controller.dart index 5acb365..7e678a7 100644 --- a/lib/controller.dart +++ b/lib/controller.dart @@ -295,6 +295,10 @@ class AppController { } init() async { + final isDisclaimerAccepted = await handlerDisclaimer(); + if (!isDisclaimerAccepted) { + system.exit(); + } updateLogStatus(); if (!config.silentLaunch) { window?.show(); @@ -311,14 +315,6 @@ class AppController { autoCheckUpdate(); } - updateTray() { - globalState.updateTray( - appState: appState, - config: config, - clashConfig: clashConfig, - ); - } - setDelay(Delay delay) { appState.setDelay(delay); } @@ -381,6 +377,47 @@ class AppController { globalState.showSnackBar(context, message: message); } + Future showDisclaimer() async { + return await globalState.showCommonDialog( + dismissible: false, + child: AlertDialog( + title: Text(appLocalizations.disclaimer), + content: Container( + width: dialogCommonWidth, + constraints: const BoxConstraints(maxHeight: 200), + child: SingleChildScrollView( + child: SelectableText( + appLocalizations.disclaimerDesc, + ), + ), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text(appLocalizations.exit), + ), + TextButton( + onPressed: () { + config.isDisclaimerAccepted = true; + Navigator.of(context).pop(true); + }, + child: Text(appLocalizations.agree), + ) + ], + ), + ) ?? + false; + } + + Future handlerDisclaimer() async { + if (config.isDisclaimerAccepted) { + return true; + } + return showDisclaimer(); + } + addProfileFormURL(String url) async { if (globalState.navigatorKey.currentState?.canPop() ?? false) { globalState.navigatorKey.currentState?.popUntil((route) => route.isFirst); @@ -496,6 +533,44 @@ class AppController { }); } + updateTun() { + clashConfig.tun = clashConfig.tun.copyWith( + enable: !clashConfig.tun.enable, + ); + } + + updateSystemProxy() { + config.desktopProps = config.desktopProps.copyWith( + systemProxy: !config.desktopProps.systemProxy, + ); + } + + updateStart() { + updateStatus(!appState.isStart); + } + + updateAutoLaunch() { + config.autoLaunch = !config.autoLaunch; + } + + updateVisible() async { + final visible = await window?.isVisible(); + if (visible != null && !visible) { + window?.show(); + } else { + window?.hide(); + } + } + + 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]; + } + recoveryData( List data, RecoveryOption recoveryOption, diff --git a/lib/enum/enum.dart b/lib/enum/enum.dart index 95d0700..89cabcc 100644 --- a/lib/enum/enum.dart +++ b/lib/enum/enum.dart @@ -1,6 +1,8 @@ // ignore_for_file: constant_identifier_names +import 'package:flutter/services.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:hotkey_manager/hotkey_manager.dart'; enum GroupType { Selector, URLTest, Fallback, LoadBalance, Relay } @@ -92,7 +94,6 @@ enum ProxiesLayout { loose, standard, tight } enum ProxyCardType { expand, shrink, min } - enum DnsMode { normal, @JsonValue("fake-ip") @@ -102,3 +103,52 @@ enum DnsMode { hosts } +enum KeyboardModifier { + alt([ + PhysicalKeyboardKey.altLeft, + PhysicalKeyboardKey.altRight, + ]), + capsLock([ + PhysicalKeyboardKey.capsLock, + ]), + control([ + PhysicalKeyboardKey.controlLeft, + PhysicalKeyboardKey.controlRight, + ]), + fn([ + PhysicalKeyboardKey.fn, + ]), + meta([ + PhysicalKeyboardKey.metaLeft, + PhysicalKeyboardKey.metaRight, + ]), + shift([ + PhysicalKeyboardKey.shiftLeft, + PhysicalKeyboardKey.shiftRight, + ]); + + final List physicalKeys; + + const KeyboardModifier(this.physicalKeys); +} + +extension KeyboardModifierExt on KeyboardModifier { + HotKeyModifier toHotKeyModifier() { + return switch (this) { + KeyboardModifier.alt => HotKeyModifier.alt, + KeyboardModifier.capsLock => HotKeyModifier.capsLock, + KeyboardModifier.control => HotKeyModifier.control, + KeyboardModifier.fn => HotKeyModifier.fn, + KeyboardModifier.meta => HotKeyModifier.meta, + KeyboardModifier.shift => HotKeyModifier.shift, + }; + } +} + +enum HotAction { + start, + view, + mode, + proxy, + tun, +} diff --git a/lib/fragments/backup_and_recovery.dart b/lib/fragments/backup_and_recovery.dart index e6f0be4..d210971 100644 --- a/lib/fragments/backup_and_recovery.dart +++ b/lib/fragments/backup_and_recovery.dart @@ -3,8 +3,7 @@ import 'dart:typed_data'; 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/config.dart'; -import 'package:fl_clash/models/dav.dart'; +import 'package:fl_clash/models/models.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/fade_box.dart'; import 'package:fl_clash/widgets/list.dart'; diff --git a/lib/fragments/config/app.dart b/lib/fragments/config/app.dart index 7bb2310..261893f 100644 --- a/lib/fragments/config/app.dart +++ b/lib/fragments/config/app.dart @@ -5,7 +5,6 @@ import 'package:fl_clash/models/config.dart'; import 'package:fl_clash/state.dart'; import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; -import 'package:path/path.dart' show dirname, join; import 'package:provider/provider.dart'; class CloseConnectionsSwitch extends StatelessWidget { @@ -58,32 +57,7 @@ class UsageSwitch extends StatelessWidget { } } -class UWPLoopbackUtil extends StatelessWidget { - const UWPLoopbackUtil({super.key}); - - @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.onlyProxy, - builder: (_, onlyProxy, __) { - return ListItem( - leading: const Icon(Icons.lock_open), - title: Text(appLocalizations.loopback), - subtitle: Text(appLocalizations.loopbackDesc), - onTap: () { - windows?.runas( - '"${join(dirname(Platform.resolvedExecutable), "EnableLoopback.exe")}"', - "", - ); - }, - ); - }, - ); - } -} - final appItems = [ - if (Platform.isWindows) const UWPLoopbackUtil(), const CloseConnectionsSwitch(), const UsageSwitch(), ]; diff --git a/lib/fragments/config/dns.dart b/lib/fragments/config/dns.dart index 70967fc..0d9a547 100644 --- a/lib/fragments/config/dns.dart +++ b/lib/fragments/config/dns.dart @@ -14,7 +14,7 @@ class OverrideItem extends StatelessWidget { _initActions(BuildContext context) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { final commonScaffoldState = - context.findAncestorStateOfType(); + context.findAncestorStateOfType(); commonScaffoldState?.actions = [ IconButton( onPressed: () { @@ -54,7 +54,8 @@ class OverrideItem extends StatelessWidget { class DnsDisabledContainer extends StatelessWidget { final Widget child; - const DnsDisabledContainer(this.child, { + const DnsDisabledContainer( + this.child, { super.key, }); @@ -268,7 +269,7 @@ class FakeIpFilterItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.fakeIpFilter, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, fakeIpFilter, __) { return UpdatePage( title: appLocalizations.fakeipFilter, @@ -278,8 +279,7 @@ class FakeIpFilterItem extends StatelessWidget { final clashConfig = globalState.appController.clashConfig; final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( - fakeIpFilter: List.from(dns.fakeIpFilter) - ..remove(value), + fakeIpFilter: List.from(dns.fakeIpFilter)..remove(value), ); }, onAdd: (value) { @@ -287,8 +287,7 @@ class FakeIpFilterItem extends StatelessWidget { final dns = clashConfig.dns; if (fakeIpFilter.contains(value)) return; clashConfig.dns = dns.copyWith( - fakeIpFilter: List.from(dns.fakeIpFilter) - ..add(value), + fakeIpFilter: List.from(dns.fakeIpFilter)..add(value), ); }, ); @@ -314,7 +313,7 @@ class DefaultNameserverItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.defaultNameserver, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, defaultNameserver, __) { return UpdatePage( title: appLocalizations.defaultNameserver, @@ -360,7 +359,7 @@ class NameserverItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.nameserver, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, nameserver, __) { return UpdatePage( title: "域名服务器", @@ -370,8 +369,7 @@ class NameserverItem extends StatelessWidget { final clashConfig = globalState.appController.clashConfig; final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( - nameserver: List.from(dns.nameserver) - ..remove(value), + nameserver: List.from(dns.nameserver)..remove(value), ); }, onAdd: (value) { @@ -379,8 +377,7 @@ class NameserverItem extends StatelessWidget { final dns = clashConfig.dns; if (nameserver.contains(value)) return; clashConfig.dns = dns.copyWith( - nameserver: List.from(dns.nameserver) - ..add(value), + nameserver: List.from(dns.nameserver)..add(value), ); }, ); @@ -458,7 +455,7 @@ class NameserverPolicyItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.nameserverPolicy, shouldRebuild: (prev, next) => - !const MapEquality().equals(prev, next), + !const MapEquality().equals(prev, next), builder: (_, nameserverPolicy, __) { return UpdatePage( title: appLocalizations.nameserverPolicy, @@ -505,7 +502,7 @@ class ProxyServerNameserverItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.proxyServerNameserver, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, proxyServerNameserver, __) { return UpdatePage( title: appLocalizations.proxyNameserver, @@ -551,7 +548,7 @@ class FallbackItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.fallback, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, fallback, __) { return UpdatePage( title: appLocalizations.fallback, @@ -561,8 +558,7 @@ class FallbackItem extends StatelessWidget { final clashConfig = globalState.appController.clashConfig; final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( - fallback: List.from(dns.fallback) - ..remove(value), + fallback: List.from(dns.fallback)..remove(value), ); }, onAdd: (value) { @@ -570,8 +566,7 @@ class FallbackItem extends StatelessWidget { final dns = clashConfig.dns; if (fallback.contains(value)) return; clashConfig.dns = dns.copyWith( - fallback: List.from(dns.fallback) - ..add(value), + fallback: List.from(dns.fallback)..add(value), ); }, ); @@ -663,7 +658,7 @@ class GeositeItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.geosite, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, geosite, __) { return UpdatePage( title: "Geosite", @@ -674,8 +669,7 @@ class GeositeItem extends StatelessWidget { final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( fallbackFilter: dns.fallbackFilter.copyWith( - geosite: List.from(geosite) - ..remove(value), + geosite: List.from(geosite)..remove(value), ), ); }, @@ -684,8 +678,7 @@ class GeositeItem extends StatelessWidget { final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( fallbackFilter: dns.fallbackFilter.copyWith( - geosite: List.from(geosite) - ..add(value), + geosite: List.from(geosite)..add(value), ), ); }, @@ -711,7 +704,7 @@ class IpcidrItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.ipcidr, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, ipcidr, __) { return UpdatePage( title: appLocalizations.ipcidr, @@ -722,8 +715,7 @@ class IpcidrItem extends StatelessWidget { final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( fallbackFilter: dns.fallbackFilter.copyWith( - ipcidr: List.from(ipcidr) - ..remove(value), + ipcidr: List.from(ipcidr)..remove(value), ), ); }, @@ -732,8 +724,7 @@ class IpcidrItem extends StatelessWidget { final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( fallbackFilter: dns.fallbackFilter.copyWith( - ipcidr: List.from(ipcidr) - ..add(value), + ipcidr: List.from(ipcidr)..add(value), ), ); }, @@ -759,7 +750,7 @@ class DomainItem extends StatelessWidget { widget: Selector>( selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.domain, shouldRebuild: (prev, next) => - !const ListEquality().equals(prev, next), + !const ListEquality().equals(prev, next), builder: (_, domain, __) { return UpdatePage( title: appLocalizations.domain, @@ -770,8 +761,7 @@ class DomainItem extends StatelessWidget { final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( fallbackFilter: dns.fallbackFilter.copyWith( - domain: List.from(domain) - ..remove(value), + domain: List.from(domain)..remove(value), ), ); }, @@ -780,8 +770,7 @@ class DomainItem extends StatelessWidget { final dns = clashConfig.dns; clashConfig.dns = dns.copyWith( fallbackFilter: dns.fallbackFilter.copyWith( - domain: List.from(domain) - ..add(value), + domain: List.from(domain)..add(value), ), ); }, diff --git a/lib/fragments/dashboard/status_switch.dart b/lib/fragments/dashboard/status_switch.dart index b9f39af..37f6459 100644 --- a/lib/fragments/dashboard/status_switch.dart +++ b/lib/fragments/dashboard/status_switch.dart @@ -47,14 +47,16 @@ class TUNSwitch extends StatelessWidget { child: 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, - ); - }, + return LocaleBuilder( + builder: (_) => Switch( + value: enable, + onChanged: (value) { + final clashConfig = globalState.appController.clashConfig; + clashConfig.tun = clashConfig.tun.copyWith( + enable: value, + ); + }, + ), ); }, ), @@ -75,14 +77,16 @@ class ProxySwitch extends StatelessWidget { child: Selector( selector: (_, config) => config.desktopProps.systemProxy, builder: (_, systemProxy, __) { - return Switch( - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - value: systemProxy, - onChanged: (value) { - final config = globalState.appController.config; - config.desktopProps = - config.desktopProps.copyWith(systemProxy: value); - }, + return LocaleBuilder( + builder: (_) => Switch( + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + value: systemProxy, + onChanged: (value) { + final config = globalState.appController.config; + config.desktopProps = + config.desktopProps.copyWith(systemProxy: value); + }, + ), ); }, ), diff --git a/lib/fragments/hotkey.dart b/lib/fragments/hotkey.dart new file mode 100644 index 0000000..b11e84a --- /dev/null +++ b/lib/fragments/hotkey.dart @@ -0,0 +1,250 @@ +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/card.dart'; +import 'package:fl_clash/widgets/list.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; + +extension IntlExt on Intl { + static actionMessage(String messageText) => + Intl.message("action_$messageText"); +} + +class HotKeyFragment extends StatelessWidget { + const HotKeyFragment({super.key}); + + String getSubtitle(HotKeyAction hotKeyAction) { + final key = hotKeyAction.key; + if (key == null) { + return appLocalizations.noHotKey; + } + final modifierLabels = + hotKeyAction.modifiers.map((item) => item.physicalKeys.first.label); + var text = ""; + if (modifierLabels.isNotEmpty) { + text += "${modifierLabels.join(" ")}+"; + } + text += PhysicalKeyboardKey(key).label; + return text; + } + + @override + Widget build(BuildContext context) { + return ListView.builder( + 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 ListItem( + title: Text(IntlExt.actionMessage(hotAction.name)), + subtitle: Text( + getSubtitle(value), + style: context.textTheme.bodyMedium + ?.copyWith(color: context.colorScheme.primary), + ), + onTap: () { + globalState.showCommonDialog( + child: HotKeyRecorder( + hotKeyAction: value, + ), + ); + }, + ); + }, + ); + }, + ); + } +} + +class HotKeyRecorder extends StatefulWidget { + final HotKeyAction hotKeyAction; + + const HotKeyRecorder({ + super.key, + required this.hotKeyAction, + }); + + @override + State createState() => _HotKeyRecorderState(); +} + +class _HotKeyRecorderState extends State { + late ValueNotifier hotKeyActionNotifier; + + @override + void initState() { + super.initState(); + hotKeyActionNotifier = ValueNotifier( + widget.hotKeyAction.copyWith(), + ); + HardwareKeyboard.instance.addHandler(_handleKeyEvent); + } + + bool _handleKeyEvent(KeyEvent keyEvent) { + if (keyEvent is KeyUpEvent) return false; + final keys = HardwareKeyboard.instance.physicalKeysPressed; + + final key = keyEvent.physicalKey; + + final modifiers = KeyboardModifier.values + .where((e) => + e.physicalKeys.any(keys.contains) && !e.physicalKeys.contains(key)) + .toSet(); + hotKeyActionNotifier.value = hotKeyActionNotifier.value.copyWith( + modifiers: modifiers, + key: key.usbHidUsage, + ); + return true; + } + + @override + void dispose() { + HardwareKeyboard.instance.removeHandler(_handleKeyEvent); + super.dispose(); + } + + _handleRemove() { + Navigator.of(context).pop(); + final config = globalState.appController.config; + config.updateOrAddHotKeyAction( + hotKeyActionNotifier.value.copyWith( + modifiers: {}, + key: null, + ), + ); + } + + _handleConfirm() { + Navigator.of(context).pop(); + final config = globalState.appController.config; + final currentHotkeyAction = hotKeyActionNotifier.value; + if (currentHotkeyAction.key == null || + currentHotkeyAction.modifiers.isEmpty) { + globalState.showMessage( + title: appLocalizations.tip, + message: TextSpan(text: appLocalizations.inputCorrectHotkey), + ); + return; + } + final hotKeyActions = config.hotKeyActions; + final index = hotKeyActions.indexWhere( + (item) => + item.key == currentHotkeyAction.key && + keyboardModifiersEquality.equals( + item.modifiers, + currentHotkeyAction.modifiers, + ), + ); + if (index != -1) { + globalState.showMessage( + title: appLocalizations.tip, + message: TextSpan(text: appLocalizations.hotkeyConflict), + ); + return; + } + config.updateOrAddHotKeyAction( + currentHotkeyAction, + ); + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text(IntlExt.actionMessage((widget.hotKeyAction.action.name))), + content: ValueListenableBuilder( + valueListenable: hotKeyActionNotifier, + builder: (_, hotKeyAction, ___) { + final key = hotKeyAction.key; + final modifiers = hotKeyAction.modifiers; + return SizedBox( + width: dialogCommonWidth, + child: key != null + ? Wrap( + spacing: 8, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + for (final modifier in modifiers) + KeyboardKeyBox( + keyboardKey: modifier.physicalKeys.first, + ), + if (modifiers.isNotEmpty) + Text( + "+", + style: context.textTheme.titleMedium, + ), + KeyboardKeyBox( + keyboardKey: PhysicalKeyboardKey(key), + ), + ], + ) + : Text( + appLocalizations.pressKeyboard, + style: context.textTheme.titleMedium, + ), + ); + }, + ), + actions: [ + TextButton( + onPressed: () { + _handleRemove(); + }, + child: Text(appLocalizations.remove), + ), + const SizedBox( + width: 8, + ), + TextButton( + onPressed: () { + _handleConfirm(); + }, + child: Text( + appLocalizations.confirm, + ), + ), + ], + ); + } +} + +class KeyboardKeyBox extends StatelessWidget { + final KeyboardKey keyboardKey; + + const KeyboardKeyBox({ + super.key, + required this.keyboardKey, + }); + + @override + Widget build(BuildContext context) { + return CommonCard( + type: CommonCardType.filled, + child: Padding( + padding: const EdgeInsets.all(12), + child: Text( + keyboardKey.label, + style: const TextStyle( + fontSize: 16, + ), + ), + ), + onPressed: () {}, + ); + } +} diff --git a/lib/fragments/profiles/profiles.dart b/lib/fragments/profiles/profiles.dart index 6bd30cd..e4e2b96 100644 --- a/lib/fragments/profiles/profiles.dart +++ b/lib/fragments/profiles/profiles.dart @@ -497,17 +497,17 @@ class _ReorderableProfilesState extends State { ), Container( padding: const EdgeInsets.symmetric( - vertical: 8, + vertical: 16, horizontal: 24, ), - child: FilledButton( + child: FilledButton.tonal( onPressed: () { Navigator.of(context).pop(); globalState.appController.config.profiles = profiles; }, style: ButtonStyle( padding: WidgetStateProperty.all( - const EdgeInsets.symmetric(vertical: 16), + const EdgeInsets.symmetric(vertical: 8), ), ), child: Row( diff --git a/lib/fragments/proxies/card.dart b/lib/fragments/proxies/card.dart index d51fc9f..3505dcf 100644 --- a/lib/fragments/proxies/card.dart +++ b/lib/fragments/proxies/card.dart @@ -25,6 +25,10 @@ class ProxyCard extends StatelessWidget { Measure get measure => globalState.measure; + _handleTestCurrentDelay() { + proxyDelayTest(proxy); + } + Widget _buildDelayText() { return SizedBox( height: measure.labelSmallHeight, @@ -36,24 +40,31 @@ class ProxyCard extends StatelessWidget { return FadeBox( child: Builder( builder: (_) { - if (delay == null) { - return Container(); - } - if (delay == 0) { + if (delay == 0 || delay == null) { return SizedBox( height: measure.labelSmallHeight, width: measure.labelSmallHeight, - child: const CircularProgressIndicator( - strokeWidth: 2, - ), + child: delay == 0 + ? const CircularProgressIndicator( + strokeWidth: 2, + ) + : IconButton( + icon: const Icon(Icons.bolt), + iconSize: globalState.measure.labelSmallHeight, + padding: EdgeInsets.zero, + onPressed: _handleTestCurrentDelay, + ), ); } - return Text( - delay > 0 ? '$delay ms' : "Timeout", - style: context.textTheme.labelSmall?.copyWith( - overflow: TextOverflow.ellipsis, - color: other.getDelayColor( - delay, + return GestureDetector( + onTap: _handleTestCurrentDelay, + child: Text( + delay > 0 ? '$delay ms' : "Timeout", + style: context.textTheme.labelSmall?.copyWith( + overflow: TextOverflow.ellipsis, + color: other.getDelayColor( + delay, + ), ), ), ); diff --git a/lib/fragments/proxies/common.dart b/lib/fragments/proxies/common.dart index 1d75326..46a4feb 100644 --- a/lib/fragments/proxies/common.dart +++ b/lib/fragments/proxies/common.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import 'package:fl_clash/clash/clash.dart'; import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/enum/enum.dart'; @@ -40,10 +38,26 @@ double getItemHeight(ProxyCardType proxyCardType) { }; } +proxyDelayTest(Proxy proxy) async { + final appController = globalState.appController; + final proxyName = appController.appState.getRealProxyName(proxy.name); + globalState.appController.setDelay( + Delay( + name: proxyName, + value: 0, + ), + ); + globalState.appController.setDelay(await clashCore.getDelay(proxyName)); +} + delayTest(List proxies) async { final appController = globalState.appController; - final delayProxies = proxies.map((proxy) async { - final proxyName = appController.appState.getRealProxyName(proxy.name); + final proxyNames = proxies + .map((proxy) => appController.appState.getRealProxyName(proxy.name)) + .toSet() + .toList(); + + final delayProxies = proxyNames.map((proxyName) async { globalState.appController.setDelay( Delay( name: proxyName, @@ -76,5 +90,5 @@ double getScrollToSelectedOffset({ ); final selectedIndex = findSelectedIndex != -1 ? findSelectedIndex : 0; final rows = (selectedIndex / columns).floor(); - return max(rows * (getItemHeight(proxyCardType) + 8) - 8, 0); + return rows * getItemHeight(proxyCardType) + (rows - 1) * 8; } diff --git a/lib/fragments/proxies/list.dart b/lib/fragments/proxies/list.dart index d4ee902..978c27e 100644 --- a/lib/fragments/proxies/list.dart +++ b/lib/fragments/proxies/list.dart @@ -1,11 +1,13 @@ +import 'dart:math'; + import 'package:cached_network_image/cached_network_image.dart'; 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/state.dart'; +import 'package:fl_clash/widgets/builder.dart'; import 'package:fl_clash/widgets/card.dart'; -import 'package:fl_clash/widgets/fade_box.dart'; import 'package:fl_clash/widgets/text.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -219,11 +221,15 @@ class _ProxiesListFragmentState extends State { final currentInitOffset = _headerOffset[index]; final proxies = _lastGroupNameProxiesMap[groupName]; _controller.animateTo( - currentInitOffset + - getScrollToSelectedOffset( - groupName: groupName, - proxies: proxies ?? [], - ), + min( + currentInitOffset + + 8 + + getScrollToSelectedOffset( + groupName: groupName, + proxies: proxies ?? [], + ), + _controller.position.maxScrollExtent, + ), duration: const Duration(milliseconds: 300), curve: Curves.easeIn, ); @@ -258,73 +264,75 @@ class _ProxiesListFragmentState extends State { return prev != next; }, builder: (_, state, __) { - final items = _buildItems( - groupNames: state.groupNames, - currentUnfoldSet: state.currentUnfoldSet, - columns: state.columns, - type: state.proxyCardType, - ); - final itemsOffset = _getItemHeightList(items, state.proxyCardType); - return Scrollbar( - controller: _controller, - thumbVisibility: true, - trackVisibility: true, - thickness: 8, - radius: const Radius.circular(8), - interactive: true, - child: Stack( - children: [ - Positioned.fill( - child: ScrollConfiguration( - behavior: HiddenBarScrollBehavior(), - child: ListView.builder( - padding: const EdgeInsets.all(16), - controller: _controller, - itemExtentBuilder: (index, __) { - return itemsOffset[index]; - }, - itemCount: items.length, - itemBuilder: (_, index) { - return items[index]; - }, + return ScaleBuilder(builder: (_) { + final items = _buildItems( + groupNames: state.groupNames, + currentUnfoldSet: state.currentUnfoldSet, + columns: state.columns, + type: state.proxyCardType, + ); + final itemsOffset = _getItemHeightList(items, state.proxyCardType); + return Scrollbar( + controller: _controller, + thumbVisibility: true, + trackVisibility: true, + thickness: 8, + radius: const Radius.circular(8), + interactive: true, + child: Stack( + children: [ + Positioned.fill( + child: ScrollConfiguration( + behavior: HiddenBarScrollBehavior(), + child: ListView.builder( + padding: const EdgeInsets.all(16), + controller: _controller, + itemExtentBuilder: (index, __) { + return itemsOffset[index]; + }, + itemCount: items.length, + itemBuilder: (_, index) { + return items[index]; + }, + ), ), ), - ), - LayoutBuilder(builder: (_, container) { - return ValueListenableBuilder( - valueListenable: _headerStateNotifier, - builder: (_, headerState, ___) { - final index = - headerState.currentIndex > state.groupNames.length - 1 - ? 0 - : headerState.currentIndex; - return Stack( - children: [ - Positioned( - top: -headerState.offset, - child: Container( - width: container.maxWidth, - color: context.colorScheme.surface, - padding: const EdgeInsets.only( - top: 16, - left: 16, - right: 16, - bottom: 8, - ), - child: _buildHeader( - groupName: state.groupNames[index], - currentUnfoldSet: state.currentUnfoldSet, + LayoutBuilder(builder: (_, container) { + return ValueListenableBuilder( + valueListenable: _headerStateNotifier, + builder: (_, headerState, ___) { + final index = + headerState.currentIndex > state.groupNames.length - 1 + ? 0 + : headerState.currentIndex; + return Stack( + children: [ + Positioned( + top: -headerState.offset, + child: Container( + width: container.maxWidth, + color: context.colorScheme.surface, + padding: const EdgeInsets.only( + top: 16, + left: 16, + right: 16, + bottom: 8, + ), + child: _buildHeader( + groupName: state.groupNames[index], + currentUnfoldSet: state.currentUnfoldSet, + ), ), ), - ), - ], - ); - }, - ); - }), - ], - ), - ); + ], + ); + }, + ); + }), + ], + ), + ); + }); }, ); } diff --git a/lib/fragments/proxies/tab.dart b/lib/fragments/proxies/tab.dart index f670dfa..5d5231e 100644 --- a/lib/fragments/proxies/tab.dart +++ b/lib/fragments/proxies/tab.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:collection/collection.dart'; import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/enum/enum.dart'; @@ -138,7 +140,7 @@ class ProxiesTabFragmentState extends State GroupNameKeyMap keyMap = {}; final children = state.groupNames.map((groupName) { keyMap[groupName] = GlobalObjectKey(groupName); - return KeepContainer( + return KeepScope( child: ProxyGroupView( key: keyMap[groupName], groupName: groupName, @@ -266,11 +268,14 @@ class ProxyGroupViewState extends State { return; } _controller.animateTo( - 16 + - getScrollToSelectedOffset( - groupName: groupName, - proxies: _lastProxies, - ), + min( + 16 + + getScrollToSelectedOffset( + groupName: groupName, + proxies: _lastProxies, + ), + _controller.position.maxScrollExtent, + ), duration: const Duration(milliseconds: 300), curve: Curves.easeIn, ); @@ -309,26 +314,33 @@ class ProxyGroupViewState extends State { }, child: Align( alignment: Alignment.topCenter, - child: GridView.builder( - controller: _controller, - padding: const EdgeInsets.all(16), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: columns, - mainAxisSpacing: 8, - crossAxisSpacing: 8, - mainAxisExtent: getItemHeight(proxyCardType), + child: ScaleBuilder( + builder: (_) => GridView.builder( + controller: _controller, + padding: const EdgeInsets.only( + top: 16, + left: 16, + right: 16, + bottom: 80, + ), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: columns, + mainAxisSpacing: 8, + crossAxisSpacing: 8, + mainAxisExtent: getItemHeight(proxyCardType), + ), + itemCount: sortedProxies.length, + itemBuilder: (_, index) { + final proxy = sortedProxies[index]; + return ProxyCard( + groupType: state.groupType, + type: proxyCardType, + key: ValueKey('$groupName.${proxy.name}'), + proxy: proxy, + groupName: groupName, + ); + }, ), - itemCount: sortedProxies.length, - itemBuilder: (_, index) { - final proxy = sortedProxies[index]; - return ProxyCard( - groupType: state.groupType, - type: proxyCardType, - key: ValueKey('$groupName.${proxy.name}'), - proxy: proxy, - groupName: groupName, - ); - }, ), ), ); diff --git a/lib/fragments/tools.dart b/lib/fragments/tools.dart index f99c39a..a83c844 100644 --- a/lib/fragments/tools.dart +++ b/lib/fragments/tools.dart @@ -5,15 +5,17 @@ import 'package:fl_clash/fragments/about.dart'; import 'package:fl_clash/fragments/access.dart'; import 'package:fl_clash/fragments/application_setting.dart'; 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/state.dart'; +import 'package:fl_clash/widgets/widgets.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; -import '../widgets/widgets.dart'; import 'backup_and_recovery.dart'; import 'theme.dart'; +import 'package:path/path.dart' show dirname, join; class ToolsFragment extends StatefulWidget { const ToolsFragment({super.key}); @@ -61,6 +63,17 @@ class _ToolboxFragmentState extends State { 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) { + system.exit(); + } + }, + ), ListItem.open( leading: const Icon(Icons.info), title: Text(appLocalizations.about), @@ -88,10 +101,7 @@ class _ToolboxFragmentState extends State { subtitle: Text(Intl.message(subTitle)), delegate: OptionsDelegate( title: appLocalizations.language, - options: [ - null, - ...AppLocalizations.delegate.supportedLocales - ], + options: [null, ...AppLocalizations.delegate.supportedLocales], onChanged: (Locale? value) { final config = context.read(); config.locale = value?.toString(); @@ -121,6 +131,28 @@ class _ToolboxFragmentState extends State { 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), @@ -155,9 +187,8 @@ class _ToolboxFragmentState extends State { @override Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.locale, - builder: (_, __, ___) { + return LocaleBuilder( + builder: (_) { final items = [ Selector( selector: (_, appState) { @@ -190,6 +221,7 @@ class _ToolboxFragmentState extends State { return ListView.builder( itemCount: items.length, itemBuilder: (_, index) => items[index], + padding: const EdgeInsets.only(bottom: 20), ); }, ); diff --git a/lib/l10n/arb/intl_en.arb b/lib/l10n/arb/intl_en.arb index e6652e6..0bbbe47 100644 --- a/lib/l10n/arb/intl_en.arb +++ b/lib/l10n/arb/intl_en.arb @@ -288,5 +288,20 @@ "ipcidr": "Ipcidr", "domain": "Domain", "resetDns": "Reset Dns", - "reset": "Reset" + "reset": "Reset", + "action_view": "Show/Hide", + "action_start": "Start/Stop", + "action_mode": "Switch mode", + "action_proxy": "System proxy", + "action_tun": "TUN", + "disclaimer": "Disclaimer", + "disclaimerDesc": "This software is only used for non-commercial purposes such as learning exchanges and scientific research. It is strictly prohibited to use this software for commercial purposes. Any commercial activity, if any, has nothing to do with this software.", + "agree": "Agree", + "hotkeyManagement": "Hotkey Management", + "hotkeyManagementDesc": "Use keyboard to control applications", + "pressKeyboard": "Please press the keyboard.", + "inputCorrectHotkey": "Please enter the correct hotkey", + "hotkeyConflict": "Hotkey conflict", + "remove": "Remove", + "noHotKey": "No HotKey" } \ 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 a53e9db..6e89c05 100644 --- a/lib/l10n/arb/intl_zh_CN.arb +++ b/lib/l10n/arb/intl_zh_CN.arb @@ -238,9 +238,9 @@ "clipboardImport": "剪贴板导入", "clipboardExport": "导出剪贴板", "layout": "布局", - "tight": "宽松", + "tight": "紧凑", "standard": "标准", - "loose": "紧凑", + "loose": "宽松", "profilesSort": "配置排序", "start": "启动", "stop": "暂停", @@ -288,5 +288,20 @@ "ipcidr": "IP/掩码", "domain": "域名", "resetDns": "重置DNS", - "reset": "重置" + "reset": "重置", + "action_view": "显示/隐藏", + "action_start": "启动/停止", + "action_mode": "切换模式", + "action_proxy": "系统代理", + "action_tun": "虚拟网卡", + "disclaimer": "免责声明", + "disclaimerDesc": "本软件仅供学习交流、科研等非商业性质的用途,严禁将本软件用于商业目的。如有任何商业行为,均与本软件无关。", + "agree": "同意", + "hotkeyManagement": "快捷键管理", + "hotkeyManagementDesc": "使用键盘控制应用程序", + "pressKeyboard": "请按下按键", + "inputCorrectHotkey": "请输入正确的快捷键", + "hotkeyConflict": "快捷键冲突", + "remove": "移除", + "noHotKey": "暂无快捷键" } \ No newline at end of file diff --git a/lib/l10n/intl/messages_en.dart b/lib/l10n/intl/messages_en.dart index 68e34a6..b086b86 100644 --- a/lib/l10n/intl/messages_en.dart +++ b/lib/l10n/intl/messages_en.dart @@ -34,6 +34,11 @@ class MessageLookup extends MessageLookupByLibrary { "accountTip": MessageLookupByLibrary.simpleMessage("Account cannot be empty"), "action": MessageLookupByLibrary.simpleMessage("Action"), + "action_mode": MessageLookupByLibrary.simpleMessage("Switch mode"), + "action_proxy": MessageLookupByLibrary.simpleMessage("System proxy"), + "action_start": MessageLookupByLibrary.simpleMessage("Start/Stop"), + "action_tun": MessageLookupByLibrary.simpleMessage("TUN"), + "action_view": MessageLookupByLibrary.simpleMessage("Show/Hide"), "add": MessageLookupByLibrary.simpleMessage("Add"), "address": MessageLookupByLibrary.simpleMessage("Address"), "addressHelp": @@ -41,6 +46,7 @@ class MessageLookup extends MessageLookupByLibrary { "addressTip": MessageLookupByLibrary.simpleMessage( "Please enter a valid WebDAV address"), "ago": MessageLookupByLibrary.simpleMessage(" Ago"), + "agree": MessageLookupByLibrary.simpleMessage("Agree"), "allApps": MessageLookupByLibrary.simpleMessage("All apps"), "allowBypass": MessageLookupByLibrary.simpleMessage( "Allow applications to bypass VPN"), @@ -130,6 +136,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."), "direct": MessageLookupByLibrary.simpleMessage("Direct"), + "disclaimer": MessageLookupByLibrary.simpleMessage("Disclaimer"), + "disclaimerDesc": MessageLookupByLibrary.simpleMessage( + "This software is only used for non-commercial purposes such as learning exchanges and scientific research. It is strictly prohibited to use this software for commercial purposes. Any commercial activity, if any, has nothing to do with this software."), "discoverNewVersion": MessageLookupByLibrary.simpleMessage("Discover the new version"), "discovery": @@ -188,12 +197,20 @@ class MessageLookup extends MessageLookupByLibrary { "go": MessageLookupByLibrary.simpleMessage("Go"), "goDownload": MessageLookupByLibrary.simpleMessage("Go to download"), "hostsDesc": MessageLookupByLibrary.simpleMessage("Add Hosts"), + "hotkeyConflict": + MessageLookupByLibrary.simpleMessage("Hotkey conflict"), + "hotkeyManagement": + MessageLookupByLibrary.simpleMessage("Hotkey Management"), + "hotkeyManagementDesc": MessageLookupByLibrary.simpleMessage( + "Use keyboard to control applications"), "hours": MessageLookupByLibrary.simpleMessage("Hours"), "importFromURL": MessageLookupByLibrary.simpleMessage("Import from URL"), "infiniteTime": MessageLookupByLibrary.simpleMessage("Long term effective"), "init": MessageLookupByLibrary.simpleMessage("Init"), + "inputCorrectHotkey": MessageLookupByLibrary.simpleMessage( + "Please enter the correct hotkey"), "intelligentSelected": MessageLookupByLibrary.simpleMessage("Intelligent selection"), "intranetIP": MessageLookupByLibrary.simpleMessage("Intranet IP"), @@ -247,6 +264,7 @@ class MessageLookup extends MessageLookupByLibrary { "networkDetection": MessageLookupByLibrary.simpleMessage("Network detection"), "networkSpeed": MessageLookupByLibrary.simpleMessage("Network speed"), + "noHotKey": MessageLookupByLibrary.simpleMessage("No HotKey"), "noInfo": MessageLookupByLibrary.simpleMessage("No info"), "noMoreInfoDesc": MessageLookupByLibrary.simpleMessage("No more info"), "noProxy": MessageLookupByLibrary.simpleMessage("No proxy"), @@ -293,6 +311,8 @@ class MessageLookup extends MessageLookupByLibrary { "port": MessageLookupByLibrary.simpleMessage("Port"), "preferH3Desc": MessageLookupByLibrary.simpleMessage( "Prioritize the use of DOH\'s http/3"), + "pressKeyboard": + MessageLookupByLibrary.simpleMessage("Please press the keyboard."), "preview": MessageLookupByLibrary.simpleMessage("Preview"), "profile": MessageLookupByLibrary.simpleMessage("Profile"), "profileAutoUpdateIntervalInvalidValidationDesc": @@ -343,6 +363,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Backup local data to WebDAV"), "remoteRecoveryDesc": MessageLookupByLibrary.simpleMessage("Recovery data from WebDAV"), + "remove": MessageLookupByLibrary.simpleMessage("Remove"), "requests": MessageLookupByLibrary.simpleMessage("Requests"), "requestsDesc": MessageLookupByLibrary.simpleMessage( "View recently request records"), diff --git a/lib/l10n/intl/messages_zh_CN.dart b/lib/l10n/intl/messages_zh_CN.dart index 07a9bbe..33fc33b 100644 --- a/lib/l10n/intl/messages_zh_CN.dart +++ b/lib/l10n/intl/messages_zh_CN.dart @@ -32,11 +32,17 @@ class MessageLookup extends MessageLookupByLibrary { "account": MessageLookupByLibrary.simpleMessage("账号"), "accountTip": MessageLookupByLibrary.simpleMessage("账号不能为空"), "action": MessageLookupByLibrary.simpleMessage("操作"), + "action_mode": MessageLookupByLibrary.simpleMessage("切换模式"), + "action_proxy": MessageLookupByLibrary.simpleMessage("系统代理"), + "action_start": MessageLookupByLibrary.simpleMessage("启动/停止"), + "action_tun": MessageLookupByLibrary.simpleMessage("虚拟网卡"), + "action_view": MessageLookupByLibrary.simpleMessage("显示/隐藏"), "add": MessageLookupByLibrary.simpleMessage("添加"), "address": MessageLookupByLibrary.simpleMessage("地址"), "addressHelp": MessageLookupByLibrary.simpleMessage("WebDAV服务器地址"), "addressTip": MessageLookupByLibrary.simpleMessage("请输入有效的WebDAV地址"), "ago": MessageLookupByLibrary.simpleMessage("前"), + "agree": MessageLookupByLibrary.simpleMessage("同意"), "allApps": MessageLookupByLibrary.simpleMessage("所有应用"), "allowBypass": MessageLookupByLibrary.simpleMessage("允许应用绕过VPN"), "allowBypassDesc": @@ -107,6 +113,9 @@ class MessageLookup extends MessageLookupByLibrary { "desc": MessageLookupByLibrary.simpleMessage( "基于ClashMeta的多平台代理客户端,简单易用,开源无广告。"), "direct": MessageLookupByLibrary.simpleMessage("直连"), + "disclaimer": MessageLookupByLibrary.simpleMessage("免责声明"), + "disclaimerDesc": MessageLookupByLibrary.simpleMessage( + "本软件仅供学习交流、科研等非商业性质的用途,严禁将本软件用于商业目的。如有任何商业行为,均与本软件无关。"), "discoverNewVersion": MessageLookupByLibrary.simpleMessage("发现新版本"), "discovery": MessageLookupByLibrary.simpleMessage("发现新版本"), "dnsDesc": MessageLookupByLibrary.simpleMessage("更新DNS相关设置"), @@ -151,10 +160,15 @@ class MessageLookup extends MessageLookupByLibrary { "go": MessageLookupByLibrary.simpleMessage("前往"), "goDownload": MessageLookupByLibrary.simpleMessage("前往下载"), "hostsDesc": MessageLookupByLibrary.simpleMessage("追加Hosts"), + "hotkeyConflict": MessageLookupByLibrary.simpleMessage("快捷键冲突"), + "hotkeyManagement": MessageLookupByLibrary.simpleMessage("快捷键管理"), + "hotkeyManagementDesc": + MessageLookupByLibrary.simpleMessage("使用键盘控制应用程序"), "hours": MessageLookupByLibrary.simpleMessage("小时"), "importFromURL": MessageLookupByLibrary.simpleMessage("从URL导入"), "infiniteTime": MessageLookupByLibrary.simpleMessage("长期有效"), "init": MessageLookupByLibrary.simpleMessage("初始化"), + "inputCorrectHotkey": MessageLookupByLibrary.simpleMessage("请输入正确的快捷键"), "intelligentSelected": MessageLookupByLibrary.simpleMessage("智能选择"), "intranetIP": MessageLookupByLibrary.simpleMessage("内网 IP"), "ipcidr": MessageLookupByLibrary.simpleMessage("IP/掩码"), @@ -178,7 +192,7 @@ class MessageLookup extends MessageLookupByLibrary { "logsDesc": MessageLookupByLibrary.simpleMessage("日志捕获记录"), "loopback": MessageLookupByLibrary.simpleMessage("回环解锁工具"), "loopbackDesc": MessageLookupByLibrary.simpleMessage("用于UWP回环解锁"), - "loose": MessageLookupByLibrary.simpleMessage("紧凑"), + "loose": MessageLookupByLibrary.simpleMessage("宽松"), "min": MessageLookupByLibrary.simpleMessage("最小"), "minimizeOnExit": MessageLookupByLibrary.simpleMessage("退出时最小化"), "minimizeOnExitDesc": @@ -196,6 +210,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("指定对应域名服务器策略"), "networkDetection": MessageLookupByLibrary.simpleMessage("网络检测"), "networkSpeed": MessageLookupByLibrary.simpleMessage("网络速度"), + "noHotKey": MessageLookupByLibrary.simpleMessage("暂无快捷键"), "noInfo": MessageLookupByLibrary.simpleMessage("暂无信息"), "noMoreInfoDesc": MessageLookupByLibrary.simpleMessage("暂无更多信息"), "noProxy": MessageLookupByLibrary.simpleMessage("暂无代理"), @@ -231,6 +246,7 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("请上传有效的二维码"), "port": MessageLookupByLibrary.simpleMessage("端口"), "preferH3Desc": MessageLookupByLibrary.simpleMessage("优先使用DOH的http/3"), + "pressKeyboard": MessageLookupByLibrary.simpleMessage("请按下按键"), "preview": MessageLookupByLibrary.simpleMessage("预览"), "profile": MessageLookupByLibrary.simpleMessage("配置"), "profileAutoUpdateIntervalInvalidValidationDesc": @@ -269,6 +285,7 @@ class MessageLookup extends MessageLookupByLibrary { "remoteBackupDesc": MessageLookupByLibrary.simpleMessage("备份数据到WebDAV"), "remoteRecoveryDesc": MessageLookupByLibrary.simpleMessage("通过WebDAV恢复数据"), + "remove": MessageLookupByLibrary.simpleMessage("移除"), "requests": MessageLookupByLibrary.simpleMessage("请求"), "requestsDesc": MessageLookupByLibrary.simpleMessage("查看最近请求记录"), "reset": MessageLookupByLibrary.simpleMessage("重置"), @@ -318,7 +335,7 @@ class MessageLookup extends MessageLookupByLibrary { "themeDesc": MessageLookupByLibrary.simpleMessage("设置深色模式,调整色彩"), "themeMode": MessageLookupByLibrary.simpleMessage("主题模式"), "threeColumns": MessageLookupByLibrary.simpleMessage("三列"), - "tight": MessageLookupByLibrary.simpleMessage("宽松"), + "tight": MessageLookupByLibrary.simpleMessage("紧凑"), "time": MessageLookupByLibrary.simpleMessage("时间"), "tip": MessageLookupByLibrary.simpleMessage("提示"), "tools": MessageLookupByLibrary.simpleMessage("工具"), diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index 693413e..6cd1388 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -2949,6 +2949,156 @@ class AppLocalizations { args: [], ); } + + /// `Show/Hide` + String get action_view { + return Intl.message( + 'Show/Hide', + name: 'action_view', + desc: '', + args: [], + ); + } + + /// `Start/Stop` + String get action_start { + return Intl.message( + 'Start/Stop', + name: 'action_start', + desc: '', + args: [], + ); + } + + /// `Switch mode` + String get action_mode { + return Intl.message( + 'Switch mode', + name: 'action_mode', + desc: '', + args: [], + ); + } + + /// `System proxy` + String get action_proxy { + return Intl.message( + 'System proxy', + name: 'action_proxy', + desc: '', + args: [], + ); + } + + /// `TUN` + String get action_tun { + return Intl.message( + 'TUN', + name: 'action_tun', + desc: '', + args: [], + ); + } + + /// `Disclaimer` + String get disclaimer { + return Intl.message( + 'Disclaimer', + name: 'disclaimer', + desc: '', + args: [], + ); + } + + /// `This software is only used for non-commercial purposes such as learning exchanges and scientific research. It is strictly prohibited to use this software for commercial purposes. Any commercial activity, if any, has nothing to do with this software.` + String get disclaimerDesc { + return Intl.message( + 'This software is only used for non-commercial purposes such as learning exchanges and scientific research. It is strictly prohibited to use this software for commercial purposes. Any commercial activity, if any, has nothing to do with this software.', + name: 'disclaimerDesc', + desc: '', + args: [], + ); + } + + /// `Agree` + String get agree { + return Intl.message( + 'Agree', + name: 'agree', + desc: '', + args: [], + ); + } + + /// `Hotkey Management` + String get hotkeyManagement { + return Intl.message( + 'Hotkey Management', + name: 'hotkeyManagement', + desc: '', + args: [], + ); + } + + /// `Use keyboard to control applications` + String get hotkeyManagementDesc { + return Intl.message( + 'Use keyboard to control applications', + name: 'hotkeyManagementDesc', + desc: '', + args: [], + ); + } + + /// `Please press the keyboard.` + String get pressKeyboard { + return Intl.message( + 'Please press the keyboard.', + name: 'pressKeyboard', + desc: '', + args: [], + ); + } + + /// `Please enter the correct hotkey` + String get inputCorrectHotkey { + return Intl.message( + 'Please enter the correct hotkey', + name: 'inputCorrectHotkey', + desc: '', + args: [], + ); + } + + /// `Hotkey conflict` + String get hotkeyConflict { + return Intl.message( + 'Hotkey conflict', + name: 'hotkeyConflict', + desc: '', + args: [], + ); + } + + /// `Remove` + String get remove { + return Intl.message( + 'Remove', + name: 'remove', + desc: '', + args: [], + ); + } + + /// `No HotKey` + String get noHotKey { + return Intl.message( + 'No HotKey', + name: 'noHotKey', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/lib/main.dart b/lib/main.dart index 09bcd42..ed0af9b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -18,13 +18,15 @@ Future main() async { WidgetsFlutterBinding.ensureInitialized(); clashCore.initMessage(); globalState.packageInfo = await PackageInfo.fromPlatform(); + final version = await system.version; final config = await preferences.getConfig() ?? Config(); globalState.autoRun = config.autoRun; final clashConfig = await preferences.getClashConfig() ?? ClashConfig(); await android?.init(); - await window?.init(config.windowProps); + await window?.init(config.windowProps, version); final appState = AppState( mode: clashConfig.mode, + version: version, isCompatible: config.isCompatible, selectedMap: config.currentSelectedMap, ); @@ -32,11 +34,6 @@ Future main() async { openLogs: config.openLogs, hasProxies: false, ); - globalState.updateTray( - appState: appState, - config: config, - clashConfig: clashConfig, - ); await globalState.init( appState: appState, config: config, @@ -56,12 +53,14 @@ Future vpnService() async { WidgetsFlutterBinding.ensureInitialized(); globalState.isVpnService = true; globalState.packageInfo = await PackageInfo.fromPlatform(); + final version = await system.version; final config = await preferences.getConfig() ?? Config(); final clashConfig = await preferences.getClashConfig() ?? ClashConfig(); final appState = AppState( mode: clashConfig.mode, isCompatible: config.isCompatible, selectedMap: config.currentSelectedMap, + version: version, ); await globalState.init( appState: appState, @@ -76,7 +75,7 @@ Future vpnService() async { clashCore.setFdMap(fd.id); }, onProcess: (Process process) async { - final packageName = await app?.resolverProcess(process); + final packageName = await vpn?.resolverProcess(process); clashCore.setProcessMap( ProcessMapItem( id: process.id, diff --git a/lib/widgets/android_container.dart b/lib/manager/android_manager.dart similarity index 68% rename from lib/widgets/android_container.dart rename to lib/manager/android_manager.dart index 0111af9..aed6fed 100644 --- a/lib/widgets/android_container.dart +++ b/lib/manager/android_manager.dart @@ -5,20 +5,25 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; -class AndroidContainer extends StatefulWidget { +class AndroidManager extends StatefulWidget { final Widget child; - const AndroidContainer({ + const AndroidManager({ super.key, required this.child, }); @override - State createState() => _AndroidContainerState(); + State createState() => _AndroidContainerState(); } -class _AndroidContainerState extends State - with WidgetsBindingObserver { +class _AndroidContainerState extends State { + @override + void initState() { + SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); + super.initState(); + } + Widget _excludeContainer(Widget child) { return Selector( selector: (_, config) => config.isExclude, @@ -44,31 +49,10 @@ class _AndroidContainerState extends State ); } - @override - void initState() { - super.initState(); - SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); - WidgetsBinding.instance.addObserver(this); - } - - @override - Future didChangeAppLifecycleState(AppLifecycleState state) async { - final isPaused = state == AppLifecycleState.paused; - if (isPaused) { - await globalState.appController.savePreferences(); - } - } - @override Widget build(BuildContext context) { return _systemUiOverlayContainer( _excludeContainer(widget.child), ); } - - @override - void dispose() { - WidgetsBinding.instance.removeObserver(this); - super.dispose(); - } } diff --git a/lib/widgets/app_state_container.dart b/lib/manager/app_state_manager.dart similarity index 57% rename from lib/widgets/app_state_container.dart rename to lib/manager/app_state_manager.dart index 58a66fc..37f97c6 100644 --- a/lib/widgets/app_state_container.dart +++ b/lib/manager/app_state_manager.dart @@ -4,14 +4,20 @@ import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -class AppStateContainer extends StatelessWidget { +class AppStateManager extends StatefulWidget { final Widget child; - const AppStateContainer({ + const AppStateManager({ super.key, required this.child, }); + @override + State createState() => _AppStateManagerState(); +} + +class _AppStateManagerState extends State + with WidgetsBindingObserver { _updateNavigationsContainer(Widget child) { return Selector2( selector: (_, appState, config) { @@ -38,10 +44,36 @@ class AppStateContainer extends StatelessWidget { ); } + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addObserver(this); + } + + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + + @override + Future didChangeAppLifecycleState(AppLifecycleState state) async { + final isPaused = state == AppLifecycleState.paused; + if (isPaused) { + await globalState.appController.savePreferences(); + } + } + + @override + void didChangePlatformBrightness() { + globalState.appController.appState.brightness = + WidgetsBinding.instance.platformDispatcher.platformBrightness; + } + @override Widget build(BuildContext context) { return _updateNavigationsContainer( - child, + widget.child, ); } } diff --git a/lib/widgets/clash_container.dart b/lib/manager/clash_manager.dart similarity index 88% rename from lib/widgets/clash_container.dart rename to lib/manager/clash_manager.dart index e7da16c..543fade 100644 --- a/lib/widgets/clash_container.dart +++ b/lib/manager/clash_manager.dart @@ -5,27 +5,27 @@ import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import '../common/function.dart'; +import '../../common/function.dart'; -class ClashContainer extends StatefulWidget { +class ClashManager extends StatefulWidget { final Widget child; - const ClashContainer({ + const ClashManager({ super.key, required this.child, }); @override - State createState() => _ClashContainerState(); + State createState() => _ClashContainerState(); } -class _ClashContainerState extends State +class _ClashContainerState extends State with AppMessageListener { Function? updateClashConfigDebounce; Widget _updateContainer(Widget child) { - return Selector2( - selector: (_,config, clashConfig) => ClashConfigState( + return Selector2( + selector: (_, config, clashConfig) => ClashConfigState( overrideDns: config.overrideDns, mixedPort: clashConfig.mixedPort, allowLan: clashConfig.allowLan, @@ -45,14 +45,16 @@ class _ClashContainerState extends State rules: clashConfig.rules, globalRealUa: clashConfig.globalRealUa, ), - builder: (__, state, child) { - if (updateClashConfigDebounce == null) { - updateClashConfigDebounce = debounce(() async { + shouldRebuild: (prev, next) { + if (prev != next) { + updateClashConfigDebounce ??= debounce(() async { await globalState.appController.updateClashConfig(); }); - } else { updateClashConfigDebounce!(); } + return prev != next; + }, + builder: (__, state, child) { return child!; }, child: child, @@ -139,7 +141,7 @@ class _ClashContainerState extends State if (log.logLevel == LogLevel.error) { globalState.appController.showSnackBar(log.payload ?? ''); } - // debugPrint("$log"); + debugPrint("$log"); super.onLog(log); } diff --git a/lib/manager/hotkey_manager.dart b/lib/manager/hotkey_manager.dart new file mode 100644 index 0000000..4c70613 --- /dev/null +++ b/lib/manager/hotkey_manager.dart @@ -0,0 +1,75 @@ +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/state.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; +import 'package:hotkey_manager/hotkey_manager.dart'; +import 'package:provider/provider.dart'; + +class HotKeyManager extends StatelessWidget { + final Widget child; + + const HotKeyManager({ + super.key, + required this.child, + }); + + _handleHotKeyAction(HotAction action) async { + switch (action) { + case HotAction.mode: + globalState.appController.updateMode(); + case HotAction.start: + globalState.appController.updateStart(); + case HotAction.view: + globalState.appController.updateVisible(); + case HotAction.proxy: + globalState.appController.updateSystemProxy(); + case HotAction.tun: + globalState.appController.updateTun(); + } + } + + _updateHotKeys({ + required List hotKeyActions, + }) async { + await hotKeyManager.unregisterAll(); + final hotkeyActionHandles = hotKeyActions.where( + (hotKeyAction) { + return hotKeyAction.key != null && hotKeyAction.modifiers.isNotEmpty; + }, + ).map( + (hotKeyAction) async { + final modifiers = hotKeyAction.modifiers + .map((item) => item.toHotKeyModifier()) + .toList(); + final hotKey = HotKey( + key: PhysicalKeyboardKey(hotKeyAction.key!), + modifiers: modifiers, + ); + return await hotKeyManager.register( + hotKey, + keyDownHandler: (_) { + _handleHotKeyAction(hotKeyAction.action); + }, + ); + }, + ); + await Future.wait(hotkeyActionHandles); + } + + @override + Widget build(BuildContext context) { + return Selector>( + selector: (_, config) => config.hotKeyActions, + shouldRebuild: (prev, next) { + return !hotKeyActionsEquality.equals(prev, next); + }, + builder: (_, hotKeyActions, __) { + _updateHotKeys(hotKeyActions: hotKeyActions); + return child; + }, + child: child, + ); + } +} diff --git a/lib/manager/manager.dart b/lib/manager/manager.dart new file mode 100644 index 0000000..97d859d --- /dev/null +++ b/lib/manager/manager.dart @@ -0,0 +1,9 @@ +export 'tray_manager.dart'; +export 'window_manager.dart'; +export 'android_manager.dart'; +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'; \ No newline at end of file diff --git a/lib/manager/media_manager.dart b/lib/manager/media_manager.dart new file mode 100644 index 0000000..3f373b4 --- /dev/null +++ b/lib/manager/media_manager.dart @@ -0,0 +1,41 @@ +import 'package:fl_clash/common/common.dart'; +import 'package:fl_clash/models/config.dart'; +import 'package:fl_clash/state.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class MediaManager extends StatelessWidget { + final Widget child; + + const MediaManager({ + super.key, + required this.child, + }); + + @override + Widget build(BuildContext context) { + return Selector( + selector: (_, config) => config.scaleProps, + builder: (_, props, child) { + globalState.measure = Measure.of(context); + return child!; + // final textScaleFactor = + // WidgetsBinding.instance.platformDispatcher.textScaleFactor; + // return MediaQuery( + // data: MediaQuery.of(context).copyWith( + // textScaler: props.custom + // ? TextScaler.linear(props.scale * textScaleFactor) + // : null, + // ), + // child: Builder( + // builder: (context) { + // globalState.measure = Measure.of(context); + // return child!; + // }, + // ), + // ); + }, + child: child, + ); + } +} diff --git a/lib/widgets/proxy_container.dart b/lib/manager/proxy_manager.dart similarity index 89% rename from lib/widgets/proxy_container.dart rename to lib/manager/proxy_manager.dart index fefadac..1043c45 100644 --- a/lib/widgets/proxy_container.dart +++ b/lib/manager/proxy_manager.dart @@ -3,10 +3,10 @@ import 'package:fl_clash/models/models.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -class ProxyContainer extends StatelessWidget { +class ProxyManager extends StatelessWidget { final Widget child; - const ProxyContainer({super.key, required this.child}); + const ProxyManager({super.key, required this.child}); _updateProxy(ProxyState proxyState) { final isStart = proxyState.isStart; diff --git a/lib/widgets/tile_container.dart b/lib/manager/tile_manager.dart similarity index 76% rename from lib/widgets/tile_container.dart rename to lib/manager/tile_manager.dart index d1ea68b..d2b79ca 100644 --- a/lib/widgets/tile_container.dart +++ b/lib/manager/tile_manager.dart @@ -2,19 +2,19 @@ import 'package:fl_clash/plugins/tile.dart'; import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; -class TileContainer extends StatefulWidget { +class TileManager extends StatefulWidget { final Widget child; - const TileContainer({ + const TileManager({ super.key, required this.child, }); @override - State createState() => _TileContainerState(); + State createState() => _TileContainerState(); } -class _TileContainerState extends State with TileListener { +class _TileContainerState extends State with TileListener { @override diff --git a/lib/manager/tray_manager.dart b/lib/manager/tray_manager.dart new file mode 100755 index 0000000..49a325f --- /dev/null +++ b/lib/manager/tray_manager.dart @@ -0,0 +1,177 @@ +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/state.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import 'package:tray_manager/tray_manager.dart'; + +class TrayManager extends StatefulWidget { + final Widget child; + + const TrayManager({ + super.key, + required this.child, + }); + + @override + State createState() => _TrayContainerState(); +} + +class _TrayContainerState extends State with TrayListener { + @override + void initState() { + super.initState(); + trayManager.addListener(this); + } + + _updateSystemTray({ + required bool isStart, + required Brightness? brightness, + }) async { + if (Platform.isLinux) { + await trayManager.destroy(); + } + await trayManager.setIcon( + other.getTrayIconPath( + isStart: isStart, + brightness: brightness ?? + WidgetsBinding.instance.platformDispatcher.platformBrightness, + ), + ); + if(!Platform.isLinux){ + await trayManager.setToolTip( + appName, + ); + } + } + + _updateTray(TrayState trayState) async { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!Platform.isLinux) { + _updateSystemTray( + isStart: trayState.isStart, + brightness: trayState.brightness, + ); + } + List menuItems = []; + final showMenuItem = MenuItem( + label: appLocalizations.show, + onClick: (_) { + window?.show(); + }, + ); + menuItems.add(showMenuItem); + final startMenuItem = MenuItem.checkbox( + label: + trayState.isStart ? appLocalizations.stop : appLocalizations.start, + onClick: (_) async { + globalState.appController.updateStart(); + }, + checked: false, + ); + menuItems.add(startMenuItem); + menuItems.add(MenuItem.separator()); + for (final mode in Mode.values) { + menuItems.add( + MenuItem.checkbox( + label: Intl.message(mode.name), + onClick: (_) { + globalState.appController.clashConfig.mode = mode; + }, + checked: mode == trayState.mode, + ), + ); + } + menuItems.add(MenuItem.separator()); + if (trayState.isStart) { + menuItems.add( + MenuItem.checkbox( + label: appLocalizations.tun, + onClick: (_) { + globalState.appController.updateTun(); + }, + checked: trayState.tunEnable, + ), + ); + menuItems.add( + MenuItem.checkbox( + label: appLocalizations.systemProxy, + onClick: (_) { + globalState.appController.updateSystemProxy(); + }, + checked: trayState.systemProxy, + ), + ); + menuItems.add(MenuItem.separator()); + } + final autoStartMenuItem = MenuItem.checkbox( + label: appLocalizations.autoLaunch, + onClick: (_) async { + globalState.appController.updateAutoLaunch(); + }, + checked: trayState.autoLaunch, + ); + menuItems.add(autoStartMenuItem); + menuItems.add(MenuItem.separator()); + final exitMenuItem = MenuItem( + label: appLocalizations.exit, + onClick: (_) async { + await globalState.appController.handleExit(); + }, + ); + menuItems.add(exitMenuItem); + final menu = Menu(); + menu.items = menuItems; + trayManager.setContextMenu(menu); + if (Platform.isLinux) { + _updateSystemTray( + isStart: trayState.isStart, + brightness: trayState.brightness, + ); + } + }); + } + + @override + Widget build(BuildContext context) { + return Selector3( + selector: (_, appState, config, clashConfig) => TrayState( + mode: clashConfig.mode, + autoLaunch: config.autoLaunch, + isStart: appState.isStart, + locale: config.locale, + systemProxy: config.desktopProps.systemProxy, + tunEnable: clashConfig.tun.enable, + brightness: appState.brightness, + ), + shouldRebuild: (prev, next) { + return prev != next; + }, + builder: (_, state, child) { + _updateTray(state); + return child!; + }, + child: widget.child, + ); + } + + @override + void onTrayIconRightMouseDown() { + trayManager.popUpContextMenu(); + } + + @override + onTrayIconMouseDown() { + window?.show(); + } + + @override + dispose() { + trayManager.removeListener(this); + super.dispose(); + } +} diff --git a/lib/widgets/vpn_container.dart b/lib/manager/vpn_manager.dart similarity index 84% rename from lib/widgets/vpn_container.dart rename to lib/manager/vpn_manager.dart index d6c03ee..8f4c801 100644 --- a/lib/widgets/vpn_container.dart +++ b/lib/manager/vpn_manager.dart @@ -4,21 +4,21 @@ import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import '../common/function.dart'; +import '../../common/function.dart'; -class VpnContainer extends StatefulWidget { +class VpnManager extends StatefulWidget { final Widget child; - const VpnContainer({ + const VpnManager({ super.key, required this.child, }); @override - State createState() => _VpnContainerState(); + State createState() => _VpnContainerState(); } -class _VpnContainerState extends State { +class _VpnContainerState extends State { Function? vpnTipDebounce; showTip() { diff --git a/lib/widgets/window_container.dart b/lib/manager/window_manager.dart similarity index 85% rename from lib/widgets/window_container.dart rename to lib/manager/window_manager.dart index be93adb..15e563f 100644 --- a/lib/widgets/window_container.dart +++ b/lib/manager/window_manager.dart @@ -7,19 +7,19 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:window_manager/window_manager.dart'; -class WindowContainer extends StatefulWidget { +class WindowManager extends StatefulWidget { final Widget child; - const WindowContainer({ + const WindowManager({ super.key, required this.child, }); @override - State createState() => _WindowContainerState(); + State createState() => _WindowContainerState(); } -class _WindowContainerState extends State with WindowListener { +class _WindowContainerState extends State with WindowListener { Function? updateLaunchDebounce; _autoLaunchContainer(Widget child) { @@ -99,21 +99,30 @@ class WindowHeaderContainer extends StatelessWidget { @override Widget build(BuildContext context) { - return Stack( - children: [ - Column( + return Selector( + selector: (_, appState) => appState.version, + builder: (_, version, child) { + if (version <= 10 && Platform.isMacOS) { + return child!; + } + return Stack( children: [ - SizedBox( - height: kHeaderHeight, - ), - Expanded( - flex: 1, - child: child, + Column( + children: [ + SizedBox( + height: kHeaderHeight, + ), + Expanded( + flex: 1, + child: child!, + ), + ], ), + const WindowHeader(), ], - ), - const WindowHeader(), - ], + ); + }, + child: child, ); } } @@ -240,14 +249,20 @@ class _WindowHeaderState extends State { ), ), ), - const Positioned( - left: 0, - child: AppIcon(), - ), - Positioned( - right: 0, - child: _buildActions(), - ), + if (Platform.isMacOS) + const Text( + appName, + ) + else ...[ + const Positioned( + left: 0, + child: AppIcon(), + ), + Positioned( + right: 0, + child: _buildActions(), + ), + ] ], ), ); diff --git a/lib/models/app.dart b/lib/models/app.dart index a26da67..e8cb09d 100644 --- a/lib/models/app.dart +++ b/lib/models/app.dart @@ -4,16 +4,9 @@ import 'package:collection/collection.dart'; import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/enum/enum.dart'; import 'package:flutter/material.dart'; -import 'connection.dart'; +import 'common.dart'; import 'ffi.dart'; -import 'log.dart'; -import 'navigation.dart'; -import 'package.dart'; import 'profile.dart'; -import 'proxy.dart'; -import 'system_color_scheme.dart'; -import 'traffic.dart'; -import 'version.dart'; typedef DelayMap = Map; @@ -38,11 +31,14 @@ class AppState with ChangeNotifier { num _checkIpNum; List _providers; List _packages; + Brightness? _brightness; + int _version; AppState({ required Mode mode, required bool isCompatible, required SelectedMap selectedMap, + required int version, }) : _navigationItems = [], _isInit = false, _currentLabel = "dashboard", @@ -54,13 +50,15 @@ class AppState with ChangeNotifier { _checkIpNum = 0, _requests = [], _mode = mode, + _brightness = null, _totalTraffic = Traffic(), _delayMap = {}, _groups = [], _providers = [], _packages = [], _isCompatible = isCompatible, - _systemColorSchemes = const SystemColorSchemes(); + _systemColorSchemes = const SystemColorSchemes(), + _version = version; String get currentLabel => _currentLabel; @@ -354,7 +352,7 @@ class AppState with ChangeNotifier { } setProvider(ExternalProvider? provider) { - if(provider == null) return; + if (provider == null) return; final index = _providers.indexWhere((item) => item.name == provider.name); if (index == -1) return; _providers = List.from(_providers)..[index] = provider; @@ -366,4 +364,22 @@ class AppState with ChangeNotifier { 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(); + } + } } diff --git a/lib/models/common.dart b/lib/models/common.dart new file mode 100644 index 0000000..467aa4c --- /dev/null +++ b/lib/models/common.dart @@ -0,0 +1,438 @@ +import 'dart:convert'; +import 'dart:math'; + +import 'package:collection/collection.dart'; +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'; + +part 'generated/common.freezed.dart'; + +part 'generated/common.g.dart'; + +@freezed +class NavigationItem with _$NavigationItem { + const factory NavigationItem({ + required Icon icon, + required String label, + final String? description, + required Widget fragment, + @Default(true) bool keep, + String? path, + @Default([NavigationItemMode.mobile, NavigationItemMode.desktop]) + List modes, + }) = _NavigationItem; +} + +@freezed +class Package with _$Package { + const factory Package({ + required String packageName, + required String label, + required bool isSystem, + required int firstInstallTime, + }) = _Package; + + factory Package.fromJson(Map json) => + _$PackageFromJson(json); +} + +@freezed +class Metadata with _$Metadata { + const factory Metadata({ + required int uid, + required String network, + required String sourceIP, + required String sourcePort, + required String destinationIP, + required String destinationPort, + required String host, + required String process, + required String remoteDestination, + }) = _Metadata; + + factory Metadata.fromJson(Map json) => + _$MetadataFromJson(json); +} + +@freezed +class Connection with _$Connection { + const factory Connection({ + required String id, + num? upload, + num? download, + required DateTime start, + required Metadata metadata, + required List chains, + }) = _Connection; + + factory Connection.fromJson(Map json) => + _$ConnectionFromJson(json); +} + +@JsonSerializable() +class Log { + @JsonKey(name: "LogLevel") + LogLevel logLevel; + @JsonKey(name: "Payload") + String? payload; + DateTime _dateTime; + + Log({ + required this.logLevel, + this.payload, + }) : _dateTime = DateTime.now(); + + DateTime get dateTime => _dateTime; + + factory Log.fromJson(Map json) { + return _$LogFromJson(json); + } + + Map toJson() { + return _$LogToJson(this); + } + + @override + String toString() { + return 'Log{logLevel: $logLevel, payload: $payload, dateTime: $dateTime}'; + } +} + +@freezed +class LogsAndKeywords with _$LogsAndKeywords { + const factory LogsAndKeywords({ + @Default([]) List logs, + @Default([]) List keywords, + }) = _LogsAndKeywords; + + factory LogsAndKeywords.fromJson(Map json) => + _$LogsAndKeywordsFromJson(json); +} + +extension LogsAndKeywordsExt on LogsAndKeywords { + List get filteredLogs => logs + .where( + (log) => {log.logLevel.name}.containsAll(keywords), + ) + .toList(); +} + +@freezed +class ConnectionsAndKeywords with _$ConnectionsAndKeywords { + const factory ConnectionsAndKeywords({ + @Default([]) List connections, + @Default([]) List keywords, + }) = _ConnectionsAndKeywords; + + factory ConnectionsAndKeywords.fromJson(Map json) => + _$ConnectionsAndKeywordsFromJson(json); +} + +extension ConnectionsAndKeywordsExt on ConnectionsAndKeywords { + List get filteredConnections => connections + .where((connection) => { + ...connection.chains, + connection.metadata.process, + }.containsAll(keywords)) + .toList(); +} + +const defaultDavFileName = "backup.zip"; + +@freezed +class DAV with _$DAV { + const factory DAV({ + required String uri, + required String user, + required String password, + @Default(defaultDavFileName) String fileName, + }) = _DAV; + + factory DAV.fromJson(Map json) => _$DAVFromJson(json); +} + +@freezed +class FileInfo with _$FileInfo { + const factory FileInfo({ + required int size, + required DateTime lastModified, + }) = _FileInfo; +} + +extension FileInfoExt on FileInfo { + String get desc => + "${TrafficValue(value: size).show} · ${lastModified.lastUpdateTimeDesc}"; +} + +@freezed +class VersionInfo with _$VersionInfo { + const factory VersionInfo({ + @Default("") String clashName, + @Default("") String version, + }) = _VersionInfo; + + factory VersionInfo.fromJson(Map json) => + _$VersionInfoFromJson(json); +} + +class Traffic { + int id; + TrafficValue up; + TrafficValue down; + + Traffic({num? up, num? down}) + : id = DateTime.now().millisecondsSinceEpoch, + up = TrafficValue(value: up), + down = TrafficValue(value: down); + + num get speed => up.value + down.value; + + factory Traffic.fromMap(Map map) { + return Traffic( + up: map['up'], + down: map['down'], + ); + } + + @override + String toString() { + return '$up↑ $down↓'; + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Traffic && + runtimeType == other.runtimeType && + id == other.id && + up == other.up && + down == other.down; + + @override + int get hashCode => id.hashCode ^ up.hashCode ^ down.hashCode; +} + +@immutable +class TrafficValueShow { + final String value; + final TrafficUnit unit; + + const TrafficValueShow({ + required this.value, + required this.unit, + }); +} + +@immutable +class TrafficValue { + final num _value; + + const TrafficValue({num? value}) : _value = value ?? 0; + + num get value => _value; + + String get show => "$showValue $showUnit"; + + String get showValue => trafficValueShow.value; + + String get showUnit => trafficValueShow.unit.name; + + TrafficValueShow get trafficValueShow { + if (_value > pow(1024, 4)) { + return TrafficValueShow( + value: (_value / pow(1024, 4)).fixed(), + unit: TrafficUnit.TB, + ); + } + if (_value > pow(1024, 3)) { + return TrafficValueShow( + value: (_value / pow(1024, 3)).fixed(), + unit: TrafficUnit.GB, + ); + } + if (_value > pow(1024, 2)) { + return TrafficValueShow( + value: (_value / pow(1024, 2)).fixed(), unit: TrafficUnit.MB); + } + if (_value > pow(1024, 1)) { + return TrafficValueShow( + value: (_value / pow(1024, 1)).fixed(), + unit: TrafficUnit.KB, + ); + } + return TrafficValueShow( + value: _value.fixed(), + unit: TrafficUnit.B, + ); + } + + @override + String toString() { + return "$showValue$showUnit"; + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is TrafficValue && + runtimeType == other.runtimeType && + _value == other._value; + + @override + 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, + @Default("") String icon, + required String name, + }) = _Group; + + factory Group.fromJson(Map json) => _$GroupFromJson(json); +} + +extension GroupExt on Group { + String get realNow => now ?? ""; + + String getCurrentSelectedName(String proxyName) { + if (type == GroupType.URLTest) { + 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) { + if (brightness == Brightness.dark) { + return darkColorScheme != null + ? ColorScheme.fromSeed( + seedColor: darkColorScheme!.primary, + brightness: Brightness.dark, + ) + : ColorScheme.fromSeed( + seedColor: defaultPrimaryColor, + brightness: Brightness.dark, + ); + } + return lightColorScheme != null + ? ColorScheme.fromSeed(seedColor: darkColorScheme!.primary) + : ColorScheme.fromSeed(seedColor: defaultPrimaryColor); + } +} + +class IpInfo { + final String ip; + final String countryCode; + + const IpInfo({ + required this.ip, + required this.countryCode, + }); + + static IpInfo fromIpInfoIoJson(Map json) { + return switch (json) { + { + "ip": final String ip, + "country": final String country, + } => + IpInfo( + ip: ip, + countryCode: country, + ), + _ => throw const FormatException("invalid json"), + }; + } + + static IpInfo fromIpApiCoJson(Map json) { + return switch (json) { + { + "ip": final String ip, + "country_code": final String countryCode, + } => + IpInfo( + ip: ip, + countryCode: countryCode, + ), + _ => throw const FormatException("invalid json"), + }; + } + + static IpInfo fromIpSbJson(Map json) { + return switch (json) { + { + "ip": final String ip, + "country_code": final String countryCode, + } => + IpInfo( + ip: ip, + countryCode: countryCode, + ), + _ => throw const FormatException("invalid json"), + }; + } + + static IpInfo fromIpwhoIsJson(Map json) { + return switch (json) { + { + "ip": final String ip, + "country_code": final String countryCode, + } => + IpInfo( + ip: ip, + countryCode: countryCode, + ), + _ => throw const FormatException("invalid json"), + }; + } + + @override + String toString() { + return 'IpInfo{ip: $ip, countryCode: $countryCode}'; + } +} + +@freezed +class HotKeyAction with _$HotKeyAction { + const factory HotKeyAction({ + required HotAction action, + int? key, + @Default({}) Set modifiers, + }) = _HotKeyAction; + + factory HotKeyAction.fromJson(Map json) => + _$HotKeyActionFromJson(json); +} + +const keyboardModifiersEquality = SetEquality(); +const hotKeyActionsEquality = ListEquality(); + diff --git a/lib/models/config.dart b/lib/models/config.dart index 43141b9..0784d1a 100644 --- a/lib/models/config.dart +++ b/lib/models/config.dart @@ -143,6 +143,8 @@ class Config extends ChangeNotifier { DesktopProps _desktopProps; bool _showLabel; bool _overrideDns; + List _hotKeyActions; + bool _isDisclaimerAccepted; Config() : _profiles = [], @@ -172,7 +174,9 @@ class Config extends ChangeNotifier { _desktopProps = const DesktopProps(), _showLabel = false, _overrideDns = false, - _scaleProps = const ScaleProps(); + _scaleProps = const ScaleProps(), + _isDisclaimerAccepted = false, + _hotKeyActions = []; deleteProfileById(String id) { _profiles = profiles.where((element) => element.id != id).toList(); @@ -597,6 +601,37 @@ class Config extends ChangeNotifier { } } + @JsonKey(defaultValue: false) + bool get isDisclaimerAccepted => _isDisclaimerAccepted; + + set isDisclaimerAccepted(bool value) { + if (_isDisclaimerAccepted != value) { + _isDisclaimerAccepted = value; + notifyListeners(); + } + } + + @JsonKey(defaultValue: []) + List get hotKeyActions => _hotKeyActions; + + set hotKeyActions(List value) { + if (_hotKeyActions != value) { + _hotKeyActions = 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, @@ -636,6 +671,7 @@ class Config extends ChangeNotifier { _vpnProps = config._vpnProps; _overrideDns = config._overrideDns; _desktopProps = config._desktopProps; + _hotKeyActions = config._hotKeyActions; } notifyListeners(); } diff --git a/lib/models/connection.dart b/lib/models/connection.dart deleted file mode 100644 index 1b2bad5..0000000 --- a/lib/models/connection.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'generated/connection.g.dart'; - -part 'generated/connection.freezed.dart'; - -@freezed -class Metadata with _$Metadata { - const factory Metadata({ - required int uid, - required String network, - required String sourceIP, - required String sourcePort, - required String destinationIP, - required String destinationPort, - required String host, - required String process, - required String remoteDestination, - }) = _Metadata; - - factory Metadata.fromJson(Map json) => - _$MetadataFromJson(json); -} - -@freezed -class Connection with _$Connection { - const factory Connection({ - required String id, - num? upload, - num? download, - required DateTime start, - required Metadata metadata, - required List chains, - }) = _Connection; - - factory Connection.fromJson(Map json) => - _$ConnectionFromJson(json); -} - -@freezed -class ConnectionsAndKeywords with _$ConnectionsAndKeywords { - const factory ConnectionsAndKeywords({ - @Default([]) List connections, - @Default([]) List keywords, - }) = _ConnectionsAndKeywords; - - factory ConnectionsAndKeywords.fromJson(Map json) => - _$ConnectionsAndKeywordsFromJson(json); -} - -extension ConnectionsAndKeywordsExt on ConnectionsAndKeywords { - List get filteredConnections => connections - .where((connection) => { - ...connection.chains, - connection.metadata.process, - }.containsAll(keywords)) - .toList(); -} diff --git a/lib/models/dav.dart b/lib/models/dav.dart deleted file mode 100644 index 2771021..0000000 --- a/lib/models/dav.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'generated/dav.g.dart'; - -part 'generated/dav.freezed.dart'; - -const defaultDavFileName = "backup.zip"; - -@freezed -class DAV with _$DAV { - const factory DAV({ - required String uri, - required String user, - required String password, - @Default(defaultDavFileName) String fileName, - }) = _DAV; - - factory DAV.fromJson(Map json) => _$DAVFromJson(json); -} diff --git a/lib/models/ffi.dart b/lib/models/ffi.dart index e304986..50b39e4 100644 --- a/lib/models/ffi.dart +++ b/lib/models/ffi.dart @@ -135,6 +135,22 @@ class ExternalProvider with _$ExternalProvider { _$ExternalProviderFromJson(json); } +@freezed +class TunProps with _$TunProps { + const factory TunProps({ + required int fd, + required String gateway, + required String gateway6, + required String portal, + required String portal6, + required String dns, + required String dns6, + }) = _TunProps; + + factory TunProps.fromJson(Map json) => + _$TunPropsFromJson(json); +} + abstract mixin class AppMessageListener { void onLog(Log log) {} diff --git a/lib/models/file.dart b/lib/models/file.dart deleted file mode 100644 index 0c3b97e..0000000 --- a/lib/models/file.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:fl_clash/common/datetime.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; - -import 'traffic.dart'; - -part 'generated/file.freezed.dart'; - -@freezed -class FileInfo with _$FileInfo { - const factory FileInfo({ - required int size, - required DateTime lastModified, - }) = _FileInfo; -} - - -extension FileInfoExt on FileInfo{ - String get desc => "${TrafficValue(value: size).show} · ${lastModified.lastUpdateTimeDesc}"; -} - - diff --git a/lib/models/generated/common.freezed.dart b/lib/models/generated/common.freezed.dart new file mode 100644 index 0000000..60769ba --- /dev/null +++ b/lib/models/generated/common.freezed.dart @@ -0,0 +1,2470 @@ +// 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 '../common.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 _$NavigationItem { + Icon get icon => throw _privateConstructorUsedError; + String get label => throw _privateConstructorUsedError; + String? get description => throw _privateConstructorUsedError; + Widget get fragment => throw _privateConstructorUsedError; + bool get keep => throw _privateConstructorUsedError; + String? get path => throw _privateConstructorUsedError; + List get modes => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $NavigationItemCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $NavigationItemCopyWith<$Res> { + factory $NavigationItemCopyWith( + NavigationItem value, $Res Function(NavigationItem) then) = + _$NavigationItemCopyWithImpl<$Res, NavigationItem>; + @useResult + $Res call( + {Icon icon, + String label, + String? description, + Widget fragment, + bool keep, + String? path, + List modes}); +} + +/// @nodoc +class _$NavigationItemCopyWithImpl<$Res, $Val extends NavigationItem> + implements $NavigationItemCopyWith<$Res> { + _$NavigationItemCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? icon = null, + Object? label = null, + Object? description = freezed, + Object? fragment = null, + Object? keep = null, + Object? path = freezed, + Object? modes = null, + }) { + return _then(_value.copyWith( + icon: null == icon + ? _value.icon + : icon // ignore: cast_nullable_to_non_nullable + as Icon, + label: null == label + ? _value.label + : label // ignore: cast_nullable_to_non_nullable + as String, + description: freezed == description + ? _value.description + : description // ignore: cast_nullable_to_non_nullable + as String?, + fragment: null == fragment + ? _value.fragment + : fragment // ignore: cast_nullable_to_non_nullable + as Widget, + keep: null == keep + ? _value.keep + : keep // ignore: cast_nullable_to_non_nullable + as bool, + path: freezed == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String?, + modes: null == modes + ? _value.modes + : modes // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$NavigationItemImplCopyWith<$Res> + implements $NavigationItemCopyWith<$Res> { + factory _$$NavigationItemImplCopyWith(_$NavigationItemImpl value, + $Res Function(_$NavigationItemImpl) then) = + __$$NavigationItemImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {Icon icon, + String label, + String? description, + Widget fragment, + bool keep, + String? path, + List modes}); +} + +/// @nodoc +class __$$NavigationItemImplCopyWithImpl<$Res> + extends _$NavigationItemCopyWithImpl<$Res, _$NavigationItemImpl> + implements _$$NavigationItemImplCopyWith<$Res> { + __$$NavigationItemImplCopyWithImpl( + _$NavigationItemImpl _value, $Res Function(_$NavigationItemImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? icon = null, + Object? label = null, + Object? description = freezed, + Object? fragment = null, + Object? keep = null, + Object? path = freezed, + Object? modes = null, + }) { + return _then(_$NavigationItemImpl( + icon: null == icon + ? _value.icon + : icon // ignore: cast_nullable_to_non_nullable + as Icon, + label: null == label + ? _value.label + : label // ignore: cast_nullable_to_non_nullable + as String, + description: freezed == description + ? _value.description + : description // ignore: cast_nullable_to_non_nullable + as String?, + fragment: null == fragment + ? _value.fragment + : fragment // ignore: cast_nullable_to_non_nullable + as Widget, + keep: null == keep + ? _value.keep + : keep // ignore: cast_nullable_to_non_nullable + as bool, + path: freezed == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String?, + modes: null == modes + ? _value._modes + : modes // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc + +class _$NavigationItemImpl implements _NavigationItem { + const _$NavigationItemImpl( + {required this.icon, + required this.label, + this.description, + required this.fragment, + this.keep = true, + this.path, + final List modes = const [ + NavigationItemMode.mobile, + NavigationItemMode.desktop + ]}) + : _modes = modes; + + @override + final Icon icon; + @override + final String label; + @override + final String? description; + @override + final Widget fragment; + @override + @JsonKey() + final bool keep; + @override + final String? path; + final List _modes; + @override + @JsonKey() + List get modes { + if (_modes is EqualUnmodifiableListView) return _modes; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_modes); + } + + @override + String toString() { + return 'NavigationItem(icon: $icon, label: $label, description: $description, fragment: $fragment, keep: $keep, path: $path, modes: $modes)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$NavigationItemImpl && + (identical(other.icon, icon) || other.icon == icon) && + (identical(other.label, label) || other.label == label) && + (identical(other.description, description) || + other.description == description) && + (identical(other.fragment, fragment) || + other.fragment == fragment) && + (identical(other.keep, keep) || other.keep == keep) && + (identical(other.path, path) || other.path == path) && + const DeepCollectionEquality().equals(other._modes, _modes)); + } + + @override + int get hashCode => Object.hash(runtimeType, icon, label, description, + fragment, keep, path, const DeepCollectionEquality().hash(_modes)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$NavigationItemImplCopyWith<_$NavigationItemImpl> get copyWith => + __$$NavigationItemImplCopyWithImpl<_$NavigationItemImpl>( + this, _$identity); +} + +abstract class _NavigationItem implements NavigationItem { + const factory _NavigationItem( + {required final Icon icon, + required final String label, + final String? description, + required final Widget fragment, + final bool keep, + final String? path, + final List modes}) = _$NavigationItemImpl; + + @override + Icon get icon; + @override + String get label; + @override + String? get description; + @override + Widget get fragment; + @override + bool get keep; + @override + String? get path; + @override + List get modes; + @override + @JsonKey(ignore: true) + _$$NavigationItemImplCopyWith<_$NavigationItemImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Package _$PackageFromJson(Map json) { + return _Package.fromJson(json); +} + +/// @nodoc +mixin _$Package { + String get packageName => throw _privateConstructorUsedError; + String get label => throw _privateConstructorUsedError; + bool get isSystem => throw _privateConstructorUsedError; + int get firstInstallTime => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $PackageCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PackageCopyWith<$Res> { + factory $PackageCopyWith(Package value, $Res Function(Package) then) = + _$PackageCopyWithImpl<$Res, Package>; + @useResult + $Res call( + {String packageName, String label, bool isSystem, int firstInstallTime}); +} + +/// @nodoc +class _$PackageCopyWithImpl<$Res, $Val extends Package> + implements $PackageCopyWith<$Res> { + _$PackageCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? packageName = null, + Object? label = null, + Object? isSystem = null, + Object? firstInstallTime = null, + }) { + return _then(_value.copyWith( + packageName: null == packageName + ? _value.packageName + : packageName // ignore: cast_nullable_to_non_nullable + as String, + label: null == label + ? _value.label + : label // ignore: cast_nullable_to_non_nullable + as String, + isSystem: null == isSystem + ? _value.isSystem + : isSystem // ignore: cast_nullable_to_non_nullable + as bool, + firstInstallTime: null == firstInstallTime + ? _value.firstInstallTime + : firstInstallTime // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$PackageImplCopyWith<$Res> implements $PackageCopyWith<$Res> { + factory _$$PackageImplCopyWith( + _$PackageImpl value, $Res Function(_$PackageImpl) then) = + __$$PackageImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String packageName, String label, bool isSystem, int firstInstallTime}); +} + +/// @nodoc +class __$$PackageImplCopyWithImpl<$Res> + extends _$PackageCopyWithImpl<$Res, _$PackageImpl> + implements _$$PackageImplCopyWith<$Res> { + __$$PackageImplCopyWithImpl( + _$PackageImpl _value, $Res Function(_$PackageImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? packageName = null, + Object? label = null, + Object? isSystem = null, + Object? firstInstallTime = null, + }) { + return _then(_$PackageImpl( + packageName: null == packageName + ? _value.packageName + : packageName // ignore: cast_nullable_to_non_nullable + as String, + label: null == label + ? _value.label + : label // ignore: cast_nullable_to_non_nullable + as String, + isSystem: null == isSystem + ? _value.isSystem + : isSystem // ignore: cast_nullable_to_non_nullable + as bool, + firstInstallTime: null == firstInstallTime + ? _value.firstInstallTime + : firstInstallTime // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$PackageImpl implements _Package { + const _$PackageImpl( + {required this.packageName, + required this.label, + required this.isSystem, + required this.firstInstallTime}); + + factory _$PackageImpl.fromJson(Map json) => + _$$PackageImplFromJson(json); + + @override + final String packageName; + @override + final String label; + @override + final bool isSystem; + @override + final int firstInstallTime; + + @override + String toString() { + return 'Package(packageName: $packageName, label: $label, isSystem: $isSystem, firstInstallTime: $firstInstallTime)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PackageImpl && + (identical(other.packageName, packageName) || + other.packageName == packageName) && + (identical(other.label, label) || other.label == label) && + (identical(other.isSystem, isSystem) || + other.isSystem == isSystem) && + (identical(other.firstInstallTime, firstInstallTime) || + other.firstInstallTime == firstInstallTime)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => + Object.hash(runtimeType, packageName, label, isSystem, firstInstallTime); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$PackageImplCopyWith<_$PackageImpl> get copyWith => + __$$PackageImplCopyWithImpl<_$PackageImpl>(this, _$identity); + + @override + Map toJson() { + return _$$PackageImplToJson( + this, + ); + } +} + +abstract class _Package implements Package { + const factory _Package( + {required final String packageName, + required final String label, + required final bool isSystem, + required final int firstInstallTime}) = _$PackageImpl; + + factory _Package.fromJson(Map json) = _$PackageImpl.fromJson; + + @override + String get packageName; + @override + String get label; + @override + bool get isSystem; + @override + int get firstInstallTime; + @override + @JsonKey(ignore: true) + _$$PackageImplCopyWith<_$PackageImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Metadata _$MetadataFromJson(Map json) { + return _Metadata.fromJson(json); +} + +/// @nodoc +mixin _$Metadata { + int get uid => throw _privateConstructorUsedError; + String get network => throw _privateConstructorUsedError; + String get sourceIP => throw _privateConstructorUsedError; + String get sourcePort => throw _privateConstructorUsedError; + String get destinationIP => throw _privateConstructorUsedError; + String get destinationPort => throw _privateConstructorUsedError; + String get host => throw _privateConstructorUsedError; + String get process => throw _privateConstructorUsedError; + String get remoteDestination => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $MetadataCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $MetadataCopyWith<$Res> { + factory $MetadataCopyWith(Metadata value, $Res Function(Metadata) then) = + _$MetadataCopyWithImpl<$Res, Metadata>; + @useResult + $Res call( + {int uid, + String network, + String sourceIP, + String sourcePort, + String destinationIP, + String destinationPort, + String host, + String process, + String remoteDestination}); +} + +/// @nodoc +class _$MetadataCopyWithImpl<$Res, $Val extends Metadata> + implements $MetadataCopyWith<$Res> { + _$MetadataCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? uid = null, + Object? network = null, + Object? sourceIP = null, + Object? sourcePort = null, + Object? destinationIP = null, + Object? destinationPort = null, + Object? host = null, + Object? process = null, + Object? remoteDestination = null, + }) { + return _then(_value.copyWith( + uid: null == uid + ? _value.uid + : uid // ignore: cast_nullable_to_non_nullable + as int, + network: null == network + ? _value.network + : network // ignore: cast_nullable_to_non_nullable + as String, + sourceIP: null == sourceIP + ? _value.sourceIP + : sourceIP // ignore: cast_nullable_to_non_nullable + as String, + sourcePort: null == sourcePort + ? _value.sourcePort + : sourcePort // ignore: cast_nullable_to_non_nullable + as String, + destinationIP: null == destinationIP + ? _value.destinationIP + : destinationIP // ignore: cast_nullable_to_non_nullable + as String, + destinationPort: null == destinationPort + ? _value.destinationPort + : destinationPort // ignore: cast_nullable_to_non_nullable + as String, + host: null == host + ? _value.host + : host // ignore: cast_nullable_to_non_nullable + as String, + process: null == process + ? _value.process + : process // ignore: cast_nullable_to_non_nullable + as String, + remoteDestination: null == remoteDestination + ? _value.remoteDestination + : remoteDestination // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$MetadataImplCopyWith<$Res> + implements $MetadataCopyWith<$Res> { + factory _$$MetadataImplCopyWith( + _$MetadataImpl value, $Res Function(_$MetadataImpl) then) = + __$$MetadataImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int uid, + String network, + String sourceIP, + String sourcePort, + String destinationIP, + String destinationPort, + String host, + String process, + String remoteDestination}); +} + +/// @nodoc +class __$$MetadataImplCopyWithImpl<$Res> + extends _$MetadataCopyWithImpl<$Res, _$MetadataImpl> + implements _$$MetadataImplCopyWith<$Res> { + __$$MetadataImplCopyWithImpl( + _$MetadataImpl _value, $Res Function(_$MetadataImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? uid = null, + Object? network = null, + Object? sourceIP = null, + Object? sourcePort = null, + Object? destinationIP = null, + Object? destinationPort = null, + Object? host = null, + Object? process = null, + Object? remoteDestination = null, + }) { + return _then(_$MetadataImpl( + uid: null == uid + ? _value.uid + : uid // ignore: cast_nullable_to_non_nullable + as int, + network: null == network + ? _value.network + : network // ignore: cast_nullable_to_non_nullable + as String, + sourceIP: null == sourceIP + ? _value.sourceIP + : sourceIP // ignore: cast_nullable_to_non_nullable + as String, + sourcePort: null == sourcePort + ? _value.sourcePort + : sourcePort // ignore: cast_nullable_to_non_nullable + as String, + destinationIP: null == destinationIP + ? _value.destinationIP + : destinationIP // ignore: cast_nullable_to_non_nullable + as String, + destinationPort: null == destinationPort + ? _value.destinationPort + : destinationPort // ignore: cast_nullable_to_non_nullable + as String, + host: null == host + ? _value.host + : host // ignore: cast_nullable_to_non_nullable + as String, + process: null == process + ? _value.process + : process // ignore: cast_nullable_to_non_nullable + as String, + remoteDestination: null == remoteDestination + ? _value.remoteDestination + : remoteDestination // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$MetadataImpl implements _Metadata { + const _$MetadataImpl( + {required this.uid, + required this.network, + required this.sourceIP, + required this.sourcePort, + required this.destinationIP, + required this.destinationPort, + required this.host, + required this.process, + required this.remoteDestination}); + + factory _$MetadataImpl.fromJson(Map json) => + _$$MetadataImplFromJson(json); + + @override + final int uid; + @override + final String network; + @override + final String sourceIP; + @override + final String sourcePort; + @override + final String destinationIP; + @override + final String destinationPort; + @override + final String host; + @override + final String process; + @override + final String remoteDestination; + + @override + String toString() { + return 'Metadata(uid: $uid, network: $network, sourceIP: $sourceIP, sourcePort: $sourcePort, destinationIP: $destinationIP, destinationPort: $destinationPort, host: $host, process: $process, remoteDestination: $remoteDestination)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$MetadataImpl && + (identical(other.uid, uid) || other.uid == uid) && + (identical(other.network, network) || other.network == network) && + (identical(other.sourceIP, sourceIP) || + other.sourceIP == sourceIP) && + (identical(other.sourcePort, sourcePort) || + other.sourcePort == sourcePort) && + (identical(other.destinationIP, destinationIP) || + other.destinationIP == destinationIP) && + (identical(other.destinationPort, destinationPort) || + other.destinationPort == destinationPort) && + (identical(other.host, host) || other.host == host) && + (identical(other.process, process) || other.process == process) && + (identical(other.remoteDestination, remoteDestination) || + other.remoteDestination == remoteDestination)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + uid, + network, + sourceIP, + sourcePort, + destinationIP, + destinationPort, + host, + process, + remoteDestination); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$MetadataImplCopyWith<_$MetadataImpl> get copyWith => + __$$MetadataImplCopyWithImpl<_$MetadataImpl>(this, _$identity); + + @override + Map toJson() { + return _$$MetadataImplToJson( + this, + ); + } +} + +abstract class _Metadata implements Metadata { + const factory _Metadata( + {required final int uid, + required final String network, + required final String sourceIP, + required final String sourcePort, + required final String destinationIP, + required final String destinationPort, + required final String host, + required final String process, + required final String remoteDestination}) = _$MetadataImpl; + + factory _Metadata.fromJson(Map json) = + _$MetadataImpl.fromJson; + + @override + int get uid; + @override + String get network; + @override + String get sourceIP; + @override + String get sourcePort; + @override + String get destinationIP; + @override + String get destinationPort; + @override + String get host; + @override + String get process; + @override + String get remoteDestination; + @override + @JsonKey(ignore: true) + _$$MetadataImplCopyWith<_$MetadataImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Connection _$ConnectionFromJson(Map json) { + return _Connection.fromJson(json); +} + +/// @nodoc +mixin _$Connection { + String get id => throw _privateConstructorUsedError; + num? get upload => throw _privateConstructorUsedError; + num? get download => throw _privateConstructorUsedError; + DateTime get start => throw _privateConstructorUsedError; + Metadata get metadata => throw _privateConstructorUsedError; + List get chains => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ConnectionCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ConnectionCopyWith<$Res> { + factory $ConnectionCopyWith( + Connection value, $Res Function(Connection) then) = + _$ConnectionCopyWithImpl<$Res, Connection>; + @useResult + $Res call( + {String id, + num? upload, + num? download, + DateTime start, + Metadata metadata, + List chains}); + + $MetadataCopyWith<$Res> get metadata; +} + +/// @nodoc +class _$ConnectionCopyWithImpl<$Res, $Val extends Connection> + implements $ConnectionCopyWith<$Res> { + _$ConnectionCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? upload = freezed, + Object? download = freezed, + Object? start = null, + Object? metadata = null, + Object? chains = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + upload: freezed == upload + ? _value.upload + : upload // ignore: cast_nullable_to_non_nullable + as num?, + download: freezed == download + ? _value.download + : download // ignore: cast_nullable_to_non_nullable + as num?, + start: null == start + ? _value.start + : start // ignore: cast_nullable_to_non_nullable + as DateTime, + metadata: null == metadata + ? _value.metadata + : metadata // ignore: cast_nullable_to_non_nullable + as Metadata, + chains: null == chains + ? _value.chains + : chains // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $MetadataCopyWith<$Res> get metadata { + return $MetadataCopyWith<$Res>(_value.metadata, (value) { + return _then(_value.copyWith(metadata: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$ConnectionImplCopyWith<$Res> + implements $ConnectionCopyWith<$Res> { + factory _$$ConnectionImplCopyWith( + _$ConnectionImpl value, $Res Function(_$ConnectionImpl) then) = + __$$ConnectionImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String id, + num? upload, + num? download, + DateTime start, + Metadata metadata, + List chains}); + + @override + $MetadataCopyWith<$Res> get metadata; +} + +/// @nodoc +class __$$ConnectionImplCopyWithImpl<$Res> + extends _$ConnectionCopyWithImpl<$Res, _$ConnectionImpl> + implements _$$ConnectionImplCopyWith<$Res> { + __$$ConnectionImplCopyWithImpl( + _$ConnectionImpl _value, $Res Function(_$ConnectionImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? upload = freezed, + Object? download = freezed, + Object? start = null, + Object? metadata = null, + Object? chains = null, + }) { + return _then(_$ConnectionImpl( + id: null == id + ? _value.id + : id // ignore: cast_nullable_to_non_nullable + as String, + upload: freezed == upload + ? _value.upload + : upload // ignore: cast_nullable_to_non_nullable + as num?, + download: freezed == download + ? _value.download + : download // ignore: cast_nullable_to_non_nullable + as num?, + start: null == start + ? _value.start + : start // ignore: cast_nullable_to_non_nullable + as DateTime, + metadata: null == metadata + ? _value.metadata + : metadata // ignore: cast_nullable_to_non_nullable + as Metadata, + chains: null == chains + ? _value._chains + : chains // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ConnectionImpl implements _Connection { + const _$ConnectionImpl( + {required this.id, + this.upload, + this.download, + required this.start, + required this.metadata, + required final List chains}) + : _chains = chains; + + factory _$ConnectionImpl.fromJson(Map json) => + _$$ConnectionImplFromJson(json); + + @override + final String id; + @override + final num? upload; + @override + final num? download; + @override + final DateTime start; + @override + final Metadata metadata; + final List _chains; + @override + List get chains { + if (_chains is EqualUnmodifiableListView) return _chains; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_chains); + } + + @override + String toString() { + return 'Connection(id: $id, upload: $upload, download: $download, start: $start, metadata: $metadata, chains: $chains)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ConnectionImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.upload, upload) || other.upload == upload) && + (identical(other.download, download) || + other.download == download) && + (identical(other.start, start) || other.start == start) && + (identical(other.metadata, metadata) || + other.metadata == metadata) && + const DeepCollectionEquality().equals(other._chains, _chains)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, id, upload, download, start, + metadata, const DeepCollectionEquality().hash(_chains)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ConnectionImplCopyWith<_$ConnectionImpl> get copyWith => + __$$ConnectionImplCopyWithImpl<_$ConnectionImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ConnectionImplToJson( + this, + ); + } +} + +abstract class _Connection implements Connection { + const factory _Connection( + {required final String id, + final num? upload, + final num? download, + required final DateTime start, + required final Metadata metadata, + required final List chains}) = _$ConnectionImpl; + + factory _Connection.fromJson(Map json) = + _$ConnectionImpl.fromJson; + + @override + String get id; + @override + num? get upload; + @override + num? get download; + @override + DateTime get start; + @override + Metadata get metadata; + @override + List get chains; + @override + @JsonKey(ignore: true) + _$$ConnectionImplCopyWith<_$ConnectionImpl> get copyWith => + throw _privateConstructorUsedError; +} + +LogsAndKeywords _$LogsAndKeywordsFromJson(Map json) { + return _LogsAndKeywords.fromJson(json); +} + +/// @nodoc +mixin _$LogsAndKeywords { + List get logs => throw _privateConstructorUsedError; + List get keywords => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $LogsAndKeywordsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $LogsAndKeywordsCopyWith<$Res> { + factory $LogsAndKeywordsCopyWith( + LogsAndKeywords value, $Res Function(LogsAndKeywords) then) = + _$LogsAndKeywordsCopyWithImpl<$Res, LogsAndKeywords>; + @useResult + $Res call({List logs, List keywords}); +} + +/// @nodoc +class _$LogsAndKeywordsCopyWithImpl<$Res, $Val extends LogsAndKeywords> + implements $LogsAndKeywordsCopyWith<$Res> { + _$LogsAndKeywordsCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? logs = null, + Object? keywords = null, + }) { + return _then(_value.copyWith( + logs: null == logs + ? _value.logs + : logs // ignore: cast_nullable_to_non_nullable + as List, + keywords: null == keywords + ? _value.keywords + : keywords // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$LogsAndKeywordsImplCopyWith<$Res> + implements $LogsAndKeywordsCopyWith<$Res> { + factory _$$LogsAndKeywordsImplCopyWith(_$LogsAndKeywordsImpl value, + $Res Function(_$LogsAndKeywordsImpl) then) = + __$$LogsAndKeywordsImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({List logs, List keywords}); +} + +/// @nodoc +class __$$LogsAndKeywordsImplCopyWithImpl<$Res> + extends _$LogsAndKeywordsCopyWithImpl<$Res, _$LogsAndKeywordsImpl> + implements _$$LogsAndKeywordsImplCopyWith<$Res> { + __$$LogsAndKeywordsImplCopyWithImpl( + _$LogsAndKeywordsImpl _value, $Res Function(_$LogsAndKeywordsImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? logs = null, + Object? keywords = null, + }) { + return _then(_$LogsAndKeywordsImpl( + logs: null == logs + ? _value._logs + : logs // ignore: cast_nullable_to_non_nullable + as List, + keywords: null == keywords + ? _value._keywords + : keywords // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$LogsAndKeywordsImpl implements _LogsAndKeywords { + const _$LogsAndKeywordsImpl( + {final List logs = const [], final List keywords = const []}) + : _logs = logs, + _keywords = keywords; + + factory _$LogsAndKeywordsImpl.fromJson(Map json) => + _$$LogsAndKeywordsImplFromJson(json); + + final List _logs; + @override + @JsonKey() + List get logs { + if (_logs is EqualUnmodifiableListView) return _logs; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_logs); + } + + final List _keywords; + @override + @JsonKey() + List get keywords { + if (_keywords is EqualUnmodifiableListView) return _keywords; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_keywords); + } + + @override + String toString() { + return 'LogsAndKeywords(logs: $logs, keywords: $keywords)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$LogsAndKeywordsImpl && + const DeepCollectionEquality().equals(other._logs, _logs) && + const DeepCollectionEquality().equals(other._keywords, _keywords)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_logs), + const DeepCollectionEquality().hash(_keywords)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$LogsAndKeywordsImplCopyWith<_$LogsAndKeywordsImpl> get copyWith => + __$$LogsAndKeywordsImplCopyWithImpl<_$LogsAndKeywordsImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$LogsAndKeywordsImplToJson( + this, + ); + } +} + +abstract class _LogsAndKeywords implements LogsAndKeywords { + const factory _LogsAndKeywords( + {final List logs, + final List keywords}) = _$LogsAndKeywordsImpl; + + factory _LogsAndKeywords.fromJson(Map json) = + _$LogsAndKeywordsImpl.fromJson; + + @override + List get logs; + @override + List get keywords; + @override + @JsonKey(ignore: true) + _$$LogsAndKeywordsImplCopyWith<_$LogsAndKeywordsImpl> get copyWith => + throw _privateConstructorUsedError; +} + +ConnectionsAndKeywords _$ConnectionsAndKeywordsFromJson( + Map json) { + return _ConnectionsAndKeywords.fromJson(json); +} + +/// @nodoc +mixin _$ConnectionsAndKeywords { + List get connections => throw _privateConstructorUsedError; + List get keywords => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ConnectionsAndKeywordsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ConnectionsAndKeywordsCopyWith<$Res> { + factory $ConnectionsAndKeywordsCopyWith(ConnectionsAndKeywords value, + $Res Function(ConnectionsAndKeywords) then) = + _$ConnectionsAndKeywordsCopyWithImpl<$Res, ConnectionsAndKeywords>; + @useResult + $Res call({List connections, List keywords}); +} + +/// @nodoc +class _$ConnectionsAndKeywordsCopyWithImpl<$Res, + $Val extends ConnectionsAndKeywords> + implements $ConnectionsAndKeywordsCopyWith<$Res> { + _$ConnectionsAndKeywordsCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? connections = null, + Object? keywords = null, + }) { + return _then(_value.copyWith( + connections: null == connections + ? _value.connections + : connections // ignore: cast_nullable_to_non_nullable + as List, + keywords: null == keywords + ? _value.keywords + : keywords // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ConnectionsAndKeywordsImplCopyWith<$Res> + implements $ConnectionsAndKeywordsCopyWith<$Res> { + factory _$$ConnectionsAndKeywordsImplCopyWith( + _$ConnectionsAndKeywordsImpl value, + $Res Function(_$ConnectionsAndKeywordsImpl) then) = + __$$ConnectionsAndKeywordsImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({List connections, List keywords}); +} + +/// @nodoc +class __$$ConnectionsAndKeywordsImplCopyWithImpl<$Res> + extends _$ConnectionsAndKeywordsCopyWithImpl<$Res, + _$ConnectionsAndKeywordsImpl> + implements _$$ConnectionsAndKeywordsImplCopyWith<$Res> { + __$$ConnectionsAndKeywordsImplCopyWithImpl( + _$ConnectionsAndKeywordsImpl _value, + $Res Function(_$ConnectionsAndKeywordsImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? connections = null, + Object? keywords = null, + }) { + return _then(_$ConnectionsAndKeywordsImpl( + connections: null == connections + ? _value._connections + : connections // ignore: cast_nullable_to_non_nullable + as List, + keywords: null == keywords + ? _value._keywords + : keywords // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ConnectionsAndKeywordsImpl implements _ConnectionsAndKeywords { + const _$ConnectionsAndKeywordsImpl( + {final List connections = const [], + final List keywords = const []}) + : _connections = connections, + _keywords = keywords; + + factory _$ConnectionsAndKeywordsImpl.fromJson(Map json) => + _$$ConnectionsAndKeywordsImplFromJson(json); + + final List _connections; + @override + @JsonKey() + List get connections { + if (_connections is EqualUnmodifiableListView) return _connections; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_connections); + } + + final List _keywords; + @override + @JsonKey() + List get keywords { + if (_keywords is EqualUnmodifiableListView) return _keywords; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_keywords); + } + + @override + String toString() { + return 'ConnectionsAndKeywords(connections: $connections, keywords: $keywords)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ConnectionsAndKeywordsImpl && + const DeepCollectionEquality() + .equals(other._connections, _connections) && + const DeepCollectionEquality().equals(other._keywords, _keywords)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, + const DeepCollectionEquality().hash(_connections), + const DeepCollectionEquality().hash(_keywords)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ConnectionsAndKeywordsImplCopyWith<_$ConnectionsAndKeywordsImpl> + get copyWith => __$$ConnectionsAndKeywordsImplCopyWithImpl< + _$ConnectionsAndKeywordsImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ConnectionsAndKeywordsImplToJson( + this, + ); + } +} + +abstract class _ConnectionsAndKeywords implements ConnectionsAndKeywords { + const factory _ConnectionsAndKeywords( + {final List connections, + final List keywords}) = _$ConnectionsAndKeywordsImpl; + + factory _ConnectionsAndKeywords.fromJson(Map json) = + _$ConnectionsAndKeywordsImpl.fromJson; + + @override + List get connections; + @override + List get keywords; + @override + @JsonKey(ignore: true) + _$$ConnectionsAndKeywordsImplCopyWith<_$ConnectionsAndKeywordsImpl> + get copyWith => throw _privateConstructorUsedError; +} + +DAV _$DAVFromJson(Map json) { + return _DAV.fromJson(json); +} + +/// @nodoc +mixin _$DAV { + String get uri => throw _privateConstructorUsedError; + String get user => throw _privateConstructorUsedError; + String get password => throw _privateConstructorUsedError; + String get fileName => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $DAVCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $DAVCopyWith<$Res> { + factory $DAVCopyWith(DAV value, $Res Function(DAV) then) = + _$DAVCopyWithImpl<$Res, DAV>; + @useResult + $Res call({String uri, String user, String password, String fileName}); +} + +/// @nodoc +class _$DAVCopyWithImpl<$Res, $Val extends DAV> implements $DAVCopyWith<$Res> { + _$DAVCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? uri = null, + Object? user = null, + Object? password = null, + Object? fileName = null, + }) { + return _then(_value.copyWith( + uri: null == uri + ? _value.uri + : uri // ignore: cast_nullable_to_non_nullable + as String, + user: null == user + ? _value.user + : user // ignore: cast_nullable_to_non_nullable + as String, + password: null == password + ? _value.password + : password // ignore: cast_nullable_to_non_nullable + as String, + fileName: null == fileName + ? _value.fileName + : fileName // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$DAVImplCopyWith<$Res> implements $DAVCopyWith<$Res> { + factory _$$DAVImplCopyWith(_$DAVImpl value, $Res Function(_$DAVImpl) then) = + __$$DAVImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String uri, String user, String password, String fileName}); +} + +/// @nodoc +class __$$DAVImplCopyWithImpl<$Res> extends _$DAVCopyWithImpl<$Res, _$DAVImpl> + implements _$$DAVImplCopyWith<$Res> { + __$$DAVImplCopyWithImpl(_$DAVImpl _value, $Res Function(_$DAVImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? uri = null, + Object? user = null, + Object? password = null, + Object? fileName = null, + }) { + return _then(_$DAVImpl( + uri: null == uri + ? _value.uri + : uri // ignore: cast_nullable_to_non_nullable + as String, + user: null == user + ? _value.user + : user // ignore: cast_nullable_to_non_nullable + as String, + password: null == password + ? _value.password + : password // ignore: cast_nullable_to_non_nullable + as String, + fileName: null == fileName + ? _value.fileName + : fileName // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$DAVImpl implements _DAV { + const _$DAVImpl( + {required this.uri, + required this.user, + required this.password, + this.fileName = defaultDavFileName}); + + factory _$DAVImpl.fromJson(Map json) => + _$$DAVImplFromJson(json); + + @override + final String uri; + @override + final String user; + @override + final String password; + @override + @JsonKey() + final String fileName; + + @override + String toString() { + return 'DAV(uri: $uri, user: $user, password: $password, fileName: $fileName)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$DAVImpl && + (identical(other.uri, uri) || other.uri == uri) && + (identical(other.user, user) || other.user == user) && + (identical(other.password, password) || + other.password == password) && + (identical(other.fileName, fileName) || + other.fileName == fileName)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, uri, user, password, fileName); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$DAVImplCopyWith<_$DAVImpl> get copyWith => + __$$DAVImplCopyWithImpl<_$DAVImpl>(this, _$identity); + + @override + Map toJson() { + return _$$DAVImplToJson( + this, + ); + } +} + +abstract class _DAV implements DAV { + const factory _DAV( + {required final String uri, + required final String user, + required final String password, + final String fileName}) = _$DAVImpl; + + factory _DAV.fromJson(Map json) = _$DAVImpl.fromJson; + + @override + String get uri; + @override + String get user; + @override + String get password; + @override + String get fileName; + @override + @JsonKey(ignore: true) + _$$DAVImplCopyWith<_$DAVImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +mixin _$FileInfo { + int get size => throw _privateConstructorUsedError; + DateTime get lastModified => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $FileInfoCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $FileInfoCopyWith<$Res> { + factory $FileInfoCopyWith(FileInfo value, $Res Function(FileInfo) then) = + _$FileInfoCopyWithImpl<$Res, FileInfo>; + @useResult + $Res call({int size, DateTime lastModified}); +} + +/// @nodoc +class _$FileInfoCopyWithImpl<$Res, $Val extends FileInfo> + implements $FileInfoCopyWith<$Res> { + _$FileInfoCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? size = null, + Object? lastModified = null, + }) { + return _then(_value.copyWith( + size: null == size + ? _value.size + : size // ignore: cast_nullable_to_non_nullable + as int, + lastModified: null == lastModified + ? _value.lastModified + : lastModified // ignore: cast_nullable_to_non_nullable + as DateTime, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$FileInfoImplCopyWith<$Res> + implements $FileInfoCopyWith<$Res> { + factory _$$FileInfoImplCopyWith( + _$FileInfoImpl value, $Res Function(_$FileInfoImpl) then) = + __$$FileInfoImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({int size, DateTime lastModified}); +} + +/// @nodoc +class __$$FileInfoImplCopyWithImpl<$Res> + extends _$FileInfoCopyWithImpl<$Res, _$FileInfoImpl> + implements _$$FileInfoImplCopyWith<$Res> { + __$$FileInfoImplCopyWithImpl( + _$FileInfoImpl _value, $Res Function(_$FileInfoImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? size = null, + Object? lastModified = null, + }) { + return _then(_$FileInfoImpl( + size: null == size + ? _value.size + : size // ignore: cast_nullable_to_non_nullable + as int, + lastModified: null == lastModified + ? _value.lastModified + : lastModified // ignore: cast_nullable_to_non_nullable + as DateTime, + )); + } +} + +/// @nodoc + +class _$FileInfoImpl implements _FileInfo { + const _$FileInfoImpl({required this.size, required this.lastModified}); + + @override + final int size; + @override + final DateTime lastModified; + + @override + String toString() { + return 'FileInfo(size: $size, lastModified: $lastModified)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$FileInfoImpl && + (identical(other.size, size) || other.size == size) && + (identical(other.lastModified, lastModified) || + other.lastModified == lastModified)); + } + + @override + int get hashCode => Object.hash(runtimeType, size, lastModified); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$FileInfoImplCopyWith<_$FileInfoImpl> get copyWith => + __$$FileInfoImplCopyWithImpl<_$FileInfoImpl>(this, _$identity); +} + +abstract class _FileInfo implements FileInfo { + const factory _FileInfo( + {required final int size, + required final DateTime lastModified}) = _$FileInfoImpl; + + @override + int get size; + @override + DateTime get lastModified; + @override + @JsonKey(ignore: true) + _$$FileInfoImplCopyWith<_$FileInfoImpl> get copyWith => + throw _privateConstructorUsedError; +} + +VersionInfo _$VersionInfoFromJson(Map json) { + return _VersionInfo.fromJson(json); +} + +/// @nodoc +mixin _$VersionInfo { + String get clashName => throw _privateConstructorUsedError; + String get version => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $VersionInfoCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $VersionInfoCopyWith<$Res> { + factory $VersionInfoCopyWith( + VersionInfo value, $Res Function(VersionInfo) then) = + _$VersionInfoCopyWithImpl<$Res, VersionInfo>; + @useResult + $Res call({String clashName, String version}); +} + +/// @nodoc +class _$VersionInfoCopyWithImpl<$Res, $Val extends VersionInfo> + implements $VersionInfoCopyWith<$Res> { + _$VersionInfoCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? clashName = null, + Object? version = null, + }) { + return _then(_value.copyWith( + clashName: null == clashName + ? _value.clashName + : clashName // ignore: cast_nullable_to_non_nullable + as String, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$VersionInfoImplCopyWith<$Res> + implements $VersionInfoCopyWith<$Res> { + factory _$$VersionInfoImplCopyWith( + _$VersionInfoImpl value, $Res Function(_$VersionInfoImpl) then) = + __$$VersionInfoImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String clashName, String version}); +} + +/// @nodoc +class __$$VersionInfoImplCopyWithImpl<$Res> + extends _$VersionInfoCopyWithImpl<$Res, _$VersionInfoImpl> + implements _$$VersionInfoImplCopyWith<$Res> { + __$$VersionInfoImplCopyWithImpl( + _$VersionInfoImpl _value, $Res Function(_$VersionInfoImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? clashName = null, + Object? version = null, + }) { + return _then(_$VersionInfoImpl( + clashName: null == clashName + ? _value.clashName + : clashName // ignore: cast_nullable_to_non_nullable + as String, + version: null == version + ? _value.version + : version // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$VersionInfoImpl implements _VersionInfo { + const _$VersionInfoImpl({this.clashName = "", this.version = ""}); + + factory _$VersionInfoImpl.fromJson(Map json) => + _$$VersionInfoImplFromJson(json); + + @override + @JsonKey() + final String clashName; + @override + @JsonKey() + final String version; + + @override + String toString() { + return 'VersionInfo(clashName: $clashName, version: $version)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$VersionInfoImpl && + (identical(other.clashName, clashName) || + other.clashName == clashName) && + (identical(other.version, version) || other.version == version)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, clashName, version); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$VersionInfoImplCopyWith<_$VersionInfoImpl> get copyWith => + __$$VersionInfoImplCopyWithImpl<_$VersionInfoImpl>(this, _$identity); + + @override + Map toJson() { + return _$$VersionInfoImplToJson( + this, + ); + } +} + +abstract class _VersionInfo implements VersionInfo { + const factory _VersionInfo({final String clashName, final String version}) = + _$VersionInfoImpl; + + factory _VersionInfo.fromJson(Map json) = + _$VersionInfoImpl.fromJson; + + @override + String get clashName; + @override + String get version; + @override + @JsonKey(ignore: true) + _$$VersionInfoImplCopyWith<_$VersionInfoImpl> get copyWith => + throw _privateConstructorUsedError; +} + +Group _$GroupFromJson(Map json) { + return _Group.fromJson(json); +} + +/// @nodoc +mixin _$Group { + GroupType get type => throw _privateConstructorUsedError; + List get all => throw _privateConstructorUsedError; + String? get now => throw _privateConstructorUsedError; + bool? get hidden => throw _privateConstructorUsedError; + String get icon => throw _privateConstructorUsedError; + String get name => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $GroupCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $GroupCopyWith<$Res> { + factory $GroupCopyWith(Group value, $Res Function(Group) then) = + _$GroupCopyWithImpl<$Res, Group>; + @useResult + $Res call( + {GroupType type, + List all, + String? now, + bool? hidden, + String icon, + String name}); +} + +/// @nodoc +class _$GroupCopyWithImpl<$Res, $Val extends Group> + implements $GroupCopyWith<$Res> { + _$GroupCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? type = null, + Object? all = null, + Object? now = freezed, + Object? hidden = freezed, + Object? icon = null, + Object? name = null, + }) { + return _then(_value.copyWith( + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as GroupType, + all: null == all + ? _value.all + : all // ignore: cast_nullable_to_non_nullable + as List, + now: freezed == now + ? _value.now + : now // ignore: cast_nullable_to_non_nullable + as String?, + hidden: freezed == hidden + ? _value.hidden + : hidden // ignore: cast_nullable_to_non_nullable + as bool?, + icon: null == icon + ? _value.icon + : icon // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$GroupImplCopyWith<$Res> implements $GroupCopyWith<$Res> { + factory _$$GroupImplCopyWith( + _$GroupImpl value, $Res Function(_$GroupImpl) then) = + __$$GroupImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {GroupType type, + List all, + String? now, + bool? hidden, + String icon, + String name}); +} + +/// @nodoc +class __$$GroupImplCopyWithImpl<$Res> + extends _$GroupCopyWithImpl<$Res, _$GroupImpl> + implements _$$GroupImplCopyWith<$Res> { + __$$GroupImplCopyWithImpl( + _$GroupImpl _value, $Res Function(_$GroupImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? type = null, + Object? all = null, + Object? now = freezed, + Object? hidden = freezed, + Object? icon = null, + Object? name = null, + }) { + return _then(_$GroupImpl( + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as GroupType, + all: null == all + ? _value._all + : all // ignore: cast_nullable_to_non_nullable + as List, + now: freezed == now + ? _value.now + : now // ignore: cast_nullable_to_non_nullable + as String?, + hidden: freezed == hidden + ? _value.hidden + : hidden // ignore: cast_nullable_to_non_nullable + as bool?, + icon: null == icon + ? _value.icon + : icon // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$GroupImpl implements _Group { + const _$GroupImpl( + {required this.type, + final List all = const [], + this.now, + this.hidden, + this.icon = "", + required this.name}) + : _all = all; + + factory _$GroupImpl.fromJson(Map json) => + _$$GroupImplFromJson(json); + + @override + final GroupType type; + final List _all; + @override + @JsonKey() + List get all { + if (_all is EqualUnmodifiableListView) return _all; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_all); + } + + @override + final String? now; + @override + final bool? hidden; + @override + @JsonKey() + final String icon; + @override + final String name; + + @override + String toString() { + return 'Group(type: $type, all: $all, now: $now, hidden: $hidden, icon: $icon, name: $name)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$GroupImpl && + (identical(other.type, type) || other.type == type) && + const DeepCollectionEquality().equals(other._all, _all) && + (identical(other.now, now) || other.now == now) && + (identical(other.hidden, hidden) || other.hidden == hidden) && + (identical(other.icon, icon) || other.icon == icon) && + (identical(other.name, name) || other.name == name)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, type, + const DeepCollectionEquality().hash(_all), now, hidden, icon, name); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$GroupImplCopyWith<_$GroupImpl> get copyWith => + __$$GroupImplCopyWithImpl<_$GroupImpl>(this, _$identity); + + @override + Map toJson() { + return _$$GroupImplToJson( + this, + ); + } +} + +abstract class _Group implements Group { + const factory _Group( + {required final GroupType type, + final List all, + final String? now, + final bool? hidden, + final String icon, + required final String name}) = _$GroupImpl; + + factory _Group.fromJson(Map json) = _$GroupImpl.fromJson; + + @override + GroupType get type; + @override + List get all; + @override + String? get now; + @override + bool? get hidden; + @override + String get icon; + @override + String get name; + @override + @JsonKey(ignore: true) + _$$GroupImplCopyWith<_$GroupImpl> get copyWith => + 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; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $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; + + @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); + + @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(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, name, type, now); + + @JsonKey(ignore: true) + @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; + @override + @JsonKey(ignore: true) + _$$ProxyImplCopyWith<_$ProxyImpl> get copyWith => + throw _privateConstructorUsedError; +} + +HotKeyAction _$HotKeyActionFromJson(Map json) { + return _HotKeyAction.fromJson(json); +} + +/// @nodoc +mixin _$HotKeyAction { + HotAction get action => throw _privateConstructorUsedError; + int? get key => throw _privateConstructorUsedError; + Set get modifiers => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $HotKeyActionCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $HotKeyActionCopyWith<$Res> { + factory $HotKeyActionCopyWith( + HotKeyAction value, $Res Function(HotKeyAction) then) = + _$HotKeyActionCopyWithImpl<$Res, HotKeyAction>; + @useResult + $Res call({HotAction action, int? key, Set modifiers}); +} + +/// @nodoc +class _$HotKeyActionCopyWithImpl<$Res, $Val extends HotKeyAction> + implements $HotKeyActionCopyWith<$Res> { + _$HotKeyActionCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? action = null, + Object? key = freezed, + Object? modifiers = null, + }) { + return _then(_value.copyWith( + action: null == action + ? _value.action + : action // ignore: cast_nullable_to_non_nullable + as HotAction, + key: freezed == key + ? _value.key + : key // ignore: cast_nullable_to_non_nullable + as int?, + modifiers: null == modifiers + ? _value.modifiers + : modifiers // ignore: cast_nullable_to_non_nullable + as Set, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$HotKeyActionImplCopyWith<$Res> + implements $HotKeyActionCopyWith<$Res> { + factory _$$HotKeyActionImplCopyWith( + _$HotKeyActionImpl value, $Res Function(_$HotKeyActionImpl) then) = + __$$HotKeyActionImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({HotAction action, int? key, Set modifiers}); +} + +/// @nodoc +class __$$HotKeyActionImplCopyWithImpl<$Res> + extends _$HotKeyActionCopyWithImpl<$Res, _$HotKeyActionImpl> + implements _$$HotKeyActionImplCopyWith<$Res> { + __$$HotKeyActionImplCopyWithImpl( + _$HotKeyActionImpl _value, $Res Function(_$HotKeyActionImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? action = null, + Object? key = freezed, + Object? modifiers = null, + }) { + return _then(_$HotKeyActionImpl( + action: null == action + ? _value.action + : action // ignore: cast_nullable_to_non_nullable + as HotAction, + key: freezed == key + ? _value.key + : key // ignore: cast_nullable_to_non_nullable + as int?, + modifiers: null == modifiers + ? _value._modifiers + : modifiers // ignore: cast_nullable_to_non_nullable + as Set, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$HotKeyActionImpl implements _HotKeyAction { + const _$HotKeyActionImpl( + {required this.action, + this.key, + final Set modifiers = const {}}) + : _modifiers = modifiers; + + factory _$HotKeyActionImpl.fromJson(Map json) => + _$$HotKeyActionImplFromJson(json); + + @override + final HotAction action; + @override + final int? key; + final Set _modifiers; + @override + @JsonKey() + Set get modifiers { + if (_modifiers is EqualUnmodifiableSetView) return _modifiers; + // ignore: implicit_dynamic_type + return EqualUnmodifiableSetView(_modifiers); + } + + @override + String toString() { + return 'HotKeyAction(action: $action, key: $key, modifiers: $modifiers)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$HotKeyActionImpl && + (identical(other.action, action) || other.action == action) && + (identical(other.key, key) || other.key == key) && + const DeepCollectionEquality() + .equals(other._modifiers, _modifiers)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, action, key, + const DeepCollectionEquality().hash(_modifiers)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$HotKeyActionImplCopyWith<_$HotKeyActionImpl> get copyWith => + __$$HotKeyActionImplCopyWithImpl<_$HotKeyActionImpl>(this, _$identity); + + @override + Map toJson() { + return _$$HotKeyActionImplToJson( + this, + ); + } +} + +abstract class _HotKeyAction implements HotKeyAction { + const factory _HotKeyAction( + {required final HotAction action, + final int? key, + final Set modifiers}) = _$HotKeyActionImpl; + + factory _HotKeyAction.fromJson(Map json) = + _$HotKeyActionImpl.fromJson; + + @override + HotAction get action; + @override + int? get key; + @override + Set get modifiers; + @override + @JsonKey(ignore: true) + _$$HotKeyActionImplCopyWith<_$HotKeyActionImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/generated/common.g.dart b/lib/models/generated/common.g.dart new file mode 100644 index 0000000..3f70cbe --- /dev/null +++ b/lib/models/generated/common.g.dart @@ -0,0 +1,232 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of '../common.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Log _$LogFromJson(Map json) => Log( + logLevel: $enumDecode(_$LogLevelEnumMap, json['LogLevel']), + payload: json['Payload'] as String?, + ); + +Map _$LogToJson(Log instance) => { + 'LogLevel': _$LogLevelEnumMap[instance.logLevel]!, + 'Payload': instance.payload, + }; + +const _$LogLevelEnumMap = { + LogLevel.debug: 'debug', + LogLevel.info: 'info', + LogLevel.warning: 'warning', + LogLevel.error: 'error', + LogLevel.silent: 'silent', +}; + +_$PackageImpl _$$PackageImplFromJson(Map json) => + _$PackageImpl( + packageName: json['packageName'] as String, + label: json['label'] as String, + isSystem: json['isSystem'] as bool, + firstInstallTime: (json['firstInstallTime'] as num).toInt(), + ); + +Map _$$PackageImplToJson(_$PackageImpl instance) => + { + 'packageName': instance.packageName, + 'label': instance.label, + 'isSystem': instance.isSystem, + 'firstInstallTime': instance.firstInstallTime, + }; + +_$MetadataImpl _$$MetadataImplFromJson(Map json) => + _$MetadataImpl( + uid: (json['uid'] as num).toInt(), + network: json['network'] as String, + sourceIP: json['sourceIP'] as String, + sourcePort: json['sourcePort'] as String, + destinationIP: json['destinationIP'] as String, + destinationPort: json['destinationPort'] as String, + host: json['host'] as String, + process: json['process'] as String, + remoteDestination: json['remoteDestination'] as String, + ); + +Map _$$MetadataImplToJson(_$MetadataImpl instance) => + { + 'uid': instance.uid, + 'network': instance.network, + 'sourceIP': instance.sourceIP, + 'sourcePort': instance.sourcePort, + 'destinationIP': instance.destinationIP, + 'destinationPort': instance.destinationPort, + 'host': instance.host, + 'process': instance.process, + 'remoteDestination': instance.remoteDestination, + }; + +_$ConnectionImpl _$$ConnectionImplFromJson(Map json) => + _$ConnectionImpl( + id: json['id'] as String, + upload: json['upload'] as num?, + download: json['download'] as num?, + start: DateTime.parse(json['start'] as String), + metadata: Metadata.fromJson(json['metadata'] as Map), + chains: + (json['chains'] as List).map((e) => e as String).toList(), + ); + +Map _$$ConnectionImplToJson(_$ConnectionImpl instance) => + { + 'id': instance.id, + 'upload': instance.upload, + 'download': instance.download, + 'start': instance.start.toIso8601String(), + 'metadata': instance.metadata, + 'chains': instance.chains, + }; + +_$LogsAndKeywordsImpl _$$LogsAndKeywordsImplFromJson( + Map json) => + _$LogsAndKeywordsImpl( + logs: (json['logs'] as List?) + ?.map((e) => Log.fromJson(e as Map)) + .toList() ?? + const [], + keywords: (json['keywords'] as List?) + ?.map((e) => e as String) + .toList() ?? + const [], + ); + +Map _$$LogsAndKeywordsImplToJson( + _$LogsAndKeywordsImpl instance) => + { + 'logs': instance.logs, + 'keywords': instance.keywords, + }; + +_$ConnectionsAndKeywordsImpl _$$ConnectionsAndKeywordsImplFromJson( + Map json) => + _$ConnectionsAndKeywordsImpl( + connections: (json['connections'] as List?) + ?.map((e) => Connection.fromJson(e as Map)) + .toList() ?? + const [], + keywords: (json['keywords'] as List?) + ?.map((e) => e as String) + .toList() ?? + const [], + ); + +Map _$$ConnectionsAndKeywordsImplToJson( + _$ConnectionsAndKeywordsImpl instance) => + { + 'connections': instance.connections, + 'keywords': instance.keywords, + }; + +_$DAVImpl _$$DAVImplFromJson(Map json) => _$DAVImpl( + uri: json['uri'] as String, + user: json['user'] as String, + password: json['password'] as String, + fileName: json['fileName'] as String? ?? defaultDavFileName, + ); + +Map _$$DAVImplToJson(_$DAVImpl instance) => { + 'uri': instance.uri, + 'user': instance.user, + 'password': instance.password, + 'fileName': instance.fileName, + }; + +_$VersionInfoImpl _$$VersionInfoImplFromJson(Map json) => + _$VersionInfoImpl( + clashName: json['clashName'] as String? ?? "", + version: json['version'] as String? ?? "", + ); + +Map _$$VersionInfoImplToJson(_$VersionInfoImpl instance) => + { + 'clashName': instance.clashName, + 'version': instance.version, + }; + +_$GroupImpl _$$GroupImplFromJson(Map json) => _$GroupImpl( + type: $enumDecode(_$GroupTypeEnumMap, json['type']), + all: (json['all'] as List?) + ?.map((e) => Proxy.fromJson(e as Map)) + .toList() ?? + const [], + now: json['now'] as String?, + hidden: json['hidden'] as bool?, + icon: json['icon'] as String? ?? "", + name: json['name'] as String, + ); + +Map _$$GroupImplToJson(_$GroupImpl instance) => + { + 'type': _$GroupTypeEnumMap[instance.type]!, + 'all': instance.all, + 'now': instance.now, + 'hidden': instance.hidden, + 'icon': instance.icon, + 'name': instance.name, + }; + +const _$GroupTypeEnumMap = { + GroupType.Selector: 'Selector', + GroupType.URLTest: 'URLTest', + GroupType.Fallback: 'Fallback', + GroupType.LoadBalance: 'LoadBalance', + 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']), + key: (json['key'] as num?)?.toInt(), + modifiers: (json['modifiers'] as List?) + ?.map((e) => $enumDecode(_$KeyboardModifierEnumMap, e)) + .toSet() ?? + const {}, + ); + +Map _$$HotKeyActionImplToJson(_$HotKeyActionImpl instance) => + { + 'action': _$HotActionEnumMap[instance.action]!, + 'key': instance.key, + 'modifiers': + instance.modifiers.map((e) => _$KeyboardModifierEnumMap[e]!).toList(), + }; + +const _$HotActionEnumMap = { + HotAction.start: 'start', + HotAction.view: 'view', + HotAction.mode: 'mode', + HotAction.proxy: 'proxy', + HotAction.tun: 'tun', +}; + +const _$KeyboardModifierEnumMap = { + KeyboardModifier.alt: 'alt', + KeyboardModifier.capsLock: 'capsLock', + KeyboardModifier.control: 'control', + KeyboardModifier.fn: 'fn', + KeyboardModifier.meta: 'meta', + KeyboardModifier.shift: 'shift', +}; diff --git a/lib/models/generated/config.g.dart b/lib/models/generated/config.g.dart index be970f2..e552bac 100644 --- a/lib/models/generated/config.g.dart +++ b/lib/models/generated/config.g.dart @@ -56,7 +56,12 @@ Config _$ConfigFromJson(Map json) => Config() ..scaleProps = ScaleProps.fromJson(json['scaleProps'] as Map?) ..showLabel = json['showLabel'] as bool? ?? false - ..overrideDns = json['overrideDns'] as bool? ?? false; + ..overrideDns = json['overrideDns'] as bool? ?? false + ..isDisclaimerAccepted = json['isDisclaimerAccepted'] as bool? ?? false + ..hotKeyActions = (json['hotKeyActions'] as List?) + ?.map((e) => HotKeyAction.fromJson(e as Map)) + .toList() ?? + []; Map _$ConfigToJson(Config instance) => { 'profiles': instance.profiles, @@ -90,6 +95,8 @@ Map _$ConfigToJson(Config instance) => { 'scaleProps': instance.scaleProps, 'showLabel': instance.showLabel, 'overrideDns': instance.overrideDns, + 'isDisclaimerAccepted': instance.isDisclaimerAccepted, + 'hotKeyActions': instance.hotKeyActions, }; const _$ThemeModeEnumMap = { diff --git a/lib/models/generated/connection.freezed.dart b/lib/models/generated/connection.freezed.dart deleted file mode 100644 index 38e2f9b..0000000 --- a/lib/models/generated/connection.freezed.dart +++ /dev/null @@ -1,772 +0,0 @@ -// 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 '../connection.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'); - -Metadata _$MetadataFromJson(Map json) { - return _Metadata.fromJson(json); -} - -/// @nodoc -mixin _$Metadata { - int get uid => throw _privateConstructorUsedError; - String get network => throw _privateConstructorUsedError; - String get sourceIP => throw _privateConstructorUsedError; - String get sourcePort => throw _privateConstructorUsedError; - String get destinationIP => throw _privateConstructorUsedError; - String get destinationPort => throw _privateConstructorUsedError; - String get host => throw _privateConstructorUsedError; - String get process => throw _privateConstructorUsedError; - String get remoteDestination => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $MetadataCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $MetadataCopyWith<$Res> { - factory $MetadataCopyWith(Metadata value, $Res Function(Metadata) then) = - _$MetadataCopyWithImpl<$Res, Metadata>; - @useResult - $Res call( - {int uid, - String network, - String sourceIP, - String sourcePort, - String destinationIP, - String destinationPort, - String host, - String process, - String remoteDestination}); -} - -/// @nodoc -class _$MetadataCopyWithImpl<$Res, $Val extends Metadata> - implements $MetadataCopyWith<$Res> { - _$MetadataCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? uid = null, - Object? network = null, - Object? sourceIP = null, - Object? sourcePort = null, - Object? destinationIP = null, - Object? destinationPort = null, - Object? host = null, - Object? process = null, - Object? remoteDestination = null, - }) { - return _then(_value.copyWith( - uid: null == uid - ? _value.uid - : uid // ignore: cast_nullable_to_non_nullable - as int, - network: null == network - ? _value.network - : network // ignore: cast_nullable_to_non_nullable - as String, - sourceIP: null == sourceIP - ? _value.sourceIP - : sourceIP // ignore: cast_nullable_to_non_nullable - as String, - sourcePort: null == sourcePort - ? _value.sourcePort - : sourcePort // ignore: cast_nullable_to_non_nullable - as String, - destinationIP: null == destinationIP - ? _value.destinationIP - : destinationIP // ignore: cast_nullable_to_non_nullable - as String, - destinationPort: null == destinationPort - ? _value.destinationPort - : destinationPort // ignore: cast_nullable_to_non_nullable - as String, - host: null == host - ? _value.host - : host // ignore: cast_nullable_to_non_nullable - as String, - process: null == process - ? _value.process - : process // ignore: cast_nullable_to_non_nullable - as String, - remoteDestination: null == remoteDestination - ? _value.remoteDestination - : remoteDestination // ignore: cast_nullable_to_non_nullable - as String, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$MetadataImplCopyWith<$Res> - implements $MetadataCopyWith<$Res> { - factory _$$MetadataImplCopyWith( - _$MetadataImpl value, $Res Function(_$MetadataImpl) then) = - __$$MetadataImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {int uid, - String network, - String sourceIP, - String sourcePort, - String destinationIP, - String destinationPort, - String host, - String process, - String remoteDestination}); -} - -/// @nodoc -class __$$MetadataImplCopyWithImpl<$Res> - extends _$MetadataCopyWithImpl<$Res, _$MetadataImpl> - implements _$$MetadataImplCopyWith<$Res> { - __$$MetadataImplCopyWithImpl( - _$MetadataImpl _value, $Res Function(_$MetadataImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? uid = null, - Object? network = null, - Object? sourceIP = null, - Object? sourcePort = null, - Object? destinationIP = null, - Object? destinationPort = null, - Object? host = null, - Object? process = null, - Object? remoteDestination = null, - }) { - return _then(_$MetadataImpl( - uid: null == uid - ? _value.uid - : uid // ignore: cast_nullable_to_non_nullable - as int, - network: null == network - ? _value.network - : network // ignore: cast_nullable_to_non_nullable - as String, - sourceIP: null == sourceIP - ? _value.sourceIP - : sourceIP // ignore: cast_nullable_to_non_nullable - as String, - sourcePort: null == sourcePort - ? _value.sourcePort - : sourcePort // ignore: cast_nullable_to_non_nullable - as String, - destinationIP: null == destinationIP - ? _value.destinationIP - : destinationIP // ignore: cast_nullable_to_non_nullable - as String, - destinationPort: null == destinationPort - ? _value.destinationPort - : destinationPort // ignore: cast_nullable_to_non_nullable - as String, - host: null == host - ? _value.host - : host // ignore: cast_nullable_to_non_nullable - as String, - process: null == process - ? _value.process - : process // ignore: cast_nullable_to_non_nullable - as String, - remoteDestination: null == remoteDestination - ? _value.remoteDestination - : remoteDestination // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$MetadataImpl implements _Metadata { - const _$MetadataImpl( - {required this.uid, - required this.network, - required this.sourceIP, - required this.sourcePort, - required this.destinationIP, - required this.destinationPort, - required this.host, - required this.process, - required this.remoteDestination}); - - factory _$MetadataImpl.fromJson(Map json) => - _$$MetadataImplFromJson(json); - - @override - final int uid; - @override - final String network; - @override - final String sourceIP; - @override - final String sourcePort; - @override - final String destinationIP; - @override - final String destinationPort; - @override - final String host; - @override - final String process; - @override - final String remoteDestination; - - @override - String toString() { - return 'Metadata(uid: $uid, network: $network, sourceIP: $sourceIP, sourcePort: $sourcePort, destinationIP: $destinationIP, destinationPort: $destinationPort, host: $host, process: $process, remoteDestination: $remoteDestination)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$MetadataImpl && - (identical(other.uid, uid) || other.uid == uid) && - (identical(other.network, network) || other.network == network) && - (identical(other.sourceIP, sourceIP) || - other.sourceIP == sourceIP) && - (identical(other.sourcePort, sourcePort) || - other.sourcePort == sourcePort) && - (identical(other.destinationIP, destinationIP) || - other.destinationIP == destinationIP) && - (identical(other.destinationPort, destinationPort) || - other.destinationPort == destinationPort) && - (identical(other.host, host) || other.host == host) && - (identical(other.process, process) || other.process == process) && - (identical(other.remoteDestination, remoteDestination) || - other.remoteDestination == remoteDestination)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => Object.hash( - runtimeType, - uid, - network, - sourceIP, - sourcePort, - destinationIP, - destinationPort, - host, - process, - remoteDestination); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$MetadataImplCopyWith<_$MetadataImpl> get copyWith => - __$$MetadataImplCopyWithImpl<_$MetadataImpl>(this, _$identity); - - @override - Map toJson() { - return _$$MetadataImplToJson( - this, - ); - } -} - -abstract class _Metadata implements Metadata { - const factory _Metadata( - {required final int uid, - required final String network, - required final String sourceIP, - required final String sourcePort, - required final String destinationIP, - required final String destinationPort, - required final String host, - required final String process, - required final String remoteDestination}) = _$MetadataImpl; - - factory _Metadata.fromJson(Map json) = - _$MetadataImpl.fromJson; - - @override - int get uid; - @override - String get network; - @override - String get sourceIP; - @override - String get sourcePort; - @override - String get destinationIP; - @override - String get destinationPort; - @override - String get host; - @override - String get process; - @override - String get remoteDestination; - @override - @JsonKey(ignore: true) - _$$MetadataImplCopyWith<_$MetadataImpl> get copyWith => - throw _privateConstructorUsedError; -} - -Connection _$ConnectionFromJson(Map json) { - return _Connection.fromJson(json); -} - -/// @nodoc -mixin _$Connection { - String get id => throw _privateConstructorUsedError; - num? get upload => throw _privateConstructorUsedError; - num? get download => throw _privateConstructorUsedError; - DateTime get start => throw _privateConstructorUsedError; - Metadata get metadata => throw _privateConstructorUsedError; - List get chains => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $ConnectionCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $ConnectionCopyWith<$Res> { - factory $ConnectionCopyWith( - Connection value, $Res Function(Connection) then) = - _$ConnectionCopyWithImpl<$Res, Connection>; - @useResult - $Res call( - {String id, - num? upload, - num? download, - DateTime start, - Metadata metadata, - List chains}); - - $MetadataCopyWith<$Res> get metadata; -} - -/// @nodoc -class _$ConnectionCopyWithImpl<$Res, $Val extends Connection> - implements $ConnectionCopyWith<$Res> { - _$ConnectionCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? upload = freezed, - Object? download = freezed, - Object? start = null, - Object? metadata = null, - Object? chains = null, - }) { - return _then(_value.copyWith( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as String, - upload: freezed == upload - ? _value.upload - : upload // ignore: cast_nullable_to_non_nullable - as num?, - download: freezed == download - ? _value.download - : download // ignore: cast_nullable_to_non_nullable - as num?, - start: null == start - ? _value.start - : start // ignore: cast_nullable_to_non_nullable - as DateTime, - metadata: null == metadata - ? _value.metadata - : metadata // ignore: cast_nullable_to_non_nullable - as Metadata, - chains: null == chains - ? _value.chains - : chains // ignore: cast_nullable_to_non_nullable - as List, - ) as $Val); - } - - @override - @pragma('vm:prefer-inline') - $MetadataCopyWith<$Res> get metadata { - return $MetadataCopyWith<$Res>(_value.metadata, (value) { - return _then(_value.copyWith(metadata: value) as $Val); - }); - } -} - -/// @nodoc -abstract class _$$ConnectionImplCopyWith<$Res> - implements $ConnectionCopyWith<$Res> { - factory _$$ConnectionImplCopyWith( - _$ConnectionImpl value, $Res Function(_$ConnectionImpl) then) = - __$$ConnectionImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String id, - num? upload, - num? download, - DateTime start, - Metadata metadata, - List chains}); - - @override - $MetadataCopyWith<$Res> get metadata; -} - -/// @nodoc -class __$$ConnectionImplCopyWithImpl<$Res> - extends _$ConnectionCopyWithImpl<$Res, _$ConnectionImpl> - implements _$$ConnectionImplCopyWith<$Res> { - __$$ConnectionImplCopyWithImpl( - _$ConnectionImpl _value, $Res Function(_$ConnectionImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? upload = freezed, - Object? download = freezed, - Object? start = null, - Object? metadata = null, - Object? chains = null, - }) { - return _then(_$ConnectionImpl( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as String, - upload: freezed == upload - ? _value.upload - : upload // ignore: cast_nullable_to_non_nullable - as num?, - download: freezed == download - ? _value.download - : download // ignore: cast_nullable_to_non_nullable - as num?, - start: null == start - ? _value.start - : start // ignore: cast_nullable_to_non_nullable - as DateTime, - metadata: null == metadata - ? _value.metadata - : metadata // ignore: cast_nullable_to_non_nullable - as Metadata, - chains: null == chains - ? _value._chains - : chains // ignore: cast_nullable_to_non_nullable - as List, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$ConnectionImpl implements _Connection { - const _$ConnectionImpl( - {required this.id, - this.upload, - this.download, - required this.start, - required this.metadata, - required final List chains}) - : _chains = chains; - - factory _$ConnectionImpl.fromJson(Map json) => - _$$ConnectionImplFromJson(json); - - @override - final String id; - @override - final num? upload; - @override - final num? download; - @override - final DateTime start; - @override - final Metadata metadata; - final List _chains; - @override - List get chains { - if (_chains is EqualUnmodifiableListView) return _chains; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_chains); - } - - @override - String toString() { - return 'Connection(id: $id, upload: $upload, download: $download, start: $start, metadata: $metadata, chains: $chains)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$ConnectionImpl && - (identical(other.id, id) || other.id == id) && - (identical(other.upload, upload) || other.upload == upload) && - (identical(other.download, download) || - other.download == download) && - (identical(other.start, start) || other.start == start) && - (identical(other.metadata, metadata) || - other.metadata == metadata) && - const DeepCollectionEquality().equals(other._chains, _chains)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => Object.hash(runtimeType, id, upload, download, start, - metadata, const DeepCollectionEquality().hash(_chains)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$ConnectionImplCopyWith<_$ConnectionImpl> get copyWith => - __$$ConnectionImplCopyWithImpl<_$ConnectionImpl>(this, _$identity); - - @override - Map toJson() { - return _$$ConnectionImplToJson( - this, - ); - } -} - -abstract class _Connection implements Connection { - const factory _Connection( - {required final String id, - final num? upload, - final num? download, - required final DateTime start, - required final Metadata metadata, - required final List chains}) = _$ConnectionImpl; - - factory _Connection.fromJson(Map json) = - _$ConnectionImpl.fromJson; - - @override - String get id; - @override - num? get upload; - @override - num? get download; - @override - DateTime get start; - @override - Metadata get metadata; - @override - List get chains; - @override - @JsonKey(ignore: true) - _$$ConnectionImplCopyWith<_$ConnectionImpl> get copyWith => - throw _privateConstructorUsedError; -} - -ConnectionsAndKeywords _$ConnectionsAndKeywordsFromJson( - Map json) { - return _ConnectionsAndKeywords.fromJson(json); -} - -/// @nodoc -mixin _$ConnectionsAndKeywords { - List get connections => throw _privateConstructorUsedError; - List get keywords => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $ConnectionsAndKeywordsCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $ConnectionsAndKeywordsCopyWith<$Res> { - factory $ConnectionsAndKeywordsCopyWith(ConnectionsAndKeywords value, - $Res Function(ConnectionsAndKeywords) then) = - _$ConnectionsAndKeywordsCopyWithImpl<$Res, ConnectionsAndKeywords>; - @useResult - $Res call({List connections, List keywords}); -} - -/// @nodoc -class _$ConnectionsAndKeywordsCopyWithImpl<$Res, - $Val extends ConnectionsAndKeywords> - implements $ConnectionsAndKeywordsCopyWith<$Res> { - _$ConnectionsAndKeywordsCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? connections = null, - Object? keywords = null, - }) { - return _then(_value.copyWith( - connections: null == connections - ? _value.connections - : connections // ignore: cast_nullable_to_non_nullable - as List, - keywords: null == keywords - ? _value.keywords - : keywords // ignore: cast_nullable_to_non_nullable - as List, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$ConnectionsAndKeywordsImplCopyWith<$Res> - implements $ConnectionsAndKeywordsCopyWith<$Res> { - factory _$$ConnectionsAndKeywordsImplCopyWith( - _$ConnectionsAndKeywordsImpl value, - $Res Function(_$ConnectionsAndKeywordsImpl) then) = - __$$ConnectionsAndKeywordsImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({List connections, List keywords}); -} - -/// @nodoc -class __$$ConnectionsAndKeywordsImplCopyWithImpl<$Res> - extends _$ConnectionsAndKeywordsCopyWithImpl<$Res, - _$ConnectionsAndKeywordsImpl> - implements _$$ConnectionsAndKeywordsImplCopyWith<$Res> { - __$$ConnectionsAndKeywordsImplCopyWithImpl( - _$ConnectionsAndKeywordsImpl _value, - $Res Function(_$ConnectionsAndKeywordsImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? connections = null, - Object? keywords = null, - }) { - return _then(_$ConnectionsAndKeywordsImpl( - connections: null == connections - ? _value._connections - : connections // ignore: cast_nullable_to_non_nullable - as List, - keywords: null == keywords - ? _value._keywords - : keywords // ignore: cast_nullable_to_non_nullable - as List, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$ConnectionsAndKeywordsImpl implements _ConnectionsAndKeywords { - const _$ConnectionsAndKeywordsImpl( - {final List connections = const [], - final List keywords = const []}) - : _connections = connections, - _keywords = keywords; - - factory _$ConnectionsAndKeywordsImpl.fromJson(Map json) => - _$$ConnectionsAndKeywordsImplFromJson(json); - - final List _connections; - @override - @JsonKey() - List get connections { - if (_connections is EqualUnmodifiableListView) return _connections; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_connections); - } - - final List _keywords; - @override - @JsonKey() - List get keywords { - if (_keywords is EqualUnmodifiableListView) return _keywords; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_keywords); - } - - @override - String toString() { - return 'ConnectionsAndKeywords(connections: $connections, keywords: $keywords)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$ConnectionsAndKeywordsImpl && - const DeepCollectionEquality() - .equals(other._connections, _connections) && - const DeepCollectionEquality().equals(other._keywords, _keywords)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => Object.hash( - runtimeType, - const DeepCollectionEquality().hash(_connections), - const DeepCollectionEquality().hash(_keywords)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$ConnectionsAndKeywordsImplCopyWith<_$ConnectionsAndKeywordsImpl> - get copyWith => __$$ConnectionsAndKeywordsImplCopyWithImpl< - _$ConnectionsAndKeywordsImpl>(this, _$identity); - - @override - Map toJson() { - return _$$ConnectionsAndKeywordsImplToJson( - this, - ); - } -} - -abstract class _ConnectionsAndKeywords implements ConnectionsAndKeywords { - const factory _ConnectionsAndKeywords( - {final List connections, - final List keywords}) = _$ConnectionsAndKeywordsImpl; - - factory _ConnectionsAndKeywords.fromJson(Map json) = - _$ConnectionsAndKeywordsImpl.fromJson; - - @override - List get connections; - @override - List get keywords; - @override - @JsonKey(ignore: true) - _$$ConnectionsAndKeywordsImplCopyWith<_$ConnectionsAndKeywordsImpl> - get copyWith => throw _privateConstructorUsedError; -} diff --git a/lib/models/generated/connection.g.dart b/lib/models/generated/connection.g.dart deleted file mode 100644 index ce739e2..0000000 --- a/lib/models/generated/connection.g.dart +++ /dev/null @@ -1,74 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of '../connection.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_$MetadataImpl _$$MetadataImplFromJson(Map json) => - _$MetadataImpl( - uid: (json['uid'] as num).toInt(), - network: json['network'] as String, - sourceIP: json['sourceIP'] as String, - sourcePort: json['sourcePort'] as String, - destinationIP: json['destinationIP'] as String, - destinationPort: json['destinationPort'] as String, - host: json['host'] as String, - process: json['process'] as String, - remoteDestination: json['remoteDestination'] as String, - ); - -Map _$$MetadataImplToJson(_$MetadataImpl instance) => - { - 'uid': instance.uid, - 'network': instance.network, - 'sourceIP': instance.sourceIP, - 'sourcePort': instance.sourcePort, - 'destinationIP': instance.destinationIP, - 'destinationPort': instance.destinationPort, - 'host': instance.host, - 'process': instance.process, - 'remoteDestination': instance.remoteDestination, - }; - -_$ConnectionImpl _$$ConnectionImplFromJson(Map json) => - _$ConnectionImpl( - id: json['id'] as String, - upload: json['upload'] as num?, - download: json['download'] as num?, - start: DateTime.parse(json['start'] as String), - metadata: Metadata.fromJson(json['metadata'] as Map), - chains: - (json['chains'] as List).map((e) => e as String).toList(), - ); - -Map _$$ConnectionImplToJson(_$ConnectionImpl instance) => - { - 'id': instance.id, - 'upload': instance.upload, - 'download': instance.download, - 'start': instance.start.toIso8601String(), - 'metadata': instance.metadata, - 'chains': instance.chains, - }; - -_$ConnectionsAndKeywordsImpl _$$ConnectionsAndKeywordsImplFromJson( - Map json) => - _$ConnectionsAndKeywordsImpl( - connections: (json['connections'] as List?) - ?.map((e) => Connection.fromJson(e as Map)) - .toList() ?? - const [], - keywords: (json['keywords'] as List?) - ?.map((e) => e as String) - .toList() ?? - const [], - ); - -Map _$$ConnectionsAndKeywordsImplToJson( - _$ConnectionsAndKeywordsImpl instance) => - { - 'connections': instance.connections, - 'keywords': instance.keywords, - }; diff --git a/lib/models/generated/dav.freezed.dart b/lib/models/generated/dav.freezed.dart deleted file mode 100644 index fab0cca..0000000 --- a/lib/models/generated/dav.freezed.dart +++ /dev/null @@ -1,202 +0,0 @@ -// 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 '../dav.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'); - -DAV _$DAVFromJson(Map json) { - return _DAV.fromJson(json); -} - -/// @nodoc -mixin _$DAV { - String get uri => throw _privateConstructorUsedError; - String get user => throw _privateConstructorUsedError; - String get password => throw _privateConstructorUsedError; - String get fileName => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $DAVCopyWith get copyWith => throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $DAVCopyWith<$Res> { - factory $DAVCopyWith(DAV value, $Res Function(DAV) then) = - _$DAVCopyWithImpl<$Res, DAV>; - @useResult - $Res call({String uri, String user, String password, String fileName}); -} - -/// @nodoc -class _$DAVCopyWithImpl<$Res, $Val extends DAV> implements $DAVCopyWith<$Res> { - _$DAVCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? uri = null, - Object? user = null, - Object? password = null, - Object? fileName = null, - }) { - return _then(_value.copyWith( - uri: null == uri - ? _value.uri - : uri // ignore: cast_nullable_to_non_nullable - as String, - user: null == user - ? _value.user - : user // ignore: cast_nullable_to_non_nullable - as String, - password: null == password - ? _value.password - : password // ignore: cast_nullable_to_non_nullable - as String, - fileName: null == fileName - ? _value.fileName - : fileName // ignore: cast_nullable_to_non_nullable - as String, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$DAVImplCopyWith<$Res> implements $DAVCopyWith<$Res> { - factory _$$DAVImplCopyWith(_$DAVImpl value, $Res Function(_$DAVImpl) then) = - __$$DAVImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({String uri, String user, String password, String fileName}); -} - -/// @nodoc -class __$$DAVImplCopyWithImpl<$Res> extends _$DAVCopyWithImpl<$Res, _$DAVImpl> - implements _$$DAVImplCopyWith<$Res> { - __$$DAVImplCopyWithImpl(_$DAVImpl _value, $Res Function(_$DAVImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? uri = null, - Object? user = null, - Object? password = null, - Object? fileName = null, - }) { - return _then(_$DAVImpl( - uri: null == uri - ? _value.uri - : uri // ignore: cast_nullable_to_non_nullable - as String, - user: null == user - ? _value.user - : user // ignore: cast_nullable_to_non_nullable - as String, - password: null == password - ? _value.password - : password // ignore: cast_nullable_to_non_nullable - as String, - fileName: null == fileName - ? _value.fileName - : fileName // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$DAVImpl implements _DAV { - const _$DAVImpl( - {required this.uri, - required this.user, - required this.password, - this.fileName = defaultDavFileName}); - - factory _$DAVImpl.fromJson(Map json) => - _$$DAVImplFromJson(json); - - @override - final String uri; - @override - final String user; - @override - final String password; - @override - @JsonKey() - final String fileName; - - @override - String toString() { - return 'DAV(uri: $uri, user: $user, password: $password, fileName: $fileName)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$DAVImpl && - (identical(other.uri, uri) || other.uri == uri) && - (identical(other.user, user) || other.user == user) && - (identical(other.password, password) || - other.password == password) && - (identical(other.fileName, fileName) || - other.fileName == fileName)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => Object.hash(runtimeType, uri, user, password, fileName); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$DAVImplCopyWith<_$DAVImpl> get copyWith => - __$$DAVImplCopyWithImpl<_$DAVImpl>(this, _$identity); - - @override - Map toJson() { - return _$$DAVImplToJson( - this, - ); - } -} - -abstract class _DAV implements DAV { - const factory _DAV( - {required final String uri, - required final String user, - required final String password, - final String fileName}) = _$DAVImpl; - - factory _DAV.fromJson(Map json) = _$DAVImpl.fromJson; - - @override - String get uri; - @override - String get user; - @override - String get password; - @override - String get fileName; - @override - @JsonKey(ignore: true) - _$$DAVImplCopyWith<_$DAVImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/models/generated/dav.g.dart b/lib/models/generated/dav.g.dart deleted file mode 100644 index 7d01b11..0000000 --- a/lib/models/generated/dav.g.dart +++ /dev/null @@ -1,21 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of '../dav.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_$DAVImpl _$$DAVImplFromJson(Map json) => _$DAVImpl( - uri: json['uri'] as String, - user: json['user'] as String, - password: json['password'] as String, - fileName: json['fileName'] as String? ?? defaultDavFileName, - ); - -Map _$$DAVImplToJson(_$DAVImpl instance) => { - 'uri': instance.uri, - 'user': instance.user, - 'password': instance.password, - 'fileName': instance.fileName, - }; diff --git a/lib/models/generated/ffi.freezed.dart b/lib/models/generated/ffi.freezed.dart index 6da4112..087c3d7 100644 --- a/lib/models/generated/ffi.freezed.dart +++ b/lib/models/generated/ffi.freezed.dart @@ -1975,3 +1975,264 @@ abstract class _ExternalProvider implements ExternalProvider { _$$ExternalProviderImplCopyWith<_$ExternalProviderImpl> get copyWith => throw _privateConstructorUsedError; } + +TunProps _$TunPropsFromJson(Map json) { + return _TunProps.fromJson(json); +} + +/// @nodoc +mixin _$TunProps { + int get fd => throw _privateConstructorUsedError; + String get gateway => throw _privateConstructorUsedError; + String get gateway6 => throw _privateConstructorUsedError; + String get portal => throw _privateConstructorUsedError; + String get portal6 => throw _privateConstructorUsedError; + String get dns => throw _privateConstructorUsedError; + String get dns6 => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $TunPropsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $TunPropsCopyWith<$Res> { + factory $TunPropsCopyWith(TunProps value, $Res Function(TunProps) then) = + _$TunPropsCopyWithImpl<$Res, TunProps>; + @useResult + $Res call( + {int fd, + String gateway, + String gateway6, + String portal, + String portal6, + String dns, + String dns6}); +} + +/// @nodoc +class _$TunPropsCopyWithImpl<$Res, $Val extends TunProps> + implements $TunPropsCopyWith<$Res> { + _$TunPropsCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? fd = null, + Object? gateway = null, + Object? gateway6 = null, + Object? portal = null, + Object? portal6 = null, + Object? dns = null, + Object? dns6 = null, + }) { + return _then(_value.copyWith( + fd: null == fd + ? _value.fd + : fd // ignore: cast_nullable_to_non_nullable + as int, + gateway: null == gateway + ? _value.gateway + : gateway // ignore: cast_nullable_to_non_nullable + as String, + gateway6: null == gateway6 + ? _value.gateway6 + : gateway6 // ignore: cast_nullable_to_non_nullable + as String, + portal: null == portal + ? _value.portal + : portal // ignore: cast_nullable_to_non_nullable + as String, + portal6: null == portal6 + ? _value.portal6 + : portal6 // ignore: cast_nullable_to_non_nullable + as String, + dns: null == dns + ? _value.dns + : dns // ignore: cast_nullable_to_non_nullable + as String, + dns6: null == dns6 + ? _value.dns6 + : dns6 // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$TunPropsImplCopyWith<$Res> + implements $TunPropsCopyWith<$Res> { + factory _$$TunPropsImplCopyWith( + _$TunPropsImpl value, $Res Function(_$TunPropsImpl) then) = + __$$TunPropsImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {int fd, + String gateway, + String gateway6, + String portal, + String portal6, + String dns, + String dns6}); +} + +/// @nodoc +class __$$TunPropsImplCopyWithImpl<$Res> + extends _$TunPropsCopyWithImpl<$Res, _$TunPropsImpl> + implements _$$TunPropsImplCopyWith<$Res> { + __$$TunPropsImplCopyWithImpl( + _$TunPropsImpl _value, $Res Function(_$TunPropsImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? fd = null, + Object? gateway = null, + Object? gateway6 = null, + Object? portal = null, + Object? portal6 = null, + Object? dns = null, + Object? dns6 = null, + }) { + return _then(_$TunPropsImpl( + fd: null == fd + ? _value.fd + : fd // ignore: cast_nullable_to_non_nullable + as int, + gateway: null == gateway + ? _value.gateway + : gateway // ignore: cast_nullable_to_non_nullable + as String, + gateway6: null == gateway6 + ? _value.gateway6 + : gateway6 // ignore: cast_nullable_to_non_nullable + as String, + portal: null == portal + ? _value.portal + : portal // ignore: cast_nullable_to_non_nullable + as String, + portal6: null == portal6 + ? _value.portal6 + : portal6 // ignore: cast_nullable_to_non_nullable + as String, + dns: null == dns + ? _value.dns + : dns // ignore: cast_nullable_to_non_nullable + as String, + dns6: null == dns6 + ? _value.dns6 + : dns6 // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$TunPropsImpl implements _TunProps { + const _$TunPropsImpl( + {required this.fd, + required this.gateway, + required this.gateway6, + required this.portal, + required this.portal6, + required this.dns, + required this.dns6}); + + factory _$TunPropsImpl.fromJson(Map json) => + _$$TunPropsImplFromJson(json); + + @override + final int fd; + @override + final String gateway; + @override + final String gateway6; + @override + final String portal; + @override + final String portal6; + @override + final String dns; + @override + final String dns6; + + @override + String toString() { + return 'TunProps(fd: $fd, gateway: $gateway, gateway6: $gateway6, portal: $portal, portal6: $portal6, dns: $dns, dns6: $dns6)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$TunPropsImpl && + (identical(other.fd, fd) || other.fd == fd) && + (identical(other.gateway, gateway) || other.gateway == gateway) && + (identical(other.gateway6, gateway6) || + other.gateway6 == gateway6) && + (identical(other.portal, portal) || other.portal == portal) && + (identical(other.portal6, portal6) || other.portal6 == portal6) && + (identical(other.dns, dns) || other.dns == dns) && + (identical(other.dns6, dns6) || other.dns6 == dns6)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, fd, gateway, gateway6, portal, portal6, dns, dns6); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$TunPropsImplCopyWith<_$TunPropsImpl> get copyWith => + __$$TunPropsImplCopyWithImpl<_$TunPropsImpl>(this, _$identity); + + @override + Map toJson() { + return _$$TunPropsImplToJson( + this, + ); + } +} + +abstract class _TunProps implements TunProps { + const factory _TunProps( + {required final int fd, + required final String gateway, + required final String gateway6, + required final String portal, + required final String portal6, + required final String dns, + required final String dns6}) = _$TunPropsImpl; + + factory _TunProps.fromJson(Map json) = + _$TunPropsImpl.fromJson; + + @override + int get fd; + @override + String get gateway; + @override + String get gateway6; + @override + String get portal; + @override + String get portal6; + @override + String get dns; + @override + String get dns6; + @override + @JsonKey(ignore: true) + _$$TunPropsImplCopyWith<_$TunPropsImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/generated/ffi.g.dart b/lib/models/generated/ffi.g.dart index 3c9e139..eae4eb1 100644 --- a/lib/models/generated/ffi.g.dart +++ b/lib/models/generated/ffi.g.dart @@ -176,3 +176,25 @@ Map _$$ExternalProviderImplToJson( 'vehicle-type': instance.vehicleType, 'update-at': instance.updateAt.toIso8601String(), }; + +_$TunPropsImpl _$$TunPropsImplFromJson(Map json) => + _$TunPropsImpl( + fd: (json['fd'] as num).toInt(), + gateway: json['gateway'] as String, + gateway6: json['gateway6'] as String, + portal: json['portal'] as String, + portal6: json['portal6'] as String, + dns: json['dns'] as String, + dns6: json['dns6'] as String, + ); + +Map _$$TunPropsImplToJson(_$TunPropsImpl instance) => + { + 'fd': instance.fd, + 'gateway': instance.gateway, + 'gateway6': instance.gateway6, + 'portal': instance.portal, + 'portal6': instance.portal6, + 'dns': instance.dns, + 'dns6': instance.dns6, + }; diff --git a/lib/models/generated/file.freezed.dart b/lib/models/generated/file.freezed.dart deleted file mode 100644 index 81f4da5..0000000 --- a/lib/models/generated/file.freezed.dart +++ /dev/null @@ -1,150 +0,0 @@ -// 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 '../file.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 _$FileInfo { - int get size => throw _privateConstructorUsedError; - DateTime get lastModified => throw _privateConstructorUsedError; - - @JsonKey(ignore: true) - $FileInfoCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $FileInfoCopyWith<$Res> { - factory $FileInfoCopyWith(FileInfo value, $Res Function(FileInfo) then) = - _$FileInfoCopyWithImpl<$Res, FileInfo>; - @useResult - $Res call({int size, DateTime lastModified}); -} - -/// @nodoc -class _$FileInfoCopyWithImpl<$Res, $Val extends FileInfo> - implements $FileInfoCopyWith<$Res> { - _$FileInfoCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? size = null, - Object? lastModified = null, - }) { - return _then(_value.copyWith( - size: null == size - ? _value.size - : size // ignore: cast_nullable_to_non_nullable - as int, - lastModified: null == lastModified - ? _value.lastModified - : lastModified // ignore: cast_nullable_to_non_nullable - as DateTime, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$FileInfoImplCopyWith<$Res> - implements $FileInfoCopyWith<$Res> { - factory _$$FileInfoImplCopyWith( - _$FileInfoImpl value, $Res Function(_$FileInfoImpl) then) = - __$$FileInfoImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({int size, DateTime lastModified}); -} - -/// @nodoc -class __$$FileInfoImplCopyWithImpl<$Res> - extends _$FileInfoCopyWithImpl<$Res, _$FileInfoImpl> - implements _$$FileInfoImplCopyWith<$Res> { - __$$FileInfoImplCopyWithImpl( - _$FileInfoImpl _value, $Res Function(_$FileInfoImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? size = null, - Object? lastModified = null, - }) { - return _then(_$FileInfoImpl( - size: null == size - ? _value.size - : size // ignore: cast_nullable_to_non_nullable - as int, - lastModified: null == lastModified - ? _value.lastModified - : lastModified // ignore: cast_nullable_to_non_nullable - as DateTime, - )); - } -} - -/// @nodoc - -class _$FileInfoImpl implements _FileInfo { - const _$FileInfoImpl({required this.size, required this.lastModified}); - - @override - final int size; - @override - final DateTime lastModified; - - @override - String toString() { - return 'FileInfo(size: $size, lastModified: $lastModified)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$FileInfoImpl && - (identical(other.size, size) || other.size == size) && - (identical(other.lastModified, lastModified) || - other.lastModified == lastModified)); - } - - @override - int get hashCode => Object.hash(runtimeType, size, lastModified); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$FileInfoImplCopyWith<_$FileInfoImpl> get copyWith => - __$$FileInfoImplCopyWithImpl<_$FileInfoImpl>(this, _$identity); -} - -abstract class _FileInfo implements FileInfo { - const factory _FileInfo( - {required final int size, - required final DateTime lastModified}) = _$FileInfoImpl; - - @override - int get size; - @override - DateTime get lastModified; - @override - @JsonKey(ignore: true) - _$$FileInfoImplCopyWith<_$FileInfoImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/models/generated/log.freezed.dart b/lib/models/generated/log.freezed.dart deleted file mode 100644 index 4cf11ea..0000000 --- a/lib/models/generated/log.freezed.dart +++ /dev/null @@ -1,189 +0,0 @@ -// 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 '../log.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'); - -LogsAndKeywords _$LogsAndKeywordsFromJson(Map json) { - return _LogsAndKeywords.fromJson(json); -} - -/// @nodoc -mixin _$LogsAndKeywords { - List get logs => throw _privateConstructorUsedError; - List get keywords => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $LogsAndKeywordsCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $LogsAndKeywordsCopyWith<$Res> { - factory $LogsAndKeywordsCopyWith( - LogsAndKeywords value, $Res Function(LogsAndKeywords) then) = - _$LogsAndKeywordsCopyWithImpl<$Res, LogsAndKeywords>; - @useResult - $Res call({List logs, List keywords}); -} - -/// @nodoc -class _$LogsAndKeywordsCopyWithImpl<$Res, $Val extends LogsAndKeywords> - implements $LogsAndKeywordsCopyWith<$Res> { - _$LogsAndKeywordsCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? logs = null, - Object? keywords = null, - }) { - return _then(_value.copyWith( - logs: null == logs - ? _value.logs - : logs // ignore: cast_nullable_to_non_nullable - as List, - keywords: null == keywords - ? _value.keywords - : keywords // ignore: cast_nullable_to_non_nullable - as List, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$LogsAndKeywordsImplCopyWith<$Res> - implements $LogsAndKeywordsCopyWith<$Res> { - factory _$$LogsAndKeywordsImplCopyWith(_$LogsAndKeywordsImpl value, - $Res Function(_$LogsAndKeywordsImpl) then) = - __$$LogsAndKeywordsImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({List logs, List keywords}); -} - -/// @nodoc -class __$$LogsAndKeywordsImplCopyWithImpl<$Res> - extends _$LogsAndKeywordsCopyWithImpl<$Res, _$LogsAndKeywordsImpl> - implements _$$LogsAndKeywordsImplCopyWith<$Res> { - __$$LogsAndKeywordsImplCopyWithImpl( - _$LogsAndKeywordsImpl _value, $Res Function(_$LogsAndKeywordsImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? logs = null, - Object? keywords = null, - }) { - return _then(_$LogsAndKeywordsImpl( - logs: null == logs - ? _value._logs - : logs // ignore: cast_nullable_to_non_nullable - as List, - keywords: null == keywords - ? _value._keywords - : keywords // ignore: cast_nullable_to_non_nullable - as List, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$LogsAndKeywordsImpl implements _LogsAndKeywords { - const _$LogsAndKeywordsImpl( - {final List logs = const [], final List keywords = const []}) - : _logs = logs, - _keywords = keywords; - - factory _$LogsAndKeywordsImpl.fromJson(Map json) => - _$$LogsAndKeywordsImplFromJson(json); - - final List _logs; - @override - @JsonKey() - List get logs { - if (_logs is EqualUnmodifiableListView) return _logs; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_logs); - } - - final List _keywords; - @override - @JsonKey() - List get keywords { - if (_keywords is EqualUnmodifiableListView) return _keywords; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_keywords); - } - - @override - String toString() { - return 'LogsAndKeywords(logs: $logs, keywords: $keywords)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$LogsAndKeywordsImpl && - const DeepCollectionEquality().equals(other._logs, _logs) && - const DeepCollectionEquality().equals(other._keywords, _keywords)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => Object.hash( - runtimeType, - const DeepCollectionEquality().hash(_logs), - const DeepCollectionEquality().hash(_keywords)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$LogsAndKeywordsImplCopyWith<_$LogsAndKeywordsImpl> get copyWith => - __$$LogsAndKeywordsImplCopyWithImpl<_$LogsAndKeywordsImpl>( - this, _$identity); - - @override - Map toJson() { - return _$$LogsAndKeywordsImplToJson( - this, - ); - } -} - -abstract class _LogsAndKeywords implements LogsAndKeywords { - const factory _LogsAndKeywords( - {final List logs, - final List keywords}) = _$LogsAndKeywordsImpl; - - factory _LogsAndKeywords.fromJson(Map json) = - _$LogsAndKeywordsImpl.fromJson; - - @override - List get logs; - @override - List get keywords; - @override - @JsonKey(ignore: true) - _$$LogsAndKeywordsImplCopyWith<_$LogsAndKeywordsImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/models/generated/log.g.dart b/lib/models/generated/log.g.dart deleted file mode 100644 index ecd47d8..0000000 --- a/lib/models/generated/log.g.dart +++ /dev/null @@ -1,45 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of '../log.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -Log _$LogFromJson(Map json) => Log( - logLevel: $enumDecode(_$LogLevelEnumMap, json['LogLevel']), - payload: json['Payload'] as String?, - ); - -Map _$LogToJson(Log instance) => { - 'LogLevel': _$LogLevelEnumMap[instance.logLevel]!, - 'Payload': instance.payload, - }; - -const _$LogLevelEnumMap = { - LogLevel.debug: 'debug', - LogLevel.info: 'info', - LogLevel.warning: 'warning', - LogLevel.error: 'error', - LogLevel.silent: 'silent', -}; - -_$LogsAndKeywordsImpl _$$LogsAndKeywordsImplFromJson( - Map json) => - _$LogsAndKeywordsImpl( - logs: (json['logs'] as List?) - ?.map((e) => Log.fromJson(e as Map)) - .toList() ?? - const [], - keywords: (json['keywords'] as List?) - ?.map((e) => e as String) - .toList() ?? - const [], - ); - -Map _$$LogsAndKeywordsImplToJson( - _$LogsAndKeywordsImpl instance) => - { - 'logs': instance.logs, - 'keywords': instance.keywords, - }; diff --git a/lib/models/generated/navigation.freezed.dart b/lib/models/generated/navigation.freezed.dart deleted file mode 100644 index c2d4a8e..0000000 --- a/lib/models/generated/navigation.freezed.dart +++ /dev/null @@ -1,271 +0,0 @@ -// 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 '../navigation.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 _$NavigationItem { - Icon get icon => throw _privateConstructorUsedError; - String get label => throw _privateConstructorUsedError; - String? get description => throw _privateConstructorUsedError; - Widget get fragment => throw _privateConstructorUsedError; - bool get keep => throw _privateConstructorUsedError; - String? get path => throw _privateConstructorUsedError; - List get modes => throw _privateConstructorUsedError; - - @JsonKey(ignore: true) - $NavigationItemCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $NavigationItemCopyWith<$Res> { - factory $NavigationItemCopyWith( - NavigationItem value, $Res Function(NavigationItem) then) = - _$NavigationItemCopyWithImpl<$Res, NavigationItem>; - @useResult - $Res call( - {Icon icon, - String label, - String? description, - Widget fragment, - bool keep, - String? path, - List modes}); -} - -/// @nodoc -class _$NavigationItemCopyWithImpl<$Res, $Val extends NavigationItem> - implements $NavigationItemCopyWith<$Res> { - _$NavigationItemCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? icon = null, - Object? label = null, - Object? description = freezed, - Object? fragment = null, - Object? keep = null, - Object? path = freezed, - Object? modes = null, - }) { - return _then(_value.copyWith( - icon: null == icon - ? _value.icon - : icon // ignore: cast_nullable_to_non_nullable - as Icon, - label: null == label - ? _value.label - : label // ignore: cast_nullable_to_non_nullable - as String, - description: freezed == description - ? _value.description - : description // ignore: cast_nullable_to_non_nullable - as String?, - fragment: null == fragment - ? _value.fragment - : fragment // ignore: cast_nullable_to_non_nullable - as Widget, - keep: null == keep - ? _value.keep - : keep // ignore: cast_nullable_to_non_nullable - as bool, - path: freezed == path - ? _value.path - : path // ignore: cast_nullable_to_non_nullable - as String?, - modes: null == modes - ? _value.modes - : modes // ignore: cast_nullable_to_non_nullable - as List, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$NavigationItemImplCopyWith<$Res> - implements $NavigationItemCopyWith<$Res> { - factory _$$NavigationItemImplCopyWith(_$NavigationItemImpl value, - $Res Function(_$NavigationItemImpl) then) = - __$$NavigationItemImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {Icon icon, - String label, - String? description, - Widget fragment, - bool keep, - String? path, - List modes}); -} - -/// @nodoc -class __$$NavigationItemImplCopyWithImpl<$Res> - extends _$NavigationItemCopyWithImpl<$Res, _$NavigationItemImpl> - implements _$$NavigationItemImplCopyWith<$Res> { - __$$NavigationItemImplCopyWithImpl( - _$NavigationItemImpl _value, $Res Function(_$NavigationItemImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? icon = null, - Object? label = null, - Object? description = freezed, - Object? fragment = null, - Object? keep = null, - Object? path = freezed, - Object? modes = null, - }) { - return _then(_$NavigationItemImpl( - icon: null == icon - ? _value.icon - : icon // ignore: cast_nullable_to_non_nullable - as Icon, - label: null == label - ? _value.label - : label // ignore: cast_nullable_to_non_nullable - as String, - description: freezed == description - ? _value.description - : description // ignore: cast_nullable_to_non_nullable - as String?, - fragment: null == fragment - ? _value.fragment - : fragment // ignore: cast_nullable_to_non_nullable - as Widget, - keep: null == keep - ? _value.keep - : keep // ignore: cast_nullable_to_non_nullable - as bool, - path: freezed == path - ? _value.path - : path // ignore: cast_nullable_to_non_nullable - as String?, - modes: null == modes - ? _value._modes - : modes // ignore: cast_nullable_to_non_nullable - as List, - )); - } -} - -/// @nodoc - -class _$NavigationItemImpl implements _NavigationItem { - const _$NavigationItemImpl( - {required this.icon, - required this.label, - this.description, - required this.fragment, - this.keep = true, - this.path, - final List modes = const [ - NavigationItemMode.mobile, - NavigationItemMode.desktop - ]}) - : _modes = modes; - - @override - final Icon icon; - @override - final String label; - @override - final String? description; - @override - final Widget fragment; - @override - @JsonKey() - final bool keep; - @override - final String? path; - final List _modes; - @override - @JsonKey() - List get modes { - if (_modes is EqualUnmodifiableListView) return _modes; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_modes); - } - - @override - String toString() { - return 'NavigationItem(icon: $icon, label: $label, description: $description, fragment: $fragment, keep: $keep, path: $path, modes: $modes)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$NavigationItemImpl && - (identical(other.icon, icon) || other.icon == icon) && - (identical(other.label, label) || other.label == label) && - (identical(other.description, description) || - other.description == description) && - (identical(other.fragment, fragment) || - other.fragment == fragment) && - (identical(other.keep, keep) || other.keep == keep) && - (identical(other.path, path) || other.path == path) && - const DeepCollectionEquality().equals(other._modes, _modes)); - } - - @override - int get hashCode => Object.hash(runtimeType, icon, label, description, - fragment, keep, path, const DeepCollectionEquality().hash(_modes)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$NavigationItemImplCopyWith<_$NavigationItemImpl> get copyWith => - __$$NavigationItemImplCopyWithImpl<_$NavigationItemImpl>( - this, _$identity); -} - -abstract class _NavigationItem implements NavigationItem { - const factory _NavigationItem( - {required final Icon icon, - required final String label, - final String? description, - required final Widget fragment, - final bool keep, - final String? path, - final List modes}) = _$NavigationItemImpl; - - @override - Icon get icon; - @override - String get label; - @override - String? get description; - @override - Widget get fragment; - @override - bool get keep; - @override - String? get path; - @override - List get modes; - @override - @JsonKey(ignore: true) - _$$NavigationItemImplCopyWith<_$NavigationItemImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/models/generated/package.freezed.dart b/lib/models/generated/package.freezed.dart deleted file mode 100644 index 5b479a5..0000000 --- a/lib/models/generated/package.freezed.dart +++ /dev/null @@ -1,209 +0,0 @@ -// 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 '../package.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'); - -Package _$PackageFromJson(Map json) { - return _Package.fromJson(json); -} - -/// @nodoc -mixin _$Package { - String get packageName => throw _privateConstructorUsedError; - String get label => throw _privateConstructorUsedError; - bool get isSystem => throw _privateConstructorUsedError; - int get firstInstallTime => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $PackageCopyWith get copyWith => throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $PackageCopyWith<$Res> { - factory $PackageCopyWith(Package value, $Res Function(Package) then) = - _$PackageCopyWithImpl<$Res, Package>; - @useResult - $Res call( - {String packageName, String label, bool isSystem, int firstInstallTime}); -} - -/// @nodoc -class _$PackageCopyWithImpl<$Res, $Val extends Package> - implements $PackageCopyWith<$Res> { - _$PackageCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? packageName = null, - Object? label = null, - Object? isSystem = null, - Object? firstInstallTime = null, - }) { - return _then(_value.copyWith( - packageName: null == packageName - ? _value.packageName - : packageName // ignore: cast_nullable_to_non_nullable - as String, - label: null == label - ? _value.label - : label // ignore: cast_nullable_to_non_nullable - as String, - isSystem: null == isSystem - ? _value.isSystem - : isSystem // ignore: cast_nullable_to_non_nullable - as bool, - firstInstallTime: null == firstInstallTime - ? _value.firstInstallTime - : firstInstallTime // ignore: cast_nullable_to_non_nullable - as int, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$PackageImplCopyWith<$Res> implements $PackageCopyWith<$Res> { - factory _$$PackageImplCopyWith( - _$PackageImpl value, $Res Function(_$PackageImpl) then) = - __$$PackageImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String packageName, String label, bool isSystem, int firstInstallTime}); -} - -/// @nodoc -class __$$PackageImplCopyWithImpl<$Res> - extends _$PackageCopyWithImpl<$Res, _$PackageImpl> - implements _$$PackageImplCopyWith<$Res> { - __$$PackageImplCopyWithImpl( - _$PackageImpl _value, $Res Function(_$PackageImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? packageName = null, - Object? label = null, - Object? isSystem = null, - Object? firstInstallTime = null, - }) { - return _then(_$PackageImpl( - packageName: null == packageName - ? _value.packageName - : packageName // ignore: cast_nullable_to_non_nullable - as String, - label: null == label - ? _value.label - : label // ignore: cast_nullable_to_non_nullable - as String, - isSystem: null == isSystem - ? _value.isSystem - : isSystem // ignore: cast_nullable_to_non_nullable - as bool, - firstInstallTime: null == firstInstallTime - ? _value.firstInstallTime - : firstInstallTime // ignore: cast_nullable_to_non_nullable - as int, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$PackageImpl implements _Package { - const _$PackageImpl( - {required this.packageName, - required this.label, - required this.isSystem, - required this.firstInstallTime}); - - factory _$PackageImpl.fromJson(Map json) => - _$$PackageImplFromJson(json); - - @override - final String packageName; - @override - final String label; - @override - final bool isSystem; - @override - final int firstInstallTime; - - @override - String toString() { - return 'Package(packageName: $packageName, label: $label, isSystem: $isSystem, firstInstallTime: $firstInstallTime)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$PackageImpl && - (identical(other.packageName, packageName) || - other.packageName == packageName) && - (identical(other.label, label) || other.label == label) && - (identical(other.isSystem, isSystem) || - other.isSystem == isSystem) && - (identical(other.firstInstallTime, firstInstallTime) || - other.firstInstallTime == firstInstallTime)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => - Object.hash(runtimeType, packageName, label, isSystem, firstInstallTime); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$PackageImplCopyWith<_$PackageImpl> get copyWith => - __$$PackageImplCopyWithImpl<_$PackageImpl>(this, _$identity); - - @override - Map toJson() { - return _$$PackageImplToJson( - this, - ); - } -} - -abstract class _Package implements Package { - const factory _Package( - {required final String packageName, - required final String label, - required final bool isSystem, - required final int firstInstallTime}) = _$PackageImpl; - - factory _Package.fromJson(Map json) = _$PackageImpl.fromJson; - - @override - String get packageName; - @override - String get label; - @override - bool get isSystem; - @override - int get firstInstallTime; - @override - @JsonKey(ignore: true) - _$$PackageImplCopyWith<_$PackageImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/models/generated/package.g.dart b/lib/models/generated/package.g.dart deleted file mode 100644 index 3d212e7..0000000 --- a/lib/models/generated/package.g.dart +++ /dev/null @@ -1,23 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of '../package.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_$PackageImpl _$$PackageImplFromJson(Map json) => - _$PackageImpl( - packageName: json['packageName'] as String, - label: json['label'] as String, - isSystem: json['isSystem'] as bool, - firstInstallTime: (json['firstInstallTime'] as num).toInt(), - ); - -Map _$$PackageImplToJson(_$PackageImpl instance) => - { - 'packageName': instance.packageName, - 'label': instance.label, - 'isSystem': instance.isSystem, - 'firstInstallTime': instance.firstInstallTime, - }; diff --git a/lib/models/generated/proxy.freezed.dart b/lib/models/generated/proxy.freezed.dart deleted file mode 100644 index 2e20232..0000000 --- a/lib/models/generated/proxy.freezed.dart +++ /dev/null @@ -1,428 +0,0 @@ -// 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 '../proxy.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'); - -Group _$GroupFromJson(Map json) { - return _Group.fromJson(json); -} - -/// @nodoc -mixin _$Group { - GroupType get type => throw _privateConstructorUsedError; - List get all => throw _privateConstructorUsedError; - String? get now => throw _privateConstructorUsedError; - bool? get hidden => throw _privateConstructorUsedError; - String get icon => throw _privateConstructorUsedError; - String get name => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $GroupCopyWith get copyWith => throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $GroupCopyWith<$Res> { - factory $GroupCopyWith(Group value, $Res Function(Group) then) = - _$GroupCopyWithImpl<$Res, Group>; - @useResult - $Res call( - {GroupType type, - List all, - String? now, - bool? hidden, - String icon, - String name}); -} - -/// @nodoc -class _$GroupCopyWithImpl<$Res, $Val extends Group> - implements $GroupCopyWith<$Res> { - _$GroupCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? type = null, - Object? all = null, - Object? now = freezed, - Object? hidden = freezed, - Object? icon = null, - Object? name = null, - }) { - return _then(_value.copyWith( - type: null == type - ? _value.type - : type // ignore: cast_nullable_to_non_nullable - as GroupType, - all: null == all - ? _value.all - : all // ignore: cast_nullable_to_non_nullable - as List, - now: freezed == now - ? _value.now - : now // ignore: cast_nullable_to_non_nullable - as String?, - hidden: freezed == hidden - ? _value.hidden - : hidden // ignore: cast_nullable_to_non_nullable - as bool?, - icon: null == icon - ? _value.icon - : icon // ignore: cast_nullable_to_non_nullable - as String, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$GroupImplCopyWith<$Res> implements $GroupCopyWith<$Res> { - factory _$$GroupImplCopyWith( - _$GroupImpl value, $Res Function(_$GroupImpl) then) = - __$$GroupImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {GroupType type, - List all, - String? now, - bool? hidden, - String icon, - String name}); -} - -/// @nodoc -class __$$GroupImplCopyWithImpl<$Res> - extends _$GroupCopyWithImpl<$Res, _$GroupImpl> - implements _$$GroupImplCopyWith<$Res> { - __$$GroupImplCopyWithImpl( - _$GroupImpl _value, $Res Function(_$GroupImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? type = null, - Object? all = null, - Object? now = freezed, - Object? hidden = freezed, - Object? icon = null, - Object? name = null, - }) { - return _then(_$GroupImpl( - type: null == type - ? _value.type - : type // ignore: cast_nullable_to_non_nullable - as GroupType, - all: null == all - ? _value._all - : all // ignore: cast_nullable_to_non_nullable - as List, - now: freezed == now - ? _value.now - : now // ignore: cast_nullable_to_non_nullable - as String?, - hidden: freezed == hidden - ? _value.hidden - : hidden // ignore: cast_nullable_to_non_nullable - as bool?, - icon: null == icon - ? _value.icon - : icon // ignore: cast_nullable_to_non_nullable - as String, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$GroupImpl implements _Group { - const _$GroupImpl( - {required this.type, - final List all = const [], - this.now, - this.hidden, - this.icon = "", - required this.name}) - : _all = all; - - factory _$GroupImpl.fromJson(Map json) => - _$$GroupImplFromJson(json); - - @override - final GroupType type; - final List _all; - @override - @JsonKey() - List get all { - if (_all is EqualUnmodifiableListView) return _all; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_all); - } - - @override - final String? now; - @override - final bool? hidden; - @override - @JsonKey() - final String icon; - @override - final String name; - - @override - String toString() { - return 'Group(type: $type, all: $all, now: $now, hidden: $hidden, icon: $icon, name: $name)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$GroupImpl && - (identical(other.type, type) || other.type == type) && - const DeepCollectionEquality().equals(other._all, _all) && - (identical(other.now, now) || other.now == now) && - (identical(other.hidden, hidden) || other.hidden == hidden) && - (identical(other.icon, icon) || other.icon == icon) && - (identical(other.name, name) || other.name == name)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => Object.hash(runtimeType, type, - const DeepCollectionEquality().hash(_all), now, hidden, icon, name); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$GroupImplCopyWith<_$GroupImpl> get copyWith => - __$$GroupImplCopyWithImpl<_$GroupImpl>(this, _$identity); - - @override - Map toJson() { - return _$$GroupImplToJson( - this, - ); - } -} - -abstract class _Group implements Group { - const factory _Group( - {required final GroupType type, - final List all, - final String? now, - final bool? hidden, - final String icon, - required final String name}) = _$GroupImpl; - - factory _Group.fromJson(Map json) = _$GroupImpl.fromJson; - - @override - GroupType get type; - @override - List get all; - @override - String? get now; - @override - bool? get hidden; - @override - String get icon; - @override - String get name; - @override - @JsonKey(ignore: true) - _$$GroupImplCopyWith<_$GroupImpl> get copyWith => - 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; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $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; - - @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); - - @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(ignore: true) - @override - int get hashCode => Object.hash(runtimeType, name, type, now); - - @JsonKey(ignore: true) - @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; - @override - @JsonKey(ignore: true) - _$$ProxyImplCopyWith<_$ProxyImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/models/generated/proxy.g.dart b/lib/models/generated/proxy.g.dart deleted file mode 100644 index c9a1213..0000000 --- a/lib/models/generated/proxy.g.dart +++ /dev/null @@ -1,50 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of '../proxy.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_$GroupImpl _$$GroupImplFromJson(Map json) => _$GroupImpl( - type: $enumDecode(_$GroupTypeEnumMap, json['type']), - all: (json['all'] as List?) - ?.map((e) => Proxy.fromJson(e as Map)) - .toList() ?? - const [], - now: json['now'] as String?, - hidden: json['hidden'] as bool?, - icon: json['icon'] as String? ?? "", - name: json['name'] as String, - ); - -Map _$$GroupImplToJson(_$GroupImpl instance) => - { - 'type': _$GroupTypeEnumMap[instance.type]!, - 'all': instance.all, - 'now': instance.now, - 'hidden': instance.hidden, - 'icon': instance.icon, - 'name': instance.name, - }; - -const _$GroupTypeEnumMap = { - GroupType.Selector: 'Selector', - GroupType.URLTest: 'URLTest', - GroupType.Fallback: 'Fallback', - GroupType.LoadBalance: 'LoadBalance', - 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, - }; diff --git a/lib/models/generated/selector.freezed.dart b/lib/models/generated/selector.freezed.dart index 7dba063..e1640f8 100644 --- a/lib/models/generated/selector.freezed.dart +++ b/lib/models/generated/selector.freezed.dart @@ -957,25 +957,24 @@ abstract class _ApplicationSelectorState implements ApplicationSelectorState { } /// @nodoc -mixin _$TrayContainerSelectorState { +mixin _$TrayState { Mode get mode => throw _privateConstructorUsedError; bool get autoLaunch => throw _privateConstructorUsedError; bool get systemProxy => throw _privateConstructorUsedError; bool get tunEnable => throw _privateConstructorUsedError; bool get isStart => throw _privateConstructorUsedError; String? get locale => throw _privateConstructorUsedError; + Brightness? get brightness => throw _privateConstructorUsedError; @JsonKey(ignore: true) - $TrayContainerSelectorStateCopyWith - get copyWith => throw _privateConstructorUsedError; + $TrayStateCopyWith get copyWith => + throw _privateConstructorUsedError; } /// @nodoc -abstract class $TrayContainerSelectorStateCopyWith<$Res> { - factory $TrayContainerSelectorStateCopyWith(TrayContainerSelectorState value, - $Res Function(TrayContainerSelectorState) then) = - _$TrayContainerSelectorStateCopyWithImpl<$Res, - TrayContainerSelectorState>; +abstract class $TrayStateCopyWith<$Res> { + factory $TrayStateCopyWith(TrayState value, $Res Function(TrayState) then) = + _$TrayStateCopyWithImpl<$Res, TrayState>; @useResult $Res call( {Mode mode, @@ -983,14 +982,14 @@ abstract class $TrayContainerSelectorStateCopyWith<$Res> { bool systemProxy, bool tunEnable, bool isStart, - String? locale}); + String? locale, + Brightness? brightness}); } /// @nodoc -class _$TrayContainerSelectorStateCopyWithImpl<$Res, - $Val extends TrayContainerSelectorState> - implements $TrayContainerSelectorStateCopyWith<$Res> { - _$TrayContainerSelectorStateCopyWithImpl(this._value, this._then); +class _$TrayStateCopyWithImpl<$Res, $Val extends TrayState> + implements $TrayStateCopyWith<$Res> { + _$TrayStateCopyWithImpl(this._value, this._then); // ignore: unused_field final $Val _value; @@ -1006,6 +1005,7 @@ class _$TrayContainerSelectorStateCopyWithImpl<$Res, Object? tunEnable = null, Object? isStart = null, Object? locale = freezed, + Object? brightness = freezed, }) { return _then(_value.copyWith( mode: null == mode @@ -1032,17 +1032,20 @@ class _$TrayContainerSelectorStateCopyWithImpl<$Res, ? _value.locale : locale // ignore: cast_nullable_to_non_nullable as String?, + brightness: freezed == brightness + ? _value.brightness + : brightness // ignore: cast_nullable_to_non_nullable + as Brightness?, ) as $Val); } } /// @nodoc -abstract class _$$TrayContainerSelectorStateImplCopyWith<$Res> - implements $TrayContainerSelectorStateCopyWith<$Res> { - factory _$$TrayContainerSelectorStateImplCopyWith( - _$TrayContainerSelectorStateImpl value, - $Res Function(_$TrayContainerSelectorStateImpl) then) = - __$$TrayContainerSelectorStateImplCopyWithImpl<$Res>; +abstract class _$$TrayStateImplCopyWith<$Res> + implements $TrayStateCopyWith<$Res> { + factory _$$TrayStateImplCopyWith( + _$TrayStateImpl value, $Res Function(_$TrayStateImpl) then) = + __$$TrayStateImplCopyWithImpl<$Res>; @override @useResult $Res call( @@ -1051,17 +1054,16 @@ abstract class _$$TrayContainerSelectorStateImplCopyWith<$Res> bool systemProxy, bool tunEnable, bool isStart, - String? locale}); + String? locale, + Brightness? brightness}); } /// @nodoc -class __$$TrayContainerSelectorStateImplCopyWithImpl<$Res> - extends _$TrayContainerSelectorStateCopyWithImpl<$Res, - _$TrayContainerSelectorStateImpl> - implements _$$TrayContainerSelectorStateImplCopyWith<$Res> { - __$$TrayContainerSelectorStateImplCopyWithImpl( - _$TrayContainerSelectorStateImpl _value, - $Res Function(_$TrayContainerSelectorStateImpl) _then) +class __$$TrayStateImplCopyWithImpl<$Res> + extends _$TrayStateCopyWithImpl<$Res, _$TrayStateImpl> + implements _$$TrayStateImplCopyWith<$Res> { + __$$TrayStateImplCopyWithImpl( + _$TrayStateImpl _value, $Res Function(_$TrayStateImpl) _then) : super(_value, _then); @pragma('vm:prefer-inline') @@ -1073,8 +1075,9 @@ class __$$TrayContainerSelectorStateImplCopyWithImpl<$Res> Object? tunEnable = null, Object? isStart = null, Object? locale = freezed, + Object? brightness = freezed, }) { - return _then(_$TrayContainerSelectorStateImpl( + return _then(_$TrayStateImpl( mode: null == mode ? _value.mode : mode // ignore: cast_nullable_to_non_nullable @@ -1099,20 +1102,25 @@ class __$$TrayContainerSelectorStateImplCopyWithImpl<$Res> ? _value.locale : locale // ignore: cast_nullable_to_non_nullable as String?, + brightness: freezed == brightness + ? _value.brightness + : brightness // ignore: cast_nullable_to_non_nullable + as Brightness?, )); } } /// @nodoc -class _$TrayContainerSelectorStateImpl implements _TrayContainerSelectorState { - const _$TrayContainerSelectorStateImpl( +class _$TrayStateImpl implements _TrayState { + const _$TrayStateImpl( {required this.mode, required this.autoLaunch, required this.systemProxy, required this.tunEnable, required this.isStart, - required this.locale}); + required this.locale, + required this.brightness}); @override final Mode mode; @@ -1126,17 +1134,19 @@ class _$TrayContainerSelectorStateImpl implements _TrayContainerSelectorState { final bool isStart; @override final String? locale; + @override + final Brightness? brightness; @override String toString() { - return 'TrayContainerSelectorState(mode: $mode, autoLaunch: $autoLaunch, systemProxy: $systemProxy, tunEnable: $tunEnable, isStart: $isStart, locale: $locale)'; + return 'TrayState(mode: $mode, autoLaunch: $autoLaunch, systemProxy: $systemProxy, tunEnable: $tunEnable, isStart: $isStart, locale: $locale, brightness: $brightness)'; } @override bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && - other is _$TrayContainerSelectorStateImpl && + other is _$TrayStateImpl && (identical(other.mode, mode) || other.mode == mode) && (identical(other.autoLaunch, autoLaunch) || other.autoLaunch == autoLaunch) && @@ -1145,30 +1155,31 @@ class _$TrayContainerSelectorStateImpl implements _TrayContainerSelectorState { (identical(other.tunEnable, tunEnable) || other.tunEnable == tunEnable) && (identical(other.isStart, isStart) || other.isStart == isStart) && - (identical(other.locale, locale) || other.locale == locale)); + (identical(other.locale, locale) || other.locale == locale) && + (identical(other.brightness, brightness) || + other.brightness == brightness)); } @override - int get hashCode => Object.hash( - runtimeType, mode, autoLaunch, systemProxy, tunEnable, isStart, locale); + int get hashCode => Object.hash(runtimeType, mode, autoLaunch, systemProxy, + tunEnable, isStart, locale, brightness); @JsonKey(ignore: true) @override @pragma('vm:prefer-inline') - _$$TrayContainerSelectorStateImplCopyWith<_$TrayContainerSelectorStateImpl> - get copyWith => __$$TrayContainerSelectorStateImplCopyWithImpl< - _$TrayContainerSelectorStateImpl>(this, _$identity); + _$$TrayStateImplCopyWith<_$TrayStateImpl> get copyWith => + __$$TrayStateImplCopyWithImpl<_$TrayStateImpl>(this, _$identity); } -abstract class _TrayContainerSelectorState - implements TrayContainerSelectorState { - const factory _TrayContainerSelectorState( +abstract class _TrayState implements TrayState { + const factory _TrayState( {required final Mode mode, required final bool autoLaunch, required final bool systemProxy, required final bool tunEnable, required final bool isStart, - required final String? locale}) = _$TrayContainerSelectorStateImpl; + required final String? locale, + required final Brightness? brightness}) = _$TrayStateImpl; @override Mode get mode; @@ -1183,9 +1194,11 @@ abstract class _TrayContainerSelectorState @override String? get locale; @override + Brightness? get brightness; + @override @JsonKey(ignore: true) - _$$TrayContainerSelectorStateImplCopyWith<_$TrayContainerSelectorStateImpl> - get copyWith => throw _privateConstructorUsedError; + _$$TrayStateImplCopyWith<_$TrayStateImpl> get copyWith => + throw _privateConstructorUsedError; } /// @nodoc @@ -1332,7 +1345,7 @@ abstract class _UpdateNavigationsSelector implements UpdateNavigationsSelector { } /// @nodoc -mixin _$HomeSelectorState { +mixin _$HomeState { String get currentLabel => throw _privateConstructorUsedError; List get navigationItems => throw _privateConstructorUsedError; @@ -1340,15 +1353,14 @@ mixin _$HomeSelectorState { String? get locale => throw _privateConstructorUsedError; @JsonKey(ignore: true) - $HomeSelectorStateCopyWith get copyWith => + $HomeStateCopyWith get copyWith => throw _privateConstructorUsedError; } /// @nodoc -abstract class $HomeSelectorStateCopyWith<$Res> { - factory $HomeSelectorStateCopyWith( - HomeSelectorState value, $Res Function(HomeSelectorState) then) = - _$HomeSelectorStateCopyWithImpl<$Res, HomeSelectorState>; +abstract class $HomeStateCopyWith<$Res> { + factory $HomeStateCopyWith(HomeState value, $Res Function(HomeState) then) = + _$HomeStateCopyWithImpl<$Res, HomeState>; @useResult $Res call( {String currentLabel, @@ -1358,9 +1370,9 @@ abstract class $HomeSelectorStateCopyWith<$Res> { } /// @nodoc -class _$HomeSelectorStateCopyWithImpl<$Res, $Val extends HomeSelectorState> - implements $HomeSelectorStateCopyWith<$Res> { - _$HomeSelectorStateCopyWithImpl(this._value, this._then); +class _$HomeStateCopyWithImpl<$Res, $Val extends HomeState> + implements $HomeStateCopyWith<$Res> { + _$HomeStateCopyWithImpl(this._value, this._then); // ignore: unused_field final $Val _value; @@ -1397,11 +1409,11 @@ class _$HomeSelectorStateCopyWithImpl<$Res, $Val extends HomeSelectorState> } /// @nodoc -abstract class _$$HomeSelectorStateImplCopyWith<$Res> - implements $HomeSelectorStateCopyWith<$Res> { - factory _$$HomeSelectorStateImplCopyWith(_$HomeSelectorStateImpl value, - $Res Function(_$HomeSelectorStateImpl) then) = - __$$HomeSelectorStateImplCopyWithImpl<$Res>; +abstract class _$$HomeStateImplCopyWith<$Res> + implements $HomeStateCopyWith<$Res> { + factory _$$HomeStateImplCopyWith( + _$HomeStateImpl value, $Res Function(_$HomeStateImpl) then) = + __$$HomeStateImplCopyWithImpl<$Res>; @override @useResult $Res call( @@ -1412,11 +1424,11 @@ abstract class _$$HomeSelectorStateImplCopyWith<$Res> } /// @nodoc -class __$$HomeSelectorStateImplCopyWithImpl<$Res> - extends _$HomeSelectorStateCopyWithImpl<$Res, _$HomeSelectorStateImpl> - implements _$$HomeSelectorStateImplCopyWith<$Res> { - __$$HomeSelectorStateImplCopyWithImpl(_$HomeSelectorStateImpl _value, - $Res Function(_$HomeSelectorStateImpl) _then) +class __$$HomeStateImplCopyWithImpl<$Res> + extends _$HomeStateCopyWithImpl<$Res, _$HomeStateImpl> + implements _$$HomeStateImplCopyWith<$Res> { + __$$HomeStateImplCopyWithImpl( + _$HomeStateImpl _value, $Res Function(_$HomeStateImpl) _then) : super(_value, _then); @pragma('vm:prefer-inline') @@ -1427,7 +1439,7 @@ class __$$HomeSelectorStateImplCopyWithImpl<$Res> Object? viewMode = null, Object? locale = freezed, }) { - return _then(_$HomeSelectorStateImpl( + return _then(_$HomeStateImpl( currentLabel: null == currentLabel ? _value.currentLabel : currentLabel // ignore: cast_nullable_to_non_nullable @@ -1450,8 +1462,8 @@ class __$$HomeSelectorStateImplCopyWithImpl<$Res> /// @nodoc -class _$HomeSelectorStateImpl implements _HomeSelectorState { - const _$HomeSelectorStateImpl( +class _$HomeStateImpl implements _HomeState { + const _$HomeStateImpl( {required this.currentLabel, required final List navigationItems, required this.viewMode, @@ -1475,14 +1487,14 @@ class _$HomeSelectorStateImpl implements _HomeSelectorState { @override String toString() { - return 'HomeSelectorState(currentLabel: $currentLabel, navigationItems: $navigationItems, viewMode: $viewMode, locale: $locale)'; + return 'HomeState(currentLabel: $currentLabel, navigationItems: $navigationItems, viewMode: $viewMode, locale: $locale)'; } @override bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && - other is _$HomeSelectorStateImpl && + other is _$HomeStateImpl && (identical(other.currentLabel, currentLabel) || other.currentLabel == currentLabel) && const DeepCollectionEquality() @@ -1499,17 +1511,16 @@ class _$HomeSelectorStateImpl implements _HomeSelectorState { @JsonKey(ignore: true) @override @pragma('vm:prefer-inline') - _$$HomeSelectorStateImplCopyWith<_$HomeSelectorStateImpl> get copyWith => - __$$HomeSelectorStateImplCopyWithImpl<_$HomeSelectorStateImpl>( - this, _$identity); + _$$HomeStateImplCopyWith<_$HomeStateImpl> get copyWith => + __$$HomeStateImplCopyWithImpl<_$HomeStateImpl>(this, _$identity); } -abstract class _HomeSelectorState implements HomeSelectorState { - const factory _HomeSelectorState( +abstract class _HomeState implements HomeState { + const factory _HomeState( {required final String currentLabel, required final List navigationItems, required final ViewMode viewMode, - required final String? locale}) = _$HomeSelectorStateImpl; + required final String? locale}) = _$HomeStateImpl; @override String get currentLabel; @@ -1521,143 +1532,10 @@ abstract class _HomeSelectorState implements HomeSelectorState { String? get locale; @override @JsonKey(ignore: true) - _$$HomeSelectorStateImplCopyWith<_$HomeSelectorStateImpl> get copyWith => + _$$HomeStateImplCopyWith<_$HomeStateImpl> get copyWith => throw _privateConstructorUsedError; } -/// @nodoc -mixin _$HomeBodySelectorState { - List get navigationItems => - throw _privateConstructorUsedError; - - @JsonKey(ignore: true) - $HomeBodySelectorStateCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $HomeBodySelectorStateCopyWith<$Res> { - factory $HomeBodySelectorStateCopyWith(HomeBodySelectorState value, - $Res Function(HomeBodySelectorState) then) = - _$HomeBodySelectorStateCopyWithImpl<$Res, HomeBodySelectorState>; - @useResult - $Res call({List navigationItems}); -} - -/// @nodoc -class _$HomeBodySelectorStateCopyWithImpl<$Res, - $Val extends HomeBodySelectorState> - implements $HomeBodySelectorStateCopyWith<$Res> { - _$HomeBodySelectorStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? navigationItems = null, - }) { - return _then(_value.copyWith( - navigationItems: null == navigationItems - ? _value.navigationItems - : navigationItems // ignore: cast_nullable_to_non_nullable - as List, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$HomeBodySelectorStateImplCopyWith<$Res> - implements $HomeBodySelectorStateCopyWith<$Res> { - factory _$$HomeBodySelectorStateImplCopyWith( - _$HomeBodySelectorStateImpl value, - $Res Function(_$HomeBodySelectorStateImpl) then) = - __$$HomeBodySelectorStateImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({List navigationItems}); -} - -/// @nodoc -class __$$HomeBodySelectorStateImplCopyWithImpl<$Res> - extends _$HomeBodySelectorStateCopyWithImpl<$Res, - _$HomeBodySelectorStateImpl> - implements _$$HomeBodySelectorStateImplCopyWith<$Res> { - __$$HomeBodySelectorStateImplCopyWithImpl(_$HomeBodySelectorStateImpl _value, - $Res Function(_$HomeBodySelectorStateImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? navigationItems = null, - }) { - return _then(_$HomeBodySelectorStateImpl( - navigationItems: null == navigationItems - ? _value._navigationItems - : navigationItems // ignore: cast_nullable_to_non_nullable - as List, - )); - } -} - -/// @nodoc - -class _$HomeBodySelectorStateImpl implements _HomeBodySelectorState { - const _$HomeBodySelectorStateImpl( - {required final List navigationItems}) - : _navigationItems = navigationItems; - - final List _navigationItems; - @override - List get navigationItems { - if (_navigationItems is EqualUnmodifiableListView) return _navigationItems; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_navigationItems); - } - - @override - String toString() { - return 'HomeBodySelectorState(navigationItems: $navigationItems)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$HomeBodySelectorStateImpl && - const DeepCollectionEquality() - .equals(other._navigationItems, _navigationItems)); - } - - @override - int get hashCode => Object.hash( - runtimeType, const DeepCollectionEquality().hash(_navigationItems)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$HomeBodySelectorStateImplCopyWith<_$HomeBodySelectorStateImpl> - get copyWith => __$$HomeBodySelectorStateImplCopyWithImpl< - _$HomeBodySelectorStateImpl>(this, _$identity); -} - -abstract class _HomeBodySelectorState implements HomeBodySelectorState { - const factory _HomeBodySelectorState( - {required final List navigationItems}) = - _$HomeBodySelectorStateImpl; - - @override - List get navigationItems; - @override - @JsonKey(ignore: true) - _$$HomeBodySelectorStateImplCopyWith<_$HomeBodySelectorStateImpl> - get copyWith => throw _privateConstructorUsedError; -} - /// @nodoc mixin _$ProxiesCardSelectorState { bool get isSelected => throw _privateConstructorUsedError; @@ -4003,3 +3881,152 @@ abstract class _ClashConfigState implements ClashConfigState { _$$ClashConfigStateImplCopyWith<_$ClashConfigStateImpl> get copyWith => throw _privateConstructorUsedError; } + +/// @nodoc +mixin _$ThemeState { + String? get locale => throw _privateConstructorUsedError; + ScaleProps get scaleProps => throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $ThemeStateCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ThemeStateCopyWith<$Res> { + factory $ThemeStateCopyWith( + ThemeState value, $Res Function(ThemeState) then) = + _$ThemeStateCopyWithImpl<$Res, ThemeState>; + @useResult + $Res call({String? locale, ScaleProps scaleProps}); + + $ScalePropsCopyWith<$Res> get scaleProps; +} + +/// @nodoc +class _$ThemeStateCopyWithImpl<$Res, $Val extends ThemeState> + implements $ThemeStateCopyWith<$Res> { + _$ThemeStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? locale = freezed, + Object? scaleProps = null, + }) { + return _then(_value.copyWith( + locale: freezed == locale + ? _value.locale + : locale // ignore: cast_nullable_to_non_nullable + as String?, + scaleProps: null == scaleProps + ? _value.scaleProps + : scaleProps // ignore: cast_nullable_to_non_nullable + as ScaleProps, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $ScalePropsCopyWith<$Res> get scaleProps { + return $ScalePropsCopyWith<$Res>(_value.scaleProps, (value) { + return _then(_value.copyWith(scaleProps: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$ThemeStateImplCopyWith<$Res> + implements $ThemeStateCopyWith<$Res> { + factory _$$ThemeStateImplCopyWith( + _$ThemeStateImpl value, $Res Function(_$ThemeStateImpl) then) = + __$$ThemeStateImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String? locale, ScaleProps scaleProps}); + + @override + $ScalePropsCopyWith<$Res> get scaleProps; +} + +/// @nodoc +class __$$ThemeStateImplCopyWithImpl<$Res> + extends _$ThemeStateCopyWithImpl<$Res, _$ThemeStateImpl> + implements _$$ThemeStateImplCopyWith<$Res> { + __$$ThemeStateImplCopyWithImpl( + _$ThemeStateImpl _value, $Res Function(_$ThemeStateImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? locale = freezed, + Object? scaleProps = null, + }) { + return _then(_$ThemeStateImpl( + locale: freezed == locale + ? _value.locale + : locale // ignore: cast_nullable_to_non_nullable + as String?, + scaleProps: null == scaleProps + ? _value.scaleProps + : scaleProps // ignore: cast_nullable_to_non_nullable + as ScaleProps, + )); + } +} + +/// @nodoc + +class _$ThemeStateImpl implements _ThemeState { + const _$ThemeStateImpl({required this.locale, required this.scaleProps}); + + @override + final String? locale; + @override + final ScaleProps scaleProps; + + @override + String toString() { + return 'ThemeState(locale: $locale, scaleProps: $scaleProps)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ThemeStateImpl && + (identical(other.locale, locale) || other.locale == locale) && + (identical(other.scaleProps, scaleProps) || + other.scaleProps == scaleProps)); + } + + @override + int get hashCode => Object.hash(runtimeType, locale, scaleProps); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ThemeStateImplCopyWith<_$ThemeStateImpl> get copyWith => + __$$ThemeStateImplCopyWithImpl<_$ThemeStateImpl>(this, _$identity); +} + +abstract class _ThemeState implements ThemeState { + const factory _ThemeState( + {required final String? locale, + required final ScaleProps scaleProps}) = _$ThemeStateImpl; + + @override + String? get locale; + @override + ScaleProps get scaleProps; + @override + @JsonKey(ignore: true) + _$$ThemeStateImplCopyWith<_$ThemeStateImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/models/generated/version.freezed.dart b/lib/models/generated/version.freezed.dart deleted file mode 100644 index c508073..0000000 --- a/lib/models/generated/version.freezed.dart +++ /dev/null @@ -1,171 +0,0 @@ -// 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 '../version.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'); - -VersionInfo _$VersionInfoFromJson(Map json) { - return _VersionInfo.fromJson(json); -} - -/// @nodoc -mixin _$VersionInfo { - String get clashName => throw _privateConstructorUsedError; - String get version => throw _privateConstructorUsedError; - - Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) - $VersionInfoCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $VersionInfoCopyWith<$Res> { - factory $VersionInfoCopyWith( - VersionInfo value, $Res Function(VersionInfo) then) = - _$VersionInfoCopyWithImpl<$Res, VersionInfo>; - @useResult - $Res call({String clashName, String version}); -} - -/// @nodoc -class _$VersionInfoCopyWithImpl<$Res, $Val extends VersionInfo> - implements $VersionInfoCopyWith<$Res> { - _$VersionInfoCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? clashName = null, - Object? version = null, - }) { - return _then(_value.copyWith( - clashName: null == clashName - ? _value.clashName - : clashName // ignore: cast_nullable_to_non_nullable - as String, - version: null == version - ? _value.version - : version // ignore: cast_nullable_to_non_nullable - as String, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$VersionInfoImplCopyWith<$Res> - implements $VersionInfoCopyWith<$Res> { - factory _$$VersionInfoImplCopyWith( - _$VersionInfoImpl value, $Res Function(_$VersionInfoImpl) then) = - __$$VersionInfoImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({String clashName, String version}); -} - -/// @nodoc -class __$$VersionInfoImplCopyWithImpl<$Res> - extends _$VersionInfoCopyWithImpl<$Res, _$VersionInfoImpl> - implements _$$VersionInfoImplCopyWith<$Res> { - __$$VersionInfoImplCopyWithImpl( - _$VersionInfoImpl _value, $Res Function(_$VersionInfoImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? clashName = null, - Object? version = null, - }) { - return _then(_$VersionInfoImpl( - clashName: null == clashName - ? _value.clashName - : clashName // ignore: cast_nullable_to_non_nullable - as String, - version: null == version - ? _value.version - : version // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$VersionInfoImpl implements _VersionInfo { - const _$VersionInfoImpl({this.clashName = "", this.version = ""}); - - factory _$VersionInfoImpl.fromJson(Map json) => - _$$VersionInfoImplFromJson(json); - - @override - @JsonKey() - final String clashName; - @override - @JsonKey() - final String version; - - @override - String toString() { - return 'VersionInfo(clashName: $clashName, version: $version)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$VersionInfoImpl && - (identical(other.clashName, clashName) || - other.clashName == clashName) && - (identical(other.version, version) || other.version == version)); - } - - @JsonKey(ignore: true) - @override - int get hashCode => Object.hash(runtimeType, clashName, version); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$VersionInfoImplCopyWith<_$VersionInfoImpl> get copyWith => - __$$VersionInfoImplCopyWithImpl<_$VersionInfoImpl>(this, _$identity); - - @override - Map toJson() { - return _$$VersionInfoImplToJson( - this, - ); - } -} - -abstract class _VersionInfo implements VersionInfo { - const factory _VersionInfo({final String clashName, final String version}) = - _$VersionInfoImpl; - - factory _VersionInfo.fromJson(Map json) = - _$VersionInfoImpl.fromJson; - - @override - String get clashName; - @override - String get version; - @override - @JsonKey(ignore: true) - _$$VersionInfoImplCopyWith<_$VersionInfoImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/lib/models/generated/version.g.dart b/lib/models/generated/version.g.dart deleted file mode 100644 index 8d92bcb..0000000 --- a/lib/models/generated/version.g.dart +++ /dev/null @@ -1,19 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of '../version.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_$VersionInfoImpl _$$VersionInfoImplFromJson(Map json) => - _$VersionInfoImpl( - clashName: json['clashName'] as String? ?? "", - version: json['version'] as String? ?? "", - ); - -Map _$$VersionInfoImplToJson(_$VersionInfoImpl instance) => - { - 'clashName': instance.clashName, - 'version': instance.version, - }; diff --git a/lib/models/ip.dart b/lib/models/ip.dart deleted file mode 100644 index cc72c11..0000000 --- a/lib/models/ip.dart +++ /dev/null @@ -1,70 +0,0 @@ -class IpInfo { - final String ip; - final String countryCode; - - const IpInfo({ - required this.ip, - required this.countryCode, - }); - - static IpInfo fromIpInfoIoJson(Map json) { - return switch (json) { - { - "ip": final String ip, - "country": final String country, - } => - IpInfo( - ip: ip, - countryCode: country, - ), - _ => throw const FormatException("invalid json"), - }; - } - - static IpInfo fromIpApiCoJson(Map json) { - return switch (json) { - { - "ip": final String ip, - "country_code": final String countryCode, - } => - IpInfo( - ip: ip, - countryCode: countryCode, - ), - _ => throw const FormatException("invalid json"), - }; - } - - static IpInfo fromIpSbJson(Map json) { - return switch (json) { - { - "ip": final String ip, - "country_code": final String countryCode, - } => - IpInfo( - ip: ip, - countryCode: countryCode, - ), - _ => throw const FormatException("invalid json"), - }; - } - - static IpInfo fromIpwhoIsJson(Map json) { - return switch (json) { - { - "ip": final String ip, - "country_code": final String countryCode, - } => - IpInfo( - ip: ip, - countryCode: countryCode, - ), - _ => throw const FormatException("invalid json"), - }; - } - - @override - String toString() { - return 'IpInfo{ip: $ip, countryCode: $countryCode}'; - } -} diff --git a/lib/models/log.dart b/lib/models/log.dart deleted file mode 100644 index 3d7f483..0000000 --- a/lib/models/log.dart +++ /dev/null @@ -1,56 +0,0 @@ -// ignore_for_file: invalid_annotation_target - -import 'package:fl_clash/enum/enum.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'generated/log.g.dart'; - -part 'generated/log.freezed.dart'; - -@JsonSerializable() -class Log { - @JsonKey(name: "LogLevel") - LogLevel logLevel; - @JsonKey(name: "Payload") - String? payload; - DateTime _dateTime; - - Log({ - required this.logLevel, - this.payload, - }) : _dateTime = DateTime.now(); - - DateTime get dateTime => _dateTime; - - factory Log.fromJson(Map json) { - return _$LogFromJson(json); - } - - Map toJson() { - return _$LogToJson(this); - } - - @override - String toString() { - return 'Log{logLevel: $logLevel, payload: $payload, dateTime: $dateTime}'; - } -} - -@freezed -class LogsAndKeywords with _$LogsAndKeywords { - const factory LogsAndKeywords({ - @Default([]) List logs, - @Default([]) List keywords, - }) = _LogsAndKeywords; - - factory LogsAndKeywords.fromJson(Map json) => - _$LogsAndKeywordsFromJson(json); -} - -extension LogsAndKeywordsExt on LogsAndKeywords { - List get filteredLogs => logs - .where( - (log) => {log.logLevel.name}.containsAll(keywords), - ) - .toList(); -} diff --git a/lib/models/models.dart b/lib/models/models.dart index 9532967..d75d5a0 100644 --- a/lib/models/models.dart +++ b/lib/models/models.dart @@ -2,16 +2,6 @@ export 'app.dart'; export 'clash_config.dart'; export 'config.dart'; export 'profile.dart'; -export 'proxy.dart'; -export 'version.dart'; -export 'traffic.dart'; -export 'log.dart'; -export 'system_color_scheme.dart'; -export 'connection.dart'; -export 'package.dart'; export 'ffi.dart'; export 'selector.dart'; -export 'navigation.dart'; -export 'dav.dart'; -export 'ip.dart'; -export 'file.dart'; \ No newline at end of file +export 'common.dart'; \ No newline at end of file diff --git a/lib/models/navigation.dart b/lib/models/navigation.dart deleted file mode 100644 index 2e9d4f9..0000000 --- a/lib/models/navigation.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:fl_clash/enum/enum.dart'; -import 'package:flutter/material.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'generated/navigation.freezed.dart'; - -@freezed -class NavigationItem with _$NavigationItem { - const factory NavigationItem({ - required Icon icon, - required String label, - final String? description, - required Widget fragment, - @Default(true) bool keep, - String? path, - @Default([NavigationItemMode.mobile, NavigationItemMode.desktop]) - List modes, - }) = _NavigationItem; -} diff --git a/lib/models/package.dart b/lib/models/package.dart deleted file mode 100644 index 31eb642..0000000 --- a/lib/models/package.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'generated/package.g.dart'; -part 'generated/package.freezed.dart'; - -@freezed -class Package with _$Package { - const factory Package({ - required String packageName, - required String label, - required bool isSystem, - required int firstInstallTime, - }) = _Package; - - factory Package.fromJson(Map json) => - _$PackageFromJson(json); -} diff --git a/lib/models/proxy.dart b/lib/models/proxy.dart deleted file mode 100644 index 631c57a..0000000 --- a/lib/models/proxy.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -import '../enum/enum.dart'; - -part 'generated/proxy.g.dart'; - -part 'generated/proxy.freezed.dart'; - -typedef ProxyMap = Map; - -@freezed -class Group with _$Group { - const factory Group({ - required GroupType type, - @Default([]) List all, - String? now, - bool? hidden, - @Default("") String icon, - required String name, - }) = _Group; - - factory Group.fromJson(Map json) => _$GroupFromJson(json); -} - -extension GroupExt on Group { - String get realNow => now ?? ""; - - String getCurrentSelectedName(String proxyName) { - if (type == GroupType.URLTest) { - 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); -} diff --git a/lib/models/selector.dart b/lib/models/selector.dart index ff06789..85be482 100644 --- a/lib/models/selector.dart +++ b/lib/models/selector.dart @@ -59,15 +59,16 @@ class ApplicationSelectorState with _$ApplicationSelectorState { } @freezed -class TrayContainerSelectorState with _$TrayContainerSelectorState { - const factory TrayContainerSelectorState({ +class TrayState with _$TrayState { + const factory TrayState({ required Mode mode, required bool autoLaunch, required bool systemProxy, required bool tunEnable, required bool isStart, required String? locale, - }) = _TrayContainerSelectorState; + required Brightness? brightness, + }) = _TrayState; } @freezed @@ -79,21 +80,15 @@ class UpdateNavigationsSelector with _$UpdateNavigationsSelector { } @freezed -class HomeSelectorState with _$HomeSelectorState { - const factory HomeSelectorState({ +class HomeState with _$HomeState { + const factory HomeState({ required String currentLabel, required List navigationItems, required ViewMode viewMode, required String? locale, - }) = _HomeSelectorState; + }) = _HomeState; } -@freezed -class HomeBodySelectorState with _$HomeBodySelectorState { - const factory HomeBodySelectorState({ - required List navigationItems, - }) = _HomeBodySelectorState; -} @freezed class ProxiesCardSelectorState with _$ProxiesCardSelectorState { @@ -245,3 +240,12 @@ class ClashConfigState with _$ClashConfigState { required String? globalRealUa, }) = _ClashConfigState; } + +@freezed +class ThemeState with _$ThemeState { + const factory ThemeState({ + required String? locale, + required ScaleProps scaleProps, + }) = _ThemeState; +} + diff --git a/lib/models/system_color_scheme.dart b/lib/models/system_color_scheme.dart deleted file mode 100644 index 549ceae..0000000 --- a/lib/models/system_color_scheme.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:fl_clash/common/constant.dart'; -import 'package:flutter/material.dart'; - -@immutable -class SystemColorSchemes { - final ColorScheme? lightColorScheme; - final ColorScheme? darkColorScheme; - - const SystemColorSchemes({ - this.lightColorScheme, - this.darkColorScheme, - }); - - getSystemColorSchemeForBrightness(Brightness? brightness) { - if (brightness == Brightness.dark) { - return darkColorScheme != null - ? ColorScheme.fromSeed( - seedColor: darkColorScheme!.primary, - brightness: Brightness.dark, - ) - : ColorScheme.fromSeed( - seedColor: defaultPrimaryColor, - brightness: Brightness.dark, - ); - } - return lightColorScheme != null - ? ColorScheme.fromSeed(seedColor: darkColorScheme!.primary) - : ColorScheme.fromSeed(seedColor: defaultPrimaryColor); - } -} diff --git a/lib/models/traffic.dart b/lib/models/traffic.dart deleted file mode 100644 index 4558ca8..0000000 --- a/lib/models/traffic.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'dart:math'; - -import 'package:fl_clash/common/common.dart'; -import 'package:fl_clash/enum/enum.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; - -class Traffic { - int id; - TrafficValue up; - TrafficValue down; - - Traffic({num? up, num? down}) - : id = DateTime.now().millisecondsSinceEpoch, - up = TrafficValue(value: up), - down = TrafficValue(value: down); - - num get speed => up.value + down.value; - - factory Traffic.fromMap(Map map) { - return Traffic( - up: map['up'], - down: map['down'], - ); - } - - @override - String toString() { - return '$up↑ $down↓'; - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is Traffic && - runtimeType == other.runtimeType && - id == other.id && - up == other.up && - down == other.down; - - @override - int get hashCode => id.hashCode ^ up.hashCode ^ down.hashCode; -} - -@immutable -class TrafficValueShow { - final String value; - final TrafficUnit unit; - - const TrafficValueShow({ - required this.value, - required this.unit, - }); -} - -@immutable -class TrafficValue { - final num _value; - - const TrafficValue({num? value}) : _value = value ?? 0; - - num get value => _value; - - String get show => "$showValue $showUnit"; - - String get showValue => trafficValueShow.value; - - String get showUnit => trafficValueShow.unit.name; - - TrafficValueShow get trafficValueShow { - if (_value > pow(1024, 4)) { - return TrafficValueShow( - value: (_value / pow(1024, 4)).fixed(), - unit: TrafficUnit.TB, - ); - } - if (_value > pow(1024, 3)) { - return TrafficValueShow( - value: (_value / pow(1024, 3)).fixed(), - unit: TrafficUnit.GB, - ); - } - if (_value > pow(1024, 2)) { - return TrafficValueShow( - value: (_value / pow(1024, 2)).fixed(), unit: TrafficUnit.MB); - } - if (_value > pow(1024, 1)) { - return TrafficValueShow( - value: (_value / pow(1024, 1)).fixed(), - unit: TrafficUnit.KB, - ); - } - return TrafficValueShow( - value: _value.fixed(), - unit: TrafficUnit.B, - ); - } - - @override - String toString() { - return "$showValue$showUnit"; - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is TrafficValue && - runtimeType == other.runtimeType && - _value == other._value; - - @override - int get hashCode => _value.hashCode; -} diff --git a/lib/models/version.dart b/lib/models/version.dart deleted file mode 100644 index 7de99b2..0000000 --- a/lib/models/version.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'generated/version.g.dart'; - -part 'generated/version.freezed.dart'; - -@freezed -class VersionInfo with _$VersionInfo { - const factory VersionInfo({ - @Default("") String clashName, - @Default("") String version, - }) = _VersionInfo; - - factory VersionInfo.fromJson(Map json) => - _$VersionInfoFromJson(json); -} diff --git a/lib/pages/home.dart b/lib/pages/home.dart index e102455..c9574f5 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/models/models.dart'; import 'package:fl_clash/state.dart'; @@ -52,7 +53,7 @@ class HomePage extends StatelessWidget { builder: (_, showLabel, __) { return NavigationRail( backgroundColor: - context.colorScheme.surfaceContainer, + context.colorScheme.surfaceContainer, selectedIconTheme: IconThemeData( color: context.colorScheme.onSurfaceVariant, ), @@ -60,25 +61,25 @@ class HomePage extends StatelessWidget { color: context.colorScheme.onSurfaceVariant, ), selectedLabelTextStyle: - context.textTheme.labelLarge!.copyWith( + context.textTheme.labelLarge!.copyWith( color: context.colorScheme.onSurface, ), unselectedLabelTextStyle: - context.textTheme.labelLarge!.copyWith( + context.textTheme.labelLarge!.copyWith( color: context.colorScheme.onSurface, ), destinations: navigationItems .map( (e) => NavigationRailDestination( - icon: e.icon, - label: Text( - Intl.message(e.label), - ), - ), - ) + icon: e.icon, + label: Text( + Intl.message(e.label), + ), + ), + ) .toList(), onDestinationSelected: - globalState.appController.toPage, + globalState.appController.toPage, extended: false, selectedIndex: currentIndex, labelType: showLabel @@ -108,9 +109,52 @@ class HomePage extends StatelessWidget { ); } + _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 PopContainer( + return BackScope( child: LayoutBuilder( builder: (_, container) { final appController = globalState.appController; @@ -118,15 +162,18 @@ class HomePage extends StatelessWidget { if (appController.appState.viewWidth != maxWidth) { globalState.appController.updateViewWidth(maxWidth); } - return Selector2( + return Selector2( selector: (_, appState, config) { - return HomeSelectorState( + return HomeState( currentLabel: appState.currentLabel, navigationItems: appState.currentNavigationItems, viewMode: other.getViewMode(maxWidth), locale: config.locale, ); }, + shouldRebuild: (prev, next) { + return prev != next; + }, builder: (_, state, child) { final viewMode = state.viewMode; final navigationItems = state.navigationItems; @@ -155,60 +202,10 @@ class HomePage extends StatelessWidget { bottomNavigationBar: bottomNavigationBar, ); }, - child: const HomeBody( - key: Key("home_boy"), - ), + child: _buildPageView(), ); }, ), ); } } - -class HomeBody extends StatelessWidget { - const HomeBody({super.key}); - - _updatePageIndex(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, - ); - } - } - - @override - Widget build(BuildContext context) { - return Selector( - selector: (_, appState) => HomeBodySelectorState( - navigationItems: appState.currentNavigationItems, - ), - builder: (_, state, __) { - final navigationItems = state.navigationItems; - _updatePageIndex(navigationItems); - return PageView.builder( - controller: globalState.pageController, - physics: const NeverScrollableScrollPhysics(), - itemCount: navigationItems.length, - itemBuilder: (_, index) { - final navigationItem = navigationItems[index]; - return KeepContainer( - keep: navigationItem.keep, - key: Key(navigationItem.label), - child: navigationItem.fragment, - ); - }, - ); - }, - ); - } -} diff --git a/lib/plugins/app.dart b/lib/plugins/app.dart index df1ef60..9e975e9 100644 --- a/lib/plugins/app.dart +++ b/lib/plugins/app.dart @@ -5,6 +5,7 @@ import 'dart:isolate'; import 'package:fl_clash/clash/clash.dart'; import 'package:fl_clash/models/models.dart'; +import 'package:fl_clash/state.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -21,8 +22,6 @@ class App { if (onExit != null) { await onExit!(); } - case "gc": - clashCore.requestGc(); default: throw MissingPluginException(); } @@ -86,12 +85,6 @@ class App { "value": value, }); } - - Future resolverProcess(Process process) async { - return await methodChannel.invokeMethod("resolverProcess", { - "data": json.encode(process), - }); - } } final app = Platform.isAndroid ? App() : null; diff --git a/lib/plugins/service.dart b/lib/plugins/service.dart index 0c854ba..cb2ee04 100644 --- a/lib/plugins/service.dart +++ b/lib/plugins/service.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:io'; import 'dart:isolate'; +import 'package:fl_clash/state.dart'; import 'package:flutter/services.dart'; class Service { @@ -26,4 +27,5 @@ class Service { } } -final service = Platform.isAndroid ? Service() : null; +final service = + Platform.isAndroid && !globalState.isVpnService ? Service() : null; diff --git a/lib/plugins/vpn.dart b/lib/plugins/vpn.dart index d2bb609..499dfc6 100644 --- a/lib/plugins/vpn.dart +++ b/lib/plugins/vpn.dart @@ -6,6 +6,8 @@ import 'dart:isolate'; import 'package:fl_clash/clash/clash.dart'; 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'; import 'package:flutter/services.dart'; class Vpn { @@ -19,9 +21,16 @@ class Vpn { methodChannel.setMethodCallHandler((call) async { switch (call.method) { case "started": - final fd = call.arguments; - onStarted(fd); + final tunProps = call.arguments != null + ? TunProps.fromJson(json.decode((call.arguments))) + : null; + onStarted(tunProps); break; + case "gc": + clashCore.requestGc(); + case "dnsChanged": + final dns = call.arguments as String; + clashCore.updateDns(dns); default: throw MissingPluginException(); } @@ -49,6 +58,12 @@ class Vpn { return await methodChannel.invokeMethod("setProtect", {'fd': fd}); } + Future resolverProcess(Process process) async { + return await methodChannel.invokeMethod("resolverProcess", { + "data": json.encode(process), + }); + } + Future startForeground({ required String title, required String content, @@ -59,7 +74,7 @@ class Vpn { }); } - onStarted(int? fd) { + onStarted(TunProps? tunProps) { if (receiver != null) { receiver!.close(); receiver == null; @@ -68,7 +83,7 @@ class Vpn { receiver!.listen((message) { _handleServiceMessage(message); }); - clashCore.startTun(fd ?? 0, receiver!.sendPort.nativePort); + clashCore.startTun(tunProps, receiver!.sendPort.nativePort); } setServiceMessageHandler(ServiceMessageListener serviceMessageListener) { @@ -90,4 +105,4 @@ class Vpn { } } -final vpn = Platform.isAndroid ? Vpn() : null; +final vpn = Platform.isAndroid && globalState.isVpnService ? Vpn() : null; diff --git a/lib/state.dart b/lib/state.dart index 28d217d..0376a74 100644 --- a/lib/state.dart +++ b/lib/state.dart @@ -7,15 +7,10 @@ import 'package:fl_clash/plugins/service.dart'; import 'package:fl_clash/plugins/vpn.dart'; import 'package:fl_clash/widgets/scaffold.dart'; import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'package:tray_manager/tray_manager.dart'; import 'package:url_launcher/url_launcher.dart'; import 'controller.dart'; - -import 'enum/enum.dart'; -import 'l10n/l10n.dart'; import 'models/models.dart'; import 'common/common.dart'; @@ -33,7 +28,6 @@ class GlobalState { late AppController appController; GlobalKey homeScaffoldKey = GlobalKey(); List updateFunctionLists = []; - var isTrayInit = false; bool get isStart => startTime != null && startTime!.isBeforeNow; @@ -82,7 +76,7 @@ class GlobalState { required ClashConfig clashConfig, }) async { clashCore.start(); - if (globalState.isVpnService) { + if (vpn != null) { await vpn?.startVpn(clashConfig.mixedPort); startListenUpdate(); return; @@ -196,121 +190,6 @@ class GlobalState { ); } - _updateOtherTray() async { - if (isTrayInit == false) { - await trayManager.setIcon( - other.getTrayIconPath(), - ); - await trayManager.setToolTip( - appName, - ); - isTrayInit = true; - } - } - - _updateLinuxTray() async { - await trayManager.destroy(); - await trayManager.setIcon( - other.getTrayIconPath(), - ); - await trayManager.setToolTip( - appName, - ); - } - - updateTray({ - required AppState appState, - required Config config, - required ClashConfig clashConfig, - }) async { - final appLocalizations = await AppLocalizations.load( - other.getLocaleForString(config.locale) ?? - WidgetsBinding.instance.platformDispatcher.locale, - ); - if (!Platform.isLinux) { - _updateOtherTray(); - } - List menuItems = []; - final showMenuItem = MenuItem( - label: appLocalizations.show, - onClick: (_) { - window?.show(); - }, - ); - menuItems.add(showMenuItem); - final startMenuItem = MenuItem.checkbox( - label: appState.isStart ? appLocalizations.stop : appLocalizations.start, - onClick: (_) async { - globalState.appController.updateStatus(!appState.isStart); - }, - checked: false, - ); - menuItems.add(startMenuItem); - menuItems.add(MenuItem.separator()); - for (final mode in Mode.values) { - menuItems.add( - MenuItem.checkbox( - label: Intl.message(mode.name), - onClick: (_) { - globalState.appController.clashConfig.mode = mode; - }, - checked: mode == appState.mode, - ), - ); - } - menuItems.add(MenuItem.separator()); - if (appState.isStart) { - menuItems.add( - MenuItem.checkbox( - label: appLocalizations.tun, - onClick: (_) { - final clashConfig = globalState.appController.clashConfig; - clashConfig.tun = clashConfig.tun.copyWith( - enable: !clashConfig.tun.enable, - ); - }, - checked: clashConfig.tun.enable, - ), - ); - menuItems.add( - MenuItem.checkbox( - label: appLocalizations.systemProxy, - onClick: (_) { - final config = globalState.appController.config; - config.desktopProps = config.desktopProps.copyWith( - systemProxy: !config.desktopProps.systemProxy, - ); - }, - checked: config.desktopProps.systemProxy, - ), - ); - menuItems.add(MenuItem.separator()); - } - final autoStartMenuItem = MenuItem.checkbox( - label: appLocalizations.autoLaunch, - onClick: (_) async { - globalState.appController.config.autoLaunch = - !globalState.appController.config.autoLaunch; - }, - checked: config.autoLaunch, - ); - menuItems.add(autoStartMenuItem); - menuItems.add(MenuItem.separator()); - final exitMenuItem = MenuItem( - label: appLocalizations.exit, - onClick: (_) async { - await globalState.appController.handleExit(); - }, - ); - menuItems.add(exitMenuItem); - final menu = Menu(); - menu.items = menuItems; - trayManager.setContextMenu(menu); - if (Platform.isLinux) { - _updateLinuxTray(); - } - } - changeProxy({ required Config config, required String groupName, @@ -329,11 +208,13 @@ class GlobalState { Future showCommonDialog({ required Widget child, + bool dismissible = true, }) async { return await showModal( context: navigatorKey.currentState!.context, - configuration: const FadeScaleTransitionConfiguration( + configuration: FadeScaleTransitionConfiguration( barrierColor: Colors.black38, + barrierDismissible: dismissible, ), builder: (_) => child, filter: filter, diff --git a/lib/widgets/pop_container.dart b/lib/widgets/back_scope.dart similarity index 73% rename from lib/widgets/pop_container.dart rename to lib/widgets/back_scope.dart index 0ea357f..c4e5b3f 100644 --- a/lib/widgets/pop_container.dart +++ b/lib/widgets/back_scope.dart @@ -4,16 +4,16 @@ import 'dart:io'; import 'package:fl_clash/state.dart'; import 'package:flutter/widgets.dart'; -class PopContainer extends StatefulWidget { +class BackScope extends StatefulWidget { final Widget child; - const PopContainer({super.key, required this.child}); + const BackScope({super.key, required this.child}); @override - State createState() => _PopContainerState(); + State createState() => _PopContainerState(); } -class _PopContainerState extends State { +class _PopContainerState extends State { @override Widget build(BuildContext context) { if (Platform.isAndroid) { diff --git a/lib/widgets/builder.dart b/lib/widgets/builder.dart index 7a1710f..1234c02 100644 --- a/lib/widgets/builder.dart +++ b/lib/widgets/builder.dart @@ -65,3 +65,47 @@ class ProxiesActionsBuilder extends StatelessWidget { ); } } + +typedef StateWidgetBuilder = Widget Function(T state); + +class ScaleBuilder extends StatelessWidget { + final StateWidgetBuilder builder; + + const ScaleBuilder({ + super.key, + required this.builder, + }); + + @override + Widget build(BuildContext context) { + return Selector( + selector: (_, config) { + return config.scaleProps.custom + ? config.scaleProps.scale + : 1; + }, + builder: (_, state, __) { + return builder(state); + }, + ); + } +} + +class LocaleBuilder extends StatelessWidget { + final StateWidgetBuilder builder; + + const LocaleBuilder({ + super.key, + required this.builder, + }); + + @override + Widget build(BuildContext context) { + return Selector( + selector: (_, config) => config.locale, + builder: (_, state, __) { + return builder(state); + }, + ); + } +} diff --git a/lib/widgets/keep_container.dart b/lib/widgets/keep_scope.dart similarity index 66% rename from lib/widgets/keep_container.dart rename to lib/widgets/keep_scope.dart index df4d75b..4bb1879 100644 --- a/lib/widgets/keep_container.dart +++ b/lib/widgets/keep_scope.dart @@ -1,20 +1,20 @@ import 'package:flutter/material.dart'; -class KeepContainer extends StatefulWidget { +class KeepScope extends StatefulWidget { final Widget child; final bool keep; - const KeepContainer({ + const KeepScope({ super.key, required this.child, this.keep = true, }); @override - State createState() => _KeepContainerState(); + State createState() => _KeepContainerState(); } -class _KeepContainerState extends State +class _KeepContainerState extends State with AutomaticKeepAliveClientMixin { @override Widget build(BuildContext context) { diff --git a/lib/widgets/media_container.dart b/lib/widgets/media_container.dart deleted file mode 100644 index d0c8770..0000000 --- a/lib/widgets/media_container.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:fl_clash/common/common.dart'; -import 'package:fl_clash/models/config.dart'; -import 'package:fl_clash/state.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -class MediaContainer extends StatelessWidget { - final Widget child; - - const MediaContainer({ - super.key, - required this.child, - }); - - @override - Widget build(BuildContext context) { - return Selector( - selector: (_, config) => config.scaleProps, - builder: (_, props, child) { - return MediaQuery( - data: MediaQuery.of(context).copyWith( - textScaler: props.custom ? TextScaler.linear(props.scale) : null, - ), - child: Builder( - builder: (context) { - globalState.measure = Measure.of(context); - return child!; - }, - ), - ); - }, - child: child, - ); - } -} diff --git a/lib/widgets/tray_container.dart b/lib/widgets/tray_container.dart deleted file mode 100644 index 7ef0e42..0000000 --- a/lib/widgets/tray_container.dart +++ /dev/null @@ -1,72 +0,0 @@ -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/state.dart'; -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'package:provider/provider.dart'; -import 'package:tray_manager/tray_manager.dart'; - -class TrayContainer extends StatefulWidget { - final Widget child; - - const TrayContainer({ - super.key, - required this.child, - }); - - @override - State createState() => _TrayContainerState(); -} - -class _TrayContainerState extends State with TrayListener { - - @override - void initState() { - super.initState(); - trayManager.addListener(this); - } - - @override - Widget build(BuildContext context) { - return Selector3( - selector: (_, appState, config, clashConfig) => - TrayContainerSelectorState( - mode: clashConfig.mode, - autoLaunch: config.autoLaunch, - isStart: appState.isStart, - locale: config.locale, - systemProxy: config.desktopProps.systemProxy, - tunEnable: clashConfig.tun.enable, - ), - shouldRebuild: (prev,next){ - if(prev != next){ - globalState.appController.updateTray(); - } - return prev != next; - }, - builder: (_, state, child) { - return child!; - }, - child: widget.child, - ); - } - - @override - void onTrayIconRightMouseDown() { - trayManager.popUpContextMenu(); - } - - @override - onTrayIconMouseDown() { - window?.show(); - } - - @override - dispose() { - trayManager.removeListener(this); - super.dispose(); - } -} diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart index a199899..094dab2 100644 --- a/lib/widgets/widgets.dart +++ b/lib/widgets/widgets.dart @@ -8,24 +8,16 @@ export 'grid.dart'; export 'open_container.dart'; export 'color_scheme_box.dart'; export 'null_status.dart'; -export 'pop_container.dart'; export 'disabled_mask.dart'; export 'side_sheet.dart'; export 'sheet.dart'; -export 'keep_container.dart'; export 'animate_grid.dart'; -export 'tray_container.dart'; -export 'window_container.dart'; -export 'android_container.dart'; -export 'clash_container.dart'; -export 'tile_container.dart'; export 'chip.dart'; export 'fade_box.dart'; -export 'app_state_container.dart'; export 'text.dart'; export 'connection_item.dart'; export 'builder.dart'; export 'setting.dart'; -export 'vpn_container.dart'; export 'input.dart'; -export 'media_container.dart'; +export 'keep_scope.dart'; +export 'back_scope.dart'; diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc old mode 100644 new mode 100755 index a47e9c9..4af4bb2 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) gtk_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin"); gtk_plugin_register_with_registrar(gtk_registrar); + g_autoptr(FlPluginRegistrar) hotkey_manager_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "HotkeyManagerLinuxPlugin"); + hotkey_manager_linux_plugin_register_with_registrar(hotkey_manager_linux_registrar); g_autoptr(FlPluginRegistrar) screen_retriever_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin"); screen_retriever_plugin_register_with_registrar(screen_retriever_registrar); diff --git a/linux/flutter/generated_plugin_registrant.h b/linux/flutter/generated_plugin_registrant.h old mode 100644 new mode 100755 diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake old mode 100644 new mode 100755 index 794fd2e..7fb4ddf --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST dynamic_color file_selector_linux gtk + hotkey_manager_linux screen_retriever tray_manager url_launcher_linux diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift old mode 100644 new mode 100755 index 48ddff5..e72650c --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,8 +6,10 @@ import FlutterMacOS import Foundation import app_links +import device_info_plus import dynamic_color import file_selector_macos +import hotkey_manager_macos import mobile_scanner import package_info_plus import path_provider_foundation @@ -20,8 +22,10 @@ import window_manager func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) + DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + HotkeyManagerMacosPlugin.register(with: registry.registrar(forPlugin: "HotkeyManagerMacosPlugin")) MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) diff --git a/plugins/flutter_distributor b/plugins/flutter_distributor index 7701c7b..98d508b 160000 --- a/plugins/flutter_distributor +++ b/plugins/flutter_distributor @@ -1 +1 @@ -Subproject commit 7701c7be83d4b7fa91f9f16ee45dfcb8fc1e9645 +Subproject commit 98d508b0886957540d1f15b9630b90c72c721912 diff --git a/pubspec.lock b/pubspec.lock old mode 100644 new mode 100755 index f457e60..dfee981 --- a/pubspec.lock +++ b/pubspec.lock @@ -241,6 +241,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.6" + device_info_plus: + dependency: "direct main" + description: + name: device_info_plus + sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074 + url: "https://pub.dev" + source: hosted + version: "10.1.2" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba" + url: "https://pub.dev" + source: hosted + version: "7.0.1" dio: dependency: "direct main" description: @@ -445,6 +461,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + hotkey_manager: + dependency: "direct main" + description: + name: hotkey_manager + sha256: "06f0655b76c8dd322fb7101dc615afbdbf39c3d3414df9e059c33892104479cd" + url: "https://pub.dev" + source: hosted + version: "0.2.3" + hotkey_manager_linux: + dependency: transitive + description: + name: hotkey_manager_linux + sha256: "83676bda8210a3377bc6f1977f193bc1dbdd4c46f1bdd02875f44b6eff9a8473" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + hotkey_manager_macos: + dependency: transitive + description: + name: hotkey_manager_macos + sha256: "03b5967e64357b9ac05188ea4a5df6fe4ed4205762cb80aaccf8916ee1713c96" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + hotkey_manager_platform_interface: + dependency: transitive + description: + name: hotkey_manager_platform_interface + sha256: "98ffca25b8cc9081552902747b2942e3bc37855389a4218c9d50ca316b653b13" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + hotkey_manager_windows: + dependency: transitive + description: + name: hotkey_manager_windows + sha256: "0d03ced9fe563ed0b68f0a0e1b22c9ffe26eb8053cb960e401f68a4f070e0117" + url: "https://pub.dev" + source: hosted + version: "0.2.0" http: dependency: transitive description: @@ -1121,6 +1177,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + uni_platform: + dependency: "direct main" + description: + name: uni_platform + sha256: e02213a7ee5352212412ca026afd41d269eb00d982faa552f419ffc2debfad84 + url: "https://pub.dev" + source: hosted + version: "0.1.3" url_launcher: dependency: "direct main" description: @@ -1323,4 +1387,4 @@ packages: version: "0.2.3" sdks: dart: ">=3.4.0 <4.0.0" - flutter: ">=3.22.3" + flutter: ">=3.22.0" diff --git a/pubspec.yaml b/pubspec.yaml old mode 100644 new mode 100755 index 9f0b5c5..f04e21d --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: 'none' version: 0.8.59+202409091 environment: sdk: '>=3.1.0 <4.0.0' - flutter: 3.22.3 + flutter: 3.22.0 dependencies: flutter: @@ -47,6 +47,9 @@ dependencies: emoji_regex: ^0.0.5 process_run: ^1.1.0 cached_network_image: ^3.4.0 + hotkey_manager: ^0.2.3 + uni_platform: ^0.1.3 + device_info_plus: ^10.1.2 dev_dependencies: flutter_test: sdk: flutter diff --git a/setup.dart b/setup.dart old mode 100644 new mode 100755 index 0845f84..d8ce724 --- a/setup.dart +++ b/setup.dart @@ -297,6 +297,9 @@ class BuildCommand extends Command { await Build.exec( Build.getExecutable("sudo apt install -y rpm patchelf"), ); + await Build.exec( + Build.getExecutable("sudo apt install -y rpm keybinder-3.0"), + ); await Build.exec( Build.getExecutable("sudo apt install -y locate"), ); diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc old mode 100644 new mode 100755 index 115b973..b8eca89 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("DynamicColorPluginCApi")); FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); + HotkeyManagerWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("HotkeyManagerWindowsPluginCApi")); ProxyPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("ProxyPluginCApi")); ScreenRetrieverPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugin_registrant.h b/windows/flutter/generated_plugin_registrant.h old mode 100644 new mode 100755 diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake old mode 100644 new mode 100755 index 0877746..de7671a --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST app_links dynamic_color file_selector_windows + hotkey_manager_windows proxy screen_retriever tray_manager