diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 13b39ae..e93f589 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -64,6 +64,14 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt b/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt
index 084a4ae..0ee3115 100644
--- a/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/GlobalState.kt
@@ -33,7 +33,7 @@ object GlobalState {
return currentEngine?.plugins?.get(AppPlugin::class.java) as AppPlugin?
}
- fun getCurrentTitlePlugin(): TilePlugin? {
+ fun getCurrentTilePlugin(): TilePlugin? {
val currentEngine = if (flutterEngine != null) flutterEngine else serviceEngine
return currentEngine?.plugins?.get(TilePlugin::class.java) as TilePlugin?
}
diff --git a/android/app/src/main/kotlin/com/follow/clash/MainActivity.kt b/android/app/src/main/kotlin/com/follow/clash/MainActivity.kt
index 4fef0d7..b351774 100644
--- a/android/app/src/main/kotlin/com/follow/clash/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/MainActivity.kt
@@ -1,6 +1,8 @@
package com.follow.clash
+import android.content.Intent
+import android.os.Bundle
import com.follow.clash.plugins.AppPlugin
import com.follow.clash.plugins.ServicePlugin
import com.follow.clash.plugins.VpnPlugin
@@ -9,6 +11,18 @@ import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
class MainActivity : FlutterActivity() {
+ override fun onNewIntent(intent: Intent) {
+ super.onNewIntent(intent)
+ when (intent.action) {
+ "com.follow.clash.action.START" -> {
+ GlobalState.getCurrentTilePlugin()?.handleStart()
+ }
+
+ "com.follow.clash.action.STOP" -> {
+ GlobalState.getCurrentTilePlugin()?.handleStop()
+ }
+ }
+ }
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
diff --git a/android/app/src/main/kotlin/com/follow/clash/extensions/Ext.kt b/android/app/src/main/kotlin/com/follow/clash/extensions/Ext.kt
index 5635249..0ef55f0 100644
--- a/android/app/src/main/kotlin/com/follow/clash/extensions/Ext.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/extensions/Ext.kt
@@ -34,9 +34,9 @@ fun Metadata.getProtocol(): Int? {
}
-fun ConnectivityManager.resolvePrimaryDns(network: Network?): String? {
- val properties = getLinkProperties(network) ?: return null
- return properties.dnsServers.firstOrNull()?.asSocketAddressText(53)
+fun ConnectivityManager.resolveDns(network: Network?): List {
+ val properties = getLinkProperties(network) ?: return listOf()
+ return properties.dnsServers.map { it.asSocketAddressText(53) }
}
fun InetAddress.asSocketAddressText(port: Int): String {
diff --git a/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt b/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt
index b1a0120..0f3098d 100644
--- a/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/plugins/VpnPlugin.kt
@@ -16,7 +16,7 @@ import com.follow.clash.BaseServiceInterface
import com.follow.clash.GlobalState
import com.follow.clash.RunState
import com.follow.clash.extensions.getProtocol
-import com.follow.clash.extensions.resolvePrimaryDns
+import com.follow.clash.extensions.resolveDns
import com.follow.clash.models.Props
import com.follow.clash.models.TunProps
import com.follow.clash.services.FlClashService
@@ -177,9 +177,11 @@ class VpnPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
val networks = mutableSetOf()
fun onUpdateNetwork() {
- val dns = networks.mapNotNull {
- connectivity?.resolvePrimaryDns(it)
- }.joinToString(separator = ",")
+ val dns = networks.flatMap { network ->
+ connectivity?.resolveDns(network) ?: emptyList()
+ }
+ .toSet()
+ .joinToString(",")
scope.launch {
withContext(Dispatchers.Main) {
flutterMethodChannel.invokeMethod("dnsChanged", dns)
diff --git a/android/app/src/main/kotlin/com/follow/clash/services/FlClashTileService.kt b/android/app/src/main/kotlin/com/follow/clash/services/FlClashTileService.kt
index 73a99b8..dd15d45 100644
--- a/android/app/src/main/kotlin/com/follow/clash/services/FlClashTileService.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/services/FlClashTileService.kt
@@ -67,15 +67,15 @@ class FlClashTileService : TileService() {
activityTransfer()
if (GlobalState.runState.value == RunState.STOP) {
GlobalState.runState.value = RunState.PENDING
- val titlePlugin = GlobalState.getCurrentTitlePlugin()
- if (titlePlugin != null) {
- titlePlugin.handleStart()
+ val tilePlugin = GlobalState.getCurrentTilePlugin()
+ if (tilePlugin != null) {
+ tilePlugin.handleStart()
} else {
GlobalState.initServiceEngine(applicationContext)
}
} else if (GlobalState.runState.value == RunState.START) {
GlobalState.runState.value = RunState.PENDING
- GlobalState.getCurrentTitlePlugin()?.handleStop()
+ GlobalState.getCurrentTilePlugin()?.handleStop()
}
}
diff --git a/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt b/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt
index 8458138..8d836e5 100644
--- a/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt
+++ b/android/app/src/main/kotlin/com/follow/clash/services/FlClashVpnService.kt
@@ -159,6 +159,22 @@ class FlClashVpnService : VpnService(), BaseServiceInterface {
PendingIntent.FLAG_UPDATE_CURRENT
)
}
+
+ val stopPendingIntent = if (Build.VERSION.SDK_INT >= 31) {
+ PendingIntent.getActivity(
+ this,
+ 0,
+ Intent("com.follow.clash.action.STOP"),
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
+ )
+ } else {
+ PendingIntent.getActivity(
+ this,
+ 0,
+ Intent("com.follow.clash.action.STOP"),
+ PendingIntent.FLAG_UPDATE_CURRENT
+ )
+ }
with(NotificationCompat.Builder(this, CHANNEL)) {
setSmallIcon(R.drawable.ic_stat_name)
setContentTitle("FlClash")
@@ -172,6 +188,7 @@ class FlClashVpnService : VpnService(), BaseServiceInterface {
setShowWhen(false)
setOnlyAlertOnce(true)
setAutoCancel(true)
+ addAction(0, "Stop", stopPendingIntent);
}
}
@@ -210,7 +227,7 @@ class FlClashVpnService : VpnService(), BaseServiceInterface {
val isSuccess = super.onTransact(code, data, reply, flags)
if (!isSuccess) {
CoroutineScope(Dispatchers.Main).launch {
- GlobalState.getCurrentTitlePlugin()?.handleStop()
+ GlobalState.getCurrentTilePlugin()?.handleStop()
}
}
return isSuccess
diff --git a/core/tun/tun.go b/core/tun/tun.go
index 4ebb7db..39f99e3 100644
--- a/core/tun/tun.go
+++ b/core/tun/tun.go
@@ -47,7 +47,7 @@ func Start(tunProps Props) (*sing_tun.Listener, error) {
options := LC.Tun{
Enable: true,
Device: sing_tun.InterfaceName,
- Stack: constant.TunSystem,
+ Stack: constant.TunMixed,
DNSHijack: dnsHijack,
AutoRoute: false,
AutoDetectInterface: false,
diff --git a/lib/application.dart b/lib/application.dart
index 75d3aba..6e94851 100644
--- a/lib/application.dart
+++ b/lib/application.dart
@@ -1,6 +1,4 @@
import 'dart:async';
-import 'dart:io';
-
import 'package:dynamic_color/dynamic_color.dart';
import 'package:fl_clash/l10n/l10n.dart';
import 'package:fl_clash/common/common.dart';
@@ -29,6 +27,9 @@ runAppWithPreferences(
ChangeNotifierProvider(
create: (_) => config,
),
+ ChangeNotifierProvider(
+ create: (_) => AppFlowingState(),
+ ),
ChangeNotifierProxyProvider2(
create: (_) => appState,
update: (_, config, clashConfig, appState) {
@@ -85,6 +86,7 @@ class ApplicationState extends State {
super.initState();
_initTimer();
globalState.appController = AppController(context);
+ globalState.measure = Measure.of(context);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
final currentContext = globalState.navigatorKey.currentContext;
if (currentContext != null) {
@@ -179,8 +181,15 @@ class ApplicationState extends State {
GlobalWidgetsLocalizations.delegate
],
builder: (_, child) {
- return MediaManager(
- child: _buildPage(child!),
+ return LayoutBuilder(
+ builder: (_, container) {
+ final appController = globalState.appController;
+ final maxWidth = container.maxWidth;
+ if (appController.appState.viewWidth != maxWidth) {
+ globalState.appController.updateViewWidth(maxWidth);
+ }
+ return _buildPage(child!);
+ },
);
},
scrollBehavior: BaseScrollBehavior(),
diff --git a/lib/common/context.dart b/lib/common/context.dart
index 9358caa..eba0e6d 100644
--- a/lib/common/context.dart
+++ b/lib/common/context.dart
@@ -11,7 +11,7 @@ extension BuildContextExtension on BuildContext {
return MediaQuery.of(this).size;
}
- double get width {
+ double get viewWidth {
return appSize.width;
}
diff --git a/lib/common/http.dart b/lib/common/http.dart
index 6eb9f11..174fffd 100644
--- a/lib/common/http.dart
+++ b/lib/common/http.dart
@@ -11,9 +11,13 @@ class FlClashHttpOverrides extends HttpOverrides {
client.badCertificateCallback = (_, __, ___) => true;
client.findProxy = (url) {
debugPrint("find $url");
- final port = globalState.appController.clashConfig.mixedPort;
- final isStart = globalState.appController.appState.isStart;
+ final appController = globalState.appController;
+ final port = appController.clashConfig.mixedPort;
+ final isStart = appController.appFlowingState.isStart;
if (!isStart) return "DIRECT";
+ if (appController.appState.groups.isEmpty) {
+ return "DIRECT";
+ }
return "PROXY localhost:$port";
};
return client;
diff --git a/lib/common/iterable.dart b/lib/common/iterable.dart
index 1235563..802423c 100644
--- a/lib/common/iterable.dart
+++ b/lib/common/iterable.dart
@@ -62,6 +62,6 @@ extension DoubleListExt on List {
}
}
- return -1; // 这行理论上不会执行到,但为了完整性保留
+ return -1;
}
}
diff --git a/lib/common/measure.dart b/lib/common/measure.dart
index 4e8cd96..dce0a59 100644
--- a/lib/common/measure.dart
+++ b/lib/common/measure.dart
@@ -6,7 +6,9 @@ class Measure {
final TextScaler _textScale;
late BuildContext context;
- Measure.of(this.context) : _textScale = MediaQuery.of(context).textScaler;
+ Measure.of(this.context)
+ : _textScale = TextScaler.linear(
+ WidgetsBinding.instance.platformDispatcher.textScaleFactor);
Size computeTextSize(Text text) {
final textPainter = TextPainter(
diff --git a/lib/common/other.dart b/lib/common/other.dart
index a1db0a1..81e063c 100644
--- a/lib/common/other.dart
+++ b/lib/common/other.dart
@@ -220,6 +220,12 @@ class Other {
String getBackupFileName() {
return "${appName}_backup_${DateTime.now().show}.zip";
}
+
+ Size getScreenSize() {
+ final view = WidgetsBinding.instance.platformDispatcher.views.first;
+ return view.physicalSize / view.devicePixelRatio;
+ }
+
}
final other = Other();
diff --git a/lib/common/system.dart b/lib/common/system.dart
index e4abafe..c6c68b1 100644
--- a/lib/common/system.dart
+++ b/lib/common/system.dart
@@ -3,7 +3,6 @@ import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:fl_clash/plugins/app.dart';
import 'package:flutter/services.dart';
-import 'package:window_manager/window_manager.dart';
import 'window.dart';
diff --git a/lib/controller.dart b/lib/controller.dart
index 7e678a7..4b51160 100644
--- a/lib/controller.dart
+++ b/lib/controller.dart
@@ -19,6 +19,7 @@ import 'common/common.dart';
class AppController {
final BuildContext context;
late AppState appState;
+ late AppFlowingState appFlowingState;
late Config config;
late ClashConfig clashConfig;
late Function updateClashConfigDebounce;
@@ -30,6 +31,7 @@ class AppController {
appState = context.read();
config = context.read();
clashConfig = context.read();
+ appFlowingState = context.read();
updateClashConfigDebounce = debounce(() async {
await updateClashConfig();
});
@@ -60,9 +62,9 @@ class AppController {
} else {
await globalState.handleStop();
clashCore.resetTraffic();
- appState.traffics = [];
- appState.totalTraffic = Traffic();
- appState.runTime = null;
+ appFlowingState.traffics = [];
+ appFlowingState.totalTraffic = Traffic();
+ appFlowingState.runTime = null;
addCheckIpNumDebounce();
}
}
@@ -76,15 +78,15 @@ class AppController {
if (startTime != null) {
final startTimeStamp = startTime.millisecondsSinceEpoch;
final nowTimeStamp = DateTime.now().millisecondsSinceEpoch;
- appState.runTime = nowTimeStamp - startTimeStamp;
+ appFlowingState.runTime = nowTimeStamp - startTimeStamp;
} else {
- appState.runTime = null;
+ appFlowingState.runTime = null;
}
}
updateTraffic() {
globalState.updateTraffic(
- appState: appState,
+ appFlowingState: appFlowingState,
);
}
@@ -163,7 +165,7 @@ class AppController {
try {
updateProfile(profile);
} catch (e) {
- appState.addLog(
+ appFlowingState.addLog(
Log(
logLevel: LogLevel.info,
payload: e.toString(),
@@ -241,7 +243,7 @@ class AppController {
clashCore.startLog();
} else {
clashCore.stopLog();
- appState.logs = [];
+ appFlowingState.logs = [];
}
}
@@ -546,7 +548,7 @@ class AppController {
}
updateStart() {
- updateStatus(!appState.isStart);
+ updateStatus(!appFlowingState.isStart);
}
updateAutoLaunch() {
diff --git a/lib/fragments/config/app.dart b/lib/fragments/config/app.dart
index 261893f..2a12fae 100644
--- a/lib/fragments/config/app.dart
+++ b/lib/fragments/config/app.dart
@@ -1,5 +1,3 @@
-import 'dart:io';
-
import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/models/config.dart';
import 'package:fl_clash/state.dart';
diff --git a/lib/fragments/config/dns.dart b/lib/fragments/config/dns.dart
index 0d9a547..0ec3dd7 100644
--- a/lib/fragments/config/dns.dart
+++ b/lib/fragments/config/dns.dart
@@ -1,5 +1,4 @@
import 'package:collection/collection.dart';
-import 'package:fl_clash/common/app_localizations.dart';
import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/models/models.dart';
@@ -18,7 +17,15 @@ class OverrideItem extends StatelessWidget {
commonScaffoldState?.actions = [
IconButton(
onPressed: () {
- globalState.appController.clashConfig.dns = const Dns();
+ globalState.showMessage(
+ title: appLocalizations.resetDns,
+ message: TextSpan(
+ text: appLocalizations.dnsResetTip,
+ ),
+ onTab: () {
+ globalState.appController.clashConfig.dns = const Dns();
+ Navigator.of(context).pop();
+ });
},
tooltip: appLocalizations.resetDns,
icon: const Icon(
diff --git a/lib/fragments/dashboard/dashboard.dart b/lib/fragments/dashboard/dashboard.dart
index c936813..6165796 100644
--- a/lib/fragments/dashboard/dashboard.dart
+++ b/lib/fragments/dashboard/dashboard.dart
@@ -1,4 +1,3 @@
-import 'dart:io';
import 'dart:math';
import 'package:fl_clash/common/common.dart';
diff --git a/lib/fragments/dashboard/network_detection.dart b/lib/fragments/dashboard/network_detection.dart
index 0a22901..2b82a97 100644
--- a/lib/fragments/dashboard/network_detection.dart
+++ b/lib/fragments/dashboard/network_detection.dart
@@ -26,9 +26,10 @@ class _NetworkDetectionState extends State {
_checkIp() async {
final appState = globalState.appController.appState;
+ final appFlowingState = globalState.appController.appFlowingState;
final isInit = appState.isInit;
if (!isInit) return;
- final isStart = appState.isStart;
+ final isStart = appFlowingState.isStart;
if (_preIsStart == false && _preIsStart == isStart) return;
networkDetectionState.value = networkDetectionState.value.copyWith(
isTesting: true,
diff --git a/lib/fragments/dashboard/network_speed.dart b/lib/fragments/dashboard/network_speed.dart
index 4e3bbd4..a999f43 100644
--- a/lib/fragments/dashboard/network_speed.dart
+++ b/lib/fragments/dashboard/network_speed.dart
@@ -116,8 +116,8 @@ class _NetworkSpeedState extends State {
label: appLocalizations.networkSpeed,
iconData: Icons.speed_sharp,
),
- child: Selector>(
- selector: (_, appState) => appState.traffics,
+ child: Selector>(
+ selector: (_, appFlowingState) => appFlowingState.traffics,
builder: (_, traffics, __) {
return Container(
padding: const EdgeInsets.all(16),
diff --git a/lib/fragments/dashboard/start_button.dart b/lib/fragments/dashboard/start_button.dart
index 698c877..a872ca4 100644
--- a/lib/fragments/dashboard/start_button.dart
+++ b/lib/fragments/dashboard/start_button.dart
@@ -34,7 +34,7 @@ class _StartButtonState extends State
handleSwitchStart() {
final appController = globalState.appController;
- if (isStart == appController.appState.isStart) {
+ if (isStart == appController.appFlowingState.isStart) {
isStart = !isStart;
updateController();
appController.updateStatus(isStart);
@@ -50,8 +50,8 @@ class _StartButtonState extends State
}
Widget _updateControllerContainer(Widget child) {
- return Selector(
- selector: (_, appState) => appState.isStart,
+ return Selector(
+ selector: (_, appFlowingState) => appFlowingState.isStart,
builder: (_, isStart, child) {
if (isStart != this.isStart) {
this.isStart = isStart;
@@ -127,8 +127,8 @@ class _StartButtonState extends State
);
},
child: _updateControllerContainer(
- Selector(
- selector: (_, appState) => appState.runTime,
+ Selector(
+ selector: (_, appFlowingState) => appFlowingState.runTime,
builder: (_, int? value, __) {
final text = other.getTimeText(value);
return Text(
diff --git a/lib/fragments/dashboard/traffic_usage.dart b/lib/fragments/dashboard/traffic_usage.dart
index dee6773..99605a6 100644
--- a/lib/fragments/dashboard/traffic_usage.dart
+++ b/lib/fragments/dashboard/traffic_usage.dart
@@ -56,8 +56,8 @@ class TrafficUsage extends StatelessWidget {
label: appLocalizations.trafficUsage,
iconData: Icons.data_saver_off,
),
- child: Selector(
- selector: (_, appState) => appState.totalTraffic,
+ child: Selector(
+ selector: (_, appFlowingState) => appFlowingState.totalTraffic,
builder: (_, totalTraffic, __) {
final upTotalTrafficValue = totalTraffic.up;
final downTotalTrafficValue = totalTraffic.down;
diff --git a/lib/fragments/logs.dart b/lib/fragments/logs.dart
index 83e6509..f827223 100644
--- a/lib/fragments/logs.dart
+++ b/lib/fragments/logs.dart
@@ -29,14 +29,14 @@ class _LogsFragmentState extends State {
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
- final appState = globalState.appController.appState;
- logsNotifier.value = logsNotifier.value.copyWith(logs: appState.logs);
+ final appFlowingState = globalState.appController.appFlowingState;
+ logsNotifier.value = logsNotifier.value.copyWith(logs: appFlowingState.logs);
if (timer != null) {
timer?.cancel();
timer = null;
}
timer = Timer.periodic(const Duration(milliseconds: 200), (timer) {
- final logs = appState.logs;
+ final logs = appFlowingState.logs;
if (!const ListEquality().equals(
logsNotifier.value.logs,
logs,
diff --git a/lib/fragments/proxies/card.dart b/lib/fragments/proxies/card.dart
index 3505dcf..72daa59 100644
--- a/lib/fragments/proxies/card.dart
+++ b/lib/fragments/proxies/card.dart
@@ -133,7 +133,7 @@ class ProxyCard extends StatelessWidget {
final measure = globalState.measure;
final delayText = _buildDelayText();
final proxyNameText = _buildProxyNameText(context);
- return currentGroupProxyNameBuilder(
+ return currentSelectedProxyNameBuilder(
groupName: groupName,
builder: (currentGroupName) {
return Stack(
@@ -214,23 +214,9 @@ class ProxyCard extends StatelessWidget {
config.currentSelectedMap[groupName];
return selectedProxyName ?? '';
},
- builder: (_, value, __) {
+ builder: (_, value, child) {
if (value != proxy.name) return Container();
- return Positioned.fill(
- child: Container(
- alignment: Alignment.topRight,
- margin: const EdgeInsets.all(8),
- child: Container(
- padding: const EdgeInsets.all(4),
- decoration: BoxDecoration(
- shape: BoxShape.circle,
- color:
- Theme.of(context).colorScheme.secondaryContainer,
- ),
- child: const SelectIcon(),
- ),
- ),
- );
+ return child!;
},
child: Positioned.fill(
child: Container(
diff --git a/lib/fragments/proxies/common.dart b/lib/fragments/proxies/common.dart
index 46a4feb..323a7a4 100644
--- a/lib/fragments/proxies/common.dart
+++ b/lib/fragments/proxies/common.dart
@@ -6,7 +6,7 @@ import 'package:fl_clash/state.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
-Widget currentGroupProxyNameBuilder({
+Widget currentSelectedProxyNameBuilder({
required String groupName,
required Widget Function(String currentGroupName) builder,
}) {
@@ -16,8 +16,8 @@ Widget currentGroupProxyNameBuilder({
final selectedProxyName = config.currentSelectedMap[groupName];
return group?.getCurrentSelectedName(selectedProxyName ?? "") ?? "";
},
- builder: (_, currentGroupName, ___) {
- return builder(currentGroupName);
+ builder: (_, currentSelectedProxyName, ___) {
+ return builder(currentSelectedProxyName);
},
);
}
diff --git a/lib/fragments/proxies/list.dart b/lib/fragments/proxies/list.dart
index 978c27e..08ea675 100644
--- a/lib/fragments/proxies/list.dart
+++ b/lib/fragments/proxies/list.dart
@@ -487,7 +487,7 @@ class _ListHeaderState extends State
),
Flexible(
flex: 1,
- child: currentGroupProxyNameBuilder(
+ child: currentSelectedProxyNameBuilder(
groupName: groupName,
builder: (currentGroupName) {
return Row(
diff --git a/lib/fragments/proxies/tab.dart b/lib/fragments/proxies/tab.dart
index 5d5231e..d65cd88 100644
--- a/lib/fragments/proxies/tab.dart
+++ b/lib/fragments/proxies/tab.dart
@@ -321,7 +321,7 @@ class ProxyGroupViewState extends State {
top: 16,
left: 16,
right: 16,
- bottom: 80,
+ bottom: 96,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
diff --git a/lib/l10n/arb/intl_en.arb b/lib/l10n/arb/intl_en.arb
index 0bbbe47..a8c1d72 100644
--- a/lib/l10n/arb/intl_en.arb
+++ b/lib/l10n/arb/intl_en.arb
@@ -303,5 +303,6 @@
"inputCorrectHotkey": "Please enter the correct hotkey",
"hotkeyConflict": "Hotkey conflict",
"remove": "Remove",
- "noHotKey": "No HotKey"
+ "noHotKey": "No HotKey",
+ "dnsResetTip": "Make sure to reset the DNS"
}
\ No newline at end of file
diff --git a/lib/l10n/arb/intl_zh_CN.arb b/lib/l10n/arb/intl_zh_CN.arb
index 6e89c05..50f0cbb 100644
--- a/lib/l10n/arb/intl_zh_CN.arb
+++ b/lib/l10n/arb/intl_zh_CN.arb
@@ -303,5 +303,6 @@
"inputCorrectHotkey": "请输入正确的快捷键",
"hotkeyConflict": "快捷键冲突",
"remove": "移除",
- "noHotKey": "暂无快捷键"
+ "noHotKey": "暂无快捷键",
+ "dnsResetTip": "确定重置DNS"
}
\ No newline at end of file
diff --git a/lib/l10n/intl/messages_en.dart b/lib/l10n/intl/messages_en.dart
index b086b86..9b048f0 100644
--- a/lib/l10n/intl/messages_en.dart
+++ b/lib/l10n/intl/messages_en.dart
@@ -146,6 +146,8 @@ class MessageLookup extends MessageLookupByLibrary {
"dnsDesc":
MessageLookupByLibrary.simpleMessage("Update DNS related settings"),
"dnsMode": MessageLookupByLibrary.simpleMessage("DNS mode"),
+ "dnsResetTip":
+ MessageLookupByLibrary.simpleMessage("Make sure to reset the DNS"),
"doYouWantToPass":
MessageLookupByLibrary.simpleMessage("Do you want to pass"),
"domain": MessageLookupByLibrary.simpleMessage("Domain"),
diff --git a/lib/l10n/intl/messages_zh_CN.dart b/lib/l10n/intl/messages_zh_CN.dart
index 33fc33b..69c6792 100644
--- a/lib/l10n/intl/messages_zh_CN.dart
+++ b/lib/l10n/intl/messages_zh_CN.dart
@@ -120,6 +120,7 @@ class MessageLookup extends MessageLookupByLibrary {
"discovery": MessageLookupByLibrary.simpleMessage("发现新版本"),
"dnsDesc": MessageLookupByLibrary.simpleMessage("更新DNS相关设置"),
"dnsMode": MessageLookupByLibrary.simpleMessage("DNS模式"),
+ "dnsResetTip": MessageLookupByLibrary.simpleMessage("确定重置DNS"),
"doYouWantToPass": MessageLookupByLibrary.simpleMessage("是否要通过"),
"domain": MessageLookupByLibrary.simpleMessage("域名"),
"download": MessageLookupByLibrary.simpleMessage("下载"),
diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart
index 6cd1388..96b614a 100644
--- a/lib/l10n/l10n.dart
+++ b/lib/l10n/l10n.dart
@@ -3099,6 +3099,16 @@ class AppLocalizations {
args: [],
);
}
+
+ /// `Make sure to reset the DNS`
+ String get dnsResetTip {
+ return Intl.message(
+ 'Make sure to reset the DNS',
+ name: 'dnsResetTip',
+ desc: '',
+ args: [],
+ );
+ }
}
class AppLocalizationDelegate extends LocalizationsDelegate {
diff --git a/lib/main.dart b/lib/main.dart
index ed0af9b..de2ac5c 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -2,7 +2,6 @@ import 'dart:async';
import 'dart:io';
import 'package:fl_clash/clash/clash.dart';
-import 'package:fl_clash/common/http.dart';
import 'package:fl_clash/plugins/app.dart';
import 'package:fl_clash/plugins/tile.dart';
import 'package:fl_clash/plugins/vpn.dart';
diff --git a/lib/manager/android_manager.dart b/lib/manager/android_manager.dart
index aed6fed..a8f3b2c 100644
--- a/lib/manager/android_manager.dart
+++ b/lib/manager/android_manager.dart
@@ -1,6 +1,5 @@
import 'package:fl_clash/models/models.dart';
import 'package:fl_clash/plugins/app.dart';
-import 'package:fl_clash/state.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
diff --git a/lib/manager/clash_manager.dart b/lib/manager/clash_manager.dart
index 543fade..cdbbd10 100644
--- a/lib/manager/clash_manager.dart
+++ b/lib/manager/clash_manager.dart
@@ -137,7 +137,7 @@ class _ClashContainerState extends State
@override
void onLog(Log log) {
- globalState.appController.appState.addLog(log);
+ globalState.appController.appFlowingState.addLog(log);
if (log.logLevel == LogLevel.error) {
globalState.appController.showSnackBar(log.payload ?? '');
}
diff --git a/lib/manager/proxy_manager.dart b/lib/manager/proxy_manager.dart
index 1043c45..25ede2c 100644
--- a/lib/manager/proxy_manager.dart
+++ b/lib/manager/proxy_manager.dart
@@ -21,9 +21,9 @@ class ProxyManager extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return Selector3(
- selector: (_, appState, config, clashConfig) => ProxyState(
- isStart: appState.isStart,
+ return Selector3(
+ selector: (_, appFlowingState, config, clashConfig) => ProxyState(
+ isStart: appFlowingState.isStart,
systemProxy: config.desktopProps.systemProxy,
port: clashConfig.mixedPort,
),
diff --git a/lib/manager/tray_manager.dart b/lib/manager/tray_manager.dart
index 49a325f..d6902d5 100755
--- a/lib/manager/tray_manager.dart
+++ b/lib/manager/tray_manager.dart
@@ -42,7 +42,7 @@ class _TrayContainerState extends State with TrayListener {
WidgetsBinding.instance.platformDispatcher.platformBrightness,
),
);
- if(!Platform.isLinux){
+ if (!Platform.isLinux) {
await trayManager.setToolTip(
appName,
);
@@ -138,11 +138,12 @@ class _TrayContainerState extends State with TrayListener {
@override
Widget build(BuildContext context) {
- return Selector3(
- selector: (_, appState, config, clashConfig) => TrayState(
+ return Selector4(
+ selector: (_, appState, appFlowingState, config, clashConfig) =>
+ TrayState(
mode: clashConfig.mode,
autoLaunch: config.autoLaunch,
- isStart: appState.isStart,
+ isStart: appFlowingState.isStart,
locale: config.locale,
systemProxy: config.desktopProps.systemProxy,
tunEnable: clashConfig.tun.enable,
diff --git a/lib/manager/vpn_manager.dart b/lib/manager/vpn_manager.dart
index 8f4c801..0eef88c 100644
--- a/lib/manager/vpn_manager.dart
+++ b/lib/manager/vpn_manager.dart
@@ -24,8 +24,8 @@ class _VpnContainerState extends State {
showTip() {
vpnTipDebounce ??= debounce(() async {
WidgetsBinding.instance.addPostFrameCallback((_) {
- final appState = globalState.appController.appState;
- if (appState.isStart) {
+ final appFlowingState = globalState.appController.appFlowingState;
+ if (appFlowingState.isStart) {
globalState.showSnackBar(
context,
message: appLocalizations.vpnTip,
diff --git a/lib/models/app.dart b/lib/models/app.dart
index e8cb09d..1d8af29 100644
--- a/lib/models/app.dart
+++ b/lib/models/app.dart
@@ -12,12 +12,8 @@ typedef DelayMap = Map;
class AppState with ChangeNotifier {
List _navigationItems;
- int? _runTime;
bool _isInit;
VersionInfo? _versionInfo;
- List _traffics;
- Traffic _totalTraffic;
- List _logs;
String _currentLabel;
SystemColorSchemes _systemColorSchemes;
num _sortNum;
@@ -42,16 +38,13 @@ class AppState with ChangeNotifier {
}) : _navigationItems = [],
_isInit = false,
_currentLabel = "dashboard",
- _traffics = [],
- _logs = [],
- _viewWidth = 0,
+ _viewWidth = other.getScreenSize().width,
_selectedMap = selectedMap,
_sortNum = 0,
_checkIpNum = 0,
_requests = [],
_mode = mode,
_brightness = null,
- _totalTraffic = Traffic(),
_delayMap = {},
_groups = [],
_providers = [],
@@ -101,17 +94,6 @@ class AppState with ChangeNotifier {
}
}
- bool get isStart => _runTime != null;
-
- int? get runTime => _runTime;
-
- set runTime(int? value) {
- if (_runTime != value) {
- _runTime = value;
- notifyListeners();
- }
- }
-
String getDesc(String type, String proxyName) {
final groupTypeNamesList = GroupType.values.map((e) => e.name).toList();
if (!groupTypeNamesList.contains(type)) {
@@ -158,33 +140,6 @@ class AppState with ChangeNotifier {
}
}
- List get traffics => _traffics;
-
- set traffics(List value) {
- if (_traffics != value) {
- _traffics = value;
- notifyListeners();
- }
- }
-
- addTraffic(Traffic traffic) {
- _traffics = List.from(_traffics)..add(traffic);
- const maxLength = 60;
- if (_traffics.length > maxLength) {
- _traffics = _traffics.sublist(_traffics.length - maxLength);
- }
- notifyListeners();
- }
-
- Traffic get totalTraffic => _totalTraffic;
-
- set totalTraffic(Traffic value) {
- if (_totalTraffic != value) {
- _totalTraffic = value;
- notifyListeners();
- }
- }
-
List get requests => _requests;
set requests(List value) {
@@ -203,24 +158,6 @@ class AppState with ChangeNotifier {
notifyListeners();
}
- List get logs => _logs;
-
- set logs(List value) {
- if (_logs != value) {
- _logs = value;
- notifyListeners();
- }
- }
-
- addLog(Log log) {
- _logs = List.from(_logs)..add(log);
- final maxLength = Platform.isAndroid ? 1000 : 60;
- if (_logs.length > maxLength) {
- _logs = _logs.sublist(_logs.length - maxLength);
- }
- notifyListeners();
- }
-
SystemColorSchemes get systemColorSchemes => _systemColorSchemes;
set systemColorSchemes(SystemColorSchemes value) {
@@ -383,3 +320,71 @@ class AppState with ChangeNotifier {
}
}
}
+
+class AppFlowingState with ChangeNotifier {
+ int? _runTime;
+ List _logs;
+ List _traffics;
+ Traffic _totalTraffic;
+
+ AppFlowingState()
+ : _logs = [],
+ _traffics = [],
+ _totalTraffic = Traffic();
+
+ bool get isStart => _runTime != null;
+
+ int? get runTime => _runTime;
+
+ set runTime(int? value) {
+ if (_runTime != value) {
+ _runTime = value;
+ notifyListeners();
+ }
+ }
+
+ List get logs => _logs;
+
+ set logs(List value) {
+ if (_logs != value) {
+ _logs = value;
+ notifyListeners();
+ }
+ }
+
+ addLog(Log log) {
+ _logs = List.from(_logs)..add(log);
+ final maxLength = Platform.isAndroid ? 1000 : 60;
+ if (_logs.length > maxLength) {
+ _logs = _logs.sublist(_logs.length - maxLength);
+ }
+ notifyListeners();
+ }
+
+ List get traffics => _traffics;
+
+ set traffics(List value) {
+ if (_traffics != value) {
+ _traffics = value;
+ notifyListeners();
+ }
+ }
+
+ addTraffic(Traffic traffic) {
+ _traffics = List.from(_traffics)..add(traffic);
+ const maxLength = 60;
+ if (_traffics.length > maxLength) {
+ _traffics = _traffics.sublist(_traffics.length - maxLength);
+ }
+ notifyListeners();
+ }
+
+ Traffic get totalTraffic => _totalTraffic;
+
+ set totalTraffic(Traffic value) {
+ if (_totalTraffic != value) {
+ _totalTraffic = value;
+ notifyListeners();
+ }
+ }
+}
diff --git a/lib/models/clash_config.dart b/lib/models/clash_config.dart
index 98d70c6..e0b1d36 100644
--- a/lib/models/clash_config.dart
+++ b/lib/models/clash_config.dart
@@ -52,7 +52,7 @@ class Dns with _$Dns {
@Default(false) @JsonKey(name: "prefer-h3") bool preferH3,
@Default(true) @JsonKey(name: "use-hosts") bool useHosts,
@Default(true) @JsonKey(name: "use-system-hosts") bool useSystemHosts,
- @Default(true) @JsonKey(name: "respect-rules") bool respectRules,
+ @Default(false) @JsonKey(name: "respect-rules") bool respectRules,
@Default(false) bool ipv6,
@Default(["223.5.5.5"])
@JsonKey(name: "default-nameserver")
diff --git a/lib/models/common.dart b/lib/models/common.dart
index 467aa4c..b46fe48 100644
--- a/lib/models/common.dart
+++ b/lib/models/common.dart
@@ -1,4 +1,3 @@
-import 'dart:convert';
import 'dart:math';
import 'package:collection/collection.dart';
diff --git a/lib/models/generated/clash_config.freezed.dart b/lib/models/generated/clash_config.freezed.dart
index 364e450..b1c3528 100644
--- a/lib/models/generated/clash_config.freezed.dart
+++ b/lib/models/generated/clash_config.freezed.dart
@@ -772,7 +772,7 @@ class _$DnsImpl implements _Dns {
@JsonKey(name: "prefer-h3") this.preferH3 = false,
@JsonKey(name: "use-hosts") this.useHosts = true,
@JsonKey(name: "use-system-hosts") this.useSystemHosts = true,
- @JsonKey(name: "respect-rules") this.respectRules = true,
+ @JsonKey(name: "respect-rules") this.respectRules = false,
this.ipv6 = false,
@JsonKey(name: "default-nameserver")
final List defaultNameserver = const ["223.5.5.5"],
diff --git a/lib/models/generated/clash_config.g.dart b/lib/models/generated/clash_config.g.dart
index 7f88196..61f7d95 100644
--- a/lib/models/generated/clash_config.g.dart
+++ b/lib/models/generated/clash_config.g.dart
@@ -141,7 +141,7 @@ _$DnsImpl _$$DnsImplFromJson(Map json) => _$DnsImpl(
preferH3: json['prefer-h3'] as bool? ?? false,
useHosts: json['use-hosts'] as bool? ?? true,
useSystemHosts: json['use-system-hosts'] as bool? ?? true,
- respectRules: json['respect-rules'] as bool? ?? true,
+ respectRules: json['respect-rules'] as bool? ?? false,
ipv6: json['ipv6'] as bool? ?? false,
defaultNameserver: (json['default-nameserver'] as List?)
?.map((e) => e as String)
diff --git a/lib/pages/home.dart b/lib/pages/home.dart
index c9574f5..314cfb6 100644
--- a/lib/pages/home.dart
+++ b/lib/pages/home.dart
@@ -1,4 +1,3 @@
-import 'package:collection/collection.dart';
import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/models/models.dart';
import 'package:fl_clash/state.dart';
@@ -155,56 +154,47 @@ class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BackScope(
- child: LayoutBuilder(
- builder: (_, container) {
- final appController = globalState.appController;
- final maxWidth = container.maxWidth;
- if (appController.appState.viewWidth != maxWidth) {
- globalState.appController.updateViewWidth(maxWidth);
- }
- return Selector2(
- selector: (_, appState, config) {
- return HomeState(
- currentLabel: appState.currentLabel,
- navigationItems: appState.currentNavigationItems,
- viewMode: other.getViewMode(maxWidth),
- locale: config.locale,
- );
- },
- shouldRebuild: (prev, next) {
- return prev != next;
- },
- builder: (_, state, child) {
- final viewMode = state.viewMode;
- final navigationItems = state.navigationItems;
- final currentLabel = state.currentLabel;
- final index = navigationItems.lastIndexWhere(
- (element) => element.label == currentLabel,
- );
- final currentIndex = index == -1 ? 0 : index;
- final navigationBar = _getNavigationBar(
- context: context,
- viewMode: viewMode,
- navigationItems: navigationItems,
- currentIndex: currentIndex,
- );
- final bottomNavigationBar =
- viewMode == ViewMode.mobile ? navigationBar : null;
- final sideNavigationBar =
- viewMode != ViewMode.mobile ? navigationBar : null;
- return CommonScaffold(
- key: globalState.homeScaffoldKey,
- title: Intl.message(
- currentLabel,
- ),
- sideNavigationBar: sideNavigationBar,
- body: child!,
- bottomNavigationBar: bottomNavigationBar,
- );
- },
- child: _buildPageView(),
+ child: Selector2(
+ selector: (_, appState, config) {
+ return HomeState(
+ currentLabel: appState.currentLabel,
+ navigationItems: appState.currentNavigationItems,
+ viewMode: appState.viewMode,
+ locale: config.locale,
);
},
+ shouldRebuild: (prev, next) {
+ return prev != next;
+ },
+ builder: (_, state, child) {
+ final viewMode = state.viewMode;
+ final navigationItems = state.navigationItems;
+ final currentLabel = state.currentLabel;
+ final index = navigationItems.lastIndexWhere(
+ (element) => element.label == currentLabel,
+ );
+ final currentIndex = index == -1 ? 0 : index;
+ final navigationBar = _getNavigationBar(
+ context: context,
+ viewMode: viewMode,
+ navigationItems: navigationItems,
+ currentIndex: currentIndex,
+ );
+ final bottomNavigationBar =
+ viewMode == ViewMode.mobile ? navigationBar : null;
+ final sideNavigationBar =
+ viewMode != ViewMode.mobile ? navigationBar : null;
+ return CommonScaffold(
+ key: globalState.homeScaffoldKey,
+ title: Intl.message(
+ currentLabel,
+ ),
+ sideNavigationBar: sideNavigationBar,
+ body: child!,
+ bottomNavigationBar: bottomNavigationBar,
+ );
+ },
+ child: _buildPageView(),
),
);
}
diff --git a/lib/plugins/app.dart b/lib/plugins/app.dart
index 9e975e9..57296ce 100644
--- a/lib/plugins/app.dart
+++ b/lib/plugins/app.dart
@@ -3,9 +3,7 @@ import 'dart:convert';
import 'dart:io';
import 'dart:isolate';
-import 'package:fl_clash/clash/clash.dart';
import 'package:fl_clash/models/models.dart';
-import 'package:fl_clash/state.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
diff --git a/lib/plugins/service.dart b/lib/plugins/service.dart
index cb2ee04..11b35f0 100644
--- a/lib/plugins/service.dart
+++ b/lib/plugins/service.dart
@@ -1,7 +1,6 @@
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
-import 'package:fl_clash/state.dart';
import 'package:flutter/services.dart';
class Service {
@@ -28,4 +27,4 @@ class Service {
}
final service =
- Platform.isAndroid && !globalState.isVpnService ? Service() : null;
+ Platform.isAndroid ? Service() : null;
diff --git a/lib/plugins/vpn.dart b/lib/plugins/vpn.dart
index 499dfc6..4003d39 100644
--- a/lib/plugins/vpn.dart
+++ b/lib/plugins/vpn.dart
@@ -6,8 +6,6 @@ import 'dart:isolate';
import 'package:fl_clash/clash/clash.dart';
import 'package:fl_clash/enum/enum.dart';
import 'package:fl_clash/models/models.dart';
-import 'package:fl_clash/state.dart';
-import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
class Vpn {
@@ -105,4 +103,4 @@ class Vpn {
}
}
-final vpn = Platform.isAndroid && globalState.isVpnService ? Vpn() : null;
+final vpn = Platform.isAndroid ? Vpn() : null;
diff --git a/lib/state.dart b/lib/state.dart
index 0376a74..367b85a 100644
--- a/lib/state.dart
+++ b/lib/state.dart
@@ -76,7 +76,7 @@ class GlobalState {
required ClashConfig clashConfig,
}) async {
clashCore.start();
- if (vpn != null) {
+ if (globalState.isVpnService) {
await vpn?.startVpn(clashConfig.mixedPort);
startListenUpdate();
return;
@@ -222,7 +222,7 @@ class GlobalState {
}
updateTraffic({
- AppState? appState,
+ AppFlowingState? appFlowingState,
}) {
final traffic = clashCore.getTraffic();
if (Platform.isAndroid && isVpnService == true) {
@@ -231,9 +231,9 @@ class GlobalState {
content: "$traffic",
);
} else {
- if (appState != null) {
- appState.addTraffic(traffic);
- appState.totalTraffic = clashCore.getTotalTraffic();
+ if (appFlowingState != null) {
+ appFlowingState.addTraffic(traffic);
+ appFlowingState.totalTraffic = clashCore.getTotalTraffic();
}
}
}
@@ -243,7 +243,7 @@ class GlobalState {
required String message,
SnackBarAction? action,
}) {
- final width = context.width;
+ final width = context.viewWidth;
EdgeInsets margin;
if (width < 600) {
margin = const EdgeInsets.only(
diff --git a/lib/widgets/card.dart b/lib/widgets/card.dart
index f957a22..589954a 100644
--- a/lib/widgets/card.dart
+++ b/lib/widgets/card.dart
@@ -1,6 +1,5 @@
import 'package:fl_clash/common/common.dart';
import 'package:fl_clash/enum/enum.dart';
-import 'package:fl_clash/state.dart';
import 'package:flutter/material.dart';
import 'text.dart';
diff --git a/lib/widgets/open_container.dart b/lib/widgets/open_container.dart
index fb4ad3d..0fcc0e5 100644
--- a/lib/widgets/open_container.dart
+++ b/lib/widgets/open_container.dart
@@ -462,7 +462,6 @@ class _OpenContainerRoute extends ModalRoute {
);
TweenSequence? colorTween;
TweenSequence? closedOpacityTween, openOpacityTween;
- Animatable? scrimTween;
switch (animation.status) {
case AnimationStatus.dismissed:
case AnimationStatus.forward:
diff --git a/lib/widgets/sheet.dart b/lib/widgets/sheet.dart
index 130d334..63d8627 100644
--- a/lib/widgets/sheet.dart
+++ b/lib/widgets/sheet.dart
@@ -53,7 +53,7 @@ showExtendPage(
body: uniqueBody,
);
return SizedBox(
- width: isMobile ? context.width : extendPageWidth ?? 300,
+ width: isMobile ? context.viewWidth : extendPageWidth ?? 300,
child: commonScaffold,
);
},
diff --git a/pubspec.yaml b/pubspec.yaml
index d1b9243..1b8edc1 100755
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,7 +1,7 @@
name: fl_clash
description: A multi-platform proxy client based on ClashMeta, simple and easy to use, open-source and ad-free.
publish_to: 'none'
-version: 0.8.60+202409171
+version: 0.8.61+202409201
environment:
sdk: '>=3.1.0 <4.0.0'
flutter: 3.22.0