From 13d31cf708663e100dbee506790774a909fd33a7 Mon Sep 17 00:00:00 2001 From: chen08209 Date: Wed, 18 Sep 2024 10:27:53 +0800 Subject: [PATCH] Fix android system dns issues Optimize dns default option Fix some issues --- android/app/src/main/AndroidManifest.xml | 8 ++ .../kotlin/com/follow/clash/GlobalState.kt | 2 +- .../kotlin/com/follow/clash/MainActivity.kt | 14 ++ .../kotlin/com/follow/clash/extensions/Ext.kt | 6 +- .../com/follow/clash/plugins/VpnPlugin.kt | 10 +- .../clash/services/FlClashTileService.kt | 8 +- .../clash/services/FlClashVpnService.kt | 19 ++- core/tun/tun.go | 2 +- lib/application.dart | 17 ++- lib/common/context.dart | 2 +- lib/common/http.dart | 8 +- lib/common/iterable.dart | 2 +- lib/common/measure.dart | 4 +- lib/common/other.dart | 6 + lib/common/system.dart | 1 - lib/controller.dart | 20 +-- lib/fragments/config/app.dart | 2 - lib/fragments/config/dns.dart | 11 +- lib/fragments/dashboard/dashboard.dart | 1 - .../dashboard/network_detection.dart | 3 +- lib/fragments/dashboard/network_speed.dart | 4 +- lib/fragments/dashboard/start_button.dart | 10 +- lib/fragments/dashboard/traffic_usage.dart | 4 +- lib/fragments/logs.dart | 6 +- lib/fragments/proxies/card.dart | 20 +-- lib/fragments/proxies/common.dart | 6 +- lib/fragments/proxies/list.dart | 2 +- lib/fragments/proxies/tab.dart | 2 +- lib/l10n/arb/intl_en.arb | 3 +- lib/l10n/arb/intl_zh_CN.arb | 3 +- lib/l10n/intl/messages_en.dart | 2 + lib/l10n/intl/messages_zh_CN.dart | 1 + lib/l10n/l10n.dart | 10 ++ lib/main.dart | 1 - lib/manager/android_manager.dart | 1 - lib/manager/clash_manager.dart | 2 +- lib/manager/proxy_manager.dart | 6 +- lib/manager/tray_manager.dart | 9 +- lib/manager/vpn_manager.dart | 4 +- lib/models/app.dart | 133 +++++++++--------- lib/models/clash_config.dart | 2 +- lib/models/common.dart | 1 - .../generated/clash_config.freezed.dart | 2 +- lib/models/generated/clash_config.g.dart | 2 +- lib/pages/home.dart | 88 +++++------- lib/plugins/app.dart | 2 - lib/plugins/service.dart | 3 +- lib/plugins/vpn.dart | 4 +- lib/state.dart | 12 +- lib/widgets/card.dart | 1 - lib/widgets/open_container.dart | 1 - lib/widgets/sheet.dart | 2 +- pubspec.yaml | 2 +- 53 files changed, 276 insertions(+), 221 deletions(-) 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