Compare commits
1 Commits
v0.8.88-pr
...
v0.8.88-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5756fba7e8 |
@@ -54,7 +54,7 @@ Support the following actions
|
||||
|
||||
com.follow.clash.action.STOP
|
||||
|
||||
com.follow.clash.action.CHANGE
|
||||
com.follow.clash.action.TOGGLE
|
||||
```
|
||||
|
||||
## Download
|
||||
|
||||
@@ -54,7 +54,7 @@ on Mobile:
|
||||
|
||||
com.follow.clash.action.STOP
|
||||
|
||||
com.follow.clash.action.CHANGE
|
||||
com.follow.clash.action.TOGGLE
|
||||
```
|
||||
|
||||
## Download
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
analyzer:
|
||||
plugins:
|
||||
- custom_lint
|
||||
exclude:
|
||||
- lib/l10n/intl/**
|
||||
errors:
|
||||
invalid_annotation_target: ignore
|
||||
|
||||
linter:
|
||||
rules:
|
||||
|
||||
@@ -1,28 +1,76 @@
|
||||
package com.follow.clash
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Base64
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import com.follow.clash.common.GlobalState
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
suspend fun Drawable.getBase64(): String {
|
||||
val drawable = this
|
||||
return withContext(Dispatchers.IO) {
|
||||
val bitmap = drawable.toBitmap()
|
||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
|
||||
Base64.encodeToString(byteArrayOutputStream.toByteArray(), Base64.NO_WRAP)
|
||||
private const val ICON_TTL_DAYS = 1L
|
||||
|
||||
suspend fun PackageManager.getPackageIconPath(packageName: String): String =
|
||||
withContext(Dispatchers.IO) {
|
||||
val cacheDir = GlobalState.application.cacheDir
|
||||
val iconDir = File(cacheDir, "icons").apply { mkdirs() }
|
||||
val pkgInfo = getPackageInfo(packageName, 0)
|
||||
val lastUpdateTime = pkgInfo.lastUpdateTime
|
||||
val iconFile = File(iconDir, "${packageName}_${lastUpdateTime}.webp")
|
||||
if (iconFile.exists() && !isExpired(iconFile)) {
|
||||
return@withContext iconFile.absolutePath
|
||||
}
|
||||
iconDir.listFiles()?.forEach { file ->
|
||||
if (file.name.startsWith(packageName + "_")) file.delete()
|
||||
}
|
||||
return@withContext try {
|
||||
val icon = getApplicationIcon(packageName)
|
||||
saveDrawableToFile(icon, iconFile)
|
||||
iconFile.absolutePath
|
||||
} catch (_: Exception) {
|
||||
val defaultIconFile = File(iconDir, "default_icon.webp")
|
||||
if (!defaultIconFile.exists()) {
|
||||
saveDrawableToFile(defaultActivityIcon, defaultIconFile)
|
||||
}
|
||||
defaultIconFile.absolutePath
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveDrawableToFile(drawable: Drawable, file: File) {
|
||||
val bitmap = drawable.toBitmap()
|
||||
try {
|
||||
val format = when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {
|
||||
Bitmap.CompressFormat.WEBP_LOSSY
|
||||
}
|
||||
|
||||
else -> {
|
||||
Bitmap.CompressFormat.WEBP
|
||||
}
|
||||
}
|
||||
FileOutputStream(file).use { fos ->
|
||||
bitmap.compress(format, 90, fos)
|
||||
}
|
||||
} finally {
|
||||
if (!bitmap.isRecycled) bitmap.recycle()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isExpired(file: File): Boolean {
|
||||
val now = System.currentTimeMillis()
|
||||
val age = now - file.lastModified()
|
||||
return age > TimeUnit.DAYS.toMillis(ICON_TTL_DAYS)
|
||||
}
|
||||
|
||||
suspend fun <T> MethodChannel.awaitResult(
|
||||
|
||||
@@ -22,7 +22,7 @@ import com.follow.clash.common.Components
|
||||
import com.follow.clash.common.GlobalState
|
||||
import com.follow.clash.common.QuickAction
|
||||
import com.follow.clash.common.quickIntent
|
||||
import com.follow.clash.getBase64
|
||||
import com.follow.clash.getPackageIconPath
|
||||
import com.follow.clash.models.Package
|
||||
import com.google.gson.Gson
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
@@ -150,26 +150,7 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
|
||||
}
|
||||
|
||||
"getPackageIcon" -> {
|
||||
scope.launch {
|
||||
val packageName = call.argument<String>("packageName")
|
||||
if (packageName == null) {
|
||||
result.success(null)
|
||||
return@launch
|
||||
}
|
||||
val packageIcon = getPackageIcon(packageName)
|
||||
packageIcon.let {
|
||||
if (it != null) {
|
||||
result.success(it)
|
||||
return@launch
|
||||
}
|
||||
if (iconMap["default"] == null) {
|
||||
iconMap["default"] =
|
||||
GlobalState.application.packageManager?.defaultActivityIcon?.getBase64()
|
||||
}
|
||||
result.success(iconMap["default"])
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
handleGetPackageIcon(call, result)
|
||||
}
|
||||
|
||||
"tip" -> {
|
||||
@@ -184,6 +165,19 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleGetPackageIcon(call: MethodCall, result: Result) {
|
||||
scope.launch {
|
||||
val packageName = call.argument<String>("packageName")
|
||||
if (packageName == null) {
|
||||
result.success("")
|
||||
return@launch
|
||||
}
|
||||
val path =
|
||||
GlobalState.application.packageManager.getPackageIconPath(packageName)
|
||||
result.success(path)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initShortcuts(label: String) {
|
||||
val shortcut = with(ShortcutInfoCompat.Builder(GlobalState.application, "toggle")) {
|
||||
setShortLabel(label)
|
||||
@@ -223,18 +217,6 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getPackageIcon(packageName: String): String? {
|
||||
val packageManager = GlobalState.application.packageManager
|
||||
if (iconMap[packageName] == null) {
|
||||
iconMap[packageName] = try {
|
||||
packageManager?.getApplicationIcon(packageName)?.getBase64()
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
}
|
||||
return iconMap[packageName]
|
||||
}
|
||||
|
||||
private fun getPackages(): List<Package> {
|
||||
val packageManager = GlobalState.application.packageManager
|
||||
|
||||
@@ -28,10 +28,6 @@ class RemoteService : Service(),
|
||||
}
|
||||
}
|
||||
|
||||
fun onServiceDisconnected() {
|
||||
handleStopService()
|
||||
}
|
||||
|
||||
private fun handleStartService() {
|
||||
launch {
|
||||
val nextIntent = when (State.options?.enable == true) {
|
||||
@@ -40,7 +36,7 @@ class RemoteService : Service(),
|
||||
}
|
||||
if (intent != nextIntent) {
|
||||
delegate?.unbind()
|
||||
delegate = ServiceDelegate(nextIntent, ::onServiceDisconnected) { binder ->
|
||||
delegate = ServiceDelegate(nextIntent) { binder ->
|
||||
when (binder) {
|
||||
is VpnService.LocalBinder -> binder.getService()
|
||||
is CommonService.LocalBinder -> binder.getService()
|
||||
|
||||
Submodule core/Clash.Meta updated: 6fe704ae11...52dfcca013
@@ -181,6 +181,10 @@ func handleAction(action *Action, result ActionResult) {
|
||||
case crashMethod:
|
||||
result.success(true)
|
||||
handleCrash()
|
||||
case deleteFile:
|
||||
path := action.Data.(string)
|
||||
handleDelFile(path, result)
|
||||
return
|
||||
default:
|
||||
nextHandle(action, result)
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ const (
|
||||
crashMethod Method = "crash"
|
||||
setupConfigMethod Method = "setupConfig"
|
||||
getConfigMethod Method = "getConfig"
|
||||
deleteFile Method = "deleteFile"
|
||||
)
|
||||
|
||||
type Method string
|
||||
|
||||
35
core/go.mod
35
core/go.mod
@@ -10,7 +10,6 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/3andne/restls-client-go v0.1.6 // indirect
|
||||
github.com/RyuaNerin/go-krypto v1.3.0 // indirect
|
||||
github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect
|
||||
github.com/ajg/form v1.5.1 // indirect
|
||||
@@ -19,15 +18,15 @@ require (
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/coreos/go-iptables v0.8.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
||||
github.com/ebitengine/purego v0.8.3 // indirect
|
||||
github.com/enfein/mieru/v3 v3.16.1 // indirect
|
||||
github.com/ebitengine/purego v0.8.4 // indirect
|
||||
github.com/enfein/mieru/v3 v3.19.1 // indirect
|
||||
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 // indirect
|
||||
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
|
||||
github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect
|
||||
github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/gaukas/godicttls v0.0.4 // indirect
|
||||
github.com/go-chi/chi/v5 v5.2.2 // indirect
|
||||
github.com/go-chi/chi/v5 v5.2.3 // indirect
|
||||
github.com/go-chi/render v1.0.3 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
@@ -42,35 +41,36 @@ require (
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab // indirect
|
||||
github.com/metacubex/amneziawg-go v0.0.0-20250820070344-732c0c9d418a // indirect
|
||||
github.com/metacubex/ascon v0.1.0 // indirect
|
||||
github.com/metacubex/bart v0.20.5 // indirect
|
||||
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b // indirect
|
||||
github.com/metacubex/blake3 v0.1.0 // indirect
|
||||
github.com/metacubex/chacha v0.1.5 // indirect
|
||||
github.com/metacubex/fswatch v0.1.1 // indirect
|
||||
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect
|
||||
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b // indirect
|
||||
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 // indirect
|
||||
github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c // indirect
|
||||
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295 // indirect
|
||||
github.com/metacubex/randv2 v0.2.0 // indirect
|
||||
github.com/metacubex/sing v0.5.4 // indirect
|
||||
github.com/metacubex/sing-mux v0.3.2 // indirect
|
||||
github.com/metacubex/restls-client-go v0.1.7 // indirect
|
||||
github.com/metacubex/sing v0.5.5 // indirect
|
||||
github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac // indirect
|
||||
github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb // indirect
|
||||
github.com/metacubex/sing-shadowsocks v0.2.11 // indirect
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.5 // indirect
|
||||
github.com/metacubex/sing-shadowsocks v0.2.12 // indirect
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.6 // indirect
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 // indirect
|
||||
github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97 // indirect
|
||||
github.com/metacubex/sing-vmess v0.2.3 // indirect
|
||||
github.com/metacubex/sing-tun v0.4.7 // indirect
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0 // indirect
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f // indirect
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee // indirect
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 // indirect
|
||||
github.com/metacubex/utls v1.8.0 // indirect
|
||||
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 // indirect
|
||||
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617 // indirect
|
||||
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142 // indirect
|
||||
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f // indirect
|
||||
github.com/miekg/dns v1.1.63 // indirect
|
||||
github.com/mroth/weightedrand/v2 v2.1.0 // indirect
|
||||
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
|
||||
@@ -110,5 +110,4 @@ require (
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/blake3 v1.3.0 // indirect
|
||||
)
|
||||
|
||||
72
core/go.sum
72
core/go.sum
@@ -1,5 +1,3 @@
|
||||
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/RyuaNerin/go-krypto v1.3.0 h1:smavTzSMAx8iuVlGb4pEwl9MD2qicqMzuXR2QWp2/Pg=
|
||||
github.com/RyuaNerin/go-krypto v1.3.0/go.mod h1:9R9TU936laAIqAmjcHo/LsaXYOZlymudOAxjaBf62UM=
|
||||
github.com/RyuaNerin/testingutil v0.1.0 h1:IYT6JL57RV3U2ml3dLHZsVtPOP6yNK7WUVdzzlpNrss=
|
||||
@@ -24,10 +22,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
|
||||
github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/enfein/mieru/v3 v3.16.1 h1:CfIt1pQCCQbohkw+HBD2o8V9tnhZvB5yuXGGQIXTLOs=
|
||||
github.com/enfein/mieru/v3 v3.16.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
|
||||
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
|
||||
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/enfein/mieru/v3 v3.19.1 h1:19b9kgFC7oJXX9RLEO5Pi1gO6yek5cWlpK7IJVUoE8I=
|
||||
github.com/enfein/mieru/v3 v3.19.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
|
||||
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 h1:kXYqH/sL8dS/FdoFjr12ePjnLPorPo2FsnrHNuXSDyo=
|
||||
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
|
||||
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
|
||||
@@ -41,8 +39,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
|
||||
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
|
||||
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
|
||||
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
|
||||
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
@@ -80,24 +78,24 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
|
||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab h1:Chbw+/31UC14YFNr78pESt5Vowlc62zziw05JCUqoL4=
|
||||
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab/go.mod h1:xVKK8jC5Sd3hfh7WjmCq+HorehIbrBijaUWmcuKjPcI=
|
||||
github.com/metacubex/amneziawg-go v0.0.0-20250820070344-732c0c9d418a h1:c1QSGpacSeQdBdWcEKZKGuWLcqIG2wxHEygAcXuDwS4=
|
||||
github.com/metacubex/amneziawg-go v0.0.0-20250820070344-732c0c9d418a/go.mod h1:MsM/5czONyXMJ3PRr5DbQ4O/BxzAnJWOIcJdLzW6qHY=
|
||||
github.com/metacubex/ascon v0.1.0 h1:6ZWxmXYszT1XXtwkf6nxfFhc/OTtQ9R3Vyj1jN32lGM=
|
||||
github.com/metacubex/ascon v0.1.0/go.mod h1:eV5oim4cVPPdEL8/EYaTZ0iIKARH9pnhAK/fcT5Kacc=
|
||||
github.com/metacubex/bart v0.20.5 h1:XkgLZ17QxfxkqKdGsojoM2Zu01mmHyyQSFzt2/calTM=
|
||||
github.com/metacubex/bart v0.20.5/go.mod h1:DCcyfP4MC+Zy7sLK7XeGuMw+P5K9mIRsYOBgiE8icsI=
|
||||
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b h1:j7dadXD8I2KTmMt8jg1JcaP1ANL3JEObJPdANKcSYPY=
|
||||
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b/go.mod h1:+WmP0VJZDkDszvpa83HzfUp6QzARl/IKkMorH4+nODw=
|
||||
github.com/metacubex/blake3 v0.1.0 h1:KGnjh/56REO7U+cgZA8dnBhxdP7jByrG7hTP+bu6cqY=
|
||||
github.com/metacubex/blake3 v0.1.0/go.mod h1:CCkLdzFrqf7xmxCdhQFvJsRRV2mwOLDoSPg6vUTB9Uk=
|
||||
github.com/metacubex/chacha v0.1.5 h1:fKWMb/5c7ZrY8Uoqi79PPFxl+qwR7X/q0OrsAubyX2M=
|
||||
github.com/metacubex/chacha v0.1.5/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8=
|
||||
github.com/metacubex/fswatch v0.1.1 h1:jqU7C/v+g0qc2RUFgmAOPoVvfl2BXXUXEumn6oQuxhU=
|
||||
@@ -108,37 +106,39 @@ github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b h1:RUh4OdVPz/jDrM
|
||||
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU=
|
||||
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo=
|
||||
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793/go.mod h1:RjRNb4G52yAgfR+Oe/kp9G4PJJ97Fnj89eY1BFO3YyA=
|
||||
github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c h1:ABQzmOaZddM3q0OYeoZEc0XF+KW+dUdPNvY/c5rsunI=
|
||||
github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c/go.mod h1:eWlAK3zsKI0P8UhYpXlIsl3mtW4D6MpMNuYLIu8CKWI=
|
||||
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295 h1:8JVlYuE8uSJAvmyCd4TjvDxs57xjb0WxEoaWafK5+qs=
|
||||
github.com/metacubex/quic-go v0.54.1-0.20250730114134-a1ae705fe295/go.mod h1:1lktQFtCD17FZliVypbrDHwbsFSsmz2xz2TRXydvB5c=
|
||||
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
|
||||
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY=
|
||||
github.com/metacubex/restls-client-go v0.1.7 h1:eCwiXCTQb5WJu9IlgYvDBA1OgrINv58dEe7hcN5H15k=
|
||||
github.com/metacubex/restls-client-go v0.1.7/go.mod h1:BN/U52vPw7j8VTSh2vleD/MnmVKCov84mS5VcjVHH4g=
|
||||
github.com/metacubex/sing v0.5.2/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
|
||||
github.com/metacubex/sing v0.5.4 h1:a4kAOZmF+OXosbzPEcrSc5QD35/ex+MNuZsrcuWskHk=
|
||||
github.com/metacubex/sing v0.5.4/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
|
||||
github.com/metacubex/sing-mux v0.3.2 h1:nJv52pyRivHcaZJKk2JgxpaVvj1GAXG81scSa9N7ncw=
|
||||
github.com/metacubex/sing-mux v0.3.2/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw=
|
||||
github.com/metacubex/sing v0.5.5 h1:m5U8iHvRAUxlme3FZlE/LPIGHjU8oMCUzXWGbQQAC1E=
|
||||
github.com/metacubex/sing v0.5.5/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
|
||||
github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac h1:wDH/Jh/yqWbzPktqJP+Y1cUG8hchcrzKzUxJiSpnaQs=
|
||||
github.com/metacubex/sing-mux v0.3.3-0.20250813083925-d7c9aeaeeaac/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb h1:U/m3h8lp/j7i8zFgfvScLdZa1/Y8dd74oO7iZaQq80s=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb/go.mod h1:B60FxaPHjR1SeQB0IiLrgwgvKsaoASfOWdiqhLjmMGA=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.11 h1:p2NGNOdF95e6XvdDKipLj1FRRqR8dnbfC/7pw2CCTlw=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.11/go.mod h1:bT1PCTV316zFnlToRMk5zt9HmIQYRBveiT71mplYPfc=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.5 h1:MnPn0hbcDkSJt6TlpI15XImHKK6IqaOwBUGPKyMnJnE=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.5/go.mod h1:Zyh+rAQRyevYfG/COCvDs1c/YMhGqCuknn7QrGmoQIw=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.12 h1:Wqzo8bYXrK5aWqxu/TjlTnYZzAKtKsaFQBdr6IHFaBE=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.12/go.mod h1:2e5EIaw0rxKrm1YTRmiMnDulwbGxH9hAFlrwQLQMQkU=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.6 h1:ZR1kYT0f0Vi64iQSS09OdhFfppiNkh7kjgRdMm0SB98=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.6/go.mod h1:vOEbfKC60txi0ca+yUlqEwOGc3Obl6cnSgx9Gf45KjE=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
|
||||
github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97 h1:YYpc60UZE2G0pUeHbRw9erDrUDZrPQy8QzWFqA3kHsk=
|
||||
github.com/metacubex/sing-tun v0.4.7-0.20250721020617-8e7c37ed3d97/go.mod h1:2YywXPWW8Z97kTH7RffOeykKzU+l0aiKlglWV1PAS64=
|
||||
github.com/metacubex/sing-vmess v0.2.3 h1:QKLdIk5A2FcR3Y7m2/JO1XhfzgDA8tF4W9/ffsH9opo=
|
||||
github.com/metacubex/sing-vmess v0.2.3/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
|
||||
github.com/metacubex/sing-tun v0.4.7 h1:ZDY/W+1c7PeWWKeKRyUo18fySF/TWjB0i5ui81Ar778=
|
||||
github.com/metacubex/sing-tun v0.4.7/go.mod h1:xHecZRwBnKWe6zG9amAK9cXf91lF6blgjBqm+VvOrmU=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0 h1:WZepq4TOZa6WewB8tGAZrrL+bL2R2ivoBzuEgAeolWc=
|
||||
github.com/metacubex/sing-vmess v0.2.4-0.20250822020810-4856053566f0/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f/go.mod h1:jpAkVLPnCpGSfNyVmj6Cq4YbuZsFepm/Dc+9BAOcR80=
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113awp7P6odM2okB5s60HUyF0FMqKmo=
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/metacubex/utls v1.8.0 h1:mSYi6FMnmc5riARl5UZDmWVy710z+P5b7xuGW0lV9ac=
|
||||
github.com/metacubex/utls v1.8.0/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
|
||||
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 h1:hJLQviGySBuaynlCwf/oYgIxbVbGRUIKZCxdya9YrbQ=
|
||||
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181/go.mod h1:phewKljNYiTVT31Gcif8RiCKnTUOgVWFJjccqYM8s+Y=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617 h1:yN3mQ4cT9sPUciw/rO0Isc/8QlO86DB6g9SEMRgQ8Cw=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250827083229-aa432b865617/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142 h1:csEbKOzRAxJXffOeZnnS3/kA/F55JiTbKv5jcYqCXms=
|
||||
github.com/metacubex/utls v1.8.1-0.20250823120917-12f5ba126142/go.mod h1:67I3skhEY4Sya8f1YxELwWPoeQdXqZCrWNYLvq8gn2U=
|
||||
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f h1:FGBPRb1zUabhPhDrlKEjQ9lgIwQ6cHL4x8M9lrERhbk=
|
||||
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f/go.mod h1:oPGcV994OGJedmmxrcK9+ni7jUEMGhR+uVQAdaduIP4=
|
||||
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
|
||||
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
|
||||
github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU=
|
||||
@@ -191,7 +191,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
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/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
@@ -271,5 +271,3 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
|
||||
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
|
||||
28
core/hub.go
28
core/hub.go
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/metacubex/mihomo/tunnel"
|
||||
"github.com/metacubex/mihomo/tunnel/statistic"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -454,6 +455,33 @@ func handleUpdateConfig(bytes []byte) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func handleDelFile(path string, result ActionResult) {
|
||||
go func() {
|
||||
fileInfo, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
result.success(err.Error())
|
||||
}
|
||||
result.success("")
|
||||
return
|
||||
}
|
||||
if fileInfo.IsDir() {
|
||||
err = os.RemoveAll(path)
|
||||
if err != nil {
|
||||
result.success(err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err = os.Remove(path)
|
||||
if err != nil {
|
||||
result.success(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
result.success("")
|
||||
}()
|
||||
}
|
||||
|
||||
func handleSetupConfig(bytes []byte) string {
|
||||
var params = defaultSetupParams()
|
||||
err := UnmarshalJson(bytes, params)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export 'android.dart';
|
||||
export 'app_localizations.dart';
|
||||
export 'color.dart';
|
||||
export 'compute.dart';
|
||||
export 'constant.dart';
|
||||
export 'context.dart';
|
||||
export 'converter.dart';
|
||||
|
||||
114
lib/common/compute.dart
Normal file
114
lib/common/compute.dart
Normal file
@@ -0,0 +1,114 @@
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/models/models.dart';
|
||||
|
||||
import 'string.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
List<Group> computeSort({
|
||||
required List<Group> groups,
|
||||
required ProxiesSortType sortType,
|
||||
required DelayMap delayMap,
|
||||
required SelectedMap selectedMap,
|
||||
required String defaultTestUrl,
|
||||
}) {
|
||||
return groups.map((group) {
|
||||
final proxies = group.all;
|
||||
final newProxies = switch (sortType) {
|
||||
ProxiesSortType.none => proxies,
|
||||
ProxiesSortType.delay => _sortOfDelay(
|
||||
groups: groups,
|
||||
proxies: proxies,
|
||||
delayMap: delayMap,
|
||||
selectedMap: selectedMap,
|
||||
testUrl: group.testUrl.getSafeValue(defaultTestUrl),
|
||||
),
|
||||
ProxiesSortType.name => _sortOfName(proxies),
|
||||
};
|
||||
return group.copyWith(all: newProxies);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
DelayState computeProxyDelayState({
|
||||
required String proxyName,
|
||||
required String testUrl,
|
||||
required List<Group> groups,
|
||||
required SelectedMap selectedMap,
|
||||
required DelayMap delayMap,
|
||||
}) {
|
||||
final state = computeRealSelectedProxyState(
|
||||
proxyName,
|
||||
groups: groups,
|
||||
selectedMap: selectedMap,
|
||||
);
|
||||
final currentDelayMap = delayMap[state.testUrl.getSafeValue(testUrl)] ?? {};
|
||||
final delay = currentDelayMap[state.proxyName];
|
||||
return DelayState(delay: delay ?? 0, group: state.group);
|
||||
}
|
||||
|
||||
SelectedProxyState computeRealSelectedProxyState(
|
||||
String proxyName, {
|
||||
required List<Group> groups,
|
||||
required SelectedMap selectedMap,
|
||||
}) {
|
||||
return _getRealSelectedProxyState(
|
||||
SelectedProxyState(proxyName: proxyName),
|
||||
groups: groups,
|
||||
selectedMap: selectedMap,
|
||||
);
|
||||
}
|
||||
|
||||
SelectedProxyState _getRealSelectedProxyState(
|
||||
SelectedProxyState state, {
|
||||
required List<Group> groups,
|
||||
required SelectedMap selectedMap,
|
||||
}) {
|
||||
if (state.proxyName.isEmpty) return state;
|
||||
final index = groups.indexWhere((element) => element.name == state.proxyName);
|
||||
final newState = state.copyWith(group: true);
|
||||
if (index == -1) return newState;
|
||||
final group = groups[index];
|
||||
final currentSelectedName = group.getCurrentSelectedName(
|
||||
selectedMap[newState.proxyName] ?? '',
|
||||
);
|
||||
if (currentSelectedName.isEmpty) {
|
||||
return newState;
|
||||
}
|
||||
return _getRealSelectedProxyState(
|
||||
newState.copyWith(proxyName: currentSelectedName, testUrl: group.testUrl),
|
||||
groups: groups,
|
||||
selectedMap: selectedMap,
|
||||
);
|
||||
}
|
||||
|
||||
List<Proxy> _sortOfDelay({
|
||||
required List<Group> groups,
|
||||
required List<Proxy> proxies,
|
||||
required DelayMap delayMap,
|
||||
required SelectedMap selectedMap,
|
||||
required String testUrl,
|
||||
}) {
|
||||
return List.from(proxies)..sort((a, b) {
|
||||
final aDelayState = computeProxyDelayState(
|
||||
proxyName: a.name,
|
||||
testUrl: testUrl,
|
||||
groups: groups,
|
||||
selectedMap: selectedMap,
|
||||
delayMap: delayMap,
|
||||
);
|
||||
final bDelayState = computeProxyDelayState(
|
||||
proxyName: b.name,
|
||||
testUrl: testUrl,
|
||||
groups: groups,
|
||||
selectedMap: selectedMap,
|
||||
delayMap: delayMap,
|
||||
);
|
||||
return aDelayState.compareTo(bDelayState);
|
||||
});
|
||||
}
|
||||
|
||||
List<Proxy> _sortOfName(List<Proxy> proxies) {
|
||||
return List.of(proxies)..sort(
|
||||
(a, b) =>
|
||||
utils.sortByChar(utils.getPinyin(a.name), utils.getPinyin(b.name)),
|
||||
);
|
||||
}
|
||||
@@ -36,8 +36,8 @@ const geoIpFileName = 'GeoIP.dat';
|
||||
const geoSiteFileName = 'GeoSite.dat';
|
||||
final double kHeaderHeight = system.isDesktop
|
||||
? !system.isMacOS
|
||||
? 40
|
||||
: 28
|
||||
? 40
|
||||
: 28
|
||||
: 0;
|
||||
const profilesDirectoryName = 'profiles';
|
||||
const localhost = '127.0.0.1';
|
||||
@@ -84,7 +84,7 @@ const profilesStoreKey = PageStorageKey<String>('profiles');
|
||||
const defaultPrimaryColor = 0XFFD8C0C3;
|
||||
|
||||
double getWidgetHeight(num lines) {
|
||||
return max(lines * 84 + (lines - 1) * 16, 0).ap;
|
||||
return max(lines * 80 + (lines - 1) * 16, 0).ap;
|
||||
}
|
||||
|
||||
const maxLength = 1000;
|
||||
|
||||
@@ -9,23 +9,17 @@ class Debouncer {
|
||||
FunctionTag tag,
|
||||
Function func, {
|
||||
List<dynamic>? args,
|
||||
Duration duration = const Duration(milliseconds: 600),
|
||||
Duration? duration,
|
||||
}) {
|
||||
final timer = _operations[tag];
|
||||
if (timer != null) {
|
||||
timer.cancel();
|
||||
}
|
||||
_operations[tag] = Timer(
|
||||
duration,
|
||||
() {
|
||||
_operations[tag]?.cancel();
|
||||
_operations.remove(tag);
|
||||
Function.apply(
|
||||
func,
|
||||
args,
|
||||
);
|
||||
},
|
||||
);
|
||||
_operations[tag] = Timer(duration ?? const Duration(milliseconds: 600), () {
|
||||
_operations[tag]?.cancel();
|
||||
_operations.remove(tag);
|
||||
Function.apply(func, args);
|
||||
});
|
||||
}
|
||||
|
||||
void cancel(dynamic tag) {
|
||||
@@ -47,17 +41,11 @@ class Throttler {
|
||||
if (timer != null) {
|
||||
return true;
|
||||
}
|
||||
_operations[tag] = Timer(
|
||||
duration,
|
||||
() {
|
||||
_operations[tag]?.cancel();
|
||||
_operations.remove(tag);
|
||||
Function.apply(
|
||||
func,
|
||||
args,
|
||||
);
|
||||
},
|
||||
);
|
||||
_operations[tag] = Timer(duration, () {
|
||||
_operations[tag]?.cancel();
|
||||
_operations.remove(tag);
|
||||
Function.apply(func, args);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:riverpod/riverpod.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
mixin AutoDisposeNotifierMixin<T> on AnyNotifier<T, T> {
|
||||
set value(T value) {
|
||||
@@ -20,3 +21,26 @@ mixin AutoDisposeNotifierMixin<T> on AnyNotifier<T, T> {
|
||||
|
||||
void onUpdate(T value) {}
|
||||
}
|
||||
|
||||
mixin AnyNotifierMixin<T> on AnyNotifier<T, T> {
|
||||
T get value;
|
||||
|
||||
set value(T value) {
|
||||
if (ref.mounted) {
|
||||
state = value;
|
||||
} else {
|
||||
onUpdate(value);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(previous, next) {
|
||||
final res = super.updateShouldNotify(previous, next);
|
||||
if (res) {
|
||||
onUpdate(next);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void onUpdate(T value) {}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,12 @@ class Navigation {
|
||||
keep: false,
|
||||
icon: Icon(Icons.space_dashboard),
|
||||
label: PageLabel.dashboard,
|
||||
builder: (_) =>
|
||||
const DashboardView(key: GlobalObjectKey(PageLabel.dashboard)),
|
||||
builder: (_) => const DashboardView(),
|
||||
),
|
||||
NavigationItem(
|
||||
icon: const Icon(Icons.article),
|
||||
label: PageLabel.proxies,
|
||||
builder: (_) =>
|
||||
const ProxiesView(key: GlobalObjectKey(PageLabel.proxies)),
|
||||
builder: (_) => const ProxiesView(),
|
||||
modes: hasProxies
|
||||
? [NavigationItemMode.mobile, NavigationItemMode.desktop]
|
||||
: [],
|
||||
@@ -30,22 +28,19 @@ class Navigation {
|
||||
NavigationItem(
|
||||
icon: Icon(Icons.folder),
|
||||
label: PageLabel.profiles,
|
||||
builder: (_) =>
|
||||
const ProfilesView(key: GlobalObjectKey(PageLabel.profiles)),
|
||||
builder: (_) => const ProfilesView(),
|
||||
),
|
||||
NavigationItem(
|
||||
icon: Icon(Icons.view_timeline),
|
||||
label: PageLabel.requests,
|
||||
builder: (_) =>
|
||||
const RequestsView(key: GlobalObjectKey(PageLabel.requests)),
|
||||
builder: (_) => const RequestsView(),
|
||||
description: 'requestsDesc',
|
||||
modes: [NavigationItemMode.desktop, NavigationItemMode.more],
|
||||
),
|
||||
NavigationItem(
|
||||
icon: Icon(Icons.ballot),
|
||||
label: PageLabel.connections,
|
||||
builder: (_) =>
|
||||
const ConnectionsView(key: GlobalObjectKey(PageLabel.connections)),
|
||||
builder: (_) => const ConnectionsView(),
|
||||
description: 'connectionsDesc',
|
||||
modes: [NavigationItemMode.desktop, NavigationItemMode.more],
|
||||
),
|
||||
@@ -53,14 +48,13 @@ class Navigation {
|
||||
icon: Icon(Icons.storage),
|
||||
label: PageLabel.resources,
|
||||
description: 'resourcesDesc',
|
||||
builder: (_) =>
|
||||
const ResourcesView(key: GlobalObjectKey(PageLabel.resources)),
|
||||
builder: (_) => const ResourcesView(),
|
||||
modes: [NavigationItemMode.more],
|
||||
),
|
||||
NavigationItem(
|
||||
icon: const Icon(Icons.adb),
|
||||
label: PageLabel.logs,
|
||||
builder: (_) => const LogsView(key: GlobalObjectKey(PageLabel.logs)),
|
||||
builder: (_) => const LogsView(),
|
||||
description: 'logsDesc',
|
||||
modes: openLogs
|
||||
? [NavigationItemMode.desktop, NavigationItemMode.more]
|
||||
@@ -69,7 +63,7 @@ class Navigation {
|
||||
NavigationItem(
|
||||
icon: Icon(Icons.construction),
|
||||
label: PageLabel.tools,
|
||||
builder: (_) => const ToolsView(key: GlobalObjectKey(PageLabel.tools)),
|
||||
builder: (_) => const ToolsView(),
|
||||
modes: [NavigationItemMode.desktop, NavigationItemMode.mobile],
|
||||
),
|
||||
];
|
||||
|
||||
@@ -10,6 +10,7 @@ class AppPath {
|
||||
Completer<Directory> dataDir = Completer();
|
||||
Completer<Directory> downloadDir = Completer();
|
||||
Completer<Directory> tempDir = Completer();
|
||||
Completer<Directory> cacheDir = Completer();
|
||||
late String appDirPath;
|
||||
|
||||
AppPath._internal() {
|
||||
@@ -23,6 +24,9 @@ class AppPath {
|
||||
getDownloadsDirectory().then((value) {
|
||||
downloadDir.complete(value);
|
||||
});
|
||||
getApplicationCacheDirectory().then((value) {
|
||||
cacheDir.complete(value);
|
||||
});
|
||||
}
|
||||
|
||||
factory AppPath() {
|
||||
@@ -82,6 +86,11 @@ class AppPath {
|
||||
return join(directory, '$id.yaml');
|
||||
}
|
||||
|
||||
Future<String> getIconsCacheDir() async {
|
||||
final directory = await cacheDir.future;
|
||||
return join(directory.path, 'icons');
|
||||
}
|
||||
|
||||
Future<String> getProvidersRootPath() async {
|
||||
final directory = await profilesPath;
|
||||
return join(directory, 'providers');
|
||||
|
||||
@@ -16,30 +16,24 @@ class Request {
|
||||
String? userAgent;
|
||||
|
||||
Request() {
|
||||
_dio = Dio(
|
||||
BaseOptions(
|
||||
headers: {
|
||||
'User-Agent': browserUa,
|
||||
},
|
||||
),
|
||||
);
|
||||
_dio = Dio(BaseOptions(headers: {'User-Agent': browserUa}));
|
||||
_clashDio = Dio();
|
||||
_clashDio.httpClientAdapter = IOHttpClientAdapter(createHttpClient: () {
|
||||
final client = HttpClient();
|
||||
client.findProxy = (Uri uri) {
|
||||
client.userAgent = globalState.ua;
|
||||
return FlClashHttpOverrides.handleFindProxy(uri);
|
||||
};
|
||||
return client;
|
||||
});
|
||||
_clashDio.httpClientAdapter = IOHttpClientAdapter(
|
||||
createHttpClient: () {
|
||||
final client = HttpClient();
|
||||
client.findProxy = (Uri uri) {
|
||||
client.userAgent = globalState.ua;
|
||||
return FlClashHttpOverrides.handleFindProxy(uri);
|
||||
};
|
||||
return client;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<Response> getFileResponseForUrl(String url) async {
|
||||
final response = await _clashDio.get(
|
||||
url,
|
||||
options: Options(
|
||||
responseType: ResponseType.bytes,
|
||||
),
|
||||
options: Options(responseType: ResponseType.bytes),
|
||||
);
|
||||
return response;
|
||||
}
|
||||
@@ -47,9 +41,7 @@ class Request {
|
||||
Future<Response> getTextResponseForUrl(String url) async {
|
||||
final response = await _clashDio.get(
|
||||
url,
|
||||
options: Options(
|
||||
responseType: ResponseType.plain,
|
||||
),
|
||||
options: Options(responseType: ResponseType.plain),
|
||||
);
|
||||
return response;
|
||||
}
|
||||
@@ -58,9 +50,7 @@ class Request {
|
||||
if (url.isEmpty) return null;
|
||||
final response = await _dio.get<Uint8List>(
|
||||
url,
|
||||
options: Options(
|
||||
responseType: ResponseType.bytes,
|
||||
),
|
||||
options: Options(responseType: ResponseType.bytes),
|
||||
);
|
||||
final data = response.data;
|
||||
if (data == null) return null;
|
||||
@@ -70,9 +60,7 @@ class Request {
|
||||
Future<Map<String, dynamic>?> checkForUpdate() async {
|
||||
final response = await _dio.get(
|
||||
'https://api.github.com/repos/$repository/releases/latest',
|
||||
options: Options(
|
||||
responseType: ResponseType.json,
|
||||
),
|
||||
options: Options(responseType: ResponseType.json),
|
||||
);
|
||||
if (response.statusCode != 200) return null;
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
@@ -85,9 +73,12 @@ class Request {
|
||||
}
|
||||
|
||||
final Map<String, IpInfo Function(Map<String, dynamic>)> _ipInfoSources = {
|
||||
'https://ipwho.is/': IpInfo.fromIpwhoIsJson,
|
||||
'https://api.ip.sb/geoip/': IpInfo.fromIpSbJson,
|
||||
'https://ipwho.is/': IpInfo.fromIpWhoIsJson,
|
||||
'https://api.myip.com/': IpInfo.fromMyIpJson,
|
||||
'https://ipapi.co/json/': IpInfo.fromIpApiCoJson,
|
||||
'https://ident.me/json/': IpInfo.fromIdentMeJson,
|
||||
'http://ip-api.com/json/': IpInfo.fromIpAPIJson,
|
||||
'https://api.ip.sb/geoip/': IpInfo.fromIpSbJson,
|
||||
'https://ipinfo.io/json/': IpInfo.fromIpInfoIoJson,
|
||||
};
|
||||
|
||||
@@ -101,27 +92,28 @@ class Request {
|
||||
}
|
||||
}
|
||||
|
||||
final future = Dio().get<Map<String, dynamic>>(
|
||||
final future = _dio.get<Map<String, dynamic>>(
|
||||
source.key,
|
||||
cancelToken: cancelToken,
|
||||
options: Options(
|
||||
responseType: ResponseType.json,
|
||||
),
|
||||
options: Options(responseType: ResponseType.json),
|
||||
);
|
||||
future.then((res) {
|
||||
if (res.statusCode == HttpStatus.ok && res.data != null) {
|
||||
completer.complete(Result.success(source.value(res.data!)));
|
||||
} else {
|
||||
failureCount++;
|
||||
handleFailRes();
|
||||
}
|
||||
}).catchError((e) {
|
||||
failureCount++;
|
||||
if (e is DioException && e.type == DioExceptionType.cancel) {
|
||||
completer.complete(Result.error('cancelled'));
|
||||
}
|
||||
handleFailRes();
|
||||
});
|
||||
future
|
||||
.then((res) {
|
||||
if (res.statusCode == HttpStatus.ok && res.data != null) {
|
||||
completer.complete(Result.success(source.value(res.data!)));
|
||||
return;
|
||||
}
|
||||
failureCount++;
|
||||
handleFailRes();
|
||||
})
|
||||
.catchError((e) {
|
||||
print(e);
|
||||
failureCount++;
|
||||
if (e is DioException && e.type == DioExceptionType.cancel) {
|
||||
completer.complete(Result.error('cancelled'));
|
||||
}
|
||||
handleFailRes();
|
||||
});
|
||||
return completer.future;
|
||||
});
|
||||
final res = await Future.any(futures);
|
||||
@@ -134,15 +126,9 @@ class Request {
|
||||
final response = await _dio
|
||||
.get(
|
||||
'http://$localhost:$helperPort/ping',
|
||||
options: Options(
|
||||
responseType: ResponseType.plain,
|
||||
),
|
||||
options: Options(responseType: ResponseType.plain),
|
||||
)
|
||||
.timeout(
|
||||
const Duration(
|
||||
milliseconds: 2000,
|
||||
),
|
||||
);
|
||||
.timeout(const Duration(milliseconds: 2000));
|
||||
if (response.statusCode != HttpStatus.ok) {
|
||||
return false;
|
||||
}
|
||||
@@ -157,19 +143,10 @@ class Request {
|
||||
final response = await _dio
|
||||
.post(
|
||||
'http://$localhost:$helperPort/start',
|
||||
data: json.encode({
|
||||
'path': appPath.corePath,
|
||||
'arg': arg,
|
||||
}),
|
||||
options: Options(
|
||||
responseType: ResponseType.plain,
|
||||
),
|
||||
data: json.encode({'path': appPath.corePath, 'arg': arg}),
|
||||
options: Options(responseType: ResponseType.plain),
|
||||
)
|
||||
.timeout(
|
||||
const Duration(
|
||||
milliseconds: 2000,
|
||||
),
|
||||
);
|
||||
.timeout(const Duration(milliseconds: 2000));
|
||||
if (response.statusCode != HttpStatus.ok) {
|
||||
return false;
|
||||
}
|
||||
@@ -185,15 +162,9 @@ class Request {
|
||||
final response = await _dio
|
||||
.post(
|
||||
'http://$localhost:$helperPort/stop',
|
||||
options: Options(
|
||||
responseType: ResponseType.plain,
|
||||
),
|
||||
options: Options(responseType: ResponseType.plain),
|
||||
)
|
||||
.timeout(
|
||||
const Duration(
|
||||
milliseconds: 2000,
|
||||
),
|
||||
);
|
||||
.timeout(const Duration(milliseconds: 2000));
|
||||
if (response.statusCode != HttpStatus.ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -21,16 +21,15 @@ class Utils {
|
||||
String get id {
|
||||
final timestamp = DateTime.now().microsecondsSinceEpoch;
|
||||
final random = Random();
|
||||
final randomStr =
|
||||
String.fromCharCodes(List.generate(8, (_) => random.nextInt(26) + 97));
|
||||
final randomStr = String.fromCharCodes(
|
||||
List.generate(8, (_) => random.nextInt(26) + 97),
|
||||
);
|
||||
return '$timestamp$randomStr';
|
||||
}
|
||||
|
||||
String getDateStringLast2(int value) {
|
||||
var valueRaw = '0$value';
|
||||
return valueRaw.substring(
|
||||
valueRaw.length - 2,
|
||||
);
|
||||
return valueRaw.substring(valueRaw.length - 2);
|
||||
}
|
||||
|
||||
String generateRandomString({int minLength = 10, int maxLength = 100}) {
|
||||
@@ -43,8 +42,9 @@ class Utils {
|
||||
String result = '';
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (random.nextBool()) {
|
||||
result +=
|
||||
String.fromCharCode(0x4E00 + random.nextInt(0x9FA5 - 0x4E00 + 1));
|
||||
result += String.fromCharCode(
|
||||
0x4E00 + random.nextInt(0x9FA5 - 0x4E00 + 1),
|
||||
);
|
||||
} else {
|
||||
result += latinChars[random.nextInt(latinChars.length)];
|
||||
}
|
||||
@@ -60,8 +60,9 @@ class Utils {
|
||||
bytes[6] = (bytes[6] & 0x0F) | 0x40;
|
||||
bytes[8] = (bytes[8] & 0x3F) | 0x80;
|
||||
|
||||
final hex =
|
||||
bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join();
|
||||
final hex = bytes
|
||||
.map((byte) => byte.toRadixString(16).padLeft(2, '0'))
|
||||
.join();
|
||||
|
||||
return '${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${hex.substring(20, 32)}';
|
||||
}
|
||||
@@ -102,9 +103,10 @@ class Utils {
|
||||
}
|
||||
if (localSplit.length == 3) {
|
||||
return Locale.fromSubtags(
|
||||
languageCode: localSplit[0],
|
||||
scriptCode: localSplit[1],
|
||||
countryCode: localSplit[2]);
|
||||
languageCode: localSplit[0],
|
||||
scriptCode: localSplit[1],
|
||||
countryCode: localSplit[2],
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -141,9 +143,7 @@ class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
String getTrayIconPath({
|
||||
required Brightness brightness,
|
||||
}) {
|
||||
String getTrayIconPath({required Brightness brightness}) {
|
||||
if (system.isMacOS) {
|
||||
return 'assets/images/icon_white.png';
|
||||
}
|
||||
@@ -188,16 +188,20 @@ class Utils {
|
||||
if (disposition == null) return null;
|
||||
final parseValue = HeaderValue.parse(disposition);
|
||||
final parameters = parseValue.parameters;
|
||||
final fileNamePointKey = parameters.keys
|
||||
.firstWhere((key) => key == 'filename*', orElse: () => '');
|
||||
final fileNamePointKey = parameters.keys.firstWhere(
|
||||
(key) => key == 'filename*',
|
||||
orElse: () => '',
|
||||
);
|
||||
if (fileNamePointKey.isNotEmpty) {
|
||||
final res = parameters[fileNamePointKey]?.split("''") ?? [];
|
||||
if (res.length >= 2) {
|
||||
return Uri.decodeComponent(res[1]);
|
||||
}
|
||||
}
|
||||
final fileNameKey = parameters.keys
|
||||
.firstWhere((key) => key == 'filename', orElse: () => '');
|
||||
final fileNameKey = parameters.keys.firstWhere(
|
||||
(key) => key == 'filename',
|
||||
orElse: () => '',
|
||||
);
|
||||
if (fileNameKey.isEmpty) return null;
|
||||
return parameters[fileNameKey];
|
||||
}
|
||||
@@ -236,19 +240,7 @@ class Utils {
|
||||
return max((viewWidth / 320).floor(), 1);
|
||||
}
|
||||
|
||||
final _indexPrimary = [
|
||||
50,
|
||||
100,
|
||||
200,
|
||||
300,
|
||||
400,
|
||||
500,
|
||||
600,
|
||||
700,
|
||||
800,
|
||||
850,
|
||||
900,
|
||||
];
|
||||
final _indexPrimary = [50, 100, 200, 300, 400, 500, 600, 700, 800, 850, 900];
|
||||
|
||||
MaterialColor _createPrimarySwatch(Color color) {
|
||||
final Map<int, Color> swatch = <int, Color>{};
|
||||
@@ -302,16 +294,15 @@ class Utils {
|
||||
}
|
||||
|
||||
Future<String?> getLocalIpAddress() async {
|
||||
List<NetworkInterface> interfaces = await NetworkInterface.list(
|
||||
includeLoopback: false,
|
||||
)
|
||||
..sort((a, b) {
|
||||
if (a.isWifi && !b.isWifi) return -1;
|
||||
if (!a.isWifi && b.isWifi) return 1;
|
||||
if (a.includesIPv4 && !b.includesIPv4) return -1;
|
||||
if (!a.includesIPv4 && b.includesIPv4) return 1;
|
||||
return 0;
|
||||
});
|
||||
List<NetworkInterface> interfaces =
|
||||
await NetworkInterface.list(includeLoopback: false)
|
||||
..sort((a, b) {
|
||||
if (a.isWifi && !b.isWifi) return -1;
|
||||
if (!a.isWifi && b.isWifi) return 1;
|
||||
if (a.includesIPv4 && !b.includesIPv4) return -1;
|
||||
if (!a.includesIPv4 && b.includesIPv4) return 1;
|
||||
return 0;
|
||||
});
|
||||
for (final interface in interfaces) {
|
||||
final addresses = interface.addresses;
|
||||
if (addresses.isEmpty) {
|
||||
@@ -329,59 +320,9 @@ class Utils {
|
||||
|
||||
SingleActivator controlSingleActivator(LogicalKeyboardKey trigger) {
|
||||
final control = system.isMacOS ? false : true;
|
||||
return SingleActivator(
|
||||
trigger,
|
||||
control: control,
|
||||
meta: !control,
|
||||
);
|
||||
return SingleActivator(trigger, control: control, meta: !control);
|
||||
}
|
||||
|
||||
// dynamic convertYamlNode(dynamic node) {
|
||||
// if (node is YamlMap) {
|
||||
// final map = <String, dynamic>{};
|
||||
// YamlNode? mergeKeyNode;
|
||||
// for (final entry in node.nodes.entries) {
|
||||
// if (entry.key is YamlScalar &&
|
||||
// (entry.key as YamlScalar).value == '<<') {
|
||||
// mergeKeyNode = entry.value;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (mergeKeyNode != null) {
|
||||
// final mergeValue = mergeKeyNode.value;
|
||||
// if (mergeValue is YamlMap) {
|
||||
// map.addAll(convertYamlNode(mergeValue) as Map<String, dynamic>);
|
||||
// } else if (mergeValue is YamlList) {
|
||||
// for (final node in mergeValue.nodes) {
|
||||
// if (node.value is YamlMap) {
|
||||
// map.addAll(convertYamlNode(node.value) as Map<String, dynamic>);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// node.nodes.forEach((key, value) {
|
||||
// String stringKey;
|
||||
// if (key is YamlScalar) {
|
||||
// stringKey = key.value.toString();
|
||||
// } else {
|
||||
// stringKey = key.toString();
|
||||
// }
|
||||
// map[stringKey] = convertYamlNode(value.value);
|
||||
// });
|
||||
// return map;
|
||||
// } else if (node is YamlList) {
|
||||
// final list = <dynamic>[];
|
||||
// for (final item in node.nodes) {
|
||||
// list.add(convertYamlNode(item.value));
|
||||
// }
|
||||
// return list;
|
||||
// } else if (node is YamlScalar) {
|
||||
// return node.value;
|
||||
// }
|
||||
// return node;
|
||||
// }
|
||||
|
||||
FutureOr<T> handleWatch<T>(Function function) async {
|
||||
if (kDebugMode) {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
|
||||
@@ -41,8 +41,8 @@ class AppController {
|
||||
});
|
||||
}
|
||||
|
||||
void updateGroupsDebounce() {
|
||||
debouncer.call(FunctionTag.updateGroups, updateGroups);
|
||||
void updateGroupsDebounce([Duration? duration]) {
|
||||
debouncer.call(FunctionTag.updateGroups, updateGroups, duration: duration);
|
||||
}
|
||||
|
||||
void addCheckIpNumDebounce() {
|
||||
@@ -231,10 +231,6 @@ class AppController {
|
||||
return currentGroupName;
|
||||
}
|
||||
|
||||
ProxyCardState getProxyCardState(String proxyName) {
|
||||
return _ref.read(getProxyCardStateProvider(proxyName));
|
||||
}
|
||||
|
||||
String? getSelectedProxyName(String groupName) {
|
||||
return _ref.read(getSelectedProxyNameProvider(groupName));
|
||||
}
|
||||
@@ -366,7 +362,22 @@ class AppController {
|
||||
try {
|
||||
_ref.read(groupsProvider.notifier).value = await retry(
|
||||
task: () async {
|
||||
return await coreController.getProxiesGroups();
|
||||
final sortType = _ref.read(
|
||||
proxiesStyleSettingProvider.select((state) => state.sortType),
|
||||
);
|
||||
final delayMap = _ref.read(delayDataSourceProvider);
|
||||
final testUrl = _ref.read(
|
||||
appSettingProvider.select((state) => state.testUrl),
|
||||
);
|
||||
final selectedMap = _ref.read(
|
||||
currentProfileProvider.select((state) => state?.selectedMap ?? {}),
|
||||
);
|
||||
return await coreController.getProxiesGroups(
|
||||
selectedMap: selectedMap,
|
||||
sortType: sortType,
|
||||
delayMap: delayMap,
|
||||
defaultTestUrl: testUrl,
|
||||
);
|
||||
},
|
||||
retryIf: (res) => res.isEmpty,
|
||||
);
|
||||
@@ -691,47 +702,7 @@ class AppController {
|
||||
_ref.read(providersProvider.notifier).setProvider(provider);
|
||||
}
|
||||
|
||||
List<Proxy> _sortOfName(List<Proxy> proxies) {
|
||||
return List.of(proxies)..sort(
|
||||
(a, b) =>
|
||||
utils.sortByChar(utils.getPinyin(a.name), utils.getPinyin(b.name)),
|
||||
);
|
||||
}
|
||||
|
||||
List<Proxy> _sortOfDelay({required List<Proxy> proxies, String? testUrl}) {
|
||||
return List.of(proxies)..sort((a, b) {
|
||||
final aDelay = _ref.read(
|
||||
getDelayProvider(proxyName: a.name, testUrl: testUrl),
|
||||
);
|
||||
final bDelay = _ref.read(
|
||||
getDelayProvider(proxyName: b.name, testUrl: testUrl),
|
||||
);
|
||||
if (aDelay == null && bDelay == null) {
|
||||
return 0;
|
||||
}
|
||||
if (aDelay == null || aDelay == -1) {
|
||||
return 1;
|
||||
}
|
||||
if (bDelay == null || bDelay == -1) {
|
||||
return -1;
|
||||
}
|
||||
return aDelay.compareTo(bDelay);
|
||||
});
|
||||
}
|
||||
|
||||
List<Proxy> getSortProxies({
|
||||
required List<Proxy> proxies,
|
||||
required ProxiesSortType sortType,
|
||||
String? testUrl,
|
||||
}) {
|
||||
return switch (sortType) {
|
||||
ProxiesSortType.none => proxies,
|
||||
ProxiesSortType.delay => _sortOfDelay(proxies: proxies, testUrl: testUrl),
|
||||
ProxiesSortType.name => _sortOfName(proxies),
|
||||
};
|
||||
}
|
||||
|
||||
Future<Null> clearEffect(String profileId) async {
|
||||
Future<void> clearEffect(String profileId) async {
|
||||
final profilePath = await appPath.getProfilePath(profileId);
|
||||
final providersDirPath = await appPath.getProvidersDirPath(profileId);
|
||||
return await Isolate.run(() async {
|
||||
@@ -740,11 +711,7 @@ class AppController {
|
||||
if (isExists) {
|
||||
profileFile.delete(recursive: true);
|
||||
}
|
||||
final providersFileDir = File(providersDirPath);
|
||||
final providersFileIsExists = await providersFileDir.exists();
|
||||
if (providersFileIsExists) {
|
||||
providersFileDir.delete(recursive: true);
|
||||
}
|
||||
await coreController.deleteFile(providersDirPath);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -90,25 +90,39 @@ class CoreController {
|
||||
return await _interface.setupConfig(params);
|
||||
}
|
||||
|
||||
Future<List<Group>> getProxiesGroups() async {
|
||||
Future<List<Group>> getProxiesGroups({
|
||||
required ProxiesSortType sortType,
|
||||
required DelayMap delayMap,
|
||||
required SelectedMap selectedMap,
|
||||
required String defaultTestUrl,
|
||||
}) async {
|
||||
final proxies = await _interface.getProxies();
|
||||
if (proxies.isEmpty) return [];
|
||||
final groupNames = [
|
||||
UsedProxy.GLOBAL.name,
|
||||
...(proxies[UsedProxy.GLOBAL.name]['all'] as List).where((e) {
|
||||
final proxy = proxies[e] ?? {};
|
||||
return GroupTypeExtension.valueList.contains(proxy['type']);
|
||||
}),
|
||||
];
|
||||
final groupsRaw = groupNames.map((groupName) {
|
||||
final group = proxies[groupName];
|
||||
group['all'] = ((group['all'] ?? []) as List)
|
||||
.map((name) => proxies[name])
|
||||
.where((proxy) => proxy != null)
|
||||
.toList();
|
||||
return group;
|
||||
}).toList();
|
||||
return groupsRaw.map((e) => Group.fromJson(e)).toList();
|
||||
return Isolate.run<List<Group>>(() {
|
||||
if (proxies.isEmpty) return [];
|
||||
final groupNames = [
|
||||
UsedProxy.GLOBAL.name,
|
||||
...(proxies[UsedProxy.GLOBAL.name]['all'] as List).where((e) {
|
||||
final proxy = proxies[e] ?? {};
|
||||
return GroupTypeExtension.valueList.contains(proxy['type']);
|
||||
}),
|
||||
];
|
||||
final groupsRaw = groupNames.map((groupName) {
|
||||
final group = proxies[groupName];
|
||||
group['all'] = ((group['all'] ?? []) as List)
|
||||
.map((name) => proxies[name])
|
||||
.where((proxy) => proxy != null)
|
||||
.toList();
|
||||
return group;
|
||||
}).toList();
|
||||
final groups = groupsRaw.map((e) => Group.fromJson(e)).toList();
|
||||
return computeSort(
|
||||
groups: groups,
|
||||
sortType: sortType,
|
||||
delayMap: delayMap,
|
||||
selectedMap: selectedMap,
|
||||
defaultTestUrl: defaultTestUrl,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
FutureOr<String> changeProxy(ChangeProxyParams changeProxyParams) async {
|
||||
@@ -258,6 +272,10 @@ class CoreController {
|
||||
Future<void> crash() async {
|
||||
await _interface.crash();
|
||||
}
|
||||
|
||||
Future<String> deleteFile(String path) async {
|
||||
return await _interface.deleteFile(path);
|
||||
}
|
||||
}
|
||||
|
||||
final coreController = CoreController();
|
||||
|
||||
@@ -68,6 +68,8 @@ mixin CoreInterface {
|
||||
|
||||
FutureOr<bool> closeConnection(String id);
|
||||
|
||||
FutureOr<String> deleteFile(String path);
|
||||
|
||||
FutureOr<bool> closeConnections();
|
||||
|
||||
FutureOr<bool> resetConnections();
|
||||
@@ -263,6 +265,12 @@ abstract class CoreHandlerInterface with CoreInterface {
|
||||
'';
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> deleteFile(String path) async {
|
||||
return await _invoke<String>(method: ActionMethod.deleteFile, data: path) ??
|
||||
'';
|
||||
}
|
||||
|
||||
@override
|
||||
resetTraffic() {
|
||||
_invoke(method: ActionMethod.resetTraffic);
|
||||
|
||||
@@ -243,6 +243,7 @@ enum ActionMethod {
|
||||
getMemory,
|
||||
crash,
|
||||
setupConfig,
|
||||
deleteFile,
|
||||
|
||||
///Android,
|
||||
setState,
|
||||
|
||||
@@ -28,10 +28,9 @@ class AppLocalizations {
|
||||
static const AppLocalizationDelegate delegate = AppLocalizationDelegate();
|
||||
|
||||
static Future<AppLocalizations> load(Locale locale) {
|
||||
final name =
|
||||
(locale.countryCode?.isEmpty ?? false)
|
||||
? locale.languageCode
|
||||
: locale.toString();
|
||||
final name = (locale.countryCode?.isEmpty ?? false)
|
||||
? locale.languageCode
|
||||
: locale.toString();
|
||||
final localeName = Intl.canonicalizedLocale(name);
|
||||
return initializeMessages(localeName).then((_) {
|
||||
Intl.defaultLocale = localeName;
|
||||
|
||||
@@ -43,6 +43,11 @@ class _AppStateManagerState extends ConsumerState<AppStateManager>
|
||||
globalState.appController.savePreferencesDebounce();
|
||||
}
|
||||
});
|
||||
ref.listenManual(needUpdateGroupsProvider, (prev, next) {
|
||||
if (prev != next) {
|
||||
globalState.appController.updateGroupsDebounce(commonDuration);
|
||||
}
|
||||
});
|
||||
if (window == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// ignore_for_file: invalid_annotation_target
|
||||
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// ignore_for_file: invalid_annotation_target
|
||||
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -365,13 +363,41 @@ abstract class IpInfo with _$IpInfo {
|
||||
};
|
||||
}
|
||||
|
||||
static IpInfo fromIpwhoIsJson(Map<String, dynamic> 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'),
|
||||
};
|
||||
}
|
||||
|
||||
static IpInfo fromMyIpJson(Map<String, dynamic> json) {
|
||||
return switch (json) {
|
||||
{'ip': final String ip, 'cc': final String countryCode} => IpInfo(
|
||||
ip: ip,
|
||||
countryCode: countryCode,
|
||||
),
|
||||
_ => throw const FormatException('invalid json'),
|
||||
};
|
||||
}
|
||||
|
||||
static IpInfo fromIpAPIJson(Map<String, dynamic> json) {
|
||||
return switch (json) {
|
||||
{'query': final String ip, 'countryCode': final String countryCode} =>
|
||||
IpInfo(ip: ip, countryCode: countryCode),
|
||||
_ => throw const FormatException('invalid json'),
|
||||
};
|
||||
}
|
||||
|
||||
static IpInfo fromIdentMeJson(Map<String, dynamic> json) {
|
||||
return switch (json) {
|
||||
{'ip': final String ip, 'cc': final String countryCode} => IpInfo(
|
||||
ip: ip,
|
||||
countryCode: countryCode,
|
||||
),
|
||||
_ => throw const FormatException('invalid json'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
@@ -464,3 +490,29 @@ abstract class Script with _$Script {
|
||||
|
||||
factory Script.fromJson(Map<String, Object?> json) => _$ScriptFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class DelayState with _$DelayState {
|
||||
const factory DelayState({required int delay, required bool group}) =
|
||||
_DelayState;
|
||||
}
|
||||
|
||||
extension DelayStateExt on DelayState {
|
||||
int get priority {
|
||||
if (delay > 0) return 0;
|
||||
if (delay == 0) return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int compareTo(DelayState other) {
|
||||
if (priority != other.priority) {
|
||||
return priority.compareTo(other.priority);
|
||||
}
|
||||
if (delay != other.delay) {
|
||||
return delay.compareTo(other.delay);
|
||||
}
|
||||
if (group && !group) return -1;
|
||||
if (!group && group) return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// ignore_for_file: invalid_annotation_target
|
||||
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -27,7 +25,7 @@ const defaultBypassDomain = [
|
||||
'172.2*',
|
||||
'172.30.*',
|
||||
'172.31.*',
|
||||
'192.168.*'
|
||||
'192.168.*',
|
||||
];
|
||||
|
||||
const defaultAppSettingProps = AppSettingProps();
|
||||
@@ -36,9 +34,7 @@ const defaultNetworkProps = NetworkProps();
|
||||
const defaultProxiesStyle = ProxiesStyle();
|
||||
const defaultWindowProps = WindowProps();
|
||||
const defaultAccessControl = AccessControl();
|
||||
final defaultThemeProps = ThemeProps(
|
||||
primaryColor: defaultPrimaryColor,
|
||||
);
|
||||
final defaultThemeProps = ThemeProps(primaryColor: defaultPrimaryColor);
|
||||
|
||||
const List<DashboardWidget> defaultDashboardWidgets = [
|
||||
DashboardWidget.networkSpeed,
|
||||
@@ -115,9 +111,9 @@ abstract class AccessControl with _$AccessControl {
|
||||
|
||||
extension AccessControlExt on AccessControl {
|
||||
List<String> get currentList => switch (mode) {
|
||||
AccessControlMode.acceptSelected => acceptList,
|
||||
AccessControlMode.rejectSelected => rejectList,
|
||||
};
|
||||
AccessControlMode.acceptSelected => acceptList,
|
||||
AccessControlMode.rejectSelected => rejectList,
|
||||
};
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// ignore_for_file: invalid_annotation_target
|
||||
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/models/models.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
@@ -5768,6 +5768,266 @@ as String,
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$DelayState {
|
||||
|
||||
int get delay; bool get group;
|
||||
/// Create a copy of DelayState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$DelayStateCopyWith<DelayState> get copyWith => _$DelayStateCopyWithImpl<DelayState>(this as DelayState, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is DelayState&&(identical(other.delay, delay) || other.delay == delay)&&(identical(other.group, group) || other.group == group));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,delay,group);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DelayState(delay: $delay, group: $group)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $DelayStateCopyWith<$Res> {
|
||||
factory $DelayStateCopyWith(DelayState value, $Res Function(DelayState) _then) = _$DelayStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
int delay, bool group
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$DelayStateCopyWithImpl<$Res>
|
||||
implements $DelayStateCopyWith<$Res> {
|
||||
_$DelayStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final DelayState _self;
|
||||
final $Res Function(DelayState) _then;
|
||||
|
||||
/// Create a copy of DelayState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? delay = null,Object? group = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
delay: null == delay ? _self.delay : delay // ignore: cast_nullable_to_non_nullable
|
||||
as int,group: null == group ? _self.group : group // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [DelayState].
|
||||
extension DelayStatePatterns on DelayState {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _DelayState value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _DelayState() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _DelayState value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _DelayState():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _DelayState value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _DelayState() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int delay, bool group)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _DelayState() when $default != null:
|
||||
return $default(_that.delay,_that.group);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int delay, bool group) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _DelayState():
|
||||
return $default(_that.delay,_that.group);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int delay, bool group)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _DelayState() when $default != null:
|
||||
return $default(_that.delay,_that.group);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _DelayState implements DelayState {
|
||||
const _DelayState({required this.delay, required this.group});
|
||||
|
||||
|
||||
@override final int delay;
|
||||
@override final bool group;
|
||||
|
||||
/// Create a copy of DelayState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$DelayStateCopyWith<_DelayState> get copyWith => __$DelayStateCopyWithImpl<_DelayState>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _DelayState&&(identical(other.delay, delay) || other.delay == delay)&&(identical(other.group, group) || other.group == group));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,delay,group);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DelayState(delay: $delay, group: $group)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$DelayStateCopyWith<$Res> implements $DelayStateCopyWith<$Res> {
|
||||
factory _$DelayStateCopyWith(_DelayState value, $Res Function(_DelayState) _then) = __$DelayStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
int delay, bool group
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$DelayStateCopyWithImpl<$Res>
|
||||
implements _$DelayStateCopyWith<$Res> {
|
||||
__$DelayStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _DelayState _self;
|
||||
final $Res Function(_DelayState) _then;
|
||||
|
||||
/// Create a copy of DelayState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? delay = null,Object? group = null,}) {
|
||||
return _then(_DelayState(
|
||||
delay: null == delay ? _self.delay : delay // ignore: cast_nullable_to_non_nullable
|
||||
as int,group: null == group ? _self.group : group // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
|
||||
@@ -291,6 +291,7 @@ const _$ActionMethodEnumMap = {
|
||||
ActionMethod.getMemory: 'getMemory',
|
||||
ActionMethod.crash: 'crash',
|
||||
ActionMethod.setupConfig: 'setupConfig',
|
||||
ActionMethod.deleteFile: 'deleteFile',
|
||||
ActionMethod.setState: 'setState',
|
||||
ActionMethod.startTun: 'startTun',
|
||||
ActionMethod.stopTun: 'stopTun',
|
||||
|
||||
@@ -2982,7 +2982,7 @@ as List<NavigationItem>,
|
||||
/// @nodoc
|
||||
mixin _$ProxiesListState {
|
||||
|
||||
List<Group> get groups; Set<String> get currentUnfoldSet; ProxiesSortType get proxiesSortType; ProxyCardType get proxyCardType; num get sortNum; int get columns;
|
||||
List<Group> get groups; Set<String> get currentUnfoldSet; ProxyCardType get proxyCardType; int get columns;
|
||||
/// Create a copy of ProxiesListState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -2993,16 +2993,16 @@ $ProxiesListStateCopyWith<ProxiesListState> get copyWith => _$ProxiesListStateCo
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ProxiesListState&&const DeepCollectionEquality().equals(other.groups, groups)&&const DeepCollectionEquality().equals(other.currentUnfoldSet, currentUnfoldSet)&&(identical(other.proxiesSortType, proxiesSortType) || other.proxiesSortType == proxiesSortType)&&(identical(other.proxyCardType, proxyCardType) || other.proxyCardType == proxyCardType)&&(identical(other.sortNum, sortNum) || other.sortNum == sortNum)&&(identical(other.columns, columns) || other.columns == columns));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ProxiesListState&&const DeepCollectionEquality().equals(other.groups, groups)&&const DeepCollectionEquality().equals(other.currentUnfoldSet, currentUnfoldSet)&&(identical(other.proxyCardType, proxyCardType) || other.proxyCardType == proxyCardType)&&(identical(other.columns, columns) || other.columns == columns));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(groups),const DeepCollectionEquality().hash(currentUnfoldSet),proxiesSortType,proxyCardType,sortNum,columns);
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(groups),const DeepCollectionEquality().hash(currentUnfoldSet),proxyCardType,columns);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxiesListState(groups: $groups, currentUnfoldSet: $currentUnfoldSet, proxiesSortType: $proxiesSortType, proxyCardType: $proxyCardType, sortNum: $sortNum, columns: $columns)';
|
||||
return 'ProxiesListState(groups: $groups, currentUnfoldSet: $currentUnfoldSet, proxyCardType: $proxyCardType, columns: $columns)';
|
||||
}
|
||||
|
||||
|
||||
@@ -3013,7 +3013,7 @@ abstract mixin class $ProxiesListStateCopyWith<$Res> {
|
||||
factory $ProxiesListStateCopyWith(ProxiesListState value, $Res Function(ProxiesListState) _then) = _$ProxiesListStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
List<Group> groups, Set<String> currentUnfoldSet, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns
|
||||
List<Group> groups, Set<String> currentUnfoldSet, ProxyCardType proxyCardType, int columns
|
||||
});
|
||||
|
||||
|
||||
@@ -3030,14 +3030,12 @@ class _$ProxiesListStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of ProxiesListState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? groups = null,Object? currentUnfoldSet = null,Object? proxiesSortType = null,Object? proxyCardType = null,Object? sortNum = null,Object? columns = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? groups = null,Object? currentUnfoldSet = null,Object? proxyCardType = null,Object? columns = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
groups: null == groups ? _self.groups : groups // ignore: cast_nullable_to_non_nullable
|
||||
as List<Group>,currentUnfoldSet: null == currentUnfoldSet ? _self.currentUnfoldSet : currentUnfoldSet // ignore: cast_nullable_to_non_nullable
|
||||
as Set<String>,proxiesSortType: null == proxiesSortType ? _self.proxiesSortType : proxiesSortType // ignore: cast_nullable_to_non_nullable
|
||||
as ProxiesSortType,proxyCardType: null == proxyCardType ? _self.proxyCardType : proxyCardType // ignore: cast_nullable_to_non_nullable
|
||||
as ProxyCardType,sortNum: null == sortNum ? _self.sortNum : sortNum // ignore: cast_nullable_to_non_nullable
|
||||
as num,columns: null == columns ? _self.columns : columns // ignore: cast_nullable_to_non_nullable
|
||||
as Set<String>,proxyCardType: null == proxyCardType ? _self.proxyCardType : proxyCardType // ignore: cast_nullable_to_non_nullable
|
||||
as ProxyCardType,columns: null == columns ? _self.columns : columns // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
@@ -3123,10 +3121,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<Group> groups, Set<String> currentUnfoldSet, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<Group> groups, Set<String> currentUnfoldSet, ProxyCardType proxyCardType, int columns)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ProxiesListState() when $default != null:
|
||||
return $default(_that.groups,_that.currentUnfoldSet,_that.proxiesSortType,_that.proxyCardType,_that.sortNum,_that.columns);case _:
|
||||
return $default(_that.groups,_that.currentUnfoldSet,_that.proxyCardType,_that.columns);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -3144,10 +3142,10 @@ return $default(_that.groups,_that.currentUnfoldSet,_that.proxiesSortType,_that.
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<Group> groups, Set<String> currentUnfoldSet, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<Group> groups, Set<String> currentUnfoldSet, ProxyCardType proxyCardType, int columns) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ProxiesListState():
|
||||
return $default(_that.groups,_that.currentUnfoldSet,_that.proxiesSortType,_that.proxyCardType,_that.sortNum,_that.columns);case _:
|
||||
return $default(_that.groups,_that.currentUnfoldSet,_that.proxyCardType,_that.columns);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -3164,10 +3162,10 @@ return $default(_that.groups,_that.currentUnfoldSet,_that.proxiesSortType,_that.
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<Group> groups, Set<String> currentUnfoldSet, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<Group> groups, Set<String> currentUnfoldSet, ProxyCardType proxyCardType, int columns)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ProxiesListState() when $default != null:
|
||||
return $default(_that.groups,_that.currentUnfoldSet,_that.proxiesSortType,_that.proxyCardType,_that.sortNum,_that.columns);case _:
|
||||
return $default(_that.groups,_that.currentUnfoldSet,_that.proxyCardType,_that.columns);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -3179,7 +3177,7 @@ return $default(_that.groups,_that.currentUnfoldSet,_that.proxiesSortType,_that.
|
||||
|
||||
|
||||
class _ProxiesListState implements ProxiesListState {
|
||||
const _ProxiesListState({required final List<Group> groups, required final Set<String> currentUnfoldSet, required this.proxiesSortType, required this.proxyCardType, required this.sortNum, required this.columns}): _groups = groups,_currentUnfoldSet = currentUnfoldSet;
|
||||
const _ProxiesListState({required final List<Group> groups, required final Set<String> currentUnfoldSet, required this.proxyCardType, required this.columns}): _groups = groups,_currentUnfoldSet = currentUnfoldSet;
|
||||
|
||||
|
||||
final List<Group> _groups;
|
||||
@@ -3196,9 +3194,7 @@ class _ProxiesListState implements ProxiesListState {
|
||||
return EqualUnmodifiableSetView(_currentUnfoldSet);
|
||||
}
|
||||
|
||||
@override final ProxiesSortType proxiesSortType;
|
||||
@override final ProxyCardType proxyCardType;
|
||||
@override final num sortNum;
|
||||
@override final int columns;
|
||||
|
||||
/// Create a copy of ProxiesListState
|
||||
@@ -3211,16 +3207,16 @@ _$ProxiesListStateCopyWith<_ProxiesListState> get copyWith => __$ProxiesListStat
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProxiesListState&&const DeepCollectionEquality().equals(other._groups, _groups)&&const DeepCollectionEquality().equals(other._currentUnfoldSet, _currentUnfoldSet)&&(identical(other.proxiesSortType, proxiesSortType) || other.proxiesSortType == proxiesSortType)&&(identical(other.proxyCardType, proxyCardType) || other.proxyCardType == proxyCardType)&&(identical(other.sortNum, sortNum) || other.sortNum == sortNum)&&(identical(other.columns, columns) || other.columns == columns));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProxiesListState&&const DeepCollectionEquality().equals(other._groups, _groups)&&const DeepCollectionEquality().equals(other._currentUnfoldSet, _currentUnfoldSet)&&(identical(other.proxyCardType, proxyCardType) || other.proxyCardType == proxyCardType)&&(identical(other.columns, columns) || other.columns == columns));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_groups),const DeepCollectionEquality().hash(_currentUnfoldSet),proxiesSortType,proxyCardType,sortNum,columns);
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_groups),const DeepCollectionEquality().hash(_currentUnfoldSet),proxyCardType,columns);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxiesListState(groups: $groups, currentUnfoldSet: $currentUnfoldSet, proxiesSortType: $proxiesSortType, proxyCardType: $proxyCardType, sortNum: $sortNum, columns: $columns)';
|
||||
return 'ProxiesListState(groups: $groups, currentUnfoldSet: $currentUnfoldSet, proxyCardType: $proxyCardType, columns: $columns)';
|
||||
}
|
||||
|
||||
|
||||
@@ -3231,7 +3227,7 @@ abstract mixin class _$ProxiesListStateCopyWith<$Res> implements $ProxiesListSta
|
||||
factory _$ProxiesListStateCopyWith(_ProxiesListState value, $Res Function(_ProxiesListState) _then) = __$ProxiesListStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
List<Group> groups, Set<String> currentUnfoldSet, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns
|
||||
List<Group> groups, Set<String> currentUnfoldSet, ProxyCardType proxyCardType, int columns
|
||||
});
|
||||
|
||||
|
||||
@@ -3248,14 +3244,12 @@ class __$ProxiesListStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of ProxiesListState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? groups = null,Object? currentUnfoldSet = null,Object? proxiesSortType = null,Object? proxyCardType = null,Object? sortNum = null,Object? columns = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? groups = null,Object? currentUnfoldSet = null,Object? proxyCardType = null,Object? columns = null,}) {
|
||||
return _then(_ProxiesListState(
|
||||
groups: null == groups ? _self._groups : groups // ignore: cast_nullable_to_non_nullable
|
||||
as List<Group>,currentUnfoldSet: null == currentUnfoldSet ? _self._currentUnfoldSet : currentUnfoldSet // ignore: cast_nullable_to_non_nullable
|
||||
as Set<String>,proxiesSortType: null == proxiesSortType ? _self.proxiesSortType : proxiesSortType // ignore: cast_nullable_to_non_nullable
|
||||
as ProxiesSortType,proxyCardType: null == proxyCardType ? _self.proxyCardType : proxyCardType // ignore: cast_nullable_to_non_nullable
|
||||
as ProxyCardType,sortNum: null == sortNum ? _self.sortNum : sortNum // ignore: cast_nullable_to_non_nullable
|
||||
as num,columns: null == columns ? _self.columns : columns // ignore: cast_nullable_to_non_nullable
|
||||
as Set<String>,proxyCardType: null == proxyCardType ? _self.proxyCardType : proxyCardType // ignore: cast_nullable_to_non_nullable
|
||||
as ProxyCardType,columns: null == columns ? _self.columns : columns // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
@@ -3266,7 +3260,7 @@ as int,
|
||||
/// @nodoc
|
||||
mixin _$ProxiesTabState {
|
||||
|
||||
List<Group> get groups; String? get currentGroupName; ProxiesSortType get proxiesSortType; ProxyCardType get proxyCardType; num get sortNum; int get columns;
|
||||
List<Group> get groups; String? get currentGroupName; ProxyCardType get proxyCardType; int get columns;
|
||||
/// Create a copy of ProxiesTabState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -3277,16 +3271,16 @@ $ProxiesTabStateCopyWith<ProxiesTabState> get copyWith => _$ProxiesTabStateCopyW
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ProxiesTabState&&const DeepCollectionEquality().equals(other.groups, groups)&&(identical(other.currentGroupName, currentGroupName) || other.currentGroupName == currentGroupName)&&(identical(other.proxiesSortType, proxiesSortType) || other.proxiesSortType == proxiesSortType)&&(identical(other.proxyCardType, proxyCardType) || other.proxyCardType == proxyCardType)&&(identical(other.sortNum, sortNum) || other.sortNum == sortNum)&&(identical(other.columns, columns) || other.columns == columns));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ProxiesTabState&&const DeepCollectionEquality().equals(other.groups, groups)&&(identical(other.currentGroupName, currentGroupName) || other.currentGroupName == currentGroupName)&&(identical(other.proxyCardType, proxyCardType) || other.proxyCardType == proxyCardType)&&(identical(other.columns, columns) || other.columns == columns));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(groups),currentGroupName,proxiesSortType,proxyCardType,sortNum,columns);
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(groups),currentGroupName,proxyCardType,columns);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxiesTabState(groups: $groups, currentGroupName: $currentGroupName, proxiesSortType: $proxiesSortType, proxyCardType: $proxyCardType, sortNum: $sortNum, columns: $columns)';
|
||||
return 'ProxiesTabState(groups: $groups, currentGroupName: $currentGroupName, proxyCardType: $proxyCardType, columns: $columns)';
|
||||
}
|
||||
|
||||
|
||||
@@ -3297,7 +3291,7 @@ abstract mixin class $ProxiesTabStateCopyWith<$Res> {
|
||||
factory $ProxiesTabStateCopyWith(ProxiesTabState value, $Res Function(ProxiesTabState) _then) = _$ProxiesTabStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
List<Group> groups, String? currentGroupName, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns
|
||||
List<Group> groups, String? currentGroupName, ProxyCardType proxyCardType, int columns
|
||||
});
|
||||
|
||||
|
||||
@@ -3314,14 +3308,12 @@ class _$ProxiesTabStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of ProxiesTabState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? groups = null,Object? currentGroupName = freezed,Object? proxiesSortType = null,Object? proxyCardType = null,Object? sortNum = null,Object? columns = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? groups = null,Object? currentGroupName = freezed,Object? proxyCardType = null,Object? columns = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
groups: null == groups ? _self.groups : groups // ignore: cast_nullable_to_non_nullable
|
||||
as List<Group>,currentGroupName: freezed == currentGroupName ? _self.currentGroupName : currentGroupName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,proxiesSortType: null == proxiesSortType ? _self.proxiesSortType : proxiesSortType // ignore: cast_nullable_to_non_nullable
|
||||
as ProxiesSortType,proxyCardType: null == proxyCardType ? _self.proxyCardType : proxyCardType // ignore: cast_nullable_to_non_nullable
|
||||
as ProxyCardType,sortNum: null == sortNum ? _self.sortNum : sortNum // ignore: cast_nullable_to_non_nullable
|
||||
as num,columns: null == columns ? _self.columns : columns // ignore: cast_nullable_to_non_nullable
|
||||
as String?,proxyCardType: null == proxyCardType ? _self.proxyCardType : proxyCardType // ignore: cast_nullable_to_non_nullable
|
||||
as ProxyCardType,columns: null == columns ? _self.columns : columns // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
@@ -3407,10 +3399,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<Group> groups, String? currentGroupName, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<Group> groups, String? currentGroupName, ProxyCardType proxyCardType, int columns)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ProxiesTabState() when $default != null:
|
||||
return $default(_that.groups,_that.currentGroupName,_that.proxiesSortType,_that.proxyCardType,_that.sortNum,_that.columns);case _:
|
||||
return $default(_that.groups,_that.currentGroupName,_that.proxyCardType,_that.columns);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -3428,10 +3420,10 @@ return $default(_that.groups,_that.currentGroupName,_that.proxiesSortType,_that.
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<Group> groups, String? currentGroupName, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<Group> groups, String? currentGroupName, ProxyCardType proxyCardType, int columns) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ProxiesTabState():
|
||||
return $default(_that.groups,_that.currentGroupName,_that.proxiesSortType,_that.proxyCardType,_that.sortNum,_that.columns);case _:
|
||||
return $default(_that.groups,_that.currentGroupName,_that.proxyCardType,_that.columns);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -3448,10 +3440,10 @@ return $default(_that.groups,_that.currentGroupName,_that.proxiesSortType,_that.
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<Group> groups, String? currentGroupName, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<Group> groups, String? currentGroupName, ProxyCardType proxyCardType, int columns)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ProxiesTabState() when $default != null:
|
||||
return $default(_that.groups,_that.currentGroupName,_that.proxiesSortType,_that.proxyCardType,_that.sortNum,_that.columns);case _:
|
||||
return $default(_that.groups,_that.currentGroupName,_that.proxyCardType,_that.columns);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -3463,7 +3455,7 @@ return $default(_that.groups,_that.currentGroupName,_that.proxiesSortType,_that.
|
||||
|
||||
|
||||
class _ProxiesTabState implements ProxiesTabState {
|
||||
const _ProxiesTabState({required final List<Group> groups, required this.currentGroupName, required this.proxiesSortType, required this.proxyCardType, required this.sortNum, required this.columns}): _groups = groups;
|
||||
const _ProxiesTabState({required final List<Group> groups, required this.currentGroupName, required this.proxyCardType, required this.columns}): _groups = groups;
|
||||
|
||||
|
||||
final List<Group> _groups;
|
||||
@@ -3474,9 +3466,7 @@ class _ProxiesTabState implements ProxiesTabState {
|
||||
}
|
||||
|
||||
@override final String? currentGroupName;
|
||||
@override final ProxiesSortType proxiesSortType;
|
||||
@override final ProxyCardType proxyCardType;
|
||||
@override final num sortNum;
|
||||
@override final int columns;
|
||||
|
||||
/// Create a copy of ProxiesTabState
|
||||
@@ -3489,16 +3479,16 @@ _$ProxiesTabStateCopyWith<_ProxiesTabState> get copyWith => __$ProxiesTabStateCo
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProxiesTabState&&const DeepCollectionEquality().equals(other._groups, _groups)&&(identical(other.currentGroupName, currentGroupName) || other.currentGroupName == currentGroupName)&&(identical(other.proxiesSortType, proxiesSortType) || other.proxiesSortType == proxiesSortType)&&(identical(other.proxyCardType, proxyCardType) || other.proxyCardType == proxyCardType)&&(identical(other.sortNum, sortNum) || other.sortNum == sortNum)&&(identical(other.columns, columns) || other.columns == columns));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProxiesTabState&&const DeepCollectionEquality().equals(other._groups, _groups)&&(identical(other.currentGroupName, currentGroupName) || other.currentGroupName == currentGroupName)&&(identical(other.proxyCardType, proxyCardType) || other.proxyCardType == proxyCardType)&&(identical(other.columns, columns) || other.columns == columns));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_groups),currentGroupName,proxiesSortType,proxyCardType,sortNum,columns);
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_groups),currentGroupName,proxyCardType,columns);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxiesTabState(groups: $groups, currentGroupName: $currentGroupName, proxiesSortType: $proxiesSortType, proxyCardType: $proxyCardType, sortNum: $sortNum, columns: $columns)';
|
||||
return 'ProxiesTabState(groups: $groups, currentGroupName: $currentGroupName, proxyCardType: $proxyCardType, columns: $columns)';
|
||||
}
|
||||
|
||||
|
||||
@@ -3509,7 +3499,7 @@ abstract mixin class _$ProxiesTabStateCopyWith<$Res> implements $ProxiesTabState
|
||||
factory _$ProxiesTabStateCopyWith(_ProxiesTabState value, $Res Function(_ProxiesTabState) _then) = __$ProxiesTabStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
List<Group> groups, String? currentGroupName, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns
|
||||
List<Group> groups, String? currentGroupName, ProxyCardType proxyCardType, int columns
|
||||
});
|
||||
|
||||
|
||||
@@ -3526,14 +3516,12 @@ class __$ProxiesTabStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of ProxiesTabState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? groups = null,Object? currentGroupName = freezed,Object? proxiesSortType = null,Object? proxyCardType = null,Object? sortNum = null,Object? columns = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? groups = null,Object? currentGroupName = freezed,Object? proxyCardType = null,Object? columns = null,}) {
|
||||
return _then(_ProxiesTabState(
|
||||
groups: null == groups ? _self._groups : groups // ignore: cast_nullable_to_non_nullable
|
||||
as List<Group>,currentGroupName: freezed == currentGroupName ? _self.currentGroupName : currentGroupName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,proxiesSortType: null == proxiesSortType ? _self.proxiesSortType : proxiesSortType // ignore: cast_nullable_to_non_nullable
|
||||
as ProxiesSortType,proxyCardType: null == proxyCardType ? _self.proxyCardType : proxyCardType // ignore: cast_nullable_to_non_nullable
|
||||
as ProxyCardType,sortNum: null == sortNum ? _self.sortNum : sortNum // ignore: cast_nullable_to_non_nullable
|
||||
as num,columns: null == columns ? _self.columns : columns // ignore: cast_nullable_to_non_nullable
|
||||
as String?,proxyCardType: null == proxyCardType ? _self.proxyCardType : proxyCardType // ignore: cast_nullable_to_non_nullable
|
||||
as ProxyCardType,columns: null == columns ? _self.columns : columns // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
@@ -5733,40 +5721,40 @@ as double,
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ProxyCardState {
|
||||
mixin _$SelectedProxyState {
|
||||
|
||||
String get proxyName; String? get testUrl;
|
||||
/// Create a copy of ProxyCardState
|
||||
String get proxyName; bool get group; String? get testUrl;
|
||||
/// Create a copy of SelectedProxyState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$ProxyCardStateCopyWith<ProxyCardState> get copyWith => _$ProxyCardStateCopyWithImpl<ProxyCardState>(this as ProxyCardState, _$identity);
|
||||
$SelectedProxyStateCopyWith<SelectedProxyState> get copyWith => _$SelectedProxyStateCopyWithImpl<SelectedProxyState>(this as SelectedProxyState, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ProxyCardState&&(identical(other.proxyName, proxyName) || other.proxyName == proxyName)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SelectedProxyState&&(identical(other.proxyName, proxyName) || other.proxyName == proxyName)&&(identical(other.group, group) || other.group == group)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,proxyName,testUrl);
|
||||
int get hashCode => Object.hash(runtimeType,proxyName,group,testUrl);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxyCardState(proxyName: $proxyName, testUrl: $testUrl)';
|
||||
return 'SelectedProxyState(proxyName: $proxyName, group: $group, testUrl: $testUrl)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $ProxyCardStateCopyWith<$Res> {
|
||||
factory $ProxyCardStateCopyWith(ProxyCardState value, $Res Function(ProxyCardState) _then) = _$ProxyCardStateCopyWithImpl;
|
||||
abstract mixin class $SelectedProxyStateCopyWith<$Res> {
|
||||
factory $SelectedProxyStateCopyWith(SelectedProxyState value, $Res Function(SelectedProxyState) _then) = _$SelectedProxyStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String proxyName, String? testUrl
|
||||
String proxyName, bool group, String? testUrl
|
||||
});
|
||||
|
||||
|
||||
@@ -5774,19 +5762,20 @@ $Res call({
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$ProxyCardStateCopyWithImpl<$Res>
|
||||
implements $ProxyCardStateCopyWith<$Res> {
|
||||
_$ProxyCardStateCopyWithImpl(this._self, this._then);
|
||||
class _$SelectedProxyStateCopyWithImpl<$Res>
|
||||
implements $SelectedProxyStateCopyWith<$Res> {
|
||||
_$SelectedProxyStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final ProxyCardState _self;
|
||||
final $Res Function(ProxyCardState) _then;
|
||||
final SelectedProxyState _self;
|
||||
final $Res Function(SelectedProxyState) _then;
|
||||
|
||||
/// Create a copy of ProxyCardState
|
||||
/// Create a copy of SelectedProxyState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? proxyName = null,Object? testUrl = freezed,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? proxyName = null,Object? group = null,Object? testUrl = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
proxyName: null == proxyName ? _self.proxyName : proxyName // ignore: cast_nullable_to_non_nullable
|
||||
as String,testUrl: freezed == testUrl ? _self.testUrl : testUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String,group: null == group ? _self.group : group // ignore: cast_nullable_to_non_nullable
|
||||
as bool,testUrl: freezed == testUrl ? _self.testUrl : testUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
@@ -5794,8 +5783,8 @@ as String?,
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [ProxyCardState].
|
||||
extension ProxyCardStatePatterns on ProxyCardState {
|
||||
/// Adds pattern-matching-related methods to [SelectedProxyState].
|
||||
extension SelectedProxyStatePatterns on SelectedProxyState {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
@@ -5808,10 +5797,10 @@ extension ProxyCardStatePatterns on ProxyCardState {
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ProxyCardState value)? $default,{required TResult orElse(),}){
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SelectedProxyState value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ProxyCardState() when $default != null:
|
||||
case _SelectedProxyState() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
@@ -5830,10 +5819,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ProxyCardState value) $default,){
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SelectedProxyState value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ProxyCardState():
|
||||
case _SelectedProxyState():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
@@ -5851,10 +5840,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ProxyCardState value)? $default,){
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SelectedProxyState value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ProxyCardState() when $default != null:
|
||||
case _SelectedProxyState() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
@@ -5872,10 +5861,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String proxyName, String? testUrl)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String proxyName, bool group, String? testUrl)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ProxyCardState() when $default != null:
|
||||
return $default(_that.proxyName,_that.testUrl);case _:
|
||||
case _SelectedProxyState() when $default != null:
|
||||
return $default(_that.proxyName,_that.group,_that.testUrl);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -5893,10 +5882,10 @@ return $default(_that.proxyName,_that.testUrl);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String proxyName, String? testUrl) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String proxyName, bool group, String? testUrl) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ProxyCardState():
|
||||
return $default(_that.proxyName,_that.testUrl);case _:
|
||||
case _SelectedProxyState():
|
||||
return $default(_that.proxyName,_that.group,_that.testUrl);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -5913,10 +5902,10 @@ return $default(_that.proxyName,_that.testUrl);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String proxyName, String? testUrl)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String proxyName, bool group, String? testUrl)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ProxyCardState() when $default != null:
|
||||
return $default(_that.proxyName,_that.testUrl);case _:
|
||||
case _SelectedProxyState() when $default != null:
|
||||
return $default(_that.proxyName,_that.group,_that.testUrl);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -5927,44 +5916,45 @@ return $default(_that.proxyName,_that.testUrl);case _:
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _ProxyCardState implements ProxyCardState {
|
||||
const _ProxyCardState({required this.proxyName, this.testUrl});
|
||||
class _SelectedProxyState implements SelectedProxyState {
|
||||
const _SelectedProxyState({required this.proxyName, this.group = false, this.testUrl});
|
||||
|
||||
|
||||
@override final String proxyName;
|
||||
@override@JsonKey() final bool group;
|
||||
@override final String? testUrl;
|
||||
|
||||
/// Create a copy of ProxyCardState
|
||||
/// Create a copy of SelectedProxyState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$ProxyCardStateCopyWith<_ProxyCardState> get copyWith => __$ProxyCardStateCopyWithImpl<_ProxyCardState>(this, _$identity);
|
||||
_$SelectedProxyStateCopyWith<_SelectedProxyState> get copyWith => __$SelectedProxyStateCopyWithImpl<_SelectedProxyState>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProxyCardState&&(identical(other.proxyName, proxyName) || other.proxyName == proxyName)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SelectedProxyState&&(identical(other.proxyName, proxyName) || other.proxyName == proxyName)&&(identical(other.group, group) || other.group == group)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,proxyName,testUrl);
|
||||
int get hashCode => Object.hash(runtimeType,proxyName,group,testUrl);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxyCardState(proxyName: $proxyName, testUrl: $testUrl)';
|
||||
return 'SelectedProxyState(proxyName: $proxyName, group: $group, testUrl: $testUrl)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$ProxyCardStateCopyWith<$Res> implements $ProxyCardStateCopyWith<$Res> {
|
||||
factory _$ProxyCardStateCopyWith(_ProxyCardState value, $Res Function(_ProxyCardState) _then) = __$ProxyCardStateCopyWithImpl;
|
||||
abstract mixin class _$SelectedProxyStateCopyWith<$Res> implements $SelectedProxyStateCopyWith<$Res> {
|
||||
factory _$SelectedProxyStateCopyWith(_SelectedProxyState value, $Res Function(_SelectedProxyState) _then) = __$SelectedProxyStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String proxyName, String? testUrl
|
||||
String proxyName, bool group, String? testUrl
|
||||
});
|
||||
|
||||
|
||||
@@ -5972,19 +5962,20 @@ $Res call({
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$ProxyCardStateCopyWithImpl<$Res>
|
||||
implements _$ProxyCardStateCopyWith<$Res> {
|
||||
__$ProxyCardStateCopyWithImpl(this._self, this._then);
|
||||
class __$SelectedProxyStateCopyWithImpl<$Res>
|
||||
implements _$SelectedProxyStateCopyWith<$Res> {
|
||||
__$SelectedProxyStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _ProxyCardState _self;
|
||||
final $Res Function(_ProxyCardState) _then;
|
||||
final _SelectedProxyState _self;
|
||||
final $Res Function(_SelectedProxyState) _then;
|
||||
|
||||
/// Create a copy of ProxyCardState
|
||||
/// Create a copy of SelectedProxyState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? proxyName = null,Object? testUrl = freezed,}) {
|
||||
return _then(_ProxyCardState(
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? proxyName = null,Object? group = null,Object? testUrl = freezed,}) {
|
||||
return _then(_SelectedProxyState(
|
||||
proxyName: null == proxyName ? _self.proxyName : proxyName // ignore: cast_nullable_to_non_nullable
|
||||
as String,testUrl: freezed == testUrl ? _self.testUrl : testUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String,group: null == group ? _self.group : group // ignore: cast_nullable_to_non_nullable
|
||||
as bool,testUrl: freezed == testUrl ? _self.testUrl : testUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// ignore_for_file: invalid_annotation_target
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
@@ -102,9 +102,7 @@ abstract class ProxiesListState with _$ProxiesListState {
|
||||
const factory ProxiesListState({
|
||||
required List<Group> groups,
|
||||
required Set<String> currentUnfoldSet,
|
||||
required ProxiesSortType proxiesSortType,
|
||||
required ProxyCardType proxyCardType,
|
||||
required num sortNum,
|
||||
required int columns,
|
||||
}) = _ProxiesListState;
|
||||
}
|
||||
@@ -114,9 +112,7 @@ abstract class ProxiesTabState with _$ProxiesTabState {
|
||||
const factory ProxiesTabState({
|
||||
required List<Group> groups,
|
||||
required String? currentGroupName,
|
||||
required ProxiesSortType proxiesSortType,
|
||||
required ProxyCardType proxyCardType,
|
||||
required num sortNum,
|
||||
required int columns,
|
||||
}) = _ProxiesTabState;
|
||||
}
|
||||
@@ -233,9 +229,12 @@ abstract class DashboardState with _$DashboardState {
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class ProxyCardState with _$ProxyCardState {
|
||||
const factory ProxyCardState({required String proxyName, String? testUrl}) =
|
||||
_ProxyCardState;
|
||||
abstract class SelectedProxyState with _$SelectedProxyState {
|
||||
const factory SelectedProxyState({
|
||||
required String proxyName,
|
||||
@Default(false) bool group,
|
||||
String? testUrl,
|
||||
}) = _SelectedProxyState;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
||||
@@ -27,19 +27,15 @@ class HomePage extends StatelessWidget {
|
||||
pageBuilder: (_, index) {
|
||||
final navigationItem = state.navigationItems[index];
|
||||
final navigationView = navigationItem.builder(context);
|
||||
final view = isMobile
|
||||
? KeepScope(
|
||||
keep: navigationItem.keep,
|
||||
child: navigationView,
|
||||
)
|
||||
: KeepScope(
|
||||
keep: navigationItem.keep,
|
||||
child: Navigator(
|
||||
onGenerateRoute: (_) {
|
||||
return CommonRoute(builder: (_) => navigationView);
|
||||
},
|
||||
final view = KeepScope(
|
||||
keep: navigationItem.keep,
|
||||
child: isMobile
|
||||
? navigationView
|
||||
: Navigator(
|
||||
pages: [MaterialPage(child: navigationView)],
|
||||
onDidRemovePage: (_) {},
|
||||
),
|
||||
);
|
||||
);
|
||||
return view;
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:fl_clash/common/app_localizations.dart';
|
||||
@@ -38,45 +39,48 @@ class App {
|
||||
}
|
||||
|
||||
Future<List<Package>> getPackages() async {
|
||||
final packagesString =
|
||||
await methodChannel.invokeMethod<String>('getPackages');
|
||||
final packagesString = await methodChannel.invokeMethod<String>(
|
||||
'getPackages',
|
||||
);
|
||||
return Isolate.run<List<Package>>(() {
|
||||
final List<dynamic> packagesRaw =
|
||||
packagesString != null ? json.decode(packagesString) : [];
|
||||
final List<dynamic> packagesRaw = packagesString != null
|
||||
? json.decode(packagesString)
|
||||
: [];
|
||||
return packagesRaw.map((e) => Package.fromJson(e)).toSet().toList();
|
||||
});
|
||||
}
|
||||
|
||||
Future<List<String>> getChinaPackageNames() async {
|
||||
final packageNamesString =
|
||||
await methodChannel.invokeMethod<String>('getChinaPackageNames');
|
||||
final packageNamesString = await methodChannel.invokeMethod<String>(
|
||||
'getChinaPackageNames',
|
||||
);
|
||||
return Isolate.run<List<String>>(() {
|
||||
final List<dynamic> packageNamesRaw =
|
||||
packageNamesString != null ? json.decode(packageNamesString) : [];
|
||||
final List<dynamic> packageNamesRaw = packageNamesString != null
|
||||
? json.decode(packageNamesString)
|
||||
: [];
|
||||
return packageNamesRaw.map((e) => e.toString()).toList();
|
||||
});
|
||||
}
|
||||
|
||||
Future<bool?> requestNotificationsPermission() async {
|
||||
return await methodChannel
|
||||
.invokeMethod<bool>('requestNotificationsPermission');
|
||||
return await methodChannel.invokeMethod<bool>(
|
||||
'requestNotificationsPermission',
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> openFile(String path) async {
|
||||
return await methodChannel.invokeMethod<bool>('openFile', {
|
||||
'path': path,
|
||||
}) ??
|
||||
return await methodChannel.invokeMethod<bool>('openFile', {'path': path}) ??
|
||||
false;
|
||||
}
|
||||
|
||||
Future<ImageProvider?> getPackageIcon(String packageName) async {
|
||||
final base64 = await methodChannel.invokeMethod<String>('getPackageIcon', {
|
||||
final path = await methodChannel.invokeMethod<String>('getPackageIcon', {
|
||||
'packageName': packageName,
|
||||
});
|
||||
if (base64 == null) {
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
return MemoryImage(base64Decode(base64));
|
||||
return FileImage(File(path));
|
||||
}
|
||||
|
||||
Future<bool?> tip(String? message) async {
|
||||
|
||||
@@ -54,8 +54,11 @@ class Requests extends _$Requests with AutoDisposeNotifierMixin {
|
||||
}
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class Providers extends _$Providers with AutoDisposeNotifierMixin {
|
||||
@riverpod
|
||||
class Providers extends _$Providers with AnyNotifierMixin {
|
||||
@override
|
||||
List<ExternalProvider> get value => globalState.appState.providers;
|
||||
|
||||
@override
|
||||
List<ExternalProvider> build() {
|
||||
return globalState.appState.providers;
|
||||
@@ -71,9 +74,9 @@ class Providers extends _$Providers with AutoDisposeNotifierMixin {
|
||||
return;
|
||||
}
|
||||
if (provider == null) return;
|
||||
final index = state.indexWhere((item) => item.name == provider.name);
|
||||
final index = value.indexWhere((item) => item.name == provider.name);
|
||||
if (index == -1) return;
|
||||
final newState = List<ExternalProvider>.from(state)..[index] = provider;
|
||||
final newState = List<ExternalProvider>.from(value)..[index] = provider;
|
||||
value = newState;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ final class ProvidersProvider
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'providersProvider',
|
||||
isAutoDispose: false,
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
@@ -197,7 +197,7 @@ final class ProvidersProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$providersHash() => r'b1175e1e2b22e34f8d414386fe672c4933fc47a3';
|
||||
String _$providersHash() => r'9cb491314be6dca0d9ff2d09aa276d19a92895af';
|
||||
|
||||
abstract class _$Providers extends $Notifier<List<ExternalProvider>> {
|
||||
List<ExternalProvider> build();
|
||||
|
||||
@@ -698,7 +698,7 @@ final class ProxiesListStateProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$proxiesListStateHash() => r'1438dbcaf0d45fbd2cb7fdde81cf1dc06bbd992f';
|
||||
String _$proxiesListStateHash() => r'b16ad96516ece78f6cb22f558a0535000b784317';
|
||||
|
||||
@ProviderFor(proxiesTabState)
|
||||
const proxiesTabStateProvider = ProxiesTabStateProvider._();
|
||||
@@ -740,7 +740,7 @@ final class ProxiesTabStateProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$proxiesTabStateHash() => r'591fd8c2fa0df4c6a4832ffa04eb8d62453ba225';
|
||||
String _$proxiesTabStateHash() => r'143b106d74da618327cbac48af15078efd8cabee';
|
||||
|
||||
@ProviderFor(isStart)
|
||||
const isStartProvider = IsStartProvider._();
|
||||
@@ -1248,7 +1248,7 @@ final class GetDelayProvider extends $FunctionalProvider<int?, int?, int?>
|
||||
}
|
||||
}
|
||||
|
||||
String _$getDelayHash() => r'b5920ac7de0aaadb8ff63fac993bd90ff87cd25a';
|
||||
String _$getDelayHash() => r'15df90fb31665501b21ea671a72e35beaf32141b';
|
||||
|
||||
final class GetDelayFamily extends $Family
|
||||
with
|
||||
@@ -1512,55 +1512,62 @@ final class GetProxiesColumnsProvider extends $FunctionalProvider<int, int, int>
|
||||
|
||||
String _$getProxiesColumnsHash() => r'725066b5fc21f590a4c2656a1fd5e14ab7079079';
|
||||
|
||||
@ProviderFor(getProxyCardState)
|
||||
const getProxyCardStateProvider = GetProxyCardStateFamily._();
|
||||
@ProviderFor(realSelectedProxyState)
|
||||
const realSelectedProxyStateProvider = RealSelectedProxyStateFamily._();
|
||||
|
||||
final class GetProxyCardStateProvider
|
||||
extends $FunctionalProvider<ProxyCardState, ProxyCardState, ProxyCardState>
|
||||
with $Provider<ProxyCardState> {
|
||||
const GetProxyCardStateProvider._({
|
||||
required GetProxyCardStateFamily super.from,
|
||||
final class RealSelectedProxyStateProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
SelectedProxyState,
|
||||
SelectedProxyState,
|
||||
SelectedProxyState
|
||||
>
|
||||
with $Provider<SelectedProxyState> {
|
||||
const RealSelectedProxyStateProvider._({
|
||||
required RealSelectedProxyStateFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'getProxyCardStateProvider',
|
||||
name: r'realSelectedProxyStateProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$getProxyCardStateHash();
|
||||
String debugGetCreateSourceHash() => _$realSelectedProxyStateHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'getProxyCardStateProvider'
|
||||
return r'realSelectedProxyStateProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<ProxyCardState> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
$ProviderElement<SelectedProxyState> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
ProxyCardState create(Ref ref) {
|
||||
SelectedProxyState create(Ref ref) {
|
||||
final argument = this.argument as String;
|
||||
return getProxyCardState(ref, argument);
|
||||
return realSelectedProxyState(ref, argument);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(ProxyCardState value) {
|
||||
Override overrideWithValue(SelectedProxyState value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<ProxyCardState>(value),
|
||||
providerOverride: $SyncValueProvider<SelectedProxyState>(value),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is GetProxyCardStateProvider && other.argument == argument;
|
||||
return other is RealSelectedProxyStateProvider &&
|
||||
other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1569,24 +1576,25 @@ final class GetProxyCardStateProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$getProxyCardStateHash() => r'0f131148cb5ed60c9c4c4f31fbe32f114ac346bb';
|
||||
String _$realSelectedProxyStateHash() =>
|
||||
r'42fa131419f0a26e30c4f5269bf020893b7f828c';
|
||||
|
||||
final class GetProxyCardStateFamily extends $Family
|
||||
with $FunctionalFamilyOverride<ProxyCardState, String> {
|
||||
const GetProxyCardStateFamily._()
|
||||
final class RealSelectedProxyStateFamily extends $Family
|
||||
with $FunctionalFamilyOverride<SelectedProxyState, String> {
|
||||
const RealSelectedProxyStateFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'getProxyCardStateProvider',
|
||||
name: r'realSelectedProxyStateProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
GetProxyCardStateProvider call(String proxyName) =>
|
||||
GetProxyCardStateProvider._(argument: proxyName, from: this);
|
||||
RealSelectedProxyStateProvider call(String proxyName) =>
|
||||
RealSelectedProxyStateProvider._(argument: proxyName, from: this);
|
||||
|
||||
@override
|
||||
String toString() => r'getProxyCardStateProvider';
|
||||
String toString() => r'realSelectedProxyStateProvider';
|
||||
}
|
||||
|
||||
@ProviderFor(getProxyName)
|
||||
@@ -1801,7 +1809,7 @@ final class GetProxyDescProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$getProxyDescHash() => r'c173fe2393d9c4f5d5d17480e69f9126bb76a17d';
|
||||
String _$getProxyDescHash() => r'4579b55bf7e9fbcfdf91b91619bd0320c585f23d';
|
||||
|
||||
final class GetProxyDescFamily extends $Family
|
||||
with $FunctionalFamilyOverride<String, Proxy> {
|
||||
@@ -2205,6 +2213,55 @@ final class AutoSetSystemDnsStateProvider
|
||||
String _$autoSetSystemDnsStateHash() =>
|
||||
r'2e0976e079100325b1ca797285df48a94c2c066c';
|
||||
|
||||
@ProviderFor(needUpdateGroups)
|
||||
const needUpdateGroupsProvider = NeedUpdateGroupsProvider._();
|
||||
|
||||
final class NeedUpdateGroupsProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
VM3<bool, int, ProxiesSortType>,
|
||||
VM3<bool, int, ProxiesSortType>,
|
||||
VM3<bool, int, ProxiesSortType>
|
||||
>
|
||||
with $Provider<VM3<bool, int, ProxiesSortType>> {
|
||||
const NeedUpdateGroupsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'needUpdateGroupsProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$needUpdateGroupsHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<VM3<bool, int, ProxiesSortType>> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
VM3<bool, int, ProxiesSortType> create(Ref ref) {
|
||||
return needUpdateGroups(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(VM3<bool, int, ProxiesSortType> value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<VM3<bool, int, ProxiesSortType>>(
|
||||
value,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$needUpdateGroupsHash() => r'1d1fbf135b4b5d2a2ee984e421ccffe7c4bb0a47';
|
||||
|
||||
@ProviderFor(androidState)
|
||||
const androidStateProvider = AndroidStateProvider._();
|
||||
|
||||
|
||||
@@ -268,20 +268,15 @@ ProxiesListState proxiesListState(Ref ref) {
|
||||
final query = ref.watch(queryProvider(QueryTag.proxies));
|
||||
final currentGroups = ref.watch(filterGroupsStateProvider(query));
|
||||
final currentUnfoldSet = ref.watch(unfoldSetProvider);
|
||||
final vm2 = ref.watch(
|
||||
proxiesStyleSettingProvider.select(
|
||||
(state) => VM2(a: state.sortType, b: state.cardType),
|
||||
),
|
||||
final cardType = ref.watch(
|
||||
proxiesStyleSettingProvider.select((state) => state.cardType),
|
||||
);
|
||||
|
||||
final sortNum = ref.watch(sortNumProvider);
|
||||
final columns = ref.watch(getProxiesColumnsProvider);
|
||||
return ProxiesListState(
|
||||
groups: currentGroups.value,
|
||||
currentUnfoldSet: currentUnfoldSet,
|
||||
proxiesSortType: vm2.a,
|
||||
proxyCardType: vm2.b,
|
||||
sortNum: sortNum,
|
||||
proxyCardType: cardType,
|
||||
columns: columns,
|
||||
);
|
||||
}
|
||||
@@ -293,19 +288,14 @@ ProxiesTabState proxiesTabState(Ref ref) {
|
||||
final currentGroupName = ref.watch(
|
||||
currentProfileProvider.select((state) => state?.currentGroupName),
|
||||
);
|
||||
final vm2 = ref.watch(
|
||||
proxiesStyleSettingProvider.select(
|
||||
(state) => VM2(a: state.sortType, b: state.cardType),
|
||||
),
|
||||
final cardType = ref.watch(
|
||||
proxiesStyleSettingProvider.select((state) => state.cardType),
|
||||
);
|
||||
final sortNum = ref.watch(sortNumProvider);
|
||||
final columns = ref.watch(getProxiesColumnsProvider);
|
||||
return ProxiesTabState(
|
||||
groups: currentGroups.value,
|
||||
currentGroupName: currentGroupName,
|
||||
proxiesSortType: vm2.a,
|
||||
proxyCardType: vm2.b,
|
||||
sortNum: sortNum,
|
||||
proxyCardType: cardType,
|
||||
columns: columns,
|
||||
);
|
||||
}
|
||||
@@ -416,14 +406,14 @@ String getRealTestUrl(Ref ref, [String? testUrl]) {
|
||||
@riverpod
|
||||
int? getDelay(Ref ref, {required String proxyName, String? testUrl}) {
|
||||
final currentTestUrl = ref.watch(getRealTestUrlProvider(testUrl));
|
||||
final proxyCardState = ref.watch(getProxyCardStateProvider(proxyName));
|
||||
final proxyState = ref.watch(realSelectedProxyStateProvider(proxyName));
|
||||
final delay = ref.watch(
|
||||
delayDataSourceProvider.select((state) {
|
||||
final delayMap =
|
||||
state[proxyCardState.testUrl.getSafeValue(currentTestUrl)];
|
||||
return delayMap?[proxyCardState.proxyName];
|
||||
final delayMap = state[proxyState.testUrl.getSafeValue(currentTestUrl)];
|
||||
return delayMap?[proxyState.proxyName];
|
||||
}),
|
||||
);
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
||||
@@ -470,41 +460,14 @@ int getProxiesColumns(Ref ref) {
|
||||
return utils.getProxiesColumns(viewWidth, proxiesLayout);
|
||||
}
|
||||
|
||||
ProxyCardState _getProxyCardState(
|
||||
List<Group> groups,
|
||||
SelectedMap selectedMap,
|
||||
ProxyCardState proxyDelayState,
|
||||
) {
|
||||
if (proxyDelayState.proxyName.isEmpty) return proxyDelayState;
|
||||
final index = groups.indexWhere(
|
||||
(element) => element.name == proxyDelayState.proxyName,
|
||||
);
|
||||
if (index == -1) return proxyDelayState;
|
||||
final group = groups[index];
|
||||
final currentSelectedName = group.getCurrentSelectedName(
|
||||
selectedMap[proxyDelayState.proxyName] ?? '',
|
||||
);
|
||||
if (currentSelectedName.isEmpty) {
|
||||
return proxyDelayState;
|
||||
}
|
||||
return _getProxyCardState(
|
||||
groups,
|
||||
selectedMap,
|
||||
proxyDelayState.copyWith(
|
||||
proxyName: currentSelectedName,
|
||||
testUrl: group.testUrl,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
ProxyCardState getProxyCardState(Ref ref, String proxyName) {
|
||||
SelectedProxyState realSelectedProxyState(Ref ref, String proxyName) {
|
||||
final groups = ref.watch(groupsProvider);
|
||||
final selectedMap = ref.watch(selectedMapProvider);
|
||||
return _getProxyCardState(
|
||||
groups,
|
||||
selectedMap,
|
||||
ProxyCardState(proxyName: proxyName),
|
||||
return computeRealSelectedProxyState(
|
||||
proxyName,
|
||||
groups: groups,
|
||||
selectedMap: selectedMap,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -534,7 +497,7 @@ String getProxyDesc(Ref ref, Proxy proxy) {
|
||||
final groups = ref.watch(groupsProvider);
|
||||
final index = groups.indexWhere((element) => element.name == proxy.name);
|
||||
if (index == -1) return proxy.type;
|
||||
final state = ref.watch(getProxyCardStateProvider(proxy.name));
|
||||
final state = ref.watch(realSelectedProxyStateProvider(proxy.name));
|
||||
return "${proxy.type}(${state.proxyName.isNotEmpty ? state.proxyName : '*'})";
|
||||
}
|
||||
}
|
||||
@@ -638,6 +601,18 @@ VM2<bool, bool> autoSetSystemDnsState(Ref ref) {
|
||||
return VM2(a: isStart ? realTunEnable : false, b: autoSetSystemDns);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
VM3<bool, int, ProxiesSortType> needUpdateGroups(Ref ref) {
|
||||
final isProxies = ref.watch(
|
||||
currentPageLabelProvider.select((state) => state == PageLabel.proxies),
|
||||
);
|
||||
final sortNum = ref.watch(sortNumProvider);
|
||||
final sortType = ref.watch(
|
||||
proxiesStyleSettingProvider.select((state) => state.sortType),
|
||||
);
|
||||
return VM3(a: isProxies, b: sortNum, c: sortType);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
AndroidState androidState(Ref ref) {
|
||||
final currentProfileName = ref.watch(
|
||||
|
||||
@@ -18,6 +18,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_js/flutter_js.dart';
|
||||
import 'package:material_color_utilities/palettes/core_palette.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:yaml_writer/yaml_writer.dart';
|
||||
|
||||
@@ -81,6 +82,38 @@ class GlobalState {
|
||||
await init();
|
||||
appState = appState.copyWith(coreStatus: CoreStatus.connected);
|
||||
await window?.init(version);
|
||||
_shakingStore();
|
||||
}
|
||||
|
||||
Future<void> _shakingStore() async {
|
||||
final profileIds = config.profiles.map((item) => item.id);
|
||||
final providersRootPath = await appPath.getProvidersRootPath();
|
||||
final profilesRootPath = await appPath.profilesPath;
|
||||
Isolate.run(() async {
|
||||
final profilesDir = Directory(profilesRootPath);
|
||||
final providersDir = Directory(providersRootPath);
|
||||
final List<FileSystemEntity> entities = [];
|
||||
if (await profilesDir.exists()) {
|
||||
entities.addAll(
|
||||
profilesDir.listSync().where(
|
||||
(item) => !item.path.contains('providers'),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (await providersDir.exists()) {
|
||||
entities.addAll(providersDir.listSync());
|
||||
}
|
||||
final deleteFutures = entities.map((entity) async {
|
||||
if (!profileIds.contains(basenameWithoutExtension(entity.path))) {
|
||||
final res = await coreController.deleteFile(entity.path);
|
||||
if (res.isNotEmpty) {
|
||||
throw res;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
await Future.wait(deleteFutures);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _initDynamicColor() async {
|
||||
@@ -275,7 +308,7 @@ class GlobalState {
|
||||
if (!await file.exists()) {
|
||||
await file.create(recursive: true);
|
||||
}
|
||||
await file.writeAsString(data, flush: true);
|
||||
await file.writeAsString(data);
|
||||
return '';
|
||||
} catch (e) {
|
||||
return e.toString();
|
||||
|
||||
@@ -93,7 +93,7 @@ class OutboundModeV2 extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final height = getWidgetHeight(0.72);
|
||||
final height = getWidgetHeight(1);
|
||||
return SizedBox(
|
||||
height: height,
|
||||
child: CommonCard(
|
||||
@@ -108,42 +108,56 @@ class OutboundModeV2 extends StatelessWidget {
|
||||
Mode.global => globalState.theme.darken3PrimaryContainer,
|
||||
Mode.direct => context.colorScheme.tertiaryContainer,
|
||||
};
|
||||
return Container(
|
||||
constraints: BoxConstraints.expand(),
|
||||
child: CommonTabBar<Mode>(
|
||||
children: Map.fromEntries(
|
||||
Mode.values.map(
|
||||
(item) => MapEntry(
|
||||
item,
|
||||
Container(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(),
|
||||
height: height - 16,
|
||||
child: Text(
|
||||
Intl.message(item.name),
|
||||
style: Theme.of(context).textTheme.titleSmall
|
||||
?.adjustSize(1)
|
||||
.copyWith(
|
||||
color: item == mode
|
||||
? _getTextColor(context, item)
|
||||
: null,
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
constraints: BoxConstraints.expand(),
|
||||
padding: EdgeInsets.all(12),
|
||||
child: LayoutBuilder(
|
||||
builder: (_, constraints) {
|
||||
return CommonTabBar<Mode>(
|
||||
children: Map.fromEntries(
|
||||
Mode.values.map(
|
||||
(item) => MapEntry(
|
||||
item,
|
||||
Container(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(),
|
||||
height: constraints.maxHeight,
|
||||
child: Text(
|
||||
Intl.message(item.name),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleSmall
|
||||
?.adjustSize(1)
|
||||
.copyWith(
|
||||
color: item == mode
|
||||
? _getTextColor(context, item)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 0),
|
||||
groupValue: mode,
|
||||
onValueChanged: (value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
globalState.appController.changeMode(value);
|
||||
},
|
||||
thumbColor: thumbColor,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
groupValue: mode,
|
||||
onValueChanged: (value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
globalState.appController.changeMode(value);
|
||||
},
|
||||
thumbColor: thumbColor,
|
||||
),
|
||||
Container(color: thumbColor, height: 10.ap),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -58,7 +58,7 @@ class _StartButtonState extends ConsumerState<StartButton>
|
||||
|
||||
void updateController() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (isStart) {
|
||||
if (isStart && mounted) {
|
||||
_controller.forward();
|
||||
} else {
|
||||
_controller.reverse();
|
||||
|
||||
@@ -22,13 +22,25 @@ double getItemHeight(ProxyCardType proxyCardType) {
|
||||
|
||||
Future<void> proxyDelayTest(Proxy proxy, [String? testUrl]) async {
|
||||
final appController = globalState.appController;
|
||||
final state = appController.getProxyCardState(proxy.name);
|
||||
final url = state.testUrl.getSafeValue(appController.getRealTestUrl(testUrl));
|
||||
final groups = globalState.appState.groups;
|
||||
final selectedMap = globalState.config.currentProfile?.selectedMap ?? {};
|
||||
final state = computeRealSelectedProxyState(
|
||||
proxy.name,
|
||||
groups: groups,
|
||||
selectedMap: selectedMap,
|
||||
);
|
||||
final currentTestUrl = state.testUrl.getSafeValue(
|
||||
appController.getRealTestUrl(testUrl),
|
||||
);
|
||||
if (state.proxyName.isEmpty) {
|
||||
return;
|
||||
}
|
||||
appController.setDelay(Delay(url: url, name: state.proxyName, value: 0));
|
||||
appController.setDelay(await coreController.getDelay(url, state.proxyName));
|
||||
appController.setDelay(
|
||||
Delay(url: currentTestUrl, name: state.proxyName, value: 0),
|
||||
);
|
||||
appController.setDelay(
|
||||
await coreController.getDelay(currentTestUrl, state.proxyName),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> delayTest(List<Proxy> proxies, [String? testUrl]) async {
|
||||
@@ -36,7 +48,13 @@ Future<void> delayTest(List<Proxy> proxies, [String? testUrl]) async {
|
||||
final proxyNames = proxies.map((proxy) => proxy.name).toSet().toList();
|
||||
|
||||
final delayProxies = proxyNames.map<Future>((proxyName) async {
|
||||
final state = appController.getProxyCardState(proxyName);
|
||||
final groups = globalState.appState.groups;
|
||||
final selectedMap = globalState.config.currentProfile?.selectedMap ?? {};
|
||||
final state = computeRealSelectedProxyState(
|
||||
proxyName,
|
||||
groups: groups,
|
||||
selectedMap: selectedMap,
|
||||
);
|
||||
final url = state.testUrl.getSafeValue(
|
||||
appController.getRealTestUrl(testUrl),
|
||||
);
|
||||
|
||||
@@ -28,7 +28,6 @@ class _ProxiesListViewState extends State<ProxiesListView> {
|
||||
null,
|
||||
);
|
||||
List<double> _headerOffset = [];
|
||||
GroupNameProxiesMap _lastGroupNameProxiesMap = {};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -118,10 +117,8 @@ class _ProxiesListViewState extends State<ProxiesListView> {
|
||||
required int columns,
|
||||
required Set<String> currentUnfoldSet,
|
||||
required ProxyCardType cardType,
|
||||
required ProxiesSortType sortType,
|
||||
}) {
|
||||
final items = <Widget>[];
|
||||
final GroupNameProxiesMap groupNameProxiesMap = {};
|
||||
for (final group in groups) {
|
||||
final groupName = group.name;
|
||||
final isExpand = currentUnfoldSet.contains(groupName);
|
||||
@@ -137,25 +134,23 @@ class _ProxiesListViewState extends State<ProxiesListView> {
|
||||
const SizedBox(height: 8),
|
||||
]);
|
||||
if (isExpand) {
|
||||
final sortedProxies = globalState.appController.getSortProxies(
|
||||
proxies: group.all,
|
||||
sortType: sortType,
|
||||
testUrl: group.testUrl,
|
||||
);
|
||||
groupNameProxiesMap[groupName] = sortedProxies;
|
||||
final chunks = sortedProxies.chunks(columns);
|
||||
final proxies = group.all;
|
||||
final chunks = proxies.chunks(columns);
|
||||
final rows = chunks
|
||||
.map<Widget>((proxies) {
|
||||
final children = proxies
|
||||
.map<Widget>(
|
||||
(proxy) => Flexible(
|
||||
child: ProxyCard(
|
||||
testUrl: group.testUrl,
|
||||
type: cardType,
|
||||
groupType: group.type,
|
||||
key: ValueKey('$groupName.${proxy.name}'),
|
||||
proxy: proxy,
|
||||
groupName: groupName,
|
||||
child: SizedBox(
|
||||
height: getItemHeight(cardType),
|
||||
child: ProxyCard(
|
||||
testUrl: group.testUrl,
|
||||
type: cardType,
|
||||
groupType: group.type,
|
||||
key: ValueKey('$groupName.${proxy.name}'),
|
||||
proxy: proxy,
|
||||
groupName: groupName,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
@@ -171,7 +166,6 @@ class _ProxiesListViewState extends State<ProxiesListView> {
|
||||
items.addAll([...rows, const SizedBox(height: 8)]);
|
||||
}
|
||||
}
|
||||
_lastGroupNameProxiesMap = groupNameProxiesMap;
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -203,11 +197,12 @@ class _ProxiesListViewState extends State<ProxiesListView> {
|
||||
}
|
||||
final appController = globalState.appController;
|
||||
final currentGroups = appController.getCurrentGroups();
|
||||
final groupNames = currentGroups.map((e) => e.name).toList();
|
||||
final findIndex = groupNames.indexWhere((item) => item == groupName);
|
||||
final findIndex = currentGroups.indexWhere(
|
||||
(item) => item.name == groupName,
|
||||
);
|
||||
final index = findIndex != -1 ? findIndex : 0;
|
||||
final currentInitOffset = _headerOffset[index];
|
||||
final proxies = _lastGroupNameProxiesMap[groupName];
|
||||
final proxies = currentGroups.getGroup(groupName)?.all;
|
||||
_controller.animateTo(
|
||||
min(
|
||||
currentInitOffset +
|
||||
@@ -240,7 +235,6 @@ class _ProxiesListViewState extends State<ProxiesListView> {
|
||||
currentUnfoldSet: state.currentUnfoldSet,
|
||||
columns: state.columns,
|
||||
cardType: state.proxyCardType,
|
||||
sortType: state.proxiesSortType,
|
||||
);
|
||||
final itemsOffset = _getItemHeightList(items, state.proxyCardType);
|
||||
return CommonScrollBar(
|
||||
|
||||
@@ -3,7 +3,6 @@ import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/models/common.dart';
|
||||
import 'package:fl_clash/models/widget.dart';
|
||||
import 'package:fl_clash/providers/providers.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:fl_clash/views/proxies/list.dart';
|
||||
import 'package:fl_clash/views/proxies/providers.dart';
|
||||
import 'package:fl_clash/widgets/widgets.dart';
|
||||
@@ -138,11 +137,6 @@ class _ProxiesViewState extends ConsumerState<ProxiesView> {
|
||||
},
|
||||
fireImmediately: true,
|
||||
);
|
||||
ref.listenManual(currentPageLabelProvider, (prev, next) {
|
||||
if (prev != next) {
|
||||
globalState.appController.updateGroupsDebounce();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -2,15 +2,14 @@ import 'dart:math';
|
||||
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/models/common.dart';
|
||||
import 'package:fl_clash/models/config.dart';
|
||||
import 'package:fl_clash/providers/providers.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:fl_clash/widgets/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:riverpod_annotation/experimental/scope.dart';
|
||||
|
||||
import '../../models/common.dart';
|
||||
import 'card.dart';
|
||||
import 'common.dart';
|
||||
|
||||
@@ -61,7 +60,7 @@ class ProxiesTabViewState extends ConsumerState<ProxiesTabView>
|
||||
Future<void> delayTestCurrentGroup() async {
|
||||
final currentGroupName = globalState.appController.getCurrentGroupName();
|
||||
final currentState = _keyMap[currentGroupName]?.currentState;
|
||||
await delayTest(currentState?.proxies ?? [], currentState?.testUrl);
|
||||
await delayTest(currentState?.currentProxies ?? [], currentState?.testUrl);
|
||||
}
|
||||
|
||||
Widget _buildMoreButton() {
|
||||
@@ -182,15 +181,11 @@ class ProxiesTabViewState extends ConsumerState<ProxiesTabView>
|
||||
final children = groups.map((group) {
|
||||
final key = GlobalObjectKey<_ProxyGroupViewState>(group.name);
|
||||
keyMap[group.name] = key;
|
||||
return KeepScope(
|
||||
keep: true,
|
||||
child: ProxyGroupView(
|
||||
key: key,
|
||||
group: group,
|
||||
columns: state.columns,
|
||||
cardType: state.proxyCardType,
|
||||
sortType: state.proxiesSortType,
|
||||
),
|
||||
return ProxyGroupView(
|
||||
key: key,
|
||||
group: group,
|
||||
columns: state.columns,
|
||||
cardType: state.proxyCardType,
|
||||
);
|
||||
}).toList();
|
||||
_keyMap = keyMap;
|
||||
@@ -252,19 +247,16 @@ class ProxiesTabViewState extends ConsumerState<ProxiesTabView>
|
||||
}
|
||||
}
|
||||
|
||||
@Dependencies([proxiesTabState, proxiesTabControllerState])
|
||||
class ProxyGroupView extends ConsumerStatefulWidget {
|
||||
final Group group;
|
||||
final int columns;
|
||||
final ProxyCardType cardType;
|
||||
final ProxiesSortType sortType;
|
||||
|
||||
const ProxyGroupView({
|
||||
super.key,
|
||||
required this.group,
|
||||
required this.columns,
|
||||
required this.cardType,
|
||||
required this.sortType,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -274,7 +266,7 @@ class ProxyGroupView extends ConsumerStatefulWidget {
|
||||
class _ProxyGroupViewState extends ConsumerState<ProxyGroupView> {
|
||||
late final ScrollController _controller;
|
||||
|
||||
List<Proxy> proxies = [];
|
||||
List<Proxy> currentProxies = [];
|
||||
String? testUrl;
|
||||
|
||||
@override
|
||||
@@ -308,7 +300,7 @@ class _ProxyGroupViewState extends ConsumerState<ProxyGroupView> {
|
||||
16 +
|
||||
getScrollToSelectedOffset(
|
||||
groupName: widget.group.name,
|
||||
proxies: proxies,
|
||||
proxies: currentProxies,
|
||||
),
|
||||
_controller.position.maxScrollExtent,
|
||||
),
|
||||
@@ -321,45 +313,36 @@ class _ProxyGroupViewState extends ConsumerState<ProxyGroupView> {
|
||||
Widget build(BuildContext context) {
|
||||
final group = widget.group;
|
||||
final proxies = group.all;
|
||||
final sortedProxies = globalState.appController.getSortProxies(
|
||||
proxies: proxies,
|
||||
sortType: widget.sortType,
|
||||
testUrl: group.testUrl,
|
||||
);
|
||||
this.proxies = sortedProxies;
|
||||
testUrl = group.testUrl;
|
||||
|
||||
return Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: CommonScrollBar(
|
||||
currentProxies = proxies;
|
||||
return CommonScrollBar(
|
||||
controller: _controller,
|
||||
child: GridView.builder(
|
||||
key: _getPageStorageKey(),
|
||||
controller: _controller,
|
||||
child: GridView.builder(
|
||||
key: _getPageStorageKey(),
|
||||
controller: _controller,
|
||||
padding: const EdgeInsets.only(
|
||||
top: 16,
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: 96,
|
||||
),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: widget.columns,
|
||||
mainAxisSpacing: 8,
|
||||
crossAxisSpacing: 8,
|
||||
mainAxisExtent: getItemHeight(widget.cardType),
|
||||
),
|
||||
itemCount: sortedProxies.length,
|
||||
itemBuilder: (_, index) {
|
||||
final proxy = sortedProxies[index];
|
||||
return ProxyCard(
|
||||
testUrl: group.testUrl,
|
||||
groupType: group.type,
|
||||
type: widget.cardType,
|
||||
proxy: proxy,
|
||||
groupName: group.name,
|
||||
);
|
||||
},
|
||||
padding: const EdgeInsets.only(
|
||||
top: 16,
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: 96,
|
||||
),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: widget.columns,
|
||||
mainAxisSpacing: 8,
|
||||
crossAxisSpacing: 8,
|
||||
mainAxisExtent: getItemHeight(widget.cardType),
|
||||
),
|
||||
itemCount: currentProxies.length,
|
||||
itemBuilder: (_, index) {
|
||||
final proxy = currentProxies[index];
|
||||
return ProxyCard(
|
||||
testUrl: group.testUrl,
|
||||
groupType: group.type,
|
||||
type: widget.cardType,
|
||||
proxy: proxy,
|
||||
groupName: group.name,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ packages:
|
||||
source: hosted
|
||||
version: "3.0.6"
|
||||
custom_lint:
|
||||
dependency: "direct dev"
|
||||
dependency: transitive
|
||||
description:
|
||||
name: custom_lint
|
||||
sha256: "78085fbe842de7c5bef92de811ca81536968dbcbbcdac5c316711add2d15e796"
|
||||
@@ -770,10 +770,10 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: json_serializable
|
||||
sha256: ce2cf974ccdee13be2a510832d7fba0b94b364e0b0395dee42abaa51b855be27
|
||||
sha256: "3f2913b7c2430afe8ac5afe6fb15c1de4a60af4f630625e6e238f80ba4b80cbd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.10.0"
|
||||
version: "6.11.0"
|
||||
launch_at_startup:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: fl_clash
|
||||
description: A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free.
|
||||
publish_to: 'none'
|
||||
version: 0.8.88+2025082901
|
||||
version: 0.8.88+2025083101
|
||||
environment:
|
||||
sdk: '>=3.8.0 <4.0.0'
|
||||
|
||||
@@ -74,7 +74,6 @@ dev_dependencies:
|
||||
freezed: ^3.2.0
|
||||
riverpod_generator: ^3.0.0-dev.17
|
||||
riverpod_lint: ^3.0.0-dev.17
|
||||
custom_lint: ^0.8.0
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
||||
Reference in New Issue
Block a user