Compare commits
1 Commits
v0.8.86
...
v0.8.85-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ba6ef1b9c |
11
.github/workflows/build.yaml
vendored
11
.github/workflows/build.yaml
vendored
@@ -63,19 +63,12 @@ jobs:
|
||||
cache-dependency-path: |
|
||||
core/go.sum
|
||||
|
||||
- name: Setup Flutter Master
|
||||
if: startsWith(matrix.os, 'windows-11-arm') || startsWith(matrix.os, 'ubuntu-24.04-arm')
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: 'master'
|
||||
cache: true
|
||||
- name: Setup Flutter
|
||||
if: ${{ !(startsWith(matrix.os, 'windows-11-arm') || startsWith(matrix.os, 'ubuntu-24.04-arm')) }}
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: 'stable'
|
||||
channel: ${{ (startsWith(matrix.os, 'windows-11-arm') || startsWith(matrix.os, 'ubuntu-24.04-arm')) && 'master' || 'stable' }}
|
||||
cache: true
|
||||
# flutter-version: 3.29.3
|
||||
flutter-version: 3.29.3
|
||||
|
||||
- name: Get Flutter Dependency
|
||||
run: flutter pub get
|
||||
|
||||
16
CHANGELOG.md
16
CHANGELOG.md
@@ -1,19 +1,3 @@
|
||||
## v0.8.85
|
||||
|
||||
- Support override script
|
||||
|
||||
- Support proxies search
|
||||
|
||||
- Support svg display
|
||||
|
||||
- Optimize config persistence
|
||||
|
||||
- Add some scenes auto close connections
|
||||
|
||||
- Update core
|
||||
|
||||
- Optimize more details
|
||||
|
||||
## v0.8.84
|
||||
|
||||
- Fix windows service verify issues
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.software.leanback"
|
||||
android:required="false" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
@@ -25,7 +22,6 @@
|
||||
|
||||
<application
|
||||
android:name=".FlClashApplication"
|
||||
android:banner="@mipmap/ic_banner"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="FlClash">
|
||||
@@ -92,7 +88,7 @@
|
||||
<service
|
||||
android:name=".services.FlClashTileService"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/ic"
|
||||
android:icon="@drawable/ic_stat_name"
|
||||
android:label="FlClash"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
|
||||
tools:targetApi="n">
|
||||
|
||||
@@ -104,7 +104,7 @@ fun ConnectivityManager.resolveDns(network: Network?): List<String> {
|
||||
fun InetAddress.asSocketAddressText(port: Int): String {
|
||||
return when (this) {
|
||||
is Inet6Address ->
|
||||
"[${numericToTextFormat(this)}]:$port"
|
||||
"[${numericToTextFormat(this.address)}]:$port"
|
||||
|
||||
is Inet4Address ->
|
||||
"${this.hostAddress}:$port"
|
||||
@@ -141,8 +141,7 @@ fun Context.getActionPendingIntent(action: String): PendingIntent {
|
||||
}
|
||||
}
|
||||
|
||||
private fun numericToTextFormat(address: Inet6Address): String {
|
||||
val src = address.address
|
||||
private fun numericToTextFormat(src: ByteArray): String {
|
||||
val sb = StringBuilder(39)
|
||||
for (i in 0 until 8) {
|
||||
sb.append(
|
||||
@@ -155,10 +154,6 @@ private fun numericToTextFormat(address: Inet6Address): String {
|
||||
sb.append(":")
|
||||
}
|
||||
}
|
||||
if (address.scopeId > 0) {
|
||||
sb.append("%")
|
||||
sb.append(address.scopeId)
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,6 @@ data object VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
|
||||
}
|
||||
|
||||
fun handleStart(options: VpnOptions): Boolean {
|
||||
onUpdateNetwork();
|
||||
if (options.enable != this.options?.enable) {
|
||||
this.flClashService = null
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.follow.clash.MainActivity
|
||||
import com.follow.clash.R
|
||||
import com.follow.clash.extensions.getActionPendingIntent
|
||||
import com.follow.clash.models.VpnOptions
|
||||
import io.flutter.Log
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -53,7 +54,7 @@ fun Service.createFlClashNotificationBuilder(): Deferred<NotificationCompat.Buil
|
||||
this@createFlClashNotificationBuilder, GlobalState.NOTIFICATION_CHANNEL
|
||||
)
|
||||
) {
|
||||
setSmallIcon(R.drawable.ic)
|
||||
setSmallIcon(R.drawable.ic_stat_name)
|
||||
setContentTitle("FlClash")
|
||||
setContentIntent(pendingIntent)
|
||||
setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||
@@ -75,8 +76,9 @@ fun Service.startForeground(notification: Notification) {
|
||||
val manager = getSystemService(NotificationManager::class.java)
|
||||
var channel = manager?.getNotificationChannel(GlobalState.NOTIFICATION_CHANNEL)
|
||||
if (channel == null) {
|
||||
Log.d("[FlClash]","createNotificationChannel===>")
|
||||
channel = NotificationChannel(
|
||||
GlobalState.NOTIFICATION_CHANNEL, "SERVICE_CHANNEL", NotificationManager.IMPORTANCE_LOW
|
||||
GlobalState.NOTIFICATION_CHANNEL, "FlClash", NotificationManager.IMPORTANCE_LOW
|
||||
)
|
||||
manager?.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
BIN
android/app/src/main/res/drawable-hdpi/ic_stat_name.png
Normal file
BIN
android/app/src/main/res/drawable-hdpi/ic_stat_name.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 618 B |
BIN
android/app/src/main/res/drawable-mdpi/ic_stat_name.png
Normal file
BIN
android/app/src/main/res/drawable-mdpi/ic_stat_name.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 423 B |
BIN
android/app/src/main/res/drawable-xhdpi/ic_stat_name.png
Normal file
BIN
android/app/src/main/res/drawable-xhdpi/ic_stat_name.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 803 B |
BIN
android/app/src/main/res/drawable-xxhdpi/ic_stat_name.png
Normal file
BIN
android/app/src/main/res/drawable-xxhdpi/ic_stat_name.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
android/app/src/main/res/drawable-xxxhdpi/ic_stat_name.png
Normal file
BIN
android/app/src/main/res/drawable-xxxhdpi/ic_stat_name.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
@@ -1,17 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:width="240dp"
|
||||
android:height="240dp"
|
||||
android:viewportWidth="240"
|
||||
android:viewportHeight="240"
|
||||
tools:ignore="VectorRaster">
|
||||
<path
|
||||
android:pathData="M48.1,80.89L168.44,11.41c11.08,-6.4 25.24,-2.6 31.64,8.48 0,0 0,0 0,0h0c6.4,11.08 2.6,25.24 -8.48,31.64 0,0 0,0 0,0l-120.34,69.48c-11.08,6.4 -25.24,2.6 -31.64,-8.48 0,0 0,0 0,0h0c-6.4,-11.08 -2.6,-25.24 8.48,-31.64 0,0 0,0 0,0Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M78.98,134.37l60.18,-34.74c11.07,-6.39 25.23,-2.59 31.63,8.48h0c6.4,11.07 2.61,25.24 -8.47,31.64l-60.18,34.74c-11.08,6.4 -25.24,2.6 -31.64,-8.48 0,0 0,0 0,0h0c-6.4,-11.08 -2.6,-25.24 8.48,-31.64h0Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M109.86,187.86h0c11.08,-6.4 25.24,-2.6 31.64,8.48 0,0 0,0 0,0h0c6.4,11.08 2.6,25.24 -8.48,31.64 0,0 0,0 0,0h0c-11.08,6.4 -25.24,2.6 -31.64,-8.48 0,0 0,0 0,0h0c-6.4,-11.08 -2.6,-25.24 8.48,-31.64 0,0 0,0 0,0Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</vector>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -385,6 +385,7 @@
|
||||
"logsTest": "Logs test",
|
||||
"emptyTip": "{label} cannot be empty",
|
||||
"urlTip": "{label} must be a url",
|
||||
"proxyPortTip": "proxy port must be between 1024 and 49151",
|
||||
"numberTip": "{label} must be a number",
|
||||
"interval": "Interval",
|
||||
"existsTip": "Current {label} already exists",
|
||||
@@ -396,15 +397,5 @@
|
||||
"rename": "Rename",
|
||||
"unnamed": "Unnamed",
|
||||
"pleaseEnterScriptName": "Please enter a script name",
|
||||
"overrideInvalidTip": "Does not take effect in script mode",
|
||||
"mixedPort": "Mixed Port",
|
||||
"socksPort": "Socks Port",
|
||||
"redirPort": "Redir Port",
|
||||
"tproxyPort": "Tproxy Port",
|
||||
"portTip": "{label} must be between 1024 and 49151",
|
||||
"portConflictTip": "Please enter a different port",
|
||||
"import": "Import",
|
||||
"importFile": "Import from file",
|
||||
"importUrl": "Import from URL",
|
||||
"autoSetSystemDns": "Auto set system DNS"
|
||||
"overrideInvalidTip": "Does not take effect in script mode"
|
||||
}
|
||||
@@ -386,6 +386,7 @@
|
||||
"logsTest": "ログテスト",
|
||||
"emptyTip": "{label}は空欄にできません",
|
||||
"urlTip": "{label}はURLである必要があります",
|
||||
"proxyPortTip": "プロキシポートは1024から49151の間でなければなりません",
|
||||
"numberTip": "{label}は数字でなければなりません",
|
||||
"interval": "インターバル",
|
||||
"existsTip": "現在の{label}は既に存在しています",
|
||||
@@ -397,15 +398,5 @@
|
||||
"rename": "リネーム",
|
||||
"unnamed": "無題",
|
||||
"pleaseEnterScriptName": "スクリプト名を入力してください",
|
||||
"overrideInvalidTip": "スクリプトモードでは有効になりません",
|
||||
"mixedPort": "混合ポート",
|
||||
"socksPort": "Socksポート",
|
||||
"redirPort": "Redirポート",
|
||||
"tproxyPort": "Tproxyポート",
|
||||
"portTip": "{label} は 1024 から 49151 の間でなければなりません",
|
||||
"portConflictTip": "別のポートを入力してください",
|
||||
"import": "インポート",
|
||||
"importFile": "ファイルからインポート",
|
||||
"importUrl": "URLからインポート",
|
||||
"autoSetSystemDns": "オートセットシステムDNS"
|
||||
"overrideInvalidTip": "スクリプトモードでは有効になりません"
|
||||
}
|
||||
@@ -386,6 +386,7 @@
|
||||
"logsTest": "Тест журналов",
|
||||
"emptyTip": "{label} не может быть пустым",
|
||||
"urlTip": "{label} должен быть URL",
|
||||
"proxyPortTip": "Порт прокси должен быть в диапазоне от 1024 до 49151",
|
||||
"numberTip": "{label} должно быть числом",
|
||||
"interval": "Интервал",
|
||||
"existsTip": "Текущий {label} уже существует",
|
||||
@@ -397,15 +398,5 @@
|
||||
"rename": "Переименовать",
|
||||
"unnamed": "Без имени",
|
||||
"pleaseEnterScriptName": "Пожалуйста, введите название скрипта",
|
||||
"overrideInvalidTip": "В скриптовом режиме не действует",
|
||||
"mixedPort": "Смешанный порт",
|
||||
"socksPort": "Socks-порт",
|
||||
"redirPort": "Redir-порт",
|
||||
"tproxyPort": "Tproxy-порт",
|
||||
"portTip": "{label} должен быть числом от 1024 до 49151",
|
||||
"portConflictTip": "Введите другой порт",
|
||||
"import": "Импорт",
|
||||
"importFile": "Импорт из файла",
|
||||
"importUrl": "Импорт по URL",
|
||||
"autoSetSystemDns": "Автоматическая настройка системного DNS"
|
||||
"overrideInvalidTip": "В скриптовом режиме не действует"
|
||||
}
|
||||
@@ -386,6 +386,7 @@
|
||||
"logsTest": "日志测试",
|
||||
"emptyTip": "{label}不能为空",
|
||||
"urlTip": "{label}必须为URL",
|
||||
"proxyPortTip": "代理端口必须在1024到49151之间",
|
||||
"numberTip": "{label}必须为数字",
|
||||
"interval": "间隔",
|
||||
"existsTip": "{label}当前已存在",
|
||||
@@ -397,15 +398,5 @@
|
||||
"rename": "重命名",
|
||||
"unnamed": "未命名",
|
||||
"pleaseEnterScriptName": "请输入脚本名称",
|
||||
"overrideInvalidTip": "在脚本模式下不生效",
|
||||
"mixedPort": "混合端口",
|
||||
"socksPort": "Socks端口",
|
||||
"redirPort": "Redir端口",
|
||||
"tproxyPort": "Tproxy端口",
|
||||
"portTip": "{label} 必须在 1024 到 49151 之间",
|
||||
"portConflictTip": "请输入不同的端口",
|
||||
"import": "导入",
|
||||
"importFile": "通过文件导入",
|
||||
"importUrl": "通过URL导入",
|
||||
"autoSetSystemDns": "自动设置系统DNS"
|
||||
"overrideInvalidTip": "在脚本模式下不生效"
|
||||
}
|
||||
|
||||
Submodule core/Clash.Meta updated: 413467ae6b...a77851dd9a
24
core/go.mod
24
core/go.mod
@@ -6,6 +6,7 @@ replace github.com/metacubex/mihomo => ./Clash.Meta
|
||||
|
||||
require (
|
||||
github.com/metacubex/mihomo v0.0.0-00010101000000-000000000000
|
||||
github.com/samber/lo v1.50.0
|
||||
golang.org/x/sync v0.11.0
|
||||
)
|
||||
|
||||
@@ -20,7 +21,7 @@ require (
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/coreos/go-iptables v0.8.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
||||
github.com/ebitengine/purego v0.8.3 // indirect
|
||||
github.com/ebitengine/purego v0.8.3-0.20250507171810-1638563e3615 // indirect
|
||||
github.com/enfein/mieru/v3 v3.13.0 // indirect
|
||||
github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 // indirect
|
||||
github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect
|
||||
@@ -50,27 +51,27 @@ 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.20.5 // 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.2 // indirect
|
||||
github.com/metacubex/fswatch v0.1.1 // indirect
|
||||
github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect
|
||||
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b // indirect
|
||||
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 // indirect
|
||||
github.com/metacubex/quic-go v0.52.1-0.20250522021943-aef454b9e639 // indirect
|
||||
github.com/metacubex/quic-go v0.51.1-0.20250511032541-4e34341cf18b // indirect
|
||||
github.com/metacubex/randv2 v0.2.0 // indirect
|
||||
github.com/metacubex/sing v0.5.3 // indirect
|
||||
github.com/metacubex/sing v0.5.3-0.20250504031621-1f99e54c15b7 // indirect
|
||||
github.com/metacubex/sing-mux v0.3.2 // indirect
|
||||
github.com/metacubex/sing-quic v0.0.0-20250523120938-f1a248e5ec7f // indirect
|
||||
github.com/metacubex/sing-shadowsocks v0.2.10 // indirect
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.4 // indirect
|
||||
github.com/metacubex/sing-quic v0.0.0-20250511034158-b46e0e3e81b2 // indirect
|
||||
github.com/metacubex/sing-shadowsocks v0.2.9 // indirect
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.3 // indirect
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 // indirect
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250524142129-9d110c0af70c // indirect
|
||||
github.com/metacubex/sing-vmess v0.2.2 // indirect
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250503065609-efb9f0beb6f6 // indirect
|
||||
github.com/metacubex/sing-vmess v0.2.1 // indirect
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f // indirect
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee // indirect
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 // indirect
|
||||
github.com/metacubex/utls v1.7.3 // indirect
|
||||
github.com/metacubex/tfo-go v0.0.0-20250503140532-decbcfccbfdf // indirect
|
||||
github.com/metacubex/utls v1.7.0-alpha.3 // 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
|
||||
@@ -84,7 +85,6 @@ require (
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/sagernet/cors v1.2.1 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
|
||||
github.com/samber/lo v1.50.0 // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.25.1 // indirect
|
||||
github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect
|
||||
github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect
|
||||
|
||||
44
core/go.sum
44
core/go.sum
@@ -26,8 +26,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc=
|
||||
github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/ebitengine/purego v0.8.3-0.20250507171810-1638563e3615 h1:W7mpP4uiOAbBOdDnRXT9EUdauFv7bz+ERT5rPIord00=
|
||||
github.com/ebitengine/purego v0.8.3-0.20250507171810-1638563e3615/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
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-20250325060835-cd0defd64358 h1:kXYqH/sL8dS/FdoFjr12ePjnLPorPo2FsnrHNuXSDyo=
|
||||
@@ -97,8 +97,8 @@ 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.20.5 h1:XkgLZ17QxfxkqKdGsojoM2Zu01mmHyyQSFzt2/calTM=
|
||||
github.com/metacubex/bart v0.20.5/go.mod h1:DCcyfP4MC+Zy7sLK7XeGuMw+P5K9mIRsYOBgiE8icsI=
|
||||
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.2 h1:QulCq3eVm3TO6+4nVIWJtmSe7BT2GMrgVHuAoqRQnlc=
|
||||
@@ -111,35 +111,35 @@ github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b h1:RUh4OdVPz/jDrM
|
||||
github.com/metacubex/gvisor v0.0.0-20250324165734-5857f47bd43b/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU=
|
||||
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo=
|
||||
github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793/go.mod h1:RjRNb4G52yAgfR+Oe/kp9G4PJJ97Fnj89eY1BFO3YyA=
|
||||
github.com/metacubex/quic-go v0.52.1-0.20250522021943-aef454b9e639 h1:L+1brQNzBhCCxWlicwfK1TlceemCRmrDE4HmcVHc29w=
|
||||
github.com/metacubex/quic-go v0.52.1-0.20250522021943-aef454b9e639/go.mod h1:Kc6h++Q/zf3AxcUCevJhJwgrskJumv+pZdR8g/E/10k=
|
||||
github.com/metacubex/quic-go v0.51.1-0.20250511032541-4e34341cf18b h1:8oDU32eJ+RRhl1FodGgPfxQxtoBAiD9D40XG2XtU/SE=
|
||||
github.com/metacubex/quic-go v0.51.1-0.20250511032541-4e34341cf18b/go.mod h1:9R1NOzCgTcWsdWvOMlmtMuF0uKzuOpsfvEf7U3I8zM0=
|
||||
github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs=
|
||||
github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY=
|
||||
github.com/metacubex/sing v0.5.2/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
|
||||
github.com/metacubex/sing v0.5.3 h1:QWdN16WFKMk06x4nzkc8SvZ7y2x+TLQrpkPoHs+WSVM=
|
||||
github.com/metacubex/sing v0.5.3/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
|
||||
github.com/metacubex/sing v0.5.3-0.20250504031621-1f99e54c15b7 h1:m4nSxvw46JEgxMzzmnXams+ebwabcry4Ydep/zNiesQ=
|
||||
github.com/metacubex/sing v0.5.3-0.20250504031621-1f99e54c15b7/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w=
|
||||
github.com/metacubex/sing-mux v0.3.2 h1:nJv52pyRivHcaZJKk2JgxpaVvj1GAXG81scSa9N7ncw=
|
||||
github.com/metacubex/sing-mux v0.3.2/go.mod h1:3rt1soewn0O6j89GCLmwAQFsq257u0jf2zQSPhTL3Bw=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250523120938-f1a248e5ec7f h1:mP3vIm+9hRFI0C0Vl3pE0NESF/L85FDbuB0tGgUii6I=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250523120938-f1a248e5ec7f/go.mod h1:JPTpf7fpnojsSuwRJExhSZSy63pVbp3VM39+zj+sAJM=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.10 h1:Pr7LDbjMANIQHl07zWgl1vDuhpsfDQUpZ8cX6DPabfg=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.10/go.mod h1:MtRM0ZZjR0kaDOzy9zWSt6/4/UlrnsNBq+1FNAF4vBk=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.4 h1:Ec0x3hHR7xkld5Z09IGh16wtUUpBb2HgqZ9DExd8Q7s=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.4/go.mod h1:WP8+S0kqtnSbX1vlIpo5i8Irm/ijZITEPBcZ26B5unY=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250511034158-b46e0e3e81b2 h1:wfmYgtECbEYo1slMtyo+2kMqscYYDSjU/TVgS3018F4=
|
||||
github.com/metacubex/sing-quic v0.0.0-20250511034158-b46e0e3e81b2/go.mod h1:P1kd57U6XXmXv9PbwWdznUGT0k9bKgFJXF0fEORbIlk=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.9 h1:2e++13WNN7EGjGtvrGLUzW1xrCdQbW2gIFpgw5GEw00=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.9/go.mod h1:CJSEGO4FWQAWe+ZiLZxCweGdjRR60A61SIoVjdjQeBA=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.3 h1:v3rNS/5Ywh0NIZ6VU/NmdERQIN5RePzyxCFeQsU4Cx0=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.2.3/go.mod h1:/WNy/Q8ahLCoPRriWuFZFD0Jy+JNp1MEQl28Zw6SaF8=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
|
||||
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250524142129-9d110c0af70c h1:Y6jk7AH5BEg9Dsvczrf/KokYsvxeKSZZlCLHg+hC4ro=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250524142129-9d110c0af70c/go.mod h1:HDaHDL6onAX2ZGbAGUXKp++PohRdNb7Nzt6zxzhox+U=
|
||||
github.com/metacubex/sing-vmess v0.2.2 h1:nG6GIKF1UOGmlzs+BIetdGHkFZ20YqFVIYp5Htqzp+4=
|
||||
github.com/metacubex/sing-vmess v0.2.2/go.mod h1:CVDNcdSLVYFgTHQlubr88d8CdqupAUDqLjROos+H9xk=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250503065609-efb9f0beb6f6 h1:TAwL91XPa6x1QK55CRm+VTzPvLPUfEr/uFDnOZArqEU=
|
||||
github.com/metacubex/sing-tun v0.4.6-0.20250503065609-efb9f0beb6f6/go.mod h1:HDaHDL6onAX2ZGbAGUXKp++PohRdNb7Nzt6zxzhox+U=
|
||||
github.com/metacubex/sing-vmess v0.2.1 h1:I6gM3VUjtvJ15D805EUbNH+SRBuqzJeFnuIbKYUsWZ0=
|
||||
github.com/metacubex/sing-vmess v0.2.1/go.mod h1:DsODWItJtOMZNna8Qhheg8r3tUivrcO3vWgaTYKnfTo=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f/go.mod h1:jpAkVLPnCpGSfNyVmj6Cq4YbuZsFepm/Dc+9BAOcR80=
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee h1:lp6hJ+4wCLZu113awp7P6odM2okB5s60HUyF0FMqKmo=
|
||||
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/metacubex/utls v1.7.3 h1:yDcMEWojFh+t8rU9X0HPcZDPAoFze/rIIyssqivzj8A=
|
||||
github.com/metacubex/utls v1.7.3/go.mod h1:oknYT0qTOwE4hjPmZOEpzVdefnW7bAdGLvZcqmk4TLU=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250503140532-decbcfccbfdf h1:LwID1wz4tzypidd412dd4dC1H0m1TgRCQ/XvRvMJDFM=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250503140532-decbcfccbfdf/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/metacubex/utls v1.7.0-alpha.3 h1:cp1cEMUnoifiWrGHRzo+nCwPRveN9yPD8QaRFmfcYxA=
|
||||
github.com/metacubex/utls v1.7.0-alpha.3/go.mod h1:oknYT0qTOwE4hjPmZOEpzVdefnW7bAdGLvZcqmk4TLU=
|
||||
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=
|
||||
|
||||
@@ -66,11 +66,6 @@ class ClashCore {
|
||||
|
||||
Future<bool> init() async {
|
||||
await initGeo();
|
||||
if (globalState.config.appSetting.openLogs) {
|
||||
clashCore.startLog();
|
||||
} else {
|
||||
clashCore.stopLog();
|
||||
}
|
||||
final homeDirPath = await appPath.homeDirPath;
|
||||
return await clashInterface.init(
|
||||
InitParams(
|
||||
|
||||
@@ -6,7 +6,7 @@ import 'dart:isolate';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/common/constant.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/models/models.dart';
|
||||
import 'package:fl_clash/plugins/service.dart';
|
||||
@@ -240,19 +240,18 @@ class ClashLibHandler {
|
||||
return DateTime.fromMillisecondsSinceEpoch(int.parse(runTimeString));
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> getConfig(String id) async {
|
||||
final path = await appPath.getProfilePath(id);
|
||||
final pathChar = path.toNativeUtf8().cast<Char>();
|
||||
final configRaw = clashFFI.getConfig(pathChar);
|
||||
final configString = configRaw.cast<Utf8>().toDartString();
|
||||
if (configString.isEmpty) {
|
||||
return {};
|
||||
}
|
||||
final config = json.decode(configString);
|
||||
malloc.free(pathChar);
|
||||
clashFFI.freeCString(configRaw);
|
||||
return config;
|
||||
}
|
||||
// Map<String, dynamic> getConfig(String path) {
|
||||
// final pathChar = path.toNativeUtf8().cast<Char>();
|
||||
// final configRaw = clashFFI.getConfig(pathChar);
|
||||
// final configString = configRaw.cast<Utf8>().toDartString();
|
||||
// if (configString.isEmpty) {
|
||||
// return {};
|
||||
// }
|
||||
// final config = json.decode(configString);
|
||||
// malloc.free(pathChar);
|
||||
// clashFFI.freeCString(configRaw);
|
||||
// return config;
|
||||
// }
|
||||
|
||||
Future<String> quickStart(
|
||||
InitParams initParams,
|
||||
@@ -290,4 +289,4 @@ ClashLib? get clashLib =>
|
||||
Platform.isAndroid && !globalState.isService ? ClashLib() : null;
|
||||
|
||||
ClashLibHandler? get clashLibHandler =>
|
||||
Platform.isAndroid && globalState.isService ? ClashLibHandler() : null;
|
||||
Platform.isAndroid ? ClashLibHandler() : null;
|
||||
|
||||
@@ -11,6 +11,7 @@ export 'future.dart';
|
||||
export 'http.dart';
|
||||
export 'icons.dart';
|
||||
export 'iterable.dart';
|
||||
export 'javascript.dart';
|
||||
export 'keyboard.dart';
|
||||
export 'launch.dart';
|
||||
export 'link.dart';
|
||||
|
||||
@@ -28,7 +28,6 @@ final defaultTextScaleFactor =
|
||||
const httpTimeoutDuration = Duration(milliseconds: 5000);
|
||||
const moreDuration = Duration(milliseconds: 100);
|
||||
const animateDuration = Duration(milliseconds: 100);
|
||||
const midDuration = Duration(milliseconds: 200);
|
||||
const commonDuration = Duration(milliseconds: 300);
|
||||
const defaultUpdateDuration = Duration(days: 1);
|
||||
const mmdbFileName = "geoip.metadb";
|
||||
|
||||
@@ -18,7 +18,6 @@ class FlClashHttpOverrides extends HttpOverrides {
|
||||
@override
|
||||
HttpClient createHttpClient(SecurityContext? context) {
|
||||
final client = super.createHttpClient(context);
|
||||
client.badCertificateCallback = (_, __, ___) => true;
|
||||
client.findProxy = handleFindProxy;
|
||||
return client;
|
||||
}
|
||||
|
||||
18
lib/common/javascript.dart
Normal file
18
lib/common/javascript.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:flutter_js/flutter_js.dart';
|
||||
|
||||
class Javascript {
|
||||
static Javascript? _instance;
|
||||
|
||||
Javascript._internal();
|
||||
|
||||
JavascriptRuntime get runTime {
|
||||
return getJavascriptRuntime();
|
||||
}
|
||||
|
||||
factory Javascript() {
|
||||
_instance ??= Javascript._internal();
|
||||
return _instance!;
|
||||
}
|
||||
}
|
||||
|
||||
final js = Javascript();
|
||||
@@ -1,10 +1,11 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import 'constant.dart';
|
||||
|
||||
class AppPath {
|
||||
static AppPath? _instance;
|
||||
Completer<Directory> dataDir = Completer();
|
||||
@@ -77,28 +78,17 @@ class AppPath {
|
||||
return join(directory, "$id.yaml");
|
||||
}
|
||||
|
||||
Future<String> getProvidersDirPath(String id) async {
|
||||
Future<String> getProvidersPath(String id, {String filePath = ""}) async {
|
||||
final directory = await profilesPath;
|
||||
return join(
|
||||
final path = join(
|
||||
directory,
|
||||
"providers",
|
||||
id,
|
||||
);
|
||||
}
|
||||
|
||||
Future<String> getProvidersFilePath(
|
||||
String id,
|
||||
String type,
|
||||
String url,
|
||||
) async {
|
||||
final directory = await profilesPath;
|
||||
return join(
|
||||
directory,
|
||||
"providers",
|
||||
id,
|
||||
type,
|
||||
url.toMd5(),
|
||||
);
|
||||
if (filePath.isNotEmpty) {
|
||||
return join(path, filePath);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
Future<String> get tempPath async {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
@@ -44,16 +43,6 @@ class Request {
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<Response> getTextResponseForUrl(String url) async {
|
||||
final response = await _clashDio.get(
|
||||
url,
|
||||
options: Options(
|
||||
responseType: ResponseType.plain,
|
||||
),
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<MemoryImage?> getImage(String url) async {
|
||||
if (url.isEmpty) return null;
|
||||
final response = await _dio.get<Uint8List>(
|
||||
@@ -91,37 +80,37 @@ class Request {
|
||||
"https://ipinfo.io/json/": IpInfo.fromIpInfoIoJson,
|
||||
};
|
||||
|
||||
Future<Result<IpInfo?>> checkIp({CancelToken? cancelToken}) async {
|
||||
var failureCount = 0;
|
||||
final futures = _ipInfoSources.entries.map((source) async {
|
||||
final Completer<Result<IpInfo?>> completer = Completer();
|
||||
final future = Dio().get<Map<String, dynamic>>(
|
||||
source.key,
|
||||
cancelToken: cancelToken,
|
||||
options: Options(
|
||||
responseType: ResponseType.json,
|
||||
),
|
||||
);
|
||||
future.then((res) {
|
||||
if (res.statusCode == HttpStatus.ok && res.data != null) {
|
||||
completer.complete(Result.success(source.value(res.data!)));
|
||||
} else {
|
||||
failureCount++;
|
||||
if (failureCount == _ipInfoSources.length) {
|
||||
completer.complete(Result.success(null));
|
||||
}
|
||||
Future<IpInfo?> checkIp({CancelToken? cancelToken}) async {
|
||||
for (final source in _ipInfoSources.entries) {
|
||||
try {
|
||||
final response = await Dio()
|
||||
.get<Map<String, dynamic>>(
|
||||
source.key,
|
||||
cancelToken: cancelToken,
|
||||
options: Options(
|
||||
responseType: ResponseType.json,
|
||||
),
|
||||
)
|
||||
.timeout(
|
||||
Duration(
|
||||
seconds: 30,
|
||||
),
|
||||
);
|
||||
if (response.statusCode != 200 || response.data == null) {
|
||||
continue;
|
||||
}
|
||||
}).catchError((e) {
|
||||
failureCount++;
|
||||
if (e == DioExceptionType.cancel) {
|
||||
completer.complete(Result.error("cancelled"));
|
||||
if (response.data == null) {
|
||||
continue;
|
||||
}
|
||||
});
|
||||
return completer.future;
|
||||
});
|
||||
final res = await Future.any(futures);
|
||||
cancelToken?.cancel();
|
||||
return res;
|
||||
return source.value(response.data!);
|
||||
} catch (e) {
|
||||
commonPrint.log("checkIp error ===> $e");
|
||||
if (e is DioException && e.type == DioExceptionType.cancel) {
|
||||
throw "cancelled";
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<bool> pingHelper() async {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
|
||||
import 'print.dart';
|
||||
|
||||
extension StringExtension on String {
|
||||
@@ -47,10 +45,6 @@ extension StringExtension on String {
|
||||
}
|
||||
}
|
||||
|
||||
bool get isSvg {
|
||||
return endsWith(".svg");
|
||||
}
|
||||
|
||||
bool get isRegex {
|
||||
try {
|
||||
RegExp(this);
|
||||
@@ -61,11 +55,6 @@ extension StringExtension on String {
|
||||
}
|
||||
}
|
||||
|
||||
String toMd5() {
|
||||
final bytes = utf8.encode(this);
|
||||
return md5.convert(bytes).toString();
|
||||
}
|
||||
|
||||
// bool containsToLower(String target) {
|
||||
// return toLowerCase().contains(target);
|
||||
// }
|
||||
|
||||
@@ -10,7 +10,6 @@ import 'package:flutter/services.dart';
|
||||
|
||||
class System {
|
||||
static System? _instance;
|
||||
List<String>? originDns;
|
||||
|
||||
System._internal();
|
||||
|
||||
@@ -105,100 +104,6 @@ class System {
|
||||
return AuthorizeCode.error;
|
||||
}
|
||||
|
||||
Future<String?> getMacOSDefaultServiceName() async {
|
||||
if (!Platform.isMacOS) {
|
||||
return null;
|
||||
}
|
||||
final result = await Process.run('route', ['-n', 'get', 'default']);
|
||||
final output = result.stdout.toString();
|
||||
final deviceLine = output
|
||||
.split('\n')
|
||||
.firstWhere((s) => s.contains('interface:'), orElse: () => "");
|
||||
final lineSplits = deviceLine.trim().split(' ');
|
||||
if (lineSplits.length != 2) {
|
||||
return null;
|
||||
}
|
||||
final device = lineSplits[1];
|
||||
final serviceResult = await Process.run(
|
||||
'networksetup',
|
||||
['-listnetworkserviceorder'],
|
||||
);
|
||||
final serviceResultOutput = serviceResult.stdout.toString();
|
||||
final currentService = serviceResultOutput.split('\n\n').firstWhere(
|
||||
(s) => s.contains("Device: $device"),
|
||||
orElse: () => "",
|
||||
);
|
||||
if (currentService.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final currentServiceNameLine = currentService.split("\n").firstWhere(
|
||||
(line) => RegExp(r'^\(\d+\).*').hasMatch(line),
|
||||
orElse: () => "");
|
||||
final currentServiceNameLineSplits =
|
||||
currentServiceNameLine.trim().split(' ');
|
||||
if (currentServiceNameLineSplits.length < 2) {
|
||||
return null;
|
||||
}
|
||||
return currentServiceNameLineSplits[1];
|
||||
}
|
||||
|
||||
Future<List<String>?> getMacOSOriginDns() async {
|
||||
if (!Platform.isMacOS) {
|
||||
return null;
|
||||
}
|
||||
final deviceServiceName = await getMacOSDefaultServiceName();
|
||||
if (deviceServiceName == null) {
|
||||
return null;
|
||||
}
|
||||
final result = await Process.run(
|
||||
'networksetup',
|
||||
['-getdnsservers', deviceServiceName],
|
||||
);
|
||||
final output = result.stdout.toString().trim();
|
||||
if (output.startsWith("There aren't any DNS Servers set on")) {
|
||||
originDns = [];
|
||||
} else {
|
||||
originDns = output.split("\n");
|
||||
}
|
||||
return originDns;
|
||||
}
|
||||
|
||||
setMacOSDns(bool restore) async {
|
||||
if (!Platform.isMacOS) {
|
||||
return;
|
||||
}
|
||||
final serviceName = await getMacOSDefaultServiceName();
|
||||
if (serviceName == null) {
|
||||
return;
|
||||
}
|
||||
List<String>? nextDns;
|
||||
if (restore) {
|
||||
nextDns = originDns;
|
||||
} else {
|
||||
final originDns = await system.getMacOSOriginDns();
|
||||
if (originDns == null) {
|
||||
return;
|
||||
}
|
||||
final needAddDns = "223.5.5.5";
|
||||
if (originDns.contains(needAddDns)) {
|
||||
return;
|
||||
}
|
||||
nextDns = List.from(originDns)..add(needAddDns);
|
||||
}
|
||||
if (nextDns == null) {
|
||||
return;
|
||||
}
|
||||
await Process.run(
|
||||
'networksetup',
|
||||
[
|
||||
'-setdnsservers',
|
||||
serviceName,
|
||||
if (nextDns.isNotEmpty) ...nextDns,
|
||||
if (nextDns.isEmpty) "Empty",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
back() async {
|
||||
await app?.moveTaskToBack();
|
||||
await window?.hide();
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:lpinyin/lpinyin.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
class Utils {
|
||||
Color? getDelayColor(int? delay) {
|
||||
@@ -336,51 +337,51 @@ class Utils {
|
||||
);
|
||||
}
|
||||
|
||||
// dynamic convertYamlNode(dynamic node) {
|
||||
// if (node is YamlMap) {
|
||||
// final map = <String, dynamic>{};
|
||||
// YamlNode? mergeKeyNode;
|
||||
// for (final entry in node.nodes.entries) {
|
||||
// if (entry.key is YamlScalar &&
|
||||
// (entry.key as YamlScalar).value == '<<') {
|
||||
// mergeKeyNode = entry.value;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (mergeKeyNode != null) {
|
||||
// final mergeValue = mergeKeyNode.value;
|
||||
// if (mergeValue is YamlMap) {
|
||||
// map.addAll(convertYamlNode(mergeValue) as Map<String, dynamic>);
|
||||
// } else if (mergeValue is YamlList) {
|
||||
// for (final node in mergeValue.nodes) {
|
||||
// if (node.value is YamlMap) {
|
||||
// map.addAll(convertYamlNode(node.value) as Map<String, dynamic>);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// node.nodes.forEach((key, value) {
|
||||
// String stringKey;
|
||||
// if (key is YamlScalar) {
|
||||
// stringKey = key.value.toString();
|
||||
// } else {
|
||||
// stringKey = key.toString();
|
||||
// }
|
||||
// map[stringKey] = convertYamlNode(value.value);
|
||||
// });
|
||||
// return map;
|
||||
// } else if (node is YamlList) {
|
||||
// final list = <dynamic>[];
|
||||
// for (final item in node.nodes) {
|
||||
// list.add(convertYamlNode(item.value));
|
||||
// }
|
||||
// return list;
|
||||
// } else if (node is YamlScalar) {
|
||||
// return node.value;
|
||||
// }
|
||||
// return node;
|
||||
// }
|
||||
dynamic convertYamlNode(dynamic node) {
|
||||
if (node is YamlMap) {
|
||||
final map = <String, dynamic>{};
|
||||
YamlNode? mergeKeyNode;
|
||||
for (final entry in node.nodes.entries) {
|
||||
if (entry.key is YamlScalar &&
|
||||
(entry.key as YamlScalar).value == '<<') {
|
||||
mergeKeyNode = entry.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mergeKeyNode != null) {
|
||||
final mergeValue = mergeKeyNode.value;
|
||||
if (mergeValue is YamlMap) {
|
||||
map.addAll(convertYamlNode(mergeValue) as Map<String, dynamic>);
|
||||
} else if (mergeValue is YamlList) {
|
||||
for (final node in mergeValue.nodes) {
|
||||
if (node.value is YamlMap) {
|
||||
map.addAll(convertYamlNode(node.value) as Map<String, dynamic>);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node.nodes.forEach((key, value) {
|
||||
String stringKey;
|
||||
if (key is YamlScalar) {
|
||||
stringKey = key.value.toString();
|
||||
} else {
|
||||
stringKey = key.toString();
|
||||
}
|
||||
map[stringKey] = convertYamlNode(value.value);
|
||||
});
|
||||
return map;
|
||||
} else if (node is YamlList) {
|
||||
final list = <dynamic>[];
|
||||
for (final item in node.nodes) {
|
||||
list.add(convertYamlNode(item.value));
|
||||
}
|
||||
return list;
|
||||
} else if (node is YamlScalar) {
|
||||
return node.value;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
FutureOr<T> handleWatch<T>(Function function) async {
|
||||
if (kDebugMode) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import 'models/models.dart';
|
||||
import 'views/profiles/override_profile.dart';
|
||||
|
||||
class AppController {
|
||||
bool lastTunEnable = false;
|
||||
int? lastProfileModified;
|
||||
|
||||
final BuildContext context;
|
||||
@@ -262,31 +263,29 @@ class AppController {
|
||||
if (res.isError) {
|
||||
return;
|
||||
}
|
||||
final realTunEnable = _ref.read(realTunEnableProvider);
|
||||
lastTunEnable = res.data == true;
|
||||
final message = await clashCore.updateConfig(
|
||||
updateParams.copyWith.tun(
|
||||
enable: realTunEnable,
|
||||
enable: lastTunEnable,
|
||||
),
|
||||
);
|
||||
if (message.isNotEmpty) throw message;
|
||||
}
|
||||
|
||||
Future<Result<bool>> _requestAdmin(bool enableTun) async {
|
||||
final realTunEnable = _ref.read(realTunEnableProvider);
|
||||
if (enableTun != realTunEnable && realTunEnable == false) {
|
||||
if (enableTun != lastTunEnable && lastTunEnable == false) {
|
||||
final code = await system.authorizeCore();
|
||||
switch (code) {
|
||||
case AuthorizeCode.none:
|
||||
return Result.success(enableTun);
|
||||
case AuthorizeCode.success:
|
||||
await restartCore();
|
||||
return Result.error("");
|
||||
case AuthorizeCode.none:
|
||||
break;
|
||||
case AuthorizeCode.error:
|
||||
enableTun = false;
|
||||
break;
|
||||
return Result.success(false);
|
||||
}
|
||||
}
|
||||
_ref.read(realTunEnableProvider.notifier).value = enableTun;
|
||||
return Result.success(enableTun);
|
||||
}
|
||||
|
||||
@@ -305,8 +304,8 @@ class AppController {
|
||||
if (res.isError) {
|
||||
return;
|
||||
}
|
||||
final realTunEnable = _ref.read(realTunEnableProvider);
|
||||
final realPatchConfig = patchConfig.copyWith.tun(enable: realTunEnable);
|
||||
lastTunEnable = res.data == true;
|
||||
final realPatchConfig = patchConfig.copyWith.tun(enable: lastTunEnable);
|
||||
final params = await globalState.getSetupParams(
|
||||
pathConfig: realPatchConfig,
|
||||
);
|
||||
@@ -444,7 +443,6 @@ class AppController {
|
||||
});
|
||||
try {
|
||||
await savePreferences();
|
||||
await system.setMacOSDns(true);
|
||||
await proxy?.stopProxy();
|
||||
await clashCore.shutdown();
|
||||
await clashService?.destroy();
|
||||
@@ -776,14 +774,14 @@ class AppController {
|
||||
|
||||
clearEffect(String profileId) async {
|
||||
final profilePath = await appPath.getProfilePath(profileId);
|
||||
final providersDirPath = await appPath.getProvidersDirPath(profileId);
|
||||
final providersPath = await appPath.getProvidersPath(profileId);
|
||||
return await Isolate.run(() async {
|
||||
final profileFile = File(profilePath);
|
||||
final isExists = await profileFile.exists();
|
||||
if (isExists) {
|
||||
profileFile.delete(recursive: true);
|
||||
}
|
||||
final providersFileDir = File(providersDirPath);
|
||||
final providersFileDir = File(providersPath);
|
||||
final providersFileIsExists = await providersFileDir.exists();
|
||||
if (providersFileIsExists) {
|
||||
providersFileDir.delete(recursive: true);
|
||||
@@ -1033,7 +1031,6 @@ class AppController {
|
||||
_ref.read(overrideDnsProvider.notifier).value = config.overrideDns;
|
||||
_ref.read(networkSettingProvider.notifier).value = config.networkProps;
|
||||
_ref.read(hotKeyActionsProvider.notifier).value = config.hotKeyActions;
|
||||
_ref.read(scriptStateProvider.notifier).value = config.scriptProps;
|
||||
}
|
||||
final currentProfile = _ref.read(currentProfileProvider);
|
||||
if (currentProfile == null) {
|
||||
|
||||
@@ -499,8 +499,3 @@ enum Language {
|
||||
yaml,
|
||||
javaScript,
|
||||
}
|
||||
|
||||
enum ImportOption {
|
||||
file,
|
||||
url,
|
||||
}
|
||||
|
||||
@@ -34,11 +34,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
|
||||
static String m5(label) => "${label} must be a number";
|
||||
|
||||
static String m6(label) => "${label} must be between 1024 and 49151";
|
||||
static String m6(count) => "${count} items have been selected";
|
||||
|
||||
static String m7(count) => "${count} items have been selected";
|
||||
|
||||
static String m8(label) => "${label} must be a url";
|
||||
static String m7(label) => "${label} must be a url";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
@@ -123,9 +121,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"autoRunDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Auto run when the application is opened",
|
||||
),
|
||||
"autoSetSystemDns": MessageLookupByLibrary.simpleMessage(
|
||||
"Auto set system DNS",
|
||||
),
|
||||
"autoUpdate": MessageLookupByLibrary.simpleMessage("Auto update"),
|
||||
"autoUpdateInterval": MessageLookupByLibrary.simpleMessage(
|
||||
"Auto update interval (minutes)",
|
||||
@@ -326,10 +321,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Icon configuration",
|
||||
),
|
||||
"iconStyle": MessageLookupByLibrary.simpleMessage("Icon style"),
|
||||
"import": MessageLookupByLibrary.simpleMessage("Import"),
|
||||
"importFile": MessageLookupByLibrary.simpleMessage("Import from file"),
|
||||
"importFromURL": MessageLookupByLibrary.simpleMessage("Import from URL"),
|
||||
"importUrl": MessageLookupByLibrary.simpleMessage("Import from URL"),
|
||||
"infiniteTime": MessageLookupByLibrary.simpleMessage("Long term effective"),
|
||||
"init": MessageLookupByLibrary.simpleMessage("Init"),
|
||||
"inputCorrectHotkey": MessageLookupByLibrary.simpleMessage(
|
||||
@@ -390,7 +382,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Modify the default system exit event",
|
||||
),
|
||||
"minutes": MessageLookupByLibrary.simpleMessage("Minutes"),
|
||||
"mixedPort": MessageLookupByLibrary.simpleMessage("Mixed Port"),
|
||||
"mode": MessageLookupByLibrary.simpleMessage("Mode"),
|
||||
"monochromeScheme": MessageLookupByLibrary.simpleMessage("Monochrome"),
|
||||
"months": MessageLookupByLibrary.simpleMessage("Months"),
|
||||
@@ -487,10 +478,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Please upload a valid QR code",
|
||||
),
|
||||
"port": MessageLookupByLibrary.simpleMessage("Port"),
|
||||
"portConflictTip": MessageLookupByLibrary.simpleMessage(
|
||||
"Please enter a different port",
|
||||
),
|
||||
"portTip": m6,
|
||||
"preferH3Desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Prioritize the use of DOH\'s http/3",
|
||||
),
|
||||
@@ -537,6 +524,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"proxyPortDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Set the Clash listening port",
|
||||
),
|
||||
"proxyPortTip": MessageLookupByLibrary.simpleMessage(
|
||||
"proxy port must be between 1024 and 49151",
|
||||
),
|
||||
"proxyProviders": MessageLookupByLibrary.simpleMessage("Proxy providers"),
|
||||
"pureBlackMode": MessageLookupByLibrary.simpleMessage("Pure black mode"),
|
||||
"qrcode": MessageLookupByLibrary.simpleMessage("QR code"),
|
||||
@@ -559,7 +549,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Override",
|
||||
),
|
||||
"recoverySuccess": MessageLookupByLibrary.simpleMessage("Recovery success"),
|
||||
"redirPort": MessageLookupByLibrary.simpleMessage("Redir Port"),
|
||||
"redo": MessageLookupByLibrary.simpleMessage("redo"),
|
||||
"regExp": MessageLookupByLibrary.simpleMessage("RegExp"),
|
||||
"remote": MessageLookupByLibrary.simpleMessage("Remote"),
|
||||
@@ -611,7 +600,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"seconds": MessageLookupByLibrary.simpleMessage("Seconds"),
|
||||
"selectAll": MessageLookupByLibrary.simpleMessage("Select all"),
|
||||
"selected": MessageLookupByLibrary.simpleMessage("Selected"),
|
||||
"selectedCountTitle": m7,
|
||||
"selectedCountTitle": m6,
|
||||
"settings": MessageLookupByLibrary.simpleMessage("Settings"),
|
||||
"show": MessageLookupByLibrary.simpleMessage("Show"),
|
||||
"shrink": MessageLookupByLibrary.simpleMessage("Shrink"),
|
||||
@@ -620,7 +609,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Start in the background",
|
||||
),
|
||||
"size": MessageLookupByLibrary.simpleMessage("Size"),
|
||||
"socksPort": MessageLookupByLibrary.simpleMessage("Socks Port"),
|
||||
"sort": MessageLookupByLibrary.simpleMessage("Sort"),
|
||||
"source": MessageLookupByLibrary.simpleMessage("Source"),
|
||||
"sourceIp": MessageLookupByLibrary.simpleMessage("Source IP"),
|
||||
@@ -669,7 +657,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"toggle": MessageLookupByLibrary.simpleMessage("Toggle"),
|
||||
"tonalSpotScheme": MessageLookupByLibrary.simpleMessage("TonalSpot"),
|
||||
"tools": MessageLookupByLibrary.simpleMessage("Tools"),
|
||||
"tproxyPort": MessageLookupByLibrary.simpleMessage("Tproxy Port"),
|
||||
"trafficUsage": MessageLookupByLibrary.simpleMessage("Traffic usage"),
|
||||
"tun": MessageLookupByLibrary.simpleMessage("TUN"),
|
||||
"tunDesc": MessageLookupByLibrary.simpleMessage(
|
||||
@@ -692,7 +679,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"urlDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Obtain profile through URL",
|
||||
),
|
||||
"urlTip": m8,
|
||||
"urlTip": m7,
|
||||
"useHosts": MessageLookupByLibrary.simpleMessage("Use hosts"),
|
||||
"useSystemHosts": MessageLookupByLibrary.simpleMessage("Use system hosts"),
|
||||
"value": MessageLookupByLibrary.simpleMessage("Value"),
|
||||
|
||||
@@ -32,11 +32,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
|
||||
static String m5(label) => "${label}は数字でなければなりません";
|
||||
|
||||
static String m6(label) => "${label} は 1024 から 49151 の間でなければなりません";
|
||||
static String m6(count) => "${count} 項目が選択されています";
|
||||
|
||||
static String m7(count) => "${count} 項目が選択されています";
|
||||
|
||||
static String m8(label) => "${label}はURLである必要があります";
|
||||
static String m7(label) => "${label}はURLである必要があります";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
@@ -93,7 +91,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"autoLaunchDesc": MessageLookupByLibrary.simpleMessage("システムの自動起動に従う"),
|
||||
"autoRun": MessageLookupByLibrary.simpleMessage("自動実行"),
|
||||
"autoRunDesc": MessageLookupByLibrary.simpleMessage("アプリ起動時に自動実行"),
|
||||
"autoSetSystemDns": MessageLookupByLibrary.simpleMessage("オートセットシステムDNS"),
|
||||
"autoUpdate": MessageLookupByLibrary.simpleMessage("自動更新"),
|
||||
"autoUpdateInterval": MessageLookupByLibrary.simpleMessage("自動更新間隔(分)"),
|
||||
"backup": MessageLookupByLibrary.simpleMessage("バックアップ"),
|
||||
@@ -246,10 +243,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"icon": MessageLookupByLibrary.simpleMessage("アイコン"),
|
||||
"iconConfiguration": MessageLookupByLibrary.simpleMessage("アイコン設定"),
|
||||
"iconStyle": MessageLookupByLibrary.simpleMessage("アイコンスタイル"),
|
||||
"import": MessageLookupByLibrary.simpleMessage("インポート"),
|
||||
"importFile": MessageLookupByLibrary.simpleMessage("ファイルからインポート"),
|
||||
"importFromURL": MessageLookupByLibrary.simpleMessage("URLからインポート"),
|
||||
"importUrl": MessageLookupByLibrary.simpleMessage("URLからインポート"),
|
||||
"infiniteTime": MessageLookupByLibrary.simpleMessage("長期有効"),
|
||||
"init": MessageLookupByLibrary.simpleMessage("初期化"),
|
||||
"inputCorrectHotkey": MessageLookupByLibrary.simpleMessage("正しいホットキーを入力"),
|
||||
@@ -292,7 +286,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"システムの終了イベントを変更",
|
||||
),
|
||||
"minutes": MessageLookupByLibrary.simpleMessage("分"),
|
||||
"mixedPort": MessageLookupByLibrary.simpleMessage("混合ポート"),
|
||||
"mode": MessageLookupByLibrary.simpleMessage("モード"),
|
||||
"monochromeScheme": MessageLookupByLibrary.simpleMessage("モノクローム"),
|
||||
"months": MessageLookupByLibrary.simpleMessage("月"),
|
||||
@@ -371,8 +364,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"有効なQRコードをアップロードしてください",
|
||||
),
|
||||
"port": MessageLookupByLibrary.simpleMessage("ポート"),
|
||||
"portConflictTip": MessageLookupByLibrary.simpleMessage("別のポートを入力してください"),
|
||||
"portTip": m6,
|
||||
"preferH3Desc": MessageLookupByLibrary.simpleMessage("DOHのHTTP/3を優先使用"),
|
||||
"pressKeyboard": MessageLookupByLibrary.simpleMessage("キーボードを押してください"),
|
||||
"preview": MessageLookupByLibrary.simpleMessage("プレビュー"),
|
||||
@@ -409,6 +400,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
),
|
||||
"proxyPort": MessageLookupByLibrary.simpleMessage("プロキシポート"),
|
||||
"proxyPortDesc": MessageLookupByLibrary.simpleMessage("Clashのリスニングポートを設定"),
|
||||
"proxyPortTip": MessageLookupByLibrary.simpleMessage(
|
||||
"プロキシポートは1024から49151の間でなければなりません",
|
||||
),
|
||||
"proxyProviders": MessageLookupByLibrary.simpleMessage("プロキシプロバイダー"),
|
||||
"pureBlackMode": MessageLookupByLibrary.simpleMessage("純黒モード"),
|
||||
"qrcode": MessageLookupByLibrary.simpleMessage("QRコード"),
|
||||
@@ -423,7 +417,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"オーバーライド",
|
||||
),
|
||||
"recoverySuccess": MessageLookupByLibrary.simpleMessage("復元成功"),
|
||||
"redirPort": MessageLookupByLibrary.simpleMessage("Redirポート"),
|
||||
"redo": MessageLookupByLibrary.simpleMessage("やり直す"),
|
||||
"regExp": MessageLookupByLibrary.simpleMessage("正規表現"),
|
||||
"remote": MessageLookupByLibrary.simpleMessage("リモート"),
|
||||
@@ -465,14 +458,13 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"seconds": MessageLookupByLibrary.simpleMessage("秒"),
|
||||
"selectAll": MessageLookupByLibrary.simpleMessage("すべて選択"),
|
||||
"selected": MessageLookupByLibrary.simpleMessage("選択済み"),
|
||||
"selectedCountTitle": m7,
|
||||
"selectedCountTitle": m6,
|
||||
"settings": MessageLookupByLibrary.simpleMessage("設定"),
|
||||
"show": MessageLookupByLibrary.simpleMessage("表示"),
|
||||
"shrink": MessageLookupByLibrary.simpleMessage("縮小"),
|
||||
"silentLaunch": MessageLookupByLibrary.simpleMessage("バックグラウンド起動"),
|
||||
"silentLaunchDesc": MessageLookupByLibrary.simpleMessage("バックグラウンドで起動"),
|
||||
"size": MessageLookupByLibrary.simpleMessage("サイズ"),
|
||||
"socksPort": MessageLookupByLibrary.simpleMessage("Socksポート"),
|
||||
"sort": MessageLookupByLibrary.simpleMessage("並び替え"),
|
||||
"source": MessageLookupByLibrary.simpleMessage("ソース"),
|
||||
"sourceIp": MessageLookupByLibrary.simpleMessage("送信元IP"),
|
||||
@@ -513,7 +505,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"toggle": MessageLookupByLibrary.simpleMessage("トグル"),
|
||||
"tonalSpotScheme": MessageLookupByLibrary.simpleMessage("トーンスポット"),
|
||||
"tools": MessageLookupByLibrary.simpleMessage("ツール"),
|
||||
"tproxyPort": MessageLookupByLibrary.simpleMessage("Tproxyポート"),
|
||||
"trafficUsage": MessageLookupByLibrary.simpleMessage("トラフィック使用量"),
|
||||
"tun": MessageLookupByLibrary.simpleMessage("TUN"),
|
||||
"tunDesc": MessageLookupByLibrary.simpleMessage("管理者モードでのみ有効"),
|
||||
@@ -532,7 +523,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"upload": MessageLookupByLibrary.simpleMessage("アップロード"),
|
||||
"url": MessageLookupByLibrary.simpleMessage("URL"),
|
||||
"urlDesc": MessageLookupByLibrary.simpleMessage("URL経由でプロファイルを取得"),
|
||||
"urlTip": m8,
|
||||
"urlTip": m7,
|
||||
"useHosts": MessageLookupByLibrary.simpleMessage("ホストを使用"),
|
||||
"useSystemHosts": MessageLookupByLibrary.simpleMessage("システムホストを使用"),
|
||||
"value": MessageLookupByLibrary.simpleMessage("値"),
|
||||
|
||||
@@ -33,11 +33,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
|
||||
static String m5(label) => "${label} должно быть числом";
|
||||
|
||||
static String m6(label) => "${label} должен быть числом от 1024 до 49151";
|
||||
static String m6(count) => "Выбрано ${count} элементов";
|
||||
|
||||
static String m7(count) => "Выбрано ${count} элементов";
|
||||
|
||||
static String m8(label) => "${label} должен быть URL";
|
||||
static String m7(label) => "${label} должен быть URL";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
@@ -120,9 +118,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"autoRunDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Автоматический запуск при открытии приложения",
|
||||
),
|
||||
"autoSetSystemDns": MessageLookupByLibrary.simpleMessage(
|
||||
"Автоматическая настройка системного DNS",
|
||||
),
|
||||
"autoUpdate": MessageLookupByLibrary.simpleMessage("Автообновление"),
|
||||
"autoUpdateInterval": MessageLookupByLibrary.simpleMessage(
|
||||
"Интервал автообновления (минуты)",
|
||||
@@ -345,10 +340,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Конфигурация иконки",
|
||||
),
|
||||
"iconStyle": MessageLookupByLibrary.simpleMessage("Стиль иконки"),
|
||||
"import": MessageLookupByLibrary.simpleMessage("Импорт"),
|
||||
"importFile": MessageLookupByLibrary.simpleMessage("Импорт из файла"),
|
||||
"importFromURL": MessageLookupByLibrary.simpleMessage("Импорт из URL"),
|
||||
"importUrl": MessageLookupByLibrary.simpleMessage("Импорт по URL"),
|
||||
"infiniteTime": MessageLookupByLibrary.simpleMessage(
|
||||
"Долгосрочное действие",
|
||||
),
|
||||
@@ -415,7 +407,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Изменить стандартное событие выхода из системы",
|
||||
),
|
||||
"minutes": MessageLookupByLibrary.simpleMessage("Минут"),
|
||||
"mixedPort": MessageLookupByLibrary.simpleMessage("Смешанный порт"),
|
||||
"mode": MessageLookupByLibrary.simpleMessage("Режим"),
|
||||
"monochromeScheme": MessageLookupByLibrary.simpleMessage("Монохром"),
|
||||
"months": MessageLookupByLibrary.simpleMessage("Месяцев"),
|
||||
@@ -516,10 +507,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Пожалуйста, загрузите действительный QR-код",
|
||||
),
|
||||
"port": MessageLookupByLibrary.simpleMessage("Порт"),
|
||||
"portConflictTip": MessageLookupByLibrary.simpleMessage(
|
||||
"Введите другой порт",
|
||||
),
|
||||
"portTip": m6,
|
||||
"preferH3Desc": MessageLookupByLibrary.simpleMessage(
|
||||
"Приоритетное использование HTTP/3 для DOH",
|
||||
),
|
||||
@@ -568,6 +555,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"proxyPortDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Установить порт прослушивания Clash",
|
||||
),
|
||||
"proxyPortTip": MessageLookupByLibrary.simpleMessage(
|
||||
"Порт прокси должен быть в диапазоне от 1024 до 49151",
|
||||
),
|
||||
"proxyProviders": MessageLookupByLibrary.simpleMessage("Провайдеры прокси"),
|
||||
"pureBlackMode": MessageLookupByLibrary.simpleMessage("Чисто черный режим"),
|
||||
"qrcode": MessageLookupByLibrary.simpleMessage("QR-код"),
|
||||
@@ -594,7 +584,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"recoverySuccess": MessageLookupByLibrary.simpleMessage(
|
||||
"Восстановление успешно",
|
||||
),
|
||||
"redirPort": MessageLookupByLibrary.simpleMessage("Redir-порт"),
|
||||
"redo": MessageLookupByLibrary.simpleMessage("Повторить"),
|
||||
"regExp": MessageLookupByLibrary.simpleMessage("Регулярное выражение"),
|
||||
"remote": MessageLookupByLibrary.simpleMessage("Удаленный"),
|
||||
@@ -648,7 +637,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"seconds": MessageLookupByLibrary.simpleMessage("Секунд"),
|
||||
"selectAll": MessageLookupByLibrary.simpleMessage("Выбрать все"),
|
||||
"selected": MessageLookupByLibrary.simpleMessage("Выбрано"),
|
||||
"selectedCountTitle": m7,
|
||||
"selectedCountTitle": m6,
|
||||
"settings": MessageLookupByLibrary.simpleMessage("Настройки"),
|
||||
"show": MessageLookupByLibrary.simpleMessage("Показать"),
|
||||
"shrink": MessageLookupByLibrary.simpleMessage("Сжать"),
|
||||
@@ -657,7 +646,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"Запуск в фоновом режиме",
|
||||
),
|
||||
"size": MessageLookupByLibrary.simpleMessage("Размер"),
|
||||
"socksPort": MessageLookupByLibrary.simpleMessage("Socks-порт"),
|
||||
"sort": MessageLookupByLibrary.simpleMessage("Сортировка"),
|
||||
"source": MessageLookupByLibrary.simpleMessage("Источник"),
|
||||
"sourceIp": MessageLookupByLibrary.simpleMessage("Исходный IP"),
|
||||
@@ -706,7 +694,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"toggle": MessageLookupByLibrary.simpleMessage("Переключить"),
|
||||
"tonalSpotScheme": MessageLookupByLibrary.simpleMessage("Тональный акцент"),
|
||||
"tools": MessageLookupByLibrary.simpleMessage("Инструменты"),
|
||||
"tproxyPort": MessageLookupByLibrary.simpleMessage("Tproxy-порт"),
|
||||
"trafficUsage": MessageLookupByLibrary.simpleMessage(
|
||||
"Использование трафика",
|
||||
),
|
||||
@@ -733,7 +720,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"urlDesc": MessageLookupByLibrary.simpleMessage(
|
||||
"Получить профиль через URL",
|
||||
),
|
||||
"urlTip": m8,
|
||||
"urlTip": m7,
|
||||
"useHosts": MessageLookupByLibrary.simpleMessage("Использовать hosts"),
|
||||
"useSystemHosts": MessageLookupByLibrary.simpleMessage(
|
||||
"Использовать системные hosts",
|
||||
|
||||
@@ -32,11 +32,9 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
|
||||
static String m5(label) => "${label}必须为数字";
|
||||
|
||||
static String m6(label) => "${label} 必须在 1024 到 49151 之间";
|
||||
static String m6(count) => "已选择 ${count} 项";
|
||||
|
||||
static String m7(count) => "已选择 ${count} 项";
|
||||
|
||||
static String m8(label) => "${label}必须为URL";
|
||||
static String m7(label) => "${label}必须为URL";
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
@@ -87,7 +85,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"autoLaunchDesc": MessageLookupByLibrary.simpleMessage("跟随系统自启动"),
|
||||
"autoRun": MessageLookupByLibrary.simpleMessage("自动运行"),
|
||||
"autoRunDesc": MessageLookupByLibrary.simpleMessage("应用打开时自动运行"),
|
||||
"autoSetSystemDns": MessageLookupByLibrary.simpleMessage("自动设置系统DNS"),
|
||||
"autoUpdate": MessageLookupByLibrary.simpleMessage("自动更新"),
|
||||
"autoUpdateInterval": MessageLookupByLibrary.simpleMessage("自动更新间隔(分钟)"),
|
||||
"backup": MessageLookupByLibrary.simpleMessage("备份"),
|
||||
@@ -222,10 +219,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"icon": MessageLookupByLibrary.simpleMessage("图片"),
|
||||
"iconConfiguration": MessageLookupByLibrary.simpleMessage("图片配置"),
|
||||
"iconStyle": MessageLookupByLibrary.simpleMessage("图标样式"),
|
||||
"import": MessageLookupByLibrary.simpleMessage("导入"),
|
||||
"importFile": MessageLookupByLibrary.simpleMessage("通过文件导入"),
|
||||
"importFromURL": MessageLookupByLibrary.simpleMessage("从URL导入"),
|
||||
"importUrl": MessageLookupByLibrary.simpleMessage("通过URL导入"),
|
||||
"infiniteTime": MessageLookupByLibrary.simpleMessage("长期有效"),
|
||||
"init": MessageLookupByLibrary.simpleMessage("初始化"),
|
||||
"inputCorrectHotkey": MessageLookupByLibrary.simpleMessage("请输入正确的快捷键"),
|
||||
@@ -264,7 +258,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"minimizeOnExit": MessageLookupByLibrary.simpleMessage("退出时最小化"),
|
||||
"minimizeOnExitDesc": MessageLookupByLibrary.simpleMessage("修改系统默认退出事件"),
|
||||
"minutes": MessageLookupByLibrary.simpleMessage("分钟"),
|
||||
"mixedPort": MessageLookupByLibrary.simpleMessage("混合端口"),
|
||||
"mode": MessageLookupByLibrary.simpleMessage("模式"),
|
||||
"monochromeScheme": MessageLookupByLibrary.simpleMessage("单色"),
|
||||
"months": MessageLookupByLibrary.simpleMessage("月"),
|
||||
@@ -325,8 +318,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"请上传有效的二维码",
|
||||
),
|
||||
"port": MessageLookupByLibrary.simpleMessage("端口"),
|
||||
"portConflictTip": MessageLookupByLibrary.simpleMessage("请输入不同的端口"),
|
||||
"portTip": m6,
|
||||
"preferH3Desc": MessageLookupByLibrary.simpleMessage("优先使用DOH的http/3"),
|
||||
"pressKeyboard": MessageLookupByLibrary.simpleMessage("请按下按键"),
|
||||
"preview": MessageLookupByLibrary.simpleMessage("预览"),
|
||||
@@ -359,6 +350,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"proxyNameserverDesc": MessageLookupByLibrary.simpleMessage("用于解析代理节点的域名"),
|
||||
"proxyPort": MessageLookupByLibrary.simpleMessage("代理端口"),
|
||||
"proxyPortDesc": MessageLookupByLibrary.simpleMessage("设置Clash监听端口"),
|
||||
"proxyPortTip": MessageLookupByLibrary.simpleMessage("代理端口必须在1024到49151之间"),
|
||||
"proxyProviders": MessageLookupByLibrary.simpleMessage("代理提供者"),
|
||||
"pureBlackMode": MessageLookupByLibrary.simpleMessage("纯黑模式"),
|
||||
"qrcode": MessageLookupByLibrary.simpleMessage("二维码"),
|
||||
@@ -371,7 +363,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"recoveryStrategy_compatible": MessageLookupByLibrary.simpleMessage("兼容"),
|
||||
"recoveryStrategy_override": MessageLookupByLibrary.simpleMessage("覆盖"),
|
||||
"recoverySuccess": MessageLookupByLibrary.simpleMessage("恢复成功"),
|
||||
"redirPort": MessageLookupByLibrary.simpleMessage("Redir端口"),
|
||||
"redo": MessageLookupByLibrary.simpleMessage("重做"),
|
||||
"regExp": MessageLookupByLibrary.simpleMessage("正则"),
|
||||
"remote": MessageLookupByLibrary.simpleMessage("远程"),
|
||||
@@ -407,14 +398,13 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"seconds": MessageLookupByLibrary.simpleMessage("秒"),
|
||||
"selectAll": MessageLookupByLibrary.simpleMessage("全选"),
|
||||
"selected": MessageLookupByLibrary.simpleMessage("已选择"),
|
||||
"selectedCountTitle": m7,
|
||||
"selectedCountTitle": m6,
|
||||
"settings": MessageLookupByLibrary.simpleMessage("设置"),
|
||||
"show": MessageLookupByLibrary.simpleMessage("显示"),
|
||||
"shrink": MessageLookupByLibrary.simpleMessage("紧凑"),
|
||||
"silentLaunch": MessageLookupByLibrary.simpleMessage("静默启动"),
|
||||
"silentLaunchDesc": MessageLookupByLibrary.simpleMessage("后台启动"),
|
||||
"size": MessageLookupByLibrary.simpleMessage("尺寸"),
|
||||
"socksPort": MessageLookupByLibrary.simpleMessage("Socks端口"),
|
||||
"sort": MessageLookupByLibrary.simpleMessage("排序"),
|
||||
"source": MessageLookupByLibrary.simpleMessage("来源"),
|
||||
"sourceIp": MessageLookupByLibrary.simpleMessage("源IP"),
|
||||
@@ -453,7 +443,6 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"toggle": MessageLookupByLibrary.simpleMessage("切换"),
|
||||
"tonalSpotScheme": MessageLookupByLibrary.simpleMessage("调性点缀"),
|
||||
"tools": MessageLookupByLibrary.simpleMessage("工具"),
|
||||
"tproxyPort": MessageLookupByLibrary.simpleMessage("Tproxy端口"),
|
||||
"trafficUsage": MessageLookupByLibrary.simpleMessage("流量统计"),
|
||||
"tun": MessageLookupByLibrary.simpleMessage("虚拟网卡"),
|
||||
"tunDesc": MessageLookupByLibrary.simpleMessage("仅在管理员模式生效"),
|
||||
@@ -470,7 +459,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"upload": MessageLookupByLibrary.simpleMessage("上传"),
|
||||
"url": MessageLookupByLibrary.simpleMessage("URL"),
|
||||
"urlDesc": MessageLookupByLibrary.simpleMessage("通过URL获取配置文件"),
|
||||
"urlTip": m8,
|
||||
"urlTip": m7,
|
||||
"useHosts": MessageLookupByLibrary.simpleMessage("使用Hosts"),
|
||||
"useSystemHosts": MessageLookupByLibrary.simpleMessage("使用系统Hosts"),
|
||||
"value": MessageLookupByLibrary.simpleMessage("值"),
|
||||
|
||||
@@ -2970,6 +2970,16 @@ class AppLocalizations {
|
||||
);
|
||||
}
|
||||
|
||||
/// `proxy port must be between 1024 and 49151`
|
||||
String get proxyPortTip {
|
||||
return Intl.message(
|
||||
'proxy port must be between 1024 and 49151',
|
||||
name: 'proxyPortTip',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `{label} must be a number`
|
||||
String numberTip(Object label) {
|
||||
return Intl.message(
|
||||
@@ -3064,81 +3074,6 @@ class AppLocalizations {
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Mixed Port`
|
||||
String get mixedPort {
|
||||
return Intl.message('Mixed Port', name: 'mixedPort', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `Socks Port`
|
||||
String get socksPort {
|
||||
return Intl.message('Socks Port', name: 'socksPort', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `Redir Port`
|
||||
String get redirPort {
|
||||
return Intl.message('Redir Port', name: 'redirPort', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `Tproxy Port`
|
||||
String get tproxyPort {
|
||||
return Intl.message('Tproxy Port', name: 'tproxyPort', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `{label} must be between 1024 and 49151`
|
||||
String portTip(Object label) {
|
||||
return Intl.message(
|
||||
'$label must be between 1024 and 49151',
|
||||
name: 'portTip',
|
||||
desc: '',
|
||||
args: [label],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Please enter a different port`
|
||||
String get portConflictTip {
|
||||
return Intl.message(
|
||||
'Please enter a different port',
|
||||
name: 'portConflictTip',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Import`
|
||||
String get import {
|
||||
return Intl.message('Import', name: 'import', desc: '', args: []);
|
||||
}
|
||||
|
||||
/// `Import from file`
|
||||
String get importFile {
|
||||
return Intl.message(
|
||||
'Import from file',
|
||||
name: 'importFile',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Import from URL`
|
||||
String get importUrl {
|
||||
return Intl.message(
|
||||
'Import from URL',
|
||||
name: 'importUrl',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Auto set system DNS`
|
||||
String get autoSetSystemDns {
|
||||
return Intl.message(
|
||||
'Auto set system DNS',
|
||||
name: 'autoSetSystemDns',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<AppLocalizations> {
|
||||
|
||||
@@ -62,7 +62,6 @@ Future<void> _service(List<String> flags) async {
|
||||
vpn?.addListener(
|
||||
_VpnListenerWithService(
|
||||
onDnsChanged: (String dns) {
|
||||
print("handle dns $dns");
|
||||
clashLibHandler.updateDns(dns);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -41,34 +41,10 @@ class _AppStateManagerState extends ConsumerState<AppStateManager>
|
||||
},
|
||||
fireImmediately: true,
|
||||
);
|
||||
ref.listenManual(configStateProvider, (prev, next) {
|
||||
if (prev != next) {
|
||||
globalState.appController.savePreferencesDebounce();
|
||||
}
|
||||
});
|
||||
ref.listenManual(
|
||||
autoSetSystemDnsStateProvider,
|
||||
(prev, next) async {
|
||||
if (prev == next) {
|
||||
return;
|
||||
}
|
||||
if (next.a == true && next.b == true) {
|
||||
system.setMacOSDns(false);
|
||||
} else {
|
||||
system.setMacOSDns(true);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
reassemble() {
|
||||
super.reassemble();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() async {
|
||||
await system.setMacOSDns(true);
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ class _ClashContainerState extends ConsumerState<ClashManager>
|
||||
clashCore.stopLog();
|
||||
}
|
||||
},
|
||||
fireImmediately: true,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ class MessageManagerState extends State<MessageManager> {
|
||||
key: Key(messages.last.id),
|
||||
builder: (_, constraints) {
|
||||
return Card(
|
||||
shape: const RoundedSuperellipseBorder(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(12.0),
|
||||
),
|
||||
|
||||
@@ -102,10 +102,9 @@ class _WindowContainerState extends ConsumerState<WindowManager>
|
||||
}
|
||||
|
||||
@override
|
||||
void onWindowRestore() {
|
||||
commonPrint.log("restore");
|
||||
render?.resume();
|
||||
super.onWindowRestore();
|
||||
Future<void> onTaskbarCreated() async {
|
||||
// globalState.appController.updateTray(true);
|
||||
super.onTaskbarCreated();
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -32,7 +32,6 @@ class AppState with _$AppState {
|
||||
required FixedList<Traffic> traffics,
|
||||
required Traffic totalTraffic,
|
||||
@Default("") String proxiesQuery,
|
||||
@Default(false) bool realTunEnable,
|
||||
}) = _AppState;
|
||||
}
|
||||
|
||||
|
||||
@@ -200,24 +200,6 @@ class Tun with _$Tun {
|
||||
}
|
||||
}
|
||||
|
||||
extension TunExt on Tun {
|
||||
Tun getRealTun(RouteMode routeMode) {
|
||||
final mRouteAddress = routeMode == RouteMode.bypassPrivate
|
||||
? defaultBypassPrivateRouteAddress
|
||||
: routeAddress;
|
||||
return switch (system.isDesktop) {
|
||||
true => copyWith(
|
||||
autoRoute: true,
|
||||
routeAddress: [],
|
||||
),
|
||||
false => copyWith(
|
||||
autoRoute: mRouteAddress.isEmpty ? true : false,
|
||||
routeAddress: mRouteAddress,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class FallbackFilter with _$FallbackFilter {
|
||||
const factory FallbackFilter({
|
||||
@@ -476,10 +458,6 @@ class ClashConfigSnippet with _$ClashConfigSnippet {
|
||||
class ClashConfig with _$ClashConfig {
|
||||
const factory ClashConfig({
|
||||
@Default(defaultMixedPort) @JsonKey(name: "mixed-port") int mixedPort,
|
||||
@Default(0) @JsonKey(name: "socks-port") int socksPort,
|
||||
@Default(0) @JsonKey(name: "port") int port,
|
||||
@Default(0) @JsonKey(name: "redir-port") int redirPort,
|
||||
@Default(0) @JsonKey(name: "tproxy-port") int tproxyPort,
|
||||
@Default(Mode.rule) Mode mode,
|
||||
@Default(false) @JsonKey(name: "allow-lan") bool allowLan,
|
||||
@Default(LogLevel.error) @JsonKey(name: "log-level") LogLevel logLevel,
|
||||
|
||||
@@ -152,8 +152,7 @@ class NetworkProps with _$NetworkProps {
|
||||
const factory NetworkProps({
|
||||
@Default(true) bool systemProxy,
|
||||
@Default(defaultBypassDomain) List<String> bypassDomain,
|
||||
@Default(RouteMode.config) RouteMode routeMode,
|
||||
@Default(true) bool autoSetSystemDns,
|
||||
@Default(RouteMode.bypassPrivate) RouteMode routeMode,
|
||||
}) = _NetworkProps;
|
||||
|
||||
factory NetworkProps.fromJson(Map<String, Object?>? json) =>
|
||||
|
||||
@@ -36,7 +36,6 @@ mixin _$AppState {
|
||||
FixedList<Traffic> get traffics => throw _privateConstructorUsedError;
|
||||
Traffic get totalTraffic => throw _privateConstructorUsedError;
|
||||
String get proxiesQuery => throw _privateConstructorUsedError;
|
||||
bool get realTunEnable => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of AppState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -69,8 +68,7 @@ abstract class $AppStateCopyWith<$Res> {
|
||||
FixedList<Log> logs,
|
||||
FixedList<Traffic> traffics,
|
||||
Traffic totalTraffic,
|
||||
String proxiesQuery,
|
||||
bool realTunEnable});
|
||||
String proxiesQuery});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -107,7 +105,6 @@ class _$AppStateCopyWithImpl<$Res, $Val extends AppState>
|
||||
Object? traffics = null,
|
||||
Object? totalTraffic = null,
|
||||
Object? proxiesQuery = null,
|
||||
Object? realTunEnable = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
isInit: null == isInit
|
||||
@@ -186,10 +183,6 @@ class _$AppStateCopyWithImpl<$Res, $Val extends AppState>
|
||||
? _value.proxiesQuery
|
||||
: proxiesQuery // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
realTunEnable: null == realTunEnable
|
||||
? _value.realTunEnable
|
||||
: realTunEnable // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@@ -221,8 +214,7 @@ abstract class _$$AppStateImplCopyWith<$Res>
|
||||
FixedList<Log> logs,
|
||||
FixedList<Traffic> traffics,
|
||||
Traffic totalTraffic,
|
||||
String proxiesQuery,
|
||||
bool realTunEnable});
|
||||
String proxiesQuery});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -257,7 +249,6 @@ class __$$AppStateImplCopyWithImpl<$Res>
|
||||
Object? traffics = null,
|
||||
Object? totalTraffic = null,
|
||||
Object? proxiesQuery = null,
|
||||
Object? realTunEnable = null,
|
||||
}) {
|
||||
return _then(_$AppStateImpl(
|
||||
isInit: null == isInit
|
||||
@@ -336,10 +327,6 @@ class __$$AppStateImplCopyWithImpl<$Res>
|
||||
? _value.proxiesQuery
|
||||
: proxiesQuery // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
realTunEnable: null == realTunEnable
|
||||
? _value.realTunEnable
|
||||
: realTunEnable // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -366,8 +353,7 @@ class _$AppStateImpl implements _AppState {
|
||||
required this.logs,
|
||||
required this.traffics,
|
||||
required this.totalTraffic,
|
||||
this.proxiesQuery = "",
|
||||
this.realTunEnable = false})
|
||||
this.proxiesQuery = ""})
|
||||
: _packages = packages,
|
||||
_delayMap = delayMap,
|
||||
_groups = groups,
|
||||
@@ -445,13 +431,10 @@ class _$AppStateImpl implements _AppState {
|
||||
@override
|
||||
@JsonKey()
|
||||
final String proxiesQuery;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool realTunEnable;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
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, proxiesQuery: $proxiesQuery, realTunEnable: $realTunEnable)';
|
||||
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, proxiesQuery: $proxiesQuery)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -487,9 +470,7 @@ class _$AppStateImpl implements _AppState {
|
||||
(identical(other.totalTraffic, totalTraffic) ||
|
||||
other.totalTraffic == totalTraffic) &&
|
||||
(identical(other.proxiesQuery, proxiesQuery) ||
|
||||
other.proxiesQuery == proxiesQuery) &&
|
||||
(identical(other.realTunEnable, realTunEnable) ||
|
||||
other.realTunEnable == realTunEnable));
|
||||
other.proxiesQuery == proxiesQuery));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -513,8 +494,7 @@ class _$AppStateImpl implements _AppState {
|
||||
logs,
|
||||
traffics,
|
||||
totalTraffic,
|
||||
proxiesQuery,
|
||||
realTunEnable
|
||||
proxiesQuery
|
||||
]);
|
||||
|
||||
/// Create a copy of AppState
|
||||
@@ -546,8 +526,7 @@ abstract class _AppState implements AppState {
|
||||
required final FixedList<Log> logs,
|
||||
required final FixedList<Traffic> traffics,
|
||||
required final Traffic totalTraffic,
|
||||
final String proxiesQuery,
|
||||
final bool realTunEnable}) = _$AppStateImpl;
|
||||
final String proxiesQuery}) = _$AppStateImpl;
|
||||
|
||||
@override
|
||||
bool get isInit;
|
||||
@@ -587,8 +566,6 @@ abstract class _AppState implements AppState {
|
||||
Traffic get totalTraffic;
|
||||
@override
|
||||
String get proxiesQuery;
|
||||
@override
|
||||
bool get realTunEnable;
|
||||
|
||||
/// Create a copy of AppState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
||||
@@ -3486,14 +3486,6 @@ ClashConfig _$ClashConfigFromJson(Map<String, dynamic> json) {
|
||||
mixin _$ClashConfig {
|
||||
@JsonKey(name: "mixed-port")
|
||||
int get mixedPort => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "socks-port")
|
||||
int get socksPort => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "port")
|
||||
int get port => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "redir-port")
|
||||
int get redirPort => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "tproxy-port")
|
||||
int get tproxyPort => throw _privateConstructorUsedError;
|
||||
Mode get mode => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "allow-lan")
|
||||
bool get allowLan => throw _privateConstructorUsedError;
|
||||
@@ -3544,10 +3536,6 @@ abstract class $ClashConfigCopyWith<$Res> {
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: "mixed-port") int mixedPort,
|
||||
@JsonKey(name: "socks-port") int socksPort,
|
||||
@JsonKey(name: "port") int port,
|
||||
@JsonKey(name: "redir-port") int redirPort,
|
||||
@JsonKey(name: "tproxy-port") int tproxyPort,
|
||||
Mode mode,
|
||||
@JsonKey(name: "allow-lan") bool allowLan,
|
||||
@JsonKey(name: "log-level") LogLevel logLevel,
|
||||
@@ -3591,10 +3579,6 @@ class _$ClashConfigCopyWithImpl<$Res, $Val extends ClashConfig>
|
||||
@override
|
||||
$Res call({
|
||||
Object? mixedPort = null,
|
||||
Object? socksPort = null,
|
||||
Object? port = null,
|
||||
Object? redirPort = null,
|
||||
Object? tproxyPort = null,
|
||||
Object? mode = null,
|
||||
Object? allowLan = null,
|
||||
Object? logLevel = null,
|
||||
@@ -3618,22 +3602,6 @@ class _$ClashConfigCopyWithImpl<$Res, $Val extends ClashConfig>
|
||||
? _value.mixedPort
|
||||
: mixedPort // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
socksPort: null == socksPort
|
||||
? _value.socksPort
|
||||
: socksPort // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
port: null == port
|
||||
? _value.port
|
||||
: port // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
redirPort: null == redirPort
|
||||
? _value.redirPort
|
||||
: redirPort // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
tproxyPort: null == tproxyPort
|
||||
? _value.tproxyPort
|
||||
: tproxyPort // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
mode: null == mode
|
||||
? _value.mode
|
||||
: mode // ignore: cast_nullable_to_non_nullable
|
||||
@@ -3746,10 +3714,6 @@ abstract class _$$ClashConfigImplCopyWith<$Res>
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: "mixed-port") int mixedPort,
|
||||
@JsonKey(name: "socks-port") int socksPort,
|
||||
@JsonKey(name: "port") int port,
|
||||
@JsonKey(name: "redir-port") int redirPort,
|
||||
@JsonKey(name: "tproxy-port") int tproxyPort,
|
||||
Mode mode,
|
||||
@JsonKey(name: "allow-lan") bool allowLan,
|
||||
@JsonKey(name: "log-level") LogLevel logLevel,
|
||||
@@ -3794,10 +3758,6 @@ class __$$ClashConfigImplCopyWithImpl<$Res>
|
||||
@override
|
||||
$Res call({
|
||||
Object? mixedPort = null,
|
||||
Object? socksPort = null,
|
||||
Object? port = null,
|
||||
Object? redirPort = null,
|
||||
Object? tproxyPort = null,
|
||||
Object? mode = null,
|
||||
Object? allowLan = null,
|
||||
Object? logLevel = null,
|
||||
@@ -3821,22 +3781,6 @@ class __$$ClashConfigImplCopyWithImpl<$Res>
|
||||
? _value.mixedPort
|
||||
: mixedPort // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
socksPort: null == socksPort
|
||||
? _value.socksPort
|
||||
: socksPort // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
port: null == port
|
||||
? _value.port
|
||||
: port // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
redirPort: null == redirPort
|
||||
? _value.redirPort
|
||||
: redirPort // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
tproxyPort: null == tproxyPort
|
||||
? _value.tproxyPort
|
||||
: tproxyPort // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
mode: null == mode
|
||||
? _value.mode
|
||||
: mode // ignore: cast_nullable_to_non_nullable
|
||||
@@ -3914,10 +3858,6 @@ class __$$ClashConfigImplCopyWithImpl<$Res>
|
||||
class _$ClashConfigImpl implements _ClashConfig {
|
||||
const _$ClashConfigImpl(
|
||||
{@JsonKey(name: "mixed-port") this.mixedPort = defaultMixedPort,
|
||||
@JsonKey(name: "socks-port") this.socksPort = 0,
|
||||
@JsonKey(name: "port") this.port = 0,
|
||||
@JsonKey(name: "redir-port") this.redirPort = 0,
|
||||
@JsonKey(name: "tproxy-port") this.tproxyPort = 0,
|
||||
this.mode = Mode.rule,
|
||||
@JsonKey(name: "allow-lan") this.allowLan = false,
|
||||
@JsonKey(name: "log-level") this.logLevel = LogLevel.error,
|
||||
@@ -3953,18 +3893,6 @@ class _$ClashConfigImpl implements _ClashConfig {
|
||||
@JsonKey(name: "mixed-port")
|
||||
final int mixedPort;
|
||||
@override
|
||||
@JsonKey(name: "socks-port")
|
||||
final int socksPort;
|
||||
@override
|
||||
@JsonKey(name: "port")
|
||||
final int port;
|
||||
@override
|
||||
@JsonKey(name: "redir-port")
|
||||
final int redirPort;
|
||||
@override
|
||||
@JsonKey(name: "tproxy-port")
|
||||
final int tproxyPort;
|
||||
@override
|
||||
@JsonKey()
|
||||
final Mode mode;
|
||||
@override
|
||||
@@ -4035,7 +3963,7 @@ class _$ClashConfigImpl implements _ClashConfig {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ClashConfig(mixedPort: $mixedPort, socksPort: $socksPort, port: $port, redirPort: $redirPort, tproxyPort: $tproxyPort, mode: $mode, allowLan: $allowLan, logLevel: $logLevel, ipv6: $ipv6, findProcessMode: $findProcessMode, keepAliveInterval: $keepAliveInterval, unifiedDelay: $unifiedDelay, tcpConcurrent: $tcpConcurrent, tun: $tun, dns: $dns, geoXUrl: $geoXUrl, geodataLoader: $geodataLoader, proxyGroups: $proxyGroups, rule: $rule, globalUa: $globalUa, externalController: $externalController, hosts: $hosts)';
|
||||
return 'ClashConfig(mixedPort: $mixedPort, mode: $mode, allowLan: $allowLan, logLevel: $logLevel, ipv6: $ipv6, findProcessMode: $findProcessMode, keepAliveInterval: $keepAliveInterval, unifiedDelay: $unifiedDelay, tcpConcurrent: $tcpConcurrent, tun: $tun, dns: $dns, geoXUrl: $geoXUrl, geodataLoader: $geodataLoader, proxyGroups: $proxyGroups, rule: $rule, globalUa: $globalUa, externalController: $externalController, hosts: $hosts)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -4045,13 +3973,6 @@ class _$ClashConfigImpl implements _ClashConfig {
|
||||
other is _$ClashConfigImpl &&
|
||||
(identical(other.mixedPort, mixedPort) ||
|
||||
other.mixedPort == mixedPort) &&
|
||||
(identical(other.socksPort, socksPort) ||
|
||||
other.socksPort == socksPort) &&
|
||||
(identical(other.port, port) || other.port == port) &&
|
||||
(identical(other.redirPort, redirPort) ||
|
||||
other.redirPort == redirPort) &&
|
||||
(identical(other.tproxyPort, tproxyPort) ||
|
||||
other.tproxyPort == tproxyPort) &&
|
||||
(identical(other.mode, mode) || other.mode == mode) &&
|
||||
(identical(other.allowLan, allowLan) ||
|
||||
other.allowLan == allowLan) &&
|
||||
@@ -4083,31 +4004,26 @@ class _$ClashConfigImpl implements _ClashConfig {
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hashAll([
|
||||
runtimeType,
|
||||
mixedPort,
|
||||
socksPort,
|
||||
port,
|
||||
redirPort,
|
||||
tproxyPort,
|
||||
mode,
|
||||
allowLan,
|
||||
logLevel,
|
||||
ipv6,
|
||||
findProcessMode,
|
||||
keepAliveInterval,
|
||||
unifiedDelay,
|
||||
tcpConcurrent,
|
||||
tun,
|
||||
dns,
|
||||
geoXUrl,
|
||||
geodataLoader,
|
||||
const DeepCollectionEquality().hash(_proxyGroups),
|
||||
const DeepCollectionEquality().hash(_rule),
|
||||
globalUa,
|
||||
externalController,
|
||||
const DeepCollectionEquality().hash(_hosts)
|
||||
]);
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
mixedPort,
|
||||
mode,
|
||||
allowLan,
|
||||
logLevel,
|
||||
ipv6,
|
||||
findProcessMode,
|
||||
keepAliveInterval,
|
||||
unifiedDelay,
|
||||
tcpConcurrent,
|
||||
tun,
|
||||
dns,
|
||||
geoXUrl,
|
||||
geodataLoader,
|
||||
const DeepCollectionEquality().hash(_proxyGroups),
|
||||
const DeepCollectionEquality().hash(_rule),
|
||||
globalUa,
|
||||
externalController,
|
||||
const DeepCollectionEquality().hash(_hosts));
|
||||
|
||||
/// Create a copy of ClashConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -4128,10 +4044,6 @@ class _$ClashConfigImpl implements _ClashConfig {
|
||||
abstract class _ClashConfig implements ClashConfig {
|
||||
const factory _ClashConfig(
|
||||
{@JsonKey(name: "mixed-port") final int mixedPort,
|
||||
@JsonKey(name: "socks-port") final int socksPort,
|
||||
@JsonKey(name: "port") final int port,
|
||||
@JsonKey(name: "redir-port") final int redirPort,
|
||||
@JsonKey(name: "tproxy-port") final int tproxyPort,
|
||||
final Mode mode,
|
||||
@JsonKey(name: "allow-lan") final bool allowLan,
|
||||
@JsonKey(name: "log-level") final LogLevel logLevel,
|
||||
@@ -4161,18 +4073,6 @@ abstract class _ClashConfig implements ClashConfig {
|
||||
@JsonKey(name: "mixed-port")
|
||||
int get mixedPort;
|
||||
@override
|
||||
@JsonKey(name: "socks-port")
|
||||
int get socksPort;
|
||||
@override
|
||||
@JsonKey(name: "port")
|
||||
int get port;
|
||||
@override
|
||||
@JsonKey(name: "redir-port")
|
||||
int get redirPort;
|
||||
@override
|
||||
@JsonKey(name: "tproxy-port")
|
||||
int get tproxyPort;
|
||||
@override
|
||||
Mode get mode;
|
||||
@override
|
||||
@JsonKey(name: "allow-lan")
|
||||
|
||||
@@ -333,10 +333,6 @@ Map<String, dynamic> _$$ClashConfigSnippetImplToJson(
|
||||
_$ClashConfigImpl _$$ClashConfigImplFromJson(Map<String, dynamic> json) =>
|
||||
_$ClashConfigImpl(
|
||||
mixedPort: (json['mixed-port'] as num?)?.toInt() ?? defaultMixedPort,
|
||||
socksPort: (json['socks-port'] as num?)?.toInt() ?? 0,
|
||||
port: (json['port'] as num?)?.toInt() ?? 0,
|
||||
redirPort: (json['redir-port'] as num?)?.toInt() ?? 0,
|
||||
tproxyPort: (json['tproxy-port'] as num?)?.toInt() ?? 0,
|
||||
mode: $enumDecodeNullable(_$ModeEnumMap, json['mode']) ?? Mode.rule,
|
||||
allowLan: json['allow-lan'] as bool? ?? false,
|
||||
logLevel: $enumDecodeNullable(_$LogLevelEnumMap, json['log-level']) ??
|
||||
@@ -382,10 +378,6 @@ _$ClashConfigImpl _$$ClashConfigImplFromJson(Map<String, dynamic> json) =>
|
||||
Map<String, dynamic> _$$ClashConfigImplToJson(_$ClashConfigImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'mixed-port': instance.mixedPort,
|
||||
'socks-port': instance.socksPort,
|
||||
'port': instance.port,
|
||||
'redir-port': instance.redirPort,
|
||||
'tproxy-port': instance.tproxyPort,
|
||||
'mode': _$ModeEnumMap[instance.mode]!,
|
||||
'allow-lan': instance.allowLan,
|
||||
'log-level': _$LogLevelEnumMap[instance.logLevel]!,
|
||||
|
||||
@@ -1325,7 +1325,6 @@ mixin _$NetworkProps {
|
||||
bool get systemProxy => throw _privateConstructorUsedError;
|
||||
List<String> get bypassDomain => throw _privateConstructorUsedError;
|
||||
RouteMode get routeMode => throw _privateConstructorUsedError;
|
||||
bool get autoSetSystemDns => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this NetworkProps to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@@ -1343,11 +1342,7 @@ abstract class $NetworkPropsCopyWith<$Res> {
|
||||
NetworkProps value, $Res Function(NetworkProps) then) =
|
||||
_$NetworkPropsCopyWithImpl<$Res, NetworkProps>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{bool systemProxy,
|
||||
List<String> bypassDomain,
|
||||
RouteMode routeMode,
|
||||
bool autoSetSystemDns});
|
||||
$Res call({bool systemProxy, List<String> bypassDomain, RouteMode routeMode});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -1368,7 +1363,6 @@ class _$NetworkPropsCopyWithImpl<$Res, $Val extends NetworkProps>
|
||||
Object? systemProxy = null,
|
||||
Object? bypassDomain = null,
|
||||
Object? routeMode = null,
|
||||
Object? autoSetSystemDns = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
systemProxy: null == systemProxy
|
||||
@@ -1383,10 +1377,6 @@ class _$NetworkPropsCopyWithImpl<$Res, $Val extends NetworkProps>
|
||||
? _value.routeMode
|
||||
: routeMode // ignore: cast_nullable_to_non_nullable
|
||||
as RouteMode,
|
||||
autoSetSystemDns: null == autoSetSystemDns
|
||||
? _value.autoSetSystemDns
|
||||
: autoSetSystemDns // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@@ -1399,11 +1389,7 @@ abstract class _$$NetworkPropsImplCopyWith<$Res>
|
||||
__$$NetworkPropsImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{bool systemProxy,
|
||||
List<String> bypassDomain,
|
||||
RouteMode routeMode,
|
||||
bool autoSetSystemDns});
|
||||
$Res call({bool systemProxy, List<String> bypassDomain, RouteMode routeMode});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@@ -1422,7 +1408,6 @@ class __$$NetworkPropsImplCopyWithImpl<$Res>
|
||||
Object? systemProxy = null,
|
||||
Object? bypassDomain = null,
|
||||
Object? routeMode = null,
|
||||
Object? autoSetSystemDns = null,
|
||||
}) {
|
||||
return _then(_$NetworkPropsImpl(
|
||||
systemProxy: null == systemProxy
|
||||
@@ -1437,10 +1422,6 @@ class __$$NetworkPropsImplCopyWithImpl<$Res>
|
||||
? _value.routeMode
|
||||
: routeMode // ignore: cast_nullable_to_non_nullable
|
||||
as RouteMode,
|
||||
autoSetSystemDns: null == autoSetSystemDns
|
||||
? _value.autoSetSystemDns
|
||||
: autoSetSystemDns // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1451,8 +1432,7 @@ class _$NetworkPropsImpl implements _NetworkProps {
|
||||
const _$NetworkPropsImpl(
|
||||
{this.systemProxy = true,
|
||||
final List<String> bypassDomain = defaultBypassDomain,
|
||||
this.routeMode = RouteMode.config,
|
||||
this.autoSetSystemDns = true})
|
||||
this.routeMode = RouteMode.bypassPrivate})
|
||||
: _bypassDomain = bypassDomain;
|
||||
|
||||
factory _$NetworkPropsImpl.fromJson(Map<String, dynamic> json) =>
|
||||
@@ -1473,13 +1453,10 @@ class _$NetworkPropsImpl implements _NetworkProps {
|
||||
@override
|
||||
@JsonKey()
|
||||
final RouteMode routeMode;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool autoSetSystemDns;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NetworkProps(systemProxy: $systemProxy, bypassDomain: $bypassDomain, routeMode: $routeMode, autoSetSystemDns: $autoSetSystemDns)';
|
||||
return 'NetworkProps(systemProxy: $systemProxy, bypassDomain: $bypassDomain, routeMode: $routeMode)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1492,19 +1469,13 @@ class _$NetworkPropsImpl implements _NetworkProps {
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._bypassDomain, _bypassDomain) &&
|
||||
(identical(other.routeMode, routeMode) ||
|
||||
other.routeMode == routeMode) &&
|
||||
(identical(other.autoSetSystemDns, autoSetSystemDns) ||
|
||||
other.autoSetSystemDns == autoSetSystemDns));
|
||||
other.routeMode == routeMode));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
systemProxy,
|
||||
const DeepCollectionEquality().hash(_bypassDomain),
|
||||
routeMode,
|
||||
autoSetSystemDns);
|
||||
int get hashCode => Object.hash(runtimeType, systemProxy,
|
||||
const DeepCollectionEquality().hash(_bypassDomain), routeMode);
|
||||
|
||||
/// Create a copy of NetworkProps
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -1526,8 +1497,7 @@ abstract class _NetworkProps implements NetworkProps {
|
||||
const factory _NetworkProps(
|
||||
{final bool systemProxy,
|
||||
final List<String> bypassDomain,
|
||||
final RouteMode routeMode,
|
||||
final bool autoSetSystemDns}) = _$NetworkPropsImpl;
|
||||
final RouteMode routeMode}) = _$NetworkPropsImpl;
|
||||
|
||||
factory _NetworkProps.fromJson(Map<String, dynamic> json) =
|
||||
_$NetworkPropsImpl.fromJson;
|
||||
@@ -1538,8 +1508,6 @@ abstract class _NetworkProps implements NetworkProps {
|
||||
List<String> get bypassDomain;
|
||||
@override
|
||||
RouteMode get routeMode;
|
||||
@override
|
||||
bool get autoSetSystemDns;
|
||||
|
||||
/// Create a copy of NetworkProps
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
||||
@@ -160,8 +160,7 @@ _$NetworkPropsImpl _$$NetworkPropsImplFromJson(Map<String, dynamic> json) =>
|
||||
.toList() ??
|
||||
defaultBypassDomain,
|
||||
routeMode: $enumDecodeNullable(_$RouteModeEnumMap, json['routeMode']) ??
|
||||
RouteMode.config,
|
||||
autoSetSystemDns: json['autoSetSystemDns'] as bool? ?? true,
|
||||
RouteMode.bypassPrivate,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$NetworkPropsImplToJson(_$NetworkPropsImpl instance) =>
|
||||
@@ -169,7 +168,6 @@ Map<String, dynamic> _$$NetworkPropsImplToJson(_$NetworkPropsImpl instance) =>
|
||||
'systemProxy': instance.systemProxy,
|
||||
'bypassDomain': instance.bypassDomain,
|
||||
'routeMode': _$RouteModeEnumMap[instance.routeMode]!,
|
||||
'autoSetSystemDns': instance.autoSetSystemDns,
|
||||
};
|
||||
|
||||
const _$RouteModeEnumMap = {
|
||||
|
||||
@@ -514,215 +514,6 @@ abstract class _VM4<A, B, C, D> implements VM4<A, B, C, D> {
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$VM5<A, B, C, D, E> {
|
||||
A get a => throw _privateConstructorUsedError;
|
||||
B get b => throw _privateConstructorUsedError;
|
||||
C get c => throw _privateConstructorUsedError;
|
||||
D get d => throw _privateConstructorUsedError;
|
||||
E get e => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of VM5
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$VM5CopyWith<A, B, C, D, E, VM5<A, B, C, D, E>> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $VM5CopyWith<A, B, C, D, E, $Res> {
|
||||
factory $VM5CopyWith(
|
||||
VM5<A, B, C, D, E> value, $Res Function(VM5<A, B, C, D, E>) then) =
|
||||
_$VM5CopyWithImpl<A, B, C, D, E, $Res, VM5<A, B, C, D, E>>;
|
||||
@useResult
|
||||
$Res call({A a, B b, C c, D d, E e});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$VM5CopyWithImpl<A, B, C, D, E, $Res, $Val extends VM5<A, B, C, D, E>>
|
||||
implements $VM5CopyWith<A, B, C, D, E, $Res> {
|
||||
_$VM5CopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of VM5
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? a = freezed,
|
||||
Object? b = freezed,
|
||||
Object? c = freezed,
|
||||
Object? d = freezed,
|
||||
Object? e = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
a: freezed == a
|
||||
? _value.a
|
||||
: a // ignore: cast_nullable_to_non_nullable
|
||||
as A,
|
||||
b: freezed == b
|
||||
? _value.b
|
||||
: b // ignore: cast_nullable_to_non_nullable
|
||||
as B,
|
||||
c: freezed == c
|
||||
? _value.c
|
||||
: c // ignore: cast_nullable_to_non_nullable
|
||||
as C,
|
||||
d: freezed == d
|
||||
? _value.d
|
||||
: d // ignore: cast_nullable_to_non_nullable
|
||||
as D,
|
||||
e: freezed == e
|
||||
? _value.e
|
||||
: e // ignore: cast_nullable_to_non_nullable
|
||||
as E,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$VM5ImplCopyWith<A, B, C, D, E, $Res>
|
||||
implements $VM5CopyWith<A, B, C, D, E, $Res> {
|
||||
factory _$$VM5ImplCopyWith(_$VM5Impl<A, B, C, D, E> value,
|
||||
$Res Function(_$VM5Impl<A, B, C, D, E>) then) =
|
||||
__$$VM5ImplCopyWithImpl<A, B, C, D, E, $Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({A a, B b, C c, D d, E e});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$VM5ImplCopyWithImpl<A, B, C, D, E, $Res>
|
||||
extends _$VM5CopyWithImpl<A, B, C, D, E, $Res, _$VM5Impl<A, B, C, D, E>>
|
||||
implements _$$VM5ImplCopyWith<A, B, C, D, E, $Res> {
|
||||
__$$VM5ImplCopyWithImpl(_$VM5Impl<A, B, C, D, E> _value,
|
||||
$Res Function(_$VM5Impl<A, B, C, D, E>) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of VM5
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? a = freezed,
|
||||
Object? b = freezed,
|
||||
Object? c = freezed,
|
||||
Object? d = freezed,
|
||||
Object? e = freezed,
|
||||
}) {
|
||||
return _then(_$VM5Impl<A, B, C, D, E>(
|
||||
a: freezed == a
|
||||
? _value.a
|
||||
: a // ignore: cast_nullable_to_non_nullable
|
||||
as A,
|
||||
b: freezed == b
|
||||
? _value.b
|
||||
: b // ignore: cast_nullable_to_non_nullable
|
||||
as B,
|
||||
c: freezed == c
|
||||
? _value.c
|
||||
: c // ignore: cast_nullable_to_non_nullable
|
||||
as C,
|
||||
d: freezed == d
|
||||
? _value.d
|
||||
: d // ignore: cast_nullable_to_non_nullable
|
||||
as D,
|
||||
e: freezed == e
|
||||
? _value.e
|
||||
: e // ignore: cast_nullable_to_non_nullable
|
||||
as E,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$VM5Impl<A, B, C, D, E> implements _VM5<A, B, C, D, E> {
|
||||
const _$VM5Impl(
|
||||
{required this.a,
|
||||
required this.b,
|
||||
required this.c,
|
||||
required this.d,
|
||||
required this.e});
|
||||
|
||||
@override
|
||||
final A a;
|
||||
@override
|
||||
final B b;
|
||||
@override
|
||||
final C c;
|
||||
@override
|
||||
final D d;
|
||||
@override
|
||||
final E e;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'VM5<$A, $B, $C, $D, $E>(a: $a, b: $b, c: $c, d: $d, e: $e)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$VM5Impl<A, B, C, D, E> &&
|
||||
const DeepCollectionEquality().equals(other.a, a) &&
|
||||
const DeepCollectionEquality().equals(other.b, b) &&
|
||||
const DeepCollectionEquality().equals(other.c, c) &&
|
||||
const DeepCollectionEquality().equals(other.d, d) &&
|
||||
const DeepCollectionEquality().equals(other.e, e));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(a),
|
||||
const DeepCollectionEquality().hash(b),
|
||||
const DeepCollectionEquality().hash(c),
|
||||
const DeepCollectionEquality().hash(d),
|
||||
const DeepCollectionEquality().hash(e));
|
||||
|
||||
/// Create a copy of VM5
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$VM5ImplCopyWith<A, B, C, D, E, _$VM5Impl<A, B, C, D, E>> get copyWith =>
|
||||
__$$VM5ImplCopyWithImpl<A, B, C, D, E, _$VM5Impl<A, B, C, D, E>>(
|
||||
this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _VM5<A, B, C, D, E> implements VM5<A, B, C, D, E> {
|
||||
const factory _VM5(
|
||||
{required final A a,
|
||||
required final B b,
|
||||
required final C c,
|
||||
required final D d,
|
||||
required final E e}) = _$VM5Impl<A, B, C, D, E>;
|
||||
|
||||
@override
|
||||
A get a;
|
||||
@override
|
||||
B get b;
|
||||
@override
|
||||
C get c;
|
||||
@override
|
||||
D get d;
|
||||
@override
|
||||
E get e;
|
||||
|
||||
/// Create a copy of VM5
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$VM5ImplCopyWith<A, B, C, D, E, _$VM5Impl<A, B, C, D, E>> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$StartButtonSelectorState {
|
||||
bool get isInit => throw _privateConstructorUsedError;
|
||||
|
||||
@@ -34,17 +34,6 @@ class VM4<A, B, C, D> with _$VM4<A, B, C, D> {
|
||||
}) = _VM4;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class VM5<A, B, C, D, E> with _$VM5<A, B, C, D, E> {
|
||||
const factory VM5({
|
||||
required A a,
|
||||
required B b,
|
||||
required C c,
|
||||
required D d,
|
||||
required E e,
|
||||
}) = _VM5;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class StartButtonSelectorState with _$StartButtonSelectorState {
|
||||
const factory StartButtonSelectorState({
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/models/common.dart';
|
||||
import 'package:fl_clash/providers/app.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:fl_clash/widgets/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@@ -19,7 +18,6 @@ class EditorPage extends ConsumerStatefulWidget {
|
||||
final String title;
|
||||
final String content;
|
||||
final List<Language> languages;
|
||||
final bool supportRemoteDownload;
|
||||
final bool titleEditable;
|
||||
final Function(BuildContext context, String title, String content)? onSave;
|
||||
final Future<bool> Function(
|
||||
@@ -32,7 +30,6 @@ class EditorPage extends ConsumerStatefulWidget {
|
||||
this.titleEditable = false,
|
||||
this.onSave,
|
||||
this.onPop,
|
||||
this.supportRemoteDownload = false,
|
||||
this.languages = const [
|
||||
Language.yaml,
|
||||
],
|
||||
@@ -111,45 +108,6 @@ class _EditorPageState extends ConsumerState<EditorPage> {
|
||||
_findController.findMode();
|
||||
}
|
||||
|
||||
_handleImport() async {
|
||||
final option = await globalState.showCommonDialog<ImportOption>(
|
||||
child: _ImportOptionsDialog(),
|
||||
);
|
||||
if (option == null) {
|
||||
return;
|
||||
}
|
||||
if (option == ImportOption.file) {
|
||||
final file = await picker.pickerFile();
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
final res = String.fromCharCodes(file.bytes?.toList() ?? []);
|
||||
_controller.text = res;
|
||||
return;
|
||||
}
|
||||
final url = await globalState.showCommonDialog(
|
||||
child: InputDialog(
|
||||
title: "导入",
|
||||
value: "",
|
||||
labelText: appLocalizations.url,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return appLocalizations.emptyTip(appLocalizations.value);
|
||||
}
|
||||
if (!value.isUrl) {
|
||||
return appLocalizations.urlTip(appLocalizations.value);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
);
|
||||
if (url == null) {
|
||||
return;
|
||||
}
|
||||
final res = await request.getTextResponseForUrl(url);
|
||||
_controller.text = res.data;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isMobileView = ref.watch(isMobileViewProvider);
|
||||
@@ -199,13 +157,6 @@ class _EditorPageState extends ConsumerState<EditorPage> {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.supportRemoteDownload)
|
||||
IconButton(
|
||||
onPressed: _handleImport,
|
||||
icon: Icon(
|
||||
Icons.arrow_downward,
|
||||
),
|
||||
),
|
||||
_wrapController(
|
||||
(value) => CommonPopupBox(
|
||||
targetBuilder: (open) {
|
||||
@@ -251,7 +202,6 @@ class _EditorPageState extends ConsumerState<EditorPage> {
|
||||
padding: EdgeInsets.only(
|
||||
right: 16,
|
||||
),
|
||||
autocompleteSymbols: true,
|
||||
focusNode: _focusNode,
|
||||
scrollbarBuilder: (context, child, details) {
|
||||
return CommonScrollBar(
|
||||
@@ -678,45 +628,7 @@ class _NoInputBorder extends InputBorder {
|
||||
double gapExtent = 0.0,
|
||||
double gapPercentage = 0.0,
|
||||
TextDirection? textDirection,
|
||||
}) {}
|
||||
}
|
||||
|
||||
class _ImportOptionsDialog extends StatefulWidget {
|
||||
const _ImportOptionsDialog();
|
||||
|
||||
@override
|
||||
State<_ImportOptionsDialog> createState() => _ImportOptionsDialogState();
|
||||
}
|
||||
|
||||
class _ImportOptionsDialogState extends State<_ImportOptionsDialog> {
|
||||
_handleOnTab(ImportOption value) {
|
||||
Navigator.of(context).pop(value);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CommonDialog(
|
||||
title: appLocalizations.import,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 16,
|
||||
),
|
||||
child: Wrap(
|
||||
children: [
|
||||
ListItem(
|
||||
onTap: () {
|
||||
_handleOnTab(ImportOption.url);
|
||||
},
|
||||
title: Text(appLocalizations.importUrl),
|
||||
),
|
||||
ListItem(
|
||||
onTap: () {
|
||||
_handleOnTab(ImportOption.file);
|
||||
},
|
||||
title: Text(appLocalizations.importFile),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}) {
|
||||
// Do not paint.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,21 +8,6 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'generated/app.g.dart';
|
||||
|
||||
@riverpod
|
||||
class RealTunEnable extends _$RealTunEnable with AutoDisposeNotifierMixin {
|
||||
@override
|
||||
bool build() {
|
||||
return globalState.appState.realTunEnable;
|
||||
}
|
||||
|
||||
@override
|
||||
onUpdate(value) {
|
||||
globalState.appState = globalState.appState.copyWith(
|
||||
realTunEnable: value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class Logs extends _$Logs with AutoDisposeNotifierMixin {
|
||||
@override
|
||||
|
||||
@@ -285,10 +285,6 @@ class ScriptState extends _$ScriptState with AutoDisposeNotifierMixin {
|
||||
currentId: nextId,
|
||||
);
|
||||
}
|
||||
|
||||
isExits(String label) {
|
||||
return state.scripts.indexWhere((item) => item.label == label) != -1;
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
|
||||
@@ -70,22 +70,6 @@ final viewHeightProvider = AutoDisposeProvider<double>.internal(
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef ViewHeightRef = AutoDisposeProviderRef<double>;
|
||||
String _$realTunEnableHash() => r'a4e995c86deca4c8307966470e69d93d64a40df6';
|
||||
|
||||
/// See also [RealTunEnable].
|
||||
@ProviderFor(RealTunEnable)
|
||||
final realTunEnableProvider =
|
||||
AutoDisposeNotifierProvider<RealTunEnable, bool>.internal(
|
||||
RealTunEnable.new,
|
||||
name: r'realTunEnableProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$realTunEnableHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$RealTunEnable = AutoDisposeNotifier<bool>;
|
||||
String _$logsHash() => r'56fb8aa9d62a97b026b749d204576a7384084737';
|
||||
|
||||
/// See also [Logs].
|
||||
|
||||
@@ -178,7 +178,7 @@ final proxiesStyleSettingProvider =
|
||||
);
|
||||
|
||||
typedef _$ProxiesStyleSetting = AutoDisposeNotifier<ProxiesStyle>;
|
||||
String _$scriptStateHash() => r'884581c71fd5afa3c9d34f31625d967cf561cdbe';
|
||||
String _$scriptStateHash() => r'16d669009ffb233d95b2cb206cf771342ebc1cc1';
|
||||
|
||||
/// See also [ScriptState].
|
||||
@ProviderFor(ScriptState)
|
||||
|
||||
@@ -6,22 +6,6 @@ part of '../state.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$configStateHash() => r'1f4ea3cc8f6461ba734e7e0c5d7295bfa4fd5afb';
|
||||
|
||||
/// See also [configState].
|
||||
@ProviderFor(configState)
|
||||
final configStateProvider = AutoDisposeProvider<Config>.internal(
|
||||
configState,
|
||||
name: r'configStateProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$configStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef ConfigStateRef = AutoDisposeProviderRef<Config>;
|
||||
String _$currentGroupsStateHash() =>
|
||||
r'6222c006e1970e7435268d32903b9019cf1a4351';
|
||||
|
||||
@@ -94,7 +78,7 @@ final coreStateProvider = AutoDisposeProvider<CoreState>.internal(
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef CoreStateRef = AutoDisposeProviderRef<CoreState>;
|
||||
String _$updateParamsHash() => r'012df72ab0e769a51c573f4692031506d7b1f1b4';
|
||||
String _$updateParamsHash() => r'79fd7a5a8650fabac3a2ca7ce903c1d9eb363ed2';
|
||||
|
||||
/// See also [updateParams].
|
||||
@ProviderFor(updateParams)
|
||||
@@ -126,7 +110,7 @@ final proxyStateProvider = AutoDisposeProvider<ProxyState>.internal(
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef ProxyStateRef = AutoDisposeProviderRef<ProxyState>;
|
||||
String _$trayStateHash() => r'61c99bbae2cb7ed69dc9ee0f2149510eb6a87df4';
|
||||
String _$trayStateHash() => r'39ff84c50ad9c9cc666fa2538fe13ec0d7236b2e';
|
||||
|
||||
/// See also [trayState].
|
||||
@ProviderFor(trayState)
|
||||
@@ -1975,12 +1959,11 @@ class _GenColorSchemeProviderElement
|
||||
bool get ignoreConfig => (origin as GenColorSchemeProvider).ignoreConfig;
|
||||
}
|
||||
|
||||
String _$needSetupHash() => r'3668e8dc9f40a9bea45c94321804eb3afa0e7c51';
|
||||
String _$needSetupHash() => r'1116c73bb2964321de63bdca631a983d31e30d69';
|
||||
|
||||
/// See also [needSetup].
|
||||
@ProviderFor(needSetup)
|
||||
final needSetupProvider =
|
||||
AutoDisposeProvider<VM3<String?, String?, Dns?>>.internal(
|
||||
final needSetupProvider = AutoDisposeProvider<VM2>.internal(
|
||||
needSetup,
|
||||
name: r'needSetupProvider',
|
||||
debugGetCreateSourceHash:
|
||||
@@ -1991,26 +1974,7 @@ final needSetupProvider =
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef NeedSetupRef = AutoDisposeProviderRef<VM3<String?, String?, Dns?>>;
|
||||
String _$autoSetSystemDnsStateHash() =>
|
||||
r'2e0976e079100325b1ca797285df48a94c2c066c';
|
||||
|
||||
/// See also [autoSetSystemDnsState].
|
||||
@ProviderFor(autoSetSystemDnsState)
|
||||
final autoSetSystemDnsStateProvider =
|
||||
AutoDisposeProvider<VM2<bool, bool>>.internal(
|
||||
autoSetSystemDnsState,
|
||||
name: r'autoSetSystemDnsStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$autoSetSystemDnsStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef AutoSetSystemDnsStateRef = AutoDisposeProviderRef<VM2<bool, bool>>;
|
||||
typedef NeedSetupRef = AutoDisposeProviderRef<VM2>;
|
||||
String _$profileOverrideStateHash() =>
|
||||
r'fa26570a355ab39e27b1f93d1d2f358717065592';
|
||||
|
||||
|
||||
@@ -12,38 +12,6 @@ import 'config.dart';
|
||||
|
||||
part 'generated/state.g.dart';
|
||||
|
||||
@riverpod
|
||||
Config configState(Ref ref) {
|
||||
final themeProps = ref.watch(themeSettingProvider);
|
||||
final patchClashConfig = ref.watch(patchClashConfigProvider);
|
||||
final appSetting = ref.watch(appSettingProvider);
|
||||
final profiles = ref.watch(profilesProvider);
|
||||
final currentProfileId = ref.watch(currentProfileIdProvider);
|
||||
final overrideDns = ref.watch(overrideDnsProvider);
|
||||
final networkProps = ref.watch(networkSettingProvider);
|
||||
final vpnProps = ref.watch(vpnSettingProvider);
|
||||
final proxiesStyle = ref.watch(proxiesStyleSettingProvider);
|
||||
final scriptProps = ref.watch(scriptStateProvider);
|
||||
final hotKeyActions = ref.watch(hotKeyActionsProvider);
|
||||
final dav = ref.watch(appDAVSettingProvider);
|
||||
final windowProps = ref.watch(windowSettingProvider);
|
||||
return Config(
|
||||
dav: dav,
|
||||
windowProps: windowProps,
|
||||
hotKeyActions: hotKeyActions,
|
||||
scriptProps: scriptProps,
|
||||
proxiesStyle: proxiesStyle,
|
||||
vpnProps: vpnProps,
|
||||
networkProps: networkProps,
|
||||
overrideDns: overrideDns,
|
||||
currentProfileId: currentProfileId,
|
||||
profiles: profiles,
|
||||
appSetting: appSetting,
|
||||
themeProps: themeProps,
|
||||
patchClashConfig: patchClashConfig,
|
||||
);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
GroupsState currentGroupsState(Ref ref) {
|
||||
final mode =
|
||||
@@ -105,15 +73,10 @@ CoreState coreState(Ref ref) {
|
||||
|
||||
@riverpod
|
||||
UpdateParams updateParams(Ref ref) {
|
||||
final routeMode = ref.watch(
|
||||
networkSettingProvider.select(
|
||||
(state) => state.routeMode,
|
||||
),
|
||||
);
|
||||
return ref.watch(
|
||||
patchClashConfigProvider.select(
|
||||
(state) => UpdateParams(
|
||||
tun: state.tun.getRealTun(routeMode),
|
||||
tun: state.tun,
|
||||
allowLan: state.allowLan,
|
||||
findProcessMode: state.findProcessMode,
|
||||
mode: state.mode,
|
||||
@@ -158,11 +121,9 @@ TrayState trayState(Ref ref) {
|
||||
final appSetting = ref.watch(
|
||||
appSettingProvider,
|
||||
);
|
||||
final groups = ref
|
||||
.watch(
|
||||
currentGroupsStateProvider,
|
||||
)
|
||||
.value;
|
||||
final groups = ref.watch(
|
||||
groupsProvider,
|
||||
);
|
||||
final brightness = ref.watch(
|
||||
appBrightnessProvider,
|
||||
);
|
||||
@@ -629,34 +590,9 @@ ColorScheme genColorScheme(
|
||||
}
|
||||
|
||||
@riverpod
|
||||
VM3<String?, String?, Dns?> needSetup(Ref ref) {
|
||||
VM2 needSetup(Ref ref) {
|
||||
final profileId = ref.watch(currentProfileIdProvider);
|
||||
final content = ref.watch(
|
||||
scriptStateProvider.select((state) => state.currentScript?.content));
|
||||
final overrideDns = ref.watch(overrideDnsProvider);
|
||||
final dns = overrideDns == true
|
||||
? ref.watch(patchClashConfigProvider.select(
|
||||
(state) => state.dns,
|
||||
))
|
||||
: null;
|
||||
return VM3(
|
||||
a: profileId,
|
||||
b: content,
|
||||
c: dns,
|
||||
);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
VM2<bool, bool> autoSetSystemDnsState(Ref ref) {
|
||||
final isStart = ref.watch(runTimeProvider.select((state) => state != null));
|
||||
final realTunEnable = ref.watch(realTunEnableProvider);
|
||||
final autoSetSystemDns = ref.watch(
|
||||
networkSettingProvider.select(
|
||||
(state) => state.autoSetSystemDns,
|
||||
),
|
||||
);
|
||||
return VM2(
|
||||
a: isStart ? realTunEnable : false,
|
||||
b: autoSetSystemDns,
|
||||
);
|
||||
return VM2(a: profileId, b: content);
|
||||
}
|
||||
|
||||
206
lib/state.dart
206
lib/state.dart
@@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:ffi' show Pointer;
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:animations/animations.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
@@ -13,10 +14,10 @@ import 'package:fl_clash/plugins/service.dart';
|
||||
import 'package:fl_clash/widgets/dialog.dart';
|
||||
import 'package:fl_clash/widgets/scaffold.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_js/flutter_js.dart';
|
||||
import 'package:material_color_utilities/palettes/core_palette.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'common/common.dart';
|
||||
import 'controller.dart';
|
||||
@@ -191,26 +192,26 @@ class GlobalState {
|
||||
);
|
||||
}
|
||||
|
||||
// Future<Map<String, dynamic>> getProfileMap(String id) async {
|
||||
// final profilePath = await appPath.getProfilePath(id);
|
||||
// final res = await Isolate.run<Result<dynamic>>(() async {
|
||||
// try {
|
||||
// final file = File(profilePath);
|
||||
// if (!await file.exists()) {
|
||||
// return Result.error("");
|
||||
// }
|
||||
// final value = await file.readAsString();
|
||||
// return Result.success(utils.convertYamlNode(loadYaml(value)));
|
||||
// } catch (e) {
|
||||
// return Result.error(e.toString());
|
||||
// }
|
||||
// });
|
||||
// if (res.isSuccess) {
|
||||
// return res.data as Map<String, dynamic>;
|
||||
// } else {
|
||||
// throw res.message;
|
||||
// }
|
||||
// }
|
||||
Future<Map<String, dynamic>> getProfileMap(String id) async {
|
||||
final profilePath = await appPath.getProfilePath(id);
|
||||
final res = await Isolate.run<Result<dynamic>>(() async {
|
||||
try {
|
||||
final file = File(profilePath);
|
||||
if (!await file.exists()) {
|
||||
return Result.error("");
|
||||
}
|
||||
final value = await file.readAsString();
|
||||
return Result.success(utils.convertYamlNode(loadYaml(value)));
|
||||
} catch (e) {
|
||||
return Result.error(e.toString());
|
||||
}
|
||||
});
|
||||
if (res.isSuccess) {
|
||||
return res.data as Map<String, dynamic>;
|
||||
} else {
|
||||
throw res.message;
|
||||
}
|
||||
}
|
||||
|
||||
Future<T?> showCommonDialog<T>({
|
||||
required Widget child,
|
||||
@@ -313,10 +314,17 @@ class GlobalState {
|
||||
return {};
|
||||
}
|
||||
final profileId = profile.id;
|
||||
final configMap = await getProfileConfig(profileId);
|
||||
final rawConfig = await handleEvaluate(configMap);
|
||||
final realPatchConfig = patchConfig.copyWith(
|
||||
tun: patchConfig.tun.getRealTun(config.networkProps.routeMode),
|
||||
|
||||
final rawConfig =
|
||||
await handleEvaluate(await globalState.getProfileMap(profileId));
|
||||
|
||||
final routeAddress =
|
||||
config.networkProps.routeMode == RouteMode.bypassPrivate
|
||||
? defaultBypassPrivateRouteAddress
|
||||
: patchConfig.tun.routeAddress;
|
||||
final realPatchConfig = patchConfig.copyWith.tun(
|
||||
autoRoute: routeAddress.isEmpty ? true : false,
|
||||
routeAddress: routeAddress,
|
||||
);
|
||||
rawConfig["external-controller"] = realPatchConfig.externalController.value;
|
||||
rawConfig["external-ui"] = "";
|
||||
@@ -330,10 +338,6 @@ class GlobalState {
|
||||
rawConfig["socks-port"] = 0;
|
||||
rawConfig["keep-alive-interval"] = realPatchConfig.keepAliveInterval;
|
||||
rawConfig["mixed-port"] = realPatchConfig.mixedPort;
|
||||
rawConfig["port"] = realPatchConfig.port;
|
||||
rawConfig["socks-port"] = realPatchConfig.socksPort;
|
||||
rawConfig["redir-port"] = realPatchConfig.redirPort;
|
||||
rawConfig["tproxy-port"] = realPatchConfig.tproxyPort;
|
||||
rawConfig["find-process-mode"] = realPatchConfig.findProcessMode.name;
|
||||
rawConfig["allow-lan"] = realPatchConfig.allowLan;
|
||||
rawConfig["mode"] = realPatchConfig.mode.name;
|
||||
@@ -347,13 +351,8 @@ class GlobalState {
|
||||
rawConfig["tun"]["route-address"] = realPatchConfig.tun.routeAddress;
|
||||
rawConfig["tun"]["auto-route"] = realPatchConfig.tun.autoRoute;
|
||||
rawConfig["geodata-loader"] = realPatchConfig.geodataLoader.name;
|
||||
if (rawConfig["sniffer"]?["sniff"] != null) {
|
||||
for (final value in (rawConfig["sniffer"]?["sniff"] as Map).values) {
|
||||
if (value["ports"] != null && value["ports"] is List) {
|
||||
value["ports"] =
|
||||
value["ports"]?.map((item) => item.toString()).toList() ?? [];
|
||||
}
|
||||
}
|
||||
if (rawConfig["sniffer"] != null) {
|
||||
rawConfig["sniffer"] = Sniffer.fromJson(rawConfig["sniffer"]);
|
||||
}
|
||||
if (rawConfig["profile"] == null) {
|
||||
rawConfig["profile"] = {};
|
||||
@@ -362,15 +361,9 @@ class GlobalState {
|
||||
final proxyProviders = rawConfig["proxy-providers"] as Map;
|
||||
for (final key in proxyProviders.keys) {
|
||||
final proxyProvider = proxyProviders[key];
|
||||
if (proxyProvider["type"] != "http") {
|
||||
continue;
|
||||
}
|
||||
if (proxyProvider["url"] != null) {
|
||||
proxyProvider["path"] = await appPath.getProvidersFilePath(
|
||||
profile.id,
|
||||
"proxies",
|
||||
proxyProvider["url"],
|
||||
);
|
||||
if (proxyProvider["path"] != null) {
|
||||
proxyProvider["path"] = await appPath.getProvidersPath(profile.id,
|
||||
filePath: proxyProvider["path"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,15 +372,9 @@ class GlobalState {
|
||||
final ruleProviders = rawConfig["rule-providers"] as Map;
|
||||
for (final key in ruleProviders.keys) {
|
||||
final ruleProvider = ruleProviders[key];
|
||||
if (ruleProvider["type"] != "http") {
|
||||
continue;
|
||||
}
|
||||
if (ruleProvider["url"] != null) {
|
||||
ruleProvider["path"] = await appPath.getProvidersFilePath(
|
||||
profile.id,
|
||||
"rules",
|
||||
ruleProvider["url"],
|
||||
);
|
||||
if (ruleProvider["path"] != null) {
|
||||
ruleProvider["path"] = await appPath.getProvidersPath(profile.id,
|
||||
filePath: ruleProvider["path"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -401,27 +388,28 @@ class GlobalState {
|
||||
for (final host in realPatchConfig.hosts.entries) {
|
||||
rawConfig["hosts"][host.key] = host.value.splitByMultipleSeparators;
|
||||
}
|
||||
if (rawConfig["dns"] == null) {
|
||||
rawConfig["dns"] = {};
|
||||
}
|
||||
final isEnableDns = rawConfig["dns"]["enable"] == true;
|
||||
final overrideDns = globalState.config.overrideDns;
|
||||
if (overrideDns || !isEnableDns) {
|
||||
final dns = switch (!isEnableDns) {
|
||||
true => realPatchConfig.dns.copyWith(
|
||||
nameserver: [...realPatchConfig.dns.nameserver, "system://"]),
|
||||
false => realPatchConfig.dns,
|
||||
};
|
||||
rawConfig["dns"] = dns.toJson();
|
||||
if (overrideDns) {
|
||||
rawConfig["dns"] = realPatchConfig.dns.toJson();
|
||||
rawConfig["dns"]["nameserver-policy"] = {};
|
||||
for (final entry in dns.nameserverPolicy.entries) {
|
||||
for (final entry in realPatchConfig.dns.nameserverPolicy.entries) {
|
||||
rawConfig["dns"]["nameserver-policy"][entry.key] =
|
||||
entry.value.splitByMultipleSeparators;
|
||||
}
|
||||
} else {
|
||||
if (rawConfig["dns"] == null) {
|
||||
rawConfig["dns"] = {};
|
||||
}
|
||||
if (rawConfig["dns"]["enable"] != false) {
|
||||
rawConfig["dns"]["enable"] = true;
|
||||
}
|
||||
}
|
||||
var rules = [];
|
||||
// if (rawConfig["rule"] != null) {
|
||||
// rules.addAll(rawConfig["rule"]);
|
||||
// }
|
||||
if (rawConfig["rules"] != null) {
|
||||
rules = rawConfig["rules"];
|
||||
rules.addAll(rawConfig["rules"]);
|
||||
}
|
||||
rawConfig.remove("rules");
|
||||
|
||||
@@ -430,23 +418,13 @@ class GlobalState {
|
||||
if (overrideData.rule.type == OverrideRuleType.override) {
|
||||
rules = overrideData.runningRule;
|
||||
} else {
|
||||
rules = [...overrideData.runningRule, ...rules];
|
||||
rules.addAll(overrideData.runningRule);
|
||||
}
|
||||
}
|
||||
rawConfig["rule"] = rules;
|
||||
return rawConfig;
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> getProfileConfig(String profileId) async {
|
||||
final configMap = await switch (clashLibHandler != null) {
|
||||
true => clashLibHandler!.getConfig(profileId),
|
||||
false => clashCore.getConfig(profileId),
|
||||
};
|
||||
configMap["rules"] = configMap["rule"];
|
||||
configMap.remove("rule");
|
||||
return configMap;
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> handleEvaluate(
|
||||
Map<String, dynamic> config,
|
||||
) async {
|
||||
@@ -454,23 +432,17 @@ class GlobalState {
|
||||
if (currentScript == null) {
|
||||
return config;
|
||||
}
|
||||
if (config["proxy-providers"] == null) {
|
||||
config["proxy-providers"] = {};
|
||||
}
|
||||
final configJs = json.encode(config);
|
||||
final runtime = getJavascriptRuntime();
|
||||
final res = await runtime.evaluateAsync("""
|
||||
final runtime = js.runTime;
|
||||
final res = await js.runTime.evaluateAsync("""
|
||||
${currentScript.content}
|
||||
main($configJs)
|
||||
""");
|
||||
if (res.isError) {
|
||||
throw res.stringResult;
|
||||
}
|
||||
final value = switch (res.rawResult is Pointer) {
|
||||
true => runtime.convertValue<Map<String, dynamic>>(res),
|
||||
false => Map<String, dynamic>.from(res.rawResult),
|
||||
};
|
||||
return value ?? config;
|
||||
final value = runtime.convertValue<Map<String, dynamic>>(res) ?? config;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,9 +473,6 @@ class DetectionState {
|
||||
debouncer.call(
|
||||
FunctionTag.checkIp,
|
||||
_checkIp,
|
||||
duration: Duration(
|
||||
milliseconds: 1200,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -528,35 +497,36 @@ class DetectionState {
|
||||
cancelToken = null;
|
||||
}
|
||||
cancelToken = CancelToken();
|
||||
state.value = state.value.copyWith(
|
||||
isTesting: true,
|
||||
);
|
||||
final res = await request.checkIp(cancelToken: cancelToken);
|
||||
if (res.isError) {
|
||||
try {
|
||||
state.value = state.value.copyWith(
|
||||
isLoading: true,
|
||||
ipInfo: null,
|
||||
isTesting: true,
|
||||
);
|
||||
return;
|
||||
final ipInfo = await request.checkIp(cancelToken: cancelToken);
|
||||
state.value = state.value.copyWith(
|
||||
isTesting: false,
|
||||
);
|
||||
if (ipInfo != null) {
|
||||
state.value = state.value.copyWith(
|
||||
isLoading: false,
|
||||
ipInfo: ipInfo,
|
||||
);
|
||||
return;
|
||||
}
|
||||
_clearSetTimeoutTimer();
|
||||
_setTimeoutTimer = Timer(const Duration(milliseconds: 300), () {
|
||||
state.value = state.value.copyWith(
|
||||
isLoading: false,
|
||||
ipInfo: null,
|
||||
);
|
||||
});
|
||||
} catch (e) {
|
||||
if (e.toString() == "cancelled") {
|
||||
state.value = state.value.copyWith(
|
||||
isLoading: true,
|
||||
ipInfo: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
final ipInfo = res.data;
|
||||
state.value = state.value.copyWith(
|
||||
isTesting: false,
|
||||
);
|
||||
if (ipInfo != null) {
|
||||
state.value = state.value.copyWith(
|
||||
isLoading: false,
|
||||
ipInfo: ipInfo,
|
||||
);
|
||||
return;
|
||||
}
|
||||
_clearSetTimeoutTimer();
|
||||
_setTimeoutTimer = Timer(const Duration(milliseconds: 300), () {
|
||||
state.value = state.value.copyWith(
|
||||
isLoading: false,
|
||||
ipInfo: null,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
_clearSetTimeoutTimer() {
|
||||
|
||||
@@ -47,6 +47,15 @@ class AboutView extends StatelessWidget {
|
||||
_checkUpdate(context);
|
||||
},
|
||||
),
|
||||
ListItem(
|
||||
title: Text(appLocalizations.contactMe),
|
||||
onTap: () {
|
||||
globalState.showMessage(
|
||||
title: appLocalizations.contactMe,
|
||||
message: TextSpan(text: "chen08209@gmail.com"),
|
||||
);
|
||||
},
|
||||
),
|
||||
ListItem(
|
||||
title: const Text("Telegram"),
|
||||
onTap: () {
|
||||
|
||||
@@ -2,7 +2,6 @@ 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/providers.dart';
|
||||
import 'package:fl_clash/state.dart';
|
||||
import 'package:fl_clash/widgets/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
@@ -151,56 +150,46 @@ class TestUrlItem extends ConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class PortItem extends ConsumerWidget {
|
||||
const PortItem({super.key});
|
||||
|
||||
handleShowPortDialog() async {
|
||||
await globalState.showCommonDialog(
|
||||
child: _PortDialog(),
|
||||
);
|
||||
// inputDelegate.onChanged(value);
|
||||
}
|
||||
class MixedPortItem extends ConsumerWidget {
|
||||
const MixedPortItem({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
final mixedPort =
|
||||
ref.watch(patchClashConfigProvider.select((state) => state.mixedPort));
|
||||
return ListItem(
|
||||
return ListItem.input(
|
||||
leading: const Icon(Icons.adjust_outlined),
|
||||
title: Text(appLocalizations.port),
|
||||
title: Text(appLocalizations.proxyPort),
|
||||
subtitle: Text("$mixedPort"),
|
||||
onTap: () {
|
||||
handleShowPortDialog();
|
||||
},
|
||||
// delegate: InputDelegate(
|
||||
// title: appLocalizations.port,
|
||||
// value: "$mixedPort",
|
||||
// validator: (String? value) {
|
||||
// if (value == null || value.isEmpty) {
|
||||
// return appLocalizations.emptyTip(appLocalizations.proxyPort);
|
||||
// }
|
||||
// final mixedPort = int.tryParse(value);
|
||||
// if (mixedPort == null) {
|
||||
// return appLocalizations.numberTip(appLocalizations.proxyPort);
|
||||
// }
|
||||
// if (mixedPort < 1024 || mixedPort > 49151) {
|
||||
// return appLocalizations.proxyPortTip;
|
||||
// }
|
||||
// return null;
|
||||
// },
|
||||
// onChanged: (String? value) {
|
||||
// if (value == null) {
|
||||
// return;
|
||||
// }
|
||||
// final mixedPort = int.parse(value);
|
||||
// ref.read(patchClashConfigProvider.notifier).updateState(
|
||||
// (state) => state.copyWith(
|
||||
// mixedPort: mixedPort,
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// resetValue: "$defaultMixedPort",
|
||||
// ),
|
||||
delegate: InputDelegate(
|
||||
title: appLocalizations.proxyPort,
|
||||
value: "$mixedPort",
|
||||
validator: (String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return appLocalizations.emptyTip(appLocalizations.proxyPort);
|
||||
}
|
||||
final mixedPort = int.tryParse(value);
|
||||
if (mixedPort == null) {
|
||||
return appLocalizations.numberTip(appLocalizations.proxyPort);
|
||||
}
|
||||
if (mixedPort < 1024 || mixedPort > 49151) {
|
||||
return appLocalizations.proxyPortTip;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onChanged: (String? value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
final mixedPort = int.parse(value);
|
||||
ref.read(patchClashConfigProvider.notifier).updateState(
|
||||
(state) => state.copyWith(
|
||||
mixedPort: mixedPort,
|
||||
),
|
||||
);
|
||||
},
|
||||
resetValue: "$defaultMixedPort",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -428,7 +417,7 @@ final generalItems = <Widget>[
|
||||
UaItem(),
|
||||
if (system.isDesktop) KeepAliveIntervalItem(),
|
||||
TestUrlItem(),
|
||||
PortItem(),
|
||||
MixedPortItem(),
|
||||
HostsItem(),
|
||||
Ipv6Item(),
|
||||
AllowLanItem(),
|
||||
@@ -444,350 +433,3 @@ final generalItems = <Widget>[
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
class _PortDialog extends ConsumerStatefulWidget {
|
||||
const _PortDialog();
|
||||
|
||||
@override
|
||||
ConsumerState<_PortDialog> createState() => _PortDialogState();
|
||||
}
|
||||
|
||||
class _PortDialogState extends ConsumerState<_PortDialog> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
bool _isMore = false;
|
||||
|
||||
late TextEditingController _mixedPortController;
|
||||
late TextEditingController _portController;
|
||||
late TextEditingController _socksPortController;
|
||||
late TextEditingController _redirPortController;
|
||||
late TextEditingController _tProxyPortController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final vm5 = ref.read(patchClashConfigProvider.select((state) {
|
||||
return VM5(
|
||||
a: state.mixedPort,
|
||||
b: state.port,
|
||||
c: state.socksPort,
|
||||
d: state.redirPort,
|
||||
e: state.tproxyPort,
|
||||
);
|
||||
}));
|
||||
_mixedPortController = TextEditingController(
|
||||
text: vm5.a.toString(),
|
||||
);
|
||||
_portController = TextEditingController(
|
||||
text: vm5.b.toString(),
|
||||
);
|
||||
_socksPortController = TextEditingController(
|
||||
text: vm5.c.toString(),
|
||||
);
|
||||
_redirPortController = TextEditingController(
|
||||
text: vm5.d.toString(),
|
||||
);
|
||||
_tProxyPortController = TextEditingController(
|
||||
text: vm5.e.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
_handleReset() async {
|
||||
final res = await globalState.showMessage(
|
||||
message: TextSpan(
|
||||
text: appLocalizations.resetTip,
|
||||
),
|
||||
);
|
||||
if (res != true) {
|
||||
return;
|
||||
}
|
||||
ref.read(patchClashConfigProvider.notifier).updateState(
|
||||
(state) => state.copyWith(
|
||||
mixedPort: 7890,
|
||||
port: 0,
|
||||
socksPort: 0,
|
||||
redirPort: 0,
|
||||
tproxyPort: 0,
|
||||
),
|
||||
);
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
|
||||
_handleUpdate() {
|
||||
if (_formKey.currentState?.validate() == false) return;
|
||||
ref.read(patchClashConfigProvider.notifier).updateState(
|
||||
(state) => state.copyWith(
|
||||
mixedPort: int.parse(_mixedPortController.text),
|
||||
port: int.parse(_portController.text),
|
||||
socksPort: int.parse(_socksPortController.text),
|
||||
redirPort: int.parse(_redirPortController.text),
|
||||
tproxyPort: int.parse(_tProxyPortController.text),
|
||||
),
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
_handleMore() {
|
||||
setState(() {
|
||||
_isMore = !_isMore;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CommonDialog(
|
||||
title: appLocalizations.port,
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
IconButton.filledTonal(
|
||||
onPressed: _handleMore,
|
||||
icon: CommonExpandIcon(
|
||||
expand: _isMore,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: _handleReset,
|
||||
child: Text(appLocalizations.reset),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 4,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: _handleUpdate,
|
||||
child: Text(appLocalizations.submit),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
child: Form(
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
key: _formKey,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 8),
|
||||
child: AnimatedSize(
|
||||
duration: midDuration,
|
||||
curve: Curves.easeOutQuad,
|
||||
alignment: Alignment.topCenter,
|
||||
child: Column(
|
||||
spacing: 24,
|
||||
children: [
|
||||
TextFormField(
|
||||
keyboardType: TextInputType.url,
|
||||
maxLines: 1,
|
||||
minLines: 1,
|
||||
controller: _mixedPortController,
|
||||
onFieldSubmitted: (_) {
|
||||
_handleUpdate();
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: appLocalizations.mixedPort,
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return appLocalizations
|
||||
.emptyTip(appLocalizations.mixedPort);
|
||||
}
|
||||
final port = int.tryParse(value);
|
||||
if (port == null) {
|
||||
return appLocalizations
|
||||
.numberTip(appLocalizations.mixedPort);
|
||||
}
|
||||
if (port < 1024 || port > 49151) {
|
||||
return appLocalizations
|
||||
.portTip(appLocalizations.mixedPort);
|
||||
}
|
||||
final ports = [
|
||||
_portController.text,
|
||||
_socksPortController.text,
|
||||
_tProxyPortController.text,
|
||||
_redirPortController.text
|
||||
].map((item) => item.trim());
|
||||
if (ports.contains(value.trim())) {
|
||||
return appLocalizations.portConflictTip;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
if (_isMore) ...[
|
||||
TextFormField(
|
||||
keyboardType: TextInputType.url,
|
||||
maxLines: 1,
|
||||
minLines: 1,
|
||||
controller: _portController,
|
||||
onFieldSubmitted: (_) {
|
||||
_handleUpdate();
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: appLocalizations.port,
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return appLocalizations.emptyTip(appLocalizations.port);
|
||||
}
|
||||
final port = int.tryParse(value);
|
||||
if (port == null) {
|
||||
return appLocalizations.numberTip(
|
||||
appLocalizations.port,
|
||||
);
|
||||
}
|
||||
if (port == 0) {
|
||||
return null;
|
||||
}
|
||||
if (port < 1024 || port > 49151) {
|
||||
return appLocalizations.portTip(appLocalizations.port);
|
||||
}
|
||||
final ports = [
|
||||
_mixedPortController.text,
|
||||
_socksPortController.text,
|
||||
_tProxyPortController.text,
|
||||
_redirPortController.text
|
||||
].map((item) => item.trim());
|
||||
if (ports.contains(value.trim())) {
|
||||
return appLocalizations.portConflictTip;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
TextFormField(
|
||||
keyboardType: TextInputType.url,
|
||||
maxLines: 1,
|
||||
minLines: 1,
|
||||
controller: _socksPortController,
|
||||
onFieldSubmitted: (_) {
|
||||
_handleUpdate();
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: appLocalizations.socksPort,
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return appLocalizations
|
||||
.emptyTip(appLocalizations.socksPort);
|
||||
}
|
||||
final port = int.tryParse(value);
|
||||
if (port == null) {
|
||||
return appLocalizations
|
||||
.numberTip(appLocalizations.socksPort);
|
||||
}
|
||||
if (port == 0) {
|
||||
return null;
|
||||
}
|
||||
if (port < 1024 || port > 49151) {
|
||||
return appLocalizations
|
||||
.portTip(appLocalizations.socksPort);
|
||||
}
|
||||
final ports = [
|
||||
_portController.text,
|
||||
_mixedPortController.text,
|
||||
_tProxyPortController.text,
|
||||
_redirPortController.text
|
||||
].map((item) => item.trim());
|
||||
if (ports.contains(value.trim())) {
|
||||
return appLocalizations.portConflictTip;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
TextFormField(
|
||||
keyboardType: TextInputType.url,
|
||||
maxLines: 1,
|
||||
minLines: 1,
|
||||
controller: _redirPortController,
|
||||
onFieldSubmitted: (_) {
|
||||
_handleUpdate();
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: appLocalizations.redirPort,
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return appLocalizations
|
||||
.emptyTip(appLocalizations.redirPort);
|
||||
}
|
||||
final port = int.tryParse(value);
|
||||
if (port == null) {
|
||||
return appLocalizations
|
||||
.numberTip(appLocalizations.redirPort);
|
||||
}
|
||||
if (port == 0) {
|
||||
return null;
|
||||
}
|
||||
if (port < 1024 || port > 49151) {
|
||||
return appLocalizations
|
||||
.portTip(appLocalizations.redirPort);
|
||||
}
|
||||
final ports = [
|
||||
_portController.text,
|
||||
_socksPortController.text,
|
||||
_tProxyPortController.text,
|
||||
_mixedPortController.text
|
||||
].map((item) => item.trim());
|
||||
if (ports.contains(value.trim())) {
|
||||
return appLocalizations.portConflictTip;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
TextFormField(
|
||||
keyboardType: TextInputType.url,
|
||||
maxLines: 1,
|
||||
minLines: 1,
|
||||
controller: _tProxyPortController,
|
||||
onFieldSubmitted: (_) {
|
||||
_handleUpdate();
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: appLocalizations.tproxyPort,
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return appLocalizations
|
||||
.emptyTip(appLocalizations.tproxyPort);
|
||||
}
|
||||
final port = int.tryParse(value);
|
||||
if (port == null) {
|
||||
return appLocalizations
|
||||
.numberTip(appLocalizations.tproxyPort);
|
||||
}
|
||||
if (port == 0) {
|
||||
return null;
|
||||
}
|
||||
if (port < 1024 || port > 49151) {
|
||||
return appLocalizations.portTip(
|
||||
appLocalizations.tproxyPort,
|
||||
);
|
||||
}
|
||||
final ports = [
|
||||
_portController.text,
|
||||
_socksPortController.text,
|
||||
_mixedPortController.text,
|
||||
_redirPortController.text
|
||||
].map((item) => item.trim());
|
||||
if (ports.contains(value.trim())) {
|
||||
return appLocalizations.portConflictTip;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
),
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,29 +155,6 @@ class Ipv6Item extends ConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class AutoSetSystemDnsItem extends ConsumerWidget {
|
||||
const AutoSetSystemDnsItem({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
final autoSetSystemDns = ref.watch(
|
||||
networkSettingProvider.select((state) => state.autoSetSystemDns));
|
||||
return ListItem.switchItem(
|
||||
title: Text(appLocalizations.autoSetSystemDns),
|
||||
delegate: SwitchDelegate(
|
||||
value: autoSetSystemDns,
|
||||
onChanged: (bool value) async {
|
||||
ref.read(networkSettingProvider.notifier).updateState(
|
||||
(state) => state.copyWith(
|
||||
autoSetSystemDns: value,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TunStackItem extends ConsumerWidget {
|
||||
const TunStackItem({super.key});
|
||||
|
||||
@@ -372,12 +349,9 @@ final networkItems = [
|
||||
title: appLocalizations.options,
|
||||
items: [
|
||||
if (system.isDesktop) const TUNItem(),
|
||||
if (Platform.isMacOS) const AutoSetSystemDnsItem(),
|
||||
const TunStackItem(),
|
||||
if (!system.isDesktop) ...[
|
||||
const RouteModeItem(),
|
||||
const RouteAddressItem(),
|
||||
]
|
||||
const RouteModeItem(),
|
||||
const RouteAddressItem(),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:defer_pointer/defer_pointer.dart';
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/providers/providers.dart';
|
||||
@@ -10,8 +9,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'widgets/start_button.dart';
|
||||
|
||||
typedef _IsEditWidgetBuilder = Widget Function(bool isEdit);
|
||||
|
||||
class DashboardView extends ConsumerStatefulWidget {
|
||||
const DashboardView({super.key});
|
||||
|
||||
@@ -21,8 +18,6 @@ class DashboardView extends ConsumerStatefulWidget {
|
||||
|
||||
class _DashboardViewState extends ConsumerState<DashboardView> with PageMixin {
|
||||
final key = GlobalKey<SuperGridState>();
|
||||
final _isEditNotifier = ValueNotifier<bool>(false);
|
||||
final _addedWidgetsNotifier = ValueNotifier<List<GridItem>>([]);
|
||||
|
||||
@override
|
||||
initState() {
|
||||
@@ -38,282 +33,115 @@ class _DashboardViewState extends ConsumerState<DashboardView> with PageMixin {
|
||||
return super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
dispose() {
|
||||
_isEditNotifier.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget? get floatingActionButton => const StartButton();
|
||||
|
||||
Widget _buildIsEdit(_IsEditWidgetBuilder builder) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: _isEditNotifier,
|
||||
builder: (_, isEdit, ___) {
|
||||
return builder(isEdit);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Widget> get actions => [
|
||||
_buildIsEdit((isEdit) {
|
||||
return isEdit
|
||||
? ValueListenableBuilder(
|
||||
valueListenable: _addedWidgetsNotifier,
|
||||
builder: (_, addedChildren, child) {
|
||||
if (addedChildren.isEmpty) {
|
||||
return Container();
|
||||
}
|
||||
return child!;
|
||||
},
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
_showAddWidgetsModal();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.add_circle,
|
||||
),
|
||||
),
|
||||
)
|
||||
: SizedBox();
|
||||
}),
|
||||
ValueListenableBuilder(
|
||||
valueListenable: key.currentState!.addedChildrenNotifier,
|
||||
builder: (_, addedChildren, child) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: key.currentState!.isEditNotifier,
|
||||
builder: (_, isEdit, child) {
|
||||
if (!isEdit || addedChildren.isEmpty) {
|
||||
return Container();
|
||||
}
|
||||
return child!;
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
key.currentState!.showAddModal();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.add_circle,
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: _buildIsEdit((isEdit) {
|
||||
return isEdit
|
||||
? Icon(Icons.save)
|
||||
: Icon(
|
||||
Icons.edit,
|
||||
);
|
||||
}),
|
||||
onPressed: _handleUpdateIsEdit,
|
||||
icon: ValueListenableBuilder(
|
||||
valueListenable: key.currentState!.isEditNotifier,
|
||||
builder: (_, isEdit, ___) {
|
||||
return isEdit
|
||||
? SystemBackBlock(
|
||||
child: CommonPopScope(
|
||||
child: Icon(Icons.save),
|
||||
onPop: () {
|
||||
key.currentState!.isEditNotifier.value =
|
||||
!key.currentState!.isEditNotifier.value;
|
||||
return false;
|
||||
},
|
||||
),
|
||||
)
|
||||
: Icon(
|
||||
Icons.edit,
|
||||
);
|
||||
},
|
||||
),
|
||||
onPressed: () {
|
||||
key.currentState!.isEditNotifier.value =
|
||||
!key.currentState!.isEditNotifier.value;
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
_showAddWidgetsModal() {
|
||||
showSheet(
|
||||
builder: (_, type) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: _addedWidgetsNotifier,
|
||||
builder: (_, value, __) {
|
||||
return AdaptiveSheetScaffold(
|
||||
type: type,
|
||||
body: _AddDashboardWidgetModal(
|
||||
items: value,
|
||||
onAdd: (gridItem) {
|
||||
key.currentState?.handleAdd(gridItem);
|
||||
},
|
||||
),
|
||||
title: appLocalizations.add,
|
||||
);
|
||||
},
|
||||
_handleSave(List<GridItem> girdItems, WidgetRef ref) {
|
||||
final dashboardWidgets = girdItems
|
||||
.map(
|
||||
(item) => DashboardWidget.getDashboardWidget(item),
|
||||
)
|
||||
.toList();
|
||||
ref.read(appSettingProvider.notifier).updateState(
|
||||
(state) => state.copyWith(dashboardWidgets: dashboardWidgets),
|
||||
);
|
||||
},
|
||||
context: context,
|
||||
);
|
||||
}
|
||||
|
||||
_handleUpdateIsEdit() {
|
||||
if (_isEditNotifier.value == true) {
|
||||
_handleSave();
|
||||
}
|
||||
_isEditNotifier.value = !_isEditNotifier.value;
|
||||
}
|
||||
|
||||
_handleSave() {
|
||||
final children = key.currentState?.children;
|
||||
if (children == null) {
|
||||
return;
|
||||
}
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final dashboardWidgets = children
|
||||
.map(
|
||||
(item) => DashboardWidget.getDashboardWidget(item),
|
||||
)
|
||||
.toList();
|
||||
ref.read(appSettingProvider.notifier).updateState(
|
||||
(state) => state.copyWith(dashboardWidgets: dashboardWidgets),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final dashboardState = ref.watch(dashboardStateProvider);
|
||||
final columns = max(4 * ((dashboardState.viewWidth / 320).ceil()), 8);
|
||||
final spacing = 16.ap;
|
||||
final children = [
|
||||
...dashboardState.dashboardWidgets
|
||||
.where(
|
||||
(item) => item.platforms.contains(
|
||||
SupportPlatform.currentPlatform,
|
||||
),
|
||||
)
|
||||
.map(
|
||||
(item) => item.widget,
|
||||
),
|
||||
];
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_addedWidgetsNotifier.value = DashboardWidget.values
|
||||
.where(
|
||||
(item) =>
|
||||
!children.contains(item.widget) &&
|
||||
item.platforms.contains(
|
||||
SupportPlatform.currentPlatform,
|
||||
),
|
||||
)
|
||||
.map((item) => item.widget)
|
||||
.toList();
|
||||
});
|
||||
return Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16).copyWith(
|
||||
bottom: 88,
|
||||
),
|
||||
child: _buildIsEdit((isEdit) {
|
||||
return isEdit
|
||||
? SystemBackBlock(
|
||||
child: CommonPopScope(
|
||||
child: SuperGrid(
|
||||
key: key,
|
||||
crossAxisCount: columns,
|
||||
crossAxisSpacing: spacing,
|
||||
mainAxisSpacing: spacing,
|
||||
children: [
|
||||
...dashboardState.dashboardWidgets
|
||||
.where(
|
||||
(item) => item.platforms.contains(
|
||||
SupportPlatform.currentPlatform,
|
||||
),
|
||||
)
|
||||
.map(
|
||||
(item) => item.widget,
|
||||
),
|
||||
],
|
||||
onUpdate: () {
|
||||
_handleSave();
|
||||
},
|
||||
),
|
||||
onPop: () {
|
||||
_handleUpdateIsEdit();
|
||||
return false;
|
||||
},
|
||||
),
|
||||
)
|
||||
: Grid(
|
||||
crossAxisCount: columns,
|
||||
crossAxisSpacing: spacing,
|
||||
mainAxisSpacing: spacing,
|
||||
children: children,
|
||||
);
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AddDashboardWidgetModal extends StatelessWidget {
|
||||
final List<GridItem> items;
|
||||
final Function(GridItem item) onAdd;
|
||||
|
||||
const _AddDashboardWidgetModal({
|
||||
required this.items,
|
||||
required this.onAdd,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DeferredPointerHandler(
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.all(
|
||||
16,
|
||||
padding: const EdgeInsets.all(16).copyWith(
|
||||
bottom: 88,
|
||||
),
|
||||
child: Grid(
|
||||
crossAxisCount: 8,
|
||||
crossAxisSpacing: 16,
|
||||
mainAxisSpacing: 16,
|
||||
children: items
|
||||
.map(
|
||||
(item) => item.wrap(
|
||||
builder: (child) {
|
||||
return _AddedContainer(
|
||||
onAdd: () {
|
||||
onAdd(item);
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: SuperGrid(
|
||||
key: key,
|
||||
crossAxisCount: columns,
|
||||
crossAxisSpacing: 16.ap,
|
||||
mainAxisSpacing: 16.ap,
|
||||
children: [
|
||||
...dashboardState.dashboardWidgets
|
||||
.where(
|
||||
(item) => item.platforms.contains(
|
||||
SupportPlatform.currentPlatform,
|
||||
),
|
||||
)
|
||||
.map(
|
||||
(item) => item.widget,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
],
|
||||
onSave: (girdItems) {
|
||||
_handleSave(girdItems, ref);
|
||||
},
|
||||
addedItemsBuilder: (girdItems) {
|
||||
return DashboardWidget.values
|
||||
.where(
|
||||
(item) =>
|
||||
!girdItems.contains(item.widget) &&
|
||||
item.platforms.contains(
|
||||
SupportPlatform.currentPlatform,
|
||||
),
|
||||
)
|
||||
.map((item) => item.widget)
|
||||
.toList();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AddedContainer extends StatefulWidget {
|
||||
final Widget child;
|
||||
final VoidCallback onAdd;
|
||||
|
||||
const _AddedContainer({
|
||||
required this.child,
|
||||
required this.onAdd,
|
||||
});
|
||||
|
||||
@override
|
||||
State<_AddedContainer> createState() => _AddedContainerState();
|
||||
}
|
||||
|
||||
class _AddedContainerState extends State<_AddedContainer> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(_AddedContainer oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.child != widget.child) {}
|
||||
}
|
||||
|
||||
_handleAdd() async {
|
||||
widget.onAdd();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
ActivateBox(
|
||||
child: widget.child,
|
||||
),
|
||||
Positioned(
|
||||
top: -8,
|
||||
right: -8,
|
||||
child: DeferPointer(
|
||||
child: SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: IconButton.filled(
|
||||
iconSize: 20,
|
||||
padding: EdgeInsets.all(2),
|
||||
onPressed: _handleAdd,
|
||||
icon: Icon(
|
||||
Icons.add,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/providers/config.dart';
|
||||
import 'package:fl_clash/views/config/network.dart';
|
||||
@@ -25,7 +23,6 @@ class TUNButton extends StatelessWidget {
|
||||
generateSection(
|
||||
items: [
|
||||
if (system.isDesktop) const TUNItem(),
|
||||
if (Platform.isMacOS) const AutoSetSystemDnsItem(),
|
||||
const TunStackItem(),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -135,12 +135,10 @@ class TrafficUsage extends StatelessWidget {
|
||||
Container(
|
||||
width: 20,
|
||||
height: 8,
|
||||
decoration: ShapeDecoration(
|
||||
decoration: BoxDecoration(
|
||||
color: primaryColor,
|
||||
shape: RoundedSuperellipseBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(3),
|
||||
),
|
||||
borderRadius:
|
||||
BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
@@ -163,12 +161,10 @@ class TrafficUsage extends StatelessWidget {
|
||||
Container(
|
||||
width: 20,
|
||||
height: 8,
|
||||
decoration: ShapeDecoration(
|
||||
decoration: BoxDecoration(
|
||||
color: secondaryColor,
|
||||
shape: RoundedSuperellipseBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(3),
|
||||
),
|
||||
borderRadius:
|
||||
BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:fl_clash/clash/clash.dart';
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/models/models.dart';
|
||||
@@ -26,7 +27,7 @@ class _OverrideProfileViewState extends State<OverrideProfileView> {
|
||||
_initState(WidgetRef ref) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
Future.delayed(Duration(milliseconds: 300), () async {
|
||||
final rawConfig = await globalState.getProfileConfig(widget.profileId);
|
||||
final rawConfig = await clashCore.getConfig(widget.profileId);
|
||||
final snippet = ClashConfigSnippet.fromJson(rawConfig);
|
||||
final overrideData = ref.read(
|
||||
getProfileOverrideDataProvider(widget.profileId),
|
||||
@@ -597,7 +598,7 @@ class RuleContent extends ConsumerWidget {
|
||||
tag: CacheTag.rules,
|
||||
itemBuilder: (context, index) {
|
||||
final rule = rules[index];
|
||||
return ReorderableDelayedDragStartListener(
|
||||
return ReorderableDragStartListener(
|
||||
key: ObjectKey(rule),
|
||||
index: index,
|
||||
child: _buildItem(
|
||||
|
||||
@@ -136,9 +136,12 @@ class _ScriptsViewState extends ConsumerState<ScriptsView> {
|
||||
return appLocalizations.emptyTip(appLocalizations.name);
|
||||
}
|
||||
if (value != script?.label) {
|
||||
final isExits =
|
||||
ref.read(scriptStateProvider.notifier).isExits(value);
|
||||
if (isExits) {
|
||||
final index = ref
|
||||
.read(scriptStateProvider.select((state) => state.scripts))
|
||||
.indexWhere(
|
||||
(item) => item.label == value,
|
||||
);
|
||||
if (index != -1) {
|
||||
return appLocalizations.existsTip(
|
||||
appLocalizations.name,
|
||||
);
|
||||
@@ -153,18 +156,6 @@ class _ScriptsViewState extends ConsumerState<ScriptsView> {
|
||||
}
|
||||
newScript = newScript.copyWith(label: res);
|
||||
}
|
||||
if (newScript.label != script?.label) {
|
||||
final isExits =
|
||||
ref.read(scriptStateProvider.notifier).isExits(newScript.label);
|
||||
if (isExits) {
|
||||
globalState.showMessage(
|
||||
message: TextSpan(
|
||||
text: appLocalizations.existsTip(appLocalizations.name),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ref.read(scriptStateProvider.notifier).setScript(newScript);
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
@@ -207,7 +198,6 @@ class _ScriptsViewState extends ConsumerState<ScriptsView> {
|
||||
EditorPage(
|
||||
titleEditable: true,
|
||||
title: title,
|
||||
supportRemoteDownload: true,
|
||||
onSave: (context, title, content) {
|
||||
_handleEditorSave(
|
||||
context,
|
||||
|
||||
@@ -357,7 +357,10 @@ class ListHeader extends StatefulWidget {
|
||||
State<ListHeader> createState() => _ListHeaderState();
|
||||
}
|
||||
|
||||
class _ListHeaderState extends State<ListHeader> {
|
||||
class _ListHeaderState extends State<ListHeader>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _animationController;
|
||||
late Animation<double> _iconTurns;
|
||||
var isLock = false;
|
||||
|
||||
String get icon => widget.group.icon;
|
||||
@@ -382,6 +385,39 @@ class _ListHeaderState extends State<ListHeader> {
|
||||
widget.onChange(groupName);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_animationController = AnimationController(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
vsync: this,
|
||||
);
|
||||
_iconTurns = _animationController.drive(
|
||||
Tween<double>(begin: 0.0, end: 0.5),
|
||||
);
|
||||
if (isExpand) {
|
||||
_animationController.value = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(ListHeader oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.isExpand != widget.isExpand) {
|
||||
if (isExpand) {
|
||||
_animationController.forward();
|
||||
} else {
|
||||
_animationController.reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildIcon() {
|
||||
return Consumer(
|
||||
builder: (_, ref, child) {
|
||||
@@ -418,11 +454,9 @@ class _ListHeaderState extends State<ListHeader> {
|
||||
width: constraints.maxWidth,
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.all(6.ap),
|
||||
decoration: ShapeDecoration(
|
||||
shape: RoundedSuperellipseBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: context.colorScheme.secondaryContainer,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: CommonTargetIcon(
|
||||
@@ -565,13 +599,21 @@ class _ListHeaderState extends State<ListHeader> {
|
||||
SizedBox(
|
||||
width: 4,
|
||||
),
|
||||
IconButton.filledTonal(
|
||||
onPressed: () {
|
||||
_handleChange(groupName);
|
||||
AnimatedBuilder(
|
||||
animation: _animationController.view,
|
||||
builder: (_, __) {
|
||||
return IconButton.filledTonal(
|
||||
onPressed: () {
|
||||
_handleChange(groupName);
|
||||
},
|
||||
icon: RotationTransition(
|
||||
turns: _iconTurns,
|
||||
child: const Icon(
|
||||
Icons.expand_more,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: CommonExpandIcon(
|
||||
expand: isExpand,
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
@@ -185,7 +185,7 @@ class CommonCard extends StatelessWidget {
|
||||
style: ButtonStyle(
|
||||
padding: const WidgetStatePropertyAll(EdgeInsets.zero),
|
||||
shape: WidgetStatePropertyAll(
|
||||
RoundedSuperellipseBorder(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(radius),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:fl_clash/providers/providers.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'card.dart';
|
||||
import 'grid.dart';
|
||||
|
||||
|
||||
@@ -60,68 +60,6 @@ class _EffectGestureDetectorState extends State<EffectGestureDetector>
|
||||
}
|
||||
}
|
||||
|
||||
class CommonExpandIcon extends StatefulWidget {
|
||||
final bool expand;
|
||||
|
||||
const CommonExpandIcon({
|
||||
super.key,
|
||||
this.expand = false,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CommonExpandIcon> createState() => _CommonExpandIconState();
|
||||
}
|
||||
|
||||
class _CommonExpandIconState extends State<CommonExpandIcon>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _animationController;
|
||||
late Animation<double> _iconTurns;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_animationController = AnimationController(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
vsync: this,
|
||||
);
|
||||
_iconTurns = _animationController.drive(
|
||||
Tween<double>(begin: 0.0, end: 0.5),
|
||||
);
|
||||
if (widget.expand) {
|
||||
_animationController.value = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant CommonExpandIcon oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.expand != widget.expand) {
|
||||
if (widget.expand) {
|
||||
_animationController.forward();
|
||||
} else {
|
||||
_animationController.reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
animation: _animationController.view,
|
||||
builder: (_, child) {
|
||||
return RotationTransition(
|
||||
turns: _iconTurns,
|
||||
child: child!,
|
||||
);
|
||||
},
|
||||
child: const Icon(
|
||||
Icons.expand_more,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget proxyDecorator(
|
||||
Widget child,
|
||||
int index,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:fl_clash/common/common.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
class CommonTargetIcon extends StatelessWidget {
|
||||
final String src;
|
||||
@@ -34,23 +33,11 @@ class CommonTargetIcon extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
}
|
||||
return FutureBuilder(
|
||||
future: DefaultCacheManager().getSingleFile(src),
|
||||
builder: (_, snapshot) {
|
||||
final data = snapshot.data;
|
||||
if (data == null) {
|
||||
return SizedBox();
|
||||
}
|
||||
return src.isSvg
|
||||
? SvgPicture.file(
|
||||
data,
|
||||
errorBuilder: (_, __, ___) => _defaultIcon(),
|
||||
)
|
||||
: Image.file(
|
||||
data,
|
||||
errorBuilder: (_, __, ___) => _defaultIcon(),
|
||||
);
|
||||
},
|
||||
return CachedNetworkImage(
|
||||
imageUrl: src,
|
||||
fadeInDuration: Duration.zero,
|
||||
fadeOutDuration: Duration.zero,
|
||||
errorWidget: (_, __, ___) => _defaultIcon(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -288,7 +288,7 @@ class ListInputPage extends StatelessWidget {
|
||||
final e = items[index];
|
||||
return _InputItem(
|
||||
key: ValueKey(e),
|
||||
ReorderableDelayedDragStartListener(
|
||||
ReorderableDragStartListener(
|
||||
index: index,
|
||||
child: CommonCard(
|
||||
child: ListItem(
|
||||
@@ -440,7 +440,7 @@ class MapInputPage extends StatelessWidget {
|
||||
final e = items[index];
|
||||
return _InputItem(
|
||||
key: ValueKey(e.key),
|
||||
ReorderableDelayedDragStartListener(
|
||||
ReorderableDragStartListener(
|
||||
index: index,
|
||||
child: CommonCard(
|
||||
child: ListItem(
|
||||
@@ -613,7 +613,7 @@ class _InputItem extends StatelessWidget {
|
||||
color: Colors.transparent,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
margin: EdgeInsets.symmetric(vertical: 8),
|
||||
margin: EdgeInsets.symmetric(vertical: 4),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -422,7 +422,6 @@ class ListItem<T> extends StatelessWidget {
|
||||
value: radioDelegate.value,
|
||||
groupValue: radioDelegate.groupValue,
|
||||
onChanged: radioDelegate.onChanged,
|
||||
toggleable: true,
|
||||
),
|
||||
trailing: trailing,
|
||||
);
|
||||
|
||||
@@ -279,7 +279,7 @@ class CommonPopupMenu extends StatelessWidget {
|
||||
elevation: 12,
|
||||
color: context.colorScheme.surfaceContainer,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
shape: RoundedSuperellipseBorder(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
|
||||
@@ -148,11 +148,9 @@ class _AdaptiveSheetScaffoldState extends State<AdaptiveSheetScaffold> {
|
||||
final handleSize = Size(32, 4);
|
||||
return Container(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: ShapeDecoration(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(28.0)),
|
||||
color: backgroundColor,
|
||||
shape: RoundedSuperellipseBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(28.0)),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -163,10 +161,8 @@ class _AdaptiveSheetScaffoldState extends State<AdaptiveSheetScaffold> {
|
||||
alignment: Alignment.center,
|
||||
height: handleSize.height,
|
||||
width: handleSize.width,
|
||||
decoration: ShapeDecoration(
|
||||
shape: RoundedSuperellipseBorder(
|
||||
borderRadius: BorderRadius.circular(handleSize.height / 2),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(handleSize.height / 2),
|
||||
color: context.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -83,7 +83,7 @@ class _SideSheetState extends State<SideSheet> {
|
||||
final Color shadowColor = widget.shadowColor ?? Colors.transparent;
|
||||
final double elevation = widget.elevation ?? 0;
|
||||
final ShapeBorder shape = widget.shape ??
|
||||
RoundedSuperellipseBorder(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:fl_clash/enum/enum.dart';
|
||||
import 'package:fl_clash/widgets/activate_box.dart';
|
||||
import 'package:fl_clash/widgets/card.dart';
|
||||
import 'package:fl_clash/widgets/grid.dart';
|
||||
import 'package:fl_clash/widgets/sheet.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/physics.dart';
|
||||
|
||||
@@ -17,7 +18,8 @@ class SuperGrid extends StatefulWidget {
|
||||
final double mainAxisSpacing;
|
||||
final double crossAxisSpacing;
|
||||
final int crossAxisCount;
|
||||
final VoidCallback? onUpdate;
|
||||
final void Function(List<GridItem> newChildren)? onSave;
|
||||
final List<GridItem> Function(List<GridItem> newChildren)? addedItemsBuilder;
|
||||
|
||||
const SuperGrid({
|
||||
super.key,
|
||||
@@ -25,7 +27,8 @@ class SuperGrid extends StatefulWidget {
|
||||
this.crossAxisCount = 1,
|
||||
this.mainAxisSpacing = 0,
|
||||
this.crossAxisSpacing = 0,
|
||||
this.onUpdate,
|
||||
this.onSave,
|
||||
this.addedItemsBuilder,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -34,7 +37,7 @@ class SuperGrid extends StatefulWidget {
|
||||
|
||||
class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
final ValueNotifier<List<GridItem>> _childrenNotifier = ValueNotifier([]);
|
||||
List<GridItem> children = [];
|
||||
final ValueNotifier<List<GridItem>> addedChildrenNotifier = ValueNotifier([]);
|
||||
|
||||
int get length => _childrenNotifier.value.length;
|
||||
List<int> _tempIndexList = [];
|
||||
@@ -46,6 +49,8 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
List<Offset> _offsets = [];
|
||||
Offset _parentOffset = Offset.zero;
|
||||
EdgeDraggingAutoScroller? _edgeDraggingAutoScroller;
|
||||
final ValueNotifier<bool> isEditNotifier = ValueNotifier(false);
|
||||
|
||||
Map<int, Tween<Offset>> _transformTweenMap = {};
|
||||
|
||||
final ValueNotifier<bool> _animating = ValueNotifier(false);
|
||||
@@ -90,6 +95,35 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
_containerSize = context.size!;
|
||||
}
|
||||
|
||||
showAddModal() {
|
||||
if (!isEditNotifier.value) {
|
||||
return;
|
||||
}
|
||||
showSheet(
|
||||
builder: (_, type) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: addedChildrenNotifier,
|
||||
builder: (_, value, __) {
|
||||
return AdaptiveSheetScaffold(
|
||||
type: type,
|
||||
body: _AddedWidgetsModal(
|
||||
items: value,
|
||||
onAdd: (gridItem) {
|
||||
_childrenNotifier.value = List.from(_childrenNotifier.value)
|
||||
..add(
|
||||
gridItem,
|
||||
);
|
||||
},
|
||||
),
|
||||
title: appLocalizations.add,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
context: context,
|
||||
);
|
||||
}
|
||||
|
||||
_initState() {
|
||||
_transformController.value = 0;
|
||||
_sizes = List.generate(length, (index) => Size.zero);
|
||||
@@ -105,18 +139,22 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
_targetIndex = -1;
|
||||
}
|
||||
|
||||
_handleChildrenNotifierChange() {
|
||||
addedChildrenNotifier.value = widget.addedItemsBuilder != null
|
||||
? widget.addedItemsBuilder!(_childrenNotifier.value)
|
||||
: [];
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_childrenNotifier.addListener(() {
|
||||
children = _childrenNotifier.value;
|
||||
if (widget.onUpdate != null) {
|
||||
widget.onUpdate!();
|
||||
}
|
||||
});
|
||||
|
||||
_childrenNotifier.value = widget.children;
|
||||
|
||||
_childrenNotifier.addListener(_handleChildrenNotifierChange);
|
||||
|
||||
isEditNotifier.addListener(_handleIsEditChange);
|
||||
|
||||
_fakeDragWidgetController = AnimationController.unbounded(
|
||||
vsync: this,
|
||||
duration: commonDuration,
|
||||
@@ -126,7 +164,6 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
vsync: this,
|
||||
duration: Duration(milliseconds: 120),
|
||||
);
|
||||
|
||||
_shakeAnimation = Tween<double>(
|
||||
begin: -0.012,
|
||||
end: 0.012,
|
||||
@@ -145,11 +182,15 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
_initState();
|
||||
}
|
||||
|
||||
handleAdd(GridItem gridItem) {
|
||||
_childrenNotifier.value = List.from(_childrenNotifier.value)
|
||||
..add(
|
||||
gridItem,
|
||||
);
|
||||
_handleIsEditChange() async {
|
||||
_handleChildrenNotifierChange();
|
||||
if (isEditNotifier.value == false) {
|
||||
if (widget.onSave != null) {
|
||||
await _transformCompleter?.future;
|
||||
await Future.delayed(commonDuration);
|
||||
widget.onSave!(_childrenNotifier.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -264,9 +305,6 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
}
|
||||
|
||||
_handleDragEnd(DraggableDetails details) async {
|
||||
final children = List<GridItem>.from(_childrenNotifier.value);
|
||||
children.insert(_targetIndex, children.removeAt(_dragIndexNotifier.value));
|
||||
this.children = children;
|
||||
debouncer.cancel(FunctionTag.handleWill);
|
||||
if (_targetIndex == -1) {
|
||||
return;
|
||||
@@ -296,6 +334,8 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
_fakeDragWidgetAnimation = null;
|
||||
_transformTweenMap.clear();
|
||||
_transformAnimationMap.clear();
|
||||
final children = List<GridItem>.from(_childrenNotifier.value);
|
||||
children.insert(_targetIndex, children.removeAt(_dragIndexNotifier.value));
|
||||
_childrenNotifier.value = children;
|
||||
_initState();
|
||||
}
|
||||
@@ -345,15 +385,17 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
_initState();
|
||||
}
|
||||
|
||||
Widget _buildTransform(Widget rawChild, int index) {
|
||||
Widget _wrapTransform(Widget rawChild, int index) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: _animating,
|
||||
builder: (_, animating, child) {
|
||||
if (animating && _dragIndexNotifier.value == index) {
|
||||
return _buildSizeBox(
|
||||
Container(),
|
||||
index,
|
||||
);
|
||||
if (animating) {
|
||||
if (_dragIndexNotifier.value == index) {
|
||||
return _sizeBoxWrap(
|
||||
Container(),
|
||||
index,
|
||||
);
|
||||
}
|
||||
}
|
||||
return child!;
|
||||
},
|
||||
@@ -400,7 +442,7 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
return nextOffset;
|
||||
}
|
||||
|
||||
Widget _buildSizeBox(Widget child, int index) {
|
||||
Widget _sizeBoxWrap(Widget child, int index) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: _dragWidgetSizeNotifier,
|
||||
builder: (_, size, child) {
|
||||
@@ -413,7 +455,7 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInactivate(Widget child) {
|
||||
Widget _ignoreWrap(Widget child) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: _animating,
|
||||
builder: (_, animating, child) {
|
||||
@@ -429,7 +471,7 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildShake(Widget child) {
|
||||
Widget _shakeWrap(Widget child) {
|
||||
final random = 0.7 + Random().nextDouble() * 0.3;
|
||||
_shakeController.stop();
|
||||
_shakeController.repeat(reverse: true);
|
||||
@@ -445,7 +487,7 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDraggable({
|
||||
Widget _draggableWrap({
|
||||
required Widget childWhenDragging,
|
||||
required Widget feedback,
|
||||
required Widget item,
|
||||
@@ -481,7 +523,7 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
if (dragIndex == index) {
|
||||
return child!;
|
||||
}
|
||||
return _buildShake(
|
||||
return _shakeWrap(
|
||||
_DeletableContainer(
|
||||
onDelete: () {
|
||||
_handleDelete(index);
|
||||
@@ -524,7 +566,16 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
},
|
||||
child: shakeTarget,
|
||||
);
|
||||
return draggableChild;
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: isEditNotifier,
|
||||
builder: (_, isEdit, child) {
|
||||
if (!isEdit) {
|
||||
return item;
|
||||
}
|
||||
return child!;
|
||||
},
|
||||
child: draggableChild,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _builderItem(int index) {
|
||||
@@ -539,7 +590,7 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
final childWhenDragging = ActivateBox(
|
||||
child: Opacity(
|
||||
opacity: 0.6,
|
||||
child: _buildSizeBox(
|
||||
child: _sizeBoxWrap(
|
||||
CommonCard(
|
||||
child: child,
|
||||
),
|
||||
@@ -548,7 +599,7 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
),
|
||||
);
|
||||
final feedback = ActivateBox(
|
||||
child: _buildSizeBox(
|
||||
child: _sizeBoxWrap(
|
||||
CommonCard(
|
||||
child: Material(
|
||||
elevation: 6,
|
||||
@@ -558,8 +609,8 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
index,
|
||||
),
|
||||
);
|
||||
return _buildTransform(
|
||||
_buildDraggable(
|
||||
return _wrapTransform(
|
||||
_draggableWrap(
|
||||
childWhenDragging: childWhenDragging,
|
||||
feedback: feedback,
|
||||
item: child,
|
||||
@@ -580,7 +631,7 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
if (!animating || _fakeDragWidgetAnimation == null || index == -1) {
|
||||
return Container();
|
||||
}
|
||||
return _buildSizeBox(
|
||||
return _sizeBoxWrap(
|
||||
AnimatedBuilder(
|
||||
animation: _fakeDragWidgetAnimation!,
|
||||
builder: (_, child) {
|
||||
@@ -607,7 +658,10 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
_transformController.dispose();
|
||||
_dragIndexNotifier.dispose();
|
||||
_animating.dispose();
|
||||
_childrenNotifier.removeListener(_handleChildrenNotifierChange);
|
||||
_childrenNotifier.dispose();
|
||||
isEditNotifier.removeListener(_handleIsEditChange);
|
||||
isEditNotifier.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -616,7 +670,7 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
return DeferredPointerHandler(
|
||||
child: Stack(
|
||||
children: [
|
||||
_buildInactivate(
|
||||
_ignoreWrap(
|
||||
ValueListenableBuilder(
|
||||
valueListenable: _childrenNotifier,
|
||||
builder: (_, children, __) {
|
||||
@@ -640,6 +694,46 @@ class SuperGridState extends State<SuperGrid> with TickerProviderStateMixin {
|
||||
}
|
||||
}
|
||||
|
||||
class _AddedWidgetsModal extends StatelessWidget {
|
||||
final List<GridItem> items;
|
||||
final Function(GridItem item) onAdd;
|
||||
|
||||
const _AddedWidgetsModal({
|
||||
required this.items,
|
||||
required this.onAdd,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DeferredPointerHandler(
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.all(
|
||||
16,
|
||||
),
|
||||
child: Grid(
|
||||
crossAxisCount: 8,
|
||||
crossAxisSpacing: 16,
|
||||
mainAxisSpacing: 16,
|
||||
children: items
|
||||
.map(
|
||||
(item) => item.wrap(
|
||||
builder: (child) {
|
||||
return _AddedContainer(
|
||||
onAdd: () {
|
||||
onAdd(item);
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DeletableContainer extends StatefulWidget {
|
||||
final Widget child;
|
||||
final VoidCallback onDelete;
|
||||
@@ -747,3 +841,68 @@ class _DeletableContainerState extends State<_DeletableContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AddedContainer extends StatefulWidget {
|
||||
final Widget child;
|
||||
final VoidCallback onAdd;
|
||||
|
||||
const _AddedContainer({
|
||||
required this.child,
|
||||
required this.onAdd,
|
||||
});
|
||||
|
||||
@override
|
||||
State<_AddedContainer> createState() => _AddedContainerState();
|
||||
}
|
||||
|
||||
class _AddedContainerState extends State<_AddedContainer> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(_AddedContainer oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.child != widget.child) {}
|
||||
}
|
||||
|
||||
_handleAdd() async {
|
||||
widget.onAdd();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
ActivateBox(
|
||||
child: widget.child,
|
||||
),
|
||||
Positioned(
|
||||
top: -8,
|
||||
right: -8,
|
||||
child: DeferPointer(
|
||||
child: SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: IconButton.filled(
|
||||
iconSize: 20,
|
||||
padding: EdgeInsets.all(2),
|
||||
onPressed: _handleAdd,
|
||||
icon: Icon(
|
||||
Icons.add,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,10 +373,8 @@ class _CommonTabBarState<T extends Object> extends State<CommonTabBar<T>>
|
||||
child: Container(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
padding: widget.padding.resolve(Directionality.of(context)),
|
||||
decoration: ShapeDecoration(
|
||||
shape: RoundedSuperellipseBorder(
|
||||
borderRadius: const BorderRadius.all(_kCornerRadius),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(_kCornerRadius),
|
||||
color: widget.backgroundColor,
|
||||
),
|
||||
child: AnimatedBuilder(
|
||||
|
||||
@@ -81,24 +81,6 @@ static gboolean my_application_local_command_line(GApplication* application, gch
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Implements GApplication::startup.
|
||||
static void my_application_startup(GApplication* application) {
|
||||
//MyApplication* self = MY_APPLICATION(object);
|
||||
|
||||
// Perform any actions required at application startup.
|
||||
|
||||
G_APPLICATION_CLASS(my_application_parent_class)->startup(application);
|
||||
}
|
||||
|
||||
// Implements GApplication::shutdown.
|
||||
static void my_application_shutdown(GApplication* application) {
|
||||
//MyApplication* self = MY_APPLICATION(object);
|
||||
|
||||
// Perform any actions required at application shutdown.
|
||||
|
||||
G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);
|
||||
}
|
||||
|
||||
// Implements GObject::dispose.
|
||||
static void my_application_dispose(GObject* object) {
|
||||
MyApplication* self = MY_APPLICATION(object);
|
||||
@@ -109,21 +91,12 @@ static void my_application_dispose(GObject* object) {
|
||||
static void my_application_class_init(MyApplicationClass* klass) {
|
||||
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
|
||||
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
|
||||
G_APPLICATION_CLASS(klass)->startup = my_application_startup;
|
||||
G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
|
||||
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
|
||||
}
|
||||
|
||||
static void my_application_init(MyApplication* self) {}
|
||||
|
||||
MyApplication* my_application_new() {
|
||||
// Set the program name to the application ID, which helps various systems
|
||||
// like GTK and desktop environments map this running application to its
|
||||
// corresponding .desktop file. This ensures better integration by allowing
|
||||
// the application to be recognized beyond its binary name.
|
||||
g_set_prgname(APPLICATION_ID);
|
||||
|
||||
return MY_APPLICATION(g_object_new(my_application_get_type(),
|
||||
"application-id", APPLICATION_ID,
|
||||
nullptr));
|
||||
}
|
||||
return MY_APPLICATION(g_object_new(my_application_get_type(),
|
||||
"application-id", APPLICATION_ID,
|
||||
nullptr)); }
|
||||
|
||||
@@ -40,7 +40,7 @@ PODS:
|
||||
- FlutterMacOS
|
||||
- window_ext (0.0.1):
|
||||
- FlutterMacOS
|
||||
- window_manager (0.5.0):
|
||||
- window_manager (0.2.0):
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
@@ -128,7 +128,7 @@ SPEC CHECKSUMS:
|
||||
tray_manager: a104b5c81b578d83f3c3d0f40a997c8b10810166
|
||||
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
|
||||
window_ext: 4afef727fe428b30c68ce800ba92e890fd329f63
|
||||
window_manager: b729e31d38fb04905235df9ea896128991cad99e
|
||||
window_manager: 1d01fa7ac65a6e6f83b965471b1a7fdd3f06166c
|
||||
|
||||
PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367
|
||||
|
||||
|
||||
111
pubspec.lock
111
pubspec.lock
@@ -85,10 +85,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
||||
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.13.0"
|
||||
version: "2.12.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -161,6 +161,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.9.5"
|
||||
cached_network_image:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cached_network_image
|
||||
sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.1"
|
||||
cached_network_image_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cached_network_image_platform_interface
|
||||
sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.1"
|
||||
cached_network_image_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cached_network_image_web
|
||||
sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -250,7 +274,7 @@ packages:
|
||||
source: hosted
|
||||
version: "0.3.4+2"
|
||||
crypto:
|
||||
dependency: "direct main"
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: crypto
|
||||
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
||||
@@ -373,10 +397,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
|
||||
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
version: "1.3.2"
|
||||
ffi:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -455,7 +479,7 @@ packages:
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_cache_manager:
|
||||
dependency: "direct main"
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_cache_manager
|
||||
sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386"
|
||||
@@ -500,14 +524,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.1"
|
||||
flutter_svg:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_svg
|
||||
sha256: d44bf546b13025ec7353091516f6881f1d4c633993cb109c3916c3a0159dadf1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@@ -706,10 +722,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl
|
||||
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
|
||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.20.2"
|
||||
version: "0.19.0"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -770,10 +786,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
|
||||
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.9"
|
||||
version: "10.0.8"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -870,6 +886,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.0"
|
||||
octo_image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: octo_image
|
||||
sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -902,14 +926,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
path_parsing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_parsing
|
||||
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
path_provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1024,11 +1040,10 @@ packages:
|
||||
re_editor:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: "7cda330fc33d5ef9e00333048b70ce65a5f5d550"
|
||||
url: "https://github.com/chen08209/re-editor.git"
|
||||
source: git
|
||||
name: re_editor
|
||||
sha256: "17e430f0591dd361992ec2dd6f69191c1853fa46e05432e095310a8f82ee820e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
re_highlight:
|
||||
dependency: "direct main"
|
||||
@@ -1459,30 +1474,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.1"
|
||||
vector_graphics:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics
|
||||
sha256: "44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.18"
|
||||
vector_graphics_codec:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_codec
|
||||
sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.13"
|
||||
vector_graphics_compiler:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_compiler
|
||||
sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.17"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1495,10 +1486,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
|
||||
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "15.0.0"
|
||||
version: "14.3.1"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1566,10 +1557,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: window_manager
|
||||
sha256: "51d50168ab267d344b975b15390426b1243600d436770d3f13de67e55b05ec16"
|
||||
sha256: "732896e1416297c63c9e3fb95aea72d0355f61390263982a47fd519169dc5059"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.0"
|
||||
version: "0.4.3"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1587,7 +1578,7 @@ packages:
|
||||
source: hosted
|
||||
version: "6.5.0"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: yaml
|
||||
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
|
||||
|
||||
18
pubspec.yaml
18
pubspec.yaml
@@ -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.86+2025061501
|
||||
version: 0.8.85+202505281
|
||||
environment:
|
||||
sdk: '>=3.1.0 <4.0.0'
|
||||
|
||||
@@ -14,7 +14,7 @@ dependencies:
|
||||
path_provider: ^2.1.0
|
||||
path: ^1.9.0
|
||||
shared_preferences: ^2.5.3
|
||||
window_manager: ^0.5.0
|
||||
window_manager: ^0.4.3
|
||||
dynamic_color: ^1.7.0
|
||||
proxy:
|
||||
path: plugins/proxy
|
||||
@@ -37,14 +37,12 @@ dependencies:
|
||||
dio: ^5.8.0+1
|
||||
win32: ^5.5.1
|
||||
ffi: ^2.1.2
|
||||
re_editor:
|
||||
git:
|
||||
url: https://github.com/chen08209/re-editor.git
|
||||
ref: main
|
||||
re_editor: ^0.7.0
|
||||
re_highlight: ^0.0.3
|
||||
archive: ^3.6.1
|
||||
lpinyin: ^2.0.3
|
||||
emoji_regex: ^0.0.5
|
||||
cached_network_image: ^3.4.0
|
||||
hotkey_manager: ^0.2.3
|
||||
uni_platform: ^0.1.3
|
||||
device_info_plus: ^11.3.3
|
||||
@@ -59,10 +57,7 @@ dependencies:
|
||||
git:
|
||||
url: https://github.com/chen08209/flutter_js
|
||||
ref: master
|
||||
# yaml: ^3.1.3
|
||||
flutter_svg: ^2.1.0
|
||||
flutter_cache_manager: ^3.4.1
|
||||
crypto: ^3.0.3
|
||||
yaml: ^3.1.3
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
@@ -73,8 +68,9 @@ dev_dependencies:
|
||||
args: ^2.4.2
|
||||
freezed: ^2.5.1
|
||||
riverpod_generator: ^2.6.3
|
||||
riverpod_lint: ^2.6.3
|
||||
custom_lint: ^0.7.0
|
||||
riverpod_lint: ^2.6.3
|
||||
crypto: ^3.0.3
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
fn main() {
|
||||
let version = std::env::var("TOKEN").unwrap_or_default();
|
||||
println!("cargo:rustc-env=TOKEN={}", version);
|
||||
println!("cargo:rerun-if-env-changed=TOKEN");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user