Compare commits
1 Commits
v0.8.88-pr
...
v0.8.88-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7635a4e086 |
@@ -54,7 +54,7 @@ Support the following actions
|
||||
|
||||
com.follow.clash.action.STOP
|
||||
|
||||
com.follow.clash.action.TOGGLE
|
||||
com.follow.clash.action.CHANGE
|
||||
```
|
||||
|
||||
## Download
|
||||
|
||||
@@ -54,7 +54,7 @@ on Mobile:
|
||||
|
||||
com.follow.clash.action.STOP
|
||||
|
||||
com.follow.clash.action.TOGGLE
|
||||
com.follow.clash.action.CHANGE
|
||||
```
|
||||
|
||||
## 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:
|
||||
|
||||
@@ -29,7 +29,6 @@ android {
|
||||
ndkVersion = libs.versions.ndkVersion.get()
|
||||
|
||||
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
@@ -54,12 +53,6 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
packaging {
|
||||
jniLibs {
|
||||
useLegacyPackaging = true
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
isMinifyEnabled = false
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<permission
|
||||
android:name="${applicationId}.permission.RECEIVE_BROADCASTS"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
@@ -20,23 +24,28 @@
|
||||
<uses-permission
|
||||
android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<application
|
||||
android:name=".Application"
|
||||
android:banner="@mipmap/ic_banner"
|
||||
android:extractNativeLibs="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="FlClash">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name="com.follow.clash.MainActivity"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:exported="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme" />
|
||||
@@ -103,12 +112,33 @@
|
||||
android:exported="true"
|
||||
android:permission="${applicationId}.permission.RECEIVE_BROADCASTS">
|
||||
<intent-filter>
|
||||
<action android:name="${applicationId}.intent.action.START" />
|
||||
<action android:name="${applicationId}.intent.action.STOP" />
|
||||
<action android:name="${applicationId}.intent.action.TOGGLE" />
|
||||
<action android:name="${applicationId}.action.CREATE_VPN" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
|
||||
<provider
|
||||
android:name=".FilesProvider"
|
||||
android:authorities="${applicationId}.files"
|
||||
android:exported="true"
|
||||
android:grantUriPermissions="true"
|
||||
android:permission="android.permission.MANAGE_DOCUMENTS"
|
||||
android:process=":background">
|
||||
<intent-filter>
|
||||
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
|
||||
</intent-filter>
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileProvider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
|
||||
@@ -14,21 +14,11 @@ class BroadcastReceiver : BroadcastReceiver(),
|
||||
CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.Default) {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
when (intent?.action) {
|
||||
BroadcastAction.START.action -> {
|
||||
BroadcastAction.CREATE_VPN.action -> {
|
||||
launch {
|
||||
State.handleStartServiceAction()
|
||||
}
|
||||
}
|
||||
|
||||
BroadcastAction.STOP.action -> {
|
||||
State.handleStopServiceAction()
|
||||
}
|
||||
|
||||
BroadcastAction.TOGGLE.action -> {
|
||||
launch {
|
||||
State.handleToggleAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +1,33 @@
|
||||
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.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.io.ByteArrayOutputStream
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
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() }
|
||||
return@withContext try {
|
||||
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()
|
||||
}
|
||||
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
|
||||
}
|
||||
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 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(
|
||||
method: String, arguments: Any? = null
|
||||
): T? = withContext(Dispatchers.Main) {
|
||||
): T? = withContext(Dispatchers.Main) { // 切换到主线程
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
invokeMethod(method, arguments, object : MethodChannel.Result {
|
||||
override fun success(result: Any?) {
|
||||
@@ -99,12 +51,15 @@ inline fun <reified T : FlutterPlugin> FlutterEngine.plugin(): T? {
|
||||
|
||||
|
||||
fun <T> MethodChannel.invokeMethodOnMainThread(
|
||||
method: String, arguments: Any? = null, callback: ((Result<T>) -> Unit)? = null
|
||||
method: String,
|
||||
arguments: Any? = null,
|
||||
callback: ((Result<T>) -> Unit)? = null
|
||||
) {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
invokeMethod(method, arguments, object : MethodChannel.Result {
|
||||
override fun success(result: Any?) {
|
||||
@Suppress("UNCHECKED_CAST") callback?.invoke(Result.success(result as T))
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
callback?.invoke(Result.success(result as T))
|
||||
}
|
||||
|
||||
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
|
||||
|
||||
@@ -1,33 +1,35 @@
|
||||
package com.follow.clash.service
|
||||
package com.follow.clash
|
||||
|
||||
import android.database.Cursor
|
||||
import android.database.MatrixCursor
|
||||
import android.os.CancellationSignal
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.provider.DocumentsContract
|
||||
import android.provider.DocumentsContract.Document
|
||||
import android.provider.DocumentsContract.Root
|
||||
import android.provider.DocumentsProvider
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
|
||||
|
||||
class FilesProvider : DocumentsProvider() {
|
||||
|
||||
companion object {
|
||||
private const val DEFAULT_ROOT_ID = "0"
|
||||
|
||||
private val DEFAULT_DOCUMENT_COLUMNS = arrayOf(
|
||||
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
|
||||
DocumentsContract.Document.COLUMN_DISPLAY_NAME,
|
||||
DocumentsContract.Document.COLUMN_MIME_TYPE,
|
||||
DocumentsContract.Document.COLUMN_FLAGS,
|
||||
DocumentsContract.Document.COLUMN_SIZE,
|
||||
Document.COLUMN_DOCUMENT_ID,
|
||||
Document.COLUMN_DISPLAY_NAME,
|
||||
Document.COLUMN_MIME_TYPE,
|
||||
Document.COLUMN_FLAGS,
|
||||
Document.COLUMN_SIZE,
|
||||
)
|
||||
private val DEFAULT_ROOT_COLUMNS = arrayOf(
|
||||
DocumentsContract.Root.COLUMN_ROOT_ID,
|
||||
DocumentsContract.Root.COLUMN_FLAGS,
|
||||
DocumentsContract.Root.COLUMN_ICON,
|
||||
DocumentsContract.Root.COLUMN_TITLE,
|
||||
DocumentsContract.Root.COLUMN_SUMMARY,
|
||||
DocumentsContract.Root.COLUMN_DOCUMENT_ID
|
||||
Root.COLUMN_ROOT_ID,
|
||||
Root.COLUMN_FLAGS,
|
||||
Root.COLUMN_ICON,
|
||||
Root.COLUMN_TITLE,
|
||||
Root.COLUMN_SUMMARY,
|
||||
Root.COLUMN_DOCUMENT_ID
|
||||
)
|
||||
}
|
||||
|
||||
@@ -38,12 +40,12 @@ class FilesProvider : DocumentsProvider() {
|
||||
override fun queryRoots(projection: Array<String>?): Cursor {
|
||||
return MatrixCursor(projection ?: DEFAULT_ROOT_COLUMNS).apply {
|
||||
newRow().apply {
|
||||
add(DocumentsContract.Root.COLUMN_ROOT_ID, DEFAULT_ROOT_ID)
|
||||
add(DocumentsContract.Root.COLUMN_FLAGS, DocumentsContract.Root.FLAG_LOCAL_ONLY)
|
||||
add(DocumentsContract.Root.COLUMN_ICON, R.drawable.ic_service)
|
||||
add(DocumentsContract.Root.COLUMN_TITLE, "FlClash")
|
||||
add(DocumentsContract.Root.COLUMN_SUMMARY, "Data")
|
||||
add(DocumentsContract.Root.COLUMN_DOCUMENT_ID, "/")
|
||||
add(Root.COLUMN_ROOT_ID, DEFAULT_ROOT_ID)
|
||||
add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY)
|
||||
add(Root.COLUMN_ICON, R.mipmap.ic_launcher)
|
||||
add(Root.COLUMN_TITLE, "FlClash")
|
||||
add(Root.COLUMN_SUMMARY, "Data")
|
||||
add(Root.COLUMN_DOCUMENT_ID, "/")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,20 +87,20 @@ class FilesProvider : DocumentsProvider() {
|
||||
|
||||
private fun includeFile(result: MatrixCursor, file: File) {
|
||||
result.newRow().apply {
|
||||
add(DocumentsContract.Document.COLUMN_DOCUMENT_ID, file.absolutePath)
|
||||
add(DocumentsContract.Document.COLUMN_DISPLAY_NAME, file.name)
|
||||
add(DocumentsContract.Document.COLUMN_SIZE, file.length())
|
||||
add(Document.COLUMN_DOCUMENT_ID, file.absolutePath)
|
||||
add(Document.COLUMN_DISPLAY_NAME, file.name)
|
||||
add(Document.COLUMN_SIZE, file.length())
|
||||
add(
|
||||
DocumentsContract.Document.COLUMN_FLAGS,
|
||||
DocumentsContract.Document.FLAG_SUPPORTS_WRITE or DocumentsContract.Document.FLAG_SUPPORTS_DELETE
|
||||
Document.COLUMN_FLAGS,
|
||||
Document.FLAG_SUPPORTS_WRITE or Document.FLAG_SUPPORTS_DELETE
|
||||
)
|
||||
add(DocumentsContract.Document.COLUMN_MIME_TYPE, getDocumentType(file))
|
||||
add(Document.COLUMN_MIME_TYPE, getDocumentType(file))
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDocumentType(file: File): String {
|
||||
return if (file.isDirectory) {
|
||||
DocumentsContract.Document.MIME_TYPE_DIR
|
||||
Document.MIME_TYPE_DIR
|
||||
} else {
|
||||
"application/octet-stream"
|
||||
}
|
||||
@@ -1,23 +1,19 @@
|
||||
package com.follow.clash
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import android.os.PersistableBundle
|
||||
import com.follow.clash.common.GlobalState
|
||||
import com.follow.clash.plugins.AppPlugin
|
||||
import com.follow.clash.plugins.ServicePlugin
|
||||
import com.follow.clash.plugins.TilePlugin
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MainActivity : FlutterActivity(),
|
||||
CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.Default) {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
lifecycleScope.launch {
|
||||
class MainActivity : FlutterActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
|
||||
super.onCreate(savedInstanceState, persistentState)
|
||||
GlobalState.launch {
|
||||
State.destroyServiceEngine()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,44 +3,45 @@ package com.follow.clash
|
||||
import com.follow.clash.common.ServiceDelegate
|
||||
import com.follow.clash.common.intent
|
||||
import com.follow.clash.service.ICallbackInterface
|
||||
import com.follow.clash.service.IMessageInterface
|
||||
import com.follow.clash.service.IRemoteInterface
|
||||
import com.follow.clash.service.RemoteService
|
||||
import com.follow.clash.service.models.NotificationParams
|
||||
import com.follow.clash.service.models.VpnOptions
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
object Service {
|
||||
private val delegate by lazy {
|
||||
ServiceDelegate<IRemoteInterface>(
|
||||
RemoteService::class.intent, ::handleServiceDisconnected
|
||||
RemoteService::class.intent, ::handleOnServiceCrash
|
||||
) {
|
||||
IRemoteInterface.Stub.asInterface(it)
|
||||
}
|
||||
}
|
||||
|
||||
var onServiceDisconnected: ((String) -> Unit)? = null
|
||||
var onServiceCrash: (() -> Unit)? = null
|
||||
|
||||
private fun handleServiceDisconnected(message: String) {
|
||||
onServiceDisconnected?.let {
|
||||
it(message)
|
||||
private fun handleOnServiceCrash() {
|
||||
bindingState.set(false)
|
||||
onServiceCrash?.let {
|
||||
it()
|
||||
}
|
||||
}
|
||||
|
||||
fun bind() {
|
||||
delegate.bind()
|
||||
}
|
||||
private val bindingState = AtomicBoolean(false)
|
||||
|
||||
fun unbind() {
|
||||
delegate.unbind()
|
||||
fun bind() {
|
||||
if (bindingState.compareAndSet(false, true)) {
|
||||
delegate.bind()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun invokeAction(
|
||||
data: String, cb: (result: ByteArray?, isSuccess: Boolean) -> Unit
|
||||
): Result<Unit> {
|
||||
return delegate.useService {
|
||||
data: String, cb: (result: String?) -> Unit
|
||||
) {
|
||||
delegate.useService {
|
||||
it.invokeAction(data, object : ICallbackInterface.Stub() {
|
||||
override fun onResult(result: ByteArray?, isSuccess: Boolean) {
|
||||
cb(result, isSuccess)
|
||||
override fun onResult(result: String?) {
|
||||
cb(result)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -48,17 +49,17 @@ object Service {
|
||||
|
||||
suspend fun updateNotificationParams(
|
||||
params: NotificationParams
|
||||
): Result<Unit> {
|
||||
return delegate.useService {
|
||||
) {
|
||||
delegate.useService {
|
||||
it.updateNotificationParams(params)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun setMessageCallback(
|
||||
cb: (result: String?) -> Unit
|
||||
): Result<Unit> {
|
||||
return delegate.useService {
|
||||
it.setMessageCallback(object : IMessageInterface.Stub() {
|
||||
) {
|
||||
delegate.useService {
|
||||
it.setMessageCallback(object : ICallbackInterface.Stub() {
|
||||
override fun onResult(result: String?) {
|
||||
cb(result)
|
||||
}
|
||||
|
||||
@@ -53,18 +53,12 @@ object State {
|
||||
|
||||
suspend fun handleStartServiceAction() {
|
||||
tilePlugin?.handleStart()
|
||||
if (flutterEngine != null) {
|
||||
return
|
||||
}
|
||||
startServiceWithEngine()
|
||||
}
|
||||
|
||||
fun handleStopServiceAction() {
|
||||
suspend fun handleStopServiceAction() {
|
||||
tilePlugin?.handleStop()
|
||||
if (flutterEngine != null || serviceFlutterEngine != null) {
|
||||
return
|
||||
}
|
||||
handleStopService()
|
||||
destroyServiceEngine()
|
||||
}
|
||||
|
||||
fun handleStartService() {
|
||||
@@ -79,16 +73,15 @@ object State {
|
||||
|
||||
suspend fun destroyServiceEngine() {
|
||||
runLock.withLock {
|
||||
withContext(Dispatchers.Main) {
|
||||
runCatching {
|
||||
serviceFlutterEngine?.destroy()
|
||||
serviceFlutterEngine = null
|
||||
}
|
||||
}
|
||||
serviceFlutterEngine?.destroy()
|
||||
serviceFlutterEngine = null
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun startServiceWithEngine() {
|
||||
if (flutterEngine != null) {
|
||||
return
|
||||
}
|
||||
runLock.withLock {
|
||||
withContext(Dispatchers.Main) {
|
||||
serviceFlutterEngine = FlutterEngine(GlobalState.application)
|
||||
@@ -107,9 +100,6 @@ object State {
|
||||
private fun startService() {
|
||||
GlobalState.launch {
|
||||
runLock.withLock {
|
||||
if (runStateFlow.value == RunState.PENDING || runStateFlow.value == RunState.START) {
|
||||
return@launch
|
||||
}
|
||||
runStateFlow.tryEmit(RunState.PENDING)
|
||||
if (servicePlugin == null) {
|
||||
return@launch
|
||||
@@ -119,9 +109,9 @@ object State {
|
||||
return@launch
|
||||
}
|
||||
appPlugin?.prepare(options.enable) {
|
||||
runTime = System.currentTimeMillis()
|
||||
Service.startService(options, true)
|
||||
servicePlugin?.startService(options, true)
|
||||
runStateFlow.tryEmit(RunState.START)
|
||||
runTime = System.currentTimeMillis()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,15 +121,11 @@ object State {
|
||||
fun handleStopService() {
|
||||
GlobalState.launch {
|
||||
runLock.withLock {
|
||||
if (runStateFlow.value == RunState.PENDING || runStateFlow.value == RunState.STOP) {
|
||||
return@launch
|
||||
}
|
||||
runStateFlow.tryEmit(RunState.PENDING)
|
||||
Service.stopService()
|
||||
servicePlugin?.stopService()
|
||||
runStateFlow.tryEmit(RunState.STOP)
|
||||
runTime = 0
|
||||
}
|
||||
destroyServiceEngine()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ class TempActivity : Activity(),
|
||||
}
|
||||
|
||||
QuickAction.STOP.action -> {
|
||||
State.handleStopServiceAction()
|
||||
launch {
|
||||
State.handleStopServiceAction()
|
||||
}
|
||||
}
|
||||
|
||||
QuickAction.TOGGLE.action -> {
|
||||
|
||||
@@ -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.getPackageIconPath
|
||||
import com.follow.clash.getBase64
|
||||
import com.follow.clash.models.Package
|
||||
import com.google.gson.Gson
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
@@ -57,7 +57,9 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
|
||||
private var vpnPrepareCallback: (suspend () -> Unit)? = null
|
||||
|
||||
private var requestNotificationCallback: (() -> Unit)? = null
|
||||
|
||||
|
||||
private val iconMap = mutableMapOf<String, String?>()
|
||||
|
||||
private val packages = mutableListOf<Package>()
|
||||
|
||||
private val skipPrefixList = listOf(
|
||||
@@ -148,7 +150,26 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
|
||||
}
|
||||
|
||||
"getPackageIcon" -> {
|
||||
handleGetPackageIcon(call, result)
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"tip" -> {
|
||||
@@ -163,18 +184,6 @@ 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)
|
||||
@@ -214,18 +223,31 @@ 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
|
||||
if (packages.isNotEmpty()) return packages
|
||||
packageManager?.getInstalledPackages(PackageManager.GET_META_DATA or PackageManager.GET_PERMISSIONS)
|
||||
?.filter {
|
||||
it.packageName != GlobalState.application.packageName && it.packageName != "android"
|
||||
it.packageName != GlobalState.application.packageName || it.packageName == "android"
|
||||
|
||||
}?.map {
|
||||
Package(
|
||||
packageName = it.packageName,
|
||||
label = it.applicationInfo?.loadLabel(packageManager).toString(),
|
||||
system = (it.applicationInfo?.flags?.and(ApplicationInfo.FLAG_SYSTEM)) != 0,
|
||||
system = (it.applicationInfo?.flags?.and(ApplicationInfo.FLAG_SYSTEM)) == 1,
|
||||
lastUpdateTime = it.lastUpdateTime,
|
||||
internet = it.requestedPermissions?.contains(Manifest.permission.INTERNET) == true
|
||||
)
|
||||
@@ -263,12 +285,9 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
|
||||
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
|
||||
NOTIFICATION_PERMISSION_REQUEST_CODE
|
||||
)
|
||||
return
|
||||
}
|
||||
return
|
||||
} else {
|
||||
invokeRequestNotificationCallback()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun invokeRequestNotificationCallback() {
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package com.follow.clash.plugins
|
||||
|
||||
import com.follow.clash.RunState
|
||||
import com.follow.clash.Service
|
||||
import com.follow.clash.State
|
||||
import com.follow.clash.awaitResult
|
||||
import com.follow.clash.common.Components
|
||||
import com.follow.clash.common.formatString
|
||||
import com.follow.clash.invokeMethodOnMainThread
|
||||
import com.follow.clash.models.AppState
|
||||
import com.follow.clash.service.models.NotificationParams
|
||||
@@ -41,10 +39,6 @@ class ServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
|
||||
handleInit(result)
|
||||
}
|
||||
|
||||
"shutdown" -> {
|
||||
handleShutdown(result)
|
||||
}
|
||||
|
||||
"invokeAction" -> {
|
||||
handleInvokeAction(call, result)
|
||||
}
|
||||
@@ -73,21 +67,12 @@ class ServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
|
||||
private fun handleInvokeAction(call: MethodCall, result: MethodChannel.Result) {
|
||||
launch {
|
||||
val data = call.arguments<String>()!!
|
||||
val res = mutableListOf<ByteArray>()
|
||||
Service.invokeAction(data) { byteArray, isSuccess ->
|
||||
res.add(byteArray ?: byteArrayOf())
|
||||
if (isSuccess) {
|
||||
result.success(res.formatString())
|
||||
}
|
||||
Service.invokeAction(data) {
|
||||
result.success(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleShutdown(result: MethodChannel.Result) {
|
||||
Service.unbind()
|
||||
result.success(true)
|
||||
}
|
||||
|
||||
private fun handleStart(result: MethodChannel.Result) {
|
||||
State.handleStartService()
|
||||
result.success(true)
|
||||
@@ -103,6 +88,14 @@ class ServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
|
||||
return Gson().fromJson(res, VpnOptions::class.java)
|
||||
}
|
||||
|
||||
suspend fun startService(options: VpnOptions, inApp: Boolean) {
|
||||
Service.startService(options, inApp)
|
||||
}
|
||||
|
||||
suspend fun stopService() {
|
||||
Service.stopService()
|
||||
}
|
||||
|
||||
val semaphore = Semaphore(10)
|
||||
|
||||
fun handleSendEvent(value: String?) {
|
||||
@@ -113,9 +106,8 @@ class ServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
|
||||
}
|
||||
}
|
||||
|
||||
private fun onServiceDisconnected(message: String) {
|
||||
State.runStateFlow.tryEmit(RunState.STOP)
|
||||
flutterMethodChannel.invokeMethodOnMainThread<Any>("crash", message)
|
||||
private fun onServiceCrash() {
|
||||
flutterMethodChannel.invokeMethodOnMainThread<Any>("crash", null)
|
||||
}
|
||||
|
||||
private fun handleSyncState(call: MethodCall, result: MethodChannel.Result) {
|
||||
@@ -128,27 +120,21 @@ class ServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
|
||||
stopText = params.stopText,
|
||||
onlyStatisticsProxy = params.onlyStatisticsProxy
|
||||
)
|
||||
).onSuccess {
|
||||
result.success("")
|
||||
}.onFailure {
|
||||
result.success(it.message)
|
||||
}
|
||||
)
|
||||
result.success(true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun handleInit(result: MethodChannel.Result) {
|
||||
Service.bind()
|
||||
launch {
|
||||
Service.bind()
|
||||
Service.setMessageCallback {
|
||||
handleSendEvent(it)
|
||||
}.onSuccess {
|
||||
result.success("")
|
||||
}.onFailure {
|
||||
result.success(it.message)
|
||||
}
|
||||
|
||||
result.success(true)
|
||||
}
|
||||
Service.onServiceDisconnected = ::onServiceDisconnected
|
||||
Service.onServiceCrash = ::onServiceCrash
|
||||
}
|
||||
|
||||
private fun handleGetRunTime(result: MethodChannel.Result) {
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<permission
|
||||
android:name="${applicationId}.permission.RECEIVE_BROADCASTS"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<uses-permission android:name="${applicationId}.permission.RECEIVE_BROADCASTS" />
|
||||
</manifest>
|
||||
@@ -10,7 +10,4 @@ object Components {
|
||||
|
||||
val TEMP_ACTIVITY =
|
||||
ComponentName(GlobalState.packageName, "${PACKAGE_NAME}.TempActivity")
|
||||
|
||||
val BROADCAST_RECEIVER =
|
||||
ComponentName(GlobalState.packageName, "${PACKAGE_NAME}.BroadcastReceiver")
|
||||
}
|
||||
@@ -10,9 +10,7 @@ enum class QuickAction {
|
||||
}
|
||||
|
||||
enum class BroadcastAction {
|
||||
START,
|
||||
STOP,
|
||||
TOGGLE,
|
||||
CREATE_VPN,
|
||||
}
|
||||
|
||||
enum class AccessControlMode {
|
||||
|
||||
@@ -13,21 +13,14 @@ import android.content.Context.RECEIVER_NOT_EXPORTED
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.ServiceConnection
|
||||
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
|
||||
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.IBinder
|
||||
import android.os.Looper
|
||||
import android.os.RemoteException
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.retryWhen
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.nio.charset.Charset
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
//fun Context.startForegroundServiceCompat(intent: Intent?) {
|
||||
@@ -43,35 +36,24 @@ val KClass<*>.intent: Intent
|
||||
|
||||
fun Service.startForegroundCompat(id: Int, notification: Notification) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
startForeground(id, notification, FOREGROUND_SERVICE_TYPE_SPECIAL_USE)
|
||||
startForeground(id, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC)
|
||||
} else {
|
||||
startForeground(id, notification)
|
||||
}
|
||||
}
|
||||
|
||||
val ComponentName.intent: Intent
|
||||
get() = Intent().apply {
|
||||
setComponent(this@intent)
|
||||
setPackage(GlobalState.packageName)
|
||||
}
|
||||
|
||||
val QuickAction.action: String
|
||||
val Enum<*>.action: String
|
||||
get() = "${GlobalState.application.packageName}.action.${this.name}"
|
||||
|
||||
val QuickAction.quickIntent: Intent
|
||||
get() = Components.TEMP_ACTIVITY.intent.apply {
|
||||
get() = Intent().apply {
|
||||
Log.d("[quickIntent]", Components.TEMP_ACTIVITY.toString())
|
||||
setComponent(Components.TEMP_ACTIVITY)
|
||||
setPackage(GlobalState.packageName)
|
||||
action = this@quickIntent.action
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
|
||||
}
|
||||
|
||||
val BroadcastAction.action: String
|
||||
get() = "${GlobalState.application.packageName}.intent.action.${this.name}"
|
||||
|
||||
val BroadcastAction.quickIntent: Intent
|
||||
get() = Components.BROADCAST_RECEIVER.intent.apply {
|
||||
action = this@quickIntent.action
|
||||
}
|
||||
|
||||
fun BroadcastAction.sendBroadcast() {
|
||||
val intent = Intent().apply {
|
||||
action = this@sendBroadcast.action
|
||||
@@ -134,54 +116,62 @@ fun Context.receiveBroadcastFlow(
|
||||
}
|
||||
|
||||
|
||||
sealed class BindServiceEvent<out T : IBinder> {
|
||||
data class Connected<T : IBinder>(val binder: T) : BindServiceEvent<T>()
|
||||
object Disconnected : BindServiceEvent<Nothing>()
|
||||
object Crashed : BindServiceEvent<Nothing>()
|
||||
}
|
||||
|
||||
inline fun <reified T : IBinder> Context.bindServiceFlow(
|
||||
intent: Intent,
|
||||
flags: Int = Context.BIND_AUTO_CREATE,
|
||||
maxRetries: Int = 5,
|
||||
retryDelayMillis: Long = 200L
|
||||
): Flow<Pair<IBinder?, String>> = callbackFlow {
|
||||
): Flow<BindServiceEvent<T>> = callbackFlow {
|
||||
var currentBinder: IBinder? = null
|
||||
val deathRecipient = IBinder.DeathRecipient {
|
||||
trySend(BindServiceEvent.Crashed)
|
||||
}
|
||||
|
||||
val connection = object : ServiceConnection {
|
||||
override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
|
||||
if (binder != null) {
|
||||
try {
|
||||
binder.linkToDeath(deathRecipient, 0)
|
||||
currentBinder = binder
|
||||
@Suppress("UNCHECKED_CAST") val casted = binder as? T
|
||||
if (casted != null) {
|
||||
trySend(Pair(casted, ""))
|
||||
trySend(BindServiceEvent.Connected(casted))
|
||||
} else {
|
||||
trySend(Pair(null, "Binder is not of type ${T::class.java}"))
|
||||
GlobalState.log("Binder is not of type ${T::class.java}")
|
||||
trySend(BindServiceEvent.Disconnected)
|
||||
}
|
||||
} catch (e: RemoteException) {
|
||||
trySend(Pair(null, "Failed to link to death: ${e.message}"))
|
||||
GlobalState.log("Failed to link to death: ${e.message}")
|
||||
binder.unlinkToDeath(deathRecipient, 0)
|
||||
trySend(BindServiceEvent.Disconnected)
|
||||
}
|
||||
} else {
|
||||
trySend(Pair(null, "Binder empty"))
|
||||
trySend(BindServiceEvent.Disconnected)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(name: ComponentName?) {
|
||||
trySend(Pair(null, "Service disconnected"))
|
||||
GlobalState.log("Service disconnected")
|
||||
currentBinder?.unlinkToDeath(deathRecipient, 0)
|
||||
currentBinder = null
|
||||
trySend(BindServiceEvent.Disconnected)
|
||||
}
|
||||
}
|
||||
|
||||
val success = withContext(Dispatchers.Main) {
|
||||
bindService(intent, connection, flags)
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
throw IllegalStateException("bindService() failed, will retry")
|
||||
if (!bindService(intent, connection, flags)) {
|
||||
GlobalState.log("Failed to bind service")
|
||||
trySend(BindServiceEvent.Disconnected)
|
||||
close()
|
||||
return@callbackFlow
|
||||
}
|
||||
|
||||
awaitClose {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
unbindService(connection)
|
||||
}
|
||||
}
|
||||
}.retryWhen { cause, attempt ->
|
||||
if (attempt < maxRetries && cause is Exception) {
|
||||
delay(retryDelayMillis)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
currentBinder?.unlinkToDeath(deathRecipient, 0)
|
||||
unbindService(connection)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,37 +192,4 @@ val Long.formatBytes: String
|
||||
} else {
|
||||
"%.1f${units[unitIndex]}".format(size)
|
||||
}
|
||||
}
|
||||
|
||||
fun String.chunkedForAidl(charset: Charset = Charsets.UTF_8): List<ByteArray> {
|
||||
val allBytes = toByteArray(charset)
|
||||
val total = allBytes.size
|
||||
|
||||
val maxBytes = when {
|
||||
total <= 100 * 1024 -> total
|
||||
total <= 1024 * 1024 -> 64 * 1024
|
||||
total <= 10 * 1024 * 1024 -> 128 * 1024
|
||||
else -> 256 * 1024
|
||||
}
|
||||
|
||||
val result = mutableListOf<ByteArray>()
|
||||
var index = 0
|
||||
while (index < total) {
|
||||
val end = minOf(index + maxBytes, total)
|
||||
result.add(allBytes.copyOfRange(index, end))
|
||||
index = end
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
fun <T : List<ByteArray>> T.formatString(charset: Charset = Charsets.UTF_8): String {
|
||||
val totalSize = this.sumOf { it.size }
|
||||
val combined = ByteArray(totalSize)
|
||||
var offset = 0
|
||||
forEach { byteArray ->
|
||||
byteArray.copyInto(combined, offset)
|
||||
offset += byteArray.size
|
||||
}
|
||||
return String(combined, charset)
|
||||
}
|
||||
}
|
||||
@@ -8,65 +8,62 @@ import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
|
||||
class ServiceDelegate<T>(
|
||||
private val intent: Intent,
|
||||
private val onServiceDisconnected: ((String) -> Unit)? = null,
|
||||
private val onServiceCrash: (() -> Unit)? = null,
|
||||
private val interfaceCreator: (IBinder) -> T,
|
||||
) : CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.Default) {
|
||||
|
||||
private val _bindingState = AtomicBoolean(false)
|
||||
private val _service = MutableStateFlow<T?>(null)
|
||||
|
||||
private var _serviceState = MutableStateFlow<Pair<T?, String>?>(null)
|
||||
val service: StateFlow<T?> = _service
|
||||
|
||||
val serviceState: StateFlow<Pair<T?, String>?> = _serviceState
|
||||
private var job: Job? = null
|
||||
private var bindJob: Job? = null
|
||||
private fun handleBindEvent(event: BindServiceEvent<IBinder>) {
|
||||
when (event) {
|
||||
is BindServiceEvent.Connected -> {
|
||||
_service.value = event.binder.let(interfaceCreator)
|
||||
}
|
||||
|
||||
private fun handleBind(data: Pair<IBinder?, String>) {
|
||||
data.first?.let {
|
||||
_serviceState.value = Pair(interfaceCreator(it), data.second)
|
||||
} ?: run {
|
||||
_serviceState.value = Pair(null, data.second)
|
||||
unbind()
|
||||
onServiceDisconnected?.invoke(data.second)
|
||||
_bindingState.set(false)
|
||||
is BindServiceEvent.Disconnected -> {
|
||||
_service.value = null
|
||||
}
|
||||
|
||||
is BindServiceEvent.Crashed -> {
|
||||
_service.value = null
|
||||
onServiceCrash?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun bind() {
|
||||
if (_bindingState.compareAndSet(false, true)) {
|
||||
job?.cancel()
|
||||
job = null
|
||||
_serviceState.value = null
|
||||
job = launch {
|
||||
GlobalState.application.bindServiceFlow<IBinder>(intent).collect { handleBind(it) }
|
||||
unbind()
|
||||
bindJob = launch {
|
||||
GlobalState.application.bindServiceFlow<IBinder>(intent).collect { it ->
|
||||
handleBindEvent(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend inline fun <R> useService(
|
||||
timeoutMillis: Long = 5000, crossinline block: (T) -> R
|
||||
): Result<R> {
|
||||
return runCatching {
|
||||
withTimeout(timeoutMillis) {
|
||||
val state = serviceState.filterNotNull().first()
|
||||
state.first?.let {
|
||||
block(it)
|
||||
} ?: throw Exception(state.second)
|
||||
suspend inline fun <R> useService(crossinline block: (T) -> R): Result<R> {
|
||||
return withTimeoutOrNull(10_000) {
|
||||
service.first { it != null }
|
||||
}?.let { service ->
|
||||
try {
|
||||
Result.success(block(service))
|
||||
} catch (e: Exception) {
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
} ?: Result.failure(Exception("Service connection timeout"))
|
||||
}
|
||||
|
||||
fun unbind() {
|
||||
if (_bindingState.compareAndSet(true, false)) {
|
||||
job?.cancel()
|
||||
job = null
|
||||
_serviceState.value = null
|
||||
}
|
||||
_service.value = null
|
||||
bindJob?.cancel()
|
||||
bindJob = null
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
</manifest>
|
||||
@@ -9,14 +9,14 @@
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_follow_clash_core_Core_startTun(JNIEnv *env, jobject thiz, jint fd, jobject cb,
|
||||
jstring stack, jstring address, jstring dns) {
|
||||
jstring address, jstring dns) {
|
||||
const auto interface = new_global(cb);
|
||||
startTUN(interface, fd, get_string(stack), get_string(address), get_string(dns));
|
||||
startTUN(interface, fd, get_string(address), get_string(dns));
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_follow_clash_core_Core_stopTun(JNIEnv *env, jobject thiz) {
|
||||
Java_com_follow_clash_core_Core_stopTun(JNIEnv *) {
|
||||
stopTun();
|
||||
}
|
||||
|
||||
@@ -50,14 +50,16 @@ extern "C"
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_follow_clash_core_Core_getTraffic(JNIEnv *env, jobject thiz,
|
||||
const jboolean only_statistics_proxy) {
|
||||
return new_string(getTraffic(only_statistics_proxy));
|
||||
scoped_string res = getTraffic(only_statistics_proxy);
|
||||
return new_string(res);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_follow_clash_core_Core_getTotalTraffic(JNIEnv *env, jobject thiz,
|
||||
const jboolean only_statistics_proxy) {
|
||||
return new_string(getTotalTraffic(only_statistics_proxy));
|
||||
scoped_string res = getTotalTraffic(only_statistics_proxy);
|
||||
return new_string(res);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -77,10 +79,6 @@ static void release_jni_object_impl(void *obj) {
|
||||
del_global(static_cast<jobject>(obj));
|
||||
}
|
||||
|
||||
static void free_string_impl(char *str) {
|
||||
free(str);
|
||||
}
|
||||
|
||||
static void call_tun_interface_protect_impl(void *tun_interface, const int fd) {
|
||||
ATTACH_JNI();
|
||||
env->CallVoidMethod(static_cast<jobject>(tun_interface),
|
||||
@@ -95,12 +93,12 @@ call_tun_interface_resolve_process_impl(void *tun_interface, const int protocol,
|
||||
const int uid) {
|
||||
ATTACH_JNI();
|
||||
const auto packageName = reinterpret_cast<jstring>(env->CallObjectMethod(
|
||||
static_cast<jobject>(tun_interface),
|
||||
m_tun_interface_resolve_process,
|
||||
protocol,
|
||||
new_string(source),
|
||||
new_string(target),
|
||||
uid));
|
||||
static_cast<jobject>(tun_interface),
|
||||
m_tun_interface_resolve_process,
|
||||
protocol,
|
||||
new_string(source),
|
||||
new_string(target),
|
||||
uid));
|
||||
return get_string(packageName);
|
||||
}
|
||||
|
||||
@@ -136,7 +134,6 @@ JNI_OnLoad(JavaVM *vm, void *) {
|
||||
resolve_process_func = &call_tun_interface_resolve_process_impl;
|
||||
result_func = &call_invoke_interface_result_impl;
|
||||
release_object_func = &release_jni_object_impl;
|
||||
free_string_func = &free_string_impl;
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
@@ -144,7 +141,7 @@ JNI_OnLoad(JavaVM *vm, void *) {
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_follow_clash_core_Core_startTun(JNIEnv *env, jobject thiz, jint fd, jobject cb,
|
||||
jstring stack, jstring address, jstring dns) {
|
||||
jstring address, jstring dns) {
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -187,4 +184,4 @@ extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_follow_clash_core_Core_suspended(JNIEnv *env, jobject thiz, jboolean suspended) {
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -8,7 +8,6 @@ data object Core {
|
||||
private external fun startTun(
|
||||
fd: Int,
|
||||
cb: TunInterface,
|
||||
stack: String,
|
||||
address: String,
|
||||
dns: String,
|
||||
)
|
||||
@@ -30,7 +29,6 @@ data object Core {
|
||||
fd: Int,
|
||||
protect: (Int) -> Boolean,
|
||||
resolverProcess: (protocol: Int, source: InetSocketAddress, target: InetSocketAddress, uid: Int) -> String,
|
||||
stack: String,
|
||||
address: String,
|
||||
dns: String,
|
||||
) {
|
||||
@@ -55,7 +53,6 @@ data object Core {
|
||||
)
|
||||
}
|
||||
},
|
||||
stack,
|
||||
address,
|
||||
dns
|
||||
)
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
<application>
|
||||
<service
|
||||
android:name=".VpnService"
|
||||
android:name="com.follow.clash.service.VpnService"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="specialUse"
|
||||
android:foregroundServiceType="dataSync"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE"
|
||||
android:process=":remote">
|
||||
android:process=":background">
|
||||
<intent-filter>
|
||||
<action android:name="android.net.VpnService" />
|
||||
</intent-filter>
|
||||
@@ -19,31 +19,18 @@
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".CommonService"
|
||||
android:name="com.follow.clash.service.CommonService"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="specialUse"
|
||||
android:process=":remote">
|
||||
android:foregroundServiceType="dataSync"
|
||||
android:process=":background">
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="service" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".RemoteService"
|
||||
android:enabled="true"
|
||||
android:name="com.follow.clash.service.RemoteService"
|
||||
android:exported="false"
|
||||
android:process=":remote" />
|
||||
|
||||
<provider
|
||||
android:name=".FilesProvider"
|
||||
android:authorities="${applicationId}.files"
|
||||
android:exported="true"
|
||||
android:grantUriPermissions="true"
|
||||
android:permission="android.permission.MANAGE_DOCUMENTS"
|
||||
android:process=":remote">
|
||||
<intent-filter>
|
||||
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
|
||||
</intent-filter>
|
||||
</provider>
|
||||
android:process=":background" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -2,5 +2,5 @@
|
||||
package com.follow.clash.service;
|
||||
|
||||
interface ICallbackInterface {
|
||||
void onResult(in byte[] result, boolean isSuccess);
|
||||
void onResult(String result);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// IMessageInterface.aidl
|
||||
package com.follow.clash.service;
|
||||
|
||||
interface IMessageInterface {
|
||||
void onResult(String result);
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
package com.follow.clash.service;
|
||||
|
||||
import com.follow.clash.service.ICallbackInterface;
|
||||
import com.follow.clash.service.IMessageInterface;
|
||||
import com.follow.clash.service.models.VpnOptions;
|
||||
import com.follow.clash.service.models.NotificationParams;
|
||||
|
||||
@@ -11,5 +10,5 @@ interface IRemoteInterface {
|
||||
void updateNotificationParams(in NotificationParams params);
|
||||
void startService(in VpnOptions options,in boolean inApp);
|
||||
void stopService();
|
||||
void setMessageCallback(in IMessageInterface messageCallback);
|
||||
void setMessageCallback(in ICallbackInterface messageCallback);
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import com.follow.clash.common.sendBroadcast
|
||||
interface IBaseService {
|
||||
fun handleCreate() {
|
||||
if (!State.inApp) {
|
||||
BroadcastAction.START.sendBroadcast()
|
||||
BroadcastAction.CREATE_VPN.sendBroadcast()
|
||||
} else {
|
||||
State.inApp = false
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import com.follow.clash.common.ServiceDelegate
|
||||
import com.follow.clash.common.chunkedForAidl
|
||||
import com.follow.clash.common.intent
|
||||
import com.follow.clash.core.Core
|
||||
import com.follow.clash.service.models.NotificationParams
|
||||
@@ -23,16 +22,11 @@ class RemoteService : Service(),
|
||||
launch {
|
||||
delegate?.useService { service ->
|
||||
service.stop()
|
||||
delegate?.unbind()
|
||||
}
|
||||
delegate?.unbind()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleServiceDisconnected(message: String) {
|
||||
intent = null
|
||||
delegate = null
|
||||
}
|
||||
|
||||
private fun handleStartService() {
|
||||
launch {
|
||||
val nextIntent = when (State.options?.enable == true) {
|
||||
@@ -41,7 +35,7 @@ class RemoteService : Service(),
|
||||
}
|
||||
if (intent != nextIntent) {
|
||||
delegate?.unbind()
|
||||
delegate = ServiceDelegate(nextIntent, ::handleServiceDisconnected) { binder ->
|
||||
delegate = ServiceDelegate(nextIntent, {}) { binder ->
|
||||
when (binder) {
|
||||
is VpnService.LocalBinder -> binder.getService()
|
||||
is CommonService.LocalBinder -> binder.getService()
|
||||
@@ -57,15 +51,9 @@ class RemoteService : Service(),
|
||||
}
|
||||
}
|
||||
|
||||
private val binder = object : IRemoteInterface.Stub() {
|
||||
private val binder: IRemoteInterface.Stub = object : IRemoteInterface.Stub() {
|
||||
override fun invokeAction(data: String, callback: ICallbackInterface) {
|
||||
Core.invokeAction(data) {
|
||||
val chunks = it?.chunkedForAidl() ?: listOf()
|
||||
val totalSize = chunks.size
|
||||
chunks.forEachIndexed { index, chunk ->
|
||||
callback.onResult(chunk, totalSize - 1 == index)
|
||||
}
|
||||
}
|
||||
Core.invokeAction(data, callback::onResult)
|
||||
}
|
||||
|
||||
override fun updateNotificationParams(params: NotificationParams?) {
|
||||
@@ -84,7 +72,7 @@ class RemoteService : Service(),
|
||||
handleStopService()
|
||||
}
|
||||
|
||||
override fun setMessageCallback(messageCallback: IMessageInterface) {
|
||||
override fun setMessageCallback(messageCallback: ICallbackInterface) {
|
||||
setMessageCallback(messageCallback::onResult)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@ import android.os.RemoteException
|
||||
import android.util.Log
|
||||
import androidx.core.content.getSystemService
|
||||
import com.follow.clash.common.AccessControlMode
|
||||
import com.follow.clash.common.BroadcastAction
|
||||
import com.follow.clash.common.sendBroadcast
|
||||
import com.follow.clash.common.QuickAction
|
||||
import com.follow.clash.common.quickIntent
|
||||
import com.follow.clash.common.toPendingIntent
|
||||
import com.follow.clash.core.Core
|
||||
import com.follow.clash.service.models.VpnOptions
|
||||
import com.follow.clash.service.models.getIpv4RouteAddress
|
||||
@@ -43,7 +44,6 @@ class VpnService : SystemVpnService(), IBaseService,
|
||||
super.onCreate()
|
||||
handleCreate()
|
||||
}
|
||||
|
||||
private val connectivity by lazy {
|
||||
getSystemService<ConnectivityManager>()
|
||||
}
|
||||
@@ -107,7 +107,7 @@ class VpnService : SystemVpnService(), IBaseService,
|
||||
try {
|
||||
val isSuccess = super.onTransact(code, data, reply, flags)
|
||||
if (!isSuccess) {
|
||||
BroadcastAction.STOP.sendBroadcast()
|
||||
QuickAction.STOP.quickIntent.toPendingIntent.send()
|
||||
}
|
||||
return isSuccess
|
||||
} catch (e: RemoteException) {
|
||||
@@ -220,7 +220,6 @@ class VpnService : SystemVpnService(), IBaseService,
|
||||
fd,
|
||||
protect = this::protect,
|
||||
resolverProcess = this::resolverProcess,
|
||||
options.stack,
|
||||
options.address,
|
||||
options.dns
|
||||
)
|
||||
|
||||
@@ -23,7 +23,6 @@ data class VpnOptions(
|
||||
val allowBypass: Boolean,
|
||||
val systemProxy: Boolean,
|
||||
val bypassDomain: List<String>,
|
||||
val stack: String,
|
||||
val routeAddress: List<String>,
|
||||
) : Parcelable
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ class NetworkObserveModule(private val service: Service) : Module() {
|
||||
private val connectivity by lazy {
|
||||
service.getSystemService<ConnectivityManager>()
|
||||
}
|
||||
private var preDnsList = listOf<String>()
|
||||
|
||||
private val request = NetworkRequest.Builder().apply {
|
||||
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
|
||||
@@ -62,7 +61,6 @@ class NetworkObserveModule(private val service: Service) : Module() {
|
||||
|
||||
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
|
||||
networkInfos[network]?.dnsList = linkProperties.dnsServers
|
||||
onUpdateNetwork()
|
||||
setUnderlyingNetworks(network)
|
||||
super.onLinkPropertiesChanged(network, linkProperties)
|
||||
}
|
||||
@@ -98,11 +96,7 @@ class NetworkObserveModule(private val service: Service) : Module() {
|
||||
fun onUpdateNetwork() {
|
||||
val dnsList = (networkInfos.asSequence().minByOrNull { networkToInt(it) }?.value?.dnsList
|
||||
?: emptyList()).map { x -> x.asSocketAddressText(53) }
|
||||
if (dnsList == preDnsList) {
|
||||
return
|
||||
}
|
||||
preDnsList = dnsList
|
||||
Core.updateDNS(dnsList.toSet().joinToString(","))
|
||||
Core.updateDNS(dnsList.joinToString { "," })
|
||||
}
|
||||
|
||||
fun setUnderlyingNetworks(network: Network) {
|
||||
|
||||
@@ -25,30 +25,18 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.flow.zip
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
data class ExtendedNotificationParams(
|
||||
val title: String,
|
||||
val stopText: String,
|
||||
val onlyStatisticsProxy: Boolean,
|
||||
val contentText: String,
|
||||
)
|
||||
|
||||
val NotificationParams.extended: ExtendedNotificationParams
|
||||
get() = ExtendedNotificationParams(
|
||||
title, stopText, onlyStatisticsProxy, Core.getSpeedTrafficText(onlyStatisticsProxy)
|
||||
)
|
||||
|
||||
class NotificationModule(private val service: Service) : Module() {
|
||||
private val scope = CoroutineScope(Dispatchers.Default)
|
||||
|
||||
override fun onInstall() {
|
||||
State.notificationParamsFlow.value?.let {
|
||||
update(it.extended)
|
||||
update(it)
|
||||
}
|
||||
scope.launch {
|
||||
val screenFlow = service.receiveBroadcastFlow {
|
||||
@@ -60,12 +48,11 @@ class NotificationModule(private val service: Service) : Module() {
|
||||
emit(isScreenOn())
|
||||
}
|
||||
|
||||
combine(
|
||||
tickerFlow(1000, 0), State.notificationParamsFlow, screenFlow
|
||||
) { _, params, screenOn ->
|
||||
params?.extended to screenOn
|
||||
}.filter { (params, screenOn) -> params != null && screenOn }
|
||||
.distinctUntilChanged { old, new -> old.first == new.first && old.second == new.second }
|
||||
tickerFlow(1000, 0)
|
||||
.combine(State.notificationParamsFlow.zip(screenFlow) { params, screenOn ->
|
||||
params to screenOn
|
||||
}) { _, (params, screenOn) -> params to screenOn }
|
||||
.filter { (params, screenOn) -> params != null && screenOn }
|
||||
.collect { (params, _) ->
|
||||
update(params!!)
|
||||
}
|
||||
@@ -100,15 +87,17 @@ class NotificationModule(private val service: Service) : Module() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun update(params: ExtendedNotificationParams) {
|
||||
private fun update(params: NotificationParams) {
|
||||
val contentText = Core.getSpeedTrafficText(params.onlyStatisticsProxy)
|
||||
service.startForeground(
|
||||
with(notificationBuilder) {
|
||||
setContentTitle(params.title)
|
||||
setContentText(params.contentText)
|
||||
setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
setContentText(contentText)
|
||||
clearActions()
|
||||
addAction(
|
||||
0, params.stopText, QuickAction.STOP.quickIntent.toPendingIntent
|
||||
0,
|
||||
params.stopText,
|
||||
QuickAction.STOP.quickIntent.toPendingIntent
|
||||
).build()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:width="240dp"
|
||||
android:height="240dp"
|
||||
android:viewportWidth="240"
|
||||
android:viewportHeight="240"
|
||||
tools:ignore="VectorRaster">
|
||||
<path
|
||||
android:pathData="M48.1,80.89L168.44,11.41c11.08,-6.4 25.24,-2.6 31.64,8.48 0,0 0,0 0,0h0c6.4,11.08 2.6,25.24 -8.48,31.64 0,0 0,0 0,0l-120.34,69.48c-11.08,6.4 -25.24,2.6 -31.64,-8.48 0,0 0,0 0,0h0c-6.4,-11.08 -2.6,-25.24 8.48,-31.64 0,0 0,0 0,0Z"
|
||||
android:fillColor="#6666FB"/>
|
||||
<path
|
||||
android:pathData="M78.98,134.37l60.18,-34.74c11.07,-6.39 25.23,-2.59 31.63,8.48h0c6.4,11.07 2.61,25.24 -8.47,31.64l-60.18,34.74c-11.08,6.4 -25.24,2.6 -31.64,-8.48 0,0 0,0 0,0h0c-6.4,-11.08 -2.6,-25.24 8.48,-31.64h0Z"
|
||||
android:fillColor="#336AB6"/>
|
||||
<path
|
||||
android:pathData="M109.86,187.86h0c11.08,-6.4 25.24,-2.6 31.64,8.48 0,0 0,0 0,0h0c6.4,11.08 2.6,25.24 -8.48,31.64 0,0 0,0 0,0h0c-11.08,6.4 -25.24,2.6 -31.64,-8.48 0,0 0,0 0,0h0c-6.4,-11.08 -2.6,-25.24 8.48,-31.64 0,0 0,0 0,0Z"
|
||||
android:fillColor="#5CA8E9"/>
|
||||
</vector>
|
||||
@@ -426,7 +426,5 @@
|
||||
"disconnected": "Disconnected",
|
||||
"connecting": "Connecting...",
|
||||
"restartCoreTip": "Are you sure you want to restart the core?",
|
||||
"forceRestartCoreTip": "Are you sure you want to force restart the core?",
|
||||
"dnsHijacking": "DNS hijacking",
|
||||
"coreStatus": "Core status"
|
||||
"forceRestartCoreTip": "Are you sure you want to force restart the core?"
|
||||
}
|
||||
@@ -427,7 +427,5 @@
|
||||
"disconnected": "切断済み",
|
||||
"connecting": "接続中...",
|
||||
"restartCoreTip": "コアを再起動してもよろしいですか?",
|
||||
"forceRestartCoreTip": "コアを強制再起動してもよろしいですか?",
|
||||
"dnsHijacking": "DNSハイジャッキング",
|
||||
"coreStatus": "コアステータス"
|
||||
"forceRestartCoreTip": "コアを強制再起動してもよろしいですか?"
|
||||
}
|
||||
@@ -427,7 +427,5 @@
|
||||
"disconnected": "Отключено",
|
||||
"connecting": "Подключение...",
|
||||
"restartCoreTip": "Вы уверены, что хотите перезапустить ядро?",
|
||||
"forceRestartCoreTip": "Вы уверены, что хотите принудительно перезапустить ядро?",
|
||||
"dnsHijacking": "DNS-перехват",
|
||||
"coreStatus": "Основной статус"
|
||||
"forceRestartCoreTip": "Вы уверены, что хотите принудительно перезапустить ядро?"
|
||||
}
|
||||
@@ -427,7 +427,5 @@
|
||||
"disconnected": "已断开",
|
||||
"connecting": "连接中...",
|
||||
"restartCoreTip": "您确定要重启核心吗?",
|
||||
"forceRestartCoreTip": "您确定要强制重启核心吗?",
|
||||
"dnsHijacking": "DNS劫持",
|
||||
"coreStatus": "核心状态"
|
||||
"forceRestartCoreTip": "您确定要强制重启核心吗?"
|
||||
}
|
||||
|
||||
Submodule core/Clash.Meta updated: ef78ae3278...82906c837a
@@ -181,10 +181,6 @@ 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)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
void (*release_object_func)(void *obj);
|
||||
|
||||
void (*free_string_func)(char *data);
|
||||
|
||||
void (*protect_func)(void *tun_interface, int fd);
|
||||
|
||||
char* (*resolve_process_func)(void *tun_interface,int protocol, const char *source, const char *target, int uid);
|
||||
@@ -22,10 +20,6 @@ void release_object(void *obj) {
|
||||
release_object_func(obj);
|
||||
}
|
||||
|
||||
void free_string(char *data) {
|
||||
free_string_func(data);
|
||||
}
|
||||
|
||||
void result(void *invoke_Interface, const char *data) {
|
||||
return result_func(invoke_Interface, data);
|
||||
}
|
||||
@@ -16,6 +16,7 @@ func resolveProcess(callback unsafe.Pointer, protocol int, source, target string
|
||||
t := C.CString(target)
|
||||
defer C.free(unsafe.Pointer(t))
|
||||
res := C.resolve_process(callback, C.int(protocol), s, t, C.int(uid))
|
||||
defer releaseObject(unsafe.Pointer(res))
|
||||
return takeCString(res)
|
||||
}
|
||||
|
||||
@@ -30,6 +31,6 @@ func releaseObject(callback unsafe.Pointer) {
|
||||
}
|
||||
|
||||
func takeCString(s *C.char) string {
|
||||
defer C.free_string(s)
|
||||
defer releaseObject(unsafe.Pointer(s))
|
||||
return C.GoString(s)
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
extern void (*release_object_func)(void *obj);
|
||||
|
||||
extern void (*free_string_func)(char *data);
|
||||
|
||||
extern void (*protect_func)(void *tun_interface, int fd);
|
||||
|
||||
extern char* (*resolve_process_func)(void *tun_interface, int protocol, const char *source, const char *target, int uid);
|
||||
@@ -18,6 +16,4 @@ extern char* resolve_process(void *tun_interface, int protocol, const char *sour
|
||||
|
||||
extern void release_object(void *obj);
|
||||
|
||||
extern void free_string(char *data);
|
||||
|
||||
extern void result(void *invoke_Interface, const char *data);
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
rp "github.com/metacubex/mihomo/rules/provider"
|
||||
"github.com/metacubex/mihomo/tunnel"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -115,15 +114,11 @@ func updateListeners() {
|
||||
listeners := currentConfig.Listeners
|
||||
general := currentConfig.General
|
||||
listener.PatchInboundListeners(listeners, tunnel.Tunnel, true)
|
||||
|
||||
allowLan := general.AllowLan
|
||||
listener.SetAllowLan(allowLan)
|
||||
listener.SetAllowLan(general.AllowLan)
|
||||
inbound.SetSkipAuthPrefixes(general.SkipAuthPrefixes)
|
||||
inbound.SetAllowedIPs(general.LanAllowedIPs)
|
||||
inbound.SetDisAllowedIPs(general.LanDisAllowedIPs)
|
||||
|
||||
bindAddress := general.BindAddress
|
||||
listener.SetBindAddress(bindAddress)
|
||||
listener.SetBindAddress(general.BindAddress)
|
||||
listener.ReCreateHTTP(general.Port, tunnel.Tunnel)
|
||||
listener.ReCreateSocks(general.SocksPort, tunnel.Tunnel)
|
||||
listener.ReCreateRedir(general.RedirPort, tunnel.Tunnel)
|
||||
@@ -164,6 +159,7 @@ func patchSelectGroup(mapping map[string]string) {
|
||||
|
||||
func defaultSetupParams() *SetupParams {
|
||||
return &SetupParams{
|
||||
Config: config.DefaultRawConfig(),
|
||||
TestURL: "https://www.gstatic.com/generate_204",
|
||||
SelectedMap: map[string]string{},
|
||||
}
|
||||
@@ -239,30 +235,12 @@ func updateConfig(params *UpdateParams) {
|
||||
updateListeners()
|
||||
}
|
||||
|
||||
func parseWithPath(path string) (*config.Config, error) {
|
||||
buf, err := readFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawConfig := config.DefaultRawConfig()
|
||||
err = UnmarshalJson(buf, rawConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parseRawConfig, err := config.ParseRawConfig(rawConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return parseRawConfig, nil
|
||||
}
|
||||
|
||||
func setupConfig(params *SetupParams) error {
|
||||
runLock.Lock()
|
||||
defer runLock.Unlock()
|
||||
var err error
|
||||
constant.DefaultTestURL = params.TestURL
|
||||
currentConfig, err = parseWithPath(filepath.Join(constant.Path.HomeDir(), "config.json"))
|
||||
currentConfig, err = config.ParseRawConfig(params.Config)
|
||||
if err != nil {
|
||||
currentConfig, _ = config.ParseRawConfig(config.DefaultRawConfig())
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"github.com/metacubex/mihomo/adapter/provider"
|
||||
P "github.com/metacubex/mihomo/component/process"
|
||||
"github.com/metacubex/mihomo/config"
|
||||
"github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
"github.com/metacubex/mihomo/tunnel"
|
||||
@@ -17,6 +18,7 @@ type InitParams struct {
|
||||
}
|
||||
|
||||
type SetupParams struct {
|
||||
Config *config.RawConfig `json:"config"`
|
||||
SelectedMap map[string]string `json:"selected-map"`
|
||||
TestURL string `json:"test-url"`
|
||||
}
|
||||
@@ -99,7 +101,6 @@ 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,6 +10,7 @@ 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
|
||||
@@ -18,15 +19,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.4 // indirect
|
||||
github.com/enfein/mieru/v3 v3.19.1 // indirect
|
||||
github.com/ebitengine/purego v0.8.3 // indirect
|
||||
github.com/enfein/mieru/v3 v3.16.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.3 // indirect
|
||||
github.com/go-chi/chi/v5 v5.2.2 // 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
|
||||
@@ -41,36 +42,35 @@ 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-20250820070344-732c0c9d418a // indirect
|
||||
github.com/metacubex/ascon v0.1.0 // indirect
|
||||
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab // 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.54.1-0.20250730114134-a1ae705fe295 // indirect
|
||||
github.com/metacubex/quic-go v0.53.1-0.20250628094454-fda5262d1d9c // indirect
|
||||
github.com/metacubex/randv2 v0.2.0 // 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 v0.5.4 // indirect
|
||||
github.com/metacubex/sing-mux v0.3.2 // indirect
|
||||
github.com/metacubex/sing-quic v0.0.0-20250718154553-1b193bec4cbb // indirect
|
||||
github.com/metacubex/sing-shadowsocks v0.2.12 // indirect
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.6 // indirect
|
||||
github.com/metacubex/sing-shadowsocks v0.2.11 // indirect
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.5 // indirect
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 // 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-tun v0.4.7-0.20250721020617-8e7c37ed3d97 // indirect
|
||||
github.com/metacubex/sing-vmess v0.2.3 // 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-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/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/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,4 +110,5 @@ 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,3 +1,5 @@
|
||||
github.com/3andne/restls-client-go v0.1.6 h1:tRx/YilqW7iHpgmEL4E1D8dAsuB0tFF3uvncS+B6I08=
|
||||
github.com/3andne/restls-client-go v0.1.6/go.mod h1:iEdTZNt9kzPIxjIGSMScUFSBrUH6bFRNg0BWlP4orEY=
|
||||
github.com/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=
|
||||
@@ -22,10 +24,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.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/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/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=
|
||||
@@ -39,8 +41,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.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/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/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=
|
||||
@@ -78,24 +80,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-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/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/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=
|
||||
@@ -106,39 +108,37 @@ 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.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/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/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.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 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-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.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-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-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 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-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-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-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/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/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.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
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,3 +271,5 @@ 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=
|
||||
|
||||
29
core/hub.go
29
core/hub.go
@@ -20,7 +20,6 @@ import (
|
||||
"github.com/metacubex/mihomo/tunnel"
|
||||
"github.com/metacubex/mihomo/tunnel/statistic"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
@@ -61,7 +60,6 @@ func handleStopListener() bool {
|
||||
defer runLock.Unlock()
|
||||
isRunning = false
|
||||
listener.StopListener()
|
||||
resolver.ResetConnection()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -456,33 +454,6 @@ 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)
|
||||
|
||||
23
core/lib.go
23
core/lib.go
@@ -36,11 +36,11 @@ type TunHandler struct {
|
||||
limit *semaphore.Weighted
|
||||
}
|
||||
|
||||
func (th *TunHandler) start(fd int, stack, address, dns string) {
|
||||
func (th *TunHandler) start(fd int, address, dns string) {
|
||||
_ = th.limit.Acquire(context.TODO(), 4)
|
||||
defer th.limit.Release(4)
|
||||
th.initHook()
|
||||
tunListener := t.Start(fd, stack, address, dns)
|
||||
tunListener := t.Start(fd, currentConfig.General.Tun.Device, currentConfig.General.Tun.Stack, address, dns)
|
||||
if tunListener != nil {
|
||||
log.Infoln("TUN address: %v", tunListener.Address())
|
||||
th.listener = tunListener
|
||||
@@ -136,7 +136,7 @@ func handleStopTun() {
|
||||
}
|
||||
}
|
||||
|
||||
func handleStartTun(callback unsafe.Pointer, fd int, stack, address, dns string) {
|
||||
func handleStartTun(callback unsafe.Pointer, fd int, address, dns string) {
|
||||
handleStopTun()
|
||||
tunLock.Lock()
|
||||
defer tunLock.Unlock()
|
||||
@@ -145,7 +145,7 @@ func handleStartTun(callback unsafe.Pointer, fd int, stack, address, dns string)
|
||||
callback: callback,
|
||||
limit: semaphore.NewWeighted(4),
|
||||
}
|
||||
tunHandler.start(fd, stack, address, dns)
|
||||
tunHandler.start(fd, address, dns)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,8 +164,9 @@ func (result ActionResult) send() {
|
||||
}
|
||||
invokeResult(result.callback, string(data))
|
||||
if result.Method != messageMethod {
|
||||
defer releaseObject(result.callback)
|
||||
releaseObject(result.callback)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func nextHandle(action *Action, result ActionResult) bool {
|
||||
@@ -197,8 +198,8 @@ func invokeAction(callback unsafe.Pointer, paramsChar *C.char) {
|
||||
}
|
||||
|
||||
//export startTUN
|
||||
func startTUN(callback unsafe.Pointer, fd C.int, stackChar, addressChar, dnsChar *C.char) bool {
|
||||
handleStartTun(callback, int(fd), takeCString(stackChar), takeCString(addressChar), takeCString(dnsChar))
|
||||
func startTUN(callback unsafe.Pointer, fd C.int, addressChar, dnsChar *C.char) bool {
|
||||
handleStartTun(callback, int(fd), takeCString(addressChar), takeCString(dnsChar))
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -212,16 +213,12 @@ func setMessageCallback(callback unsafe.Pointer) {
|
||||
|
||||
//export getTotalTraffic
|
||||
func getTotalTraffic(onlyStatisticsProxy bool) *C.char {
|
||||
data := C.CString(handleGetTotalTraffic(onlyStatisticsProxy))
|
||||
defer C.free(unsafe.Pointer(data))
|
||||
return data
|
||||
return C.CString(handleGetTotalTraffic(onlyStatisticsProxy))
|
||||
}
|
||||
|
||||
//export getTraffic
|
||||
func getTraffic(onlyStatisticsProxy bool) *C.char {
|
||||
data := C.CString(handleGetTraffic(onlyStatisticsProxy))
|
||||
defer C.free(unsafe.Pointer(data))
|
||||
return data
|
||||
return C.CString(handleGetTraffic(onlyStatisticsProxy))
|
||||
}
|
||||
|
||||
func sendMessage(message Message) {
|
||||
|
||||
@@ -14,13 +14,9 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Start(fd int, stack string, address, dns string) *sing_tun.Listener {
|
||||
func Start(fd int, device string, stack constant.TUNStack, address, dns string) *sing_tun.Listener {
|
||||
var prefix4 []netip.Prefix
|
||||
var prefix6 []netip.Prefix
|
||||
tunStack, ok := constant.StackTypeMapping[strings.ToLower(stack)]
|
||||
if !ok {
|
||||
tunStack = constant.TunSystem
|
||||
}
|
||||
for _, a := range strings.Split(address, ",") {
|
||||
a = strings.TrimSpace(a)
|
||||
if len(a) == 0 {
|
||||
@@ -49,8 +45,8 @@ func Start(fd int, stack string, address, dns string) *sing_tun.Listener {
|
||||
|
||||
options := LC.Tun{
|
||||
Enable: true,
|
||||
Device: "FlClash",
|
||||
Stack: tunStack,
|
||||
Device: device,
|
||||
Stack: stack,
|
||||
DNSHijack: dnsHijack,
|
||||
AutoRoute: false,
|
||||
AutoDetectInterface: false,
|
||||
|
||||
@@ -66,7 +66,7 @@ class ApplicationState extends ConsumerState<Application> {
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildPlatformState({required Widget child}) {
|
||||
Widget _buildPlatformState(Widget child) {
|
||||
if (system.isDesktop) {
|
||||
return WindowManager(
|
||||
child: TrayManager(
|
||||
@@ -77,7 +77,7 @@ class ApplicationState extends ConsumerState<Application> {
|
||||
return AndroidManager(child: TileManager(child: child));
|
||||
}
|
||||
|
||||
Widget _buildState({required Widget child}) {
|
||||
Widget _buildState(Widget child) {
|
||||
return AppStateManager(
|
||||
child: CoreManager(
|
||||
child: ConnectivityManager(
|
||||
@@ -94,70 +94,70 @@ class ApplicationState extends ConsumerState<Application> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPlatformApp({required Widget child}) {
|
||||
Widget _buildPlatformApp(Widget child) {
|
||||
if (system.isDesktop) {
|
||||
return WindowHeaderContainer(child: child);
|
||||
}
|
||||
return VpnManager(child: child);
|
||||
}
|
||||
|
||||
Widget _buildApp({required Widget child}) {
|
||||
Widget _buildApp(Widget child) {
|
||||
return MessageManager(child: ThemeManager(child: child));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(context) {
|
||||
return Consumer(
|
||||
builder: (_, ref, child) {
|
||||
final locale = ref.watch(
|
||||
appSettingProvider.select((state) => state.locale),
|
||||
);
|
||||
final themeProps = ref.watch(themeSettingProvider);
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
navigatorKey: globalState.navigatorKey,
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
],
|
||||
builder: (_, child) {
|
||||
return AppEnvManager(
|
||||
child: _buildApp(
|
||||
child: AppSidebarContainer(
|
||||
child: _buildPlatformState(
|
||||
child: _buildState(child: _buildPlatformApp(child: child!)),
|
||||
return _buildPlatformState(
|
||||
_buildState(
|
||||
Consumer(
|
||||
builder: (_, ref, child) {
|
||||
final locale = ref.watch(
|
||||
appSettingProvider.select((state) => state.locale),
|
||||
);
|
||||
final themeProps = ref.watch(themeSettingProvider);
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
navigatorKey: globalState.navigatorKey,
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
],
|
||||
builder: (_, child) {
|
||||
return AppEnvManager(
|
||||
child: _buildApp(
|
||||
AppSidebarContainer(child: _buildPlatformApp(child!)),
|
||||
),
|
||||
);
|
||||
},
|
||||
scrollBehavior: BaseScrollBehavior(),
|
||||
title: appName,
|
||||
locale: utils.getLocaleForString(locale),
|
||||
supportedLocales: AppLocalizations.delegate.supportedLocales,
|
||||
themeMode: themeProps.themeMode,
|
||||
theme: ThemeData(
|
||||
useMaterial3: true,
|
||||
pageTransitionsTheme: _pageTransitionsTheme,
|
||||
colorScheme: _getAppColorScheme(
|
||||
brightness: Brightness.light,
|
||||
primaryColor: themeProps.primaryColor,
|
||||
),
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
useMaterial3: true,
|
||||
pageTransitionsTheme: _pageTransitionsTheme,
|
||||
colorScheme: _getAppColorScheme(
|
||||
brightness: Brightness.dark,
|
||||
primaryColor: themeProps.primaryColor,
|
||||
).toPureBlack(themeProps.pureBlack),
|
||||
),
|
||||
home: child!,
|
||||
);
|
||||
},
|
||||
scrollBehavior: BaseScrollBehavior(),
|
||||
title: appName,
|
||||
locale: utils.getLocaleForString(locale),
|
||||
supportedLocales: AppLocalizations.delegate.supportedLocales,
|
||||
themeMode: themeProps.themeMode,
|
||||
theme: ThemeData(
|
||||
useMaterial3: true,
|
||||
pageTransitionsTheme: _pageTransitionsTheme,
|
||||
colorScheme: _getAppColorScheme(
|
||||
brightness: Brightness.light,
|
||||
primaryColor: themeProps.primaryColor,
|
||||
),
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
useMaterial3: true,
|
||||
pageTransitionsTheme: _pageTransitionsTheme,
|
||||
colorScheme: _getAppColorScheme(
|
||||
brightness: Brightness.dark,
|
||||
primaryColor: themeProps.primaryColor,
|
||||
).toPureBlack(themeProps.pureBlack),
|
||||
),
|
||||
home: child!,
|
||||
);
|
||||
},
|
||||
child: const HomePage(),
|
||||
child: const HomePage(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,15 +14,16 @@ extension ArchiveExt on Archive {
|
||||
final data = entity.readAsBytesSync();
|
||||
final archiveFile = ArchiveFile(relativePath, data.length, data);
|
||||
addFile(archiveFile);
|
||||
} else if (entity is Directory) {
|
||||
addDirectoryToArchive(entity.path, parentPath);
|
||||
}
|
||||
// else if (entity is Directory) {
|
||||
// addDirectoryToArchive(entity.path, parentPath);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
void addTextFile<T>(String name, T raw) {
|
||||
final data = json.encode(raw);
|
||||
addFile(ArchiveFile.string(name, data));
|
||||
addFile(
|
||||
ArchiveFile.string(name, data),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
|
||||
class LocalImageCacheManager extends CacheManager {
|
||||
static const key = 'LocalImageCacheData';
|
||||
|
||||
static final LocalImageCacheManager _instance = LocalImageCacheManager._();
|
||||
|
||||
factory LocalImageCacheManager() {
|
||||
return _instance;
|
||||
}
|
||||
|
||||
LocalImageCacheManager._()
|
||||
: super(
|
||||
Config(
|
||||
key,
|
||||
stalePeriod: Duration(days: 30),
|
||||
maxNrOfCacheObjects: 1000,
|
||||
fileService: _LocalImageCacheFileService(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class _LocalImageCacheFileService extends FileService {
|
||||
_LocalImageCacheFileService();
|
||||
|
||||
@override
|
||||
Future<FileServiceResponse> get(
|
||||
String url, {
|
||||
Map<String, String>? headers,
|
||||
}) async {
|
||||
final response = await request.dio.get<ResponseBody>(
|
||||
url,
|
||||
options: Options(headers: headers, responseType: ResponseType.stream),
|
||||
);
|
||||
return _LocalImageResponse(response);
|
||||
}
|
||||
}
|
||||
|
||||
class _LocalImageResponse implements FileServiceResponse {
|
||||
_LocalImageResponse(this._response);
|
||||
|
||||
final DateTime _receivedTime = DateTime.now();
|
||||
|
||||
final Response<ResponseBody> _response;
|
||||
|
||||
@override
|
||||
int get statusCode => _response.statusCode ?? 0;
|
||||
|
||||
@override
|
||||
Stream<List<int>> get content =>
|
||||
_response.data?.stream.transform(uint8ListToListIntConverter) ??
|
||||
Stream.empty();
|
||||
|
||||
@override
|
||||
int? get contentLength => _response.data?.contentLength;
|
||||
|
||||
@override
|
||||
DateTime get validTill {
|
||||
// Without a cache-control header we keep the file for a week
|
||||
var ageDuration = const Duration(days: 7);
|
||||
final controlHeader = _response.headers.value(
|
||||
HttpHeaders.cacheControlHeader,
|
||||
);
|
||||
if (controlHeader != null) {
|
||||
final controlSettings = controlHeader.split(',');
|
||||
for (final setting in controlSettings) {
|
||||
final sanitizedSetting = setting.trim().toLowerCase();
|
||||
if (sanitizedSetting.startsWith('max-age=')) {
|
||||
final validSeconds =
|
||||
int.tryParse(sanitizedSetting.split('=')[1]) ?? 0;
|
||||
if (validSeconds > 0) {
|
||||
ageDuration = Duration(seconds: validSeconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ageDuration > const Duration(days: 7)) {
|
||||
return _receivedTime.add(ageDuration);
|
||||
}
|
||||
return _receivedTime.add(const Duration(days: 7));
|
||||
}
|
||||
|
||||
@override
|
||||
String? get eTag => _response.headers.value(HttpHeaders.etagHeader);
|
||||
|
||||
@override
|
||||
String get fileExtension {
|
||||
var fileExtension = '';
|
||||
final contentTypeHeader = _response.headers.value(
|
||||
HttpHeaders.contentTypeHeader,
|
||||
);
|
||||
if (contentTypeHeader != null) {
|
||||
final contentType = ContentType.parse(contentTypeHeader);
|
||||
fileExtension = contentType.fileExtension;
|
||||
}
|
||||
return fileExtension;
|
||||
}
|
||||
}
|
||||
|
||||
extension ContentTypeConverter on ContentType {
|
||||
String get fileExtension => mimeTypes[mimeType] ?? '.$subType';
|
||||
}
|
||||
|
||||
const mimeTypes = {
|
||||
'application/vnd.android.package-archive': '.apk',
|
||||
'application/epub+zip': '.epub',
|
||||
'application/gzip': '.gz',
|
||||
'application/java-archive': '.jar',
|
||||
'application/json': '.json',
|
||||
'application/ld+json': '.jsonld',
|
||||
'application/msword': '.doc',
|
||||
'application/octet-stream': '.bin',
|
||||
'application/ogg': '.ogx',
|
||||
'application/pdf': '.pdf',
|
||||
'application/php': '.php',
|
||||
'application/rtf': '.rtf',
|
||||
'application/vnd.amazon.ebook': '.azw',
|
||||
'application/vnd.apple.installer+xml': '.mpkg',
|
||||
'application/vnd.mozilla.xul+xml': '.xul',
|
||||
'application/vnd.ms-excel': '.xls',
|
||||
'application/vnd.ms-fontobject': '.eot',
|
||||
'application/vnd.ms-powerpoint': '.ppt',
|
||||
'application/vnd.oasis.opendocument.presentation': '.odp',
|
||||
'application/vnd.oasis.opendocument.spreadsheet': '.ods',
|
||||
'application/vnd.oasis.opendocument.text': '.odt',
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation':
|
||||
'.pptx',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': '.xlsx',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
|
||||
'.docx',
|
||||
'application/vnd.rar': '.rar',
|
||||
'application/vnd.visio': '.vsd',
|
||||
'application/x-7z-compressed': '.7z',
|
||||
'application/x-abiword': '.abw',
|
||||
'application/x-bzip': '.bz',
|
||||
'application/x-bzip2': '.bz2',
|
||||
'application/x-csh': '.csh',
|
||||
'application/x-freearc': '.arc',
|
||||
'application/x-sh': '.sh',
|
||||
'application/x-shockwave-flash': '.swf',
|
||||
'application/x-tar': '.tar',
|
||||
'application/xhtml+xml': '.xhtml',
|
||||
'application/xml': '.xml',
|
||||
'application/zip': '.zip',
|
||||
'audio/3gpp': '.3gp',
|
||||
'audio/3gpp2': '.3g2',
|
||||
'audio/aac': '.aac',
|
||||
'audio/x-aac': '.aac',
|
||||
'audio/midi': '.midi',
|
||||
'audio/x-midi': '.midi',
|
||||
'audio/x-m4a': '.m4a',
|
||||
'audio/m4a': '.m4a',
|
||||
'audio/mpeg': '.mp3',
|
||||
'audio/ogg': '.oga',
|
||||
'audio/opus': '.opus',
|
||||
'audio/wav': '.wav',
|
||||
'audio/x-wav': '.wav',
|
||||
'audio/webm': '.weba',
|
||||
'font/otf': '.otf',
|
||||
'font/ttf': '.ttf',
|
||||
'font/woff': '.woff',
|
||||
'font/woff2': '.woff2',
|
||||
'image/bmp': '.bmp',
|
||||
'image/gif': '.gif',
|
||||
'image/jpeg': '.jpg',
|
||||
'image/png': '.png',
|
||||
'image/svg+xml': '.svg',
|
||||
'image/tiff': '.tiff',
|
||||
'image/vnd.microsoft.icon': '.ico',
|
||||
'image/webp': '.webp',
|
||||
'text/calendar': '.ics',
|
||||
'text/css': '.css',
|
||||
'text/csv': '.csv',
|
||||
'text/html': '.html',
|
||||
'text/javascript': '.js',
|
||||
'text/plain': '.txt',
|
||||
'text/xml': '.xml',
|
||||
'video/3gpp': '.3gp',
|
||||
'video/3gpp2': '.3g2',
|
||||
'video/mp2t': '.ts',
|
||||
'video/mpeg': '.mpeg',
|
||||
'video/ogg': '.ogv',
|
||||
'video/webm': '.webm',
|
||||
'video/x-msvideo': '.avi',
|
||||
'video/quicktime': '.mov',
|
||||
};
|
||||
@@ -1,8 +1,6 @@
|
||||
export 'android.dart';
|
||||
export 'app_localizations.dart';
|
||||
export 'cache.dart';
|
||||
export 'color.dart';
|
||||
export 'compute.dart';
|
||||
export 'constant.dart';
|
||||
export 'context.dart';
|
||||
export 'converter.dart';
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/models/models.dart';
|
||||
|
||||
import 'string.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) => a.name.compareTo(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 * 80 + (lines - 1) * 16, 0).ap;
|
||||
return max(lines * 84 + (lines - 1) * 16, 0).ap;
|
||||
}
|
||||
|
||||
const maxLength = 1000;
|
||||
|
||||
@@ -9,17 +9,23 @@ class Debouncer {
|
||||
FunctionTag tag,
|
||||
Function func, {
|
||||
List<dynamic>? args,
|
||||
Duration? duration,
|
||||
Duration duration = const Duration(milliseconds: 600),
|
||||
}) {
|
||||
final timer = _operations[tag];
|
||||
if (timer != null) {
|
||||
timer.cancel();
|
||||
}
|
||||
_operations[tag] = Timer(duration ?? const Duration(milliseconds: 600), () {
|
||||
_operations[tag]?.cancel();
|
||||
_operations.remove(tag);
|
||||
Function.apply(func, args);
|
||||
});
|
||||
_operations[tag] = Timer(
|
||||
duration,
|
||||
() {
|
||||
_operations[tag]?.cancel();
|
||||
_operations.remove(tag);
|
||||
Function.apply(
|
||||
func,
|
||||
args,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void cancel(dynamic tag) {
|
||||
@@ -41,11 +47,17 @@ 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,35 +1,9 @@
|
||||
import 'package:riverpod/riverpod.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
mixin AutoDisposeNotifierMixin<T> on AnyNotifier<T, T> {
|
||||
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) {}
|
||||
}
|
||||
|
||||
mixin AnyNotifierMixin<T> on AnyNotifier<T, T> {
|
||||
T get value;
|
||||
|
||||
set value(T value) {
|
||||
if (ref.mounted) {
|
||||
state = value;
|
||||
} else {
|
||||
onUpdate(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ class AppPath {
|
||||
Completer<Directory> dataDir = Completer();
|
||||
Completer<Directory> downloadDir = Completer();
|
||||
Completer<Directory> tempDir = Completer();
|
||||
Completer<Directory> cacheDir = Completer();
|
||||
late String appDirPath;
|
||||
|
||||
AppPath._internal() {
|
||||
@@ -24,9 +23,6 @@ class AppPath {
|
||||
getDownloadsDirectory().then((value) {
|
||||
downloadDir.complete(value);
|
||||
});
|
||||
getApplicationCacheDirectory().then((value) {
|
||||
cacheDir.complete(value);
|
||||
});
|
||||
}
|
||||
|
||||
factory AppPath() {
|
||||
@@ -62,13 +58,8 @@ class AppPath {
|
||||
}
|
||||
|
||||
Future<String> get lockFilePath async {
|
||||
final homeDirPath = await appPath.homeDirPath;
|
||||
return join(homeDirPath, 'FlClash.lock');
|
||||
}
|
||||
|
||||
Future<String> get configFilePath async {
|
||||
final homeDirPath = await appPath.homeDirPath;
|
||||
return join(homeDirPath, 'config.json');
|
||||
final directory = await dataDir.future;
|
||||
return join(directory.path, 'FlClash.lock');
|
||||
}
|
||||
|
||||
Future<String> get sharedPreferencesPath async {
|
||||
@@ -86,19 +77,13 @@ 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');
|
||||
}
|
||||
|
||||
Future<String> getProvidersDirPath(String id) async {
|
||||
final directory = await profilesPath;
|
||||
return join(directory, 'providers', id);
|
||||
return join(
|
||||
directory,
|
||||
'providers',
|
||||
id,
|
||||
);
|
||||
}
|
||||
|
||||
Future<String> getProvidersFilePath(
|
||||
@@ -107,7 +92,13 @@ class AppPath {
|
||||
String url,
|
||||
) async {
|
||||
final directory = await profilesPath;
|
||||
return join(directory, 'providers', id, type, url.toMd5());
|
||||
return join(
|
||||
directory,
|
||||
'providers',
|
||||
id,
|
||||
type,
|
||||
url.toMd5(),
|
||||
);
|
||||
}
|
||||
|
||||
Future<String> get tempPath async {
|
||||
|
||||
@@ -11,29 +11,35 @@ import 'package:fl_clash/state.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class Request {
|
||||
late final Dio dio;
|
||||
late final Dio _dio;
|
||||
late final Dio _clashDio;
|
||||
String? userAgent;
|
||||
|
||||
Request() {
|
||||
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;
|
||||
},
|
||||
_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;
|
||||
});
|
||||
}
|
||||
|
||||
Future<Response> getFileResponseForUrl(String url) async {
|
||||
final response = await _clashDio.get(
|
||||
url,
|
||||
options: Options(responseType: ResponseType.bytes),
|
||||
options: Options(
|
||||
responseType: ResponseType.bytes,
|
||||
),
|
||||
);
|
||||
return response;
|
||||
}
|
||||
@@ -41,16 +47,20 @@ 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;
|
||||
}
|
||||
|
||||
Future<MemoryImage?> getImage(String url) async {
|
||||
if (url.isEmpty) return null;
|
||||
final response = await dio.get<Uint8List>(
|
||||
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;
|
||||
@@ -58,9 +68,11 @@ class Request {
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> checkForUpdate() async {
|
||||
final response = await dio.get(
|
||||
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>;
|
||||
@@ -73,12 +85,9 @@ class Request {
|
||||
}
|
||||
|
||||
final Map<String, IpInfo Function(Map<String, dynamic>)> _ipInfoSources = {
|
||||
'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://ipwho.is/': IpInfo.fromIpwhoIsJson,
|
||||
'https://api.ip.sb/geoip/': IpInfo.fromIpSbJson,
|
||||
'https://ipapi.co/json/': IpInfo.fromIpApiCoJson,
|
||||
'https://ipinfo.io/json/': IpInfo.fromIpInfoIoJson,
|
||||
};
|
||||
|
||||
@@ -92,27 +101,27 @@ 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!)));
|
||||
return;
|
||||
}
|
||||
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!)));
|
||||
} else {
|
||||
failureCount++;
|
||||
handleFailRes();
|
||||
}
|
||||
}).catchError((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);
|
||||
@@ -122,12 +131,18 @@ class Request {
|
||||
|
||||
Future<bool> pingHelper() async {
|
||||
try {
|
||||
final response = await dio
|
||||
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;
|
||||
}
|
||||
@@ -139,13 +154,22 @@ class Request {
|
||||
|
||||
Future<bool> startCoreByHelper(String arg) async {
|
||||
try {
|
||||
final response = await dio
|
||||
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;
|
||||
}
|
||||
@@ -158,12 +182,18 @@ class Request {
|
||||
|
||||
Future<bool> stopCoreByHelper() async {
|
||||
try {
|
||||
final response = await dio
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -8,40 +8,13 @@ import 'package:flutter/material.dart';
|
||||
class BaseScrollBehavior extends MaterialScrollBehavior {
|
||||
@override
|
||||
Set<PointerDeviceKind> get dragDevices => {
|
||||
PointerDeviceKind.touch,
|
||||
PointerDeviceKind.stylus,
|
||||
PointerDeviceKind.invertedStylus,
|
||||
PointerDeviceKind.trackpad,
|
||||
if (system.isDesktop) PointerDeviceKind.mouse,
|
||||
PointerDeviceKind.unknown,
|
||||
};
|
||||
|
||||
@override
|
||||
Widget buildScrollbar(
|
||||
BuildContext context,
|
||||
Widget child,
|
||||
ScrollableDetails details,
|
||||
) {
|
||||
switch (axisDirectionToAxis(details.direction)) {
|
||||
case Axis.horizontal:
|
||||
return child;
|
||||
case Axis.vertical:
|
||||
switch (getPlatform(context)) {
|
||||
case TargetPlatform.linux:
|
||||
case TargetPlatform.macOS:
|
||||
case TargetPlatform.windows:
|
||||
assert(details.controller != null);
|
||||
return CommonScrollBar(
|
||||
controller: details.controller,
|
||||
child: child,
|
||||
);
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.iOS:
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
PointerDeviceKind.touch,
|
||||
PointerDeviceKind.stylus,
|
||||
PointerDeviceKind.invertedStylus,
|
||||
PointerDeviceKind.trackpad,
|
||||
if (system.isDesktop) PointerDeviceKind.mouse,
|
||||
PointerDeviceKind.unknown,
|
||||
};
|
||||
}
|
||||
|
||||
class HiddenBarScrollBehavior extends BaseScrollBehavior {
|
||||
@@ -62,7 +35,10 @@ class ShowBarScrollBehavior extends BaseScrollBehavior {
|
||||
Widget child,
|
||||
ScrollableDetails details,
|
||||
) {
|
||||
return CommonScrollBar(controller: details.controller, child: child);
|
||||
return CommonScrollBar(
|
||||
controller: details.controller,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,9 +52,7 @@ class NextClampingScrollPhysics extends ClampingScrollPhysics {
|
||||
|
||||
@override
|
||||
Simulation? createBallisticSimulation(
|
||||
ScrollMetrics position,
|
||||
double velocity,
|
||||
) {
|
||||
ScrollMetrics position, double velocity) {
|
||||
final Tolerance tolerance = toleranceFor(position);
|
||||
if (position.outOfRange) {
|
||||
double? end;
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:lpinyin/lpinyin.dart';
|
||||
|
||||
class Utils {
|
||||
Color? getDelayColor(int? delay) {
|
||||
@@ -20,15 +21,16 @@ 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}) {
|
||||
@@ -41,9 +43,8 @@ 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)];
|
||||
}
|
||||
@@ -59,9 +60,8 @@ 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,10 +102,9 @@ 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;
|
||||
}
|
||||
@@ -142,7 +141,9 @@ class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
String getTrayIconPath({required Brightness brightness}) {
|
||||
String getTrayIconPath({
|
||||
required Brightness brightness,
|
||||
}) {
|
||||
if (system.isMacOS) {
|
||||
return 'assets/images/icon_white.png';
|
||||
}
|
||||
@@ -177,30 +178,26 @@ class Utils {
|
||||
return build1.compareTo(build2);
|
||||
}
|
||||
|
||||
// String getPinyin(String value) {
|
||||
// return value.isNotEmpty
|
||||
// ? PinyinHelper.getFirstWordPinyin(value.substring(0, 1))
|
||||
// : '';
|
||||
// }
|
||||
String getPinyin(String value) {
|
||||
return value.isNotEmpty
|
||||
? PinyinHelper.getFirstWordPinyin(value.substring(0, 1))
|
||||
: '';
|
||||
}
|
||||
|
||||
String? getFileNameForDisposition(String? disposition) {
|
||||
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];
|
||||
}
|
||||
@@ -227,7 +224,7 @@ class Utils {
|
||||
}
|
||||
|
||||
int getProxiesColumns(double viewWidth, ProxiesLayout proxiesLayout) {
|
||||
final columns = max((viewWidth / 250).ceil(), 2);
|
||||
final columns = max((viewWidth / 300).ceil(), 2);
|
||||
return switch (proxiesLayout) {
|
||||
ProxiesLayout.tight => columns + 1,
|
||||
ProxiesLayout.standard => columns,
|
||||
@@ -236,10 +233,22 @@ class Utils {
|
||||
}
|
||||
|
||||
int getProfilesColumns(double viewWidth) {
|
||||
return max((viewWidth / 280).floor(), 1);
|
||||
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>{};
|
||||
@@ -293,15 +302,16 @@ 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) {
|
||||
@@ -319,9 +329,59 @@ 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();
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:io';
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_acrylic/flutter_acrylic.dart' as acrylic;
|
||||
import 'package:screen_retriever/screen_retriever.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
@@ -18,6 +19,9 @@ class Window {
|
||||
protocol.register('clashmeta');
|
||||
protocol.register('flclash');
|
||||
}
|
||||
if ((version > 10 && system.isMacOS)) {
|
||||
await acrylic.Window.initialize();
|
||||
}
|
||||
await windowManager.ensureInitialized();
|
||||
WindowOptions windowOptions = WindowOptions(
|
||||
size: Size(props.width, props.height),
|
||||
@@ -35,18 +39,25 @@ class Window {
|
||||
await windowManager.setAlignment(Alignment.center);
|
||||
} else {
|
||||
final displays = await screenRetriever.getAllDisplays();
|
||||
final isPositionValid = displays.any((display) {
|
||||
final displayBounds = Rect.fromLTWH(
|
||||
display.visiblePosition!.dx,
|
||||
display.visiblePosition!.dy,
|
||||
display.size.width,
|
||||
display.size.height,
|
||||
);
|
||||
return displayBounds.contains(Offset(left, top)) ||
|
||||
displayBounds.contains(Offset(right, bottom));
|
||||
});
|
||||
final isPositionValid = displays.any(
|
||||
(display) {
|
||||
final displayBounds = Rect.fromLTWH(
|
||||
display.visiblePosition!.dx,
|
||||
display.visiblePosition!.dy,
|
||||
display.size.width,
|
||||
display.size.height,
|
||||
);
|
||||
return displayBounds.contains(Offset(left, top)) ||
|
||||
displayBounds.contains(Offset(right, bottom));
|
||||
},
|
||||
);
|
||||
if (isPositionValid) {
|
||||
await windowManager.setPosition(Offset(left, top));
|
||||
await windowManager.setPosition(
|
||||
Offset(
|
||||
left,
|
||||
top,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,6 +66,13 @@ class Window {
|
||||
});
|
||||
}
|
||||
|
||||
void updateMacOSBrightness(Brightness brightness) {
|
||||
if (!system.isMacOS) {
|
||||
return;
|
||||
}
|
||||
acrylic.Window.overrideMacOSBrightness(dark: brightness == Brightness.dark);
|
||||
}
|
||||
|
||||
Future<void> show() async {
|
||||
render?.resume();
|
||||
await windowManager.show();
|
||||
|
||||
@@ -8,7 +8,6 @@ import 'package:fl_clash/common/archive.dart';
|
||||
import 'package:fl_clash/core/core.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/plugins/app.dart';
|
||||
import 'package:fl_clash/plugins/service.dart';
|
||||
import 'package:fl_clash/providers/providers.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:fl_clash/widgets/dialog.dart';
|
||||
@@ -42,8 +41,8 @@ class AppController {
|
||||
});
|
||||
}
|
||||
|
||||
void updateGroupsDebounce([Duration? duration]) {
|
||||
debouncer.call(FunctionTag.updateGroups, updateGroups, duration: duration);
|
||||
void updateGroupsDebounce() {
|
||||
debouncer.call(FunctionTag.updateGroups, updateGroups);
|
||||
}
|
||||
|
||||
void addCheckIpNumDebounce() {
|
||||
@@ -73,11 +72,11 @@ class AppController {
|
||||
}
|
||||
|
||||
Future<void> restartCore() async {
|
||||
globalState.isUserDisconnected = true;
|
||||
await coreController.shutdown();
|
||||
await _connectCore();
|
||||
_ref.read(coreStatusProvider.notifier).value = CoreStatus.connecting;
|
||||
await coreController.preload();
|
||||
await _initCore();
|
||||
_ref.read(initProvider.notifier).value = true;
|
||||
_ref.read(coreStatusProvider.notifier).value = CoreStatus.connected;
|
||||
if (_ref.read(isStartProvider)) {
|
||||
await globalState.handleStart();
|
||||
}
|
||||
@@ -232,6 +231,10 @@ class AppController {
|
||||
return currentGroupName;
|
||||
}
|
||||
|
||||
ProxyCardState getProxyCardState(String proxyName) {
|
||||
return _ref.read(getProxyCardStateProvider(proxyName));
|
||||
}
|
||||
|
||||
String? getSelectedProxyName(String groupName) {
|
||||
return _ref.read(getSelectedProxyNameProvider(groupName));
|
||||
}
|
||||
@@ -300,7 +303,10 @@ class AppController {
|
||||
}
|
||||
final realTunEnable = _ref.read(realTunEnableProvider);
|
||||
final realPatchConfig = patchConfig.copyWith.tun(enable: realTunEnable);
|
||||
final message = await coreController.setupConfig(realPatchConfig);
|
||||
final params = await globalState.getSetupParams(
|
||||
pathConfig: realPatchConfig,
|
||||
);
|
||||
final message = await coreController.setupConfig(params);
|
||||
lastProfileModified = await _ref.read(
|
||||
currentProfileProvider.select((state) => state?.profileLastModified),
|
||||
);
|
||||
@@ -363,22 +369,7 @@ class AppController {
|
||||
try {
|
||||
_ref.read(groupsProvider.notifier).value = await retry(
|
||||
task: () async {
|
||||
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,
|
||||
);
|
||||
return await coreController.getProxiesGroups();
|
||||
},
|
||||
retryIf: (res) => res.isEmpty,
|
||||
);
|
||||
@@ -535,9 +526,11 @@ class AppController {
|
||||
}
|
||||
};
|
||||
updateTray(true);
|
||||
await _initCore();
|
||||
await _initStatus();
|
||||
autoLaunch?.updateStatus(_ref.read(appSettingProvider).autoLaunch);
|
||||
autoUpdateProfiles();
|
||||
autoCheckUpdate();
|
||||
autoLaunch?.updateStatus(_ref.read(appSettingProvider).autoLaunch);
|
||||
if (!_ref.read(appSettingProvider).silentLaunch) {
|
||||
window?.show();
|
||||
} else {
|
||||
@@ -545,26 +538,9 @@ class AppController {
|
||||
}
|
||||
await _handlePreference();
|
||||
await _handlerDisclaimer();
|
||||
await _connectCore();
|
||||
await service?.syncAndroidState(globalState.getAndroidState());
|
||||
await _initCore();
|
||||
await _initStatus();
|
||||
_ref.read(initProvider.notifier).value = true;
|
||||
}
|
||||
|
||||
Future<void> _connectCore() async {
|
||||
_ref.read(coreStatusProvider.notifier).value = CoreStatus.connecting;
|
||||
final message = await coreController.preload();
|
||||
if (message.isNotEmpty) {
|
||||
_ref.read(coreStatusProvider.notifier).value = CoreStatus.disconnected;
|
||||
if (context.mounted) {
|
||||
context.showNotifier(message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
_ref.read(coreStatusProvider.notifier).value = CoreStatus.connected;
|
||||
}
|
||||
|
||||
Future<void> _initStatus() async {
|
||||
if (system.isAndroid) {
|
||||
await globalState.updateStartTime();
|
||||
@@ -718,7 +694,47 @@ class AppController {
|
||||
_ref.read(providersProvider.notifier).setProvider(provider);
|
||||
}
|
||||
|
||||
Future<void> clearEffect(String profileId) async {
|
||||
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 {
|
||||
final profilePath = await appPath.getProfilePath(profileId);
|
||||
final providersDirPath = await appPath.getProvidersDirPath(profileId);
|
||||
return await Isolate.run(() async {
|
||||
@@ -727,7 +743,11 @@ class AppController {
|
||||
if (isExists) {
|
||||
profileFile.delete(recursive: true);
|
||||
}
|
||||
await coreController.deleteFile(providersDirPath);
|
||||
final providersFileDir = File(providersDirPath);
|
||||
final providersFileIsExists = await providersFileDir.exists();
|
||||
if (providersFileIsExists) {
|
||||
providersFileDir.delete(recursive: true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -945,6 +965,7 @@ class AppController {
|
||||
commonPrint.log('$futureFunction ===> $e');
|
||||
if (realSilence) {
|
||||
globalState.showNotifier(e.toString());
|
||||
globalState.showNotifier(e.toString());
|
||||
} else {
|
||||
globalState.showMessage(
|
||||
title: title ?? appLocalizations.tip,
|
||||
|
||||
@@ -8,7 +8,6 @@ import 'package:fl_clash/core/core.dart';
|
||||
import 'package:fl_clash/core/interface.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/models/models.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:path/path.dart';
|
||||
|
||||
@@ -29,7 +28,7 @@ class CoreController {
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
Future<String> preload() {
|
||||
Future<bool> preload() {
|
||||
return _interface.preload();
|
||||
}
|
||||
|
||||
@@ -84,45 +83,29 @@ class CoreController {
|
||||
return await _interface.updateConfig(updateParams);
|
||||
}
|
||||
|
||||
Future<String> setupConfig(ClashConfig clashConfig) async {
|
||||
await globalState.genConfigFile(clashConfig);
|
||||
final params = await globalState.getSetupParams();
|
||||
return await _interface.setupConfig(params);
|
||||
Future<String> setupConfig(SetupParams setupParams) async {
|
||||
return await _interface.setupConfig(setupParams);
|
||||
}
|
||||
|
||||
Future<List<Group>> getProxiesGroups({
|
||||
required ProxiesSortType sortType,
|
||||
required DelayMap delayMap,
|
||||
required SelectedMap selectedMap,
|
||||
required String defaultTestUrl,
|
||||
}) async {
|
||||
Future<List<Group>> getProxiesGroups() async {
|
||||
final proxies = await _interface.getProxies();
|
||||
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,
|
||||
);
|
||||
});
|
||||
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();
|
||||
}
|
||||
|
||||
FutureOr<String> changeProxy(ChangeProxyParams changeProxyParams) async {
|
||||
@@ -171,6 +154,9 @@ class CoreController {
|
||||
if (externalProvidersRawString.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
if (externalProvidersRawString.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
return ExternalProvider.fromJson(json.decode(externalProvidersRawString));
|
||||
}
|
||||
|
||||
@@ -272,10 +258,6 @@ class CoreController {
|
||||
Future<void> crash() async {
|
||||
await _interface.crash();
|
||||
}
|
||||
|
||||
Future<String> deleteFile(String path) async {
|
||||
return await _interface.deleteFile(path);
|
||||
}
|
||||
}
|
||||
|
||||
final coreController = CoreController();
|
||||
|
||||
@@ -13,7 +13,7 @@ abstract mixin class CoreEventListener {
|
||||
|
||||
void onLoaded(String providerName) {}
|
||||
|
||||
void onCrash(String message) {}
|
||||
void onCrash() {}
|
||||
}
|
||||
|
||||
class CoreEventManager {
|
||||
@@ -36,7 +36,7 @@ class CoreEventManager {
|
||||
listener.onLoaded(event.data);
|
||||
break;
|
||||
case CoreEventType.crash:
|
||||
listener.onCrash(event.data);
|
||||
listener.onCrash();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import 'package:fl_clash/models/models.dart';
|
||||
mixin CoreInterface {
|
||||
Future<bool> init(InitParams params);
|
||||
|
||||
Future<String> preload();
|
||||
Future<bool> preload();
|
||||
|
||||
Future<bool> shutdown();
|
||||
|
||||
@@ -68,8 +68,6 @@ mixin CoreInterface {
|
||||
|
||||
FutureOr<bool> closeConnection(String id);
|
||||
|
||||
FutureOr<String> deleteFile(String path);
|
||||
|
||||
FutureOr<bool> closeConnections();
|
||||
|
||||
FutureOr<bool> resetConnections();
|
||||
@@ -165,7 +163,7 @@ abstract class CoreHandlerInterface with CoreInterface {
|
||||
|
||||
@override
|
||||
Future<Map> getProxies() async {
|
||||
final map = await _invoke<Map>(method: ActionMethod.getProxies);
|
||||
var map = await _invoke<Map>(method: ActionMethod.getProxies);
|
||||
return map ?? {};
|
||||
}
|
||||
|
||||
@@ -265,12 +263,6 @@ 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);
|
||||
@@ -306,7 +298,6 @@ abstract class CoreHandlerInterface with CoreInterface {
|
||||
return await _invoke<String>(
|
||||
method: ActionMethod.asyncTestDelay,
|
||||
data: json.encode(delayParams),
|
||||
timeout: Duration(seconds: 6),
|
||||
) ??
|
||||
json.encode(Delay(name: proxyName, value: -1, url: url));
|
||||
}
|
||||
|
||||
@@ -15,12 +15,10 @@ class CoreLib extends CoreHandlerInterface {
|
||||
CoreLib._internal();
|
||||
|
||||
@override
|
||||
Future<String> preload() async {
|
||||
final res = await service?.init();
|
||||
if (res?.isEmpty == true) {
|
||||
_connectedCompleter.complete(true);
|
||||
}
|
||||
return res ?? '';
|
||||
Future<bool> preload() async {
|
||||
await service?.init();
|
||||
_connectedCompleter.complete(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
factory CoreLib() {
|
||||
@@ -35,7 +33,6 @@ class CoreLib extends CoreHandlerInterface {
|
||||
|
||||
@override
|
||||
Future<bool> shutdown() async {
|
||||
await service?.shutdown();
|
||||
_connectedCompleter = Completer();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -73,9 +73,8 @@ class CoreService extends CoreHandlerInterface {
|
||||
}
|
||||
|
||||
void _handleInvokeCrashEvent() {
|
||||
coreEventManager.sendEvent(
|
||||
CoreEvent(type: CoreEventType.crash, data: 'socket done'),
|
||||
);
|
||||
_socketCompleter = Completer();
|
||||
coreEventManager.sendEvent(CoreEvent(type: CoreEventType.crash));
|
||||
}
|
||||
|
||||
Future<void> start() async {
|
||||
@@ -135,7 +134,6 @@ class CoreService extends CoreHandlerInterface {
|
||||
@override
|
||||
shutdown() async {
|
||||
await _destroySocket();
|
||||
_clearCompleter();
|
||||
if (system.isWindows) {
|
||||
await request.stopCoreByHelper();
|
||||
}
|
||||
@@ -144,17 +142,17 @@ class CoreService extends CoreHandlerInterface {
|
||||
return true;
|
||||
}
|
||||
|
||||
void _clearCompleter() {
|
||||
for (final completer in _callbackCompleterMap.values) {
|
||||
completer.safeCompleter(null);
|
||||
}
|
||||
}
|
||||
// void _clearCompleter() {
|
||||
// for (final completer in _callbackCompleterMap.values) {
|
||||
// completer.safeCompleter(null);
|
||||
// }
|
||||
// }
|
||||
|
||||
@override
|
||||
Future<String> preload() async {
|
||||
Future<bool> preload() async {
|
||||
await _serverCompleter.future;
|
||||
await start();
|
||||
return '';
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fl_clash/common/color.dart';
|
||||
import 'package:fl_clash/common/system.dart';
|
||||
import 'package:fl_clash/views/dashboard/widgets/widgets.dart';
|
||||
import 'package:fl_clash/widgets/widgets.dart';
|
||||
@@ -96,7 +95,7 @@ extension LogLevelExt on LogLevel {
|
||||
LogLevel.silent => Colors.grey.shade700,
|
||||
LogLevel.debug => Colors.grey.shade400,
|
||||
LogLevel.info => null,
|
||||
LogLevel.warning => Colors.orangeAccent.darken(),
|
||||
LogLevel.warning => Colors.yellowAccent,
|
||||
LogLevel.error => Colors.redAccent,
|
||||
};
|
||||
}
|
||||
@@ -243,7 +242,6 @@ enum ActionMethod {
|
||||
getMemory,
|
||||
crash,
|
||||
setupConfig,
|
||||
deleteFile,
|
||||
|
||||
///Android,
|
||||
setState,
|
||||
|
||||
@@ -196,7 +196,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"copySuccess": MessageLookupByLibrary.simpleMessage("Copy success"),
|
||||
"core": MessageLookupByLibrary.simpleMessage("Core"),
|
||||
"coreInfo": MessageLookupByLibrary.simpleMessage("Core info"),
|
||||
"coreStatus": MessageLookupByLibrary.simpleMessage("Core status"),
|
||||
"country": MessageLookupByLibrary.simpleMessage("Country"),
|
||||
"crashTest": MessageLookupByLibrary.simpleMessage("Crash test"),
|
||||
"create": MessageLookupByLibrary.simpleMessage("Create"),
|
||||
@@ -251,7 +250,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"dnsDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Update DNS related settings",
|
||||
),
|
||||
"dnsHijacking": MessageLookupByLibrary.simpleMessage("DNS hijacking"),
|
||||
"dnsMode": MessageLookupByLibrary.simpleMessage("DNS mode"),
|
||||
"doYouWantToPass": MessageLookupByLibrary.simpleMessage(
|
||||
"Do you want to pass",
|
||||
|
||||
@@ -148,7 +148,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"copySuccess": MessageLookupByLibrary.simpleMessage("コピー成功"),
|
||||
"core": MessageLookupByLibrary.simpleMessage("コア"),
|
||||
"coreInfo": MessageLookupByLibrary.simpleMessage("コア情報"),
|
||||
"coreStatus": MessageLookupByLibrary.simpleMessage("コアステータス"),
|
||||
"country": MessageLookupByLibrary.simpleMessage("国"),
|
||||
"crashTest": MessageLookupByLibrary.simpleMessage("クラッシュテスト"),
|
||||
"create": MessageLookupByLibrary.simpleMessage("作成"),
|
||||
@@ -189,7 +188,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"discoverNewVersion": MessageLookupByLibrary.simpleMessage("新バージョンを発見"),
|
||||
"discovery": MessageLookupByLibrary.simpleMessage("新しいバージョンを発見"),
|
||||
"dnsDesc": MessageLookupByLibrary.simpleMessage("DNS関連設定の更新"),
|
||||
"dnsHijacking": MessageLookupByLibrary.simpleMessage("DNSハイジャッキング"),
|
||||
"dnsMode": MessageLookupByLibrary.simpleMessage("DNSモード"),
|
||||
"doYouWantToPass": MessageLookupByLibrary.simpleMessage("通過させますか?"),
|
||||
"domain": MessageLookupByLibrary.simpleMessage("ドメイン"),
|
||||
|
||||
@@ -201,7 +201,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"copySuccess": MessageLookupByLibrary.simpleMessage("Копирование успешно"),
|
||||
"core": MessageLookupByLibrary.simpleMessage("Ядро"),
|
||||
"coreInfo": MessageLookupByLibrary.simpleMessage("Информация о ядре"),
|
||||
"coreStatus": MessageLookupByLibrary.simpleMessage("Основной статус"),
|
||||
"country": MessageLookupByLibrary.simpleMessage("Страна"),
|
||||
"crashTest": MessageLookupByLibrary.simpleMessage("Тест на сбои"),
|
||||
"create": MessageLookupByLibrary.simpleMessage("Создать"),
|
||||
@@ -258,7 +257,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"dnsDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Обновление настроек, связанных с DNS",
|
||||
),
|
||||
"dnsHijacking": MessageLookupByLibrary.simpleMessage("DNS-перехват"),
|
||||
"dnsMode": MessageLookupByLibrary.simpleMessage("Режим DNS"),
|
||||
"doYouWantToPass": MessageLookupByLibrary.simpleMessage(
|
||||
"Вы хотите пропустить",
|
||||
|
||||
@@ -138,7 +138,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"copySuccess": MessageLookupByLibrary.simpleMessage("复制成功"),
|
||||
"core": MessageLookupByLibrary.simpleMessage("内核"),
|
||||
"coreInfo": MessageLookupByLibrary.simpleMessage("内核信息"),
|
||||
"coreStatus": MessageLookupByLibrary.simpleMessage("核心状态"),
|
||||
"country": MessageLookupByLibrary.simpleMessage("区域"),
|
||||
"crashTest": MessageLookupByLibrary.simpleMessage("崩溃测试"),
|
||||
"create": MessageLookupByLibrary.simpleMessage("创建"),
|
||||
@@ -175,7 +174,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"discoverNewVersion": MessageLookupByLibrary.simpleMessage("发现新版本"),
|
||||
"discovery": MessageLookupByLibrary.simpleMessage("发现新版本"),
|
||||
"dnsDesc": MessageLookupByLibrary.simpleMessage("更新DNS相关设置"),
|
||||
"dnsHijacking": MessageLookupByLibrary.simpleMessage("DNS劫持"),
|
||||
"dnsMode": MessageLookupByLibrary.simpleMessage("DNS模式"),
|
||||
"doYouWantToPass": MessageLookupByLibrary.simpleMessage("是否要通过"),
|
||||
"domain": MessageLookupByLibrary.simpleMessage("域名"),
|
||||
|
||||
@@ -28,9 +28,10 @@ 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;
|
||||
@@ -3303,21 +3304,6 @@ class AppLocalizations {
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `DNS hijacking`
|
||||
String get dnsHijacking {
|
||||
return Intl.message(
|
||||
'DNS hijacking',
|
||||
name: 'dnsHijacking',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Core status`
|
||||
String get coreStatus {
|
||||
return Intl.message('Core status', name: 'coreStatus', desc: '', args: []);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<AppLocalizations> {
|
||||
|
||||
@@ -24,13 +24,12 @@ Future<void> main() async {
|
||||
Future<void> _service(List<String> flags) async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await globalState.init();
|
||||
await coreController.preload();
|
||||
await service?.syncAndroidState(globalState.getAndroidState());
|
||||
await service?.init();
|
||||
tile?.addListener(
|
||||
_TileListenerWithService(
|
||||
onStop: () async {
|
||||
await app?.tip(appLocalizations.stopVpn);
|
||||
await globalState.handleStop();
|
||||
globalState.handleStop();
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -41,8 +40,9 @@ Future<void> _service(List<String> flags) async {
|
||||
final clashConfig = globalState.config.patchClashConfig.copyWith.tun(
|
||||
enable: false,
|
||||
);
|
||||
final params = await globalState.getSetupParams(pathConfig: clashConfig);
|
||||
await coreController.setupConfig(params);
|
||||
await globalState.handleStart();
|
||||
await coreController.setupConfig(clashConfig);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -48,11 +48,9 @@ class _AndroidContainerState extends ConsumerState<AndroidManager>
|
||||
}
|
||||
|
||||
@override
|
||||
void onServiceCrash(String message) {
|
||||
coreEventManager.sendEvent(
|
||||
CoreEvent(type: CoreEventType.crash, data: message),
|
||||
);
|
||||
super.onServiceCrash(message);
|
||||
void onServiceCrash() {
|
||||
coreEventManager.sendEvent(CoreEvent(type: CoreEventType.crash));
|
||||
super.onServiceCrash();
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:fl_clash/providers/providers.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_acrylic/widgets/transparent_macos_sidebar.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
@@ -42,11 +43,6 @@ class _AppStateManagerState extends ConsumerState<AppStateManager>
|
||||
globalState.appController.savePreferencesDebounce();
|
||||
}
|
||||
});
|
||||
ref.listenManual(needUpdateGroupsProvider, (prev, next) {
|
||||
if (prev != next) {
|
||||
globalState.appController.updateGroupsDebounce();
|
||||
}
|
||||
});
|
||||
if (window == null) {
|
||||
return;
|
||||
}
|
||||
@@ -60,6 +56,12 @@ class _AppStateManagerState extends ConsumerState<AppStateManager>
|
||||
macOS?.updateDns(true);
|
||||
}
|
||||
});
|
||||
ref.listenManual(currentBrightnessProvider, (prev, next) {
|
||||
if (prev == next) {
|
||||
return;
|
||||
}
|
||||
window?.updateMacOSBrightness(next);
|
||||
}, fireImmediately: true);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -151,25 +153,15 @@ class AppSidebarContainer extends ConsumerWidget {
|
||||
required BuildContext context,
|
||||
required Widget child,
|
||||
}) {
|
||||
return Material(color: context.colorScheme.surfaceContainer, child: child);
|
||||
// if (!system.isMacOS) {
|
||||
// return Material(
|
||||
// color: context.colorScheme.surfaceContainer,
|
||||
// child: child,
|
||||
// );
|
||||
// }
|
||||
// return child;
|
||||
// return TransparentMacOSSidebar(
|
||||
// child: Material(color: Colors.transparent, child: child),
|
||||
// );
|
||||
}
|
||||
|
||||
void _updateSideBarWidth(WidgetRef ref, double contentWidth) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(sideWidthProvider.notifier).value =
|
||||
ref.read(viewSizeProvider.select((state) => state.width)) -
|
||||
contentWidth;
|
||||
});
|
||||
if (!system.isMacOS) {
|
||||
return Material(
|
||||
color: context.colorScheme.surfaceContainer,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
return TransparentMacOSSidebar(
|
||||
child: Material(color: Colors.transparent, child: child),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -181,7 +173,7 @@ class AppSidebarContainer extends ConsumerWidget {
|
||||
return child;
|
||||
}
|
||||
final currentIndex = navigationState.currentIndex;
|
||||
final isExtend = ref.watch(appSettingProvider).showLabel;
|
||||
final showLabel = ref.watch(appSettingProvider).showLabel;
|
||||
return Row(
|
||||
children: [
|
||||
Stack(
|
||||
@@ -189,106 +181,71 @@ class AppSidebarContainer extends ConsumerWidget {
|
||||
children: [
|
||||
_buildBackground(
|
||||
context: context,
|
||||
child: SafeArea(
|
||||
child: AnimatedSize(
|
||||
curve: Curves.easeOut,
|
||||
alignment: Alignment.centerLeft,
|
||||
duration: commonDuration,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (system.isMacOS) SizedBox(height: 22),
|
||||
SizedBox(height: 10),
|
||||
if (!system.isMacOS) ...[
|
||||
ClipRect(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: AppIcon(),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
],
|
||||
Expanded(
|
||||
child: ScrollConfiguration(
|
||||
behavior: HiddenBarScrollBehavior(),
|
||||
child: SingleChildScrollView(
|
||||
child: IntrinsicHeight(
|
||||
child: NavigationRail(
|
||||
backgroundColor: Colors.transparent,
|
||||
selectedLabelTextStyle: context
|
||||
.textTheme
|
||||
.labelLarge!
|
||||
.copyWith(
|
||||
color: context.colorScheme.onSurface,
|
||||
),
|
||||
unselectedLabelTextStyle: context
|
||||
.textTheme
|
||||
.labelLarge!
|
||||
.copyWith(
|
||||
color: context.colorScheme.onSurface,
|
||||
),
|
||||
destinations: navigationItems
|
||||
.map(
|
||||
(e) => NavigationRailDestination(
|
||||
icon: e.icon,
|
||||
label: Text(Intl.message(e.label.name)),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onDestinationSelected: (index) {
|
||||
globalState.appController.toPage(
|
||||
navigationItems[index].label,
|
||||
);
|
||||
},
|
||||
extended: isExtend,
|
||||
selectedIndex: currentIndex,
|
||||
// labelType: showLabel
|
||||
// ? NavigationRailLabelType.all
|
||||
// : NavigationRailLabelType.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(appSettingProvider.notifier)
|
||||
.updateState(
|
||||
(state) => state.copyWith(
|
||||
showLabel: !state.showLabel,
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: 32),
|
||||
if (!system.isMacOS) ...[AppIcon(), SizedBox(height: 12)],
|
||||
Expanded(
|
||||
child: ScrollConfiguration(
|
||||
behavior: HiddenBarScrollBehavior(),
|
||||
child: SingleChildScrollView(
|
||||
child: IntrinsicHeight(
|
||||
child: NavigationRail(
|
||||
backgroundColor: Colors.transparent,
|
||||
selectedLabelTextStyle: context
|
||||
.textTheme
|
||||
.labelLarge!
|
||||
.copyWith(color: context.colorScheme.onSurface),
|
||||
unselectedLabelTextStyle: context
|
||||
.textTheme
|
||||
.labelLarge!
|
||||
.copyWith(color: context.colorScheme.onSurface),
|
||||
destinations: navigationItems
|
||||
.map(
|
||||
(e) => NavigationRailDestination(
|
||||
icon: e.icon,
|
||||
label: Text(Intl.message(e.label.name)),
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.menu,
|
||||
color: context.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
.toList(),
|
||||
onDestinationSelected: (index) {
|
||||
globalState.appController.toPage(
|
||||
navigationItems[index].label,
|
||||
);
|
||||
},
|
||||
extended: false,
|
||||
selectedIndex: currentIndex,
|
||||
labelType: showLabel
|
||||
? NavigationRailLabelType.all
|
||||
: NavigationRailLabelType.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(appSettingProvider.notifier)
|
||||
.updateState(
|
||||
(state) =>
|
||||
state.copyWith(showLabel: !state.showLabel),
|
||||
);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.menu,
|
||||
color: context.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
_buildLoading(),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: ClipRect(
|
||||
child: LayoutBuilder(
|
||||
builder: (_, constraints) {
|
||||
_updateSideBarWidth(ref, constraints.maxWidth);
|
||||
return child;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(flex: 1, child: ClipRect(child: child)),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -92,16 +92,12 @@ class _CoreContainerState extends ConsumerState<CoreManager>
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onCrash(String message) async {
|
||||
if (!globalState.isUserDisconnected) {
|
||||
context.showNotifier(message);
|
||||
globalState.isUserDisconnected = false;
|
||||
}
|
||||
Future<void> onCrash() async {
|
||||
if (ref.read(coreStatusProvider) != CoreStatus.connected) {
|
||||
return;
|
||||
}
|
||||
ref.read(coreStatusProvider.notifier).value = CoreStatus.disconnected;
|
||||
await coreController.shutdown();
|
||||
super.onCrash(message);
|
||||
super.onCrash();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,10 @@ import '../providers/state.dart';
|
||||
class ThemeManager extends ConsumerWidget {
|
||||
final Widget child;
|
||||
|
||||
const ThemeManager({super.key, required this.child});
|
||||
const ThemeManager({
|
||||
super.key,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
Widget _buildSystemUi(Widget child) {
|
||||
if (!system.isAndroid) {
|
||||
@@ -82,7 +85,9 @@ class ThemeManager extends ConsumerWidget {
|
||||
final height = MediaQuery.of(context).size.height;
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaler: TextScaler.linear(textScaleFactor),
|
||||
textScaler: TextScaler.linear(
|
||||
textScaleFactor,
|
||||
),
|
||||
padding: padding.copyWith(
|
||||
top: padding.top > height * 0.3 ? 20.0 : padding.top,
|
||||
),
|
||||
@@ -90,7 +95,10 @@ class ThemeManager extends ConsumerWidget {
|
||||
child: LayoutBuilder(
|
||||
builder: (_, container) {
|
||||
globalState.appController.updateViewSize(
|
||||
Size(container.maxWidth, container.maxHeight),
|
||||
Size(
|
||||
container.maxWidth,
|
||||
container.maxHeight,
|
||||
),
|
||||
);
|
||||
return _buildSystemUi(child);
|
||||
},
|
||||
|
||||
@@ -20,7 +20,6 @@ abstract class AppState with _$AppState {
|
||||
@Default([]) List<Package> packages,
|
||||
@Default(0) int sortNum,
|
||||
required Size viewSize,
|
||||
@Default(0) double sideWidth,
|
||||
@Default({}) DelayMap delayMap,
|
||||
@Default([]) List<Group> groups,
|
||||
@Default(0) int checkIpNum,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// 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';
|
||||
@@ -98,14 +100,17 @@ const defaultBypassPrivateRouteAddress = [
|
||||
'f000::/5',
|
||||
'f800::/6',
|
||||
'fe00::/9',
|
||||
'fec0::/10',
|
||||
'fec0::/10'
|
||||
];
|
||||
|
||||
@freezed
|
||||
abstract class ProxyGroup with _$ProxyGroup {
|
||||
const factory ProxyGroup({
|
||||
required String name,
|
||||
@JsonKey(fromJson: GroupType.parseProfileType) required GroupType type,
|
||||
@JsonKey(
|
||||
fromJson: GroupType.parseProfileType,
|
||||
)
|
||||
required GroupType type,
|
||||
List<String>? proxies,
|
||||
List<String>? use,
|
||||
int? interval,
|
||||
@@ -127,7 +132,9 @@ abstract class ProxyGroup with _$ProxyGroup {
|
||||
|
||||
@freezed
|
||||
abstract class RuleProvider with _$RuleProvider {
|
||||
const factory RuleProvider({required String name}) = _RuleProvider;
|
||||
const factory RuleProvider({
|
||||
required String name,
|
||||
}) = _RuleProvider;
|
||||
|
||||
factory RuleProvider.fromJson(Map<String, Object?> json) =>
|
||||
_$RuleProviderFromJson(json);
|
||||
@@ -199,11 +206,14 @@ extension TunExt on Tun {
|
||||
? defaultBypassPrivateRouteAddress
|
||||
: routeAddress;
|
||||
return switch (system.isDesktop) {
|
||||
true => copyWith(autoRoute: true, routeAddress: []),
|
||||
true => copyWith(
|
||||
autoRoute: true,
|
||||
routeAddress: [],
|
||||
),
|
||||
false => copyWith(
|
||||
autoRoute: mRouteAddress.isEmpty ? true : false,
|
||||
routeAddress: mRouteAddress,
|
||||
),
|
||||
autoRoute: mRouteAddress.isEmpty ? true : false,
|
||||
routeAddress: mRouteAddress,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -215,7 +225,11 @@ abstract class FallbackFilter with _$FallbackFilter {
|
||||
@Default('CN') @JsonKey(name: 'geoip-code') String geoipCode,
|
||||
@Default(['gfw']) List<String> geosite,
|
||||
@Default(['240.0.0.0/4']) List<String> ipcidr,
|
||||
@Default(['+.google.com', '+.facebook.com', '+.youtube.com'])
|
||||
@Default([
|
||||
'+.google.com',
|
||||
'+.facebook.com',
|
||||
'+.youtube.com',
|
||||
])
|
||||
List<String> domain,
|
||||
}) = _FallbackFilter;
|
||||
|
||||
@@ -242,20 +256,32 @@ abstract class Dns with _$Dns {
|
||||
@Default('198.18.0.1/16')
|
||||
@JsonKey(name: 'fake-ip-range')
|
||||
String fakeIpRange,
|
||||
@Default(['*.lan', 'localhost.ptlogin2.qq.com'])
|
||||
@Default([
|
||||
'*.lan',
|
||||
'localhost.ptlogin2.qq.com',
|
||||
])
|
||||
@JsonKey(name: 'fake-ip-filter')
|
||||
List<String> fakeIpFilter,
|
||||
@Default({
|
||||
'www.baidu.com': '114.114.114.114',
|
||||
'+.internal.crop.com': '10.0.0.1',
|
||||
'geosite:cn': 'https://doh.pub/dns-query',
|
||||
'geosite:cn': 'https://doh.pub/dns-query'
|
||||
})
|
||||
@JsonKey(name: 'nameserver-policy')
|
||||
Map<String, String> nameserverPolicy,
|
||||
@Default(['https://doh.pub/dns-query', 'https://dns.alidns.com/dns-query'])
|
||||
@Default([
|
||||
'https://doh.pub/dns-query',
|
||||
'https://dns.alidns.com/dns-query',
|
||||
])
|
||||
List<String> nameserver,
|
||||
@Default(['tls://8.8.4.4', 'tls://1.1.1.1']) List<String> fallback,
|
||||
@Default(['https://doh.pub/dns-query'])
|
||||
@Default([
|
||||
'tls://8.8.4.4',
|
||||
'tls://1.1.1.1',
|
||||
])
|
||||
List<String> fallback,
|
||||
@Default([
|
||||
'https://doh.pub/dns-query',
|
||||
])
|
||||
@JsonKey(name: 'proxy-server-nameserver')
|
||||
List<String> proxyServerNameserver,
|
||||
@Default(FallbackFilter())
|
||||
@@ -325,7 +351,9 @@ abstract class ParsedRule with _$ParsedRule {
|
||||
factory ParsedRule.parseString(String value) {
|
||||
final splits = value.split(',');
|
||||
final shortSplits = splits
|
||||
.where((item) => !item.contains('src') && !item.contains('no-resolve'))
|
||||
.where(
|
||||
(item) => !item.contains('src') && !item.contains('no-resolve'),
|
||||
)
|
||||
.toList();
|
||||
final ruleAction = RuleAction.values.firstWhere(
|
||||
(item) => item.value == shortSplits.first,
|
||||
@@ -370,17 +398,23 @@ extension ParsedRuleExt on ParsedRule {
|
||||
if (ruleAction.hasParams) ...[
|
||||
if (src) 'src',
|
||||
if (noResolve) 'no-resolve',
|
||||
],
|
||||
]
|
||||
].join(',');
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class Rule with _$Rule {
|
||||
const factory Rule({required String id, required String value}) = _Rule;
|
||||
const factory Rule({
|
||||
required String id,
|
||||
required String value,
|
||||
}) = _Rule;
|
||||
|
||||
factory Rule.value(String value) {
|
||||
return Rule(value: value, id: utils.uuidV4);
|
||||
return Rule(
|
||||
value: value,
|
||||
id: utils.uuidV4,
|
||||
);
|
||||
}
|
||||
|
||||
factory Rule.fromJson(Map<String, Object?> json) => _$RuleFromJson(json);
|
||||
@@ -388,7 +422,9 @@ abstract class Rule with _$Rule {
|
||||
|
||||
@freezed
|
||||
abstract class SubRule with _$SubRule {
|
||||
const factory SubRule({required String name}) = _SubRule;
|
||||
const factory SubRule({
|
||||
required String name,
|
||||
}) = _SubRule;
|
||||
|
||||
factory SubRule.fromJson(Map<String, Object?> json) =>
|
||||
_$SubRuleFromJson(json);
|
||||
@@ -398,7 +434,11 @@ List<Rule> _genRule(List<dynamic>? rules) {
|
||||
if (rules == null) {
|
||||
return [];
|
||||
}
|
||||
return rules.map((item) => Rule.value(item)).toList();
|
||||
return rules
|
||||
.map(
|
||||
(item) => Rule.value(item),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
List<RuleProvider> _genRuleProviders(Map<String, dynamic> json) {
|
||||
@@ -406,7 +446,13 @@ List<RuleProvider> _genRuleProviders(Map<String, dynamic> json) {
|
||||
}
|
||||
|
||||
List<SubRule> _genSubRules(Map<String, dynamic> json) {
|
||||
return json.entries.map((entry) => SubRule(name: entry.key)).toList();
|
||||
return json.entries
|
||||
.map(
|
||||
(entry) => SubRule(
|
||||
name: entry.key,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@freezed
|
||||
@@ -438,7 +484,7 @@ abstract class ClashConfig with _$ClashConfig {
|
||||
@Default(false) @JsonKey(name: 'allow-lan') bool allowLan,
|
||||
@Default(LogLevel.error) @JsonKey(name: 'log-level') LogLevel logLevel,
|
||||
@Default(false) bool ipv6,
|
||||
@Default(FindProcessMode.always)
|
||||
@Default(FindProcessMode.off)
|
||||
@JsonKey(
|
||||
name: 'find-process-mode',
|
||||
unknownEnumValue: FindProcessMode.always,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// 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';
|
||||
@@ -95,9 +97,9 @@ extension TrackerInfoExt on TrackerInfo {
|
||||
final process = metadata.process;
|
||||
final uid = metadata.uid;
|
||||
if (uid != 0) {
|
||||
return '$process($uid)'.trim();
|
||||
return '$process($uid)';
|
||||
}
|
||||
return process.trim();
|
||||
return process;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +236,7 @@ extension TrafficExt on Traffic {
|
||||
}
|
||||
|
||||
String get desc {
|
||||
return '${up.traffic.show} ↑ ${down.traffic.show} ↓';
|
||||
return '${up.traffic.show}↑ ${down.traffic.show}↓';
|
||||
}
|
||||
|
||||
num get speed => up + down;
|
||||
@@ -247,7 +249,7 @@ abstract class TrafficShow with _$TrafficShow {
|
||||
}
|
||||
|
||||
extension TrafficShowExt on TrafficShow {
|
||||
String get show => '$value$unit';
|
||||
String get show => '$value $unit';
|
||||
}
|
||||
|
||||
@freezed
|
||||
@@ -363,41 +365,13 @@ 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
|
||||
@@ -490,29 +464,3 @@ 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,3 +1,5 @@
|
||||
// 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';
|
||||
@@ -25,7 +27,7 @@ const defaultBypassDomain = [
|
||||
'172.2*',
|
||||
'172.30.*',
|
||||
'172.31.*',
|
||||
'192.168.*',
|
||||
'192.168.*'
|
||||
];
|
||||
|
||||
const defaultAppSettingProps = AppSettingProps();
|
||||
@@ -34,7 +36,9 @@ 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,
|
||||
@@ -111,9 +115,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,3 +1,5 @@
|
||||
// ignore_for_file: invalid_annotation_target
|
||||
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/models/models.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
@@ -8,6 +10,7 @@ part 'generated/core.g.dart';
|
||||
@freezed
|
||||
abstract class SetupParams with _$SetupParams {
|
||||
const factory SetupParams({
|
||||
@JsonKey(name: 'config') required Map<String, dynamic> config,
|
||||
@JsonKey(name: 'selected-map') required Map<String, String> selectedMap,
|
||||
@JsonKey(name: 'test-url') required String testUrl,
|
||||
}) = _SetupParams;
|
||||
@@ -48,7 +51,6 @@ abstract class VpnOptions with _$VpnOptions {
|
||||
required bool allowBypass,
|
||||
required bool systemProxy,
|
||||
required List<String> bypassDomain,
|
||||
required String stack,
|
||||
@Default([]) List<String> routeAddress,
|
||||
}) = _VpnOptions;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$AppState {
|
||||
|
||||
bool get isInit; bool get backBlock; PageLabel get pageLabel; List<Package> get packages; int get sortNum; Size get viewSize; double get sideWidth; DelayMap get delayMap; List<Group> get groups; int get checkIpNum; Brightness get brightness; int? get runTime; List<ExternalProvider> get providers; String? get localIp; FixedList<TrackerInfo> get requests; int get version; FixedList<Log> get logs; FixedList<Traffic> get traffics; Traffic get totalTraffic; bool get realTunEnable; bool get loading; SystemUiOverlayStyle get systemUiOverlayStyle; ProfileOverrideModel? get profileOverrideModel; Map<QueryTag, String> get queryMap; CoreStatus get coreStatus;
|
||||
bool get isInit; bool get backBlock; PageLabel get pageLabel; List<Package> get packages; int get sortNum; Size get viewSize; DelayMap get delayMap; List<Group> get groups; int get checkIpNum; Brightness get brightness; int? get runTime; List<ExternalProvider> get providers; String? get localIp; FixedList<TrackerInfo> get requests; int get version; FixedList<Log> get logs; FixedList<Traffic> get traffics; Traffic get totalTraffic; bool get realTunEnable; bool get loading; SystemUiOverlayStyle get systemUiOverlayStyle; ProfileOverrideModel? get profileOverrideModel; Map<QueryTag, String> get queryMap; CoreStatus get coreStatus;
|
||||
/// Create a copy of AppState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -25,16 +25,16 @@ $AppStateCopyWith<AppState> get copyWith => _$AppStateCopyWithImpl<AppState>(thi
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppState&&(identical(other.isInit, isInit) || other.isInit == isInit)&&(identical(other.backBlock, backBlock) || other.backBlock == backBlock)&&(identical(other.pageLabel, pageLabel) || other.pageLabel == pageLabel)&&const DeepCollectionEquality().equals(other.packages, packages)&&(identical(other.sortNum, sortNum) || other.sortNum == sortNum)&&(identical(other.viewSize, viewSize) || other.viewSize == viewSize)&&(identical(other.sideWidth, sideWidth) || other.sideWidth == sideWidth)&&const DeepCollectionEquality().equals(other.delayMap, delayMap)&&const DeepCollectionEquality().equals(other.groups, groups)&&(identical(other.checkIpNum, checkIpNum) || other.checkIpNum == checkIpNum)&&(identical(other.brightness, brightness) || other.brightness == brightness)&&(identical(other.runTime, runTime) || other.runTime == runTime)&&const DeepCollectionEquality().equals(other.providers, providers)&&(identical(other.localIp, localIp) || other.localIp == localIp)&&(identical(other.requests, requests) || other.requests == requests)&&(identical(other.version, version) || other.version == version)&&(identical(other.logs, logs) || other.logs == logs)&&(identical(other.traffics, traffics) || other.traffics == traffics)&&(identical(other.totalTraffic, totalTraffic) || other.totalTraffic == totalTraffic)&&(identical(other.realTunEnable, realTunEnable) || other.realTunEnable == realTunEnable)&&(identical(other.loading, loading) || other.loading == loading)&&(identical(other.systemUiOverlayStyle, systemUiOverlayStyle) || other.systemUiOverlayStyle == systemUiOverlayStyle)&&(identical(other.profileOverrideModel, profileOverrideModel) || other.profileOverrideModel == profileOverrideModel)&&const DeepCollectionEquality().equals(other.queryMap, queryMap)&&(identical(other.coreStatus, coreStatus) || other.coreStatus == coreStatus));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppState&&(identical(other.isInit, isInit) || other.isInit == isInit)&&(identical(other.backBlock, backBlock) || other.backBlock == backBlock)&&(identical(other.pageLabel, pageLabel) || other.pageLabel == pageLabel)&&const DeepCollectionEquality().equals(other.packages, packages)&&(identical(other.sortNum, sortNum) || other.sortNum == sortNum)&&(identical(other.viewSize, viewSize) || other.viewSize == viewSize)&&const DeepCollectionEquality().equals(other.delayMap, delayMap)&&const DeepCollectionEquality().equals(other.groups, groups)&&(identical(other.checkIpNum, checkIpNum) || other.checkIpNum == checkIpNum)&&(identical(other.brightness, brightness) || other.brightness == brightness)&&(identical(other.runTime, runTime) || other.runTime == runTime)&&const DeepCollectionEquality().equals(other.providers, providers)&&(identical(other.localIp, localIp) || other.localIp == localIp)&&(identical(other.requests, requests) || other.requests == requests)&&(identical(other.version, version) || other.version == version)&&(identical(other.logs, logs) || other.logs == logs)&&(identical(other.traffics, traffics) || other.traffics == traffics)&&(identical(other.totalTraffic, totalTraffic) || other.totalTraffic == totalTraffic)&&(identical(other.realTunEnable, realTunEnable) || other.realTunEnable == realTunEnable)&&(identical(other.loading, loading) || other.loading == loading)&&(identical(other.systemUiOverlayStyle, systemUiOverlayStyle) || other.systemUiOverlayStyle == systemUiOverlayStyle)&&(identical(other.profileOverrideModel, profileOverrideModel) || other.profileOverrideModel == profileOverrideModel)&&const DeepCollectionEquality().equals(other.queryMap, queryMap)&&(identical(other.coreStatus, coreStatus) || other.coreStatus == coreStatus));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,isInit,backBlock,pageLabel,const DeepCollectionEquality().hash(packages),sortNum,viewSize,sideWidth,const DeepCollectionEquality().hash(delayMap),const DeepCollectionEquality().hash(groups),checkIpNum,brightness,runTime,const DeepCollectionEquality().hash(providers),localIp,requests,version,logs,traffics,totalTraffic,realTunEnable,loading,systemUiOverlayStyle,profileOverrideModel,const DeepCollectionEquality().hash(queryMap),coreStatus]);
|
||||
int get hashCode => Object.hashAll([runtimeType,isInit,backBlock,pageLabel,const DeepCollectionEquality().hash(packages),sortNum,viewSize,const DeepCollectionEquality().hash(delayMap),const DeepCollectionEquality().hash(groups),checkIpNum,brightness,runTime,const DeepCollectionEquality().hash(providers),localIp,requests,version,logs,traffics,totalTraffic,realTunEnable,loading,systemUiOverlayStyle,profileOverrideModel,const DeepCollectionEquality().hash(queryMap),coreStatus]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppState(isInit: $isInit, backBlock: $backBlock, pageLabel: $pageLabel, packages: $packages, sortNum: $sortNum, viewSize: $viewSize, sideWidth: $sideWidth, delayMap: $delayMap, groups: $groups, checkIpNum: $checkIpNum, brightness: $brightness, runTime: $runTime, providers: $providers, localIp: $localIp, requests: $requests, version: $version, logs: $logs, traffics: $traffics, totalTraffic: $totalTraffic, realTunEnable: $realTunEnable, loading: $loading, systemUiOverlayStyle: $systemUiOverlayStyle, profileOverrideModel: $profileOverrideModel, queryMap: $queryMap, coreStatus: $coreStatus)';
|
||||
return 'AppState(isInit: $isInit, backBlock: $backBlock, pageLabel: $pageLabel, packages: $packages, sortNum: $sortNum, viewSize: $viewSize, delayMap: $delayMap, groups: $groups, checkIpNum: $checkIpNum, brightness: $brightness, runTime: $runTime, providers: $providers, localIp: $localIp, requests: $requests, version: $version, logs: $logs, traffics: $traffics, totalTraffic: $totalTraffic, realTunEnable: $realTunEnable, loading: $loading, systemUiOverlayStyle: $systemUiOverlayStyle, profileOverrideModel: $profileOverrideModel, queryMap: $queryMap, coreStatus: $coreStatus)';
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ abstract mixin class $AppStateCopyWith<$Res> {
|
||||
factory $AppStateCopyWith(AppState value, $Res Function(AppState) _then) = _$AppStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool isInit, bool backBlock, PageLabel pageLabel, List<Package> packages, int sortNum, Size viewSize, double sideWidth, DelayMap delayMap, List<Group> groups, int checkIpNum, Brightness brightness, int? runTime, List<ExternalProvider> providers, String? localIp, FixedList<TrackerInfo> requests, int version, FixedList<Log> logs, FixedList<Traffic> traffics, Traffic totalTraffic, bool realTunEnable, bool loading, SystemUiOverlayStyle systemUiOverlayStyle, ProfileOverrideModel? profileOverrideModel, Map<QueryTag, String> queryMap, CoreStatus coreStatus
|
||||
bool isInit, bool backBlock, PageLabel pageLabel, List<Package> packages, int sortNum, Size viewSize, DelayMap delayMap, List<Group> groups, int checkIpNum, Brightness brightness, int? runTime, List<ExternalProvider> providers, String? localIp, FixedList<TrackerInfo> requests, int version, FixedList<Log> logs, FixedList<Traffic> traffics, Traffic totalTraffic, bool realTunEnable, bool loading, SystemUiOverlayStyle systemUiOverlayStyle, ProfileOverrideModel? profileOverrideModel, Map<QueryTag, String> queryMap, CoreStatus coreStatus
|
||||
});
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ class _$AppStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of AppState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? isInit = null,Object? backBlock = null,Object? pageLabel = null,Object? packages = null,Object? sortNum = null,Object? viewSize = null,Object? sideWidth = null,Object? delayMap = null,Object? groups = null,Object? checkIpNum = null,Object? brightness = null,Object? runTime = freezed,Object? providers = null,Object? localIp = freezed,Object? requests = null,Object? version = null,Object? logs = null,Object? traffics = null,Object? totalTraffic = null,Object? realTunEnable = null,Object? loading = null,Object? systemUiOverlayStyle = null,Object? profileOverrideModel = freezed,Object? queryMap = null,Object? coreStatus = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? isInit = null,Object? backBlock = null,Object? pageLabel = null,Object? packages = null,Object? sortNum = null,Object? viewSize = null,Object? delayMap = null,Object? groups = null,Object? checkIpNum = null,Object? brightness = null,Object? runTime = freezed,Object? providers = null,Object? localIp = freezed,Object? requests = null,Object? version = null,Object? logs = null,Object? traffics = null,Object? totalTraffic = null,Object? realTunEnable = null,Object? loading = null,Object? systemUiOverlayStyle = null,Object? profileOverrideModel = freezed,Object? queryMap = null,Object? coreStatus = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
isInit: null == isInit ? _self.isInit : isInit // ignore: cast_nullable_to_non_nullable
|
||||
as bool,backBlock: null == backBlock ? _self.backBlock : backBlock // ignore: cast_nullable_to_non_nullable
|
||||
@@ -70,8 +70,7 @@ as bool,pageLabel: null == pageLabel ? _self.pageLabel : pageLabel // ignore: ca
|
||||
as PageLabel,packages: null == packages ? _self.packages : packages // ignore: cast_nullable_to_non_nullable
|
||||
as List<Package>,sortNum: null == sortNum ? _self.sortNum : sortNum // ignore: cast_nullable_to_non_nullable
|
||||
as int,viewSize: null == viewSize ? _self.viewSize : viewSize // ignore: cast_nullable_to_non_nullable
|
||||
as Size,sideWidth: null == sideWidth ? _self.sideWidth : sideWidth // ignore: cast_nullable_to_non_nullable
|
||||
as double,delayMap: null == delayMap ? _self.delayMap : delayMap // ignore: cast_nullable_to_non_nullable
|
||||
as Size,delayMap: null == delayMap ? _self.delayMap : delayMap // ignore: cast_nullable_to_non_nullable
|
||||
as DelayMap,groups: null == groups ? _self.groups : groups // ignore: cast_nullable_to_non_nullable
|
||||
as List<Group>,checkIpNum: null == checkIpNum ? _self.checkIpNum : checkIpNum // ignore: cast_nullable_to_non_nullable
|
||||
as int,brightness: null == brightness ? _self.brightness : brightness // ignore: cast_nullable_to_non_nullable
|
||||
@@ -195,10 +194,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isInit, bool backBlock, PageLabel pageLabel, List<Package> packages, int sortNum, Size viewSize, double sideWidth, DelayMap delayMap, List<Group> groups, int checkIpNum, Brightness brightness, int? runTime, List<ExternalProvider> providers, String? localIp, FixedList<TrackerInfo> requests, int version, FixedList<Log> logs, FixedList<Traffic> traffics, Traffic totalTraffic, bool realTunEnable, bool loading, SystemUiOverlayStyle systemUiOverlayStyle, ProfileOverrideModel? profileOverrideModel, Map<QueryTag, String> queryMap, CoreStatus coreStatus)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool isInit, bool backBlock, PageLabel pageLabel, List<Package> packages, int sortNum, Size viewSize, DelayMap delayMap, List<Group> groups, int checkIpNum, Brightness brightness, int? runTime, List<ExternalProvider> providers, String? localIp, FixedList<TrackerInfo> requests, int version, FixedList<Log> logs, FixedList<Traffic> traffics, Traffic totalTraffic, bool realTunEnable, bool loading, SystemUiOverlayStyle systemUiOverlayStyle, ProfileOverrideModel? profileOverrideModel, Map<QueryTag, String> queryMap, CoreStatus coreStatus)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AppState() when $default != null:
|
||||
return $default(_that.isInit,_that.backBlock,_that.pageLabel,_that.packages,_that.sortNum,_that.viewSize,_that.sideWidth,_that.delayMap,_that.groups,_that.checkIpNum,_that.brightness,_that.runTime,_that.providers,_that.localIp,_that.requests,_that.version,_that.logs,_that.traffics,_that.totalTraffic,_that.realTunEnable,_that.loading,_that.systemUiOverlayStyle,_that.profileOverrideModel,_that.queryMap,_that.coreStatus);case _:
|
||||
return $default(_that.isInit,_that.backBlock,_that.pageLabel,_that.packages,_that.sortNum,_that.viewSize,_that.delayMap,_that.groups,_that.checkIpNum,_that.brightness,_that.runTime,_that.providers,_that.localIp,_that.requests,_that.version,_that.logs,_that.traffics,_that.totalTraffic,_that.realTunEnable,_that.loading,_that.systemUiOverlayStyle,_that.profileOverrideModel,_that.queryMap,_that.coreStatus);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -216,10 +215,10 @@ return $default(_that.isInit,_that.backBlock,_that.pageLabel,_that.packages,_tha
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isInit, bool backBlock, PageLabel pageLabel, List<Package> packages, int sortNum, Size viewSize, double sideWidth, DelayMap delayMap, List<Group> groups, int checkIpNum, Brightness brightness, int? runTime, List<ExternalProvider> providers, String? localIp, FixedList<TrackerInfo> requests, int version, FixedList<Log> logs, FixedList<Traffic> traffics, Traffic totalTraffic, bool realTunEnable, bool loading, SystemUiOverlayStyle systemUiOverlayStyle, ProfileOverrideModel? profileOverrideModel, Map<QueryTag, String> queryMap, CoreStatus coreStatus) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool isInit, bool backBlock, PageLabel pageLabel, List<Package> packages, int sortNum, Size viewSize, DelayMap delayMap, List<Group> groups, int checkIpNum, Brightness brightness, int? runTime, List<ExternalProvider> providers, String? localIp, FixedList<TrackerInfo> requests, int version, FixedList<Log> logs, FixedList<Traffic> traffics, Traffic totalTraffic, bool realTunEnable, bool loading, SystemUiOverlayStyle systemUiOverlayStyle, ProfileOverrideModel? profileOverrideModel, Map<QueryTag, String> queryMap, CoreStatus coreStatus) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AppState():
|
||||
return $default(_that.isInit,_that.backBlock,_that.pageLabel,_that.packages,_that.sortNum,_that.viewSize,_that.sideWidth,_that.delayMap,_that.groups,_that.checkIpNum,_that.brightness,_that.runTime,_that.providers,_that.localIp,_that.requests,_that.version,_that.logs,_that.traffics,_that.totalTraffic,_that.realTunEnable,_that.loading,_that.systemUiOverlayStyle,_that.profileOverrideModel,_that.queryMap,_that.coreStatus);case _:
|
||||
return $default(_that.isInit,_that.backBlock,_that.pageLabel,_that.packages,_that.sortNum,_that.viewSize,_that.delayMap,_that.groups,_that.checkIpNum,_that.brightness,_that.runTime,_that.providers,_that.localIp,_that.requests,_that.version,_that.logs,_that.traffics,_that.totalTraffic,_that.realTunEnable,_that.loading,_that.systemUiOverlayStyle,_that.profileOverrideModel,_that.queryMap,_that.coreStatus);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -236,10 +235,10 @@ return $default(_that.isInit,_that.backBlock,_that.pageLabel,_that.packages,_tha
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isInit, bool backBlock, PageLabel pageLabel, List<Package> packages, int sortNum, Size viewSize, double sideWidth, DelayMap delayMap, List<Group> groups, int checkIpNum, Brightness brightness, int? runTime, List<ExternalProvider> providers, String? localIp, FixedList<TrackerInfo> requests, int version, FixedList<Log> logs, FixedList<Traffic> traffics, Traffic totalTraffic, bool realTunEnable, bool loading, SystemUiOverlayStyle systemUiOverlayStyle, ProfileOverrideModel? profileOverrideModel, Map<QueryTag, String> queryMap, CoreStatus coreStatus)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool isInit, bool backBlock, PageLabel pageLabel, List<Package> packages, int sortNum, Size viewSize, DelayMap delayMap, List<Group> groups, int checkIpNum, Brightness brightness, int? runTime, List<ExternalProvider> providers, String? localIp, FixedList<TrackerInfo> requests, int version, FixedList<Log> logs, FixedList<Traffic> traffics, Traffic totalTraffic, bool realTunEnable, bool loading, SystemUiOverlayStyle systemUiOverlayStyle, ProfileOverrideModel? profileOverrideModel, Map<QueryTag, String> queryMap, CoreStatus coreStatus)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _AppState() when $default != null:
|
||||
return $default(_that.isInit,_that.backBlock,_that.pageLabel,_that.packages,_that.sortNum,_that.viewSize,_that.sideWidth,_that.delayMap,_that.groups,_that.checkIpNum,_that.brightness,_that.runTime,_that.providers,_that.localIp,_that.requests,_that.version,_that.logs,_that.traffics,_that.totalTraffic,_that.realTunEnable,_that.loading,_that.systemUiOverlayStyle,_that.profileOverrideModel,_that.queryMap,_that.coreStatus);case _:
|
||||
return $default(_that.isInit,_that.backBlock,_that.pageLabel,_that.packages,_that.sortNum,_that.viewSize,_that.delayMap,_that.groups,_that.checkIpNum,_that.brightness,_that.runTime,_that.providers,_that.localIp,_that.requests,_that.version,_that.logs,_that.traffics,_that.totalTraffic,_that.realTunEnable,_that.loading,_that.systemUiOverlayStyle,_that.profileOverrideModel,_that.queryMap,_that.coreStatus);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -251,7 +250,7 @@ return $default(_that.isInit,_that.backBlock,_that.pageLabel,_that.packages,_tha
|
||||
|
||||
|
||||
class _AppState implements AppState {
|
||||
const _AppState({this.isInit = false, this.backBlock = false, this.pageLabel = PageLabel.dashboard, final List<Package> packages = const [], this.sortNum = 0, required this.viewSize, this.sideWidth = 0, final DelayMap delayMap = const {}, final List<Group> groups = const [], this.checkIpNum = 0, required this.brightness, this.runTime, final List<ExternalProvider> providers = const [], this.localIp, required this.requests, required this.version, required this.logs, required this.traffics, required this.totalTraffic, this.realTunEnable = false, this.loading = false, required this.systemUiOverlayStyle, this.profileOverrideModel, final Map<QueryTag, String> queryMap = const {}, this.coreStatus = CoreStatus.connecting}): _packages = packages,_delayMap = delayMap,_groups = groups,_providers = providers,_queryMap = queryMap;
|
||||
const _AppState({this.isInit = false, this.backBlock = false, this.pageLabel = PageLabel.dashboard, final List<Package> packages = const [], this.sortNum = 0, required this.viewSize, final DelayMap delayMap = const {}, final List<Group> groups = const [], this.checkIpNum = 0, required this.brightness, this.runTime, final List<ExternalProvider> providers = const [], this.localIp, required this.requests, required this.version, required this.logs, required this.traffics, required this.totalTraffic, this.realTunEnable = false, this.loading = false, required this.systemUiOverlayStyle, this.profileOverrideModel, final Map<QueryTag, String> queryMap = const {}, this.coreStatus = CoreStatus.connecting}): _packages = packages,_delayMap = delayMap,_groups = groups,_providers = providers,_queryMap = queryMap;
|
||||
|
||||
|
||||
@override@JsonKey() final bool isInit;
|
||||
@@ -266,7 +265,6 @@ class _AppState implements AppState {
|
||||
|
||||
@override@JsonKey() final int sortNum;
|
||||
@override final Size viewSize;
|
||||
@override@JsonKey() final double sideWidth;
|
||||
final DelayMap _delayMap;
|
||||
@override@JsonKey() DelayMap get delayMap {
|
||||
if (_delayMap is EqualUnmodifiableMapView) return _delayMap;
|
||||
@@ -320,16 +318,16 @@ _$AppStateCopyWith<_AppState> get copyWith => __$AppStateCopyWithImpl<_AppState>
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppState&&(identical(other.isInit, isInit) || other.isInit == isInit)&&(identical(other.backBlock, backBlock) || other.backBlock == backBlock)&&(identical(other.pageLabel, pageLabel) || other.pageLabel == pageLabel)&&const DeepCollectionEquality().equals(other._packages, _packages)&&(identical(other.sortNum, sortNum) || other.sortNum == sortNum)&&(identical(other.viewSize, viewSize) || other.viewSize == viewSize)&&(identical(other.sideWidth, sideWidth) || other.sideWidth == sideWidth)&&const DeepCollectionEquality().equals(other._delayMap, _delayMap)&&const DeepCollectionEquality().equals(other._groups, _groups)&&(identical(other.checkIpNum, checkIpNum) || other.checkIpNum == checkIpNum)&&(identical(other.brightness, brightness) || other.brightness == brightness)&&(identical(other.runTime, runTime) || other.runTime == runTime)&&const DeepCollectionEquality().equals(other._providers, _providers)&&(identical(other.localIp, localIp) || other.localIp == localIp)&&(identical(other.requests, requests) || other.requests == requests)&&(identical(other.version, version) || other.version == version)&&(identical(other.logs, logs) || other.logs == logs)&&(identical(other.traffics, traffics) || other.traffics == traffics)&&(identical(other.totalTraffic, totalTraffic) || other.totalTraffic == totalTraffic)&&(identical(other.realTunEnable, realTunEnable) || other.realTunEnable == realTunEnable)&&(identical(other.loading, loading) || other.loading == loading)&&(identical(other.systemUiOverlayStyle, systemUiOverlayStyle) || other.systemUiOverlayStyle == systemUiOverlayStyle)&&(identical(other.profileOverrideModel, profileOverrideModel) || other.profileOverrideModel == profileOverrideModel)&&const DeepCollectionEquality().equals(other._queryMap, _queryMap)&&(identical(other.coreStatus, coreStatus) || other.coreStatus == coreStatus));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppState&&(identical(other.isInit, isInit) || other.isInit == isInit)&&(identical(other.backBlock, backBlock) || other.backBlock == backBlock)&&(identical(other.pageLabel, pageLabel) || other.pageLabel == pageLabel)&&const DeepCollectionEquality().equals(other._packages, _packages)&&(identical(other.sortNum, sortNum) || other.sortNum == sortNum)&&(identical(other.viewSize, viewSize) || other.viewSize == viewSize)&&const DeepCollectionEquality().equals(other._delayMap, _delayMap)&&const DeepCollectionEquality().equals(other._groups, _groups)&&(identical(other.checkIpNum, checkIpNum) || other.checkIpNum == checkIpNum)&&(identical(other.brightness, brightness) || other.brightness == brightness)&&(identical(other.runTime, runTime) || other.runTime == runTime)&&const DeepCollectionEquality().equals(other._providers, _providers)&&(identical(other.localIp, localIp) || other.localIp == localIp)&&(identical(other.requests, requests) || other.requests == requests)&&(identical(other.version, version) || other.version == version)&&(identical(other.logs, logs) || other.logs == logs)&&(identical(other.traffics, traffics) || other.traffics == traffics)&&(identical(other.totalTraffic, totalTraffic) || other.totalTraffic == totalTraffic)&&(identical(other.realTunEnable, realTunEnable) || other.realTunEnable == realTunEnable)&&(identical(other.loading, loading) || other.loading == loading)&&(identical(other.systemUiOverlayStyle, systemUiOverlayStyle) || other.systemUiOverlayStyle == systemUiOverlayStyle)&&(identical(other.profileOverrideModel, profileOverrideModel) || other.profileOverrideModel == profileOverrideModel)&&const DeepCollectionEquality().equals(other._queryMap, _queryMap)&&(identical(other.coreStatus, coreStatus) || other.coreStatus == coreStatus));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,isInit,backBlock,pageLabel,const DeepCollectionEquality().hash(_packages),sortNum,viewSize,sideWidth,const DeepCollectionEquality().hash(_delayMap),const DeepCollectionEquality().hash(_groups),checkIpNum,brightness,runTime,const DeepCollectionEquality().hash(_providers),localIp,requests,version,logs,traffics,totalTraffic,realTunEnable,loading,systemUiOverlayStyle,profileOverrideModel,const DeepCollectionEquality().hash(_queryMap),coreStatus]);
|
||||
int get hashCode => Object.hashAll([runtimeType,isInit,backBlock,pageLabel,const DeepCollectionEquality().hash(_packages),sortNum,viewSize,const DeepCollectionEquality().hash(_delayMap),const DeepCollectionEquality().hash(_groups),checkIpNum,brightness,runTime,const DeepCollectionEquality().hash(_providers),localIp,requests,version,logs,traffics,totalTraffic,realTunEnable,loading,systemUiOverlayStyle,profileOverrideModel,const DeepCollectionEquality().hash(_queryMap),coreStatus]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppState(isInit: $isInit, backBlock: $backBlock, pageLabel: $pageLabel, packages: $packages, sortNum: $sortNum, viewSize: $viewSize, sideWidth: $sideWidth, delayMap: $delayMap, groups: $groups, checkIpNum: $checkIpNum, brightness: $brightness, runTime: $runTime, providers: $providers, localIp: $localIp, requests: $requests, version: $version, logs: $logs, traffics: $traffics, totalTraffic: $totalTraffic, realTunEnable: $realTunEnable, loading: $loading, systemUiOverlayStyle: $systemUiOverlayStyle, profileOverrideModel: $profileOverrideModel, queryMap: $queryMap, coreStatus: $coreStatus)';
|
||||
return 'AppState(isInit: $isInit, backBlock: $backBlock, pageLabel: $pageLabel, packages: $packages, sortNum: $sortNum, viewSize: $viewSize, delayMap: $delayMap, groups: $groups, checkIpNum: $checkIpNum, brightness: $brightness, runTime: $runTime, providers: $providers, localIp: $localIp, requests: $requests, version: $version, logs: $logs, traffics: $traffics, totalTraffic: $totalTraffic, realTunEnable: $realTunEnable, loading: $loading, systemUiOverlayStyle: $systemUiOverlayStyle, profileOverrideModel: $profileOverrideModel, queryMap: $queryMap, coreStatus: $coreStatus)';
|
||||
}
|
||||
|
||||
|
||||
@@ -340,7 +338,7 @@ abstract mixin class _$AppStateCopyWith<$Res> implements $AppStateCopyWith<$Res>
|
||||
factory _$AppStateCopyWith(_AppState value, $Res Function(_AppState) _then) = __$AppStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool isInit, bool backBlock, PageLabel pageLabel, List<Package> packages, int sortNum, Size viewSize, double sideWidth, DelayMap delayMap, List<Group> groups, int checkIpNum, Brightness brightness, int? runTime, List<ExternalProvider> providers, String? localIp, FixedList<TrackerInfo> requests, int version, FixedList<Log> logs, FixedList<Traffic> traffics, Traffic totalTraffic, bool realTunEnable, bool loading, SystemUiOverlayStyle systemUiOverlayStyle, ProfileOverrideModel? profileOverrideModel, Map<QueryTag, String> queryMap, CoreStatus coreStatus
|
||||
bool isInit, bool backBlock, PageLabel pageLabel, List<Package> packages, int sortNum, Size viewSize, DelayMap delayMap, List<Group> groups, int checkIpNum, Brightness brightness, int? runTime, List<ExternalProvider> providers, String? localIp, FixedList<TrackerInfo> requests, int version, FixedList<Log> logs, FixedList<Traffic> traffics, Traffic totalTraffic, bool realTunEnable, bool loading, SystemUiOverlayStyle systemUiOverlayStyle, ProfileOverrideModel? profileOverrideModel, Map<QueryTag, String> queryMap, CoreStatus coreStatus
|
||||
});
|
||||
|
||||
|
||||
@@ -357,7 +355,7 @@ class __$AppStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of AppState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? isInit = null,Object? backBlock = null,Object? pageLabel = null,Object? packages = null,Object? sortNum = null,Object? viewSize = null,Object? sideWidth = null,Object? delayMap = null,Object? groups = null,Object? checkIpNum = null,Object? brightness = null,Object? runTime = freezed,Object? providers = null,Object? localIp = freezed,Object? requests = null,Object? version = null,Object? logs = null,Object? traffics = null,Object? totalTraffic = null,Object? realTunEnable = null,Object? loading = null,Object? systemUiOverlayStyle = null,Object? profileOverrideModel = freezed,Object? queryMap = null,Object? coreStatus = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? isInit = null,Object? backBlock = null,Object? pageLabel = null,Object? packages = null,Object? sortNum = null,Object? viewSize = null,Object? delayMap = null,Object? groups = null,Object? checkIpNum = null,Object? brightness = null,Object? runTime = freezed,Object? providers = null,Object? localIp = freezed,Object? requests = null,Object? version = null,Object? logs = null,Object? traffics = null,Object? totalTraffic = null,Object? realTunEnable = null,Object? loading = null,Object? systemUiOverlayStyle = null,Object? profileOverrideModel = freezed,Object? queryMap = null,Object? coreStatus = null,}) {
|
||||
return _then(_AppState(
|
||||
isInit: null == isInit ? _self.isInit : isInit // ignore: cast_nullable_to_non_nullable
|
||||
as bool,backBlock: null == backBlock ? _self.backBlock : backBlock // ignore: cast_nullable_to_non_nullable
|
||||
@@ -365,8 +363,7 @@ as bool,pageLabel: null == pageLabel ? _self.pageLabel : pageLabel // ignore: ca
|
||||
as PageLabel,packages: null == packages ? _self._packages : packages // ignore: cast_nullable_to_non_nullable
|
||||
as List<Package>,sortNum: null == sortNum ? _self.sortNum : sortNum // ignore: cast_nullable_to_non_nullable
|
||||
as int,viewSize: null == viewSize ? _self.viewSize : viewSize // ignore: cast_nullable_to_non_nullable
|
||||
as Size,sideWidth: null == sideWidth ? _self.sideWidth : sideWidth // ignore: cast_nullable_to_non_nullable
|
||||
as double,delayMap: null == delayMap ? _self._delayMap : delayMap // ignore: cast_nullable_to_non_nullable
|
||||
as Size,delayMap: null == delayMap ? _self._delayMap : delayMap // ignore: cast_nullable_to_non_nullable
|
||||
as DelayMap,groups: null == groups ? _self._groups : groups // ignore: cast_nullable_to_non_nullable
|
||||
as List<Group>,checkIpNum: null == checkIpNum ? _self.checkIpNum : checkIpNum // ignore: cast_nullable_to_non_nullable
|
||||
as int,brightness: null == brightness ? _self.brightness : brightness // ignore: cast_nullable_to_non_nullable
|
||||
|
||||
@@ -3765,7 +3765,7 @@ return $default(_that.mixedPort,_that.socksPort,_that.port,_that.redirPort,_that
|
||||
@JsonSerializable()
|
||||
|
||||
class _ClashConfig implements ClashConfig {
|
||||
const _ClashConfig({@JsonKey(name: 'mixed-port') this.mixedPort = defaultMixedPort, @JsonKey(name: 'socks-port') this.socksPort = 0, @JsonKey(name: 'port') this.port = 0, @JsonKey(name: 'redir-port') this.redirPort = 0, @JsonKey(name: 'tproxy-port') this.tproxyPort = 0, this.mode = Mode.rule, @JsonKey(name: 'allow-lan') this.allowLan = false, @JsonKey(name: 'log-level') this.logLevel = LogLevel.error, this.ipv6 = false, @JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) this.findProcessMode = FindProcessMode.always, @JsonKey(name: 'keep-alive-interval') this.keepAliveInterval = defaultKeepAliveInterval, @JsonKey(name: 'unified-delay') this.unifiedDelay = true, @JsonKey(name: 'tcp-concurrent') this.tcpConcurrent = true, @JsonKey(fromJson: Tun.safeFormJson) this.tun = defaultTun, @JsonKey(fromJson: Dns.safeDnsFromJson) this.dns = defaultDns, @JsonKey(name: 'geox-url', fromJson: GeoXUrl.safeFormJson) this.geoXUrl = defaultGeoXUrl, @JsonKey(name: 'geodata-loader') this.geodataLoader = GeodataLoader.memconservative, @JsonKey(name: 'proxy-groups') final List<ProxyGroup> proxyGroups = const [], final List<String> rule = const [], @JsonKey(name: 'global-ua') this.globalUa, @JsonKey(name: 'external-controller') this.externalController = ExternalControllerStatus.close, final HostsMap hosts = const {}}): _proxyGroups = proxyGroups,_rule = rule,_hosts = hosts;
|
||||
const _ClashConfig({@JsonKey(name: 'mixed-port') this.mixedPort = defaultMixedPort, @JsonKey(name: 'socks-port') this.socksPort = 0, @JsonKey(name: 'port') this.port = 0, @JsonKey(name: 'redir-port') this.redirPort = 0, @JsonKey(name: 'tproxy-port') this.tproxyPort = 0, this.mode = Mode.rule, @JsonKey(name: 'allow-lan') this.allowLan = false, @JsonKey(name: 'log-level') this.logLevel = LogLevel.error, this.ipv6 = false, @JsonKey(name: 'find-process-mode', unknownEnumValue: FindProcessMode.always) this.findProcessMode = FindProcessMode.off, @JsonKey(name: 'keep-alive-interval') this.keepAliveInterval = defaultKeepAliveInterval, @JsonKey(name: 'unified-delay') this.unifiedDelay = true, @JsonKey(name: 'tcp-concurrent') this.tcpConcurrent = true, @JsonKey(fromJson: Tun.safeFormJson) this.tun = defaultTun, @JsonKey(fromJson: Dns.safeDnsFromJson) this.dns = defaultDns, @JsonKey(name: 'geox-url', fromJson: GeoXUrl.safeFormJson) this.geoXUrl = defaultGeoXUrl, @JsonKey(name: 'geodata-loader') this.geodataLoader = GeodataLoader.memconservative, @JsonKey(name: 'proxy-groups') final List<ProxyGroup> proxyGroups = const [], final List<String> rule = const [], @JsonKey(name: 'global-ua') this.globalUa, @JsonKey(name: 'external-controller') this.externalController = ExternalControllerStatus.close, final HostsMap hosts = const {}}): _proxyGroups = proxyGroups,_rule = rule,_hosts = hosts;
|
||||
factory _ClashConfig.fromJson(Map<String, dynamic> json) => _$ClashConfigFromJson(json);
|
||||
|
||||
@override@JsonKey(name: 'mixed-port') final int mixedPort;
|
||||
|
||||
@@ -342,7 +342,7 @@ _ClashConfig _$ClashConfigFromJson(Map<String, dynamic> json) => _ClashConfig(
|
||||
json['find-process-mode'],
|
||||
unknownValue: FindProcessMode.always,
|
||||
) ??
|
||||
FindProcessMode.always,
|
||||
FindProcessMode.off,
|
||||
keepAliveInterval:
|
||||
(json['keep-alive-interval'] as num?)?.toInt() ??
|
||||
defaultKeepAliveInterval,
|
||||
|
||||
@@ -5768,266 +5768,6 @@ 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
|
||||
|
||||
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$SetupParams {
|
||||
|
||||
@JsonKey(name: 'selected-map') Map<String, String> get selectedMap;@JsonKey(name: 'test-url') String get testUrl;
|
||||
@JsonKey(name: 'config') Map<String, dynamic> get config;@JsonKey(name: 'selected-map') Map<String, String> get selectedMap;@JsonKey(name: 'test-url') String get testUrl;
|
||||
/// Create a copy of SetupParams
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -28,16 +28,16 @@ $SetupParamsCopyWith<SetupParams> get copyWith => _$SetupParamsCopyWithImpl<Setu
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SetupParams&&const DeepCollectionEquality().equals(other.selectedMap, selectedMap)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SetupParams&&const DeepCollectionEquality().equals(other.config, config)&&const DeepCollectionEquality().equals(other.selectedMap, selectedMap)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(selectedMap),testUrl);
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(config),const DeepCollectionEquality().hash(selectedMap),testUrl);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SetupParams(selectedMap: $selectedMap, testUrl: $testUrl)';
|
||||
return 'SetupParams(config: $config, selectedMap: $selectedMap, testUrl: $testUrl)';
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ abstract mixin class $SetupParamsCopyWith<$Res> {
|
||||
factory $SetupParamsCopyWith(SetupParams value, $Res Function(SetupParams) _then) = _$SetupParamsCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
@JsonKey(name: 'selected-map') Map<String, String> selectedMap,@JsonKey(name: 'test-url') String testUrl
|
||||
@JsonKey(name: 'config') Map<String, dynamic> config,@JsonKey(name: 'selected-map') Map<String, String> selectedMap,@JsonKey(name: 'test-url') String testUrl
|
||||
});
|
||||
|
||||
|
||||
@@ -65,9 +65,10 @@ class _$SetupParamsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SetupParams
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? selectedMap = null,Object? testUrl = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? config = null,Object? selectedMap = null,Object? testUrl = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
selectedMap: null == selectedMap ? _self.selectedMap : selectedMap // ignore: cast_nullable_to_non_nullable
|
||||
config: null == config ? _self.config : config // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>,selectedMap: null == selectedMap ? _self.selectedMap : selectedMap // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, String>,testUrl: null == testUrl ? _self.testUrl : testUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
@@ -154,10 +155,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@JsonKey(name: 'selected-map') Map<String, String> selectedMap, @JsonKey(name: 'test-url') String testUrl)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@JsonKey(name: 'config') Map<String, dynamic> config, @JsonKey(name: 'selected-map') Map<String, String> selectedMap, @JsonKey(name: 'test-url') String testUrl)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SetupParams() when $default != null:
|
||||
return $default(_that.selectedMap,_that.testUrl);case _:
|
||||
return $default(_that.config,_that.selectedMap,_that.testUrl);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -175,10 +176,10 @@ return $default(_that.selectedMap,_that.testUrl);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@JsonKey(name: 'selected-map') Map<String, String> selectedMap, @JsonKey(name: 'test-url') String testUrl) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@JsonKey(name: 'config') Map<String, dynamic> config, @JsonKey(name: 'selected-map') Map<String, String> selectedMap, @JsonKey(name: 'test-url') String testUrl) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SetupParams():
|
||||
return $default(_that.selectedMap,_that.testUrl);case _:
|
||||
return $default(_that.config,_that.selectedMap,_that.testUrl);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -195,10 +196,10 @@ return $default(_that.selectedMap,_that.testUrl);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@JsonKey(name: 'selected-map') Map<String, String> selectedMap, @JsonKey(name: 'test-url') String testUrl)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@JsonKey(name: 'config') Map<String, dynamic> config, @JsonKey(name: 'selected-map') Map<String, String> selectedMap, @JsonKey(name: 'test-url') String testUrl)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SetupParams() when $default != null:
|
||||
return $default(_that.selectedMap,_that.testUrl);case _:
|
||||
return $default(_that.config,_that.selectedMap,_that.testUrl);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -210,9 +211,16 @@ return $default(_that.selectedMap,_that.testUrl);case _:
|
||||
@JsonSerializable()
|
||||
|
||||
class _SetupParams implements SetupParams {
|
||||
const _SetupParams({@JsonKey(name: 'selected-map') required final Map<String, String> selectedMap, @JsonKey(name: 'test-url') required this.testUrl}): _selectedMap = selectedMap;
|
||||
const _SetupParams({@JsonKey(name: 'config') required final Map<String, dynamic> config, @JsonKey(name: 'selected-map') required final Map<String, String> selectedMap, @JsonKey(name: 'test-url') required this.testUrl}): _config = config,_selectedMap = selectedMap;
|
||||
factory _SetupParams.fromJson(Map<String, dynamic> json) => _$SetupParamsFromJson(json);
|
||||
|
||||
final Map<String, dynamic> _config;
|
||||
@override@JsonKey(name: 'config') Map<String, dynamic> get config {
|
||||
if (_config is EqualUnmodifiableMapView) return _config;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_config);
|
||||
}
|
||||
|
||||
final Map<String, String> _selectedMap;
|
||||
@override@JsonKey(name: 'selected-map') Map<String, String> get selectedMap {
|
||||
if (_selectedMap is EqualUnmodifiableMapView) return _selectedMap;
|
||||
@@ -235,16 +243,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SetupParams&&const DeepCollectionEquality().equals(other._selectedMap, _selectedMap)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SetupParams&&const DeepCollectionEquality().equals(other._config, _config)&&const DeepCollectionEquality().equals(other._selectedMap, _selectedMap)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_selectedMap),testUrl);
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_config),const DeepCollectionEquality().hash(_selectedMap),testUrl);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SetupParams(selectedMap: $selectedMap, testUrl: $testUrl)';
|
||||
return 'SetupParams(config: $config, selectedMap: $selectedMap, testUrl: $testUrl)';
|
||||
}
|
||||
|
||||
|
||||
@@ -255,7 +263,7 @@ abstract mixin class _$SetupParamsCopyWith<$Res> implements $SetupParamsCopyWith
|
||||
factory _$SetupParamsCopyWith(_SetupParams value, $Res Function(_SetupParams) _then) = __$SetupParamsCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
@JsonKey(name: 'selected-map') Map<String, String> selectedMap,@JsonKey(name: 'test-url') String testUrl
|
||||
@JsonKey(name: 'config') Map<String, dynamic> config,@JsonKey(name: 'selected-map') Map<String, String> selectedMap,@JsonKey(name: 'test-url') String testUrl
|
||||
});
|
||||
|
||||
|
||||
@@ -272,9 +280,10 @@ class __$SetupParamsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SetupParams
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? selectedMap = null,Object? testUrl = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? config = null,Object? selectedMap = null,Object? testUrl = null,}) {
|
||||
return _then(_SetupParams(
|
||||
selectedMap: null == selectedMap ? _self._selectedMap : selectedMap // ignore: cast_nullable_to_non_nullable
|
||||
config: null == config ? _self._config : config // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>,selectedMap: null == selectedMap ? _self._selectedMap : selectedMap // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, String>,testUrl: null == testUrl ? _self.testUrl : testUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
@@ -595,7 +604,7 @@ $TunCopyWith<$Res> get tun {
|
||||
/// @nodoc
|
||||
mixin _$VpnOptions {
|
||||
|
||||
bool get enable; int get port; bool get ipv6; bool get dnsHijacking; AccessControl get accessControl; bool get allowBypass; bool get systemProxy; List<String> get bypassDomain; String get stack; List<String> get routeAddress;
|
||||
bool get enable; int get port; bool get ipv6; bool get dnsHijacking; AccessControl get accessControl; bool get allowBypass; bool get systemProxy; List<String> get bypassDomain; List<String> get routeAddress;
|
||||
/// Create a copy of VpnOptions
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -608,16 +617,16 @@ $VpnOptionsCopyWith<VpnOptions> get copyWith => _$VpnOptionsCopyWithImpl<VpnOpti
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is VpnOptions&&(identical(other.enable, enable) || other.enable == enable)&&(identical(other.port, port) || other.port == port)&&(identical(other.ipv6, ipv6) || other.ipv6 == ipv6)&&(identical(other.dnsHijacking, dnsHijacking) || other.dnsHijacking == dnsHijacking)&&(identical(other.accessControl, accessControl) || other.accessControl == accessControl)&&(identical(other.allowBypass, allowBypass) || other.allowBypass == allowBypass)&&(identical(other.systemProxy, systemProxy) || other.systemProxy == systemProxy)&&const DeepCollectionEquality().equals(other.bypassDomain, bypassDomain)&&(identical(other.stack, stack) || other.stack == stack)&&const DeepCollectionEquality().equals(other.routeAddress, routeAddress));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is VpnOptions&&(identical(other.enable, enable) || other.enable == enable)&&(identical(other.port, port) || other.port == port)&&(identical(other.ipv6, ipv6) || other.ipv6 == ipv6)&&(identical(other.dnsHijacking, dnsHijacking) || other.dnsHijacking == dnsHijacking)&&(identical(other.accessControl, accessControl) || other.accessControl == accessControl)&&(identical(other.allowBypass, allowBypass) || other.allowBypass == allowBypass)&&(identical(other.systemProxy, systemProxy) || other.systemProxy == systemProxy)&&const DeepCollectionEquality().equals(other.bypassDomain, bypassDomain)&&const DeepCollectionEquality().equals(other.routeAddress, routeAddress));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,enable,port,ipv6,dnsHijacking,accessControl,allowBypass,systemProxy,const DeepCollectionEquality().hash(bypassDomain),stack,const DeepCollectionEquality().hash(routeAddress));
|
||||
int get hashCode => Object.hash(runtimeType,enable,port,ipv6,dnsHijacking,accessControl,allowBypass,systemProxy,const DeepCollectionEquality().hash(bypassDomain),const DeepCollectionEquality().hash(routeAddress));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'VpnOptions(enable: $enable, port: $port, ipv6: $ipv6, dnsHijacking: $dnsHijacking, accessControl: $accessControl, allowBypass: $allowBypass, systemProxy: $systemProxy, bypassDomain: $bypassDomain, stack: $stack, routeAddress: $routeAddress)';
|
||||
return 'VpnOptions(enable: $enable, port: $port, ipv6: $ipv6, dnsHijacking: $dnsHijacking, accessControl: $accessControl, allowBypass: $allowBypass, systemProxy: $systemProxy, bypassDomain: $bypassDomain, routeAddress: $routeAddress)';
|
||||
}
|
||||
|
||||
|
||||
@@ -628,7 +637,7 @@ abstract mixin class $VpnOptionsCopyWith<$Res> {
|
||||
factory $VpnOptionsCopyWith(VpnOptions value, $Res Function(VpnOptions) _then) = _$VpnOptionsCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool enable, int port, bool ipv6, bool dnsHijacking, AccessControl accessControl, bool allowBypass, bool systemProxy, List<String> bypassDomain, String stack, List<String> routeAddress
|
||||
bool enable, int port, bool ipv6, bool dnsHijacking, AccessControl accessControl, bool allowBypass, bool systemProxy, List<String> bypassDomain, List<String> routeAddress
|
||||
});
|
||||
|
||||
|
||||
@@ -645,7 +654,7 @@ class _$VpnOptionsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of VpnOptions
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? enable = null,Object? port = null,Object? ipv6 = null,Object? dnsHijacking = null,Object? accessControl = null,Object? allowBypass = null,Object? systemProxy = null,Object? bypassDomain = null,Object? stack = null,Object? routeAddress = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? enable = null,Object? port = null,Object? ipv6 = null,Object? dnsHijacking = null,Object? accessControl = null,Object? allowBypass = null,Object? systemProxy = null,Object? bypassDomain = null,Object? routeAddress = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
enable: null == enable ? _self.enable : enable // ignore: cast_nullable_to_non_nullable
|
||||
as bool,port: null == port ? _self.port : port // ignore: cast_nullable_to_non_nullable
|
||||
@@ -655,8 +664,7 @@ as bool,accessControl: null == accessControl ? _self.accessControl : accessContr
|
||||
as AccessControl,allowBypass: null == allowBypass ? _self.allowBypass : allowBypass // ignore: cast_nullable_to_non_nullable
|
||||
as bool,systemProxy: null == systemProxy ? _self.systemProxy : systemProxy // ignore: cast_nullable_to_non_nullable
|
||||
as bool,bypassDomain: null == bypassDomain ? _self.bypassDomain : bypassDomain // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,stack: null == stack ? _self.stack : stack // ignore: cast_nullable_to_non_nullable
|
||||
as String,routeAddress: null == routeAddress ? _self.routeAddress : routeAddress // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,routeAddress: null == routeAddress ? _self.routeAddress : routeAddress // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,
|
||||
));
|
||||
}
|
||||
@@ -751,10 +759,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool enable, int port, bool ipv6, bool dnsHijacking, AccessControl accessControl, bool allowBypass, bool systemProxy, List<String> bypassDomain, String stack, List<String> routeAddress)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool enable, int port, bool ipv6, bool dnsHijacking, AccessControl accessControl, bool allowBypass, bool systemProxy, List<String> bypassDomain, List<String> routeAddress)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _VpnOptions() when $default != null:
|
||||
return $default(_that.enable,_that.port,_that.ipv6,_that.dnsHijacking,_that.accessControl,_that.allowBypass,_that.systemProxy,_that.bypassDomain,_that.stack,_that.routeAddress);case _:
|
||||
return $default(_that.enable,_that.port,_that.ipv6,_that.dnsHijacking,_that.accessControl,_that.allowBypass,_that.systemProxy,_that.bypassDomain,_that.routeAddress);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -772,10 +780,10 @@ return $default(_that.enable,_that.port,_that.ipv6,_that.dnsHijacking,_that.acce
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool enable, int port, bool ipv6, bool dnsHijacking, AccessControl accessControl, bool allowBypass, bool systemProxy, List<String> bypassDomain, String stack, List<String> routeAddress) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool enable, int port, bool ipv6, bool dnsHijacking, AccessControl accessControl, bool allowBypass, bool systemProxy, List<String> bypassDomain, List<String> routeAddress) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _VpnOptions():
|
||||
return $default(_that.enable,_that.port,_that.ipv6,_that.dnsHijacking,_that.accessControl,_that.allowBypass,_that.systemProxy,_that.bypassDomain,_that.stack,_that.routeAddress);case _:
|
||||
return $default(_that.enable,_that.port,_that.ipv6,_that.dnsHijacking,_that.accessControl,_that.allowBypass,_that.systemProxy,_that.bypassDomain,_that.routeAddress);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -792,10 +800,10 @@ return $default(_that.enable,_that.port,_that.ipv6,_that.dnsHijacking,_that.acce
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool enable, int port, bool ipv6, bool dnsHijacking, AccessControl accessControl, bool allowBypass, bool systemProxy, List<String> bypassDomain, String stack, List<String> routeAddress)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool enable, int port, bool ipv6, bool dnsHijacking, AccessControl accessControl, bool allowBypass, bool systemProxy, List<String> bypassDomain, List<String> routeAddress)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _VpnOptions() when $default != null:
|
||||
return $default(_that.enable,_that.port,_that.ipv6,_that.dnsHijacking,_that.accessControl,_that.allowBypass,_that.systemProxy,_that.bypassDomain,_that.stack,_that.routeAddress);case _:
|
||||
return $default(_that.enable,_that.port,_that.ipv6,_that.dnsHijacking,_that.accessControl,_that.allowBypass,_that.systemProxy,_that.bypassDomain,_that.routeAddress);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -807,7 +815,7 @@ return $default(_that.enable,_that.port,_that.ipv6,_that.dnsHijacking,_that.acce
|
||||
@JsonSerializable()
|
||||
|
||||
class _VpnOptions implements VpnOptions {
|
||||
const _VpnOptions({required this.enable, required this.port, required this.ipv6, required this.dnsHijacking, required this.accessControl, required this.allowBypass, required this.systemProxy, required final List<String> bypassDomain, required this.stack, final List<String> routeAddress = const []}): _bypassDomain = bypassDomain,_routeAddress = routeAddress;
|
||||
const _VpnOptions({required this.enable, required this.port, required this.ipv6, required this.dnsHijacking, required this.accessControl, required this.allowBypass, required this.systemProxy, required final List<String> bypassDomain, final List<String> routeAddress = const []}): _bypassDomain = bypassDomain,_routeAddress = routeAddress;
|
||||
factory _VpnOptions.fromJson(Map<String, dynamic> json) => _$VpnOptionsFromJson(json);
|
||||
|
||||
@override final bool enable;
|
||||
@@ -824,7 +832,6 @@ class _VpnOptions implements VpnOptions {
|
||||
return EqualUnmodifiableListView(_bypassDomain);
|
||||
}
|
||||
|
||||
@override final String stack;
|
||||
final List<String> _routeAddress;
|
||||
@override@JsonKey() List<String> get routeAddress {
|
||||
if (_routeAddress is EqualUnmodifiableListView) return _routeAddress;
|
||||
@@ -846,16 +853,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _VpnOptions&&(identical(other.enable, enable) || other.enable == enable)&&(identical(other.port, port) || other.port == port)&&(identical(other.ipv6, ipv6) || other.ipv6 == ipv6)&&(identical(other.dnsHijacking, dnsHijacking) || other.dnsHijacking == dnsHijacking)&&(identical(other.accessControl, accessControl) || other.accessControl == accessControl)&&(identical(other.allowBypass, allowBypass) || other.allowBypass == allowBypass)&&(identical(other.systemProxy, systemProxy) || other.systemProxy == systemProxy)&&const DeepCollectionEquality().equals(other._bypassDomain, _bypassDomain)&&(identical(other.stack, stack) || other.stack == stack)&&const DeepCollectionEquality().equals(other._routeAddress, _routeAddress));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _VpnOptions&&(identical(other.enable, enable) || other.enable == enable)&&(identical(other.port, port) || other.port == port)&&(identical(other.ipv6, ipv6) || other.ipv6 == ipv6)&&(identical(other.dnsHijacking, dnsHijacking) || other.dnsHijacking == dnsHijacking)&&(identical(other.accessControl, accessControl) || other.accessControl == accessControl)&&(identical(other.allowBypass, allowBypass) || other.allowBypass == allowBypass)&&(identical(other.systemProxy, systemProxy) || other.systemProxy == systemProxy)&&const DeepCollectionEquality().equals(other._bypassDomain, _bypassDomain)&&const DeepCollectionEquality().equals(other._routeAddress, _routeAddress));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,enable,port,ipv6,dnsHijacking,accessControl,allowBypass,systemProxy,const DeepCollectionEquality().hash(_bypassDomain),stack,const DeepCollectionEquality().hash(_routeAddress));
|
||||
int get hashCode => Object.hash(runtimeType,enable,port,ipv6,dnsHijacking,accessControl,allowBypass,systemProxy,const DeepCollectionEquality().hash(_bypassDomain),const DeepCollectionEquality().hash(_routeAddress));
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'VpnOptions(enable: $enable, port: $port, ipv6: $ipv6, dnsHijacking: $dnsHijacking, accessControl: $accessControl, allowBypass: $allowBypass, systemProxy: $systemProxy, bypassDomain: $bypassDomain, stack: $stack, routeAddress: $routeAddress)';
|
||||
return 'VpnOptions(enable: $enable, port: $port, ipv6: $ipv6, dnsHijacking: $dnsHijacking, accessControl: $accessControl, allowBypass: $allowBypass, systemProxy: $systemProxy, bypassDomain: $bypassDomain, routeAddress: $routeAddress)';
|
||||
}
|
||||
|
||||
|
||||
@@ -866,7 +873,7 @@ abstract mixin class _$VpnOptionsCopyWith<$Res> implements $VpnOptionsCopyWith<$
|
||||
factory _$VpnOptionsCopyWith(_VpnOptions value, $Res Function(_VpnOptions) _then) = __$VpnOptionsCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
bool enable, int port, bool ipv6, bool dnsHijacking, AccessControl accessControl, bool allowBypass, bool systemProxy, List<String> bypassDomain, String stack, List<String> routeAddress
|
||||
bool enable, int port, bool ipv6, bool dnsHijacking, AccessControl accessControl, bool allowBypass, bool systemProxy, List<String> bypassDomain, List<String> routeAddress
|
||||
});
|
||||
|
||||
|
||||
@@ -883,7 +890,7 @@ class __$VpnOptionsCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of VpnOptions
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? enable = null,Object? port = null,Object? ipv6 = null,Object? dnsHijacking = null,Object? accessControl = null,Object? allowBypass = null,Object? systemProxy = null,Object? bypassDomain = null,Object? stack = null,Object? routeAddress = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? enable = null,Object? port = null,Object? ipv6 = null,Object? dnsHijacking = null,Object? accessControl = null,Object? allowBypass = null,Object? systemProxy = null,Object? bypassDomain = null,Object? routeAddress = null,}) {
|
||||
return _then(_VpnOptions(
|
||||
enable: null == enable ? _self.enable : enable // ignore: cast_nullable_to_non_nullable
|
||||
as bool,port: null == port ? _self.port : port // ignore: cast_nullable_to_non_nullable
|
||||
@@ -893,8 +900,7 @@ as bool,accessControl: null == accessControl ? _self.accessControl : accessContr
|
||||
as AccessControl,allowBypass: null == allowBypass ? _self.allowBypass : allowBypass // ignore: cast_nullable_to_non_nullable
|
||||
as bool,systemProxy: null == systemProxy ? _self.systemProxy : systemProxy // ignore: cast_nullable_to_non_nullable
|
||||
as bool,bypassDomain: null == bypassDomain ? _self._bypassDomain : bypassDomain // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,stack: null == stack ? _self.stack : stack // ignore: cast_nullable_to_non_nullable
|
||||
as String,routeAddress: null == routeAddress ? _self._routeAddress : routeAddress // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,routeAddress: null == routeAddress ? _self._routeAddress : routeAddress // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -7,12 +7,14 @@ part of '../core.dart';
|
||||
// **************************************************************************
|
||||
|
||||
_SetupParams _$SetupParamsFromJson(Map<String, dynamic> json) => _SetupParams(
|
||||
config: json['config'] as Map<String, dynamic>,
|
||||
selectedMap: Map<String, String>.from(json['selected-map'] as Map),
|
||||
testUrl: json['test-url'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SetupParamsToJson(_SetupParams instance) =>
|
||||
<String, dynamic>{
|
||||
'config': instance.config,
|
||||
'selected-map': instance.selectedMap,
|
||||
'test-url': instance.testUrl,
|
||||
};
|
||||
@@ -89,7 +91,6 @@ _VpnOptions _$VpnOptionsFromJson(Map<String, dynamic> json) => _VpnOptions(
|
||||
bypassDomain: (json['bypassDomain'] as List<dynamic>)
|
||||
.map((e) => e as String)
|
||||
.toList(),
|
||||
stack: json['stack'] as String,
|
||||
routeAddress:
|
||||
(json['routeAddress'] as List<dynamic>?)
|
||||
?.map((e) => e as String)
|
||||
@@ -107,7 +108,6 @@ Map<String, dynamic> _$VpnOptionsToJson(_VpnOptions instance) =>
|
||||
'allowBypass': instance.allowBypass,
|
||||
'systemProxy': instance.systemProxy,
|
||||
'bypassDomain': instance.bypassDomain,
|
||||
'stack': instance.stack,
|
||||
'routeAddress': instance.routeAddress,
|
||||
};
|
||||
|
||||
@@ -291,7 +291,6 @@ 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; ProxyCardType get proxyCardType; int get columns;
|
||||
List<Group> get groups; Set<String> get currentUnfoldSet; ProxiesSortType get proxiesSortType; ProxyCardType get proxyCardType; num get sortNum; 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.proxyCardType, proxyCardType) || other.proxyCardType == proxyCardType)&&(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.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));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(groups),const DeepCollectionEquality().hash(currentUnfoldSet),proxyCardType,columns);
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(groups),const DeepCollectionEquality().hash(currentUnfoldSet),proxiesSortType,proxyCardType,sortNum,columns);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxiesListState(groups: $groups, currentUnfoldSet: $currentUnfoldSet, proxyCardType: $proxyCardType, columns: $columns)';
|
||||
return 'ProxiesListState(groups: $groups, currentUnfoldSet: $currentUnfoldSet, proxiesSortType: $proxiesSortType, proxyCardType: $proxyCardType, sortNum: $sortNum, 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, ProxyCardType proxyCardType, int columns
|
||||
List<Group> groups, Set<String> currentUnfoldSet, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns
|
||||
});
|
||||
|
||||
|
||||
@@ -3030,12 +3030,14 @@ 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? proxyCardType = null,Object? columns = null,}) {
|
||||
@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,}) {
|
||||
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>,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 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 int,
|
||||
));
|
||||
}
|
||||
@@ -3121,10 +3123,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@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;
|
||||
@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;
|
||||
switch (_that) {
|
||||
case _ProxiesListState() when $default != null:
|
||||
return $default(_that.groups,_that.currentUnfoldSet,_that.proxyCardType,_that.columns);case _:
|
||||
return $default(_that.groups,_that.currentUnfoldSet,_that.proxiesSortType,_that.proxyCardType,_that.sortNum,_that.columns);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -3142,10 +3144,10 @@ return $default(_that.groups,_that.currentUnfoldSet,_that.proxyCardType,_that.co
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<Group> groups, Set<String> currentUnfoldSet, ProxyCardType proxyCardType, int columns) $default,) {final _that = this;
|
||||
@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;
|
||||
switch (_that) {
|
||||
case _ProxiesListState():
|
||||
return $default(_that.groups,_that.currentUnfoldSet,_that.proxyCardType,_that.columns);case _:
|
||||
return $default(_that.groups,_that.currentUnfoldSet,_that.proxiesSortType,_that.proxyCardType,_that.sortNum,_that.columns);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -3162,10 +3164,10 @@ return $default(_that.groups,_that.currentUnfoldSet,_that.proxyCardType,_that.co
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<Group> groups, Set<String> currentUnfoldSet, ProxyCardType proxyCardType, int columns)? $default,) {final _that = this;
|
||||
@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;
|
||||
switch (_that) {
|
||||
case _ProxiesListState() when $default != null:
|
||||
return $default(_that.groups,_that.currentUnfoldSet,_that.proxyCardType,_that.columns);case _:
|
||||
return $default(_that.groups,_that.currentUnfoldSet,_that.proxiesSortType,_that.proxyCardType,_that.sortNum,_that.columns);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -3177,7 +3179,7 @@ return $default(_that.groups,_that.currentUnfoldSet,_that.proxyCardType,_that.co
|
||||
|
||||
|
||||
class _ProxiesListState implements ProxiesListState {
|
||||
const _ProxiesListState({required final List<Group> groups, required final Set<String> currentUnfoldSet, required this.proxyCardType, required this.columns}): _groups = groups,_currentUnfoldSet = currentUnfoldSet;
|
||||
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;
|
||||
|
||||
|
||||
final List<Group> _groups;
|
||||
@@ -3194,7 +3196,9 @@ 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
|
||||
@@ -3207,16 +3211,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.proxyCardType, proxyCardType) || other.proxyCardType == proxyCardType)&&(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.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));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_groups),const DeepCollectionEquality().hash(_currentUnfoldSet),proxyCardType,columns);
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_groups),const DeepCollectionEquality().hash(_currentUnfoldSet),proxiesSortType,proxyCardType,sortNum,columns);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxiesListState(groups: $groups, currentUnfoldSet: $currentUnfoldSet, proxyCardType: $proxyCardType, columns: $columns)';
|
||||
return 'ProxiesListState(groups: $groups, currentUnfoldSet: $currentUnfoldSet, proxiesSortType: $proxiesSortType, proxyCardType: $proxyCardType, sortNum: $sortNum, columns: $columns)';
|
||||
}
|
||||
|
||||
|
||||
@@ -3227,7 +3231,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, ProxyCardType proxyCardType, int columns
|
||||
List<Group> groups, Set<String> currentUnfoldSet, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns
|
||||
});
|
||||
|
||||
|
||||
@@ -3244,12 +3248,14 @@ 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? proxyCardType = null,Object? columns = null,}) {
|
||||
@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,}) {
|
||||
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>,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 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 int,
|
||||
));
|
||||
}
|
||||
@@ -3260,7 +3266,7 @@ as int,
|
||||
/// @nodoc
|
||||
mixin _$ProxiesTabState {
|
||||
|
||||
List<Group> get groups; String? get currentGroupName; ProxyCardType get proxyCardType; int get columns;
|
||||
List<Group> get groups; String? get currentGroupName; ProxiesSortType get proxiesSortType; ProxyCardType get proxyCardType; num get sortNum; int get columns;
|
||||
/// Create a copy of ProxiesTabState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -3271,16 +3277,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.proxyCardType, proxyCardType) || other.proxyCardType == proxyCardType)&&(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.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));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(groups),currentGroupName,proxyCardType,columns);
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(groups),currentGroupName,proxiesSortType,proxyCardType,sortNum,columns);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxiesTabState(groups: $groups, currentGroupName: $currentGroupName, proxyCardType: $proxyCardType, columns: $columns)';
|
||||
return 'ProxiesTabState(groups: $groups, currentGroupName: $currentGroupName, proxiesSortType: $proxiesSortType, proxyCardType: $proxyCardType, sortNum: $sortNum, columns: $columns)';
|
||||
}
|
||||
|
||||
|
||||
@@ -3291,7 +3297,7 @@ abstract mixin class $ProxiesTabStateCopyWith<$Res> {
|
||||
factory $ProxiesTabStateCopyWith(ProxiesTabState value, $Res Function(ProxiesTabState) _then) = _$ProxiesTabStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
List<Group> groups, String? currentGroupName, ProxyCardType proxyCardType, int columns
|
||||
List<Group> groups, String? currentGroupName, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns
|
||||
});
|
||||
|
||||
|
||||
@@ -3308,12 +3314,14 @@ 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? proxyCardType = null,Object? columns = null,}) {
|
||||
@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,}) {
|
||||
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?,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 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 int,
|
||||
));
|
||||
}
|
||||
@@ -3399,10 +3407,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<Group> groups, String? currentGroupName, ProxyCardType proxyCardType, int columns)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@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;
|
||||
switch (_that) {
|
||||
case _ProxiesTabState() when $default != null:
|
||||
return $default(_that.groups,_that.currentGroupName,_that.proxyCardType,_that.columns);case _:
|
||||
return $default(_that.groups,_that.currentGroupName,_that.proxiesSortType,_that.proxyCardType,_that.sortNum,_that.columns);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -3420,10 +3428,10 @@ return $default(_that.groups,_that.currentGroupName,_that.proxyCardType,_that.co
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<Group> groups, String? currentGroupName, ProxyCardType proxyCardType, int columns) $default,) {final _that = this;
|
||||
@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;
|
||||
switch (_that) {
|
||||
case _ProxiesTabState():
|
||||
return $default(_that.groups,_that.currentGroupName,_that.proxyCardType,_that.columns);case _:
|
||||
return $default(_that.groups,_that.currentGroupName,_that.proxiesSortType,_that.proxyCardType,_that.sortNum,_that.columns);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -3440,10 +3448,10 @@ return $default(_that.groups,_that.currentGroupName,_that.proxyCardType,_that.co
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<Group> groups, String? currentGroupName, ProxyCardType proxyCardType, int columns)? $default,) {final _that = this;
|
||||
@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;
|
||||
switch (_that) {
|
||||
case _ProxiesTabState() when $default != null:
|
||||
return $default(_that.groups,_that.currentGroupName,_that.proxyCardType,_that.columns);case _:
|
||||
return $default(_that.groups,_that.currentGroupName,_that.proxiesSortType,_that.proxyCardType,_that.sortNum,_that.columns);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -3455,7 +3463,7 @@ return $default(_that.groups,_that.currentGroupName,_that.proxyCardType,_that.co
|
||||
|
||||
|
||||
class _ProxiesTabState implements ProxiesTabState {
|
||||
const _ProxiesTabState({required final List<Group> groups, required this.currentGroupName, required this.proxyCardType, required this.columns}): _groups = groups;
|
||||
const _ProxiesTabState({required final List<Group> groups, required this.currentGroupName, required this.proxiesSortType, required this.proxyCardType, required this.sortNum, required this.columns}): _groups = groups;
|
||||
|
||||
|
||||
final List<Group> _groups;
|
||||
@@ -3466,7 +3474,9 @@ 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
|
||||
@@ -3479,16 +3489,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.proxyCardType, proxyCardType) || other.proxyCardType == proxyCardType)&&(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.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));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_groups),currentGroupName,proxyCardType,columns);
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_groups),currentGroupName,proxiesSortType,proxyCardType,sortNum,columns);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ProxiesTabState(groups: $groups, currentGroupName: $currentGroupName, proxyCardType: $proxyCardType, columns: $columns)';
|
||||
return 'ProxiesTabState(groups: $groups, currentGroupName: $currentGroupName, proxiesSortType: $proxiesSortType, proxyCardType: $proxyCardType, sortNum: $sortNum, columns: $columns)';
|
||||
}
|
||||
|
||||
|
||||
@@ -3499,7 +3509,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, ProxyCardType proxyCardType, int columns
|
||||
List<Group> groups, String? currentGroupName, ProxiesSortType proxiesSortType, ProxyCardType proxyCardType, num sortNum, int columns
|
||||
});
|
||||
|
||||
|
||||
@@ -3516,12 +3526,14 @@ 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? proxyCardType = null,Object? columns = null,}) {
|
||||
@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,}) {
|
||||
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?,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 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 int,
|
||||
));
|
||||
}
|
||||
@@ -5457,7 +5469,7 @@ $OverrideDataCopyWith<$Res> get overrideData {
|
||||
/// @nodoc
|
||||
mixin _$DashboardState {
|
||||
|
||||
List<DashboardWidget> get dashboardWidgets; double get contentWidth;
|
||||
List<DashboardWidget> get dashboardWidgets; double get viewWidth;
|
||||
/// Create a copy of DashboardState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -5468,16 +5480,16 @@ $DashboardStateCopyWith<DashboardState> get copyWith => _$DashboardStateCopyWith
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is DashboardState&&const DeepCollectionEquality().equals(other.dashboardWidgets, dashboardWidgets)&&(identical(other.contentWidth, contentWidth) || other.contentWidth == contentWidth));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is DashboardState&&const DeepCollectionEquality().equals(other.dashboardWidgets, dashboardWidgets)&&(identical(other.viewWidth, viewWidth) || other.viewWidth == viewWidth));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(dashboardWidgets),contentWidth);
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(dashboardWidgets),viewWidth);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DashboardState(dashboardWidgets: $dashboardWidgets, contentWidth: $contentWidth)';
|
||||
return 'DashboardState(dashboardWidgets: $dashboardWidgets, viewWidth: $viewWidth)';
|
||||
}
|
||||
|
||||
|
||||
@@ -5488,7 +5500,7 @@ abstract mixin class $DashboardStateCopyWith<$Res> {
|
||||
factory $DashboardStateCopyWith(DashboardState value, $Res Function(DashboardState) _then) = _$DashboardStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
List<DashboardWidget> dashboardWidgets, double contentWidth
|
||||
List<DashboardWidget> dashboardWidgets, double viewWidth
|
||||
});
|
||||
|
||||
|
||||
@@ -5505,10 +5517,10 @@ class _$DashboardStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of DashboardState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? dashboardWidgets = null,Object? contentWidth = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? dashboardWidgets = null,Object? viewWidth = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
dashboardWidgets: null == dashboardWidgets ? _self.dashboardWidgets : dashboardWidgets // ignore: cast_nullable_to_non_nullable
|
||||
as List<DashboardWidget>,contentWidth: null == contentWidth ? _self.contentWidth : contentWidth // ignore: cast_nullable_to_non_nullable
|
||||
as List<DashboardWidget>,viewWidth: null == viewWidth ? _self.viewWidth : viewWidth // ignore: cast_nullable_to_non_nullable
|
||||
as double,
|
||||
));
|
||||
}
|
||||
@@ -5594,10 +5606,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<DashboardWidget> dashboardWidgets, double contentWidth)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<DashboardWidget> dashboardWidgets, double viewWidth)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _DashboardState() when $default != null:
|
||||
return $default(_that.dashboardWidgets,_that.contentWidth);case _:
|
||||
return $default(_that.dashboardWidgets,_that.viewWidth);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -5615,10 +5627,10 @@ return $default(_that.dashboardWidgets,_that.contentWidth);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<DashboardWidget> dashboardWidgets, double contentWidth) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<DashboardWidget> dashboardWidgets, double viewWidth) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _DashboardState():
|
||||
return $default(_that.dashboardWidgets,_that.contentWidth);case _:
|
||||
return $default(_that.dashboardWidgets,_that.viewWidth);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -5635,10 +5647,10 @@ return $default(_that.dashboardWidgets,_that.contentWidth);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<DashboardWidget> dashboardWidgets, double contentWidth)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<DashboardWidget> dashboardWidgets, double viewWidth)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _DashboardState() when $default != null:
|
||||
return $default(_that.dashboardWidgets,_that.contentWidth);case _:
|
||||
return $default(_that.dashboardWidgets,_that.viewWidth);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -5650,7 +5662,7 @@ return $default(_that.dashboardWidgets,_that.contentWidth);case _:
|
||||
|
||||
|
||||
class _DashboardState implements DashboardState {
|
||||
const _DashboardState({required final List<DashboardWidget> dashboardWidgets, required this.contentWidth}): _dashboardWidgets = dashboardWidgets;
|
||||
const _DashboardState({required final List<DashboardWidget> dashboardWidgets, required this.viewWidth}): _dashboardWidgets = dashboardWidgets;
|
||||
|
||||
|
||||
final List<DashboardWidget> _dashboardWidgets;
|
||||
@@ -5660,7 +5672,7 @@ class _DashboardState implements DashboardState {
|
||||
return EqualUnmodifiableListView(_dashboardWidgets);
|
||||
}
|
||||
|
||||
@override final double contentWidth;
|
||||
@override final double viewWidth;
|
||||
|
||||
/// Create a copy of DashboardState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -5672,16 +5684,16 @@ _$DashboardStateCopyWith<_DashboardState> get copyWith => __$DashboardStateCopyW
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _DashboardState&&const DeepCollectionEquality().equals(other._dashboardWidgets, _dashboardWidgets)&&(identical(other.contentWidth, contentWidth) || other.contentWidth == contentWidth));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _DashboardState&&const DeepCollectionEquality().equals(other._dashboardWidgets, _dashboardWidgets)&&(identical(other.viewWidth, viewWidth) || other.viewWidth == viewWidth));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_dashboardWidgets),contentWidth);
|
||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_dashboardWidgets),viewWidth);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DashboardState(dashboardWidgets: $dashboardWidgets, contentWidth: $contentWidth)';
|
||||
return 'DashboardState(dashboardWidgets: $dashboardWidgets, viewWidth: $viewWidth)';
|
||||
}
|
||||
|
||||
|
||||
@@ -5692,7 +5704,7 @@ abstract mixin class _$DashboardStateCopyWith<$Res> implements $DashboardStateCo
|
||||
factory _$DashboardStateCopyWith(_DashboardState value, $Res Function(_DashboardState) _then) = __$DashboardStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
List<DashboardWidget> dashboardWidgets, double contentWidth
|
||||
List<DashboardWidget> dashboardWidgets, double viewWidth
|
||||
});
|
||||
|
||||
|
||||
@@ -5709,10 +5721,10 @@ class __$DashboardStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of DashboardState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? dashboardWidgets = null,Object? contentWidth = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? dashboardWidgets = null,Object? viewWidth = null,}) {
|
||||
return _then(_DashboardState(
|
||||
dashboardWidgets: null == dashboardWidgets ? _self._dashboardWidgets : dashboardWidgets // ignore: cast_nullable_to_non_nullable
|
||||
as List<DashboardWidget>,contentWidth: null == contentWidth ? _self.contentWidth : contentWidth // ignore: cast_nullable_to_non_nullable
|
||||
as List<DashboardWidget>,viewWidth: null == viewWidth ? _self.viewWidth : viewWidth // ignore: cast_nullable_to_non_nullable
|
||||
as double,
|
||||
));
|
||||
}
|
||||
@@ -5721,40 +5733,40 @@ as double,
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$SelectedProxyState {
|
||||
mixin _$ProxyCardState {
|
||||
|
||||
String get proxyName; bool get group; String? get testUrl;
|
||||
/// Create a copy of SelectedProxyState
|
||||
String get proxyName; String? get testUrl;
|
||||
/// Create a copy of ProxyCardState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$SelectedProxyStateCopyWith<SelectedProxyState> get copyWith => _$SelectedProxyStateCopyWithImpl<SelectedProxyState>(this as SelectedProxyState, _$identity);
|
||||
$ProxyCardStateCopyWith<ProxyCardState> get copyWith => _$ProxyCardStateCopyWithImpl<ProxyCardState>(this as ProxyCardState, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
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));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ProxyCardState&&(identical(other.proxyName, proxyName) || other.proxyName == proxyName)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,proxyName,group,testUrl);
|
||||
int get hashCode => Object.hash(runtimeType,proxyName,testUrl);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SelectedProxyState(proxyName: $proxyName, group: $group, testUrl: $testUrl)';
|
||||
return 'ProxyCardState(proxyName: $proxyName, testUrl: $testUrl)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $SelectedProxyStateCopyWith<$Res> {
|
||||
factory $SelectedProxyStateCopyWith(SelectedProxyState value, $Res Function(SelectedProxyState) _then) = _$SelectedProxyStateCopyWithImpl;
|
||||
abstract mixin class $ProxyCardStateCopyWith<$Res> {
|
||||
factory $ProxyCardStateCopyWith(ProxyCardState value, $Res Function(ProxyCardState) _then) = _$ProxyCardStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String proxyName, bool group, String? testUrl
|
||||
String proxyName, String? testUrl
|
||||
});
|
||||
|
||||
|
||||
@@ -5762,20 +5774,19 @@ $Res call({
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$SelectedProxyStateCopyWithImpl<$Res>
|
||||
implements $SelectedProxyStateCopyWith<$Res> {
|
||||
_$SelectedProxyStateCopyWithImpl(this._self, this._then);
|
||||
class _$ProxyCardStateCopyWithImpl<$Res>
|
||||
implements $ProxyCardStateCopyWith<$Res> {
|
||||
_$ProxyCardStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final SelectedProxyState _self;
|
||||
final $Res Function(SelectedProxyState) _then;
|
||||
final ProxyCardState _self;
|
||||
final $Res Function(ProxyCardState) _then;
|
||||
|
||||
/// Create a copy of SelectedProxyState
|
||||
/// Create a copy of ProxyCardState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? proxyName = null,Object? group = null,Object? testUrl = freezed,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? proxyName = null,Object? testUrl = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
proxyName: null == proxyName ? _self.proxyName : proxyName // 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,testUrl: freezed == testUrl ? _self.testUrl : testUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
@@ -5783,8 +5794,8 @@ as String?,
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [SelectedProxyState].
|
||||
extension SelectedProxyStatePatterns on SelectedProxyState {
|
||||
/// Adds pattern-matching-related methods to [ProxyCardState].
|
||||
extension ProxyCardStatePatterns on ProxyCardState {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
@@ -5797,10 +5808,10 @@ extension SelectedProxyStatePatterns on SelectedProxyState {
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SelectedProxyState value)? $default,{required TResult orElse(),}){
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ProxyCardState value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _SelectedProxyState() when $default != null:
|
||||
case _ProxyCardState() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
@@ -5819,10 +5830,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SelectedProxyState value) $default,){
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ProxyCardState value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _SelectedProxyState():
|
||||
case _ProxyCardState():
|
||||
return $default(_that);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
@@ -5840,10 +5851,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SelectedProxyState value)? $default,){
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ProxyCardState value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _SelectedProxyState() when $default != null:
|
||||
case _ProxyCardState() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
@@ -5861,10 +5872,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String proxyName, bool group, String? testUrl)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String proxyName, String? testUrl)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SelectedProxyState() when $default != null:
|
||||
return $default(_that.proxyName,_that.group,_that.testUrl);case _:
|
||||
case _ProxyCardState() when $default != null:
|
||||
return $default(_that.proxyName,_that.testUrl);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -5882,10 +5893,10 @@ return $default(_that.proxyName,_that.group,_that.testUrl);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String proxyName, bool group, String? testUrl) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String proxyName, String? testUrl) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SelectedProxyState():
|
||||
return $default(_that.proxyName,_that.group,_that.testUrl);case _:
|
||||
case _ProxyCardState():
|
||||
return $default(_that.proxyName,_that.testUrl);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -5902,10 +5913,10 @@ return $default(_that.proxyName,_that.group,_that.testUrl);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String proxyName, bool group, String? testUrl)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String proxyName, String? testUrl)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SelectedProxyState() when $default != null:
|
||||
return $default(_that.proxyName,_that.group,_that.testUrl);case _:
|
||||
case _ProxyCardState() when $default != null:
|
||||
return $default(_that.proxyName,_that.testUrl);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -5916,45 +5927,44 @@ return $default(_that.proxyName,_that.group,_that.testUrl);case _:
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _SelectedProxyState implements SelectedProxyState {
|
||||
const _SelectedProxyState({required this.proxyName, this.group = false, this.testUrl});
|
||||
class _ProxyCardState implements ProxyCardState {
|
||||
const _ProxyCardState({required this.proxyName, this.testUrl});
|
||||
|
||||
|
||||
@override final String proxyName;
|
||||
@override@JsonKey() final bool group;
|
||||
@override final String? testUrl;
|
||||
|
||||
/// Create a copy of SelectedProxyState
|
||||
/// Create a copy of ProxyCardState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$SelectedProxyStateCopyWith<_SelectedProxyState> get copyWith => __$SelectedProxyStateCopyWithImpl<_SelectedProxyState>(this, _$identity);
|
||||
_$ProxyCardStateCopyWith<_ProxyCardState> get copyWith => __$ProxyCardStateCopyWithImpl<_ProxyCardState>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
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));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProxyCardState&&(identical(other.proxyName, proxyName) || other.proxyName == proxyName)&&(identical(other.testUrl, testUrl) || other.testUrl == testUrl));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,proxyName,group,testUrl);
|
||||
int get hashCode => Object.hash(runtimeType,proxyName,testUrl);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SelectedProxyState(proxyName: $proxyName, group: $group, testUrl: $testUrl)';
|
||||
return 'ProxyCardState(proxyName: $proxyName, testUrl: $testUrl)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$SelectedProxyStateCopyWith<$Res> implements $SelectedProxyStateCopyWith<$Res> {
|
||||
factory _$SelectedProxyStateCopyWith(_SelectedProxyState value, $Res Function(_SelectedProxyState) _then) = __$SelectedProxyStateCopyWithImpl;
|
||||
abstract mixin class _$ProxyCardStateCopyWith<$Res> implements $ProxyCardStateCopyWith<$Res> {
|
||||
factory _$ProxyCardStateCopyWith(_ProxyCardState value, $Res Function(_ProxyCardState) _then) = __$ProxyCardStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String proxyName, bool group, String? testUrl
|
||||
String proxyName, String? testUrl
|
||||
});
|
||||
|
||||
|
||||
@@ -5962,20 +5972,19 @@ $Res call({
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$SelectedProxyStateCopyWithImpl<$Res>
|
||||
implements _$SelectedProxyStateCopyWith<$Res> {
|
||||
__$SelectedProxyStateCopyWithImpl(this._self, this._then);
|
||||
class __$ProxyCardStateCopyWithImpl<$Res>
|
||||
implements _$ProxyCardStateCopyWith<$Res> {
|
||||
__$ProxyCardStateCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _SelectedProxyState _self;
|
||||
final $Res Function(_SelectedProxyState) _then;
|
||||
final _ProxyCardState _self;
|
||||
final $Res Function(_ProxyCardState) _then;
|
||||
|
||||
/// Create a copy of SelectedProxyState
|
||||
/// Create a copy of ProxyCardState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? proxyName = null,Object? group = null,Object? testUrl = freezed,}) {
|
||||
return _then(_SelectedProxyState(
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? proxyName = null,Object? testUrl = freezed,}) {
|
||||
return _then(_ProxyCardState(
|
||||
proxyName: null == proxyName ? _self.proxyName : proxyName // 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,testUrl: freezed == testUrl ? _self.testUrl : testUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// ignore_for_file: invalid_annotation_target
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/models/models.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -101,7 +102,9 @@ 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;
|
||||
}
|
||||
@@ -111,7 +114,9 @@ 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;
|
||||
}
|
||||
@@ -159,20 +164,25 @@ extension PackageListSelectorStateExt on PackageListSelectorState {
|
||||
|
||||
List<Package> getSortList(List<String> selectedList) {
|
||||
final sort = accessControl.sort;
|
||||
|
||||
return list.sorted((a, b) {
|
||||
final isSelectA = selectedList.contains(a.packageName);
|
||||
final isSelectB = selectedList.contains(b.packageName);
|
||||
|
||||
if (isSelectA != isSelectB) {
|
||||
return isSelectA ? -1 : 1;
|
||||
}
|
||||
return switch (sort) {
|
||||
AccessSortType.none => 0,
|
||||
AccessSortType.name => a.label.compareTo(b.label),
|
||||
AccessSortType.time => b.lastUpdateTime.compareTo(a.lastUpdateTime),
|
||||
};
|
||||
});
|
||||
return list
|
||||
.sorted((a, b) {
|
||||
return switch (sort) {
|
||||
AccessSortType.none => 0,
|
||||
AccessSortType.name => utils.sortByChar(
|
||||
utils.getPinyin(a.label),
|
||||
utils.getPinyin(b.label),
|
||||
),
|
||||
AccessSortType.time => b.lastUpdateTime.compareTo(a.lastUpdateTime),
|
||||
};
|
||||
})
|
||||
.sorted((a, b) {
|
||||
final isSelectA = selectedList.contains(a.packageName);
|
||||
final isSelectB = selectedList.contains(b.packageName);
|
||||
if (isSelectA && isSelectB) return 0;
|
||||
if (isSelectA) return -1;
|
||||
if (isSelectB) return 1;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,17 +228,14 @@ abstract class ClashConfigState with _$ClashConfigState {
|
||||
abstract class DashboardState with _$DashboardState {
|
||||
const factory DashboardState({
|
||||
required List<DashboardWidget> dashboardWidgets,
|
||||
required double contentWidth,
|
||||
required double viewWidth,
|
||||
}) = _DashboardState;
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class SelectedProxyState with _$SelectedProxyState {
|
||||
const factory SelectedProxyState({
|
||||
required String proxyName,
|
||||
@Default(false) bool group,
|
||||
String? testUrl,
|
||||
}) = _SelectedProxyState;
|
||||
abstract class ProxyCardState with _$ProxyCardState {
|
||||
const factory ProxyCardState({required String proxyName, String? testUrl}) =
|
||||
_ProxyCardState;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
||||
@@ -156,7 +156,7 @@ class _EditorPageState extends ConsumerState<EditorPage> {
|
||||
Widget build(BuildContext context) {
|
||||
final isMobileView = ref.watch(isMobileViewProvider);
|
||||
return CommonPopScope(
|
||||
onPop: (context) async {
|
||||
onPop: () async {
|
||||
if (widget.onPop == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ class HomePage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return HomeBackScopeContainer(
|
||||
return HomeBackScope(
|
||||
child: Material(
|
||||
color: context.colorScheme.surface,
|
||||
child: Consumer(
|
||||
@@ -27,15 +27,19 @@ class HomePage extends StatelessWidget {
|
||||
pageBuilder: (_, index) {
|
||||
final navigationItem = state.navigationItems[index];
|
||||
final navigationView = navigationItem.builder(context);
|
||||
final view = KeepScope(
|
||||
keep: navigationItem.keep,
|
||||
child: isMobile
|
||||
? navigationView
|
||||
: Navigator(
|
||||
pages: [MaterialPage(child: navigationView)],
|
||||
onDidRemovePage: (_) {},
|
||||
final view = isMobile
|
||||
? KeepScope(
|
||||
keep: navigationItem.keep,
|
||||
child: navigationView,
|
||||
)
|
||||
: KeepScope(
|
||||
keep: navigationItem.keep,
|
||||
child: Navigator(
|
||||
onGenerateRoute: (_) {
|
||||
return CommonRoute(builder: (_) => navigationView);
|
||||
},
|
||||
),
|
||||
);
|
||||
);
|
||||
return view;
|
||||
},
|
||||
);
|
||||
@@ -243,27 +247,27 @@ class _NavigationBarDefaultsM3 extends NavigationBarThemeData {
|
||||
}
|
||||
}
|
||||
|
||||
class HomeBackScopeContainer extends ConsumerWidget {
|
||||
class HomeBackScope extends StatelessWidget {
|
||||
final Widget child;
|
||||
|
||||
const HomeBackScopeContainer({super.key, required this.child});
|
||||
const HomeBackScope({super.key, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
return CommonPopScope(
|
||||
onPop: (context) async {
|
||||
final pageLabel = ref.read(currentPageLabelProvider);
|
||||
final realContext =
|
||||
GlobalObjectKey(pageLabel).currentContext ?? context;
|
||||
final canPop = Navigator.canPop(realContext);
|
||||
if (canPop) {
|
||||
Navigator.of(realContext).pop();
|
||||
} else {
|
||||
await globalState.appController.handleBackOrExit();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
Widget build(BuildContext context) {
|
||||
if (system.isAndroid) {
|
||||
return CommonPopScope(
|
||||
onPop: () async {
|
||||
final canPop = Navigator.canPop(context);
|
||||
if (canPop) {
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
await globalState.appController.handleBackOrExit();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:fl_clash/common/app_localizations.dart';
|
||||
@@ -39,48 +38,45 @@ 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 path = await methodChannel.invokeMethod<String>('getPackageIcon', {
|
||||
final base64 = await methodChannel.invokeMethod<String>('getPackageIcon', {
|
||||
'packageName': packageName,
|
||||
});
|
||||
if (path == null) {
|
||||
if (base64 == null) {
|
||||
return null;
|
||||
}
|
||||
return FileImage(File(path));
|
||||
return MemoryImage(base64Decode(base64));
|
||||
}
|
||||
|
||||
Future<bool?> tip(String? message) async {
|
||||
|
||||
@@ -13,7 +13,7 @@ import 'package:flutter/services.dart';
|
||||
abstract mixin class ServiceListener {
|
||||
void onServiceEvent(CoreEvent event) {}
|
||||
|
||||
void onServiceCrash(String message) {}
|
||||
void onServiceCrash() {}
|
||||
}
|
||||
|
||||
class Service {
|
||||
@@ -43,9 +43,8 @@ class Service {
|
||||
}
|
||||
break;
|
||||
case 'crash':
|
||||
final message = call.arguments as String? ?? '';
|
||||
for (final listener in _listeners) {
|
||||
listener.onServiceCrash(message);
|
||||
listener.onServiceCrash();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -77,20 +76,16 @@ class Service {
|
||||
return await methodChannel.invokeMethod<bool>('stop') ?? false;
|
||||
}
|
||||
|
||||
Future<String> syncAndroidState(AndroidState state) async {
|
||||
return await methodChannel.invokeMethod<String>(
|
||||
Future<bool> syncAndroidState(AndroidState state) async {
|
||||
return await methodChannel.invokeMethod<bool>(
|
||||
'syncState',
|
||||
json.encode(state),
|
||||
) ??
|
||||
'';
|
||||
false;
|
||||
}
|
||||
|
||||
Future<String> init() async {
|
||||
return await methodChannel.invokeMethod<String>('init') ?? '';
|
||||
}
|
||||
|
||||
Future<bool> shutdown() async {
|
||||
return await methodChannel.invokeMethod<bool>('shutdown') ?? true;
|
||||
Future<bool> init() async {
|
||||
return await methodChannel.invokeMethod<bool>('init') ?? false;
|
||||
}
|
||||
|
||||
Future<DateTime?> getRunTime() async {
|
||||
|
||||
@@ -28,7 +28,7 @@ class Logs extends _$Logs with AutoDisposeNotifierMixin {
|
||||
}
|
||||
|
||||
void addLog(Log value) {
|
||||
this.value = state.copyWith()..add(value);
|
||||
state = state.copyWith()..add(value);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -50,15 +50,12 @@ class Requests extends _$Requests with AutoDisposeNotifierMixin {
|
||||
}
|
||||
|
||||
void addRequest(TrackerInfo value) {
|
||||
this.value = state.copyWith()..add(value);
|
||||
state = state.copyWith()..add(value);
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class Providers extends _$Providers with AnyNotifierMixin {
|
||||
@override
|
||||
List<ExternalProvider> get value => globalState.appState.providers;
|
||||
|
||||
class Providers extends _$Providers with AutoDisposeNotifierMixin {
|
||||
@override
|
||||
List<ExternalProvider> build() {
|
||||
return globalState.appState.providers;
|
||||
@@ -70,14 +67,10 @@ class Providers extends _$Providers with AnyNotifierMixin {
|
||||
}
|
||||
|
||||
void setProvider(ExternalProvider? provider) {
|
||||
if (!ref.mounted) {
|
||||
return;
|
||||
}
|
||||
if (provider == null) return;
|
||||
final index = value.indexWhere((item) => item.name == provider.name);
|
||||
final index = state.indexWhere((item) => item.name == provider.name);
|
||||
if (index == -1) return;
|
||||
final newState = List<ExternalProvider>.from(value)..[index] = provider;
|
||||
value = newState;
|
||||
state = List.from(state)..[index] = provider;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +101,7 @@ class SystemBrightness extends _$SystemBrightness
|
||||
}
|
||||
|
||||
void setState(Brightness value) {
|
||||
this.value = value;
|
||||
state = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,11 +118,11 @@ class Traffics extends _$Traffics with AutoDisposeNotifierMixin {
|
||||
}
|
||||
|
||||
void addTraffic(Traffic value) {
|
||||
this.value = state.copyWith()..add(value);
|
||||
state = state.copyWith()..add(value);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
value = state.copyWith()..clear();
|
||||
state = state.copyWith()..clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +150,12 @@ class LocalIp extends _$LocalIp with AutoDisposeNotifierMixin {
|
||||
onUpdate(value) {
|
||||
globalState.appState = globalState.appState.copyWith(localIp: value);
|
||||
}
|
||||
|
||||
@override
|
||||
set state(String? value) {
|
||||
super.state = value;
|
||||
globalState.appState = globalState.appState.copyWith(localIp: state);
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
@@ -185,19 +184,6 @@ class ViewSize extends _$ViewSize with AutoDisposeNotifierMixin {
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class SideWidth extends _$SideWidth with AutoDisposeNotifierMixin {
|
||||
@override
|
||||
double build() {
|
||||
return globalState.appState.sideWidth;
|
||||
}
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.appState = globalState.appState.copyWith(sideWidth: value);
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
double viewWidth(Ref ref) {
|
||||
return ref.watch(viewSizeProvider).width;
|
||||
@@ -346,7 +332,7 @@ class DelayDataSource extends _$DelayDataSource with AutoDisposeNotifierMixin {
|
||||
newDelayMap[delay.url] = {};
|
||||
}
|
||||
newDelayMap[delay.url]![delay.name] = delay.value;
|
||||
value = newDelayMap;
|
||||
state = newDelayMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -389,7 +375,7 @@ class ProfileOverrideState extends _$ProfileOverrideState
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
this.value = value;
|
||||
state = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,6 +403,6 @@ class QueryMap extends _$QueryMap with AutoDisposeNotifierMixin {
|
||||
}
|
||||
|
||||
void updateQuery(QueryTag tag, String value) {
|
||||
this.value = Map.from(globalState.appState.queryMap)..[tag] = value;
|
||||
state = Map.from(globalState.appState.queryMap)..[tag] = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,13 @@ class AppSetting extends _$AppSetting with AutoDisposeNotifierMixin {
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.config = globalState.config.copyWith(appSetting: value);
|
||||
globalState.config = globalState.config.copyWith(
|
||||
appSetting: value,
|
||||
);
|
||||
}
|
||||
|
||||
void updateState(AppSettingProps Function(AppSettingProps state) builder) {
|
||||
value = builder(state);
|
||||
state = builder(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,11 +33,13 @@ class WindowSetting extends _$WindowSetting with AutoDisposeNotifierMixin {
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.config = globalState.config.copyWith(windowProps: value);
|
||||
globalState.config = globalState.config.copyWith(
|
||||
windowProps: value,
|
||||
);
|
||||
}
|
||||
|
||||
void updateState(WindowProps Function(WindowProps state) builder) {
|
||||
value = builder(state);
|
||||
state = builder(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,11 +52,13 @@ class VpnSetting extends _$VpnSetting with AutoDisposeNotifierMixin {
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.config = globalState.config.copyWith(vpnProps: value);
|
||||
globalState.config = globalState.config.copyWith(
|
||||
vpnProps: value,
|
||||
);
|
||||
}
|
||||
|
||||
void updateState(VpnProps Function(VpnProps state) builder) {
|
||||
value = builder(state);
|
||||
state = builder(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,11 +71,13 @@ class NetworkSetting extends _$NetworkSetting with AutoDisposeNotifierMixin {
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.config = globalState.config.copyWith(networkProps: value);
|
||||
globalState.config = globalState.config.copyWith(
|
||||
networkProps: value,
|
||||
);
|
||||
}
|
||||
|
||||
void updateState(NetworkProps Function(NetworkProps state) builder) {
|
||||
value = builder(state);
|
||||
state = builder(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,11 +90,13 @@ class ThemeSetting extends _$ThemeSetting with AutoDisposeNotifierMixin {
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.config = globalState.config.copyWith(themeProps: value);
|
||||
globalState.config = globalState.config.copyWith(
|
||||
themeProps: value,
|
||||
);
|
||||
}
|
||||
|
||||
void updateState(ThemeProps Function(ThemeProps state) builder) {
|
||||
value = builder(state);
|
||||
state = builder(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,15 +109,15 @@ class Profiles extends _$Profiles with AutoDisposeNotifierMixin {
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.config = globalState.config.copyWith(profiles: value);
|
||||
globalState.config = globalState.config.copyWith(
|
||||
profiles: value,
|
||||
);
|
||||
}
|
||||
|
||||
String? _getLabel(String? label, String id) {
|
||||
final realLabel = label ?? id;
|
||||
final hasDup =
|
||||
state.indexWhere(
|
||||
(element) => element.label == realLabel && element.id != id,
|
||||
) !=
|
||||
final hasDup = state.indexWhere(
|
||||
(element) => element.label == realLabel && element.id != id) !=
|
||||
-1;
|
||||
if (hasDup) {
|
||||
return _getLabel(utils.getOverwriteLabel(realLabel), id);
|
||||
@@ -118,9 +128,8 @@ class Profiles extends _$Profiles with AutoDisposeNotifierMixin {
|
||||
|
||||
void setProfile(Profile profile) {
|
||||
final List<Profile> profilesTemp = List.from(state);
|
||||
final index = profilesTemp.indexWhere(
|
||||
(element) => element.id == profile.id,
|
||||
);
|
||||
final index =
|
||||
profilesTemp.indexWhere((element) => element.id == profile.id);
|
||||
final updateProfile = profile.copyWith(
|
||||
label: _getLabel(profile.label, profile.id),
|
||||
);
|
||||
@@ -129,23 +138,21 @@ class Profiles extends _$Profiles with AutoDisposeNotifierMixin {
|
||||
} else {
|
||||
profilesTemp[index] = updateProfile;
|
||||
}
|
||||
value = profilesTemp;
|
||||
state = profilesTemp;
|
||||
}
|
||||
|
||||
void updateProfile(
|
||||
String profileId,
|
||||
Profile Function(Profile profile) builder,
|
||||
) {
|
||||
String profileId, Profile Function(Profile profile) builder) {
|
||||
final List<Profile> profilesTemp = List.from(state);
|
||||
final index = profilesTemp.indexWhere((element) => element.id == profileId);
|
||||
if (index != -1) {
|
||||
profilesTemp[index] = builder(profilesTemp[index]);
|
||||
}
|
||||
value = profilesTemp;
|
||||
state = profilesTemp;
|
||||
}
|
||||
|
||||
void deleteProfileById(String id) {
|
||||
value = state.where((element) => element.id != id).toList();
|
||||
state = state.where((element) => element.id != id).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +166,9 @@ class CurrentProfileId extends _$CurrentProfileId
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.config = globalState.config.copyWith(currentProfileId: value);
|
||||
globalState.config = globalState.config.copyWith(
|
||||
currentProfileId: value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,11 +181,13 @@ class AppDAVSetting extends _$AppDAVSetting with AutoDisposeNotifierMixin {
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.config = globalState.config.copyWith(dav: value);
|
||||
globalState.config = globalState.config.copyWith(
|
||||
dav: value,
|
||||
);
|
||||
}
|
||||
|
||||
void updateState(DAV? Function(DAV? state) builder) {
|
||||
value = builder(state);
|
||||
state = builder(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +200,9 @@ class OverrideDns extends _$OverrideDns with AutoDisposeNotifierMixin {
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.config = globalState.config.copyWith(overrideDns: value);
|
||||
globalState.config = globalState.config.copyWith(
|
||||
overrideDns: value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +215,9 @@ class HotKeyActions extends _$HotKeyActions with AutoDisposeNotifierMixin {
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.config = globalState.config.copyWith(hotKeyActions: value);
|
||||
globalState.config = globalState.config.copyWith(
|
||||
hotKeyActions: value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,11 +231,13 @@ class ProxiesStyleSetting extends _$ProxiesStyleSetting
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.config = globalState.config.copyWith(proxiesStyle: value);
|
||||
globalState.config = globalState.config.copyWith(
|
||||
proxiesStyle: value,
|
||||
);
|
||||
}
|
||||
|
||||
void updateState(ProxiesStyle Function(ProxiesStyle state) builder) {
|
||||
value = builder(state);
|
||||
state = builder(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +250,9 @@ class ScriptState extends _$ScriptState with AutoDisposeNotifierMixin {
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.config = globalState.config.copyWith(scriptProps: value);
|
||||
globalState.config = globalState.config.copyWith(
|
||||
scriptProps: value,
|
||||
);
|
||||
}
|
||||
|
||||
void setScript(Script script) {
|
||||
@@ -244,11 +263,15 @@ class ScriptState extends _$ScriptState with AutoDisposeNotifierMixin {
|
||||
} else {
|
||||
list.add(script);
|
||||
}
|
||||
value = state.copyWith(scripts: list);
|
||||
state = state.copyWith(
|
||||
scripts: list,
|
||||
);
|
||||
}
|
||||
|
||||
void setId(String id) {
|
||||
value = state.copyWith(currentId: state.currentId != id ? id : null);
|
||||
state = state.copyWith(
|
||||
currentId: state.currentId != id ? id : null,
|
||||
);
|
||||
}
|
||||
|
||||
void del(String id) {
|
||||
@@ -258,7 +281,10 @@ class ScriptState extends _$ScriptState with AutoDisposeNotifierMixin {
|
||||
list.removeAt(index);
|
||||
}
|
||||
final nextId = id == state.currentId ? null : state.currentId;
|
||||
state = state.copyWith(scripts: list, currentId: nextId);
|
||||
state = state.copyWith(
|
||||
scripts: list,
|
||||
currentId: nextId,
|
||||
);
|
||||
}
|
||||
|
||||
bool isExits(String label) {
|
||||
@@ -279,11 +305,13 @@ class PatchClashConfig extends _$PatchClashConfig
|
||||
if (newState == null) {
|
||||
return;
|
||||
}
|
||||
value = newState;
|
||||
state = newState;
|
||||
}
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.config = globalState.config.copyWith(patchClashConfig: value);
|
||||
globalState.config = globalState.config.copyWith(
|
||||
patchClashConfig: value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ final class LogsProvider extends $NotifierProvider<Logs, FixedList<Log>> {
|
||||
}
|
||||
}
|
||||
|
||||
String _$logsHash() => r'a671cf70f13d38cae75dc51841b651fe2d2dad9a';
|
||||
String _$logsHash() => r'0a32e067292d449d61af59a689cb26691f4afe44';
|
||||
|
||||
abstract class _$Logs extends $Notifier<FixedList<Log>> {
|
||||
FixedList<Log> build();
|
||||
@@ -143,7 +143,7 @@ final class RequestsProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$requestsHash() => r'8642621b8b5f2e56f3abb04554c058fb30389795';
|
||||
String _$requestsHash() => r'526f2c1da1347fd2e6e3e23aac0335fcfe0cb28a';
|
||||
|
||||
abstract class _$Requests extends $Notifier<FixedList<TrackerInfo>> {
|
||||
FixedList<TrackerInfo> build();
|
||||
@@ -197,7 +197,7 @@ final class ProvidersProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$providersHash() => r'9cb491314be6dca0d9ff2d09aa276d19a92895af';
|
||||
String _$providersHash() => r'4292240629a99470b2e72426dde3b9049b9b57e0';
|
||||
|
||||
abstract class _$Providers extends $Notifier<List<ExternalProvider>> {
|
||||
List<ExternalProvider> build();
|
||||
@@ -304,7 +304,7 @@ final class SystemBrightnessProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$systemBrightnessHash() => r'2fb112459d5f505768f8c33b314aa62cf1fb0a0a';
|
||||
String _$systemBrightnessHash() => r'46eb2d23b05405723efc29480e8f258bf2d8138b';
|
||||
|
||||
abstract class _$SystemBrightness extends $Notifier<Brightness> {
|
||||
Brightness build();
|
||||
@@ -357,7 +357,7 @@ final class TrafficsProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$trafficsHash() => r'7df7d01f39e9fa1bf629221c9f73273757fa535a';
|
||||
String _$trafficsHash() => r'8b86eb718fed5776de174c51fd5b231957011fe6';
|
||||
|
||||
abstract class _$Traffics extends $Notifier<FixedList<Traffic>> {
|
||||
FixedList<Traffic> build();
|
||||
@@ -462,7 +462,7 @@ final class LocalIpProvider extends $NotifierProvider<LocalIp, String?> {
|
||||
}
|
||||
}
|
||||
|
||||
String _$localIpHash() => r'25ff07ff9ae316eac7ef39c29d9ae2714b7ba323';
|
||||
String _$localIpHash() => r'2dd4afdb29db4791ebd80d976f9ea31c62959199';
|
||||
|
||||
abstract class _$LocalIp extends $Notifier<String?> {
|
||||
String? build();
|
||||
@@ -587,58 +587,6 @@ abstract class _$ViewSize extends $Notifier<Size> {
|
||||
}
|
||||
}
|
||||
|
||||
@ProviderFor(SideWidth)
|
||||
const sideWidthProvider = SideWidthProvider._();
|
||||
|
||||
final class SideWidthProvider extends $NotifierProvider<SideWidth, double> {
|
||||
const SideWidthProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'sideWidthProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$sideWidthHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
SideWidth create() => SideWidth();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(double value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<double>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$sideWidthHash() => r'380c2ae2136dc75346259d3c1d0dd3325e41fe49';
|
||||
|
||||
abstract class _$SideWidth extends $Notifier<double> {
|
||||
double build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<double, double>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<double, double>,
|
||||
double,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
|
||||
@ProviderFor(viewWidth)
|
||||
const viewWidthProvider = ViewWidthProvider._();
|
||||
|
||||
@@ -1251,7 +1199,7 @@ final class DelayDataSourceProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$delayDataSourceHash() => r'0cc7064c6e7e7a1823df1c5b339001ae49ee54f1';
|
||||
String _$delayDataSourceHash() => r'1b94dcfdb9e1eb4c0b7ca69d933f2299d1f94ed5';
|
||||
|
||||
abstract class _$DelayDataSource extends $Notifier<DelayMap> {
|
||||
DelayMap build();
|
||||
@@ -1360,7 +1308,7 @@ final class ProfileOverrideStateProvider
|
||||
}
|
||||
|
||||
String _$profileOverrideStateHash() =>
|
||||
r'6bcf739e034cc39623dc63bf304189d63fc19404';
|
||||
r'c57bb59c3900b6ee752d6c1cd5c9c0ccc6d1f45e';
|
||||
|
||||
abstract class _$ProfileOverrideState extends $Notifier<ProfileOverrideModel?> {
|
||||
ProfileOverrideModel? build();
|
||||
@@ -1466,7 +1414,7 @@ final class QueryMapProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$queryMapHash() => r'f64a1bf5fcd4f85986d8ba3c956e397abc4f2d5d';
|
||||
String _$queryMapHash() => r'102d489d31d312f082d7117f80a6de8318eaaf75';
|
||||
|
||||
abstract class _$QueryMap extends $Notifier<Map<QueryTag, String>> {
|
||||
Map<QueryTag, String> build();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user