diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 5164930..0b8db24 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -4,6 +4,8 @@ on:
push:
tags:
- 'v*'
+env:
+ IS_STABLE: ${{ !contains(github.ref, '-') }}
jobs:
build:
@@ -74,7 +76,7 @@ jobs:
run: flutter pub get
- name: Setup
- run: dart setup.dart ${{ matrix.platform }} ${{ matrix.arch && format('--arch {0}', matrix.arch) }}
+ run: dart setup.dart ${{ matrix.platform }} ${{ matrix.arch && format('--arch {0}', matrix.arch) }} ${{ env.IS_STABLE == 'true' && '--env stable' || '' }}
- name: Upload
uses: actions/upload-artifact@v4
@@ -88,14 +90,13 @@ jobs:
needs: [ build ]
steps:
- name: Checkout
- if: ${{ !contains(github.ref, '+') }}
uses: actions/checkout@v4
+ if: ${{ env.IS_STABLE == 'true' }}
with:
fetch-depth: 0
ref: refs/heads/main
-
- name: Generate
- if: ${{ !contains(github.ref, '+') }}
+ if: ${{ env.IS_STABLE == 'true' }}
run: |
tags=($(git tag --merged $(git rev-parse HEAD) --sort=-creatordate))
preTag=$(grep -oP '^## \K.*' CHANGELOG.md | head -n 1)
@@ -127,7 +128,7 @@ jobs:
cat NEW_CHANGELOG.md > CHANGELOG.md
- name: Commit
- if: ${{ !contains(github.ref, '+') }}
+ if: ${{ env.IS_STABLE == 'true' }}
run: |
git add CHANGELOG.md
if ! git diff --cached --quiet; then
@@ -206,7 +207,7 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install requests
- python release.py
+ python release_telegram.py
- name: Patch release.md
run: |
@@ -214,21 +215,21 @@ jobs:
sed "s|VERSION|$version|g" ./.github/release_template.md >> release.md
- name: Release
- if: ${{ !contains(github.ref, '+') }}
+ if: ${{ env.IS_STABLE == 'true' }}
uses: softprops/action-gh-release@v2
with:
files: ./dist/*
body_path: './release.md'
- name: Create Fdroid Source Dir
- if: ${{ !contains(github.ref, '+') }}
+ if: ${{ env.IS_STABLE == 'true' }}
run: |
mkdir -p ./tmp
cp ./dist/*android-arm64-v8a* ./tmp/ || true
echo "Files copied successfully"
- name: Push to fdroid repo
- if: ${{ !contains(github.ref, '+') }}
+ if: ${{ env.IS_STABLE == 'true' }}
uses: cpina/github-action-push-to-another-repository@v1.7.2
env:
SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
@@ -238,7 +239,7 @@ jobs:
destination-repository-name: FlClash-fdroid-repo
user-name: 'github-actions[bot]'
user-email: 'github-actions[bot]@users.noreply.github.com'
- target-branch: action-pr
+ target-branch: main
commit-message: Update from ${{ github.ref_name }}
target-directory: /tmp/
diff --git a/.gitmodules b/.gitmodules
index 7577fac..70bf7cd 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,7 +1,7 @@
[submodule "core/Clash.Meta"]
path = core/Clash.Meta
url = git@github.com:chen08209/Clash.Meta.git
- branch = FlClash-Alpha
+ branch = FlClash
[submodule "plugins/flutter_distributor"]
path = plugins/flutter_distributor
url = git@github.com:chen08209/flutter_distributor.git
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 0fbea86..f9b3034 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,8 +1 @@
include: package:flutter_lints/flutter.yaml
-
-linter:
- rules:
-
-analyzer:
- plugins:
- - custom_lint
diff --git a/android/app/build.gradle b/android/app/build.gradle
index fdf1998..bc8d1d0 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -33,7 +33,7 @@ def isRelease = defStoreFile.exists() && defStorePassword != null && defKeyAlias
android {
namespace "com.follow.clash"
- compileSdkVersion 34
+ compileSdkVersion 35
ndkVersion "27.1.12297006"
compileOptions {
@@ -63,7 +63,7 @@ android {
defaultConfig {
applicationId "com.follow.clash"
minSdkVersion 21
- targetSdkVersion 34
+ targetSdkVersion 35
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 185ac9c..606a14a 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -10,14 +10,12 @@
-
-
+
+
@@ -64,7 +62,9 @@
-
+
@@ -138,7 +137,7 @@
+ android:foregroundServiceType="dataSync">
diff --git a/android/app/src/main/kotlin/com/follow/clash/FlClashApplication.kt b/android/app/src/main/kotlin/com/follow/clash/FlClashApplication.kt
index 8326a75..e2b2783 100644
--- a/android/app/src/main/kotlin/com/follow/clash/FlClashApplication.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/FlClashApplication.kt
@@ -1,7 +1,7 @@
package com.follow.clash;
import android.app.Application
-import android.content.Context;
+import android.content.Context
class FlClashApplication : Application() {
companion object {
diff --git a/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt b/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt
index d3fef86..d2b8d4c 100644
--- a/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt
@@ -1,9 +1,7 @@
package com.follow.clash
-import android.content.Context
import androidx.lifecycle.MutableLiveData
import com.follow.clash.plugins.AppPlugin
-import com.follow.clash.plugins.ServicePlugin
import com.follow.clash.plugins.TilePlugin
import com.follow.clash.plugins.VpnPlugin
import io.flutter.FlutterInjector
diff --git a/android/app/src/main/kotlin/com/follow/clash/plugins/AppPlugin.kt b/android/app/src/main/kotlin/com/follow/clash/plugins/AppPlugin.kt
index 8683291..12bdb39 100644
--- a/android/app/src/main/kotlin/com/follow/clash/plugins/AppPlugin.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/plugins/AppPlugin.kt
@@ -291,16 +291,18 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
private fun getPackages(): List {
val packageManager = FlClashApplication.getAppContext().packageManager
if (packages.isNotEmpty()) return packages
- packageManager?.getInstalledPackages(PackageManager.GET_META_DATA)?.filter {
- it.packageName != FlClashApplication.getAppContext().packageName
- || it.requestedPermissions?.contains(Manifest.permission.INTERNET) == true
- || it.packageName == "android"
+ packageManager?.getInstalledPackages(PackageManager.GET_META_DATA or PackageManager.GET_PERMISSIONS)
+ ?.filter {
+ it.packageName != FlClashApplication.getAppContext().packageName && (
+ it.requestedPermissions?.contains(Manifest.permission.INTERNET) == true
+ || it.packageName == "android"
+ )
- }?.map {
+ }?.map {
Package(
packageName = it.packageName,
- label = it.applicationInfo.loadLabel(packageManager).toString(),
- isSystem = (it.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) == 1,
+ label = it.applicationInfo?.loadLabel(packageManager).toString(),
+ isSystem = (it.applicationInfo?.flags?.and(ApplicationInfo.FLAG_SYSTEM)) == 1,
lastUpdateTime = it.lastUpdateTime
)
}?.let { packages.addAll(it) }
@@ -353,7 +355,7 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
}
suspend fun getText(text: String): String? {
- return withContext(Dispatchers.Default){
+ return withContext(Dispatchers.Default) {
channel.awaitResult("getText", text)
}
}
@@ -391,31 +393,33 @@ class AppPlugin : FlutterPlugin, MethodChannel.MethodCallHandler, ActivityAware
}.forEach {
if (it.name.matches(chinaAppRegex)) return true
}
- ZipFile(File(packageInfo.applicationInfo.publicSourceDir)).use {
- for (packageEntry in it.entries()) {
- if (packageEntry.name.startsWith("firebase-")) return false
- }
- for (packageEntry in it.entries()) {
- if (!(packageEntry.name.startsWith("classes") && packageEntry.name.endsWith(
- ".dex"
- ))
- ) {
- continue
+ packageInfo.applicationInfo?.publicSourceDir?.let {
+ ZipFile(File(it)).use {
+ for (packageEntry in it.entries()) {
+ if (packageEntry.name.startsWith("firebase-")) return false
}
- if (packageEntry.size > 15000000) {
- return true
- }
- val input = it.getInputStream(packageEntry).buffered()
- val dexFile = try {
- DexBackedDexFile.fromInputStream(null, input)
- } catch (e: Exception) {
- return false
- }
- for (clazz in dexFile.classes) {
- val clazzName =
- clazz.type.substring(1, clazz.type.length - 1).replace("/", ".")
- .replace("$", ".")
- if (clazzName.matches(chinaAppRegex)) return true
+ for (packageEntry in it.entries()) {
+ if (!(packageEntry.name.startsWith("classes") && packageEntry.name.endsWith(
+ ".dex"
+ ))
+ ) {
+ continue
+ }
+ if (packageEntry.size > 15000000) {
+ return true
+ }
+ val input = it.getInputStream(packageEntry).buffered()
+ val dexFile = try {
+ DexBackedDexFile.fromInputStream(null, input)
+ } catch (e: Exception) {
+ return false
+ }
+ for (clazz in dexFile.classes) {
+ val clazzName =
+ clazz.type.substring(1, clazz.type.length - 1).replace("/", ".")
+ .replace("$", ".")
+ if (clazzName.matches(chinaAppRegex)) return true
+ }
}
}
}
diff --git a/android/app/src/main/kotlin/com/follow/clash/plugins/ServicePlugin.kt b/android/app/src/main/kotlin/com/follow/clash/plugins/ServicePlugin.kt
index 2b768c5..2f7ef69 100644
--- a/android/app/src/main/kotlin/com/follow/clash/plugins/ServicePlugin.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/plugins/ServicePlugin.kt
@@ -1,6 +1,5 @@
package com.follow.clash.plugins
-import com.follow.clash.FlClashApplication
import com.follow.clash.GlobalState
import com.follow.clash.models.VpnOptions
import com.google.gson.Gson
diff --git a/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt b/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt
index a5f2ffd..c4f6e7e 100644
--- a/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt
@@ -10,7 +10,6 @@ import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import android.os.IBinder
-import android.util.Log
import androidx.core.content.getSystemService
import com.follow.clash.FlClashApplication
import com.follow.clash.GlobalState
diff --git a/android/app/src/main/kotlin/com/follow/clash/services/FlClashService.kt b/android/app/src/main/kotlin/com/follow/clash/services/FlClashService.kt
index d46a9e3..fa0ba54 100644
--- a/android/app/src/main/kotlin/com/follow/clash/services/FlClashService.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/services/FlClashService.kt
@@ -7,7 +7,7 @@ import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
-import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
+import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
import android.os.Binder
import android.os.Build
import android.os.IBinder
@@ -87,6 +87,7 @@ class FlClashService : Service(), BaseServiceInterface {
}
}
}
+
private suspend fun getNotificationBuilder(): NotificationCompat.Builder {
return notificationBuilderDeferred.await()
}
@@ -100,7 +101,8 @@ class FlClashService : Service(), BaseServiceInterface {
}
}
- @SuppressLint("ForegroundServiceType", "WrongConstant")
+
+ @SuppressLint("ForegroundServiceType")
override suspend fun startForeground(title: String, content: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val manager = getSystemService(NotificationManager::class.java)
@@ -116,7 +118,11 @@ class FlClashService : Service(), BaseServiceInterface {
.setContentTitle(title)
.setContentText(content).build()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
- startForeground(notificationId, notification, FOREGROUND_SERVICE_TYPE_SPECIAL_USE)
+ try {
+ startForeground(notificationId, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC)
+ } catch (_: Exception) {
+ startForeground(notificationId, notification)
+ }
} else {
startForeground(notificationId, notification)
}
diff --git a/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt b/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt
index 7f097ae..37d39a0 100644
--- a/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt
@@ -6,7 +6,7 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
-import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
+import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
import android.net.ProxyInfo
import android.net.VpnService
import android.os.Binder
@@ -45,9 +45,16 @@ class FlClashVpnService : VpnService(), BaseServiceInterface {
addAddress(cidr.address, cidr.prefixLength)
val routeAddress = options.getIpv4RouteAddress()
if (routeAddress.isNotEmpty()) {
- routeAddress.forEach { i ->
- Log.d("addRoute4", "address: ${i.address} prefixLength:${i.prefixLength}")
- addRoute(i.address, i.prefixLength)
+ try {
+ routeAddress.forEach { i ->
+ Log.d(
+ "addRoute4",
+ "address: ${i.address} prefixLength:${i.prefixLength}"
+ )
+ addRoute(i.address, i.prefixLength)
+ }
+ } catch (_: Exception) {
+ addRoute("0.0.0.0", 0)
}
} else {
addRoute("0.0.0.0", 0)
@@ -58,9 +65,16 @@ class FlClashVpnService : VpnService(), BaseServiceInterface {
addAddress(cidr.address, cidr.prefixLength)
val routeAddress = options.getIpv6RouteAddress()
if (routeAddress.isNotEmpty()) {
- routeAddress.forEach { i ->
- Log.d("addRoute6", "address: ${i.address} prefixLength:${i.prefixLength}")
- addRoute(i.address, i.prefixLength)
+ try {
+ routeAddress.forEach { i ->
+ Log.d(
+ "addRoute6",
+ "address: ${i.address} prefixLength:${i.prefixLength}"
+ )
+ addRoute(i.address, i.prefixLength)
+ }
+ } catch (_: Exception) {
+ addRoute("::", 0)
}
} else {
addRoute("::", 0)
@@ -165,7 +179,7 @@ class FlClashVpnService : VpnService(), BaseServiceInterface {
return notificationBuilderDeferred.await()
}
- @SuppressLint("ForegroundServiceType", "WrongConstant")
+ @SuppressLint("ForegroundServiceType")
override suspend fun startForeground(title: String, content: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val manager = getSystemService(NotificationManager::class.java)
@@ -182,7 +196,11 @@ class FlClashVpnService : VpnService(), BaseServiceInterface {
.setContentText(content)
.build()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
- startForeground(notificationId, notification, FOREGROUND_SERVICE_TYPE_SPECIAL_USE)
+ try {
+ startForeground(notificationId, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC)
+ } catch (_: Exception) {
+ startForeground(notificationId, notification)
+ }
} else {
startForeground(notificationId, notification)
}
diff --git a/android/gradle.properties b/android/gradle.properties
index 74e2e7b..f1c93ba 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -2,4 +2,4 @@ org.gradle.jvmargs=-Xmx4G
android.useAndroidX=true
android.enableJetifier=true
kotlin_version=1.9.22
-agp_version=8.2.1
+agp_version=8.9.1
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index d055c79..90df0e8 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -2,5 +2,5 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
diff --git a/assets/fonts/JetBrainsMono-Regular.ttf b/assets/fonts/JetBrainsMono-Regular.ttf
new file mode 100644
index 0000000..dff66cc
Binary files /dev/null and b/assets/fonts/JetBrainsMono-Regular.ttf differ
diff --git a/core/Clash.Meta b/core/Clash.Meta
index 76b0d7e..f19dad5 160000
--- a/core/Clash.Meta
+++ b/core/Clash.Meta
@@ -1 +1 @@
-Subproject commit 76b0d7e8bcdaf952c35d71e6852866414a7e1f6e
+Subproject commit f19dad529f7d8ac652053f9d090e6780e199eab2
diff --git a/core/common.go b/core/common.go
index 8ae5f0d..e34eb7b 100644
--- a/core/common.go
+++ b/core/common.go
@@ -28,8 +28,12 @@ import (
"sync"
)
-func splitByComma(s string) interface{} {
- parts := strings.Split(s, ",")
+func splitByMultipleSeparators(s string) interface{} {
+ isSeparator := func(r rune) bool {
+ return r == ',' || r == ' ' || r == ';'
+ }
+
+ parts := strings.FieldsFunc(s, isSeparator)
if len(parts) > 1 {
return parts
}
@@ -168,18 +172,18 @@ func decorationConfig(profileId string, cfg config.RawConfig) *config.RawConfig
return prof
}
-func genHosts(hosts, patchHosts map[string]any) {
+func attachHosts(hosts, patchHosts map[string]any) {
for k, v := range patchHosts {
if str, ok := v.(string); ok {
- hosts[k] = splitByComma(str)
+ hosts[k] = splitByMultipleSeparators(str)
}
}
}
-func modPatchDns(dns *config.RawDNS) {
+func updatePatchDns(dns config.RawDNS) {
for pair := dns.NameServerPolicy.Oldest(); pair != nil; pair = pair.Next() {
if str, ok := pair.Value.(string); ok {
- dns.NameServerPolicy.Set(pair.Key, splitByComma(str))
+ dns.NameServerPolicy.Set(pair.Key, splitByMultipleSeparators(str))
}
}
}
@@ -191,26 +195,25 @@ func trimArr(arr []string) (r []string) {
return
}
-func overrideRules(rules *[]string) {
- var target = ""
- for _, line := range *rules {
+func overrideRules(rules, patchRules []string) []string {
+ target := ""
+ for _, line := range rules {
rule := trimArr(strings.Split(line, ","))
- l := len(rule)
- if l != 2 {
- return
+ if len(rule) != 2 {
+ continue
}
- if strings.ToUpper(rule[0]) == "MATCH" {
+ if strings.EqualFold(rule[0], "MATCH") {
target = rule[1]
break
}
}
if target == "" {
- return
+ return rules
}
- var rulesExt = lo.Map(ips, func(ip string, index int) string {
- return fmt.Sprintf("DOMAIN %s %s", ip, target)
+ rulesExt := lo.Map(ips, func(ip string, _ int) string {
+ return fmt.Sprintf("DOMAIN,%s,%s", ip, target)
})
- *rules = append(rulesExt, *rules...)
+ return append(append(rulesExt, patchRules...), rules...)
}
func overwriteConfig(targetConfig *config.RawConfig, patchConfig config.RawConfig) {
@@ -244,16 +247,20 @@ func overwriteConfig(targetConfig *config.RawConfig, patchConfig config.RawConfi
for idx := range targetConfig.ProxyGroup {
targetConfig.ProxyGroup[idx]["url"] = ""
}
- genHosts(targetConfig.Hosts, patchConfig.Hosts)
+ attachHosts(targetConfig.Hosts, patchConfig.Hosts)
if configParams.OverrideDns {
- modPatchDns(&patchConfig.DNS)
+ updatePatchDns(patchConfig.DNS)
targetConfig.DNS = patchConfig.DNS
} else {
if targetConfig.DNS.Enable == false {
targetConfig.DNS.Enable = true
}
}
- overrideRules(&targetConfig.Rule)
+ if configParams.OverrideRule {
+ targetConfig.Rule = overrideRules(patchConfig.Rule, []string{})
+ } else {
+ targetConfig.Rule = overrideRules(targetConfig.Rule, patchConfig.Rule)
+ }
}
func patchConfig() {
@@ -267,6 +274,7 @@ func patchConfig() {
dialer.DefaultInterface.Store(general.Interface)
adapter.UnifiedDelay.Store(general.UnifiedDelay)
tunnel.SetMode(general.Mode)
+ tunnel.UpdateRules(currentConfig.Rules, currentConfig.SubRules, currentConfig.RuleProviders)
log.SetLevel(general.LogLevel)
resolver.DisableIPv6 = !general.IPv6
diff --git a/core/constant.go b/core/constant.go
index a9355f6..a4cb3f7 100644
--- a/core/constant.go
+++ b/core/constant.go
@@ -13,6 +13,7 @@ type ConfigExtendedParams struct {
SelectedMap map[string]string `json:"selected-map"`
TestURL *string `json:"test-url"`
OverrideDns bool `json:"override-dns"`
+ OverrideRule bool `json:"override-rule"`
}
type GenerateConfigParams struct {
diff --git a/core/go.mod b/core/go.mod
index 30037f0..aeb042f 100644
--- a/core/go.mod
+++ b/core/go.mod
@@ -21,7 +21,7 @@ require (
github.com/coreos/go-iptables v0.8.0 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/ebitengine/purego v0.8.2 // indirect
- github.com/enfein/mieru/v3 v3.11.2 // indirect
+ github.com/enfein/mieru/v3 v3.13.0 // indirect
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 // indirect
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect
@@ -50,21 +50,22 @@ require (
github.com/mdlayher/netlink v1.7.2 // indirect
github.com/mdlayher/socket v0.4.1 // indirect
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab // indirect
+ github.com/metacubex/bart v0.19.0 // indirect
github.com/metacubex/bbolt v0.0.0-20240822011022-aed6d4850399 // indirect
github.com/metacubex/chacha v0.1.1 // indirect
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect
- github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a // indirect
+ github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b // indirect
github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996 // indirect
github.com/metacubex/randv2 v0.2.0 // indirect
github.com/metacubex/reality v0.0.0-20250219003814-74e8d7850629 // indirect
github.com/metacubex/sing-quic v0.0.0-20250119013740-2a19cce83925 // indirect
github.com/metacubex/sing-shadowsocks v0.2.8 // indirect
github.com/metacubex/sing-shadowsocks2 v0.2.2 // indirect
- github.com/metacubex/sing-tun v0.4.5 // indirect
+ github.com/metacubex/sing-tun v0.4.6-0.20250312042506-6d3b4dc05c04 // indirect
github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82 // indirect
github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 // indirect
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 // indirect
- github.com/metacubex/utls v1.6.6 // indirect
+ github.com/metacubex/utls v1.6.8-alpha.4 // indirect
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 // indirect
github.com/miekg/dns v1.1.63 // indirect
github.com/mroth/weightedrand/v2 v2.1.0 // indirect
@@ -74,7 +75,7 @@ require (
github.com/oschwald/maxminddb-golang v1.12.0 // indirect
github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
- github.com/puzpuzpuz/xsync/v3 v3.5.0 // indirect
+ github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
github.com/sagernet/cors v1.2.1 // indirect
diff --git a/core/go.sum b/core/go.sum
index 63b60b7..4a7fccb 100644
--- a/core/go.sum
+++ b/core/go.sum
@@ -28,8 +28,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
-github.com/enfein/mieru/v3 v3.11.2 h1:06KyGbXiiGz2nSHLJDOOkztAVY3cRr3wBMOpYxPotTo=
-github.com/enfein/mieru/v3 v3.11.2/go.mod h1:XvVfNsM78lUMSlJJKXJZ0Hn3lAB2o/ETXTbb84x5egw=
+github.com/enfein/mieru/v3 v3.13.0 h1:eGyxLGkb+lut9ebmx+BGwLJ5UMbEc/wGIYO0AXEKy98=
+github.com/enfein/mieru/v3 v3.13.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8=
github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I=
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g=
@@ -97,14 +97,16 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab h1:Chbw+/31UC14YFNr78pESt5Vowlc62zziw05JCUqoL4=
github.com/metacubex/amneziawg-go v0.0.0-20240922133038-fdf3a4d5a4ab/go.mod h1:xVKK8jC5Sd3hfh7WjmCq+HorehIbrBijaUWmcuKjPcI=
+github.com/metacubex/bart v0.19.0 h1:XQ9AJeI+WO+phRPkUOoflAFwlqDJnm5BPQpixciJQBY=
+github.com/metacubex/bart v0.19.0/go.mod h1:DCcyfP4MC+Zy7sLK7XeGuMw+P5K9mIRsYOBgiE8icsI=
github.com/metacubex/bbolt v0.0.0-20240822011022-aed6d4850399 h1:oBowHVKZycNtAFbZ6avaCSZJYeme2Nrj+4RpV2cNJig=
github.com/metacubex/bbolt v0.0.0-20240822011022-aed6d4850399/go.mod h1:4xcieuIK+M4bGQmQYZVqEaIYqjS1ahO4kXG7EmDgEro=
github.com/metacubex/chacha v0.1.1 h1:OHIv11Nd9CISAIzegpjfupIoZp9DYm6uQw41RxvmU/c=
github.com/metacubex/chacha v0.1.1/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8=
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI=
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88=
-github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a h1:cZ6oNVrsmsi3SNlnSnRio4zOgtQq+/XidwsaNgKICcg=
-github.com/metacubex/gvisor v0.0.0-20241126021258-5b028898cc5a/go.mod h1:xBw/SYJPgUMPQ1tklV/brGn2nxhfr3BnvBzNlyi4Nic=
+github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b h1:RUh4OdVPz/jDrM9MQ2ySuqu2aeBqcA8rtfWUYLZ8RtI=
+github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU=
github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996 h1:B+AP/Pj2/jBDS/kCYjz/x+0BCOKfd2VODYevyeIt+Ds=
github.com/metacubex/quic-go v0.49.1-0.20250212162123-c135a4412996/go.mod h1:ExVjGyEwTUjCFqx+5uxgV7MOoA3fZI+th4D40H35xmY=
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
@@ -117,16 +119,16 @@ github.com/metacubex/sing-shadowsocks v0.2.8 h1:wIhlaigswzjPw4hej75sEvWte3QR0+AJ
github.com/metacubex/sing-shadowsocks v0.2.8/go.mod h1:X3x88XtJpBxG0W0/ECOJL6Ib0SJ3xdniAkU/6/RMWU0=
github.com/metacubex/sing-shadowsocks2 v0.2.2 h1:eaf42uVx4Lr21S6MDYs0ZdTvGA0GEhDpb9no4+gdXPo=
github.com/metacubex/sing-shadowsocks2 v0.2.2/go.mod h1:BhOug03a/RbI7y6hp6q+6ITM1dXjnLTmeWBHSTwvv2Q=
-github.com/metacubex/sing-tun v0.4.5 h1:kWSyQzuzHI40r50OFBczfWIDvMBMy1RIk+JsXeBPRB0=
-github.com/metacubex/sing-tun v0.4.5/go.mod h1:V0N4rr0dWPBEE20ESkTXdbtx2riQYcb6YtwC5w/9wl0=
+github.com/metacubex/sing-tun v0.4.6-0.20250312042506-6d3b4dc05c04 h1:B211C+i/I8CWf4I/BaAV0mmkEHrDBJ0XR9EWxjPbFEg=
+github.com/metacubex/sing-tun v0.4.6-0.20250312042506-6d3b4dc05c04/go.mod h1:V0N4rr0dWPBEE20ESkTXdbtx2riQYcb6YtwC5w/9wl0=
github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82 h1:zZp5uct9+/0Hb1jKGyqDjCU4/72t43rs7qOq3Rc9oU8=
github.com/metacubex/sing-vmess v0.1.14-0.20250228002636-abc39e113b82/go.mod h1:nE7Mdzj/QUDwgRi/8BASPtsxtIFZTHA4Yst5GgwbGCQ=
github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589 h1:Z6bNy0HLTjx6BKIkV48sV/yia/GP8Bnyb5JQuGgSGzg=
github.com/metacubex/sing-wireguard v0.0.0-20241126021510-0827d417b589/go.mod h1:4NclTLIZuk+QkHVCGrP87rHi/y8YjgPytxTgApJNMhc=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422 h1:zGeQt3UyNydIVrMRB97AA5WsYEau/TyCnRtTf1yUmJY=
github.com/metacubex/tfo-go v0.0.0-20241231083714-66613d49c422/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
-github.com/metacubex/utls v1.6.6 h1:3D12YKHTf2Z41UPhQU2dWerNWJ5TVQD9gKoQ+H+iLC8=
-github.com/metacubex/utls v1.6.6/go.mod h1:+WLFUnXjcpdxXCnyX25nggw8C6YonZ8zOK2Zm/oRvdo=
+github.com/metacubex/utls v1.6.8-alpha.4 h1:5EvsCHxDNneaOtAyc8CztoNSpmonLvkvuGs01lIeeEI=
+github.com/metacubex/utls v1.6.8-alpha.4/go.mod h1:MEZ5WO/VLKYs/s/dOzEK/mlXOQxc04ESeLzRgjmLYtk=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181 h1:hJLQviGySBuaynlCwf/oYgIxbVbGRUIKZCxdya9YrbQ=
github.com/metacubex/wireguard-go v0.0.0-20240922131502-c182e7471181/go.mod h1:phewKljNYiTVT31Gcif8RiCKnTUOgVWFJjccqYM8s+Y=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
@@ -153,8 +155,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
-github.com/puzpuzpuz/xsync/v3 v3.5.0 h1:i+cMcpEDY1BkNm7lPDkCtE4oElsYLn+EKF8kAu2vXT4=
-github.com/puzpuzpuz/xsync/v3 v3.5.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
+github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
+github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
diff --git a/lib/application.dart b/lib/application.dart
index 6cf0f19..416531a 100644
--- a/lib/application.dart
+++ b/lib/application.dart
@@ -61,16 +61,6 @@ class ApplicationState extends ConsumerState {
_autoUpdateGroupTask();
_autoUpdateProfilesTask();
globalState.appController = AppController(context, ref);
- globalState.measure = Measure.of(context);
- // ref.listenManual(themeSettingProvider.select((state) => state.fontFamily),
- // (prev, next) {
- // if (prev != next) {
- // globalState.measure = Measure.of(
- // context,
- // fontFamily: next.value,
- // );
- // }
- // }, fireImmediately: true);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
final currentContext = globalState.navigatorKey.currentContext;
if (currentContext != null) {
@@ -98,7 +88,7 @@ class ApplicationState extends ConsumerState {
});
}
- _buildPlatformWrap(Widget child) {
+ _buildPlatformState(Widget child) {
if (system.isDesktop) {
return WindowManager(
child: TrayManager(
@@ -117,18 +107,7 @@ class ApplicationState extends ConsumerState {
);
}
- _buildPage(Widget page) {
- if (system.isDesktop) {
- return WindowHeaderContainer(
- child: page,
- );
- }
- return VpnManager(
- child: page,
- );
- }
-
- _buildWrap(Widget child) {
+ _buildState(Widget child) {
return AppStateManager(
child: ClashManager(
child: ConnectivityManager(
@@ -142,6 +121,25 @@ class ApplicationState extends ConsumerState {
);
}
+ _buildPlatformApp(Widget child) {
+ if (system.isDesktop) {
+ return WindowHeaderContainer(
+ child: child,
+ );
+ }
+ return VpnManager(
+ child: child,
+ );
+ }
+
+ _buildApp(Widget child) {
+ return MessageManager(
+ child: ThemeManager(
+ child: child,
+ ),
+ );
+ }
+
_updateSystemColorSchemes(
ColorScheme? lightDynamic,
ColorScheme? darkDynamic,
@@ -157,8 +155,8 @@ class ApplicationState extends ConsumerState {
@override
Widget build(context) {
- return _buildPlatformWrap(
- _buildWrap(
+ return _buildPlatformState(
+ _buildState(
Consumer(
builder: (_, ref, child) {
final locale =
@@ -168,6 +166,7 @@ class ApplicationState extends ConsumerState {
builder: (lightDynamic, darkDynamic) {
_updateSystemColorSchemes(lightDynamic, darkDynamic);
return MaterialApp(
+ debugShowCheckedModeBanner: false,
navigatorKey: globalState.navigatorKey,
localizationsDelegates: const [
AppLocalizations.delegate,
@@ -176,14 +175,9 @@ class ApplicationState extends ConsumerState {
GlobalWidgetsLocalizations.delegate
],
builder: (_, child) {
- return MessageManager(
- child: LayoutBuilder(
- builder: (_, container) {
- globalState.appController.updateViewWidth(
- container.maxWidth,
- );
- return _buildPage(child!);
- },
+ return AppEnvManager(
+ child: _buildPlatformApp(
+ _buildApp(child!),
),
);
},
diff --git a/lib/clash/core.dart b/lib/clash/core.dart
index 7ea6269..b5ae232 100644
--- a/lib/clash/core.dart
+++ b/lib/clash/core.dart
@@ -240,7 +240,7 @@ class ClashCore {
if (res.isEmpty) {
return null;
}
- return ClashConfigSnippet.fromJson(json.decode(res));
+ return Isolate.run(() => ClashConfigSnippet.fromJson(json.decode(res)));
}
resetTraffic() {
diff --git a/lib/common/color.dart b/lib/common/color.dart
index 010450f..f81b55e 100644
--- a/lib/common/color.dart
+++ b/lib/common/color.dart
@@ -1,20 +1,40 @@
import 'package:flutter/material.dart';
extension ColorExtension on Color {
- Color get toLight {
- return withOpacity(0.8);
+ Color get opacity80 {
+ return withAlpha(204);
}
- Color get toLighter {
- return withOpacity(0.6);
+ Color get opacity60 {
+ return withAlpha(153);
}
- Color get toSoft {
- return withOpacity(0.15);
+ Color get opacity50 {
+ return withAlpha(128);
}
- Color get toLittle {
- return withOpacity(0.03);
+ Color get opacity38 {
+ return withAlpha(97);
+ }
+
+ Color get opacity30 {
+ return withAlpha(77);
+ }
+
+ Color get opacity15 {
+ return withAlpha(38);
+ }
+
+ Color get opacity10 {
+ return withAlpha(15);
+ }
+
+ Color get opacity3 {
+ return withAlpha(76);
+ }
+
+ Color get opacity0 {
+ return withAlpha(0);
}
Color darken([double amount = .1]) {
diff --git a/lib/common/constant.dart b/lib/common/constant.dart
index d751c6c..a71dfc3 100644
--- a/lib/common/constant.dart
+++ b/lib/common/constant.dart
@@ -21,6 +21,11 @@ const baseInfoEdgeInsets = EdgeInsets.symmetric(
vertical: 16,
horizontal: 16,
);
+
+double textScaleFactor = min(
+ WidgetsBinding.instance.platformDispatcher.textScaleFactor,
+ 1.2,
+);
const httpTimeoutDuration = Duration(milliseconds: 5000);
const moreDuration = Duration(milliseconds: 100);
const animateDuration = Duration(milliseconds: 100);
@@ -46,7 +51,7 @@ const defaultExternalController = "127.0.0.1:9090";
const maxMobileWidth = 600;
const maxLaptopWidth = 840;
const defaultTestUrl = "https://www.gstatic.com/generate_204";
-final filter = ImageFilter.blur(
+final commonFilter = ImageFilter.blur(
sigmaX: 5,
sigmaY: 5,
tileMode: TileMode.mirror,
@@ -76,7 +81,7 @@ const viewModeColumnsMap = {
const defaultPrimaryColor = Colors.brown;
double getWidgetHeight(num lines) {
- return max(lines * 84 + (lines - 1) * 16, 0);
+ return max(lines * 84 * textScaleFactor + (lines - 1) * 16, 0);
}
final mainIsolate = "FlClashMainIsolate";
diff --git a/lib/common/function.dart b/lib/common/function.dart
index 8fd8a9f..a1e1770 100644
--- a/lib/common/function.dart
+++ b/lib/common/function.dart
@@ -1,7 +1,7 @@
import 'dart:async';
class Debouncer {
- final Map _operations = {};
+ final Map _operations = {};
call(
dynamic tag,
@@ -28,14 +28,15 @@ class Debouncer {
cancel(dynamic tag) {
_operations[tag]?.cancel();
+ _operations[tag] = null;
}
}
class Throttler {
- final Map _operations = {};
+ final Map _operations = {};
call(
- String tag,
+ dynamic tag,
Function func, {
List? args,
Duration duration = const Duration(milliseconds: 600),
@@ -60,6 +61,7 @@ class Throttler {
cancel(dynamic tag) {
_operations[tag]?.cancel();
+ _operations[tag] = null;
}
}
diff --git a/lib/common/iterable.dart b/lib/common/iterable.dart
index 802423c..aac4471 100644
--- a/lib/common/iterable.dart
+++ b/lib/common/iterable.dart
@@ -65,3 +65,12 @@ extension DoubleListExt on List {
return -1;
}
}
+
+extension MapExt on Map {
+ getCacheValue(K key, V defaultValue) {
+ if (this[key] == null) {
+ this[key] = defaultValue;
+ }
+ return this[key];
+ }
+}
diff --git a/lib/common/list.dart b/lib/common/list.dart
index 531d56a..ca8add7 100644
--- a/lib/common/list.dart
+++ b/lib/common/list.dart
@@ -32,7 +32,7 @@ class FixedList {
}
class FixedMap {
- final int maxSize;
+ int maxSize;
final Map _map = {};
final Queue _queue = Queue();
@@ -45,6 +45,7 @@ class FixedMap {
}
_map[key] = value;
_queue.add(key);
+ return value;
}
clear() {
@@ -52,8 +53,13 @@ class FixedMap {
_queue.clear();
}
+ updateMaxSize(int size){
+ maxSize = size;
+ }
+
V? get(K key) => _map[key];
+
bool containsKey(K key) => _map.containsKey(key);
int get length => _map.length;
diff --git a/lib/common/measure.dart b/lib/common/measure.dart
index 0415d95..736fdec 100644
--- a/lib/common/measure.dart
+++ b/lib/common/measure.dart
@@ -5,13 +5,11 @@ import 'package:flutter/material.dart';
class Measure {
final TextScaler _textScale;
final BuildContext context;
- final String? _fontFamily;
- Measure.of(this.context, {String? fontFamily})
+ Measure.of(this.context)
: _textScale = TextScaler.linear(
- WidgetsBinding.instance.platformDispatcher.textScaleFactor,
- ),
- _fontFamily = fontFamily ?? "";
+ textScaleFactor,
+ );
Size computeTextSize(
Text text, {
@@ -20,9 +18,7 @@ class Measure {
final textPainter = TextPainter(
text: TextSpan(
text: text.data,
- style: text.style?.copyWith(
- fontFamily: _fontFamily,
- ),
+ style: text.style,
),
maxLines: text.maxLines,
textScaler: _textScale,
diff --git a/lib/common/mixin.dart b/lib/common/mixin.dart
index e29efbb..7fe72fb 100644
--- a/lib/common/mixin.dart
+++ b/lib/common/mixin.dart
@@ -1,3 +1,4 @@
+import 'package:fl_clash/models/models.dart';
import 'package:flutter/material.dart';
import 'package:riverpod/riverpod.dart';
import 'context.dart';
@@ -29,8 +30,14 @@ mixin PageMixin on State {
final commonScaffoldState = context.commonScaffoldState;
commonScaffoldState?.actions = actions;
commonScaffoldState?.floatingActionButton = floatingActionButton;
- commonScaffoldState?.onSearch = onSearch;
commonScaffoldState?.onKeywordsUpdate = onKeywordsUpdate;
+ commonScaffoldState?.updateSearchState(
+ (_) => onSearch != null
+ ? AppBarSearchState(
+ onSearch: onSearch!,
+ )
+ : null,
+ );
});
}
diff --git a/lib/common/navigator.dart b/lib/common/navigator.dart
index b927c34..60e13e5 100644
--- a/lib/common/navigator.dart
+++ b/lib/common/navigator.dart
@@ -70,7 +70,7 @@ class CommonRoute extends MaterialPageRoute {
Duration get transitionDuration => const Duration(milliseconds: 500);
@override
- Duration get reverseTransitionDuration => const Duration(milliseconds: 250);
+ Duration get reverseTransitionDuration => const Duration(milliseconds: 500);
}
final Animatable _kRightMiddleTween = Tween(
@@ -194,7 +194,7 @@ class _CommonPageTransitionState extends State {
_primaryPositionCurve = CurvedAnimation(
parent: widget.primaryRouteAnimation,
curve: Curves.fastEaseInToSlowEaseOut,
- reverseCurve: Curves.easeInOut,
+ reverseCurve: Curves.fastEaseInToSlowEaseOut.flipped,
);
_secondaryPositionCurve = CurvedAnimation(
parent: widget.secondaryRouteAnimation,
@@ -218,9 +218,8 @@ class _CommonPageTransitionState extends State {
begin: const _CommonEdgeShadowDecoration(),
end: _CommonEdgeShadowDecoration(
[
- widget.context.colorScheme.inverseSurface.withOpacity(
- 0.06,
- ),
+ widget.context.colorScheme.inverseSurface
+ .withValues(alpha: 0.02),
Colors.transparent,
],
),
@@ -274,7 +273,7 @@ class _CommonEdgeShadowPainter extends BoxPainter {
return;
}
- final double shadowWidth = 0.03 * configuration.size!.width;
+ final double shadowWidth = 1 * configuration.size!.width;
final double shadowHeight = configuration.size!.height;
final double bandWidth = shadowWidth / (colors.length - 1);
diff --git a/lib/common/other.dart b/lib/common/other.dart
index 4be0653..3bdfaad 100644
--- a/lib/common/other.dart
+++ b/lib/common/other.dart
@@ -241,11 +241,6 @@ class Other {
return "${appName}_${DateTime.now().show}.log";
}
- Size getScreenSize() {
- final view = WidgetsBinding.instance.platformDispatcher.views.first;
- return view.physicalSize / view.devicePixelRatio;
- }
-
Future getLocalIpAddress() async {
List interfaces = await NetworkInterface.list(
includeLoopback: false,
diff --git a/lib/common/protocol.dart b/lib/common/protocol.dart
index a4fedf2..129fb73 100644
--- a/lib/common/protocol.dart
+++ b/lib/common/protocol.dart
@@ -14,15 +14,13 @@ class Protocol {
void register(String scheme) {
String protocolRegKey = 'Software\\Classes\\$scheme';
- RegistryValue protocolRegValue = const RegistryValue(
+ RegistryValue protocolRegValue = RegistryValue.string(
'URL Protocol',
- RegistryValueType.string,
'',
);
String protocolCmdRegKey = 'shell\\open\\command';
- RegistryValue protocolCmdRegValue = RegistryValue(
+ RegistryValue protocolCmdRegValue = RegistryValue.string(
'',
- RegistryValueType.string,
'"${Platform.resolvedExecutable}" "%1"',
);
final regKey = Registry.currentUser.createKey(protocolRegKey);
@@ -31,4 +29,4 @@ class Protocol {
}
}
-final protocol = Protocol();
\ No newline at end of file
+final protocol = Protocol();
diff --git a/lib/common/render.dart b/lib/common/render.dart
index 777ebbc..eb52f96 100644
--- a/lib/common/render.dart
+++ b/lib/common/render.dart
@@ -22,7 +22,7 @@ class Render {
}
pause() {
- debouncer.call(
+ throttler.call(
DebounceTag.renderPause,
_pause,
duration: Duration(seconds: 5),
@@ -30,11 +30,11 @@ class Render {
}
resume() {
- debouncer.cancel(DebounceTag.renderPause);
+ throttler.cancel(DebounceTag.renderPause);
_resume();
}
- void _pause() {
+ void _pause() async {
if (_isPaused) return;
_isPaused = true;
_beginFrame = _dispatcher.onBeginFrame;
diff --git a/lib/common/request.dart b/lib/common/request.dart
index bc061da..eee6e5a 100644
--- a/lib/common/request.dart
+++ b/lib/common/request.dart
@@ -83,13 +83,19 @@ class Request {
Future checkIp({CancelToken? cancelToken}) async {
for (final source in _ipInfoSources.entries) {
try {
- final response = await _dio.get