Support desktop hotkey

Support android ipv6 inbound

Support android system dns

fix some bugs
This commit is contained in:
chen08209
2024-09-08 21:21:21 +08:00
parent 61bd4e4549
commit e6da643186
125 changed files with 5898 additions and 4435 deletions

2
.gitmodules vendored
View File

@@ -1,7 +1,7 @@
[submodule "core/Clash.Meta"] [submodule "core/Clash.Meta"]
path = core/Clash.Meta path = core/Clash.Meta
url = git@github.com:chen08209/Clash.Meta.git url = git@github.com:chen08209/Clash.Meta.git
branch = FlClash branch = FlClash-Alpha
[submodule "plugins/flutter_distributor"] [submodule "plugins/flutter_distributor"]
path = plugins/flutter_distributor path = plugins/flutter_distributor
url = git@github.com:chen08209/flutter_distributor.git url = git@github.com:chen08209/flutter_distributor.git

View File

@@ -1,9 +1,10 @@
package com.follow.clash package com.follow.clash
import com.follow.clash.models.Props import com.follow.clash.models.Props
import com.follow.clash.models.TunProps
interface BaseServiceInterface { interface BaseServiceInterface {
fun start(port: Int, props: Props?): Int? fun start(port: Int, props: Props?): TunProps?
fun stop() fun stop()
fun startForeground(title: String, content: String) fun startForeground(title: String, content: String)
} }

View File

@@ -39,8 +39,7 @@ object GlobalState {
} }
fun getCurrentVPNPlugin(): VpnPlugin? { fun getCurrentVPNPlugin(): VpnPlugin? {
val currentEngine = if (serviceEngine != null) serviceEngine else flutterEngine return serviceEngine?.plugins?.get(VpnPlugin::class.java) as VpnPlugin?
return currentEngine?.plugins?.get(VpnPlugin::class.java) as VpnPlugin?
} }
fun destroyServiceEngine() { fun destroyServiceEngine() {

View File

@@ -1,28 +1,20 @@
package com.follow.clash.extensions 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.Bitmap
import android.graphics.drawable.Drawable 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_TCP
import android.system.OsConstants.IPPROTO_UDP import android.system.OsConstants.IPPROTO_UDP
import android.util.Base64 import android.util.Base64
import androidx.core.app.NotificationCompat
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import com.follow.clash.MainActivity
import com.follow.clash.R
import com.follow.clash.models.Metadata import com.follow.clash.models.Metadata
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.net.Inet4Address
import java.net.Inet6Address
import java.net.InetAddress
suspend fun Drawable.getBase64(): String { suspend fun Drawable.getBase64(): String {
@@ -41,6 +33,37 @@ fun Metadata.getProtocol(): Int? {
return null 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()
}

View File

@@ -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()

View File

@@ -1,7 +1,5 @@
package com.follow.clash.models package com.follow.clash.models
import java.util.Date
data class Package( data class Package(
val packageName: String, val packageName: String,
val label: String, val label: String,

View File

@@ -17,3 +17,13 @@ data class Props(
val allowBypass: Boolean?, val allowBypass: Boolean?,
val systemProxy: 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
)

View File

@@ -8,7 +8,6 @@ import android.content.Intent
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.pm.ComponentInfo import android.content.pm.ComponentInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.VpnService import android.net.VpnService
import android.os.Build import android.os.Build
import android.widget.Toast import android.widget.Toast
@@ -17,12 +16,9 @@ import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.getSystemService import androidx.core.content.ContextCompat.getSystemService
import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.core.content.getSystemService
import com.follow.clash.GlobalState import com.follow.clash.GlobalState
import com.follow.clash.extensions.getBase64 import com.follow.clash.extensions.getBase64
import com.follow.clash.extensions.getProtocol
import com.follow.clash.models.Package import com.follow.clash.models.Package
import com.follow.clash.models.Process
import com.google.gson.Gson import com.google.gson.Gson
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.FlutterPlugin
@@ -37,7 +33,6 @@ import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.net.InetSocketAddress
import java.util.zip.ZipFile import java.util.zip.ZipFile
class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware { class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware {
@@ -52,11 +47,10 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
private lateinit var scope: CoroutineScope private lateinit var scope: CoroutineScope
private var connectivity: ConnectivityManager? = null
private var vpnCallBack: (() -> Unit)? = null private var vpnCallBack: (() -> Unit)? = null
private val iconMap = mutableMapOf<String, String?>() private val iconMap = mutableMapOf<String, String?>()
private val packages = mutableListOf<Package>() private val packages = mutableListOf<Package>()
private val skipPrefixList = listOf( private val skipPrefixList = listOf(
@@ -114,7 +108,6 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
("(" + chinaAppPrefixList.joinToString("|").replace(".", "\\.") + ").*").toRegex() ("(" + chinaAppPrefixList.joinToString("|").replace(".", "\\.") + ").*").toRegex()
} }
val VPN_PERMISSION_REQUEST_CODE = 1001 val VPN_PERMISSION_REQUEST_CODE = 1001
val NOTIFICATION_PERMISSION_REQUEST_CODE = 1002 val NOTIFICATION_PERMISSION_REQUEST_CODE = 1002
@@ -191,48 +184,6 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
} }
} }
"resolverProcess" -> {
val data = call.argument<String>("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<ConnectivityManager>()
}
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" -> { "tip" -> {
val message = call.argument<String>("message") val message = call.argument<String>("message")
tip(message) tip(message)
@@ -379,7 +330,6 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
} }
} }
private fun isChinaPackage(packageName: String): Boolean { private fun isChinaPackage(packageName: String): Boolean {
val packageManager = context.packageManager ?: return false val packageManager = context.packageManager ?: return false
skipPrefixList.forEach { skipPrefixList.forEach {
@@ -447,10 +397,6 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
return false return false
} }
fun requestGc() {
channel.invokeMethod("gc", null)
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) { override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity; activity = binding.activity;
binding.addActivityResultListener(::onActivityResult) binding.addActivityResultListener(::onActivityResult)
@@ -490,4 +436,4 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
} }
return true return true
} }
} }

View File

@@ -1,6 +1,8 @@
package com.follow.clash.plugins package com.follow.clash.plugins
import android.content.Context import android.content.Context
import android.net.ConnectivityManager
import androidx.core.content.getSystemService
import com.follow.clash.GlobalState import com.follow.clash.GlobalState
import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodCall

View File

@@ -5,19 +5,33 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.ServiceConnection 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.os.IBinder
import android.util.Log import androidx.core.content.getSystemService
import com.follow.clash.BaseServiceInterface import com.follow.clash.BaseServiceInterface
import com.follow.clash.GlobalState import com.follow.clash.GlobalState
import com.follow.clash.RunState 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.Props
import com.follow.clash.models.TunProps
import com.follow.clash.services.FlClashService import com.follow.clash.services.FlClashService
import com.follow.clash.services.FlClashVpnService import com.follow.clash.services.FlClashVpnService
import com.google.gson.Gson import com.google.gson.Gson
import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel 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 kotlin.concurrent.withLock
import com.follow.clash.models.Process
class VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler { class VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
@@ -26,6 +40,11 @@ class VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
private var flClashService: BaseServiceInterface? = null private var flClashService: BaseServiceInterface? = null
private var port: Int = 7890 private var port: Int = 7890
private var props: Props? = null private var props: Props? = null
private lateinit var scope: CoroutineScope
private val connectivity by lazy {
context.getSystemService<ConnectivityManager>()
}
private val connection = object : ServiceConnection { private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) { override fun onServiceConnected(className: ComponentName, service: IBinder) {
@@ -43,55 +62,104 @@ class VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
} }
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
scope = CoroutineScope(Dispatchers.Default)
context = flutterPluginBinding.applicationContext context = flutterPluginBinding.applicationContext
scope.launch {
registerNetworkCallback()
}
flutterMethodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "vpn") flutterMethodChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "vpn")
flutterMethodChannel.setMethodCallHandler(this) flutterMethodChannel.setMethodCallHandler(this)
} }
override fun onDetachedFromEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { override fun onDetachedFromEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
unRegisterNetworkCallback()
flutterMethodChannel.setMethodCallHandler(null) flutterMethodChannel.setMethodCallHandler(null)
} }
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) = when (call.method) { override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"start" -> { "start" -> {
port = call.argument<Int>("port")!! port = call.argument<Int>("port")!!
val args = call.argument<String>("args") val args = call.argument<String>("args")
props = props =
if (args != null) Gson().fromJson(args, Props::class.java) else null if (args != null) Gson().fromJson(args, Props::class.java) else null
when (props?.enable == true) { when (props?.enable == true) {
true -> handleStartVpn() true -> handleStartVpn()
false -> start() false -> start()
}
result.success(true)
}
"stop" -> {
stop()
result.success(true)
}
"setProtect" -> {
val fd = call.argument<Int>("fd")
if (fd != null) {
if (flClashService is FlClashVpnService) {
(flClashService as FlClashVpnService).protect(fd)
} }
result.success(true) result.success(true)
} else {
result.success(false)
} }
}
"startForeground" -> { "stop" -> {
val title = call.argument<String>("title") as String stop()
val content = call.argument<String>("content") as String result.success(true)
startForeground(title, content) }
result.success(true)
}
else -> { "setProtect" -> {
result.notImplemented() val fd = call.argument<Int>("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<String>("title") as String
val content = call.argument<String>("content") as String
startForeground(title, content)
result.success(true)
}
"resolverProcess" -> {
val data = call.argument<String>("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<Network>()
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") @SuppressLint("ForegroundServiceType")
private fun startForeground(title: String, content: String) { private fun startForeground(title: String, content: String) {
GlobalState.runLock.withLock { GlobalState.runLock.withLock {
@@ -118,8 +242,11 @@ class VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
GlobalState.runLock.withLock { GlobalState.runLock.withLock {
if (GlobalState.runState.value == RunState.START) return if (GlobalState.runState.value == RunState.START) return
GlobalState.runState.value = RunState.START GlobalState.runState.value = RunState.START
val fd = flClashService?.start(port, props) val tunProps = flClashService?.start(port, props)
flutterMethodChannel.invokeMethod("started", fd) flutterMethodChannel.invokeMethod(
"started",
Gson().toJson(tunProps, TunProps::class.java)
)
} }
} }

View File

@@ -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() { override fun stop() {
stopSelf() stopSelf()

View File

@@ -7,6 +7,7 @@ import android.app.NotificationManager
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Intent import android.content.Intent
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
import android.net.Network
import android.net.ProxyInfo import android.net.ProxyInfo
import android.net.VpnService import android.net.VpnService
import android.os.Binder import android.os.Binder
@@ -22,6 +23,7 @@ import com.follow.clash.MainActivity
import com.follow.clash.R import com.follow.clash.R
import com.follow.clash.models.AccessControlMode import com.follow.clash.models.AccessControlMode
import com.follow.clash.models.Props import com.follow.clash.models.Props
import com.follow.clash.models.TunProps
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -30,36 +32,53 @@ import kotlinx.coroutines.launch
@SuppressLint("WrongConstant") @SuppressLint("WrongConstant")
class FlClashVpnService : VpnService(), BaseServiceInterface { class FlClashVpnService : VpnService(), BaseServiceInterface {
private val passList = listOf( companion object {
"*zhihu.com", private val passList = listOf(
"*zhimg.com", "*zhihu.com",
"*jd.com", "*zhimg.com",
"100ime-iat-api.xfyun.cn", "*jd.com",
"*360buyimg.com", "100ime-iat-api.xfyun.cn",
"localhost", "*360buyimg.com",
"*.local", "localhost",
"127.*", "*.local",
"10.*", "127.*",
"172.16.*", "10.*",
"172.17.*", "172.16.*",
"172.18.*", "172.17.*",
"172.19.*", "172.18.*",
"172.2*", "172.19.*",
"172.30.*", "172.2*",
"172.31.*", "172.30.*",
"192.168.*" "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() { override fun onCreate() {
super.onCreate() super.onCreate()
GlobalState.initServiceEngine(applicationContext) GlobalState.initServiceEngine(applicationContext)
} }
override fun start(port: Int, props: Props?): Int? { override fun start(port: Int, props: Props?): TunProps {
return with(Builder()) { return with(Builder()) {
addAddress("172.16.0.1", 30) addAddress(TUN_GATEWAY, TUN_SUBNET_PREFIX)
setMtu(9000) addAddress(TUN_GATEWAY6, TUN_SUBNET_PREFIX6)
addRoute("0.0.0.0", 0) addRoute(NET_ANY, 0)
addRoute(NET_ANY6, 0)
addDnsServer(TUN_DNS)
addDnsServer(TUN_DNS6)
setMtu(TUN_MTU)
props?.accessControl?.let { accessControl -> props?.accessControl?.let { accessControl ->
when (accessControl.mode) { when (accessControl.mode) {
AccessControlMode.acceptSelected -> { AccessControlMode.acceptSelected -> {
@@ -75,7 +94,6 @@ class FlClashVpnService : VpnService(), BaseServiceInterface {
} }
} }
} }
addDnsServer("172.16.0.2")
setSession("FlClash") setSession("FlClash")
setBlocking(false) setBlocking(false)
if (Build.VERSION.SDK_INT >= 29) { 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<Network>){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
this.setUnderlyingNetworks(networks)
}
}
override fun stop() { override fun stop() {
stopSelf() stopSelf()
@@ -165,7 +197,7 @@ class FlClashVpnService : VpnService(), BaseServiceInterface {
override fun onTrimMemory(level: Int) { override fun onTrimMemory(level: Int) {
super.onTrimMemory(level) super.onTrimMemory(level)
GlobalState.getCurrentAppPlugin()?.requestGc() GlobalState.getCurrentVPNPlugin()?.requestGc()
} }
private val binder = LocalBinder() private val binder = LocalBinder()

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

20
core/dns.go Normal file
View File

@@ -0,0 +1,20 @@
//go:build android
package main
import "C"
import (
"github.com/metacubex/mihomo/dns"
"github.com/metacubex/mihomo/log"
"strings"
)
//export updateDns
func updateDns(s *C.char) {
dnsList := C.GoString(s)
go func() {
log.Infoln("[DNS] updateDns %s", dnsList)
dns.UpdateSystemDNS(strings.Split(dnsList, ","))
dns.FlushCacheWithDefaultResolver()
}()
}

View File

@@ -4,12 +4,9 @@ go 1.21.0
replace github.com/metacubex/mihomo => ./Clash.Meta replace github.com/metacubex/mihomo => ./Clash.Meta
require ( require github.com/metacubex/mihomo v1.17.1
github.com/Kr328/tun2socket v0.0.0-20220414050025-d07c78d06d34
github.com/metacubex/mihomo v1.17.1 replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240724044459-6f3cf5896297
github.com/miekg/dns v1.1.62
golang.org/x/sync v0.8.0
)
require ( require (
github.com/3andne/restls-client-go v0.1.6 // indirect 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/chacha v0.1.0 // indirect
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // 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/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/randv2 v0.2.0 // indirect
github.com/metacubex/sing-quic v0.0.0-20240827003841-cd97758ed8b4 // indirect github.com/metacubex/sing-quic v0.0.0-20240827003841-cd97758ed8b4 // indirect
github.com/metacubex/sing-shadowsocks v0.2.8 // indirect github.com/metacubex/sing-shadowsocks v0.2.8 // indirect
@@ -64,6 +61,7 @@ require (
github.com/metacubex/sing-wireguard v0.0.0-20240826061955-1e4e67afe5cd // indirect github.com/metacubex/sing-wireguard v0.0.0-20240826061955-1e4e67afe5cd // indirect
github.com/metacubex/tfo-go v0.0.0-20240830120620-c5e019b67785 // indirect github.com/metacubex/tfo-go v0.0.0-20240830120620-c5e019b67785 // indirect
github.com/metacubex/utls v1.6.6 // 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/mroth/weightedrand/v2 v2.1.0 // indirect
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
github.com/onsi/ginkgo/v2 v2.9.5 // 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/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
golang.org/x/mod v0.20.0 // indirect golang.org/x/mod v0.20.0 // indirect
golang.org/x/net v0.28.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/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.5.0 // indirect golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.24.0 // indirect golang.org/x/tools v0.24.0 // indirect
google.golang.org/protobuf v1.34.2 // 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 lukechampine.com/blake3 v1.3.0 // indirect
) )

View File

@@ -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 h1:tRx/YilqW7iHpgmEL4E1D8dAsuB0tFF3uvncS+B6I08=
github.com/3andne/restls-client-go v0.1.6/go.mod h1:iEdTZNt9kzPIxjIGSMScUFSBrUH6bFRNg0BWlP4orEY= 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/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 h1:mXuNdK6M317aPV0llW6Xpjbo4moOlPF7Yxz4tb4b4Go=
github.com/RyuaNerin/go-krypto v1.2.4/go.mod h1:QqCYkoutU3yInyD9INt2PGolVRsc3W4oraQadVGXJ/8= 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/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 h1:HxreOiFTUrJXJautEo8rnE1uKTVGY8wtZepY1Tii/Nc=
github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec/go.mod h1:8BVmQ+3cxjqzWElafm24rb2Ae4jRI6vAXNXWqWjfrXw= 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.47.1-0.20240909010619-6b38f24bfcc4 h1:CgdUBRxmNlxEGkp35HwvgQ10jwOOUJKWdOxpi8yWi8o=
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/go.mod h1:Y7yRGqFE6UQL/3aKPYmiYdjfVkeujJaStP4+jiZMcN8=
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs= github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY= 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 h1:HobpULaPK6OoxrHMmgcwLkwwIduXVmwdcznwUfH1GQM=
github.com/metacubex/sing-quic v0.0.0-20240827003841-cd97758ed8b4/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8= github.com/metacubex/sing-quic v0.0.0-20240827003841-cd97758ed8b4/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8=
github.com/metacubex/sing-shadowsocks v0.2.8 h1:wIhlaigswzjPw4hej75sEvWte3QR0+AJRafgwBHO5B4= github.com/metacubex/sing-shadowsocks v0.2.8 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/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 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= 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 h1:5bCAkvDDzSMITiHFjolBwpdqYsvycdTu71FsMEFXQ14=
github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ= 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= 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 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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.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.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.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.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 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= 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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.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.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 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=

View File

@@ -378,27 +378,28 @@ func updateGeoData(geoType *C.char, geoName *C.char, port C.longlong) {
geoTypeString := C.GoString(geoType) geoTypeString := C.GoString(geoType)
geoNameString := C.GoString(geoName) geoNameString := C.GoString(geoName)
go func() { go func() {
path := constant.Path.Resolve(geoNameString)
switch geoTypeString { switch geoTypeString {
case "MMDB": case "MMDB":
err := updater.UpdateMMDB(constant.Path.Resolve(geoNameString)) err := updater.UpdateMMDBWithPath(path)
if err != nil { if err != nil {
bridge.SendToPort(i, err.Error()) bridge.SendToPort(i, err.Error())
return return
} }
case "ASN": case "ASN":
err := updater.UpdateASN(constant.Path.Resolve(geoNameString)) err := updater.UpdateASNWithPath(path)
if err != nil { if err != nil {
bridge.SendToPort(i, err.Error()) bridge.SendToPort(i, err.Error())
return return
} }
case "GeoIp": case "GeoIp":
err := updater.UpdateGeoIp(constant.Path.Resolve(geoNameString)) err := updater.UpdateGeoIpWithPath(path)
if err != nil { if err != nil {
bridge.SendToPort(i, err.Error()) bridge.SendToPort(i, err.Error())
return return
} }
case "GeoSite": case "GeoSite":
err := updater.UpdateGeoSite(constant.Path.Resolve(geoNameString)) err := updater.UpdateGeoSiteWithPath(path)
if err != nil { if err != nil {
bridge.SendToPort(i, err.Error()) bridge.SendToPort(i, err.Error())
return return

View File

@@ -6,7 +6,9 @@ import "C"
import ( import (
"core/platform" "core/platform"
t "core/tun" t "core/tun"
"encoding/json"
"errors" "errors"
"github.com/metacubex/mihomo/listener/sing_tun"
"strconv" "strconv"
"sync" "sync"
"sync/atomic" "sync/atomic"
@@ -15,11 +17,9 @@ import (
"github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/dialer"
"github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/log"
"golang.org/x/sync/semaphore"
) )
var tunLock sync.Mutex var tunLock sync.Mutex
var tun *t.Tun
var runTime *time.Time var runTime *time.Time
type FdMap struct { type FdMap struct {
@@ -35,13 +35,18 @@ func (cm *FdMap) Load(key int64) bool {
return ok return ok
} }
var fdMap FdMap var (
tunListener *sing_tun.Listener
fdMap FdMap
fdCounter int64 = 0
)
//export startTUN //export startTUN
func startTUN(fd C.int, port C.longlong) { func startTUN(s *C.char, port C.longlong) {
i := int64(port) i := int64(port)
ServicePort = i ServicePort = i
if fd == 0 { paramsString := C.GoString(s)
if paramsString == "" {
tunLock.Lock() tunLock.Lock()
defer tunLock.Unlock() defer tunLock.Unlock()
now := time.Now() now := time.Now()
@@ -57,28 +62,22 @@ func startTUN(fd C.int, port C.longlong) {
tunLock.Lock() tunLock.Lock()
defer tunLock.Unlock() defer tunLock.Unlock()
if tun != nil { var tunProps = &t.Props{}
tun.Close() err := json.Unmarshal([]byte(paramsString), tunProps)
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)
if err != nil { if err != nil {
log.Errorln("startTUN error: %v", err) 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() now := time.Now()
@@ -108,9 +107,8 @@ func stopTun() {
runTime = nil runTime = nil
if tun != nil { if tunListener != nil {
tun.Close() _ = tunListener.Close()
tun = nil
} }
}() }()
} }
@@ -137,18 +135,12 @@ func markSocket(fd Fd) {
}) })
} }
var fdCounter int64 = 0
func initSocketHook() { func initSocketHook() {
dialer.DefaultSocketHook = func(network, address string, conn syscall.RawConn) error { dialer.DefaultSocketHook = func(network, address string, conn syscall.RawConn) error {
if platform.ShouldBlockConnection() { if platform.ShouldBlockConnection() {
return errBlocked return errBlocked
} }
return conn.Control(func(fd uintptr) { return conn.Control(func(fd uintptr) {
if tun == nil {
return
}
fdInt := int64(fd) fdInt := int64(fd)
timeout := time.After(100 * time.Millisecond) timeout := time.After(100 * time.Millisecond)
id := atomic.AddInt64(&fdCounter, 1) id := atomic.AddInt64(&fdCounter, 1)

View File

@@ -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()
}

View File

@@ -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: "",
}
}

View File

@@ -4,182 +4,65 @@ package tun
import "C" import "C"
import ( 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" "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/log"
"github.com/metacubex/mihomo/transport/socks5"
"github.com/metacubex/mihomo/tunnel" "github.com/metacubex/mihomo/tunnel"
"golang.org/x/sync/semaphore"
"io"
"net" "net"
"os" "net/netip"
"time"
) )
type Tun struct { type Props struct {
Closer io.Closer Fd int `json:"fd"`
Gateway string `json:"gateway"`
Closed bool Gateway6 string `json:"gateway6"`
Limit *semaphore.Weighted Portal string `json:"portal"`
Portal6 string `json:"portal6"`
Dns string `json:"dns"`
Dns6 string `json:"dns6"`
} }
func (t *Tun) Close() { func Start(tunProps Props) (*sing_tun.Listener, error) {
_ = t.Limit.Acquire(context.TODO(), 4) var prefix4 []netip.Prefix
defer t.Limit.Release(4) tempPrefix4, err := netip.ParsePrefix(tunProps.Gateway)
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)
if err != nil { if err != nil {
panic(err.Error()) log.Errorln("startTUN error:", err)
} else { return nil, err
network.IP = ip
} }
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 { if err != nil {
_ = device.Close() log.Errorln("startTUN error:", err)
return nil, err return nil, err
} }
dnsAddr := net.ParseIP(dns) return listener, nil
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
} }

View File

@@ -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
}

View File

@@ -1,11 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:dynamic_color/dynamic_color.dart'; import 'package:dynamic_color/dynamic_color.dart';
import 'package:fl_clash/l10n/l10n.dart'; import 'package:fl_clash/l10n/l10n.dart';
import 'package:fl_clash/common/common.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/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/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -53,6 +54,7 @@ class Application extends StatefulWidget {
class ApplicationState extends State<Application> { class ApplicationState extends State<Application> {
late SystemColorSchemes systemColorSchemes; late SystemColorSchemes systemColorSchemes;
Timer? timer;
final _pageTransitionsTheme = const PageTransitionsTheme( final _pageTransitionsTheme = const PageTransitionsTheme(
builders: <TargetPlatform, PageTransitionsBuilder>{ builders: <TargetPlatform, PageTransitionsBuilder>{
@@ -81,6 +83,7 @@ class ApplicationState extends State<Application> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_initTimer();
globalState.appController = AppController(context); globalState.appController = AppController(context);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
final currentContext = globalState.navigatorKey.currentContext; final currentContext = globalState.navigatorKey.currentContext;
@@ -92,18 +95,36 @@ class ApplicationState extends State<Application> {
}); });
} }
_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) { _buildApp(Widget app) {
if (system.isDesktop) { if (system.isDesktop) {
return WindowContainer( return WindowManager(
child: TrayContainer( child: TrayManager(
child: ProxyContainer( child: HotKeyManager(
child: app, child: ProxyManager(
child: app,
),
), ),
), ),
); );
} }
return AndroidContainer( return AndroidManager(
child: TileContainer( child: TileManager(
child: app, child: app,
), ),
); );
@@ -115,7 +136,7 @@ class ApplicationState extends State<Application> {
child: page, child: page,
); );
} }
return VpnContainer( return VpnManager(
child: page, child: page,
); );
} }
@@ -136,8 +157,8 @@ class ApplicationState extends State<Application> {
@override @override
Widget build(context) { Widget build(context) {
return _buildApp( return _buildApp(
AppStateContainer( AppStateManager(
child: ClashContainer( child: ClashManager(
child: Selector2<AppState, Config, ApplicationSelectorState>( child: Selector2<AppState, Config, ApplicationSelectorState>(
selector: (_, appState, config) => ApplicationSelectorState( selector: (_, appState, config) => ApplicationSelectorState(
locale: config.locale, locale: config.locale,
@@ -158,7 +179,7 @@ class ApplicationState extends State<Application> {
GlobalWidgetsLocalizations.delegate GlobalWidgetsLocalizations.delegate
], ],
builder: (_, child) { builder: (_, child) {
return MediaContainer( return MediaManager(
child: _buildPage(child!), child: _buildPage(child!),
); );
}, },
@@ -203,5 +224,6 @@ class ApplicationState extends State<Application> {
linkManager.destroy(); linkManager.destroy();
await globalState.appController.savePreferences(); await globalState.appController.savePreferences();
super.dispose(); super.dispose();
_cancelTimer();
} }
} }

View File

@@ -158,7 +158,7 @@ class ClashCore {
final externalProviderRawString = final externalProviderRawString =
externalProviderRaw.cast<Utf8>().toDartString(); externalProviderRaw.cast<Utf8>().toDartString();
clashFFI.freeCString(externalProviderRaw); clashFFI.freeCString(externalProviderRaw);
if(externalProviderRawString.isEmpty) return null; if (externalProviderRawString.isEmpty) return null;
return ExternalProvider.fromJson(json.decode(externalProviderRawString)); return ExternalProvider.fromJson(json.decode(externalProviderRawString));
} }
@@ -322,9 +322,18 @@ class ClashCore {
clashFFI.stopLog(); clashFFI.stopLog();
} }
startTun(int fd, int port) { startTun(TunProps? tunProps, int port) {
if (!Platform.isAndroid) return; if (!Platform.isAndroid) return;
clashFFI.startTUN(fd, port); final tunPropsChar = json.encode(tunProps).toNativeUtf8().cast<Char>();
clashFFI.startTUN(tunPropsChar, port);
malloc.free(tunPropsChar);
}
updateDns(String dns) {
if (!Platform.isAndroid) return;
final dnsChar = dns.toNativeUtf8().cast<Char>();
clashFFI.updateDns(dnsChar);
malloc.free(dnsChar);
} }
requestGc() { requestGc() {

View File

@@ -5264,6 +5264,20 @@ class ClashFFI {
late final _getProxies = late final _getProxies =
_getProxiesPtr.asFunction<ffi.Pointer<ffi.Char> Function()>(); _getProxiesPtr.asFunction<ffi.Pointer<ffi.Char> Function()>();
void updateDns(
ffi.Pointer<ffi.Char> s,
) {
return _updateDns(
s,
);
}
late final _updateDnsPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Char>)>>(
'updateDns');
late final _updateDns =
_updateDnsPtr.asFunction<void Function(ffi.Pointer<ffi.Char>)>();
void changeProxy( void changeProxy(
ffi.Pointer<ffi.Char> s, ffi.Pointer<ffi.Char> s,
) { ) {
@@ -5567,19 +5581,20 @@ class ClashFFI {
_setStatePtr.asFunction<void Function(ffi.Pointer<ffi.Char>)>(); _setStatePtr.asFunction<void Function(ffi.Pointer<ffi.Char>)>();
void startTUN( void startTUN(
int fd, ffi.Pointer<ffi.Char> s,
int port, int port,
) { ) {
return _startTUN( return _startTUN(
fd, s,
port, port,
); );
} }
late final _startTUNPtr = late final _startTUNPtr = _lookup<
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int, ffi.LongLong)>>( ffi.NativeFunction<
'startTUN'); ffi.Void Function(ffi.Pointer<ffi.Char>, ffi.LongLong)>>('startTUN');
late final _startTUN = _startTUNPtr.asFunction<void Function(int, int)>(); late final _startTUN =
_startTUNPtr.asFunction<void Function(ffi.Pointer<ffi.Char>, int)>();
ffi.Pointer<ffi.Char> getRunTime() { ffi.Pointer<ffi.Char> getRunTime() {
return _getRunTime(); return _getRunTime();

View File

@@ -27,4 +27,5 @@ export 'windows.dart';
export 'iterable.dart'; export 'iterable.dart';
export 'scroll.dart'; export 'scroll.dart';
export 'icons.dart'; export 'icons.dart';
export 'http.dart'; export 'http.dart';
export 'keyboard.dart';

View File

@@ -1,3 +1,4 @@
import 'dart:io';
import 'dart:ui'; import 'dart:ui';
import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/enum/enum.dart';
@@ -16,7 +17,11 @@ const mmdbFileName = "geoip.metadb";
const asnFileName = "ASN.mmdb"; const asnFileName = "ASN.mmdb";
const geoIpFileName = "GeoIP.dat"; const geoIpFileName = "GeoIP.dat";
const geoSiteFileName = "GeoSite.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 = { const GeoXMap defaultGeoXMap = {
"mmdb": "mmdb":
"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb",

106
lib/common/keyboard.dart Normal file
View File

@@ -0,0 +1,106 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:uni_platform/uni_platform.dart';
final Map<PhysicalKeyboardKey, String> _knownKeyLabels =
<PhysicalKeyboardKey, String>{
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';
}
}

View File

@@ -100,12 +100,18 @@ class Other {
} }
} }
String getTrayIconPath() { String getTrayIconPath({
if (Platform.isWindows) { required bool isStart,
return "assets/images/icon.ico"; required Brightness brightness,
} else { }) {
return "assets/images/icon_monochrome.png"; 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) { int compareVersions(String version1, String version2) {
@@ -201,9 +207,9 @@ class Other {
int getProxiesColumns(double viewWidth, ProxiesLayout proxiesLayout) { int getProxiesColumns(double viewWidth, ProxiesLayout proxiesLayout) {
final columns = max((viewWidth / 300).ceil(), 2); final columns = max((viewWidth / 300).ceil(), 2);
return switch (proxiesLayout) { return switch (proxiesLayout) {
ProxiesLayout.tight => columns - 1, ProxiesLayout.tight => columns + 1,
ProxiesLayout.standard => columns, ProxiesLayout.standard => columns,
ProxiesLayout.loose => columns + 1, ProxiesLayout.loose => columns - 1,
}; };
} }

View File

@@ -3,7 +3,7 @@ import 'dart:typed_data';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:fl_clash/common/common.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:fl_clash/state.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';

View File

@@ -1,7 +1,9 @@
import 'dart:io'; import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:fl_clash/plugins/app.dart'; import 'package:fl_clash/plugins/app.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:window_manager/window_manager.dart';
import 'window.dart'; import 'window.dart';
@@ -24,6 +26,16 @@ class System {
return result.exitCode == 0; return result.exitCode == 0;
} }
Future<int> 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 { back() async {
await app?.moveTaskToBack(); await app?.moveTaskToBack();
await window?.hide(); await window?.hide();

16
lib/common/window.dart Normal file → Executable file
View File

@@ -9,7 +9,7 @@ import 'protocol.dart';
import 'system.dart'; import 'system.dart';
class Window { class Window {
init(WindowProps props) async { init(WindowProps props, int version) async {
if (Platform.isWindows) { if (Platform.isWindows) {
await WindowsSingleInstance.ensureSingleInstance([], "FlClash"); await WindowsSingleInstance.ensureSingleInstance([], "FlClash");
protocol.register("clash"); protocol.register("clash");
@@ -20,8 +20,6 @@ class Window {
WindowOptions windowOptions = WindowOptions( WindowOptions windowOptions = WindowOptions(
size: Size(props.width, props.height), size: Size(props.width, props.height),
minimumSize: const Size(380, 500), minimumSize: const Size(380, 500),
windowButtonVisibility: false,
titleBarStyle: TitleBarStyle.hidden,
); );
if (props.left != null || props.top != null) { if (props.left != null || props.top != null) {
await windowManager.setPosition( await windowManager.setPosition(
@@ -30,9 +28,9 @@ class Window {
} else { } else {
await windowManager.setAlignment(Alignment.center); await windowManager.setAlignment(Alignment.center);
} }
// if(Platform.isWindows){ if(!Platform.isMacOS || version > 10){
// await windowManager.setTitleBarStyle(TitleBarStyle.hidden); await windowManager.setTitleBarStyle(TitleBarStyle.hidden);
// } }
await windowManager.waitUntilReadyToShow(windowOptions, () async { await windowManager.waitUntilReadyToShow(windowOptions, () async {
await windowManager.setPreventClose(true); await windowManager.setPreventClose(true);
}); });
@@ -41,6 +39,11 @@ class Window {
show() async { show() async {
await windowManager.show(); await windowManager.show();
await windowManager.focus(); await windowManager.focus();
await windowManager.setSkipTaskbar(false);
}
Future<bool> isVisible() async {
return await windowManager.isVisible();
} }
close() async { close() async {
@@ -49,6 +52,7 @@ class Window {
hide() async { hide() async {
await windowManager.hide(); await windowManager.hide();
await windowManager.setSkipTaskbar(true);
} }
} }

View File

@@ -295,6 +295,10 @@ class AppController {
} }
init() async { init() async {
final isDisclaimerAccepted = await handlerDisclaimer();
if (!isDisclaimerAccepted) {
system.exit();
}
updateLogStatus(); updateLogStatus();
if (!config.silentLaunch) { if (!config.silentLaunch) {
window?.show(); window?.show();
@@ -311,14 +315,6 @@ class AppController {
autoCheckUpdate(); autoCheckUpdate();
} }
updateTray() {
globalState.updateTray(
appState: appState,
config: config,
clashConfig: clashConfig,
);
}
setDelay(Delay delay) { setDelay(Delay delay) {
appState.setDelay(delay); appState.setDelay(delay);
} }
@@ -381,6 +377,47 @@ class AppController {
globalState.showSnackBar(context, message: message); globalState.showSnackBar(context, message: message);
} }
Future<bool> showDisclaimer() async {
return await globalState.showCommonDialog<bool>(
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<bool>(false);
},
child: Text(appLocalizations.exit),
),
TextButton(
onPressed: () {
config.isDisclaimerAccepted = true;
Navigator.of(context).pop<bool>(true);
},
child: Text(appLocalizations.agree),
)
],
),
) ??
false;
}
Future<bool> handlerDisclaimer() async {
if (config.isDisclaimerAccepted) {
return true;
}
return showDisclaimer();
}
addProfileFormURL(String url) async { addProfileFormURL(String url) async {
if (globalState.navigatorKey.currentState?.canPop() ?? false) { if (globalState.navigatorKey.currentState?.canPop() ?? false) {
globalState.navigatorKey.currentState?.popUntil((route) => route.isFirst); 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( recoveryData(
List<int> data, List<int> data,
RecoveryOption recoveryOption, RecoveryOption recoveryOption,

View File

@@ -1,6 +1,8 @@
// ignore_for_file: constant_identifier_names // ignore_for_file: constant_identifier_names
import 'package:flutter/services.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hotkey_manager/hotkey_manager.dart';
enum GroupType { Selector, URLTest, Fallback, LoadBalance, Relay } enum GroupType { Selector, URLTest, Fallback, LoadBalance, Relay }
@@ -92,7 +94,6 @@ enum ProxiesLayout { loose, standard, tight }
enum ProxyCardType { expand, shrink, min } enum ProxyCardType { expand, shrink, min }
enum DnsMode { enum DnsMode {
normal, normal,
@JsonValue("fake-ip") @JsonValue("fake-ip")
@@ -102,3 +103,52 @@ enum DnsMode {
hosts 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<PhysicalKeyboardKey> 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,
}

View File

@@ -3,8 +3,7 @@ import 'dart:typed_data';
import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/common/dav_client.dart'; import 'package:fl_clash/common/dav_client.dart';
import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/models/config.dart'; import 'package:fl_clash/models/models.dart';
import 'package:fl_clash/models/dav.dart';
import 'package:fl_clash/state.dart'; import 'package:fl_clash/state.dart';
import 'package:fl_clash/widgets/fade_box.dart'; import 'package:fl_clash/widgets/fade_box.dart';
import 'package:fl_clash/widgets/list.dart'; import 'package:fl_clash/widgets/list.dart';

View File

@@ -5,7 +5,6 @@ import 'package:fl_clash/models/config.dart';
import 'package:fl_clash/state.dart'; import 'package:fl_clash/state.dart';
import 'package:fl_clash/widgets/widgets.dart'; import 'package:fl_clash/widgets/widgets.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:path/path.dart' show dirname, join;
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class CloseConnectionsSwitch extends StatelessWidget { 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<Config, bool>(
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 = [ final appItems = [
if (Platform.isWindows) const UWPLoopbackUtil(),
const CloseConnectionsSwitch(), const CloseConnectionsSwitch(),
const UsageSwitch(), const UsageSwitch(),
]; ];

View File

@@ -14,7 +14,7 @@ class OverrideItem extends StatelessWidget {
_initActions(BuildContext context) { _initActions(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
final commonScaffoldState = final commonScaffoldState =
context.findAncestorStateOfType<CommonScaffoldState>(); context.findAncestorStateOfType<CommonScaffoldState>();
commonScaffoldState?.actions = [ commonScaffoldState?.actions = [
IconButton( IconButton(
onPressed: () { onPressed: () {
@@ -54,7 +54,8 @@ class OverrideItem extends StatelessWidget {
class DnsDisabledContainer extends StatelessWidget { class DnsDisabledContainer extends StatelessWidget {
final Widget child; final Widget child;
const DnsDisabledContainer(this.child, { const DnsDisabledContainer(
this.child, {
super.key, super.key,
}); });
@@ -268,7 +269,7 @@ class FakeIpFilterItem extends StatelessWidget {
widget: Selector<ClashConfig, List<String>>( widget: Selector<ClashConfig, List<String>>(
selector: (_, clashConfig) => clashConfig.dns.fakeIpFilter, selector: (_, clashConfig) => clashConfig.dns.fakeIpFilter,
shouldRebuild: (prev, next) => shouldRebuild: (prev, next) =>
!const ListEquality<String>().equals(prev, next), !const ListEquality<String>().equals(prev, next),
builder: (_, fakeIpFilter, __) { builder: (_, fakeIpFilter, __) {
return UpdatePage( return UpdatePage(
title: appLocalizations.fakeipFilter, title: appLocalizations.fakeipFilter,
@@ -278,8 +279,7 @@ class FakeIpFilterItem extends StatelessWidget {
final clashConfig = globalState.appController.clashConfig; final clashConfig = globalState.appController.clashConfig;
final dns = clashConfig.dns; final dns = clashConfig.dns;
clashConfig.dns = dns.copyWith( clashConfig.dns = dns.copyWith(
fakeIpFilter: List.from(dns.fakeIpFilter) fakeIpFilter: List.from(dns.fakeIpFilter)..remove(value),
..remove(value),
); );
}, },
onAdd: (value) { onAdd: (value) {
@@ -287,8 +287,7 @@ class FakeIpFilterItem extends StatelessWidget {
final dns = clashConfig.dns; final dns = clashConfig.dns;
if (fakeIpFilter.contains(value)) return; if (fakeIpFilter.contains(value)) return;
clashConfig.dns = dns.copyWith( clashConfig.dns = dns.copyWith(
fakeIpFilter: List.from(dns.fakeIpFilter) fakeIpFilter: List.from(dns.fakeIpFilter)..add(value),
..add(value),
); );
}, },
); );
@@ -314,7 +313,7 @@ class DefaultNameserverItem extends StatelessWidget {
widget: Selector<ClashConfig, List<String>>( widget: Selector<ClashConfig, List<String>>(
selector: (_, clashConfig) => clashConfig.dns.defaultNameserver, selector: (_, clashConfig) => clashConfig.dns.defaultNameserver,
shouldRebuild: (prev, next) => shouldRebuild: (prev, next) =>
!const ListEquality<String>().equals(prev, next), !const ListEquality<String>().equals(prev, next),
builder: (_, defaultNameserver, __) { builder: (_, defaultNameserver, __) {
return UpdatePage( return UpdatePage(
title: appLocalizations.defaultNameserver, title: appLocalizations.defaultNameserver,
@@ -360,7 +359,7 @@ class NameserverItem extends StatelessWidget {
widget: Selector<ClashConfig, List<String>>( widget: Selector<ClashConfig, List<String>>(
selector: (_, clashConfig) => clashConfig.dns.nameserver, selector: (_, clashConfig) => clashConfig.dns.nameserver,
shouldRebuild: (prev, next) => shouldRebuild: (prev, next) =>
!const ListEquality<String>().equals(prev, next), !const ListEquality<String>().equals(prev, next),
builder: (_, nameserver, __) { builder: (_, nameserver, __) {
return UpdatePage( return UpdatePage(
title: "域名服务器", title: "域名服务器",
@@ -370,8 +369,7 @@ class NameserverItem extends StatelessWidget {
final clashConfig = globalState.appController.clashConfig; final clashConfig = globalState.appController.clashConfig;
final dns = clashConfig.dns; final dns = clashConfig.dns;
clashConfig.dns = dns.copyWith( clashConfig.dns = dns.copyWith(
nameserver: List.from(dns.nameserver) nameserver: List.from(dns.nameserver)..remove(value),
..remove(value),
); );
}, },
onAdd: (value) { onAdd: (value) {
@@ -379,8 +377,7 @@ class NameserverItem extends StatelessWidget {
final dns = clashConfig.dns; final dns = clashConfig.dns;
if (nameserver.contains(value)) return; if (nameserver.contains(value)) return;
clashConfig.dns = dns.copyWith( clashConfig.dns = dns.copyWith(
nameserver: List.from(dns.nameserver) nameserver: List.from(dns.nameserver)..add(value),
..add(value),
); );
}, },
); );
@@ -458,7 +455,7 @@ class NameserverPolicyItem extends StatelessWidget {
widget: Selector<ClashConfig, Map<String, String>>( widget: Selector<ClashConfig, Map<String, String>>(
selector: (_, clashConfig) => clashConfig.dns.nameserverPolicy, selector: (_, clashConfig) => clashConfig.dns.nameserverPolicy,
shouldRebuild: (prev, next) => shouldRebuild: (prev, next) =>
!const MapEquality<String, String>().equals(prev, next), !const MapEquality<String, String>().equals(prev, next),
builder: (_, nameserverPolicy, __) { builder: (_, nameserverPolicy, __) {
return UpdatePage( return UpdatePage(
title: appLocalizations.nameserverPolicy, title: appLocalizations.nameserverPolicy,
@@ -505,7 +502,7 @@ class ProxyServerNameserverItem extends StatelessWidget {
widget: Selector<ClashConfig, List<String>>( widget: Selector<ClashConfig, List<String>>(
selector: (_, clashConfig) => clashConfig.dns.proxyServerNameserver, selector: (_, clashConfig) => clashConfig.dns.proxyServerNameserver,
shouldRebuild: (prev, next) => shouldRebuild: (prev, next) =>
!const ListEquality<String>().equals(prev, next), !const ListEquality<String>().equals(prev, next),
builder: (_, proxyServerNameserver, __) { builder: (_, proxyServerNameserver, __) {
return UpdatePage( return UpdatePage(
title: appLocalizations.proxyNameserver, title: appLocalizations.proxyNameserver,
@@ -551,7 +548,7 @@ class FallbackItem extends StatelessWidget {
widget: Selector<ClashConfig, List<String>>( widget: Selector<ClashConfig, List<String>>(
selector: (_, clashConfig) => clashConfig.dns.fallback, selector: (_, clashConfig) => clashConfig.dns.fallback,
shouldRebuild: (prev, next) => shouldRebuild: (prev, next) =>
!const ListEquality<String>().equals(prev, next), !const ListEquality<String>().equals(prev, next),
builder: (_, fallback, __) { builder: (_, fallback, __) {
return UpdatePage( return UpdatePage(
title: appLocalizations.fallback, title: appLocalizations.fallback,
@@ -561,8 +558,7 @@ class FallbackItem extends StatelessWidget {
final clashConfig = globalState.appController.clashConfig; final clashConfig = globalState.appController.clashConfig;
final dns = clashConfig.dns; final dns = clashConfig.dns;
clashConfig.dns = dns.copyWith( clashConfig.dns = dns.copyWith(
fallback: List.from(dns.fallback) fallback: List.from(dns.fallback)..remove(value),
..remove(value),
); );
}, },
onAdd: (value) { onAdd: (value) {
@@ -570,8 +566,7 @@ class FallbackItem extends StatelessWidget {
final dns = clashConfig.dns; final dns = clashConfig.dns;
if (fallback.contains(value)) return; if (fallback.contains(value)) return;
clashConfig.dns = dns.copyWith( clashConfig.dns = dns.copyWith(
fallback: List.from(dns.fallback) fallback: List.from(dns.fallback)..add(value),
..add(value),
); );
}, },
); );
@@ -663,7 +658,7 @@ class GeositeItem extends StatelessWidget {
widget: Selector<ClashConfig, List<String>>( widget: Selector<ClashConfig, List<String>>(
selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.geosite, selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.geosite,
shouldRebuild: (prev, next) => shouldRebuild: (prev, next) =>
!const ListEquality<String>().equals(prev, next), !const ListEquality<String>().equals(prev, next),
builder: (_, geosite, __) { builder: (_, geosite, __) {
return UpdatePage( return UpdatePage(
title: "Geosite", title: "Geosite",
@@ -674,8 +669,7 @@ class GeositeItem extends StatelessWidget {
final dns = clashConfig.dns; final dns = clashConfig.dns;
clashConfig.dns = dns.copyWith( clashConfig.dns = dns.copyWith(
fallbackFilter: dns.fallbackFilter.copyWith( fallbackFilter: dns.fallbackFilter.copyWith(
geosite: List.from(geosite) geosite: List.from(geosite)..remove(value),
..remove(value),
), ),
); );
}, },
@@ -684,8 +678,7 @@ class GeositeItem extends StatelessWidget {
final dns = clashConfig.dns; final dns = clashConfig.dns;
clashConfig.dns = dns.copyWith( clashConfig.dns = dns.copyWith(
fallbackFilter: dns.fallbackFilter.copyWith( fallbackFilter: dns.fallbackFilter.copyWith(
geosite: List.from(geosite) geosite: List.from(geosite)..add(value),
..add(value),
), ),
); );
}, },
@@ -711,7 +704,7 @@ class IpcidrItem extends StatelessWidget {
widget: Selector<ClashConfig, List<String>>( widget: Selector<ClashConfig, List<String>>(
selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.ipcidr, selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.ipcidr,
shouldRebuild: (prev, next) => shouldRebuild: (prev, next) =>
!const ListEquality<String>().equals(prev, next), !const ListEquality<String>().equals(prev, next),
builder: (_, ipcidr, __) { builder: (_, ipcidr, __) {
return UpdatePage( return UpdatePage(
title: appLocalizations.ipcidr, title: appLocalizations.ipcidr,
@@ -722,8 +715,7 @@ class IpcidrItem extends StatelessWidget {
final dns = clashConfig.dns; final dns = clashConfig.dns;
clashConfig.dns = dns.copyWith( clashConfig.dns = dns.copyWith(
fallbackFilter: dns.fallbackFilter.copyWith( fallbackFilter: dns.fallbackFilter.copyWith(
ipcidr: List.from(ipcidr) ipcidr: List.from(ipcidr)..remove(value),
..remove(value),
), ),
); );
}, },
@@ -732,8 +724,7 @@ class IpcidrItem extends StatelessWidget {
final dns = clashConfig.dns; final dns = clashConfig.dns;
clashConfig.dns = dns.copyWith( clashConfig.dns = dns.copyWith(
fallbackFilter: dns.fallbackFilter.copyWith( fallbackFilter: dns.fallbackFilter.copyWith(
ipcidr: List.from(ipcidr) ipcidr: List.from(ipcidr)..add(value),
..add(value),
), ),
); );
}, },
@@ -759,7 +750,7 @@ class DomainItem extends StatelessWidget {
widget: Selector<ClashConfig, List<String>>( widget: Selector<ClashConfig, List<String>>(
selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.domain, selector: (_, clashConfig) => clashConfig.dns.fallbackFilter.domain,
shouldRebuild: (prev, next) => shouldRebuild: (prev, next) =>
!const ListEquality<String>().equals(prev, next), !const ListEquality<String>().equals(prev, next),
builder: (_, domain, __) { builder: (_, domain, __) {
return UpdatePage( return UpdatePage(
title: appLocalizations.domain, title: appLocalizations.domain,
@@ -770,8 +761,7 @@ class DomainItem extends StatelessWidget {
final dns = clashConfig.dns; final dns = clashConfig.dns;
clashConfig.dns = dns.copyWith( clashConfig.dns = dns.copyWith(
fallbackFilter: dns.fallbackFilter.copyWith( fallbackFilter: dns.fallbackFilter.copyWith(
domain: List.from(domain) domain: List.from(domain)..remove(value),
..remove(value),
), ),
); );
}, },
@@ -780,8 +770,7 @@ class DomainItem extends StatelessWidget {
final dns = clashConfig.dns; final dns = clashConfig.dns;
clashConfig.dns = dns.copyWith( clashConfig.dns = dns.copyWith(
fallbackFilter: dns.fallbackFilter.copyWith( fallbackFilter: dns.fallbackFilter.copyWith(
domain: List.from(domain) domain: List.from(domain)..add(value),
..add(value),
), ),
); );
}, },

View File

@@ -47,14 +47,16 @@ class TUNSwitch extends StatelessWidget {
child: Selector<ClashConfig, bool>( child: Selector<ClashConfig, bool>(
selector: (_, clashConfig) => clashConfig.tun.enable, selector: (_, clashConfig) => clashConfig.tun.enable,
builder: (_, enable, __) { builder: (_, enable, __) {
return Switch( return LocaleBuilder(
value: enable, builder: (_) => Switch(
onChanged: (value) { value: enable,
final clashConfig = globalState.appController.clashConfig; onChanged: (value) {
clashConfig.tun = clashConfig.tun.copyWith( final clashConfig = globalState.appController.clashConfig;
enable: value, clashConfig.tun = clashConfig.tun.copyWith(
); enable: value,
}, );
},
),
); );
}, },
), ),
@@ -75,14 +77,16 @@ class ProxySwitch extends StatelessWidget {
child: Selector<Config, bool>( child: Selector<Config, bool>(
selector: (_, config) => config.desktopProps.systemProxy, selector: (_, config) => config.desktopProps.systemProxy,
builder: (_, systemProxy, __) { builder: (_, systemProxy, __) {
return Switch( return LocaleBuilder(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, builder: (_) => Switch(
value: systemProxy, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
onChanged: (value) { value: systemProxy,
final config = globalState.appController.config; onChanged: (value) {
config.desktopProps = final config = globalState.appController.config;
config.desktopProps.copyWith(systemProxy: value); config.desktopProps =
}, config.desktopProps.copyWith(systemProxy: value);
},
),
); );
}, },
), ),

250
lib/fragments/hotkey.dart Normal file
View File

@@ -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<Config, HotKeyAction>(
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<HotKeyRecorder> createState() => _HotKeyRecorderState();
}
class _HotKeyRecorderState extends State<HotKeyRecorder> {
late ValueNotifier<HotKeyAction> hotKeyActionNotifier;
@override
void initState() {
super.initState();
hotKeyActionNotifier = ValueNotifier<HotKeyAction>(
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: () {},
);
}
}

View File

@@ -497,17 +497,17 @@ class _ReorderableProfilesState extends State<ReorderableProfiles> {
), ),
Container( Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 8, vertical: 16,
horizontal: 24, horizontal: 24,
), ),
child: FilledButton( child: FilledButton.tonal(
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
globalState.appController.config.profiles = profiles; globalState.appController.config.profiles = profiles;
}, },
style: ButtonStyle( style: ButtonStyle(
padding: WidgetStateProperty.all( padding: WidgetStateProperty.all(
const EdgeInsets.symmetric(vertical: 16), const EdgeInsets.symmetric(vertical: 8),
), ),
), ),
child: Row( child: Row(

View File

@@ -25,6 +25,10 @@ class ProxyCard extends StatelessWidget {
Measure get measure => globalState.measure; Measure get measure => globalState.measure;
_handleTestCurrentDelay() {
proxyDelayTest(proxy);
}
Widget _buildDelayText() { Widget _buildDelayText() {
return SizedBox( return SizedBox(
height: measure.labelSmallHeight, height: measure.labelSmallHeight,
@@ -36,24 +40,31 @@ class ProxyCard extends StatelessWidget {
return FadeBox( return FadeBox(
child: Builder( child: Builder(
builder: (_) { builder: (_) {
if (delay == null) { if (delay == 0 || delay == null) {
return Container();
}
if (delay == 0) {
return SizedBox( return SizedBox(
height: measure.labelSmallHeight, height: measure.labelSmallHeight,
width: measure.labelSmallHeight, width: measure.labelSmallHeight,
child: const CircularProgressIndicator( child: delay == 0
strokeWidth: 2, ? const CircularProgressIndicator(
), strokeWidth: 2,
)
: IconButton(
icon: const Icon(Icons.bolt),
iconSize: globalState.measure.labelSmallHeight,
padding: EdgeInsets.zero,
onPressed: _handleTestCurrentDelay,
),
); );
} }
return Text( return GestureDetector(
delay > 0 ? '$delay ms' : "Timeout", onTap: _handleTestCurrentDelay,
style: context.textTheme.labelSmall?.copyWith( child: Text(
overflow: TextOverflow.ellipsis, delay > 0 ? '$delay ms' : "Timeout",
color: other.getDelayColor( style: context.textTheme.labelSmall?.copyWith(
delay, overflow: TextOverflow.ellipsis,
color: other.getDelayColor(
delay,
),
), ),
), ),
); );

View File

@@ -1,5 +1,3 @@
import 'dart:math';
import 'package:fl_clash/clash/clash.dart'; import 'package:fl_clash/clash/clash.dart';
import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.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<Proxy> proxies) async { delayTest(List<Proxy> proxies) async {
final appController = globalState.appController; final appController = globalState.appController;
final delayProxies = proxies.map<Future>((proxy) async { final proxyNames = proxies
final proxyName = appController.appState.getRealProxyName(proxy.name); .map((proxy) => appController.appState.getRealProxyName(proxy.name))
.toSet()
.toList();
final delayProxies = proxyNames.map<Future>((proxyName) async {
globalState.appController.setDelay( globalState.appController.setDelay(
Delay( Delay(
name: proxyName, name: proxyName,
@@ -76,5 +90,5 @@ double getScrollToSelectedOffset({
); );
final selectedIndex = findSelectedIndex != -1 ? findSelectedIndex : 0; final selectedIndex = findSelectedIndex != -1 ? findSelectedIndex : 0;
final rows = (selectedIndex / columns).floor(); final rows = (selectedIndex / columns).floor();
return max(rows * (getItemHeight(proxyCardType) + 8) - 8, 0); return rows * getItemHeight(proxyCardType) + (rows - 1) * 8;
} }

View File

@@ -1,11 +1,13 @@
import 'dart:math';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/models/models.dart'; import 'package:fl_clash/models/models.dart';
import 'package:fl_clash/state.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/card.dart';
import 'package:fl_clash/widgets/fade_box.dart';
import 'package:fl_clash/widgets/text.dart'; import 'package:fl_clash/widgets/text.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -219,11 +221,15 @@ class _ProxiesListFragmentState extends State<ProxiesListFragment> {
final currentInitOffset = _headerOffset[index]; final currentInitOffset = _headerOffset[index];
final proxies = _lastGroupNameProxiesMap[groupName]; final proxies = _lastGroupNameProxiesMap[groupName];
_controller.animateTo( _controller.animateTo(
currentInitOffset + min(
getScrollToSelectedOffset( currentInitOffset +
groupName: groupName, 8 +
proxies: proxies ?? [], getScrollToSelectedOffset(
), groupName: groupName,
proxies: proxies ?? [],
),
_controller.position.maxScrollExtent,
),
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
curve: Curves.easeIn, curve: Curves.easeIn,
); );
@@ -258,73 +264,75 @@ class _ProxiesListFragmentState extends State<ProxiesListFragment> {
return prev != next; return prev != next;
}, },
builder: (_, state, __) { builder: (_, state, __) {
final items = _buildItems( return ScaleBuilder(builder: (_) {
groupNames: state.groupNames, final items = _buildItems(
currentUnfoldSet: state.currentUnfoldSet, groupNames: state.groupNames,
columns: state.columns, currentUnfoldSet: state.currentUnfoldSet,
type: state.proxyCardType, columns: state.columns,
); type: state.proxyCardType,
final itemsOffset = _getItemHeightList(items, state.proxyCardType); );
return Scrollbar( final itemsOffset = _getItemHeightList(items, state.proxyCardType);
controller: _controller, return Scrollbar(
thumbVisibility: true, controller: _controller,
trackVisibility: true, thumbVisibility: true,
thickness: 8, trackVisibility: true,
radius: const Radius.circular(8), thickness: 8,
interactive: true, radius: const Radius.circular(8),
child: Stack( interactive: true,
children: [ child: Stack(
Positioned.fill( children: [
child: ScrollConfiguration( Positioned.fill(
behavior: HiddenBarScrollBehavior(), child: ScrollConfiguration(
child: ListView.builder( behavior: HiddenBarScrollBehavior(),
padding: const EdgeInsets.all(16), child: ListView.builder(
controller: _controller, padding: const EdgeInsets.all(16),
itemExtentBuilder: (index, __) { controller: _controller,
return itemsOffset[index]; itemExtentBuilder: (index, __) {
}, return itemsOffset[index];
itemCount: items.length, },
itemBuilder: (_, index) { itemCount: items.length,
return items[index]; itemBuilder: (_, index) {
}, return items[index];
},
),
), ),
), ),
), LayoutBuilder(builder: (_, container) {
LayoutBuilder(builder: (_, container) { return ValueListenableBuilder(
return ValueListenableBuilder( valueListenable: _headerStateNotifier,
valueListenable: _headerStateNotifier, builder: (_, headerState, ___) {
builder: (_, headerState, ___) { final index =
final index = headerState.currentIndex > state.groupNames.length - 1
headerState.currentIndex > state.groupNames.length - 1 ? 0
? 0 : headerState.currentIndex;
: headerState.currentIndex; return Stack(
return Stack( children: [
children: [ Positioned(
Positioned( top: -headerState.offset,
top: -headerState.offset, child: Container(
child: Container( width: container.maxWidth,
width: container.maxWidth, color: context.colorScheme.surface,
color: context.colorScheme.surface, padding: const EdgeInsets.only(
padding: const EdgeInsets.only( top: 16,
top: 16, left: 16,
left: 16, right: 16,
right: 16, bottom: 8,
bottom: 8, ),
), child: _buildHeader(
child: _buildHeader( groupName: state.groupNames[index],
groupName: state.groupNames[index], currentUnfoldSet: state.currentUnfoldSet,
currentUnfoldSet: state.currentUnfoldSet, ),
), ),
), ),
), ],
], );
); },
}, );
); }),
}), ],
], ),
), );
); });
}, },
); );
} }

View File

@@ -1,3 +1,5 @@
import 'dart:math';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/enum/enum.dart';
@@ -138,7 +140,7 @@ class ProxiesTabFragmentState extends State<ProxiesTabFragment>
GroupNameKeyMap keyMap = {}; GroupNameKeyMap keyMap = {};
final children = state.groupNames.map((groupName) { final children = state.groupNames.map((groupName) {
keyMap[groupName] = GlobalObjectKey(groupName); keyMap[groupName] = GlobalObjectKey(groupName);
return KeepContainer( return KeepScope(
child: ProxyGroupView( child: ProxyGroupView(
key: keyMap[groupName], key: keyMap[groupName],
groupName: groupName, groupName: groupName,
@@ -266,11 +268,14 @@ class ProxyGroupViewState extends State<ProxyGroupView> {
return; return;
} }
_controller.animateTo( _controller.animateTo(
16 + min(
getScrollToSelectedOffset( 16 +
groupName: groupName, getScrollToSelectedOffset(
proxies: _lastProxies, groupName: groupName,
), proxies: _lastProxies,
),
_controller.position.maxScrollExtent,
),
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
curve: Curves.easeIn, curve: Curves.easeIn,
); );
@@ -309,26 +314,33 @@ class ProxyGroupViewState extends State<ProxyGroupView> {
}, },
child: Align( child: Align(
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: GridView.builder( child: ScaleBuilder(
controller: _controller, builder: (_) => GridView.builder(
padding: const EdgeInsets.all(16), controller: _controller,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( padding: const EdgeInsets.only(
crossAxisCount: columns, top: 16,
mainAxisSpacing: 8, left: 16,
crossAxisSpacing: 8, right: 16,
mainAxisExtent: getItemHeight(proxyCardType), 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,
);
},
), ),
), ),
); );

View File

@@ -5,15 +5,17 @@ import 'package:fl_clash/fragments/about.dart';
import 'package:fl_clash/fragments/access.dart'; import 'package:fl_clash/fragments/access.dart';
import 'package:fl_clash/fragments/application_setting.dart'; import 'package:fl_clash/fragments/application_setting.dart';
import 'package:fl_clash/fragments/config/config.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/l10n/l10n.dart';
import 'package:fl_clash/models/models.dart'; import 'package:fl_clash/models/models.dart';
import 'package:fl_clash/state.dart'; import 'package:fl_clash/state.dart';
import 'package:fl_clash/widgets/widgets.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../widgets/widgets.dart';
import 'backup_and_recovery.dart'; import 'backup_and_recovery.dart';
import 'theme.dart'; import 'theme.dart';
import 'package:path/path.dart' show dirname, join;
class ToolsFragment extends StatefulWidget { class ToolsFragment extends StatefulWidget {
const ToolsFragment({super.key}); const ToolsFragment({super.key});
@@ -61,6 +63,17 @@ class _ToolboxFragmentState extends State<ToolsFragment> {
return generateSection( return generateSection(
title: appLocalizations.other, title: appLocalizations.other,
items: [ 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( ListItem.open(
leading: const Icon(Icons.info), leading: const Icon(Icons.info),
title: Text(appLocalizations.about), title: Text(appLocalizations.about),
@@ -88,10 +101,7 @@ class _ToolboxFragmentState extends State<ToolsFragment> {
subtitle: Text(Intl.message(subTitle)), subtitle: Text(Intl.message(subTitle)),
delegate: OptionsDelegate( delegate: OptionsDelegate(
title: appLocalizations.language, title: appLocalizations.language,
options: [ options: [null, ...AppLocalizations.delegate.supportedLocales],
null,
...AppLocalizations.delegate.supportedLocales
],
onChanged: (Locale? value) { onChanged: (Locale? value) {
final config = context.read<Config>(); final config = context.read<Config>();
config.locale = value?.toString(); config.locale = value?.toString();
@@ -121,6 +131,28 @@ class _ToolboxFragmentState extends State<ToolsFragment> {
widget: const BackupAndRecovery(), widget: const BackupAndRecovery(),
), ),
), ),
if (system.isDesktop)
ListItem.open(
leading: const Icon(Icons.keyboard),
title: Text(appLocalizations.hotkeyManagement),
subtitle: Text(appLocalizations.hotkeyManagementDesc),
delegate: OpenDelegate(
title: appLocalizations.hotkeyManagement,
widget: const HotKeyFragment(),
),
),
if (Platform.isWindows)
ListItem(
leading: const Icon(Icons.lock),
title: Text(appLocalizations.loopback),
subtitle: Text(appLocalizations.loopbackDesc),
onTap: () {
windows?.runas(
'"${join(dirname(Platform.resolvedExecutable), "EnableLoopback.exe")}"',
"",
);
},
),
if (Platform.isAndroid) if (Platform.isAndroid)
ListItem.open( ListItem.open(
leading: const Icon(Icons.view_list), leading: const Icon(Icons.view_list),
@@ -155,9 +187,8 @@ class _ToolboxFragmentState extends State<ToolsFragment> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Selector<Config, String?>( return LocaleBuilder(
selector: (_, config) => config.locale, builder: (_) {
builder: (_, __, ___) {
final items = [ final items = [
Selector<AppState, MoreToolsSelectorState>( Selector<AppState, MoreToolsSelectorState>(
selector: (_, appState) { selector: (_, appState) {
@@ -190,6 +221,7 @@ class _ToolboxFragmentState extends State<ToolsFragment> {
return ListView.builder( return ListView.builder(
itemCount: items.length, itemCount: items.length,
itemBuilder: (_, index) => items[index], itemBuilder: (_, index) => items[index],
padding: const EdgeInsets.only(bottom: 20),
); );
}, },
); );

View File

@@ -288,5 +288,20 @@
"ipcidr": "Ipcidr", "ipcidr": "Ipcidr",
"domain": "Domain", "domain": "Domain",
"resetDns": "Reset Dns", "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"
} }

View File

@@ -238,9 +238,9 @@
"clipboardImport": "剪贴板导入", "clipboardImport": "剪贴板导入",
"clipboardExport": "导出剪贴板", "clipboardExport": "导出剪贴板",
"layout": "布局", "layout": "布局",
"tight": "宽松", "tight": "紧凑",
"standard": "标准", "standard": "标准",
"loose": "紧凑", "loose": "宽松",
"profilesSort": "配置排序", "profilesSort": "配置排序",
"start": "启动", "start": "启动",
"stop": "暂停", "stop": "暂停",
@@ -288,5 +288,20 @@
"ipcidr": "IP/掩码", "ipcidr": "IP/掩码",
"domain": "域名", "domain": "域名",
"resetDns": "重置DNS", "resetDns": "重置DNS",
"reset": "重置" "reset": "重置",
"action_view": "显示/隐藏",
"action_start": "启动/停止",
"action_mode": "切换模式",
"action_proxy": "系统代理",
"action_tun": "虚拟网卡",
"disclaimer": "免责声明",
"disclaimerDesc": "本软件仅供学习交流、科研等非商业性质的用途,严禁将本软件用于商业目的。如有任何商业行为,均与本软件无关。",
"agree": "同意",
"hotkeyManagement": "快捷键管理",
"hotkeyManagementDesc": "使用键盘控制应用程序",
"pressKeyboard": "请按下按键",
"inputCorrectHotkey": "请输入正确的快捷键",
"hotkeyConflict": "快捷键冲突",
"remove": "移除",
"noHotKey": "暂无快捷键"
} }

View File

@@ -34,6 +34,11 @@ class MessageLookup extends MessageLookupByLibrary {
"accountTip": "accountTip":
MessageLookupByLibrary.simpleMessage("Account cannot be empty"), MessageLookupByLibrary.simpleMessage("Account cannot be empty"),
"action": MessageLookupByLibrary.simpleMessage("Action"), "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"), "add": MessageLookupByLibrary.simpleMessage("Add"),
"address": MessageLookupByLibrary.simpleMessage("Address"), "address": MessageLookupByLibrary.simpleMessage("Address"),
"addressHelp": "addressHelp":
@@ -41,6 +46,7 @@ class MessageLookup extends MessageLookupByLibrary {
"addressTip": MessageLookupByLibrary.simpleMessage( "addressTip": MessageLookupByLibrary.simpleMessage(
"Please enter a valid WebDAV address"), "Please enter a valid WebDAV address"),
"ago": MessageLookupByLibrary.simpleMessage(" Ago"), "ago": MessageLookupByLibrary.simpleMessage(" Ago"),
"agree": MessageLookupByLibrary.simpleMessage("Agree"),
"allApps": MessageLookupByLibrary.simpleMessage("All apps"), "allApps": MessageLookupByLibrary.simpleMessage("All apps"),
"allowBypass": MessageLookupByLibrary.simpleMessage( "allowBypass": MessageLookupByLibrary.simpleMessage(
"Allow applications to bypass VPN"), "Allow applications to bypass VPN"),
@@ -130,6 +136,9 @@ class MessageLookup extends MessageLookupByLibrary {
"desc": MessageLookupByLibrary.simpleMessage( "desc": MessageLookupByLibrary.simpleMessage(
"A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free."), "A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free."),
"direct": MessageLookupByLibrary.simpleMessage("Direct"), "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": "discoverNewVersion":
MessageLookupByLibrary.simpleMessage("Discover the new version"), MessageLookupByLibrary.simpleMessage("Discover the new version"),
"discovery": "discovery":
@@ -188,12 +197,20 @@ class MessageLookup extends MessageLookupByLibrary {
"go": MessageLookupByLibrary.simpleMessage("Go"), "go": MessageLookupByLibrary.simpleMessage("Go"),
"goDownload": MessageLookupByLibrary.simpleMessage("Go to download"), "goDownload": MessageLookupByLibrary.simpleMessage("Go to download"),
"hostsDesc": MessageLookupByLibrary.simpleMessage("Add Hosts"), "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"), "hours": MessageLookupByLibrary.simpleMessage("Hours"),
"importFromURL": "importFromURL":
MessageLookupByLibrary.simpleMessage("Import from URL"), MessageLookupByLibrary.simpleMessage("Import from URL"),
"infiniteTime": "infiniteTime":
MessageLookupByLibrary.simpleMessage("Long term effective"), MessageLookupByLibrary.simpleMessage("Long term effective"),
"init": MessageLookupByLibrary.simpleMessage("Init"), "init": MessageLookupByLibrary.simpleMessage("Init"),
"inputCorrectHotkey": MessageLookupByLibrary.simpleMessage(
"Please enter the correct hotkey"),
"intelligentSelected": "intelligentSelected":
MessageLookupByLibrary.simpleMessage("Intelligent selection"), MessageLookupByLibrary.simpleMessage("Intelligent selection"),
"intranetIP": MessageLookupByLibrary.simpleMessage("Intranet IP"), "intranetIP": MessageLookupByLibrary.simpleMessage("Intranet IP"),
@@ -247,6 +264,7 @@ class MessageLookup extends MessageLookupByLibrary {
"networkDetection": "networkDetection":
MessageLookupByLibrary.simpleMessage("Network detection"), MessageLookupByLibrary.simpleMessage("Network detection"),
"networkSpeed": MessageLookupByLibrary.simpleMessage("Network speed"), "networkSpeed": MessageLookupByLibrary.simpleMessage("Network speed"),
"noHotKey": MessageLookupByLibrary.simpleMessage("No HotKey"),
"noInfo": MessageLookupByLibrary.simpleMessage("No info"), "noInfo": MessageLookupByLibrary.simpleMessage("No info"),
"noMoreInfoDesc": MessageLookupByLibrary.simpleMessage("No more info"), "noMoreInfoDesc": MessageLookupByLibrary.simpleMessage("No more info"),
"noProxy": MessageLookupByLibrary.simpleMessage("No proxy"), "noProxy": MessageLookupByLibrary.simpleMessage("No proxy"),
@@ -293,6 +311,8 @@ class MessageLookup extends MessageLookupByLibrary {
"port": MessageLookupByLibrary.simpleMessage("Port"), "port": MessageLookupByLibrary.simpleMessage("Port"),
"preferH3Desc": MessageLookupByLibrary.simpleMessage( "preferH3Desc": MessageLookupByLibrary.simpleMessage(
"Prioritize the use of DOH\'s http/3"), "Prioritize the use of DOH\'s http/3"),
"pressKeyboard":
MessageLookupByLibrary.simpleMessage("Please press the keyboard."),
"preview": MessageLookupByLibrary.simpleMessage("Preview"), "preview": MessageLookupByLibrary.simpleMessage("Preview"),
"profile": MessageLookupByLibrary.simpleMessage("Profile"), "profile": MessageLookupByLibrary.simpleMessage("Profile"),
"profileAutoUpdateIntervalInvalidValidationDesc": "profileAutoUpdateIntervalInvalidValidationDesc":
@@ -343,6 +363,7 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("Backup local data to WebDAV"), MessageLookupByLibrary.simpleMessage("Backup local data to WebDAV"),
"remoteRecoveryDesc": "remoteRecoveryDesc":
MessageLookupByLibrary.simpleMessage("Recovery data from WebDAV"), MessageLookupByLibrary.simpleMessage("Recovery data from WebDAV"),
"remove": MessageLookupByLibrary.simpleMessage("Remove"),
"requests": MessageLookupByLibrary.simpleMessage("Requests"), "requests": MessageLookupByLibrary.simpleMessage("Requests"),
"requestsDesc": MessageLookupByLibrary.simpleMessage( "requestsDesc": MessageLookupByLibrary.simpleMessage(
"View recently request records"), "View recently request records"),

View File

@@ -32,11 +32,17 @@ class MessageLookup extends MessageLookupByLibrary {
"account": MessageLookupByLibrary.simpleMessage("账号"), "account": MessageLookupByLibrary.simpleMessage("账号"),
"accountTip": MessageLookupByLibrary.simpleMessage("账号不能为空"), "accountTip": MessageLookupByLibrary.simpleMessage("账号不能为空"),
"action": 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("添加"), "add": MessageLookupByLibrary.simpleMessage("添加"),
"address": MessageLookupByLibrary.simpleMessage("地址"), "address": MessageLookupByLibrary.simpleMessage("地址"),
"addressHelp": MessageLookupByLibrary.simpleMessage("WebDAV服务器地址"), "addressHelp": MessageLookupByLibrary.simpleMessage("WebDAV服务器地址"),
"addressTip": MessageLookupByLibrary.simpleMessage("请输入有效的WebDAV地址"), "addressTip": MessageLookupByLibrary.simpleMessage("请输入有效的WebDAV地址"),
"ago": MessageLookupByLibrary.simpleMessage(""), "ago": MessageLookupByLibrary.simpleMessage(""),
"agree": MessageLookupByLibrary.simpleMessage("同意"),
"allApps": MessageLookupByLibrary.simpleMessage("所有应用"), "allApps": MessageLookupByLibrary.simpleMessage("所有应用"),
"allowBypass": MessageLookupByLibrary.simpleMessage("允许应用绕过VPN"), "allowBypass": MessageLookupByLibrary.simpleMessage("允许应用绕过VPN"),
"allowBypassDesc": "allowBypassDesc":
@@ -107,6 +113,9 @@ class MessageLookup extends MessageLookupByLibrary {
"desc": MessageLookupByLibrary.simpleMessage( "desc": MessageLookupByLibrary.simpleMessage(
"基于ClashMeta的多平台代理客户端简单易用开源无广告。"), "基于ClashMeta的多平台代理客户端简单易用开源无广告。"),
"direct": MessageLookupByLibrary.simpleMessage("直连"), "direct": MessageLookupByLibrary.simpleMessage("直连"),
"disclaimer": MessageLookupByLibrary.simpleMessage("免责声明"),
"disclaimerDesc": MessageLookupByLibrary.simpleMessage(
"本软件仅供学习交流、科研等非商业性质的用途,严禁将本软件用于商业目的。如有任何商业行为,均与本软件无关。"),
"discoverNewVersion": MessageLookupByLibrary.simpleMessage("发现新版本"), "discoverNewVersion": MessageLookupByLibrary.simpleMessage("发现新版本"),
"discovery": MessageLookupByLibrary.simpleMessage("发现新版本"), "discovery": MessageLookupByLibrary.simpleMessage("发现新版本"),
"dnsDesc": MessageLookupByLibrary.simpleMessage("更新DNS相关设置"), "dnsDesc": MessageLookupByLibrary.simpleMessage("更新DNS相关设置"),
@@ -151,10 +160,15 @@ class MessageLookup extends MessageLookupByLibrary {
"go": MessageLookupByLibrary.simpleMessage("前往"), "go": MessageLookupByLibrary.simpleMessage("前往"),
"goDownload": MessageLookupByLibrary.simpleMessage("前往下载"), "goDownload": MessageLookupByLibrary.simpleMessage("前往下载"),
"hostsDesc": MessageLookupByLibrary.simpleMessage("追加Hosts"), "hostsDesc": MessageLookupByLibrary.simpleMessage("追加Hosts"),
"hotkeyConflict": MessageLookupByLibrary.simpleMessage("快捷键冲突"),
"hotkeyManagement": MessageLookupByLibrary.simpleMessage("快捷键管理"),
"hotkeyManagementDesc":
MessageLookupByLibrary.simpleMessage("使用键盘控制应用程序"),
"hours": MessageLookupByLibrary.simpleMessage("小时"), "hours": MessageLookupByLibrary.simpleMessage("小时"),
"importFromURL": MessageLookupByLibrary.simpleMessage("从URL导入"), "importFromURL": MessageLookupByLibrary.simpleMessage("从URL导入"),
"infiniteTime": MessageLookupByLibrary.simpleMessage("长期有效"), "infiniteTime": MessageLookupByLibrary.simpleMessage("长期有效"),
"init": MessageLookupByLibrary.simpleMessage("初始化"), "init": MessageLookupByLibrary.simpleMessage("初始化"),
"inputCorrectHotkey": MessageLookupByLibrary.simpleMessage("请输入正确的快捷键"),
"intelligentSelected": MessageLookupByLibrary.simpleMessage("智能选择"), "intelligentSelected": MessageLookupByLibrary.simpleMessage("智能选择"),
"intranetIP": MessageLookupByLibrary.simpleMessage("内网 IP"), "intranetIP": MessageLookupByLibrary.simpleMessage("内网 IP"),
"ipcidr": MessageLookupByLibrary.simpleMessage("IP/掩码"), "ipcidr": MessageLookupByLibrary.simpleMessage("IP/掩码"),
@@ -178,7 +192,7 @@ class MessageLookup extends MessageLookupByLibrary {
"logsDesc": MessageLookupByLibrary.simpleMessage("日志捕获记录"), "logsDesc": MessageLookupByLibrary.simpleMessage("日志捕获记录"),
"loopback": MessageLookupByLibrary.simpleMessage("回环解锁工具"), "loopback": MessageLookupByLibrary.simpleMessage("回环解锁工具"),
"loopbackDesc": MessageLookupByLibrary.simpleMessage("用于UWP回环解锁"), "loopbackDesc": MessageLookupByLibrary.simpleMessage("用于UWP回环解锁"),
"loose": MessageLookupByLibrary.simpleMessage("紧凑"), "loose": MessageLookupByLibrary.simpleMessage("宽松"),
"min": MessageLookupByLibrary.simpleMessage("最小"), "min": MessageLookupByLibrary.simpleMessage("最小"),
"minimizeOnExit": MessageLookupByLibrary.simpleMessage("退出时最小化"), "minimizeOnExit": MessageLookupByLibrary.simpleMessage("退出时最小化"),
"minimizeOnExitDesc": "minimizeOnExitDesc":
@@ -196,6 +210,7 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("指定对应域名服务器策略"), MessageLookupByLibrary.simpleMessage("指定对应域名服务器策略"),
"networkDetection": MessageLookupByLibrary.simpleMessage("网络检测"), "networkDetection": MessageLookupByLibrary.simpleMessage("网络检测"),
"networkSpeed": MessageLookupByLibrary.simpleMessage("网络速度"), "networkSpeed": MessageLookupByLibrary.simpleMessage("网络速度"),
"noHotKey": MessageLookupByLibrary.simpleMessage("暂无快捷键"),
"noInfo": MessageLookupByLibrary.simpleMessage("暂无信息"), "noInfo": MessageLookupByLibrary.simpleMessage("暂无信息"),
"noMoreInfoDesc": MessageLookupByLibrary.simpleMessage("暂无更多信息"), "noMoreInfoDesc": MessageLookupByLibrary.simpleMessage("暂无更多信息"),
"noProxy": MessageLookupByLibrary.simpleMessage("暂无代理"), "noProxy": MessageLookupByLibrary.simpleMessage("暂无代理"),
@@ -231,6 +246,7 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("请上传有效的二维码"), MessageLookupByLibrary.simpleMessage("请上传有效的二维码"),
"port": MessageLookupByLibrary.simpleMessage("端口"), "port": MessageLookupByLibrary.simpleMessage("端口"),
"preferH3Desc": MessageLookupByLibrary.simpleMessage("优先使用DOH的http/3"), "preferH3Desc": MessageLookupByLibrary.simpleMessage("优先使用DOH的http/3"),
"pressKeyboard": MessageLookupByLibrary.simpleMessage("请按下按键"),
"preview": MessageLookupByLibrary.simpleMessage("预览"), "preview": MessageLookupByLibrary.simpleMessage("预览"),
"profile": MessageLookupByLibrary.simpleMessage("配置"), "profile": MessageLookupByLibrary.simpleMessage("配置"),
"profileAutoUpdateIntervalInvalidValidationDesc": "profileAutoUpdateIntervalInvalidValidationDesc":
@@ -269,6 +285,7 @@ class MessageLookup extends MessageLookupByLibrary {
"remoteBackupDesc": MessageLookupByLibrary.simpleMessage("备份数据到WebDAV"), "remoteBackupDesc": MessageLookupByLibrary.simpleMessage("备份数据到WebDAV"),
"remoteRecoveryDesc": "remoteRecoveryDesc":
MessageLookupByLibrary.simpleMessage("通过WebDAV恢复数据"), MessageLookupByLibrary.simpleMessage("通过WebDAV恢复数据"),
"remove": MessageLookupByLibrary.simpleMessage("移除"),
"requests": MessageLookupByLibrary.simpleMessage("请求"), "requests": MessageLookupByLibrary.simpleMessage("请求"),
"requestsDesc": MessageLookupByLibrary.simpleMessage("查看最近请求记录"), "requestsDesc": MessageLookupByLibrary.simpleMessage("查看最近请求记录"),
"reset": MessageLookupByLibrary.simpleMessage("重置"), "reset": MessageLookupByLibrary.simpleMessage("重置"),
@@ -318,7 +335,7 @@ class MessageLookup extends MessageLookupByLibrary {
"themeDesc": MessageLookupByLibrary.simpleMessage("设置深色模式,调整色彩"), "themeDesc": MessageLookupByLibrary.simpleMessage("设置深色模式,调整色彩"),
"themeMode": MessageLookupByLibrary.simpleMessage("主题模式"), "themeMode": MessageLookupByLibrary.simpleMessage("主题模式"),
"threeColumns": MessageLookupByLibrary.simpleMessage("三列"), "threeColumns": MessageLookupByLibrary.simpleMessage("三列"),
"tight": MessageLookupByLibrary.simpleMessage("宽松"), "tight": MessageLookupByLibrary.simpleMessage("紧凑"),
"time": MessageLookupByLibrary.simpleMessage("时间"), "time": MessageLookupByLibrary.simpleMessage("时间"),
"tip": MessageLookupByLibrary.simpleMessage("提示"), "tip": MessageLookupByLibrary.simpleMessage("提示"),
"tools": MessageLookupByLibrary.simpleMessage("工具"), "tools": MessageLookupByLibrary.simpleMessage("工具"),

View File

@@ -2949,6 +2949,156 @@ class AppLocalizations {
args: [], 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<AppLocalizations> { class AppLocalizationDelegate extends LocalizationsDelegate<AppLocalizations> {

View File

@@ -18,13 +18,15 @@ Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
clashCore.initMessage(); clashCore.initMessage();
globalState.packageInfo = await PackageInfo.fromPlatform(); globalState.packageInfo = await PackageInfo.fromPlatform();
final version = await system.version;
final config = await preferences.getConfig() ?? Config(); final config = await preferences.getConfig() ?? Config();
globalState.autoRun = config.autoRun; globalState.autoRun = config.autoRun;
final clashConfig = await preferences.getClashConfig() ?? ClashConfig(); final clashConfig = await preferences.getClashConfig() ?? ClashConfig();
await android?.init(); await android?.init();
await window?.init(config.windowProps); await window?.init(config.windowProps, version);
final appState = AppState( final appState = AppState(
mode: clashConfig.mode, mode: clashConfig.mode,
version: version,
isCompatible: config.isCompatible, isCompatible: config.isCompatible,
selectedMap: config.currentSelectedMap, selectedMap: config.currentSelectedMap,
); );
@@ -32,11 +34,6 @@ Future<void> main() async {
openLogs: config.openLogs, openLogs: config.openLogs,
hasProxies: false, hasProxies: false,
); );
globalState.updateTray(
appState: appState,
config: config,
clashConfig: clashConfig,
);
await globalState.init( await globalState.init(
appState: appState, appState: appState,
config: config, config: config,
@@ -56,12 +53,14 @@ Future<void> vpnService() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
globalState.isVpnService = true; globalState.isVpnService = true;
globalState.packageInfo = await PackageInfo.fromPlatform(); globalState.packageInfo = await PackageInfo.fromPlatform();
final version = await system.version;
final config = await preferences.getConfig() ?? Config(); final config = await preferences.getConfig() ?? Config();
final clashConfig = await preferences.getClashConfig() ?? ClashConfig(); final clashConfig = await preferences.getClashConfig() ?? ClashConfig();
final appState = AppState( final appState = AppState(
mode: clashConfig.mode, mode: clashConfig.mode,
isCompatible: config.isCompatible, isCompatible: config.isCompatible,
selectedMap: config.currentSelectedMap, selectedMap: config.currentSelectedMap,
version: version,
); );
await globalState.init( await globalState.init(
appState: appState, appState: appState,
@@ -76,7 +75,7 @@ Future<void> vpnService() async {
clashCore.setFdMap(fd.id); clashCore.setFdMap(fd.id);
}, },
onProcess: (Process process) async { onProcess: (Process process) async {
final packageName = await app?.resolverProcess(process); final packageName = await vpn?.resolverProcess(process);
clashCore.setProcessMap( clashCore.setProcessMap(
ProcessMapItem( ProcessMapItem(
id: process.id, id: process.id,

View File

@@ -5,20 +5,25 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class AndroidContainer extends StatefulWidget { class AndroidManager extends StatefulWidget {
final Widget child; final Widget child;
const AndroidContainer({ const AndroidManager({
super.key, super.key,
required this.child, required this.child,
}); });
@override @override
State<AndroidContainer> createState() => _AndroidContainerState(); State<AndroidManager> createState() => _AndroidContainerState();
} }
class _AndroidContainerState extends State<AndroidContainer> class _AndroidContainerState extends State<AndroidManager> {
with WidgetsBindingObserver { @override
void initState() {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
super.initState();
}
Widget _excludeContainer(Widget child) { Widget _excludeContainer(Widget child) {
return Selector<Config, bool>( return Selector<Config, bool>(
selector: (_, config) => config.isExclude, selector: (_, config) => config.isExclude,
@@ -44,31 +49,10 @@ class _AndroidContainerState extends State<AndroidContainer>
); );
} }
@override
void initState() {
super.initState();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
WidgetsBinding.instance.addObserver(this);
}
@override
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
final isPaused = state == AppLifecycleState.paused;
if (isPaused) {
await globalState.appController.savePreferences();
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return _systemUiOverlayContainer( return _systemUiOverlayContainer(
_excludeContainer(widget.child), _excludeContainer(widget.child),
); );
} }
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
} }

View File

@@ -4,14 +4,20 @@ import 'package:fl_clash/state.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class AppStateContainer extends StatelessWidget { class AppStateManager extends StatefulWidget {
final Widget child; final Widget child;
const AppStateContainer({ const AppStateManager({
super.key, super.key,
required this.child, required this.child,
}); });
@override
State<AppStateManager> createState() => _AppStateManagerState();
}
class _AppStateManagerState extends State<AppStateManager>
with WidgetsBindingObserver {
_updateNavigationsContainer(Widget child) { _updateNavigationsContainer(Widget child) {
return Selector2<AppState, Config, UpdateNavigationsSelector>( return Selector2<AppState, Config, UpdateNavigationsSelector>(
selector: (_, appState, config) { 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<void> 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return _updateNavigationsContainer( return _updateNavigationsContainer(
child, widget.child,
); );
} }
} }

View File

@@ -5,27 +5,27 @@ import 'package:fl_clash/state.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.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; final Widget child;
const ClashContainer({ const ClashManager({
super.key, super.key,
required this.child, required this.child,
}); });
@override @override
State<ClashContainer> createState() => _ClashContainerState(); State<ClashManager> createState() => _ClashContainerState();
} }
class _ClashContainerState extends State<ClashContainer> class _ClashContainerState extends State<ClashManager>
with AppMessageListener { with AppMessageListener {
Function? updateClashConfigDebounce; Function? updateClashConfigDebounce;
Widget _updateContainer(Widget child) { Widget _updateContainer(Widget child) {
return Selector2<Config,ClashConfig, ClashConfigState>( return Selector2<Config, ClashConfig, ClashConfigState>(
selector: (_,config, clashConfig) => ClashConfigState( selector: (_, config, clashConfig) => ClashConfigState(
overrideDns: config.overrideDns, overrideDns: config.overrideDns,
mixedPort: clashConfig.mixedPort, mixedPort: clashConfig.mixedPort,
allowLan: clashConfig.allowLan, allowLan: clashConfig.allowLan,
@@ -45,14 +45,16 @@ class _ClashContainerState extends State<ClashContainer>
rules: clashConfig.rules, rules: clashConfig.rules,
globalRealUa: clashConfig.globalRealUa, globalRealUa: clashConfig.globalRealUa,
), ),
builder: (__, state, child) { shouldRebuild: (prev, next) {
if (updateClashConfigDebounce == null) { if (prev != next) {
updateClashConfigDebounce = debounce<Function()>(() async { updateClashConfigDebounce ??= debounce<Function()>(() async {
await globalState.appController.updateClashConfig(); await globalState.appController.updateClashConfig();
}); });
} else {
updateClashConfigDebounce!(); updateClashConfigDebounce!();
} }
return prev != next;
},
builder: (__, state, child) {
return child!; return child!;
}, },
child: child, child: child,
@@ -139,7 +141,7 @@ class _ClashContainerState extends State<ClashContainer>
if (log.logLevel == LogLevel.error) { if (log.logLevel == LogLevel.error) {
globalState.appController.showSnackBar(log.payload ?? ''); globalState.appController.showSnackBar(log.payload ?? '');
} }
// debugPrint("$log"); debugPrint("$log");
super.onLog(log); super.onLog(log);
} }

View File

@@ -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<HotKeyAction> hotKeyActions,
}) async {
await hotKeyManager.unregisterAll();
final hotkeyActionHandles = hotKeyActions.where(
(hotKeyAction) {
return hotKeyAction.key != null && hotKeyAction.modifiers.isNotEmpty;
},
).map<Future>(
(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<Config, List<HotKeyAction>>(
selector: (_, config) => config.hotKeyActions,
shouldRebuild: (prev, next) {
return !hotKeyActionsEquality.equals(prev, next);
},
builder: (_, hotKeyActions, __) {
_updateHotKeys(hotKeyActions: hotKeyActions);
return child;
},
child: child,
);
}
}

9
lib/manager/manager.dart Normal file
View File

@@ -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';

View File

@@ -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<Config, ScaleProps>(
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,
);
}
}

View File

@@ -3,10 +3,10 @@ import 'package:fl_clash/models/models.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class ProxyContainer extends StatelessWidget { class ProxyManager extends StatelessWidget {
final Widget child; final Widget child;
const ProxyContainer({super.key, required this.child}); const ProxyManager({super.key, required this.child});
_updateProxy(ProxyState proxyState) { _updateProxy(ProxyState proxyState) {
final isStart = proxyState.isStart; final isStart = proxyState.isStart;

View File

@@ -2,19 +2,19 @@ import 'package:fl_clash/plugins/tile.dart';
import 'package:fl_clash/state.dart'; import 'package:fl_clash/state.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class TileContainer extends StatefulWidget { class TileManager extends StatefulWidget {
final Widget child; final Widget child;
const TileContainer({ const TileManager({
super.key, super.key,
required this.child, required this.child,
}); });
@override @override
State<TileContainer> createState() => _TileContainerState(); State<TileManager> createState() => _TileContainerState();
} }
class _TileContainerState extends State<TileContainer> with TileListener { class _TileContainerState extends State<TileManager> with TileListener {
@override @override

177
lib/manager/tray_manager.dart Executable file
View File

@@ -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<TrayManager> createState() => _TrayContainerState();
}
class _TrayContainerState extends State<TrayManager> 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<MenuItem> 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<AppState, Config, ClashConfig, TrayState>(
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();
}
}

View File

@@ -4,21 +4,21 @@ import 'package:fl_clash/state.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.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; final Widget child;
const VpnContainer({ const VpnManager({
super.key, super.key,
required this.child, required this.child,
}); });
@override @override
State<VpnContainer> createState() => _VpnContainerState(); State<VpnManager> createState() => _VpnContainerState();
} }
class _VpnContainerState extends State<VpnContainer> { class _VpnContainerState extends State<VpnManager> {
Function? vpnTipDebounce; Function? vpnTipDebounce;
showTip() { showTip() {

View File

@@ -7,19 +7,19 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:window_manager/window_manager.dart'; import 'package:window_manager/window_manager.dart';
class WindowContainer extends StatefulWidget { class WindowManager extends StatefulWidget {
final Widget child; final Widget child;
const WindowContainer({ const WindowManager({
super.key, super.key,
required this.child, required this.child,
}); });
@override @override
State<WindowContainer> createState() => _WindowContainerState(); State<WindowManager> createState() => _WindowContainerState();
} }
class _WindowContainerState extends State<WindowContainer> with WindowListener { class _WindowContainerState extends State<WindowManager> with WindowListener {
Function? updateLaunchDebounce; Function? updateLaunchDebounce;
_autoLaunchContainer(Widget child) { _autoLaunchContainer(Widget child) {
@@ -99,21 +99,30 @@ class WindowHeaderContainer extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack( return Selector<AppState, int>(
children: [ selector: (_, appState) => appState.version,
Column( builder: (_, version, child) {
if (version <= 10 && Platform.isMacOS) {
return child!;
}
return Stack(
children: [ children: [
SizedBox( Column(
height: kHeaderHeight, children: [
), SizedBox(
Expanded( height: kHeaderHeight,
flex: 1, ),
child: child, Expanded(
flex: 1,
child: child!,
),
],
), ),
const WindowHeader(),
], ],
), );
const WindowHeader(), },
], child: child,
); );
} }
} }
@@ -240,14 +249,20 @@ class _WindowHeaderState extends State<WindowHeader> {
), ),
), ),
), ),
const Positioned( if (Platform.isMacOS)
left: 0, const Text(
child: AppIcon(), appName,
), )
Positioned( else ...[
right: 0, const Positioned(
child: _buildActions(), left: 0,
), child: AppIcon(),
),
Positioned(
right: 0,
child: _buildActions(),
),
]
], ],
), ),
); );

View File

@@ -4,16 +4,9 @@ import 'package:collection/collection.dart';
import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart'; import 'package:fl_clash/enum/enum.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'connection.dart'; import 'common.dart';
import 'ffi.dart'; import 'ffi.dart';
import 'log.dart';
import 'navigation.dart';
import 'package.dart';
import 'profile.dart'; import 'profile.dart';
import 'proxy.dart';
import 'system_color_scheme.dart';
import 'traffic.dart';
import 'version.dart';
typedef DelayMap = Map<String, int?>; typedef DelayMap = Map<String, int?>;
@@ -38,11 +31,14 @@ class AppState with ChangeNotifier {
num _checkIpNum; num _checkIpNum;
List<ExternalProvider> _providers; List<ExternalProvider> _providers;
List<Package> _packages; List<Package> _packages;
Brightness? _brightness;
int _version;
AppState({ AppState({
required Mode mode, required Mode mode,
required bool isCompatible, required bool isCompatible,
required SelectedMap selectedMap, required SelectedMap selectedMap,
required int version,
}) : _navigationItems = [], }) : _navigationItems = [],
_isInit = false, _isInit = false,
_currentLabel = "dashboard", _currentLabel = "dashboard",
@@ -54,13 +50,15 @@ class AppState with ChangeNotifier {
_checkIpNum = 0, _checkIpNum = 0,
_requests = [], _requests = [],
_mode = mode, _mode = mode,
_brightness = null,
_totalTraffic = Traffic(), _totalTraffic = Traffic(),
_delayMap = {}, _delayMap = {},
_groups = [], _groups = [],
_providers = [], _providers = [],
_packages = [], _packages = [],
_isCompatible = isCompatible, _isCompatible = isCompatible,
_systemColorSchemes = const SystemColorSchemes(); _systemColorSchemes = const SystemColorSchemes(),
_version = version;
String get currentLabel => _currentLabel; String get currentLabel => _currentLabel;
@@ -354,7 +352,7 @@ class AppState with ChangeNotifier {
} }
setProvider(ExternalProvider? provider) { setProvider(ExternalProvider? provider) {
if(provider == null) return; if (provider == null) return;
final index = _providers.indexWhere((item) => item.name == provider.name); final index = _providers.indexWhere((item) => item.name == provider.name);
if (index == -1) return; if (index == -1) return;
_providers = List.from(_providers)..[index] = provider; _providers = List.from(_providers)..[index] = provider;
@@ -366,4 +364,22 @@ class AppState with ChangeNotifier {
currentGroups.indexWhere((element) => element.name == groupName); currentGroups.indexWhere((element) => element.name == groupName);
return index != -1 ? currentGroups[index] : null; 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();
}
}
} }

438
lib/models/common.dart Normal file
View File

@@ -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<NavigationItemMode> 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<String, Object?> 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<String, Object?> 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<String> chains,
}) = _Connection;
factory Connection.fromJson(Map<String, Object?> 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<String, dynamic> json) {
return _$LogFromJson(json);
}
Map<String, dynamic> 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<Log> logs,
@Default([]) List<String> keywords,
}) = _LogsAndKeywords;
factory LogsAndKeywords.fromJson(Map<String, Object?> json) =>
_$LogsAndKeywordsFromJson(json);
}
extension LogsAndKeywordsExt on LogsAndKeywords {
List<Log> get filteredLogs => logs
.where(
(log) => {log.logLevel.name}.containsAll(keywords),
)
.toList();
}
@freezed
class ConnectionsAndKeywords with _$ConnectionsAndKeywords {
const factory ConnectionsAndKeywords({
@Default([]) List<Connection> connections,
@Default([]) List<String> keywords,
}) = _ConnectionsAndKeywords;
factory ConnectionsAndKeywords.fromJson(Map<String, Object?> json) =>
_$ConnectionsAndKeywordsFromJson(json);
}
extension ConnectionsAndKeywordsExt on ConnectionsAndKeywords {
List<Connection> 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<String, Object?> 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<String, Object?> 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<String, dynamic> 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<String, Proxy>;
@freezed
class Group with _$Group {
const factory Group({
required GroupType type,
@Default([]) List<Proxy> all,
String? now,
bool? hidden,
@Default("") String icon,
required String name,
}) = _Group;
factory Group.fromJson(Map<String, Object?> 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<String, Object?> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<KeyboardModifier> modifiers,
}) = _HotKeyAction;
factory HotKeyAction.fromJson(Map<String, Object?> json) =>
_$HotKeyActionFromJson(json);
}
const keyboardModifiersEquality = SetEquality<KeyboardModifier>();
const hotKeyActionsEquality = ListEquality<HotKeyAction>();

View File

@@ -143,6 +143,8 @@ class Config extends ChangeNotifier {
DesktopProps _desktopProps; DesktopProps _desktopProps;
bool _showLabel; bool _showLabel;
bool _overrideDns; bool _overrideDns;
List<HotKeyAction> _hotKeyActions;
bool _isDisclaimerAccepted;
Config() Config()
: _profiles = [], : _profiles = [],
@@ -172,7 +174,9 @@ class Config extends ChangeNotifier {
_desktopProps = const DesktopProps(), _desktopProps = const DesktopProps(),
_showLabel = false, _showLabel = false,
_overrideDns = false, _overrideDns = false,
_scaleProps = const ScaleProps(); _scaleProps = const ScaleProps(),
_isDisclaimerAccepted = false,
_hotKeyActions = [];
deleteProfileById(String id) { deleteProfileById(String id) {
_profiles = profiles.where((element) => element.id != id).toList(); _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<HotKeyAction> get hotKeyActions => _hotKeyActions;
set hotKeyActions(List<HotKeyAction> 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([ update([
Config? config, Config? config,
RecoveryOption recoveryOptions = RecoveryOption.all, RecoveryOption recoveryOptions = RecoveryOption.all,
@@ -636,6 +671,7 @@ class Config extends ChangeNotifier {
_vpnProps = config._vpnProps; _vpnProps = config._vpnProps;
_overrideDns = config._overrideDns; _overrideDns = config._overrideDns;
_desktopProps = config._desktopProps; _desktopProps = config._desktopProps;
_hotKeyActions = config._hotKeyActions;
} }
notifyListeners(); notifyListeners();
} }

View File

@@ -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<String, Object?> 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<String> chains,
}) = _Connection;
factory Connection.fromJson(Map<String, Object?> json) =>
_$ConnectionFromJson(json);
}
@freezed
class ConnectionsAndKeywords with _$ConnectionsAndKeywords {
const factory ConnectionsAndKeywords({
@Default([]) List<Connection> connections,
@Default([]) List<String> keywords,
}) = _ConnectionsAndKeywords;
factory ConnectionsAndKeywords.fromJson(Map<String, Object?> json) =>
_$ConnectionsAndKeywordsFromJson(json);
}
extension ConnectionsAndKeywordsExt on ConnectionsAndKeywords {
List<Connection> get filteredConnections => connections
.where((connection) => {
...connection.chains,
connection.metadata.process,
}.containsAll(keywords))
.toList();
}

View File

@@ -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<String, Object?> json) => _$DAVFromJson(json);
}

View File

@@ -135,6 +135,22 @@ class ExternalProvider with _$ExternalProvider {
_$ExternalProviderFromJson(json); _$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<String, Object?> json) =>
_$TunPropsFromJson(json);
}
abstract mixin class AppMessageListener { abstract mixin class AppMessageListener {
void onLog(Log log) {} void onLog(Log log) {}

View File

@@ -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}";
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,232 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of '../common.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Log _$LogFromJson(Map<String, dynamic> json) => Log(
logLevel: $enumDecode(_$LogLevelEnumMap, json['LogLevel']),
payload: json['Payload'] as String?,
);
Map<String, dynamic> _$LogToJson(Log instance) => <String, dynamic>{
'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<String, dynamic> json) =>
_$PackageImpl(
packageName: json['packageName'] as String,
label: json['label'] as String,
isSystem: json['isSystem'] as bool,
firstInstallTime: (json['firstInstallTime'] as num).toInt(),
);
Map<String, dynamic> _$$PackageImplToJson(_$PackageImpl instance) =>
<String, dynamic>{
'packageName': instance.packageName,
'label': instance.label,
'isSystem': instance.isSystem,
'firstInstallTime': instance.firstInstallTime,
};
_$MetadataImpl _$$MetadataImplFromJson(Map<String, dynamic> 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<String, dynamic> _$$MetadataImplToJson(_$MetadataImpl instance) =>
<String, dynamic>{
'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<String, dynamic> 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<String, dynamic>),
chains:
(json['chains'] as List<dynamic>).map((e) => e as String).toList(),
);
Map<String, dynamic> _$$ConnectionImplToJson(_$ConnectionImpl instance) =>
<String, dynamic>{
'id': instance.id,
'upload': instance.upload,
'download': instance.download,
'start': instance.start.toIso8601String(),
'metadata': instance.metadata,
'chains': instance.chains,
};
_$LogsAndKeywordsImpl _$$LogsAndKeywordsImplFromJson(
Map<String, dynamic> json) =>
_$LogsAndKeywordsImpl(
logs: (json['logs'] as List<dynamic>?)
?.map((e) => Log.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
keywords: (json['keywords'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
const [],
);
Map<String, dynamic> _$$LogsAndKeywordsImplToJson(
_$LogsAndKeywordsImpl instance) =>
<String, dynamic>{
'logs': instance.logs,
'keywords': instance.keywords,
};
_$ConnectionsAndKeywordsImpl _$$ConnectionsAndKeywordsImplFromJson(
Map<String, dynamic> json) =>
_$ConnectionsAndKeywordsImpl(
connections: (json['connections'] as List<dynamic>?)
?.map((e) => Connection.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
keywords: (json['keywords'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
const [],
);
Map<String, dynamic> _$$ConnectionsAndKeywordsImplToJson(
_$ConnectionsAndKeywordsImpl instance) =>
<String, dynamic>{
'connections': instance.connections,
'keywords': instance.keywords,
};
_$DAVImpl _$$DAVImplFromJson(Map<String, dynamic> json) => _$DAVImpl(
uri: json['uri'] as String,
user: json['user'] as String,
password: json['password'] as String,
fileName: json['fileName'] as String? ?? defaultDavFileName,
);
Map<String, dynamic> _$$DAVImplToJson(_$DAVImpl instance) => <String, dynamic>{
'uri': instance.uri,
'user': instance.user,
'password': instance.password,
'fileName': instance.fileName,
};
_$VersionInfoImpl _$$VersionInfoImplFromJson(Map<String, dynamic> json) =>
_$VersionInfoImpl(
clashName: json['clashName'] as String? ?? "",
version: json['version'] as String? ?? "",
);
Map<String, dynamic> _$$VersionInfoImplToJson(_$VersionInfoImpl instance) =>
<String, dynamic>{
'clashName': instance.clashName,
'version': instance.version,
};
_$GroupImpl _$$GroupImplFromJson(Map<String, dynamic> json) => _$GroupImpl(
type: $enumDecode(_$GroupTypeEnumMap, json['type']),
all: (json['all'] as List<dynamic>?)
?.map((e) => Proxy.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
now: json['now'] as String?,
hidden: json['hidden'] as bool?,
icon: json['icon'] as String? ?? "",
name: json['name'] as String,
);
Map<String, dynamic> _$$GroupImplToJson(_$GroupImpl instance) =>
<String, dynamic>{
'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<String, dynamic> json) => _$ProxyImpl(
name: json['name'] as String,
type: json['type'] as String,
now: json['now'] as String?,
);
Map<String, dynamic> _$$ProxyImplToJson(_$ProxyImpl instance) =>
<String, dynamic>{
'name': instance.name,
'type': instance.type,
'now': instance.now,
};
_$HotKeyActionImpl _$$HotKeyActionImplFromJson(Map<String, dynamic> json) =>
_$HotKeyActionImpl(
action: $enumDecode(_$HotActionEnumMap, json['action']),
key: (json['key'] as num?)?.toInt(),
modifiers: (json['modifiers'] as List<dynamic>?)
?.map((e) => $enumDecode(_$KeyboardModifierEnumMap, e))
.toSet() ??
const {},
);
Map<String, dynamic> _$$HotKeyActionImplToJson(_$HotKeyActionImpl instance) =>
<String, dynamic>{
'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',
};

View File

@@ -56,7 +56,12 @@ Config _$ConfigFromJson(Map<String, dynamic> json) => Config()
..scaleProps = ..scaleProps =
ScaleProps.fromJson(json['scaleProps'] as Map<String, dynamic>?) ScaleProps.fromJson(json['scaleProps'] as Map<String, dynamic>?)
..showLabel = json['showLabel'] as bool? ?? false ..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<dynamic>?)
?.map((e) => HotKeyAction.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
Map<String, dynamic> _$ConfigToJson(Config instance) => <String, dynamic>{ Map<String, dynamic> _$ConfigToJson(Config instance) => <String, dynamic>{
'profiles': instance.profiles, 'profiles': instance.profiles,
@@ -90,6 +95,8 @@ Map<String, dynamic> _$ConfigToJson(Config instance) => <String, dynamic>{
'scaleProps': instance.scaleProps, 'scaleProps': instance.scaleProps,
'showLabel': instance.showLabel, 'showLabel': instance.showLabel,
'overrideDns': instance.overrideDns, 'overrideDns': instance.overrideDns,
'isDisclaimerAccepted': instance.isDisclaimerAccepted,
'hotKeyActions': instance.hotKeyActions,
}; };
const _$ThemeModeEnumMap = { const _$ThemeModeEnumMap = {

View File

@@ -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>(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<String, dynamic> 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<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$MetadataCopyWith<Metadata> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<String> get chains => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ConnectionCopyWith<Connection> 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<String> 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<String>,
) 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<String> 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<String>,
));
}
}
/// @nodoc
@JsonSerializable()
class _$ConnectionImpl implements _Connection {
const _$ConnectionImpl(
{required this.id,
this.upload,
this.download,
required this.start,
required this.metadata,
required final List<String> chains})
: _chains = chains;
factory _$ConnectionImpl.fromJson(Map<String, dynamic> 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<String> _chains;
@override
List<String> 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<String, dynamic> 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<String> chains}) = _$ConnectionImpl;
factory _Connection.fromJson(Map<String, dynamic> 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<String> get chains;
@override
@JsonKey(ignore: true)
_$$ConnectionImplCopyWith<_$ConnectionImpl> get copyWith =>
throw _privateConstructorUsedError;
}
ConnectionsAndKeywords _$ConnectionsAndKeywordsFromJson(
Map<String, dynamic> json) {
return _ConnectionsAndKeywords.fromJson(json);
}
/// @nodoc
mixin _$ConnectionsAndKeywords {
List<Connection> get connections => throw _privateConstructorUsedError;
List<String> get keywords => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ConnectionsAndKeywordsCopyWith<ConnectionsAndKeywords> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ConnectionsAndKeywordsCopyWith<$Res> {
factory $ConnectionsAndKeywordsCopyWith(ConnectionsAndKeywords value,
$Res Function(ConnectionsAndKeywords) then) =
_$ConnectionsAndKeywordsCopyWithImpl<$Res, ConnectionsAndKeywords>;
@useResult
$Res call({List<Connection> connections, List<String> 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<Connection>,
keywords: null == keywords
? _value.keywords
: keywords // ignore: cast_nullable_to_non_nullable
as List<String>,
) 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<Connection> connections, List<String> 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<Connection>,
keywords: null == keywords
? _value._keywords
: keywords // ignore: cast_nullable_to_non_nullable
as List<String>,
));
}
}
/// @nodoc
@JsonSerializable()
class _$ConnectionsAndKeywordsImpl implements _ConnectionsAndKeywords {
const _$ConnectionsAndKeywordsImpl(
{final List<Connection> connections = const [],
final List<String> keywords = const []})
: _connections = connections,
_keywords = keywords;
factory _$ConnectionsAndKeywordsImpl.fromJson(Map<String, dynamic> json) =>
_$$ConnectionsAndKeywordsImplFromJson(json);
final List<Connection> _connections;
@override
@JsonKey()
List<Connection> get connections {
if (_connections is EqualUnmodifiableListView) return _connections;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_connections);
}
final List<String> _keywords;
@override
@JsonKey()
List<String> 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<String, dynamic> toJson() {
return _$$ConnectionsAndKeywordsImplToJson(
this,
);
}
}
abstract class _ConnectionsAndKeywords implements ConnectionsAndKeywords {
const factory _ConnectionsAndKeywords(
{final List<Connection> connections,
final List<String> keywords}) = _$ConnectionsAndKeywordsImpl;
factory _ConnectionsAndKeywords.fromJson(Map<String, dynamic> json) =
_$ConnectionsAndKeywordsImpl.fromJson;
@override
List<Connection> get connections;
@override
List<String> get keywords;
@override
@JsonKey(ignore: true)
_$$ConnectionsAndKeywordsImplCopyWith<_$ConnectionsAndKeywordsImpl>
get copyWith => throw _privateConstructorUsedError;
}

View File

@@ -1,74 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of '../connection.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$MetadataImpl _$$MetadataImplFromJson(Map<String, dynamic> 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<String, dynamic> _$$MetadataImplToJson(_$MetadataImpl instance) =>
<String, dynamic>{
'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<String, dynamic> 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<String, dynamic>),
chains:
(json['chains'] as List<dynamic>).map((e) => e as String).toList(),
);
Map<String, dynamic> _$$ConnectionImplToJson(_$ConnectionImpl instance) =>
<String, dynamic>{
'id': instance.id,
'upload': instance.upload,
'download': instance.download,
'start': instance.start.toIso8601String(),
'metadata': instance.metadata,
'chains': instance.chains,
};
_$ConnectionsAndKeywordsImpl _$$ConnectionsAndKeywordsImplFromJson(
Map<String, dynamic> json) =>
_$ConnectionsAndKeywordsImpl(
connections: (json['connections'] as List<dynamic>?)
?.map((e) => Connection.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
keywords: (json['keywords'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
const [],
);
Map<String, dynamic> _$$ConnectionsAndKeywordsImplToJson(
_$ConnectionsAndKeywordsImpl instance) =>
<String, dynamic>{
'connections': instance.connections,
'keywords': instance.keywords,
};

View File

@@ -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>(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<String, dynamic> 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<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$DAVCopyWith<DAV> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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;
}

View File

@@ -1,21 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of '../dav.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$DAVImpl _$$DAVImplFromJson(Map<String, dynamic> json) => _$DAVImpl(
uri: json['uri'] as String,
user: json['user'] as String,
password: json['password'] as String,
fileName: json['fileName'] as String? ?? defaultDavFileName,
);
Map<String, dynamic> _$$DAVImplToJson(_$DAVImpl instance) => <String, dynamic>{
'uri': instance.uri,
'user': instance.user,
'password': instance.password,
'fileName': instance.fileName,
};

View File

@@ -1975,3 +1975,264 @@ abstract class _ExternalProvider implements ExternalProvider {
_$$ExternalProviderImplCopyWith<_$ExternalProviderImpl> get copyWith => _$$ExternalProviderImplCopyWith<_$ExternalProviderImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
TunProps _$TunPropsFromJson(Map<String, dynamic> 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<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$TunPropsCopyWith<TunProps> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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;
}

View File

@@ -176,3 +176,25 @@ Map<String, dynamic> _$$ExternalProviderImplToJson(
'vehicle-type': instance.vehicleType, 'vehicle-type': instance.vehicleType,
'update-at': instance.updateAt.toIso8601String(), 'update-at': instance.updateAt.toIso8601String(),
}; };
_$TunPropsImpl _$$TunPropsImplFromJson(Map<String, dynamic> 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<String, dynamic> _$$TunPropsImplToJson(_$TunPropsImpl instance) =>
<String, dynamic>{
'fd': instance.fd,
'gateway': instance.gateway,
'gateway6': instance.gateway6,
'portal': instance.portal,
'portal6': instance.portal6,
'dns': instance.dns,
'dns6': instance.dns6,
};

View File

@@ -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>(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<FileInfo> 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;
}

View File

@@ -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>(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<String, dynamic> json) {
return _LogsAndKeywords.fromJson(json);
}
/// @nodoc
mixin _$LogsAndKeywords {
List<Log> get logs => throw _privateConstructorUsedError;
List<String> get keywords => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$LogsAndKeywordsCopyWith<LogsAndKeywords> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $LogsAndKeywordsCopyWith<$Res> {
factory $LogsAndKeywordsCopyWith(
LogsAndKeywords value, $Res Function(LogsAndKeywords) then) =
_$LogsAndKeywordsCopyWithImpl<$Res, LogsAndKeywords>;
@useResult
$Res call({List<Log> logs, List<String> 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<Log>,
keywords: null == keywords
? _value.keywords
: keywords // ignore: cast_nullable_to_non_nullable
as List<String>,
) 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<Log> logs, List<String> 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<Log>,
keywords: null == keywords
? _value._keywords
: keywords // ignore: cast_nullable_to_non_nullable
as List<String>,
));
}
}
/// @nodoc
@JsonSerializable()
class _$LogsAndKeywordsImpl implements _LogsAndKeywords {
const _$LogsAndKeywordsImpl(
{final List<Log> logs = const [], final List<String> keywords = const []})
: _logs = logs,
_keywords = keywords;
factory _$LogsAndKeywordsImpl.fromJson(Map<String, dynamic> json) =>
_$$LogsAndKeywordsImplFromJson(json);
final List<Log> _logs;
@override
@JsonKey()
List<Log> get logs {
if (_logs is EqualUnmodifiableListView) return _logs;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_logs);
}
final List<String> _keywords;
@override
@JsonKey()
List<String> 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<String, dynamic> toJson() {
return _$$LogsAndKeywordsImplToJson(
this,
);
}
}
abstract class _LogsAndKeywords implements LogsAndKeywords {
const factory _LogsAndKeywords(
{final List<Log> logs,
final List<String> keywords}) = _$LogsAndKeywordsImpl;
factory _LogsAndKeywords.fromJson(Map<String, dynamic> json) =
_$LogsAndKeywordsImpl.fromJson;
@override
List<Log> get logs;
@override
List<String> get keywords;
@override
@JsonKey(ignore: true)
_$$LogsAndKeywordsImplCopyWith<_$LogsAndKeywordsImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -1,45 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of '../log.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Log _$LogFromJson(Map<String, dynamic> json) => Log(
logLevel: $enumDecode(_$LogLevelEnumMap, json['LogLevel']),
payload: json['Payload'] as String?,
);
Map<String, dynamic> _$LogToJson(Log instance) => <String, dynamic>{
'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<String, dynamic> json) =>
_$LogsAndKeywordsImpl(
logs: (json['logs'] as List<dynamic>?)
?.map((e) => Log.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
keywords: (json['keywords'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
const [],
);
Map<String, dynamic> _$$LogsAndKeywordsImplToJson(
_$LogsAndKeywordsImpl instance) =>
<String, dynamic>{
'logs': instance.logs,
'keywords': instance.keywords,
};

View File

@@ -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>(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<NavigationItemMode> get modes => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$NavigationItemCopyWith<NavigationItem> 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<NavigationItemMode> 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<NavigationItemMode>,
) 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<NavigationItemMode> 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<NavigationItemMode>,
));
}
}
/// @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<NavigationItemMode> 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<NavigationItemMode> _modes;
@override
@JsonKey()
List<NavigationItemMode> 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<NavigationItemMode> 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<NavigationItemMode> get modes;
@override
@JsonKey(ignore: true)
_$$NavigationItemImplCopyWith<_$NavigationItemImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -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>(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<String, dynamic> 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<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$PackageCopyWith<Package> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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;
}

View File

@@ -1,23 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of '../package.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$PackageImpl _$$PackageImplFromJson(Map<String, dynamic> json) =>
_$PackageImpl(
packageName: json['packageName'] as String,
label: json['label'] as String,
isSystem: json['isSystem'] as bool,
firstInstallTime: (json['firstInstallTime'] as num).toInt(),
);
Map<String, dynamic> _$$PackageImplToJson(_$PackageImpl instance) =>
<String, dynamic>{
'packageName': instance.packageName,
'label': instance.label,
'isSystem': instance.isSystem,
'firstInstallTime': instance.firstInstallTime,
};

View File

@@ -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>(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<String, dynamic> json) {
return _Group.fromJson(json);
}
/// @nodoc
mixin _$Group {
GroupType get type => throw _privateConstructorUsedError;
List<Proxy> 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<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$GroupCopyWith<Group> 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<Proxy> 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<Proxy>,
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<Proxy> 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<Proxy>,
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<Proxy> all = const [],
this.now,
this.hidden,
this.icon = "",
required this.name})
: _all = all;
factory _$GroupImpl.fromJson(Map<String, dynamic> json) =>
_$$GroupImplFromJson(json);
@override
final GroupType type;
final List<Proxy> _all;
@override
@JsonKey()
List<Proxy> 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<String, dynamic> toJson() {
return _$$GroupImplToJson(
this,
);
}
}
abstract class _Group implements Group {
const factory _Group(
{required final GroupType type,
final List<Proxy> all,
final String? now,
final bool? hidden,
final String icon,
required final String name}) = _$GroupImpl;
factory _Group.fromJson(Map<String, dynamic> json) = _$GroupImpl.fromJson;
@override
GroupType get type;
@override
List<Proxy> 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<String, dynamic> json) {
return _Proxy.fromJson(json);
}
/// @nodoc
mixin _$Proxy {
String get name => throw _privateConstructorUsedError;
String get type => throw _privateConstructorUsedError;
String? get now => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ProxyCopyWith<Proxy> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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;
}

View File

@@ -1,50 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of '../proxy.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$GroupImpl _$$GroupImplFromJson(Map<String, dynamic> json) => _$GroupImpl(
type: $enumDecode(_$GroupTypeEnumMap, json['type']),
all: (json['all'] as List<dynamic>?)
?.map((e) => Proxy.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
now: json['now'] as String?,
hidden: json['hidden'] as bool?,
icon: json['icon'] as String? ?? "",
name: json['name'] as String,
);
Map<String, dynamic> _$$GroupImplToJson(_$GroupImpl instance) =>
<String, dynamic>{
'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<String, dynamic> json) => _$ProxyImpl(
name: json['name'] as String,
type: json['type'] as String,
now: json['now'] as String?,
);
Map<String, dynamic> _$$ProxyImplToJson(_$ProxyImpl instance) =>
<String, dynamic>{
'name': instance.name,
'type': instance.type,
'now': instance.now,
};

View File

@@ -957,25 +957,24 @@ abstract class _ApplicationSelectorState implements ApplicationSelectorState {
} }
/// @nodoc /// @nodoc
mixin _$TrayContainerSelectorState { mixin _$TrayState {
Mode get mode => throw _privateConstructorUsedError; Mode get mode => throw _privateConstructorUsedError;
bool get autoLaunch => throw _privateConstructorUsedError; bool get autoLaunch => throw _privateConstructorUsedError;
bool get systemProxy => throw _privateConstructorUsedError; bool get systemProxy => throw _privateConstructorUsedError;
bool get tunEnable => throw _privateConstructorUsedError; bool get tunEnable => throw _privateConstructorUsedError;
bool get isStart => throw _privateConstructorUsedError; bool get isStart => throw _privateConstructorUsedError;
String? get locale => throw _privateConstructorUsedError; String? get locale => throw _privateConstructorUsedError;
Brightness? get brightness => throw _privateConstructorUsedError;
@JsonKey(ignore: true) @JsonKey(ignore: true)
$TrayContainerSelectorStateCopyWith<TrayContainerSelectorState> $TrayStateCopyWith<TrayState> get copyWith =>
get copyWith => throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
/// @nodoc /// @nodoc
abstract class $TrayContainerSelectorStateCopyWith<$Res> { abstract class $TrayStateCopyWith<$Res> {
factory $TrayContainerSelectorStateCopyWith(TrayContainerSelectorState value, factory $TrayStateCopyWith(TrayState value, $Res Function(TrayState) then) =
$Res Function(TrayContainerSelectorState) then) = _$TrayStateCopyWithImpl<$Res, TrayState>;
_$TrayContainerSelectorStateCopyWithImpl<$Res,
TrayContainerSelectorState>;
@useResult @useResult
$Res call( $Res call(
{Mode mode, {Mode mode,
@@ -983,14 +982,14 @@ abstract class $TrayContainerSelectorStateCopyWith<$Res> {
bool systemProxy, bool systemProxy,
bool tunEnable, bool tunEnable,
bool isStart, bool isStart,
String? locale}); String? locale,
Brightness? brightness});
} }
/// @nodoc /// @nodoc
class _$TrayContainerSelectorStateCopyWithImpl<$Res, class _$TrayStateCopyWithImpl<$Res, $Val extends TrayState>
$Val extends TrayContainerSelectorState> implements $TrayStateCopyWith<$Res> {
implements $TrayContainerSelectorStateCopyWith<$Res> { _$TrayStateCopyWithImpl(this._value, this._then);
_$TrayContainerSelectorStateCopyWithImpl(this._value, this._then);
// ignore: unused_field // ignore: unused_field
final $Val _value; final $Val _value;
@@ -1006,6 +1005,7 @@ class _$TrayContainerSelectorStateCopyWithImpl<$Res,
Object? tunEnable = null, Object? tunEnable = null,
Object? isStart = null, Object? isStart = null,
Object? locale = freezed, Object? locale = freezed,
Object? brightness = freezed,
}) { }) {
return _then(_value.copyWith( return _then(_value.copyWith(
mode: null == mode mode: null == mode
@@ -1032,17 +1032,20 @@ class _$TrayContainerSelectorStateCopyWithImpl<$Res,
? _value.locale ? _value.locale
: locale // ignore: cast_nullable_to_non_nullable : locale // ignore: cast_nullable_to_non_nullable
as String?, as String?,
brightness: freezed == brightness
? _value.brightness
: brightness // ignore: cast_nullable_to_non_nullable
as Brightness?,
) as $Val); ) as $Val);
} }
} }
/// @nodoc /// @nodoc
abstract class _$$TrayContainerSelectorStateImplCopyWith<$Res> abstract class _$$TrayStateImplCopyWith<$Res>
implements $TrayContainerSelectorStateCopyWith<$Res> { implements $TrayStateCopyWith<$Res> {
factory _$$TrayContainerSelectorStateImplCopyWith( factory _$$TrayStateImplCopyWith(
_$TrayContainerSelectorStateImpl value, _$TrayStateImpl value, $Res Function(_$TrayStateImpl) then) =
$Res Function(_$TrayContainerSelectorStateImpl) then) = __$$TrayStateImplCopyWithImpl<$Res>;
__$$TrayContainerSelectorStateImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call( $Res call(
@@ -1051,17 +1054,16 @@ abstract class _$$TrayContainerSelectorStateImplCopyWith<$Res>
bool systemProxy, bool systemProxy,
bool tunEnable, bool tunEnable,
bool isStart, bool isStart,
String? locale}); String? locale,
Brightness? brightness});
} }
/// @nodoc /// @nodoc
class __$$TrayContainerSelectorStateImplCopyWithImpl<$Res> class __$$TrayStateImplCopyWithImpl<$Res>
extends _$TrayContainerSelectorStateCopyWithImpl<$Res, extends _$TrayStateCopyWithImpl<$Res, _$TrayStateImpl>
_$TrayContainerSelectorStateImpl> implements _$$TrayStateImplCopyWith<$Res> {
implements _$$TrayContainerSelectorStateImplCopyWith<$Res> { __$$TrayStateImplCopyWithImpl(
__$$TrayContainerSelectorStateImplCopyWithImpl( _$TrayStateImpl _value, $Res Function(_$TrayStateImpl) _then)
_$TrayContainerSelectorStateImpl _value,
$Res Function(_$TrayContainerSelectorStateImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -1073,8 +1075,9 @@ class __$$TrayContainerSelectorStateImplCopyWithImpl<$Res>
Object? tunEnable = null, Object? tunEnable = null,
Object? isStart = null, Object? isStart = null,
Object? locale = freezed, Object? locale = freezed,
Object? brightness = freezed,
}) { }) {
return _then(_$TrayContainerSelectorStateImpl( return _then(_$TrayStateImpl(
mode: null == mode mode: null == mode
? _value.mode ? _value.mode
: mode // ignore: cast_nullable_to_non_nullable : mode // ignore: cast_nullable_to_non_nullable
@@ -1099,20 +1102,25 @@ class __$$TrayContainerSelectorStateImplCopyWithImpl<$Res>
? _value.locale ? _value.locale
: locale // ignore: cast_nullable_to_non_nullable : locale // ignore: cast_nullable_to_non_nullable
as String?, as String?,
brightness: freezed == brightness
? _value.brightness
: brightness // ignore: cast_nullable_to_non_nullable
as Brightness?,
)); ));
} }
} }
/// @nodoc /// @nodoc
class _$TrayContainerSelectorStateImpl implements _TrayContainerSelectorState { class _$TrayStateImpl implements _TrayState {
const _$TrayContainerSelectorStateImpl( const _$TrayStateImpl(
{required this.mode, {required this.mode,
required this.autoLaunch, required this.autoLaunch,
required this.systemProxy, required this.systemProxy,
required this.tunEnable, required this.tunEnable,
required this.isStart, required this.isStart,
required this.locale}); required this.locale,
required this.brightness});
@override @override
final Mode mode; final Mode mode;
@@ -1126,17 +1134,19 @@ class _$TrayContainerSelectorStateImpl implements _TrayContainerSelectorState {
final bool isStart; final bool isStart;
@override @override
final String? locale; final String? locale;
@override
final Brightness? brightness;
@override @override
String toString() { 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 @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$TrayContainerSelectorStateImpl && other is _$TrayStateImpl &&
(identical(other.mode, mode) || other.mode == mode) && (identical(other.mode, mode) || other.mode == mode) &&
(identical(other.autoLaunch, autoLaunch) || (identical(other.autoLaunch, autoLaunch) ||
other.autoLaunch == autoLaunch) && other.autoLaunch == autoLaunch) &&
@@ -1145,30 +1155,31 @@ class _$TrayContainerSelectorStateImpl implements _TrayContainerSelectorState {
(identical(other.tunEnable, tunEnable) || (identical(other.tunEnable, tunEnable) ||
other.tunEnable == tunEnable) && other.tunEnable == tunEnable) &&
(identical(other.isStart, isStart) || other.isStart == isStart) && (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 @override
int get hashCode => Object.hash( int get hashCode => Object.hash(runtimeType, mode, autoLaunch, systemProxy,
runtimeType, mode, autoLaunch, systemProxy, tunEnable, isStart, locale); tunEnable, isStart, locale, brightness);
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$TrayContainerSelectorStateImplCopyWith<_$TrayContainerSelectorStateImpl> _$$TrayStateImplCopyWith<_$TrayStateImpl> get copyWith =>
get copyWith => __$$TrayContainerSelectorStateImplCopyWithImpl< __$$TrayStateImplCopyWithImpl<_$TrayStateImpl>(this, _$identity);
_$TrayContainerSelectorStateImpl>(this, _$identity);
} }
abstract class _TrayContainerSelectorState abstract class _TrayState implements TrayState {
implements TrayContainerSelectorState { const factory _TrayState(
const factory _TrayContainerSelectorState(
{required final Mode mode, {required final Mode mode,
required final bool autoLaunch, required final bool autoLaunch,
required final bool systemProxy, required final bool systemProxy,
required final bool tunEnable, required final bool tunEnable,
required final bool isStart, required final bool isStart,
required final String? locale}) = _$TrayContainerSelectorStateImpl; required final String? locale,
required final Brightness? brightness}) = _$TrayStateImpl;
@override @override
Mode get mode; Mode get mode;
@@ -1183,9 +1194,11 @@ abstract class _TrayContainerSelectorState
@override @override
String? get locale; String? get locale;
@override @override
Brightness? get brightness;
@override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$TrayContainerSelectorStateImplCopyWith<_$TrayContainerSelectorStateImpl> _$$TrayStateImplCopyWith<_$TrayStateImpl> get copyWith =>
get copyWith => throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
/// @nodoc /// @nodoc
@@ -1332,7 +1345,7 @@ abstract class _UpdateNavigationsSelector implements UpdateNavigationsSelector {
} }
/// @nodoc /// @nodoc
mixin _$HomeSelectorState { mixin _$HomeState {
String get currentLabel => throw _privateConstructorUsedError; String get currentLabel => throw _privateConstructorUsedError;
List<NavigationItem> get navigationItems => List<NavigationItem> get navigationItems =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@@ -1340,15 +1353,14 @@ mixin _$HomeSelectorState {
String? get locale => throw _privateConstructorUsedError; String? get locale => throw _privateConstructorUsedError;
@JsonKey(ignore: true) @JsonKey(ignore: true)
$HomeSelectorStateCopyWith<HomeSelectorState> get copyWith => $HomeStateCopyWith<HomeState> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
/// @nodoc /// @nodoc
abstract class $HomeSelectorStateCopyWith<$Res> { abstract class $HomeStateCopyWith<$Res> {
factory $HomeSelectorStateCopyWith( factory $HomeStateCopyWith(HomeState value, $Res Function(HomeState) then) =
HomeSelectorState value, $Res Function(HomeSelectorState) then) = _$HomeStateCopyWithImpl<$Res, HomeState>;
_$HomeSelectorStateCopyWithImpl<$Res, HomeSelectorState>;
@useResult @useResult
$Res call( $Res call(
{String currentLabel, {String currentLabel,
@@ -1358,9 +1370,9 @@ abstract class $HomeSelectorStateCopyWith<$Res> {
} }
/// @nodoc /// @nodoc
class _$HomeSelectorStateCopyWithImpl<$Res, $Val extends HomeSelectorState> class _$HomeStateCopyWithImpl<$Res, $Val extends HomeState>
implements $HomeSelectorStateCopyWith<$Res> { implements $HomeStateCopyWith<$Res> {
_$HomeSelectorStateCopyWithImpl(this._value, this._then); _$HomeStateCopyWithImpl(this._value, this._then);
// ignore: unused_field // ignore: unused_field
final $Val _value; final $Val _value;
@@ -1397,11 +1409,11 @@ class _$HomeSelectorStateCopyWithImpl<$Res, $Val extends HomeSelectorState>
} }
/// @nodoc /// @nodoc
abstract class _$$HomeSelectorStateImplCopyWith<$Res> abstract class _$$HomeStateImplCopyWith<$Res>
implements $HomeSelectorStateCopyWith<$Res> { implements $HomeStateCopyWith<$Res> {
factory _$$HomeSelectorStateImplCopyWith(_$HomeSelectorStateImpl value, factory _$$HomeStateImplCopyWith(
$Res Function(_$HomeSelectorStateImpl) then) = _$HomeStateImpl value, $Res Function(_$HomeStateImpl) then) =
__$$HomeSelectorStateImplCopyWithImpl<$Res>; __$$HomeStateImplCopyWithImpl<$Res>;
@override @override
@useResult @useResult
$Res call( $Res call(
@@ -1412,11 +1424,11 @@ abstract class _$$HomeSelectorStateImplCopyWith<$Res>
} }
/// @nodoc /// @nodoc
class __$$HomeSelectorStateImplCopyWithImpl<$Res> class __$$HomeStateImplCopyWithImpl<$Res>
extends _$HomeSelectorStateCopyWithImpl<$Res, _$HomeSelectorStateImpl> extends _$HomeStateCopyWithImpl<$Res, _$HomeStateImpl>
implements _$$HomeSelectorStateImplCopyWith<$Res> { implements _$$HomeStateImplCopyWith<$Res> {
__$$HomeSelectorStateImplCopyWithImpl(_$HomeSelectorStateImpl _value, __$$HomeStateImplCopyWithImpl(
$Res Function(_$HomeSelectorStateImpl) _then) _$HomeStateImpl _value, $Res Function(_$HomeStateImpl) _then)
: super(_value, _then); : super(_value, _then);
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@@ -1427,7 +1439,7 @@ class __$$HomeSelectorStateImplCopyWithImpl<$Res>
Object? viewMode = null, Object? viewMode = null,
Object? locale = freezed, Object? locale = freezed,
}) { }) {
return _then(_$HomeSelectorStateImpl( return _then(_$HomeStateImpl(
currentLabel: null == currentLabel currentLabel: null == currentLabel
? _value.currentLabel ? _value.currentLabel
: currentLabel // ignore: cast_nullable_to_non_nullable : currentLabel // ignore: cast_nullable_to_non_nullable
@@ -1450,8 +1462,8 @@ class __$$HomeSelectorStateImplCopyWithImpl<$Res>
/// @nodoc /// @nodoc
class _$HomeSelectorStateImpl implements _HomeSelectorState { class _$HomeStateImpl implements _HomeState {
const _$HomeSelectorStateImpl( const _$HomeStateImpl(
{required this.currentLabel, {required this.currentLabel,
required final List<NavigationItem> navigationItems, required final List<NavigationItem> navigationItems,
required this.viewMode, required this.viewMode,
@@ -1475,14 +1487,14 @@ class _$HomeSelectorStateImpl implements _HomeSelectorState {
@override @override
String toString() { String toString() {
return 'HomeSelectorState(currentLabel: $currentLabel, navigationItems: $navigationItems, viewMode: $viewMode, locale: $locale)'; return 'HomeState(currentLabel: $currentLabel, navigationItems: $navigationItems, viewMode: $viewMode, locale: $locale)';
} }
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$HomeSelectorStateImpl && other is _$HomeStateImpl &&
(identical(other.currentLabel, currentLabel) || (identical(other.currentLabel, currentLabel) ||
other.currentLabel == currentLabel) && other.currentLabel == currentLabel) &&
const DeepCollectionEquality() const DeepCollectionEquality()
@@ -1499,17 +1511,16 @@ class _$HomeSelectorStateImpl implements _HomeSelectorState {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$HomeSelectorStateImplCopyWith<_$HomeSelectorStateImpl> get copyWith => _$$HomeStateImplCopyWith<_$HomeStateImpl> get copyWith =>
__$$HomeSelectorStateImplCopyWithImpl<_$HomeSelectorStateImpl>( __$$HomeStateImplCopyWithImpl<_$HomeStateImpl>(this, _$identity);
this, _$identity);
} }
abstract class _HomeSelectorState implements HomeSelectorState { abstract class _HomeState implements HomeState {
const factory _HomeSelectorState( const factory _HomeState(
{required final String currentLabel, {required final String currentLabel,
required final List<NavigationItem> navigationItems, required final List<NavigationItem> navigationItems,
required final ViewMode viewMode, required final ViewMode viewMode,
required final String? locale}) = _$HomeSelectorStateImpl; required final String? locale}) = _$HomeStateImpl;
@override @override
String get currentLabel; String get currentLabel;
@@ -1521,143 +1532,10 @@ abstract class _HomeSelectorState implements HomeSelectorState {
String? get locale; String? get locale;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$HomeSelectorStateImplCopyWith<_$HomeSelectorStateImpl> get copyWith => _$$HomeStateImplCopyWith<_$HomeStateImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
/// @nodoc
mixin _$HomeBodySelectorState {
List<NavigationItem> get navigationItems =>
throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$HomeBodySelectorStateCopyWith<HomeBodySelectorState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $HomeBodySelectorStateCopyWith<$Res> {
factory $HomeBodySelectorStateCopyWith(HomeBodySelectorState value,
$Res Function(HomeBodySelectorState) then) =
_$HomeBodySelectorStateCopyWithImpl<$Res, HomeBodySelectorState>;
@useResult
$Res call({List<NavigationItem> 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<NavigationItem>,
) 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<NavigationItem> 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<NavigationItem>,
));
}
}
/// @nodoc
class _$HomeBodySelectorStateImpl implements _HomeBodySelectorState {
const _$HomeBodySelectorStateImpl(
{required final List<NavigationItem> navigationItems})
: _navigationItems = navigationItems;
final List<NavigationItem> _navigationItems;
@override
List<NavigationItem> 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<NavigationItem> navigationItems}) =
_$HomeBodySelectorStateImpl;
@override
List<NavigationItem> get navigationItems;
@override
@JsonKey(ignore: true)
_$$HomeBodySelectorStateImplCopyWith<_$HomeBodySelectorStateImpl>
get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc /// @nodoc
mixin _$ProxiesCardSelectorState { mixin _$ProxiesCardSelectorState {
bool get isSelected => throw _privateConstructorUsedError; bool get isSelected => throw _privateConstructorUsedError;
@@ -4003,3 +3881,152 @@ abstract class _ClashConfigState implements ClashConfigState {
_$$ClashConfigStateImplCopyWith<_$ClashConfigStateImpl> get copyWith => _$$ClashConfigStateImplCopyWith<_$ClashConfigStateImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
/// @nodoc
mixin _$ThemeState {
String? get locale => throw _privateConstructorUsedError;
ScaleProps get scaleProps => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ThemeStateCopyWith<ThemeState> 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;
}

View File

@@ -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>(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<String, dynamic> json) {
return _VersionInfo.fromJson(json);
}
/// @nodoc
mixin _$VersionInfo {
String get clashName => throw _privateConstructorUsedError;
String get version => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$VersionInfoCopyWith<VersionInfo> 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<String, dynamic> 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<String, dynamic> toJson() {
return _$$VersionInfoImplToJson(
this,
);
}
}
abstract class _VersionInfo implements VersionInfo {
const factory _VersionInfo({final String clashName, final String version}) =
_$VersionInfoImpl;
factory _VersionInfo.fromJson(Map<String, dynamic> json) =
_$VersionInfoImpl.fromJson;
@override
String get clashName;
@override
String get version;
@override
@JsonKey(ignore: true)
_$$VersionInfoImplCopyWith<_$VersionInfoImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@@ -1,19 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of '../version.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$VersionInfoImpl _$$VersionInfoImplFromJson(Map<String, dynamic> json) =>
_$VersionInfoImpl(
clashName: json['clashName'] as String? ?? "",
version: json['version'] as String? ?? "",
);
Map<String, dynamic> _$$VersionInfoImplToJson(_$VersionInfoImpl instance) =>
<String, dynamic>{
'clashName': instance.clashName,
'version': instance.version,
};

View File

@@ -1,70 +0,0 @@
class IpInfo {
final String ip;
final String countryCode;
const IpInfo({
required this.ip,
required this.countryCode,
});
static IpInfo fromIpInfoIoJson(Map<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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<String, dynamic> 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}';
}
}

View File

@@ -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<String, dynamic> json) {
return _$LogFromJson(json);
}
Map<String, dynamic> 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<Log> logs,
@Default([]) List<String> keywords,
}) = _LogsAndKeywords;
factory LogsAndKeywords.fromJson(Map<String, Object?> json) =>
_$LogsAndKeywordsFromJson(json);
}
extension LogsAndKeywordsExt on LogsAndKeywords {
List<Log> get filteredLogs => logs
.where(
(log) => {log.logLevel.name}.containsAll(keywords),
)
.toList();
}

View File

@@ -2,16 +2,6 @@ export 'app.dart';
export 'clash_config.dart'; export 'clash_config.dart';
export 'config.dart'; export 'config.dart';
export 'profile.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 'ffi.dart';
export 'selector.dart'; export 'selector.dart';
export 'navigation.dart'; export 'common.dart';
export 'dav.dart';
export 'ip.dart';
export 'file.dart';

View File

@@ -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<NavigationItemMode> modes,
}) = _NavigationItem;
}

View File

@@ -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<String, Object?> json) =>
_$PackageFromJson(json);
}

View File

@@ -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<String, Proxy>;
@freezed
class Group with _$Group {
const factory Group({
required GroupType type,
@Default([]) List<Proxy> all,
String? now,
bool? hidden,
@Default("") String icon,
required String name,
}) = _Group;
factory Group.fromJson(Map<String, Object?> 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<String, Object?> json) => _$ProxyFromJson(json);
}

View File

@@ -59,15 +59,16 @@ class ApplicationSelectorState with _$ApplicationSelectorState {
} }
@freezed @freezed
class TrayContainerSelectorState with _$TrayContainerSelectorState { class TrayState with _$TrayState {
const factory TrayContainerSelectorState({ const factory TrayState({
required Mode mode, required Mode mode,
required bool autoLaunch, required bool autoLaunch,
required bool systemProxy, required bool systemProxy,
required bool tunEnable, required bool tunEnable,
required bool isStart, required bool isStart,
required String? locale, required String? locale,
}) = _TrayContainerSelectorState; required Brightness? brightness,
}) = _TrayState;
} }
@freezed @freezed
@@ -79,21 +80,15 @@ class UpdateNavigationsSelector with _$UpdateNavigationsSelector {
} }
@freezed @freezed
class HomeSelectorState with _$HomeSelectorState { class HomeState with _$HomeState {
const factory HomeSelectorState({ const factory HomeState({
required String currentLabel, required String currentLabel,
required List<NavigationItem> navigationItems, required List<NavigationItem> navigationItems,
required ViewMode viewMode, required ViewMode viewMode,
required String? locale, required String? locale,
}) = _HomeSelectorState; }) = _HomeState;
} }
@freezed
class HomeBodySelectorState with _$HomeBodySelectorState {
const factory HomeBodySelectorState({
required List<NavigationItem> navigationItems,
}) = _HomeBodySelectorState;
}
@freezed @freezed
class ProxiesCardSelectorState with _$ProxiesCardSelectorState { class ProxiesCardSelectorState with _$ProxiesCardSelectorState {
@@ -245,3 +240,12 @@ class ClashConfigState with _$ClashConfigState {
required String? globalRealUa, required String? globalRealUa,
}) = _ClashConfigState; }) = _ClashConfigState;
} }
@freezed
class ThemeState with _$ThemeState {
const factory ThemeState({
required String? locale,
required ScaleProps scaleProps,
}) = _ThemeState;
}

Some files were not shown because too many files have changed in this diff Show More