Compare commits
1 Commits
v0.8.88-pr
...
v0.8.88-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f06abecb3e |
3
.github/workflows/build.yaml
vendored
3
.github/workflows/build.yaml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
- platform: android
|
||||
os: ubuntu-latest
|
||||
- platform: windows
|
||||
os: Windows-2022
|
||||
os: windows-latest
|
||||
arch: amd64
|
||||
- platform: linux
|
||||
os: ubuntu-22.04
|
||||
@@ -52,7 +52,6 @@ jobs:
|
||||
if: startsWith(matrix.platform,'android')
|
||||
run: |
|
||||
echo "${{ secrets.KEYSTORE }}" | base64 --decode > android/app/keystore.jks
|
||||
echo "${{ secrets.SERVICE_JSON }}" | base64 --decode > android/app/google-services.json
|
||||
echo "keyAlias=${{ secrets.KEY_ALIAS }}" >> android/local.properties
|
||||
echo "storePassword=${{ secrets.STORE_PASSWORD }}" >> android/local.properties
|
||||
echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> android/local.properties
|
||||
|
||||
@@ -5,8 +5,6 @@ plugins {
|
||||
id("com.android.application")
|
||||
id("kotlin-android")
|
||||
id("dev.flutter.flutter-gradle-plugin")
|
||||
id("com.google.gms.google-services")
|
||||
id("com.google.firebase.crashlytics")
|
||||
}
|
||||
|
||||
val localPropertiesFile = rootProject.file("local.properties")
|
||||
@@ -20,9 +18,10 @@ val mStoreFile: File = file("keystore.jks")
|
||||
val mStorePassword: String? = localProperties.getProperty("storePassword")
|
||||
val mKeyAlias: String? = localProperties.getProperty("keyAlias")
|
||||
val mKeyPassword: String? = localProperties.getProperty("keyPassword")
|
||||
val isRelease =
|
||||
mStoreFile.exists() && mStorePassword != null && mKeyAlias != null && mKeyPassword != null
|
||||
|
||||
val isRelease = mStoreFile.exists()
|
||||
&& mStorePassword != null
|
||||
&& mKeyAlias != null
|
||||
&& mKeyPassword != null
|
||||
|
||||
android {
|
||||
namespace = "com.follow.clash"
|
||||
@@ -77,7 +76,8 @@ android {
|
||||
}
|
||||
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,6 @@ flutter {
|
||||
source = "../.."
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation(project(":service"))
|
||||
implementation(project(":common"))
|
||||
@@ -102,7 +101,4 @@ dependencies {
|
||||
implementation(libs.smali.dexlib2) {
|
||||
exclude(group = "com.google.guava", module = "guava")
|
||||
}
|
||||
implementation(platform(libs.firebase.bom))
|
||||
implementation(libs.firebase.crashlytics.ndk)
|
||||
implementation(libs.firebase.analytics)
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "000000000000",
|
||||
"project_id": "dev"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:000000000000:android:0000000000000000",
|
||||
"android_client_info": {
|
||||
"package_name": "com.follow.clash"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "0"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:000000000000:android:0000000000000000",
|
||||
"android_client_info": {
|
||||
"package_name": "com.follow.clash.debug"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "0"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3,9 +3,6 @@ package com.follow.clash
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import com.follow.clash.common.GlobalState
|
||||
import com.follow.clash.common.processName
|
||||
import com.google.firebase.FirebaseApp
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
|
||||
class Application : Application() {
|
||||
|
||||
@@ -13,21 +10,4 @@ class Application : Application() {
|
||||
super.attachBaseContext(base)
|
||||
GlobalState.init(this)
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
initRemoteCrashlytics(this)
|
||||
}
|
||||
|
||||
private fun initRemoteCrashlytics(context: Context) {
|
||||
try {
|
||||
if (processName?.endsWith(":remote") == true) {
|
||||
FirebaseApp.initializeApp(context)
|
||||
FirebaseCrashlytics.getInstance().isCrashlyticsCollectionEnabled = true
|
||||
GlobalState.log("init remote crashlytics")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
GlobalState.log("initRemoteCrashlytics error: $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ inline fun <reified T : FlutterPlugin> FlutterEngine.plugin(): T? {
|
||||
return plugins.get(T::class.java) as T?
|
||||
}
|
||||
|
||||
|
||||
fun <T> MethodChannel.invokeMethodOnMainThread(
|
||||
method: String, arguments: Any? = null, callback: ((Result<T>) -> Unit)? = null
|
||||
) {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package com.follow.clash
|
||||
|
||||
import com.follow.clash.common.ServiceDelegate
|
||||
import com.follow.clash.common.formatString
|
||||
import com.follow.clash.common.intent
|
||||
import com.follow.clash.service.ICallbackInterface
|
||||
import com.follow.clash.service.IEventInterface
|
||||
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
|
||||
@@ -31,43 +30,13 @@ object Service {
|
||||
delegate.bind()
|
||||
}
|
||||
|
||||
fun unbind() {
|
||||
delegate.unbind()
|
||||
}
|
||||
|
||||
suspend fun invokeAction(data: String, cb: (result: String) -> Unit): Result<Unit> {
|
||||
val res = mutableListOf<ByteArray>()
|
||||
return delegate.useService {
|
||||
it.invokeAction(
|
||||
data,
|
||||
object : ICallbackInterface.Stub() {
|
||||
override fun onResult(result: ByteArray?, isSuccess: Boolean) {
|
||||
res.add(result ?: byteArrayOf())
|
||||
if (isSuccess) {
|
||||
cb(res.formatString())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun setEventListener(
|
||||
cb: (result: String?) -> Unit
|
||||
suspend fun invokeAction(
|
||||
data: String, cb: (result: ByteArray?, isSuccess: Boolean) -> Unit
|
||||
): Result<Unit> {
|
||||
val results = HashMap<String, MutableList<ByteArray>>()
|
||||
return delegate.useService {
|
||||
it.setEventListener(object : IEventInterface.Stub() {
|
||||
override fun onEvent(
|
||||
id: String, data: ByteArray?, isSuccess: Boolean
|
||||
) {
|
||||
if (results[id] == null) {
|
||||
results[id] = mutableListOf()
|
||||
}
|
||||
results[id]?.add(data ?: byteArrayOf())
|
||||
if (isSuccess) {
|
||||
cb(results[id]?.formatString())
|
||||
results.remove(id)
|
||||
}
|
||||
it.invokeAction(data, object : ICallbackInterface.Stub() {
|
||||
override fun onResult(result: ByteArray?, isSuccess: Boolean) {
|
||||
cb(result, isSuccess)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -81,6 +50,18 @@ object Service {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun setMessageCallback(
|
||||
cb: (result: String?) -> Unit
|
||||
): Result<Unit> {
|
||||
return delegate.useService {
|
||||
it.setMessageCallback(object : IMessageInterface.Stub() {
|
||||
override fun onResult(result: String?) {
|
||||
cb(result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun startService(options: VpnOptions, inApp: Boolean) {
|
||||
delegate.useService { it.startService(options, inApp) }
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
@@ -170,7 +172,8 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
|
||||
result.success("")
|
||||
return@launch
|
||||
}
|
||||
val path = GlobalState.application.packageManager.getPackageIconPath(packageName)
|
||||
val path =
|
||||
GlobalState.application.packageManager.getPackageIconPath(packageName)
|
||||
result.success(path)
|
||||
}
|
||||
}
|
||||
@@ -220,12 +223,13 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
|
||||
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
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ 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
|
||||
@@ -40,10 +41,6 @@ class ServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
|
||||
handleInit(result)
|
||||
}
|
||||
|
||||
"shutdown" -> {
|
||||
handleShutdown(result)
|
||||
}
|
||||
|
||||
"invokeAction" -> {
|
||||
handleInvokeAction(call, result)
|
||||
}
|
||||
@@ -72,17 +69,16 @@ class ServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
|
||||
private fun handleInvokeAction(call: MethodCall, result: MethodChannel.Result) {
|
||||
launch {
|
||||
val data = call.arguments<String>()!!
|
||||
Service.invokeAction(data) {
|
||||
result.success(it)
|
||||
val res = mutableListOf<ByteArray>()
|
||||
Service.invokeAction(data) { byteArray, isSuccess ->
|
||||
res.add(byteArray ?: byteArrayOf())
|
||||
if (isSuccess) {
|
||||
result.success(res.formatString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleShutdown(result: MethodChannel.Result) {
|
||||
Service.unbind()
|
||||
result.success(true)
|
||||
}
|
||||
|
||||
private fun handleStart(result: MethodChannel.Result) {
|
||||
State.handleStartService()
|
||||
result.success(true)
|
||||
@@ -134,7 +130,7 @@ class ServicePlugin : FlutterPlugin, MethodChannel.MethodCallHandler,
|
||||
fun handleInit(result: MethodChannel.Result) {
|
||||
Service.bind()
|
||||
launch {
|
||||
Service.setEventListener {
|
||||
Service.setMessageCallback {
|
||||
handleSendEvent(it)
|
||||
}.onSuccess {
|
||||
result.success("")
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.follow.clash.common
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.ActivityManager
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
@@ -21,7 +20,6 @@ import android.os.IBinder
|
||||
import android.os.Looper
|
||||
import android.os.RemoteException
|
||||
import android.util.Log
|
||||
import androidx.core.content.getSystemService
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -69,16 +67,6 @@ val QuickAction.quickIntent: Intent
|
||||
val BroadcastAction.action: String
|
||||
get() = "${GlobalState.application.packageName}.intent.action.${this.name}"
|
||||
|
||||
val Context.processName: String?
|
||||
get() {
|
||||
val pid = android.os.Process.myPid()
|
||||
val activityManager = getSystemService<ActivityManager>()
|
||||
activityManager?.runningAppProcesses?.find { it.pid == pid }?.let {
|
||||
return it.processName
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
val BroadcastAction.quickIntent: Intent
|
||||
get() = Components.BROADCAST_RECEIVER.intent.apply {
|
||||
action = this@quickIntent.action
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.follow.clash.common
|
||||
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
@@ -50,7 +50,7 @@ class ServiceDelegate<T>(
|
||||
}
|
||||
|
||||
suspend inline fun <R> useService(
|
||||
timeoutMillis: Long = 5000, crossinline block: suspend (T) -> R
|
||||
timeoutMillis: Long = 5000, crossinline block: (T) -> R
|
||||
): Result<R> {
|
||||
return runCatching {
|
||||
withTimeout(timeoutMillis) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
[versions]
|
||||
#agp = "8.10.1"
|
||||
firebaseBom = "34.2.0"
|
||||
minSdk = "23"
|
||||
targetSdk = "36"
|
||||
compileSdk = "36"
|
||||
@@ -11,18 +10,11 @@ coreSplashscreen = "1.0.1"
|
||||
gson = "2.13.1"
|
||||
kotlin = "2.2.10"
|
||||
smaliDexlib2 = "3.0.9"
|
||||
firebaseCrashlyticsKtx = "20.0.1"
|
||||
firebaseCommonKtx = "22.0.0"
|
||||
|
||||
[libraries]
|
||||
build-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
androidx-core = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
|
||||
annotation-jvm = { module = "androidx.annotation:annotation-jvm", version.ref = "annotationJvm" }
|
||||
core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" }
|
||||
firebase-analytics = { module = "com.google.firebase:firebase-analytics" }
|
||||
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" }
|
||||
firebase-crashlytics-ndk = { module = "com.google.firebase:firebase-crashlytics-ndk" }
|
||||
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
|
||||
smali-dexlib2 = { module = "com.android.tools.smali:smali-dexlib2", version.ref = "smaliDexlib2" }
|
||||
firebase-crashlytics-ktx = { group = "com.google.firebase", name = "firebase-crashlytics-ktx", version.ref = "firebaseCrashlyticsKtx" }
|
||||
firebase-common-ktx = { group = "com.google.firebase", name = "firebase-common-ktx", version.ref = "firebaseCommonKtx" }
|
||||
smali-dexlib2 = { module = "com.android.tools.smali:smali-dexlib2", version.ref = "smaliDexlib2" }
|
||||
@@ -2,5 +2,5 @@
|
||||
package com.follow.clash.service;
|
||||
|
||||
interface ICallbackInterface {
|
||||
void onResult(in byte[] data,in boolean isSuccess);
|
||||
void onResult(in byte[] result, boolean isSuccess);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// IEventInterface.aidl
|
||||
package com.follow.clash.service;
|
||||
|
||||
|
||||
interface IEventInterface {
|
||||
void onEvent(in String id, in byte[] data,in boolean isSuccess);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMessageInterface.aidl
|
||||
package com.follow.clash.service;
|
||||
|
||||
interface IMessageInterface {
|
||||
void onResult(String result);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
package com.follow.clash.service;
|
||||
|
||||
import com.follow.clash.service.ICallbackInterface;
|
||||
import com.follow.clash.service.IEventInterface;
|
||||
import com.follow.clash.service.IMessageInterface;
|
||||
import com.follow.clash.service.models.VpnOptions;
|
||||
import com.follow.clash.service.models.NotificationParams;
|
||||
|
||||
@@ -11,5 +11,5 @@ interface IRemoteInterface {
|
||||
void updateNotificationParams(in NotificationParams params);
|
||||
void startService(in VpnOptions options,in boolean inApp);
|
||||
void stopService();
|
||||
void setEventListener(in IEventInterface event);
|
||||
void setMessageCallback(in IMessageInterface messageCallback);
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.UUID
|
||||
|
||||
class RemoteService : Service(),
|
||||
CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.Default) {
|
||||
@@ -61,12 +60,10 @@ class RemoteService : Service(),
|
||||
private val binder = object : IRemoteInterface.Stub() {
|
||||
override fun invokeAction(data: String, callback: ICallbackInterface) {
|
||||
Core.invokeAction(data) {
|
||||
runCatching {
|
||||
val chunks = it?.chunkedForAidl() ?: listOf()
|
||||
val totalSize = chunks.size
|
||||
chunks.forEachIndexed { index, chunk ->
|
||||
callback.onResult(chunk, totalSize - 1 == index)
|
||||
}
|
||||
val chunks = it?.chunkedForAidl() ?: listOf()
|
||||
val totalSize = chunks.size
|
||||
chunks.forEachIndexed { index, chunk ->
|
||||
callback.onResult(chunk, totalSize - 1 == index)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,20 +84,15 @@ class RemoteService : Service(),
|
||||
handleStopService()
|
||||
}
|
||||
|
||||
override fun setEventListener(event: IEventInterface) {
|
||||
Core.setMessageCallback {
|
||||
runCatching {
|
||||
val id = UUID.randomUUID().toString()
|
||||
val chunks = it?.chunkedForAidl() ?: listOf()
|
||||
val totalSize = chunks.size
|
||||
chunks.forEachIndexed { index, chunk ->
|
||||
event.onEvent(id, chunk, totalSize - 1 == index)
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun setMessageCallback(messageCallback: IMessageInterface) {
|
||||
setMessageCallback(messageCallback::onResult)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setMessageCallback(cb: (result: String?) -> Unit) {
|
||||
Core.setMessageCallback(cb)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder {
|
||||
return binder
|
||||
}
|
||||
|
||||
@@ -13,11 +13,7 @@ val Traffic.speedText: String
|
||||
get() = "${up.formatBytes}/s↑ ${down.formatBytes}/s↓"
|
||||
|
||||
fun Core.getSpeedTrafficText(onlyStatisticsProxy: Boolean): String {
|
||||
try {
|
||||
val res = getTraffic(onlyStatisticsProxy)
|
||||
val traffic = Gson().fromJson(res, Traffic::class.java)
|
||||
return traffic.speedText
|
||||
} catch (_: Exception) {
|
||||
return ""
|
||||
}
|
||||
val res = getTraffic(onlyStatisticsProxy)
|
||||
val traffic = Gson().fromJson(res, Traffic::class.java)
|
||||
return traffic.speedText
|
||||
}
|
||||
@@ -102,7 +102,7 @@ class NetworkObserveModule(private val service: Service) : Module() {
|
||||
return
|
||||
}
|
||||
preDnsList = dnsList
|
||||
Core.updateDNS(dnsList.toSet().joinToString(","))
|
||||
Core.updateDNS(dnsList.joinToString { "," })
|
||||
}
|
||||
|
||||
fun setUnderlyingNetworks(network: Network) {
|
||||
|
||||
@@ -18,10 +18,8 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
id("com.android.application") version "8.12.2" apply false
|
||||
id("com.android.application") version "8.12.1" apply false
|
||||
id("org.jetbrains.kotlin.android") version "2.2.10" apply false
|
||||
id("com.google.gms.google-services") version ("4.3.15") apply false
|
||||
id("com.google.firebase.crashlytics") version ("2.8.1") apply false
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -409,7 +409,7 @@
|
||||
"autoSetSystemDns": "Auto set system DNS",
|
||||
"details": "{label} details",
|
||||
"creationTime": "Creation time",
|
||||
"process": "Process",
|
||||
"progress": "Progress",
|
||||
"host": "Host",
|
||||
"destination": "Destination",
|
||||
"destinationGeoIP": "Destination GeoIP",
|
||||
|
||||
@@ -410,7 +410,7 @@
|
||||
"autoSetSystemDns": "オートセットシステムDNS",
|
||||
"details": "{label}詳細",
|
||||
"creationTime": "作成時間",
|
||||
"process": "プロセス",
|
||||
"progress": "進捗",
|
||||
"host": "ホスト",
|
||||
"destination": "宛先",
|
||||
"destinationGeoIP": "宛先地理情報",
|
||||
|
||||
@@ -410,7 +410,7 @@
|
||||
"autoSetSystemDns": "Автоматическая настройка системного DNS",
|
||||
"details": "Детали {}",
|
||||
"creationTime": "Время создания",
|
||||
"process": "процесс",
|
||||
"progress": "Прогресс",
|
||||
"host": "Хост",
|
||||
"destination": "Назначение",
|
||||
"destinationGeoIP": "Геолокация назначения",
|
||||
|
||||
@@ -410,7 +410,7 @@
|
||||
"autoSetSystemDns": "自动设置系统DNS",
|
||||
"details": "{label}详情",
|
||||
"creationTime": "创建时间",
|
||||
"process": "进程",
|
||||
"progress": "进度",
|
||||
"host": "主机",
|
||||
"destination": "目标地址",
|
||||
"destinationGeoIP": "目标地理定位",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
45523
assets/data/GEOSITE.dat
45523
assets/data/GEOSITE.dat
File diff suppressed because one or more lines are too long
Binary file not shown.
35960
assets/data/GeoSite.dat
Normal file
35960
assets/data/GeoSite.dat
Normal file
File diff suppressed because one or more lines are too long
BIN
assets/data/geoip.metadb
Normal file
BIN
assets/data/geoip.metadb
Normal file
Binary file not shown.
Submodule core/Clash.Meta updated: 573489787b...52dfcca013
@@ -115,15 +115,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)
|
||||
|
||||
12
core/hub.go
12
core/hub.go
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/metacubex/mihomo/adapter"
|
||||
"github.com/metacubex/mihomo/adapter/outboundgroup"
|
||||
"github.com/metacubex/mihomo/common/observable"
|
||||
@@ -60,7 +61,6 @@ func handleStopListener() bool {
|
||||
defer runLock.Unlock()
|
||||
isRunning = false
|
||||
listener.StopListener()
|
||||
resolver.ResetConnection()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ func handleGetTraffic(onlyStatisticsProxy bool) string {
|
||||
}
|
||||
data, err := json.Marshal(traffic)
|
||||
if err != nil {
|
||||
log.Errorln("Error: %s", err)
|
||||
fmt.Println("Error:", err)
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
@@ -158,7 +158,7 @@ func handleGetTotalTraffic(onlyStatisticsProxy bool) string {
|
||||
}
|
||||
data, err := json.Marshal(traffic)
|
||||
if err != nil {
|
||||
log.Errorln("Error: %s", err)
|
||||
fmt.Println("Error:", err)
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
@@ -228,7 +228,7 @@ func handleGetConnections() string {
|
||||
snapshot := statistic.DefaultManager.Snapshot()
|
||||
data, err := json.Marshal(snapshot)
|
||||
if err != nil {
|
||||
log.Errorln("Error: %s", err)
|
||||
fmt.Println("Error:", err)
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
@@ -323,13 +323,13 @@ func handleUpdateGeoData(geoType string, geoName string, fn func(value string))
|
||||
fn(err.Error())
|
||||
return
|
||||
}
|
||||
case "GEOIP":
|
||||
case "GeoIp":
|
||||
err := updater.UpdateGeoIpWithPath(path)
|
||||
if err != nil {
|
||||
fn(err.Error())
|
||||
return
|
||||
}
|
||||
case "GEOSITE":
|
||||
case "GeoSite":
|
||||
err := updater.UpdateGeoSiteWithPath(path)
|
||||
if err != nil {
|
||||
fn(err.Error())
|
||||
|
||||
@@ -164,7 +164,7 @@ func (result ActionResult) send() {
|
||||
}
|
||||
invokeResult(result.callback, string(data))
|
||||
if result.Method != messageMethod {
|
||||
defer releaseObject(result.callback)
|
||||
releaseObject(result.callback)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,14 +94,14 @@ 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));
|
||||
}
|
||||
|
||||
@@ -125,8 +125,10 @@ class ApplicationState extends ConsumerState<Application> {
|
||||
builder: (_, child) {
|
||||
return AppEnvManager(
|
||||
child: _buildApp(
|
||||
child: _buildPlatformState(
|
||||
child: _buildState(child: _buildPlatformApp(child: child!)),
|
||||
_buildPlatformState(
|
||||
_buildState(
|
||||
AppSidebarContainer(child: _buildPlatformApp(child!)),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/models/models.dart';
|
||||
|
||||
import 'string.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
List<Group> computeSort({
|
||||
required List<Group> groups,
|
||||
@@ -106,5 +107,8 @@ List<Proxy> _sortOfDelay({
|
||||
}
|
||||
|
||||
List<Proxy> _sortOfName(List<Proxy> proxies) {
|
||||
return List.of(proxies)..sort((a, b) => a.name.compareTo(b.name));
|
||||
return List.of(proxies)..sort(
|
||||
(a, b) =>
|
||||
utils.sortByChar(utils.getPinyin(a.name), utils.getPinyin(b.name)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,10 +30,10 @@ const animateDuration = Duration(milliseconds: 100);
|
||||
const midDuration = Duration(milliseconds: 200);
|
||||
const commonDuration = Duration(milliseconds: 300);
|
||||
const defaultUpdateDuration = Duration(days: 1);
|
||||
const MMDB = 'GEOIP.metadb';
|
||||
const ASN = 'ASN.mmdb';
|
||||
const GEOIP = 'GEOIP.dat';
|
||||
const GEOSITE = 'GEOSITE.dat';
|
||||
const mmdbFileName = 'geoip.metadb';
|
||||
const asnFileName = 'ASN.mmdb';
|
||||
const geoIpFileName = 'GeoIP.dat';
|
||||
const geoSiteFileName = 'GeoSite.dat';
|
||||
final double kHeaderHeight = system.isDesktop
|
||||
? !system.isMacOS
|
||||
? 40
|
||||
|
||||
@@ -7,17 +7,28 @@ extension BuildContextExtension on BuildContext {
|
||||
return findAncestorStateOfType<CommonScaffoldState>();
|
||||
}
|
||||
|
||||
void showNotifier(String text) {
|
||||
Future<void>? showNotifier(String text) {
|
||||
return findAncestorStateOfType<MessageManagerState>()?.message(text);
|
||||
}
|
||||
|
||||
void showSnackBar(String message, {SnackBarAction? action}) {
|
||||
void showSnackBar(
|
||||
String message, {
|
||||
SnackBarAction? action,
|
||||
}) {
|
||||
final width = viewWidth;
|
||||
EdgeInsets margin;
|
||||
if (width < 600) {
|
||||
margin = const EdgeInsets.only(bottom: 16, right: 16, left: 16);
|
||||
margin = const EdgeInsets.only(
|
||||
bottom: 16,
|
||||
right: 16,
|
||||
left: 16,
|
||||
);
|
||||
} else {
|
||||
margin = EdgeInsets.only(bottom: 16, left: 16, right: width - 316);
|
||||
margin = EdgeInsets.only(
|
||||
bottom: 16,
|
||||
left: 16,
|
||||
right: width - 316,
|
||||
);
|
||||
}
|
||||
ScaffoldMessenger.of(this).showSnackBar(
|
||||
SnackBar(
|
||||
@@ -65,11 +76,8 @@ extension BuildContextExtension on BuildContext {
|
||||
class BackHandleInherited extends InheritedWidget {
|
||||
final Function handleBack;
|
||||
|
||||
const BackHandleInherited({
|
||||
super.key,
|
||||
required this.handleBack,
|
||||
required super.child,
|
||||
});
|
||||
const BackHandleInherited(
|
||||
{super.key, required this.handleBack, required super.child});
|
||||
|
||||
static BackHandleInherited? of(BuildContext context) =>
|
||||
context.dependOnInheritedWidgetOfExactType<BackHandleInherited>();
|
||||
|
||||
@@ -15,14 +15,12 @@ class Navigation {
|
||||
keep: false,
|
||||
icon: Icon(Icons.space_dashboard),
|
||||
label: PageLabel.dashboard,
|
||||
builder: (_) =>
|
||||
const DashboardView(key: GlobalObjectKey(PageLabel.dashboard)),
|
||||
builder: (_) => const DashboardView(),
|
||||
),
|
||||
NavigationItem(
|
||||
icon: const Icon(Icons.article),
|
||||
label: PageLabel.proxies,
|
||||
builder: (_) =>
|
||||
const ProxiesView(key: GlobalObjectKey(PageLabel.proxies)),
|
||||
builder: (_) => const ProxiesView(),
|
||||
modes: hasProxies
|
||||
? [NavigationItemMode.mobile, NavigationItemMode.desktop]
|
||||
: [],
|
||||
@@ -30,22 +28,19 @@ class Navigation {
|
||||
NavigationItem(
|
||||
icon: Icon(Icons.folder),
|
||||
label: PageLabel.profiles,
|
||||
builder: (_) =>
|
||||
const ProfilesView(key: GlobalObjectKey(PageLabel.profiles)),
|
||||
builder: (_) => const ProfilesView(),
|
||||
),
|
||||
NavigationItem(
|
||||
icon: Icon(Icons.view_timeline),
|
||||
label: PageLabel.requests,
|
||||
builder: (_) =>
|
||||
const RequestsView(key: GlobalObjectKey(PageLabel.requests)),
|
||||
builder: (_) => const RequestsView(),
|
||||
description: 'requestsDesc',
|
||||
modes: [NavigationItemMode.desktop, NavigationItemMode.more],
|
||||
),
|
||||
NavigationItem(
|
||||
icon: Icon(Icons.ballot),
|
||||
label: PageLabel.connections,
|
||||
builder: (_) =>
|
||||
const ConnectionsView(key: GlobalObjectKey(PageLabel.connections)),
|
||||
builder: (_) => const ConnectionsView(),
|
||||
description: 'connectionsDesc',
|
||||
modes: [NavigationItemMode.desktop, NavigationItemMode.more],
|
||||
),
|
||||
@@ -53,14 +48,13 @@ class Navigation {
|
||||
icon: Icon(Icons.storage),
|
||||
label: PageLabel.resources,
|
||||
description: 'resourcesDesc',
|
||||
builder: (_) =>
|
||||
const ResourcesView(key: GlobalObjectKey(PageLabel.resources)),
|
||||
builder: (_) => const ResourcesView(),
|
||||
modes: [NavigationItemMode.more],
|
||||
),
|
||||
NavigationItem(
|
||||
icon: const Icon(Icons.adb),
|
||||
label: PageLabel.logs,
|
||||
builder: (_) => const LogsView(key: GlobalObjectKey(PageLabel.logs)),
|
||||
builder: (_) => const LogsView(),
|
||||
description: 'logsDesc',
|
||||
modes: openLogs
|
||||
? [NavigationItemMode.desktop, NavigationItemMode.more]
|
||||
@@ -69,7 +63,7 @@ class Navigation {
|
||||
NavigationItem(
|
||||
icon: Icon(Icons.construction),
|
||||
label: PageLabel.tools,
|
||||
builder: (_) => const ToolsView(key: GlobalObjectKey(PageLabel.tools)),
|
||||
builder: (_) => const ToolsView(),
|
||||
modes: [NavigationItemMode.desktop, NavigationItemMode.mobile],
|
||||
),
|
||||
];
|
||||
|
||||
@@ -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) {
|
||||
@@ -177,11 +178,11 @@ 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;
|
||||
@@ -227,7 +228,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,7 +237,7 @@ 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];
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -73,10 +73,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(coreStatusProvider.notifier).value = CoreStatus.connected;
|
||||
_ref.read(initProvider.notifier).value = true;
|
||||
if (_ref.read(isStartProvider)) {
|
||||
await globalState.handleStart();
|
||||
@@ -528,9 +529,11 @@ class AppController {
|
||||
|
||||
Future<void> init() async {
|
||||
FlutterError.onError = (details) {
|
||||
commonPrint.log(
|
||||
'exception: ${details.exception} stack: ${details.stack}',
|
||||
);
|
||||
if (kDebugMode) {
|
||||
commonPrint.log(
|
||||
'exception: ${details.exception} stack: ${details.stack}',
|
||||
);
|
||||
}
|
||||
};
|
||||
updateTray(true);
|
||||
autoUpdateProfiles();
|
||||
@@ -543,15 +546,6 @@ 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;
|
||||
@@ -561,6 +555,10 @@ class AppController {
|
||||
return;
|
||||
}
|
||||
_ref.read(coreStatusProvider.notifier).value = CoreStatus.connected;
|
||||
await service?.syncAndroidState(globalState.getAndroidState());
|
||||
await _initCore();
|
||||
await _initStatus();
|
||||
_ref.read(initProvider.notifier).value = true;
|
||||
}
|
||||
|
||||
Future<void> _initStatus() async {
|
||||
@@ -620,7 +618,6 @@ class AppController {
|
||||
|
||||
Future<bool> showDisclaimer() async {
|
||||
return await globalState.showCommonDialog<bool>(
|
||||
context: context,
|
||||
dismissible: false,
|
||||
child: CommonDialog(
|
||||
title: appLocalizations.disclaimer,
|
||||
|
||||
@@ -40,7 +40,12 @@ class CoreController {
|
||||
if (!isExists) {
|
||||
await homeDir.create(recursive: true);
|
||||
}
|
||||
const geoFileNameList = [MMDB, GEOIP, GEOSITE, ASN];
|
||||
const geoFileNameList = [
|
||||
mmdbFileName,
|
||||
geoIpFileName,
|
||||
geoSiteFileName,
|
||||
asnFileName,
|
||||
];
|
||||
try {
|
||||
for (final geoFileName in geoFileNameList) {
|
||||
final geoFile = File(join(homePath, geoFileName));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ class CoreLib extends CoreHandlerInterface {
|
||||
|
||||
@override
|
||||
Future<bool> shutdown() async {
|
||||
await service?.shutdown();
|
||||
_connectedCompleter = Completer();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -73,9 +73,7 @@ class CoreService extends CoreHandlerInterface {
|
||||
}
|
||||
|
||||
void _handleInvokeCrashEvent() {
|
||||
coreEventManager.sendEvent(
|
||||
CoreEvent(type: CoreEventType.crash, data: 'socket done'),
|
||||
);
|
||||
coreEventManager.sendEvent(CoreEvent(type: CoreEventType.crash));
|
||||
}
|
||||
|
||||
Future<void> start() async {
|
||||
@@ -100,7 +98,6 @@ class CoreService extends CoreHandlerInterface {
|
||||
commonPrint.log(error);
|
||||
}
|
||||
});
|
||||
await _socketCompleter.future;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -127,9 +124,9 @@ class CoreService extends CoreHandlerInterface {
|
||||
|
||||
Future<void> _destroySocket() async {
|
||||
if (_socketCompleter.isCompleted) {
|
||||
final socket = await _socketCompleter.future;
|
||||
final lastSocket = await _socketCompleter.future;
|
||||
_socketCompleter = Completer();
|
||||
socket.close();
|
||||
lastSocket.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,9 +177,7 @@ class CoreService extends CoreHandlerInterface {
|
||||
}
|
||||
|
||||
@override
|
||||
Future get connected {
|
||||
return _socketCompleter.future;
|
||||
}
|
||||
Future get connected => _socketCompleter.future;
|
||||
}
|
||||
|
||||
final coreService = system.isDesktop ? CoreService() : null;
|
||||
|
||||
@@ -521,7 +521,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Please press the keyboard.",
|
||||
),
|
||||
"preview": MessageLookupByLibrary.simpleMessage("Preview"),
|
||||
"process": MessageLookupByLibrary.simpleMessage("Process"),
|
||||
"profile": MessageLookupByLibrary.simpleMessage("Profile"),
|
||||
"profileAutoUpdateIntervalInvalidValidationDesc":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
@@ -548,6 +547,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"profiles": MessageLookupByLibrary.simpleMessage("Profiles"),
|
||||
"profilesSort": MessageLookupByLibrary.simpleMessage("Profiles sort"),
|
||||
"progress": MessageLookupByLibrary.simpleMessage("Progress"),
|
||||
"project": MessageLookupByLibrary.simpleMessage("Project"),
|
||||
"providers": MessageLookupByLibrary.simpleMessage("Providers"),
|
||||
"proxies": MessageLookupByLibrary.simpleMessage("Proxies"),
|
||||
|
||||
@@ -395,7 +395,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"preferH3Desc": MessageLookupByLibrary.simpleMessage("DOHのHTTP/3を優先使用"),
|
||||
"pressKeyboard": MessageLookupByLibrary.simpleMessage("キーボードを押してください"),
|
||||
"preview": MessageLookupByLibrary.simpleMessage("プレビュー"),
|
||||
"process": MessageLookupByLibrary.simpleMessage("プロセス"),
|
||||
"profile": MessageLookupByLibrary.simpleMessage("プロファイル"),
|
||||
"profileAutoUpdateIntervalInvalidValidationDesc":
|
||||
MessageLookupByLibrary.simpleMessage("有効な間隔形式を入力してください"),
|
||||
@@ -418,6 +417,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"profiles": MessageLookupByLibrary.simpleMessage("プロファイル一覧"),
|
||||
"profilesSort": MessageLookupByLibrary.simpleMessage("プロファイルの並び替え"),
|
||||
"progress": MessageLookupByLibrary.simpleMessage("進捗"),
|
||||
"project": MessageLookupByLibrary.simpleMessage("プロジェクト"),
|
||||
"providers": MessageLookupByLibrary.simpleMessage("プロバイダー"),
|
||||
"proxies": MessageLookupByLibrary.simpleMessage("プロキシ"),
|
||||
|
||||
@@ -548,7 +548,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Пожалуйста, нажмите клавишу.",
|
||||
),
|
||||
"preview": MessageLookupByLibrary.simpleMessage("Предпросмотр"),
|
||||
"process": MessageLookupByLibrary.simpleMessage("процесс"),
|
||||
"profile": MessageLookupByLibrary.simpleMessage("Профиль"),
|
||||
"profileAutoUpdateIntervalInvalidValidationDesc":
|
||||
MessageLookupByLibrary.simpleMessage(
|
||||
@@ -575,6 +574,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"profiles": MessageLookupByLibrary.simpleMessage("Профили"),
|
||||
"profilesSort": MessageLookupByLibrary.simpleMessage("Сортировка профилей"),
|
||||
"progress": MessageLookupByLibrary.simpleMessage("Прогресс"),
|
||||
"project": MessageLookupByLibrary.simpleMessage("Проект"),
|
||||
"providers": MessageLookupByLibrary.simpleMessage("Провайдеры"),
|
||||
"proxies": MessageLookupByLibrary.simpleMessage("Прокси"),
|
||||
|
||||
@@ -347,7 +347,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"preferH3Desc": MessageLookupByLibrary.simpleMessage("优先使用DOH的http/3"),
|
||||
"pressKeyboard": MessageLookupByLibrary.simpleMessage("请按下按键"),
|
||||
"preview": MessageLookupByLibrary.simpleMessage("预览"),
|
||||
"process": MessageLookupByLibrary.simpleMessage("进程"),
|
||||
"profile": MessageLookupByLibrary.simpleMessage("配置"),
|
||||
"profileAutoUpdateIntervalInvalidValidationDesc":
|
||||
MessageLookupByLibrary.simpleMessage("请输入有效间隔时间格式"),
|
||||
@@ -368,6 +367,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"profiles": MessageLookupByLibrary.simpleMessage("配置"),
|
||||
"profilesSort": MessageLookupByLibrary.simpleMessage("配置排序"),
|
||||
"progress": MessageLookupByLibrary.simpleMessage("进度"),
|
||||
"project": MessageLookupByLibrary.simpleMessage("项目"),
|
||||
"providers": MessageLookupByLibrary.simpleMessage("提供者"),
|
||||
"proxies": MessageLookupByLibrary.simpleMessage("代理"),
|
||||
|
||||
@@ -3159,9 +3159,9 @@ class AppLocalizations {
|
||||
);
|
||||
}
|
||||
|
||||
/// `Process`
|
||||
String get process {
|
||||
return Intl.message('Process', name: 'process', desc: '', args: []);
|
||||
/// `Progress`
|
||||
String get progress {
|
||||
return Intl.message('Progress', name: 'progress', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `Host`
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -60,6 +61,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 +158,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
|
||||
@@ -184,110 +181,76 @@ class AppSidebarContainer extends ConsumerWidget {
|
||||
final showLabel = ref.watch(appSettingProvider).showLabel;
|
||||
return Row(
|
||||
children: [
|
||||
_buildBackground(
|
||||
context: context,
|
||||
child: SafeArea(
|
||||
child: Stack(
|
||||
alignment: Alignment.topRight,
|
||||
children: [
|
||||
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: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: NavigationRail(
|
||||
scrollable: true,
|
||||
minExtendedWidth: 200,
|
||||
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: false,
|
||||
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),
|
||||
Stack(
|
||||
alignment: Alignment.topRight,
|
||||
children: [
|
||||
_buildBackground(
|
||||
context: context,
|
||||
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)),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onDestinationSelected: (index) {
|
||||
globalState.appController.toPage(
|
||||
navigationItems[index].label,
|
||||
);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.menu,
|
||||
color: context.colorScheme.onSurfaceVariant,
|
||||
},
|
||||
extended: false,
|
||||
selectedIndex: currentIndex,
|
||||
labelType: showLabel
|
||||
? NavigationRailLabelType.all
|
||||
: NavigationRailLabelType.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
_buildLoading(),
|
||||
],
|
||||
),
|
||||
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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: ClipRect(
|
||||
child: LayoutBuilder(
|
||||
builder: (_, constraints) {
|
||||
_updateSideBarWidth(ref, constraints.maxWidth);
|
||||
return child;
|
||||
},
|
||||
),
|
||||
),
|
||||
_buildLoading(),
|
||||
],
|
||||
),
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:collection';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
@@ -18,9 +17,8 @@ class MessageManager extends StatefulWidget {
|
||||
|
||||
class MessageManagerState extends State<MessageManager> {
|
||||
final _messagesNotifier = ValueNotifier<List<CommonMessage>>([]);
|
||||
final _bufferMessages = Queue<CommonMessage>();
|
||||
final _activeTimers = <String, Timer>{};
|
||||
bool _isDisplayingMessage = false;
|
||||
final List<CommonMessage> _bufferMessages = [];
|
||||
bool _pushing = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -30,48 +28,38 @@ class MessageManagerState extends State<MessageManager> {
|
||||
@override
|
||||
void dispose() {
|
||||
_messagesNotifier.dispose();
|
||||
for (final timer in _activeTimers.values) {
|
||||
timer.cancel();
|
||||
}
|
||||
_activeTimers.clear();
|
||||
_bufferMessages.clear();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void message(String text) {
|
||||
Future<void> message(String text) async {
|
||||
final commonMessage = CommonMessage(id: utils.uuidV4, text: text);
|
||||
commonPrint.log(text);
|
||||
_bufferMessages.add(commonMessage);
|
||||
commonPrint.log('message: $text');
|
||||
_processQueue();
|
||||
await _showMessage();
|
||||
}
|
||||
|
||||
void _cancelMessage(String id) {
|
||||
_bufferMessages.removeWhere((msg) => msg.id == id);
|
||||
if (_activeTimers.containsKey(id)) {
|
||||
_removeMessage(id);
|
||||
}
|
||||
}
|
||||
|
||||
void _processQueue() {
|
||||
if (_isDisplayingMessage || _bufferMessages.isEmpty) {
|
||||
Future<void> _showMessage() async {
|
||||
if (_pushing == true) {
|
||||
return;
|
||||
}
|
||||
_isDisplayingMessage = true;
|
||||
final message = _bufferMessages.removeFirst();
|
||||
_messagesNotifier.value = List.from(_messagesNotifier.value)..add(message);
|
||||
final timer = Timer(message.duration, () {
|
||||
_removeMessage(message.id);
|
||||
});
|
||||
_activeTimers[message.id] = timer;
|
||||
_pushing = true;
|
||||
while (_bufferMessages.isNotEmpty) {
|
||||
final commonMessage = _bufferMessages.removeAt(0);
|
||||
_messagesNotifier.value = List.from(_messagesNotifier.value)
|
||||
..add(commonMessage);
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
Future.delayed(commonMessage.duration, () {
|
||||
_handleRemove(commonMessage);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _removeMessage(String id) {
|
||||
_activeTimers.remove(id)?.cancel();
|
||||
final currentMessages = List<CommonMessage>.from(_messagesNotifier.value);
|
||||
currentMessages.removeWhere((msg) => msg.id == id);
|
||||
_messagesNotifier.value = currentMessages;
|
||||
_isDisplayingMessage = false;
|
||||
_processQueue();
|
||||
Future<void> _handleRemove(CommonMessage commonMessage) async {
|
||||
_messagesNotifier.value = List<CommonMessage>.from(_messagesNotifier.value)
|
||||
..remove(commonMessage);
|
||||
if (_bufferMessages.isEmpty) {
|
||||
_pushing = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -95,45 +83,35 @@ class MessageManagerState extends State<MessageManager> {
|
||||
: LayoutBuilder(
|
||||
key: Key(messages.last.id),
|
||||
builder: (_, constraints) {
|
||||
return Dismissible(
|
||||
key: ValueKey(messages.last.id),
|
||||
onDismissed: (_) {
|
||||
_cancelMessage(messages.last.id);
|
||||
},
|
||||
child: Card(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(14),
|
||||
),
|
||||
return Card(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12.0),
|
||||
),
|
||||
elevation: 10,
|
||||
color: context.colorScheme.surfaceContainerHigh,
|
||||
child: Container(
|
||||
width: min(constraints.maxWidth, 500),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
messages.last.text,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
_cancelMessage(messages.last.id);
|
||||
},
|
||||
child: Text(appLocalizations.cancel),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
elevation: 10,
|
||||
color: context.colorScheme.surfaceContainerHigh,
|
||||
child: Container(
|
||||
width: min(constraints.maxWidth, 500),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 10,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(child: Text(messages.last.text)),
|
||||
IconButton(
|
||||
visualDensity: VisualDensity.compact,
|
||||
iconSize: 18,
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () {
|
||||
_handleRemove(messages.last);
|
||||
},
|
||||
icon: Icon(Icons.close),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5457,7 +5457,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 +5468,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 +5488,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 +5505,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 +5594,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 +5615,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 +5635,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 +5650,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 +5660,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 +5672,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 +5692,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 +5709,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,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
@@ -159,20 +160,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,7 +224,7 @@ abstract class ClashConfigState with _$ClashConfigState {
|
||||
abstract class DashboardState with _$DashboardState {
|
||||
const factory DashboardState({
|
||||
required List<DashboardWidget> dashboardWidgets,
|
||||
required double contentWidth,
|
||||
required double viewWidth,
|
||||
}) = _DashboardState;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/manager/app_manager.dart';
|
||||
import 'package:fl_clash/providers/providers.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:fl_clash/widgets/widgets.dart';
|
||||
@@ -16,86 +15,84 @@ class HomePage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return HomeBackScopeContainer(
|
||||
child: AppSidebarContainer(
|
||||
child: Material(
|
||||
color: context.colorScheme.surface,
|
||||
child: Consumer(
|
||||
builder: (context, ref, _) {
|
||||
final state = ref.watch(navigationStateProvider);
|
||||
final isMobile = state.viewMode == ViewMode.mobile;
|
||||
final navigationItems = state.navigationItems;
|
||||
final pageView = _HomePageView(
|
||||
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: (_) {},
|
||||
),
|
||||
);
|
||||
return view;
|
||||
},
|
||||
);
|
||||
final currentIndex = state.currentIndex;
|
||||
final bottomNavigationBar = NavigationBarTheme(
|
||||
data: _NavigationBarDefaultsM3(context),
|
||||
child: NavigationBar(
|
||||
destinations: navigationItems
|
||||
.map(
|
||||
(e) => NavigationDestination(
|
||||
icon: e.icon,
|
||||
label: Intl.message(e.label.name),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onDestinationSelected: (index) {
|
||||
globalState.appController.toPage(
|
||||
navigationItems[index].label,
|
||||
);
|
||||
},
|
||||
selectedIndex: currentIndex,
|
||||
),
|
||||
);
|
||||
if (isMobile) {
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: globalState.appState.systemUiOverlayStyle.copyWith(
|
||||
systemNavigationBarColor:
|
||||
context.colorScheme.surfaceContainer,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: MediaQuery.removePadding(
|
||||
removeTop: false,
|
||||
removeBottom: true,
|
||||
removeLeft: true,
|
||||
removeRight: true,
|
||||
context: context,
|
||||
child: pageView,
|
||||
return HomeBackScope(
|
||||
child: Material(
|
||||
color: context.colorScheme.surface,
|
||||
child: Consumer(
|
||||
builder: (context, ref, _) {
|
||||
final state = ref.watch(navigationStateProvider);
|
||||
final isMobile = state.viewMode == ViewMode.mobile;
|
||||
final navigationItems = state.navigationItems;
|
||||
final pageView = _HomePageView(
|
||||
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: (_) {},
|
||||
),
|
||||
);
|
||||
return view;
|
||||
},
|
||||
);
|
||||
final currentIndex = state.currentIndex;
|
||||
final bottomNavigationBar = NavigationBarTheme(
|
||||
data: _NavigationBarDefaultsM3(context),
|
||||
child: NavigationBar(
|
||||
destinations: navigationItems
|
||||
.map(
|
||||
(e) => NavigationDestination(
|
||||
icon: e.icon,
|
||||
label: Intl.message(e.label.name),
|
||||
),
|
||||
MediaQuery.removePadding(
|
||||
removeTop: true,
|
||||
removeBottom: false,
|
||||
)
|
||||
.toList(),
|
||||
onDestinationSelected: (index) {
|
||||
globalState.appController.toPage(
|
||||
navigationItems[index].label,
|
||||
);
|
||||
},
|
||||
selectedIndex: currentIndex,
|
||||
),
|
||||
);
|
||||
if (isMobile) {
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: globalState.appState.systemUiOverlayStyle.copyWith(
|
||||
systemNavigationBarColor:
|
||||
context.colorScheme.surfaceContainer,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: MediaQuery.removePadding(
|
||||
removeTop: false,
|
||||
removeBottom: true,
|
||||
removeLeft: true,
|
||||
removeRight: true,
|
||||
context: context,
|
||||
child: bottomNavigationBar,
|
||||
child: pageView,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return pageView;
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
MediaQuery.removePadding(
|
||||
removeTop: true,
|
||||
removeBottom: false,
|
||||
removeLeft: true,
|
||||
removeRight: true,
|
||||
context: context,
|
||||
child: bottomNavigationBar,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return pageView;
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -246,27 +243,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
@@ -89,10 +88,6 @@ class Service {
|
||||
return await methodChannel.invokeMethod<String>('init') ?? '';
|
||||
}
|
||||
|
||||
Future<bool> shutdown() async {
|
||||
return await methodChannel.invokeMethod<bool>('shutdown') ?? true;
|
||||
}
|
||||
|
||||
Future<DateTime?> getRunTime() async {
|
||||
final ms = await methodChannel.invokeMethod<int>('getRunTime') ?? 0;
|
||||
if (ms == 0) {
|
||||
|
||||
@@ -185,19 +185,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;
|
||||
|
||||
@@ -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._();
|
||||
|
||||
|
||||
@@ -392,47 +392,6 @@ final class NavigationStateProvider
|
||||
|
||||
String _$navigationStateHash() => r'657dc47ecc35ba0807b58cb37e7f1baa14f6c2f9';
|
||||
|
||||
@ProviderFor(contentWidth)
|
||||
const contentWidthProvider = ContentWidthProvider._();
|
||||
|
||||
final class ContentWidthProvider
|
||||
extends $FunctionalProvider<double, double, double>
|
||||
with $Provider<double> {
|
||||
const ContentWidthProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'contentWidthProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$contentWidthHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<double> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
double create(Ref ref) {
|
||||
return contentWidth(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(double value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<double>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$contentWidthHash() => r'9ac0dc2bcdc957160f59d6065cd7f846f41a95b1';
|
||||
|
||||
@ProviderFor(dashboardState)
|
||||
const dashboardStateProvider = DashboardStateProvider._();
|
||||
|
||||
@@ -472,7 +431,7 @@ final class DashboardStateProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$dashboardStateHash() => r'e8616e327c1b96658d917e4e4950f70ecb099d85';
|
||||
String _$dashboardStateHash() => r'4434206df2753d7df9eb5223c07ddead4ed170fa';
|
||||
|
||||
@ProviderFor(proxiesActionsState)
|
||||
const proxiesActionsStateProvider = ProxiesActionsStateProvider._();
|
||||
@@ -616,7 +575,7 @@ final class ProfilesSelectorStateProvider
|
||||
}
|
||||
|
||||
String _$profilesSelectorStateHash() =>
|
||||
r'da4a4382d7054dfe4010e44e55368d31ec805536';
|
||||
r'aac2deee6e747eceaf62cb5f279ec99ce9227a5a';
|
||||
|
||||
@ProviderFor(filterGroupsState)
|
||||
const filterGroupsStateProvider = FilterGroupsStateFamily._();
|
||||
@@ -1551,7 +1510,7 @@ final class GetProxiesColumnsProvider extends $FunctionalProvider<int, int, int>
|
||||
}
|
||||
}
|
||||
|
||||
String _$getProxiesColumnsHash() => r'd5340932d4812727caa670065bce30450f1c4da5';
|
||||
String _$getProxiesColumnsHash() => r'725066b5fc21f590a4c2656a1fd5e14ab7079079';
|
||||
|
||||
@ProviderFor(realSelectedProxyState)
|
||||
const realSelectedProxyStateProvider = RealSelectedProxyStateFamily._();
|
||||
|
||||
@@ -192,22 +192,15 @@ NavigationState navigationState(Ref ref) {
|
||||
);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
double contentWidth(Ref ref) {
|
||||
final viewWidth = ref.watch(viewWidthProvider);
|
||||
final sideWidth = ref.watch(sideWidthProvider);
|
||||
return viewWidth - sideWidth;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
DashboardState dashboardState(Ref ref) {
|
||||
final dashboardWidgets = ref.watch(
|
||||
appSettingProvider.select((state) => state.dashboardWidgets),
|
||||
);
|
||||
final contentWidth = ref.watch(contentWidthProvider);
|
||||
final viewWidth = ref.watch(viewWidthProvider);
|
||||
return DashboardState(
|
||||
dashboardWidgets: dashboardWidgets,
|
||||
contentWidth: contentWidth,
|
||||
viewWidth: viewWidth,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -241,7 +234,7 @@ ProfilesSelectorState profilesSelectorState(Ref ref) {
|
||||
final currentProfileId = ref.watch(currentProfileIdProvider);
|
||||
final profiles = ref.watch(profilesProvider);
|
||||
final columns = ref.watch(
|
||||
contentWidthProvider.select((state) => utils.getProfilesColumns(state)),
|
||||
viewWidthProvider.select((state) => utils.getProfilesColumns(state)),
|
||||
);
|
||||
return ProfilesSelectorState(
|
||||
profiles: profiles,
|
||||
@@ -460,11 +453,11 @@ Profile? currentProfile(Ref ref) {
|
||||
|
||||
@riverpod
|
||||
int getProxiesColumns(Ref ref) {
|
||||
final contentWidth = ref.watch(contentWidthProvider);
|
||||
final viewWidth = ref.watch(viewWidthProvider);
|
||||
final proxiesLayout = ref.watch(
|
||||
proxiesStyleSettingProvider.select((state) => state.layout),
|
||||
);
|
||||
return utils.getProxiesColumns(contentWidth, proxiesLayout);
|
||||
return utils.getProxiesColumns(viewWidth, proxiesLayout);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
|
||||
@@ -47,7 +47,6 @@ class GlobalState {
|
||||
final navigatorKey = GlobalKey<NavigatorState>();
|
||||
AppController? _appController;
|
||||
bool isInit = false;
|
||||
bool isUserDisconnected = false;
|
||||
|
||||
bool get isStart => startTime != null && startTime!.isBeforeNow;
|
||||
|
||||
@@ -183,14 +182,12 @@ class GlobalState {
|
||||
}
|
||||
|
||||
Future<bool?> showMessage({
|
||||
required InlineSpan message,
|
||||
BuildContext? context,
|
||||
String? title,
|
||||
required InlineSpan message,
|
||||
String? confirmText,
|
||||
bool cancelable = true,
|
||||
}) async {
|
||||
return await showCommonDialog<bool>(
|
||||
context: context,
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
return CommonDialog(
|
||||
@@ -248,12 +245,10 @@ class GlobalState {
|
||||
|
||||
Future<T?> showCommonDialog<T>({
|
||||
required Widget child,
|
||||
BuildContext? context,
|
||||
bool dismissible = true,
|
||||
}) async {
|
||||
return await showModal<T>(
|
||||
useRootNavigator: false,
|
||||
context: context ?? globalState.navigatorKey.currentContext!,
|
||||
context: navigatorKey.currentState!.context,
|
||||
configuration: FadeScaleTransitionConfiguration(
|
||||
barrierColor: Colors.black38,
|
||||
barrierDismissible: dismissible,
|
||||
|
||||
@@ -202,7 +202,7 @@ class TrackerInfoDetailView extends StatelessWidget {
|
||||
return rule;
|
||||
}
|
||||
|
||||
String _getProcessText() {
|
||||
String _getProgressText() {
|
||||
final process = trackerInfo.metadata.process;
|
||||
final uid = trackerInfo.metadata.uid;
|
||||
if (uid != 0) {
|
||||
@@ -297,8 +297,8 @@ class TrackerInfoDetailView extends StatelessWidget {
|
||||
title: appLocalizations.creationTime,
|
||||
desc: trackerInfo.start.showFull,
|
||||
),
|
||||
if (_getProcessText().isNotEmpty)
|
||||
_buildItem(title: appLocalizations.process, desc: _getProcessText()),
|
||||
if (_getProgressText().isNotEmpty)
|
||||
_buildItem(title: appLocalizations.progress, desc: _getProgressText()),
|
||||
_buildItem(
|
||||
title: appLocalizations.networkType,
|
||||
desc: trackerInfo.metadata.network,
|
||||
|
||||
@@ -65,81 +65,61 @@ class _DashboardViewState extends ConsumerState<DashboardView> {
|
||||
final coreStatus = ref.watch(coreStatusProvider);
|
||||
return Tooltip(
|
||||
message: appLocalizations.coreStatus,
|
||||
child: FadeScaleBox(
|
||||
alignment: Alignment.centerRight,
|
||||
child: coreStatus == CoreStatus.connected
|
||||
? IconButton.filled(
|
||||
visualDensity: VisualDensity.compact,
|
||||
iconSize: 20,
|
||||
padding: EdgeInsets.zero,
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: Colors.greenAccent,
|
||||
foregroundColor: switch (Theme.brightnessOf(
|
||||
context,
|
||||
)) {
|
||||
Brightness.light =>
|
||||
context.colorScheme.onSurfaceVariant,
|
||||
Brightness.dark =>
|
||||
context.colorScheme.onPrimaryFixedVariant,
|
||||
},
|
||||
child: FilledButton.icon(
|
||||
onPressed: coreStatus == CoreStatus.connecting
|
||||
? () {}
|
||||
: _handleConnection,
|
||||
style: FilledButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
backgroundColor: switch (coreStatus) {
|
||||
CoreStatus.connecting => null,
|
||||
CoreStatus.connected => Colors.greenAccent,
|
||||
CoreStatus.disconnected => context.colorScheme.error,
|
||||
},
|
||||
foregroundColor: switch (coreStatus) {
|
||||
CoreStatus.connecting => null,
|
||||
CoreStatus.connected => switch (Theme.brightnessOf(
|
||||
context,
|
||||
)) {
|
||||
Brightness.light => context.colorScheme.onSurfaceVariant,
|
||||
Brightness.dark => null,
|
||||
},
|
||||
CoreStatus.disconnected => context.colorScheme.onError,
|
||||
},
|
||||
),
|
||||
icon: SizedBox(
|
||||
height: globalState.measure.bodyMediumHeight,
|
||||
width: globalState.measure.bodyMediumHeight,
|
||||
child: FadeRotationScaleBox(
|
||||
child: switch (coreStatus) {
|
||||
CoreStatus.connecting => Padding(
|
||||
padding: EdgeInsets.all(2),
|
||||
child: CircularProgressIndicator(
|
||||
key: ValueKey(CoreStatus.connecting),
|
||||
strokeWidth: 3,
|
||||
color: context.colorScheme.onPrimary,
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
onPressed: _handleConnection,
|
||||
icon: Icon(Icons.check, fontWeight: FontWeight.w900),
|
||||
)
|
||||
: FilledButton.icon(
|
||||
key: ValueKey(coreStatus),
|
||||
onPressed: _handleConnection,
|
||||
style: FilledButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
backgroundColor: switch (coreStatus) {
|
||||
CoreStatus.connecting => null,
|
||||
CoreStatus.connected => Colors.greenAccent,
|
||||
CoreStatus.disconnected =>
|
||||
context.colorScheme.error,
|
||||
},
|
||||
foregroundColor: switch (coreStatus) {
|
||||
CoreStatus.connecting => null,
|
||||
CoreStatus.connected => switch (Theme.brightnessOf(
|
||||
context,
|
||||
)) {
|
||||
Brightness.light =>
|
||||
context.colorScheme.onSurfaceVariant,
|
||||
Brightness.dark => null,
|
||||
},
|
||||
CoreStatus.disconnected =>
|
||||
context.colorScheme.onError,
|
||||
},
|
||||
),
|
||||
icon: SizedBox(
|
||||
height: globalState.measure.bodyMediumHeight,
|
||||
width: globalState.measure.bodyMediumHeight,
|
||||
child: switch (coreStatus) {
|
||||
CoreStatus.connecting => Padding(
|
||||
padding: EdgeInsets.all(2),
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 3,
|
||||
color: context.colorScheme.onPrimary,
|
||||
backgroundColor: Colors.transparent,
|
||||
),
|
||||
),
|
||||
CoreStatus.connected => Icon(
|
||||
Icons.check_sharp,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
CoreStatus.disconnected => Icon(
|
||||
Icons.restart_alt_sharp,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
},
|
||||
),
|
||||
label: Text(switch (coreStatus) {
|
||||
CoreStatus.connecting => appLocalizations.connecting,
|
||||
CoreStatus.connected => appLocalizations.connected,
|
||||
CoreStatus.disconnected =>
|
||||
appLocalizations.disconnected,
|
||||
}),
|
||||
),
|
||||
CoreStatus.connected => Icon(
|
||||
Icons.check_sharp,
|
||||
fontWeight: FontWeight.w900,
|
||||
key: ValueKey(CoreStatus.connected),
|
||||
),
|
||||
CoreStatus.disconnected => Icon(
|
||||
Icons.restart_alt_sharp,
|
||||
fontWeight: FontWeight.w900,
|
||||
key: ValueKey(CoreStatus.disconnected),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
label: Text(switch (coreStatus) {
|
||||
CoreStatus.connecting => appLocalizations.connecting,
|
||||
CoreStatus.connected => appLocalizations.connected,
|
||||
CoreStatus.disconnected => appLocalizations.disconnected,
|
||||
}),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -227,7 +207,7 @@ class _DashboardViewState extends ConsumerState<DashboardView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final dashboardState = ref.watch(dashboardStateProvider);
|
||||
final columns = max(4 * ((dashboardState.contentWidth / 300).ceil()), 8);
|
||||
final columns = max(4 * ((dashboardState.viewWidth / 320).ceil()), 8);
|
||||
final spacing = 16.ap;
|
||||
final children = [
|
||||
...dashboardState.dashboardWidgets
|
||||
@@ -276,7 +256,7 @@ class _DashboardViewState extends ConsumerState<DashboardView> {
|
||||
_handleSave();
|
||||
},
|
||||
),
|
||||
onPop: (context) {
|
||||
onPop: () {
|
||||
_handleUpdateIsEdit();
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -108,75 +108,56 @@ class OutboundModeV2 extends StatelessWidget {
|
||||
Mode.global => globalState.theme.darken3PrimaryContainer,
|
||||
Mode.direct => context.colorScheme.tertiaryContainer,
|
||||
};
|
||||
return LayoutBuilder(
|
||||
builder: (_, constraints) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(12),
|
||||
constraints: BoxConstraints.expand(),
|
||||
child: CommonTabBar<Mode>(
|
||||
children: Map.fromEntries(
|
||||
Mode.values.map(
|
||||
(item) => MapEntry(
|
||||
item,
|
||||
Container(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(),
|
||||
height: height - 8.ap - 24,
|
||||
padding: EdgeInsets.all(4),
|
||||
child: Text(
|
||||
Intl.message(item.name),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleSmall
|
||||
?.adjustSize(1)
|
||||
.copyWith(
|
||||
color: item == mode
|
||||
? _getTextColor(context, item)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
return Container(
|
||||
constraints: BoxConstraints.expand(),
|
||||
padding: EdgeInsets.all(4.ap),
|
||||
color: thumbColor.opacity38,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: context.colorScheme.surfaceContainer,
|
||||
),
|
||||
padding: EdgeInsets.all(12.ap),
|
||||
child: LayoutBuilder(
|
||||
builder: (_, constraints) {
|
||||
return CommonTabBar<Mode>(
|
||||
children: Map.fromEntries(
|
||||
Mode.values.map(
|
||||
(item) => MapEntry(
|
||||
item,
|
||||
Container(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(),
|
||||
height: constraints.maxHeight,
|
||||
padding: EdgeInsets.all(4),
|
||||
child: Text(
|
||||
Intl.message(item.name),
|
||||
style: Theme.of(context).textTheme.titleSmall
|
||||
?.adjustSize(1)
|
||||
.copyWith(
|
||||
color: item == mode
|
||||
? _getTextColor(context, item)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 0),
|
||||
groupValue: mode,
|
||||
onValueChanged: (value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
globalState.appController.changeMode(value);
|
||||
},
|
||||
thumbColor: thumbColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
color: thumbColor.opacity50,
|
||||
height: 8.ap,
|
||||
width: constraints.maxWidth,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Container(
|
||||
// width: (constraints.maxWidth - 32) / 3,
|
||||
// height: 3,
|
||||
// decoration: BoxDecoration(
|
||||
// color: _getTextColor(context, mode),
|
||||
// borderRadius: BorderRadius.circular(2),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
padding: EdgeInsets.symmetric(horizontal: 0),
|
||||
groupValue: mode,
|
||||
onValueChanged: (value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
globalState.appController.changeMode(value);
|
||||
},
|
||||
thumbColor: thumbColor,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -306,7 +306,7 @@ class _EditProfileViewState extends State<EditProfileView> {
|
||||
),
|
||||
];
|
||||
return CommonPopScope(
|
||||
onPop: (context) {
|
||||
onPop: () {
|
||||
if (fileData == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ class _OverrideProfileViewState extends ConsumerState<OverrideProfileView> {
|
||||
return SizedBox();
|
||||
}
|
||||
return CommonPopScope(
|
||||
onPop: (context) async {
|
||||
onPop: () async {
|
||||
if (equals) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ class ProfileItem extends StatelessWidget {
|
||||
SubscriptionInfoView(subscriptionInfo: subscriptionInfo),
|
||||
Text(
|
||||
profile.lastUpdateDate?.lastUpdateTimeDesc ?? '',
|
||||
style: context.textTheme.labelMedium?.toLighter,
|
||||
style: context.textTheme.labelMedium?.toLight,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ class _ProxiesListViewState extends State<ProxiesListView> {
|
||||
null,
|
||||
);
|
||||
List<double> _headerOffset = [];
|
||||
double containerHeight = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -81,10 +80,10 @@ class _ProxiesListViewState extends State<ProxiesListView> {
|
||||
}
|
||||
|
||||
void _handleChange(Set<String> currentUnfoldSet, String groupName) {
|
||||
_autoScrollToGroup(groupName);
|
||||
final tempUnfoldSet = Set<String>.from(currentUnfoldSet);
|
||||
if (tempUnfoldSet.contains(groupName)) {
|
||||
tempUnfoldSet.remove(groupName);
|
||||
_autoScrollToGroup(groupName);
|
||||
} else {
|
||||
tempUnfoldSet.add(groupName);
|
||||
}
|
||||
@@ -205,54 +204,8 @@ class _ProxiesListViewState extends State<ProxiesListView> {
|
||||
return _headerOffset[index];
|
||||
}
|
||||
|
||||
void _scrollToMakeVisibleWithPadding({
|
||||
required double containerHeight,
|
||||
required double pixels,
|
||||
required double start,
|
||||
required double end,
|
||||
double padding = 24,
|
||||
}) {
|
||||
final visibleStart = pixels;
|
||||
final visibleEnd = pixels + containerHeight;
|
||||
|
||||
final isElementVisible = start >= visibleStart && end <= visibleEnd;
|
||||
if (isElementVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
double targetScrollOffset;
|
||||
|
||||
if (end <= visibleStart) {
|
||||
targetScrollOffset = start;
|
||||
} else if (start >= visibleEnd) {
|
||||
targetScrollOffset = end - containerHeight + padding;
|
||||
} else {
|
||||
final visibleTopPart = end - visibleStart;
|
||||
final visibleBottomPart = visibleEnd - start;
|
||||
if (visibleTopPart.abs() >= visibleBottomPart.abs()) {
|
||||
targetScrollOffset = end - containerHeight + padding;
|
||||
} else {
|
||||
targetScrollOffset = start;
|
||||
}
|
||||
}
|
||||
|
||||
targetScrollOffset = targetScrollOffset.clamp(
|
||||
_controller.position.minScrollExtent,
|
||||
_controller.position.maxScrollExtent,
|
||||
);
|
||||
|
||||
_controller.jumpTo(targetScrollOffset);
|
||||
}
|
||||
|
||||
void _autoScrollToGroup(String groupName) {
|
||||
final pixels = _controller.position.pixels;
|
||||
final offset = _getGroupOffset(groupName);
|
||||
_scrollToMakeVisibleWithPadding(
|
||||
containerHeight: containerHeight,
|
||||
pixels: pixels,
|
||||
start: offset,
|
||||
end: offset + listHeaderHeight,
|
||||
);
|
||||
_controller.jumpTo(_getGroupOffset(groupName));
|
||||
}
|
||||
|
||||
void _scrollToGroupSelected(String groupName) {
|
||||
@@ -272,10 +225,7 @@ class _ProxiesListViewState extends State<ProxiesListView> {
|
||||
void _jumpTo(double offset) {
|
||||
if (mounted && _controller.hasClients) {
|
||||
_controller.animateTo(
|
||||
offset.clamp(
|
||||
_controller.position.minScrollExtent,
|
||||
_controller.position.maxScrollExtent,
|
||||
),
|
||||
min(offset, _controller.position.maxScrollExtent),
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeIn,
|
||||
);
|
||||
@@ -326,7 +276,6 @@ class _ProxiesListViewState extends State<ProxiesListView> {
|
||||
),
|
||||
LayoutBuilder(
|
||||
builder: (_, container) {
|
||||
containerHeight = container.maxHeight;
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: _headerStateNotifier,
|
||||
builder: (_, headerState, _) {
|
||||
@@ -567,29 +516,21 @@ class _ListHeaderState extends State<ListHeader> {
|
||||
children: [
|
||||
if (isExpand) ...[
|
||||
IconButton(
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: EdgeInsets.all(2),
|
||||
visualDensity: VisualDensity.standard,
|
||||
onPressed: () {
|
||||
widget.onScrollToSelected(groupName);
|
||||
},
|
||||
iconSize: 19,
|
||||
icon: const Icon(Icons.adjust),
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
IconButton(
|
||||
iconSize: 20,
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: EdgeInsets.all(2),
|
||||
onPressed: _delayTest,
|
||||
visualDensity: VisualDensity.standard,
|
||||
icon: const Icon(Icons.network_ping),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
] else
|
||||
SizedBox(width: 6),
|
||||
SizedBox(width: 4),
|
||||
IconButton.filledTonal(
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: EdgeInsets.all(2),
|
||||
iconSize: 24,
|
||||
onPressed: () {
|
||||
_handleChange(groupName);
|
||||
},
|
||||
|
||||
@@ -29,10 +29,10 @@ class ResourcesView extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const geoItems = <GeoItem>[
|
||||
GeoItem(label: 'GEOIP', fileName: GEOIP, key: 'geoip'),
|
||||
GeoItem(label: 'GEOSITE', fileName: GEOSITE, key: 'geosite'),
|
||||
GeoItem(label: 'MMDB', fileName: MMDB, key: 'mmdb'),
|
||||
GeoItem(label: 'ASN', fileName: ASN, key: 'asn'),
|
||||
GeoItem(label: 'GeoIp', fileName: geoIpFileName, key: 'geoip'),
|
||||
GeoItem(label: 'GeoSite', fileName: geoSiteFileName, key: 'geosite'),
|
||||
GeoItem(label: 'MMDB', fileName: mmdbFileName, key: 'mmdb'),
|
||||
GeoItem(label: 'ASN', fileName: asnFileName, key: 'asn'),
|
||||
];
|
||||
|
||||
return CommonScaffold(
|
||||
|
||||
@@ -277,7 +277,7 @@ class _PrimaryColorItemState extends ConsumerState<_PrimaryColorItem> {
|
||||
final isEquals = vm4.d;
|
||||
|
||||
return CommonPopScope(
|
||||
onPop: (context) {
|
||||
onPop: () {
|
||||
if (_removablePrimaryColor != null) {
|
||||
setState(() {
|
||||
_removablePrimaryColor = null;
|
||||
|
||||
@@ -125,7 +125,7 @@ class CommonCard extends StatelessWidget {
|
||||
if (isSelected) {
|
||||
return colorScheme.secondaryContainer.opacity80;
|
||||
}
|
||||
return colorScheme.surfaceContainerHigh;
|
||||
return colorScheme.surfaceContainer;
|
||||
}
|
||||
if (isSelected) {
|
||||
return colorScheme.secondaryContainer;
|
||||
|
||||
@@ -76,13 +76,13 @@ class FadeRotationScaleBox extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedSwitcher(
|
||||
duration: commonDuration,
|
||||
switchInCurve: Curves.easeOutBack,
|
||||
switchOutCurve: Curves.easeInBack,
|
||||
switchInCurve: Curves.easeOut,
|
||||
switchOutCurve: Curves.easeIn,
|
||||
transitionBuilder: (child, animation) {
|
||||
return RotationTransition(
|
||||
turns: animation.drive(Tween(begin: 0.8, end: 1.0)),
|
||||
child: FadeTransition(
|
||||
opacity: animation.drive(Tween(begin: 0.6, end: 1.0)),
|
||||
opacity: animation.drive(Tween(begin: 0.4, end: 1.0)),
|
||||
child: ScaleTransition(scale: animation, child: child),
|
||||
),
|
||||
);
|
||||
@@ -94,36 +94,19 @@ class FadeRotationScaleBox extends StatelessWidget {
|
||||
|
||||
class FadeScaleBox extends StatelessWidget {
|
||||
final Widget child;
|
||||
final AlignmentGeometry? alignment;
|
||||
|
||||
const FadeScaleBox({super.key, required this.child, this.alignment});
|
||||
const FadeScaleBox({super.key, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final realAlignment = alignment ?? Alignment.center;
|
||||
return AnimatedSwitcher(
|
||||
duration: commonDuration,
|
||||
switchOutCurve: Curves.easeOutBack,
|
||||
switchInCurve: Curves.easeInBack,
|
||||
transitionBuilder: (child, animation) {
|
||||
return FadeTransition(
|
||||
opacity: animation,
|
||||
child: ScaleTransition(
|
||||
scale: animation.drive(Tween(begin: 0.4, end: 1.0)),
|
||||
child: child,
|
||||
),
|
||||
return Container(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: FadeScaleTransition(animation: animation, child: child),
|
||||
);
|
||||
},
|
||||
layoutBuilder: (currentChild, previousChildren) => Align(
|
||||
alignment: realAlignment,
|
||||
child: Stack(
|
||||
alignment: realAlignment,
|
||||
children: <Widget>[
|
||||
...previousChildren,
|
||||
if (currentChild != null) currentChild,
|
||||
],
|
||||
),
|
||||
),
|
||||
duration: Duration(milliseconds: 300),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import 'package:flutter/widgets.dart';
|
||||
|
||||
class CommonPopScope extends StatelessWidget {
|
||||
final Widget child;
|
||||
final FutureOr<bool> Function(BuildContext context)? onPop;
|
||||
final FutureOr<bool> Function()? onPop;
|
||||
final FutureOr<void> Function()? onPopSuccess;
|
||||
|
||||
const CommonPopScope({
|
||||
@@ -25,7 +25,7 @@ class CommonPopScope extends StatelessWidget {
|
||||
if (didPop) {
|
||||
return;
|
||||
}
|
||||
final res = await onPop!(context);
|
||||
final res = await onPop!();
|
||||
if (!context.mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/models/models.dart';
|
||||
import 'package:fl_clash/providers/app.dart';
|
||||
import 'package:fl_clash/widgets/fade_box.dart';
|
||||
import 'package:fl_clash/widgets/pop_scope.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
@@ -224,7 +225,7 @@ class CommonScaffoldState extends State<CommonScaffold> {
|
||||
if (_isEdit || _isSearch) {
|
||||
return SystemBackBlock(
|
||||
child: CommonPopScope(
|
||||
onPop: (context) {
|
||||
onPop: () {
|
||||
if (_isEdit || _isSearch) {
|
||||
_handleExitSearching();
|
||||
_appBarState.value.editState?.onExit();
|
||||
@@ -336,7 +337,11 @@ class CommonScaffoldState extends State<CommonScaffold> {
|
||||
ValueListenableBuilder<Widget?>(
|
||||
valueListenable: _floatingActionButton,
|
||||
builder: (_, value, _) {
|
||||
return value ?? SizedBox();
|
||||
return IntrinsicWidth(
|
||||
child: IntrinsicHeight(
|
||||
child: FadeScaleBox(child: value ?? SizedBox()),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -26,8 +26,8 @@ class CommonScrollBar extends StatelessWidget {
|
||||
controller: controller,
|
||||
thumbVisibility: thumbVisibility,
|
||||
trackVisibility: trackVisibility,
|
||||
thickness: 6,
|
||||
radius: const Radius.circular(6),
|
||||
thickness: 8,
|
||||
radius: const Radius.circular(8),
|
||||
interactive: true,
|
||||
child: child,
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <dynamic_color/dynamic_color_plugin.h>
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <flutter_acrylic/flutter_acrylic_plugin.h>
|
||||
#include <flutter_js/flutter_js_plugin.h>
|
||||
#include <gtk/gtk_plugin.h>
|
||||
#include <hotkey_manager_linux/hotkey_manager_linux_plugin.h>
|
||||
@@ -23,6 +24,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) flutter_acrylic_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterAcrylicPlugin");
|
||||
flutter_acrylic_plugin_register_with_registrar(flutter_acrylic_registrar);
|
||||
g_autoptr(FlPluginRegistrar) flutter_js_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterJsPlugin");
|
||||
flutter_js_plugin_register_with_registrar(flutter_js_registrar);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
dynamic_color
|
||||
file_selector_linux
|
||||
flutter_acrylic
|
||||
flutter_js
|
||||
gtk
|
||||
hotkey_manager_linux
|
||||
|
||||
@@ -13,6 +13,7 @@ import file_picker
|
||||
import file_selector_macos
|
||||
import flutter_js
|
||||
import hotkey_manager_macos
|
||||
import macos_window_utils
|
||||
import mobile_scanner
|
||||
import package_info_plus
|
||||
import path_provider_foundation
|
||||
@@ -33,6 +34,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FlutterJsPlugin.register(with: registry.registrar(forPlugin: "FlutterJsPlugin"))
|
||||
HotkeyManagerMacosPlugin.register(with: registry.registrar(forPlugin: "HotkeyManagerMacosPlugin"))
|
||||
MacOSWindowUtilsPlugin.register(with: registry.registrar(forPlugin: "MacOSWindowUtilsPlugin"))
|
||||
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
|
||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
|
||||
@@ -18,6 +18,8 @@ PODS:
|
||||
- hotkey_manager_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- HotKey
|
||||
- macos_window_utils (1.0.0):
|
||||
- FlutterMacOS
|
||||
- mobile_scanner (7.0.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
@@ -53,6 +55,7 @@ DEPENDENCIES:
|
||||
- flutter_js (from `Flutter/ephemeral/.symlinks/plugins/flutter_js/macos`)
|
||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
- hotkey_manager_macos (from `Flutter/ephemeral/.symlinks/plugins/hotkey_manager_macos/macos`)
|
||||
- macos_window_utils (from `Flutter/ephemeral/.symlinks/plugins/macos_window_utils/macos`)
|
||||
- mobile_scanner (from `Flutter/ephemeral/.symlinks/plugins/mobile_scanner/darwin`)
|
||||
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
|
||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
@@ -87,6 +90,8 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral
|
||||
hotkey_manager_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/hotkey_manager_macos/macos
|
||||
macos_window_utils:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/macos_window_utils/macos
|
||||
mobile_scanner:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/mobile_scanner/darwin
|
||||
package_info_plus:
|
||||
@@ -119,6 +124,7 @@ SPEC CHECKSUMS:
|
||||
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
||||
HotKey: e96d8a2ddbf4591131e2bb3f54e69554d90cdca6
|
||||
hotkey_manager_macos: a4317849af96d2430fa89944d3c58977ca089fbe
|
||||
macos_window_utils: 23f54331a0fd51eea9e0ed347253bf48fd379d1d
|
||||
mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93
|
||||
package_info_plus: f0052d280d17aa382b932f399edf32507174e870
|
||||
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||
|
||||
24
pubspec.lock
24
pubspec.lock
@@ -462,6 +462,14 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_acrylic:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_acrylic
|
||||
sha256: b3996dbde5abf5823cc9ead4cf2e5267c3181f15585fe47ce4dc4472e7ec827a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.4"
|
||||
flutter_cache_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -814,6 +822,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
lpinyin:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: lpinyin
|
||||
sha256: "0bb843363f1f65170efd09fbdfc760c7ec34fc6354f9fcb2f89e74866a0d814a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
macos_window_utils:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: macos_window_utils
|
||||
sha256: d4df3501fd32ac0d2d7590cb6a8e4758337d061c8fa0db816fdd636be63a8438
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: fl_clash
|
||||
description: A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free.
|
||||
publish_to: 'none'
|
||||
version: 0.8.88+2025090702
|
||||
version: 0.8.88+2025083102
|
||||
environment:
|
||||
sdk: '>=3.8.0 <4.0.0'
|
||||
|
||||
@@ -43,6 +43,7 @@ dependencies:
|
||||
ref: main
|
||||
re_highlight: ^0.0.3
|
||||
archive: ^4.0.7
|
||||
lpinyin: ^2.0.3
|
||||
emoji_regex: ^0.0.5
|
||||
hotkey_manager: ^0.2.3
|
||||
uni_platform: ^0.1.3
|
||||
@@ -61,6 +62,7 @@ dependencies:
|
||||
flutter_svg: ^2.1.0
|
||||
flutter_cache_manager: ^3.4.1
|
||||
crypto: ^3.0.3
|
||||
flutter_acrylic: ^1.1.4
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||
#include <dynamic_color/dynamic_color_plugin_c_api.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <flutter_acrylic/flutter_acrylic_plugin.h>
|
||||
#include <flutter_js/flutter_js_plugin.h>
|
||||
#include <hotkey_manager_windows/hotkey_manager_windows_plugin_c_api.h>
|
||||
#include <proxy/proxy_plugin_c_api.h>
|
||||
@@ -28,6 +29,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
FlutterAcrylicPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterAcrylicPlugin"));
|
||||
FlutterJsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterJsPlugin"));
|
||||
HotkeyManagerWindowsPluginCApiRegisterWithRegistrar(
|
||||
|
||||
@@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||
connectivity_plus
|
||||
dynamic_color
|
||||
file_selector_windows
|
||||
flutter_acrylic
|
||||
flutter_js
|
||||
hotkey_manager_windows
|
||||
proxy
|
||||
|
||||
Reference in New Issue
Block a user