Compare commits

..

1 Commits

Author SHA1 Message Date
chen08209
af3eb57956 Support override script
Support proxies search

Add some scenes auto close connections

Update core

Optimize more details
2025-05-28 19:24:50 +08:00
67 changed files with 586 additions and 1209 deletions

View File

@@ -63,17 +63,10 @@ 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

View File

@@ -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

View File

@@ -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">

View File

@@ -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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -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

View File

@@ -402,9 +402,5 @@
"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"
"portConflictTip": "Please enter a different port"
}

View File

@@ -403,9 +403,5 @@
"redirPort": "Redirポート",
"tproxyPort": "Tproxyポート",
"portTip": "{label} は 1024 から 49151 の間でなければなりません",
"portConflictTip": "別のポートを入力してください",
"import": "インポート",
"importFile": "ファイルからインポート",
"importUrl": "URLからインポート",
"autoSetSystemDns": "オートセットシステムDNS"
"portConflictTip": "別のポートを入力してください"
}

View File

@@ -403,9 +403,5 @@
"redirPort": "Redir-порт",
"tproxyPort": "Tproxy-порт",
"portTip": "{label} должен быть числом от 1024 до 49151",
"portConflictTip": "Введите другой порт",
"import": "Импорт",
"importFile": "Импорт из файла",
"importUrl": "Импорт по URL",
"autoSetSystemDns": "Автоматическая настройка системного DNS"
"portConflictTip": "Введите другой порт"
}

View File

@@ -403,9 +403,5 @@
"redirPort": "Redir端口",
"tproxyPort": "Tproxy端口",
"portTip": "{label} 必须在 1024 到 49151 之间",
"portConflictTip": "请输入不同的端口",
"import": "导入",
"importFile": "通过文件导入",
"importUrl": "通过URL导入",
"autoSetSystemDns": "自动设置系统DNS"
"portConflictTip": "请输入不同的端口"
}

View File

@@ -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

View File

@@ -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=

View File

@@ -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(

View File

@@ -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;

View File

@@ -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';

View File

@@ -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;
}

View 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();

View File

@@ -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 {

View File

@@ -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);
// }

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -499,8 +499,3 @@ enum Language {
yaml,
javaScript,
}
enum ImportOption {
file,
url,
}

View File

@@ -123,9 +123,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 +323,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(

View File

@@ -93,7 +93,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 +245,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("正しいホットキーを入力"),

View File

@@ -120,9 +120,6 @@ class MessageLookup extends MessageLookupByLibrary {
"autoRunDesc": MessageLookupByLibrary.simpleMessage(
"Автоматический запуск при открытии приложения",
),
"autoSetSystemDns": MessageLookupByLibrary.simpleMessage(
"Автоматическая настройка системного DNS",
),
"autoUpdate": MessageLookupByLibrary.simpleMessage("Автообновление"),
"autoUpdateInterval": MessageLookupByLibrary.simpleMessage(
"Интервал автообновления (минуты)",
@@ -345,10 +342,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(
"Долгосрочное действие",
),

View File

@@ -87,7 +87,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 +221,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("请输入正确的快捷键"),

View File

@@ -3104,41 +3104,6 @@ class AppLocalizations {
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> {

View File

@@ -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();
}

View File

@@ -57,6 +57,7 @@ class _ClashContainerState extends ConsumerState<ClashManager>
clashCore.stopLog();
}
},
fireImmediately: true,
);
}

View File

@@ -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

View File

@@ -32,7 +32,6 @@ class AppState with _$AppState {
required FixedList<Traffic> traffics,
required Traffic totalTraffic,
@Default("") String proxiesQuery,
@Default(false) bool realTunEnable,
}) = _AppState;
}

View File

@@ -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({

View File

@@ -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) =>

View File

@@ -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.

View File

@@ -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.

View File

@@ -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 = {

View File

@@ -111,25 +111,10 @@ 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;
}
_handleRemoteDownload() async {
final url = await globalState.showCommonDialog(
child: InputDialog(
title: "导入",
title: appLocalizations.download,
value: "",
labelText: appLocalizations.url,
validator: (value) {
@@ -201,7 +186,7 @@ class _EditorPageState extends ConsumerState<EditorPage> {
),
if (widget.supportRemoteDownload)
IconButton(
onPressed: _handleImport,
onPressed: _handleRemoteDownload,
icon: Icon(
Icons.arrow_downward,
),
@@ -251,7 +236,6 @@ class _EditorPageState extends ConsumerState<EditorPage> {
padding: EdgeInsets.only(
right: 16,
),
autocompleteSymbols: true,
focusNode: _focusNode,
scrollbarBuilder: (context, child, details) {
return CommonScrollBar(
@@ -678,45 +662,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.
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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].

View File

@@ -178,7 +178,7 @@ final proxiesStyleSettingProvider =
);
typedef _$ProxiesStyleSetting = AutoDisposeNotifier<ProxiesStyle>;
String _$scriptStateHash() => r'884581c71fd5afa3c9d34f31625d967cf561cdbe';
String _$scriptStateHash() => r'16d669009ffb233d95b2cb206cf771342ebc1cc1';
/// See also [ScriptState].
@ProviderFor(ScriptState)

View File

@@ -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)
@@ -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';

View File

@@ -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,
@@ -627,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);
}

View File

@@ -1,6 +1,8 @@
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 +15,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 +193,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 +315,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"] = "";
@@ -347,13 +356,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 +366,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 +377,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"]);
}
}
}
@@ -418,8 +410,11 @@ class GlobalState {
}
}
var rules = [];
// if (rawConfig["rule"] != null) {
// rules.addAll(rawConfig["rule"]);
// }
if (rawConfig["rules"] != null) {
rules = rawConfig["rules"];
rules.addAll(rawConfig["rules"]);
}
rawConfig.remove("rules");
@@ -428,23 +423,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 {
@@ -452,12 +437,9 @@ 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)
""");

View File

@@ -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: () {

View File

@@ -601,8 +601,7 @@ class _PortDialogState extends ConsumerState<_PortDialog> {
.numberTip(appLocalizations.mixedPort);
}
if (port < 1024 || port > 49151) {
return appLocalizations
.portTip(appLocalizations.mixedPort);
return appLocalizations.mixedPort;
}
final ports = [
_portController.text,

View File

@@ -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(),
],
),
];

View File

@@ -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,
),
),
),
),
)
],
);
}
}

View File

@@ -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(),
],
),

View File

@@ -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(

View File

@@ -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();

View File

@@ -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(),
);
}

View File

@@ -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,
),
);

View File

@@ -422,7 +422,6 @@ class ListItem<T> extends StatelessWidget {
value: radioDelegate.value,
groupValue: radioDelegate.groupValue,
onChanged: radioDelegate.onChanged,
toggleable: true,
),
trailing: trailing,
);

View File

@@ -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,
),
),
),
),
)
],
);
}
}

View File

@@ -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)); }

View File

@@ -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

View File

@@ -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"
@@ -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
@@ -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:
@@ -1458,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:
@@ -1565,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:
@@ -1586,7 +1578,7 @@ packages:
source: hosted
version: "6.5.0"
yaml:
dependency: transitive
dependency: "direct main"
description:
name: yaml
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce

View File

@@ -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+202506121
version: 0.8.85+202505282
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
@@ -42,6 +42,7 @@ dependencies:
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
@@ -56,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
@@ -70,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

View File

@@ -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");
}