Parcourir la source

fix: 修改按钮样式、增加前后台切换刷新launch间隔

lilu il y a 1 mois
Parent
commit
f65af802b4

BIN
android/app/libs/libxray.aar


+ 13 - 4
android/app/src/main/kotlin/app/xixi/nomo/XRayService.kt

@@ -21,17 +21,15 @@ import com.google.gson.Gson
 import go.Seq
 import ixvpn_mobile.Ixvpn_mobile
 import ixvpn_mobile.ProxyConnectorHandler
-import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.isActive
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.withLock
-import kotlinx.coroutines.withContext
-import kotlinx.coroutines.withTimeoutOrNull
 import org.json.JSONObject
 import win.fkey.netboost.service.NetworkReporter
+import java.io.File
 
 
 class XRayService : LifecycleVpnService() {
@@ -93,7 +91,7 @@ class XRayService : LifecycleVpnService() {
         VLog.i(TAG, "XRayService onCreate")
 
         Seq.setContext(applicationContext)
-        Ixvpn_mobile.initProxyConnector(0)
+        Ixvpn_mobile.initProxyConnector(0, getXrayLog())
         registerNotificationChannel(
             this,
             NOTIFICATION_CHANNEL_ID,
@@ -105,6 +103,17 @@ class XRayService : LifecycleVpnService() {
         registerForegroundReceiver()
     }
 
+    /**
+     * 内核日志路径
+     */
+    private fun getXrayLog(): String {
+        val logDir = File(applicationContext.filesDir, "xray")
+        if (!logDir.exists()) {
+            logDir.mkdirs()
+        }
+        return logDir.absolutePath
+    }
+
     /**
      * 注册屏幕状态监听器
      */

+ 2 - 2
lib/app/constants/api_domains.dart

@@ -133,8 +133,8 @@ class ApiDomains {
   void initUrls() {
     if (Configs.debug) {
       _apiUrls = [
-        'https://api.znomo.com', // 测试环境
-        // "https://nomo-api.clickto.dev", // 开发环境
+        // 'https://api.znomo.com', // 测试环境
+        "https://nomo-api.clickto.dev", // 开发环境
       ];
       _routerUrls = [];
       _logUrls = [];

+ 25 - 13
lib/app/controllers/api_controller.dart

@@ -111,6 +111,9 @@ class ApiController extends GetxService with WidgetsBindingObserver {
   // 切换到后台时的系统时钟时间戳(毫秒,不受系统时间修改影响)
   int _backgroundElapsedRealtime = 0;
 
+  // 记录最新活跃状态时间
+  int lastActiveTime = 0;
+
   @override
   void onInit() {
     super.onInit();
@@ -135,10 +138,17 @@ class ApiController extends GetxService with WidgetsBindingObserver {
     } else if (state == AppLifecycleState.resumed) {
       if (isBackground) {
         isBackground = false;
-        asyncHandleLaunch(isRefreshLaunch: true);
         ApiStatistics.instance.onAppResumed();
         // 计算后台经过的时间,继续倒计时
         _resumeRemainTimeCountdown();
+        int currentTime = NtpTimeService().getCurrentTimestamp();
+        int activeInterval = IXSP.getAppConfig()?.activeInterval ?? 0;
+        if (activeInterval > 0 &&
+            lastActiveTime + activeInterval * 1000 * 60 > currentTime) {
+          return;
+        }
+        lastActiveTime = currentTime;
+        asyncHandleLaunch(isRefreshLaunch: true);
       }
     }
   }
@@ -248,18 +258,20 @@ class ApiController extends GetxService with WidgetsBindingObserver {
       fp.isConnectedVpn = false;
     }
     try {
-      final simInfo = await BaseCoreApi().getSimInfo();
-      // 解析sim
-      final sim = jsonDecode(simInfo ?? '{}');
-      fp.simReady = sim['simReady'];
-      fp.carrierName = sim['carrierName'];
-      fp.mcc = sim['mcc'];
-      fp.mnc = sim['mnc'];
-      fp.countryIso = sim['countryIso'];
-      fp.networkCarrierName = sim['networkCarrierName'];
-      fp.networkMcc = sim['networkMcc'];
-      fp.networkMnc = sim['networkMnc'];
-      fp.networkCountryIso = sim['networkCountryIso'];
+      if (!Platform.isWindows) {
+        final simInfo = await BaseCoreApi().getSimInfo();
+        // 解析sim
+        final sim = jsonDecode(simInfo ?? '{}');
+        fp.simReady = sim['simReady'];
+        fp.carrierName = sim['carrierName'];
+        fp.mcc = sim['mcc'];
+        fp.mnc = sim['mnc'];
+        fp.countryIso = sim['countryIso'];
+        fp.networkCarrierName = sim['networkCarrierName'];
+        fp.networkMcc = sim['networkMcc'];
+        fp.networkMnc = sim['networkMnc'];
+        fp.networkCountryIso = sim['networkCountryIso'];
+      }
     } catch (e) {
       log(TAG, 'read app sim error: $e');
     }

+ 1 - 1
lib/app/data/models/launch/app_config.dart

@@ -47,7 +47,7 @@ class AppConfig with _$AppConfig {
     int? peekTimeInterval,
     bool? enableAd,
     int? adTimeoutDuration,
-    int? reportActiveInterval,
+    int? activeInterval,
     int? serverTime,
     int? vipRemainNotice,
     int? upgradeNoticeTime,

+ 20 - 20
lib/app/data/models/launch/app_config.freezed.dart

@@ -60,7 +60,7 @@ mixin _$AppConfig {
   int? get peekTimeInterval => throw _privateConstructorUsedError;
   bool? get enableAd => throw _privateConstructorUsedError;
   int? get adTimeoutDuration => throw _privateConstructorUsedError;
-  int? get reportActiveInterval => throw _privateConstructorUsedError;
+  int? get activeInterval => throw _privateConstructorUsedError;
   int? get serverTime => throw _privateConstructorUsedError;
   int? get vipRemainNotice => throw _privateConstructorUsedError;
   int? get upgradeNoticeTime => throw _privateConstructorUsedError;
@@ -120,7 +120,7 @@ abstract class $AppConfigCopyWith<$Res> {
     int? peekTimeInterval,
     bool? enableAd,
     int? adTimeoutDuration,
-    int? reportActiveInterval,
+    int? activeInterval,
     int? serverTime,
     int? vipRemainNotice,
     int? upgradeNoticeTime,
@@ -183,7 +183,7 @@ class _$AppConfigCopyWithImpl<$Res, $Val extends AppConfig>
     Object? peekTimeInterval = freezed,
     Object? enableAd = freezed,
     Object? adTimeoutDuration = freezed,
-    Object? reportActiveInterval = freezed,
+    Object? activeInterval = freezed,
     Object? serverTime = freezed,
     Object? vipRemainNotice = freezed,
     Object? upgradeNoticeTime = freezed,
@@ -340,9 +340,9 @@ class _$AppConfigCopyWithImpl<$Res, $Val extends AppConfig>
                 ? _value.adTimeoutDuration
                 : adTimeoutDuration // ignore: cast_nullable_to_non_nullable
                       as int?,
-            reportActiveInterval: freezed == reportActiveInterval
-                ? _value.reportActiveInterval
-                : reportActiveInterval // ignore: cast_nullable_to_non_nullable
+            activeInterval: freezed == activeInterval
+                ? _value.activeInterval
+                : activeInterval // ignore: cast_nullable_to_non_nullable
                       as int?,
             serverTime: freezed == serverTime
                 ? _value.serverTime
@@ -431,7 +431,7 @@ abstract class _$$AppConfigImplCopyWith<$Res>
     int? peekTimeInterval,
     bool? enableAd,
     int? adTimeoutDuration,
-    int? reportActiveInterval,
+    int? activeInterval,
     int? serverTime,
     int? vipRemainNotice,
     int? upgradeNoticeTime,
@@ -494,7 +494,7 @@ class __$$AppConfigImplCopyWithImpl<$Res>
     Object? peekTimeInterval = freezed,
     Object? enableAd = freezed,
     Object? adTimeoutDuration = freezed,
-    Object? reportActiveInterval = freezed,
+    Object? activeInterval = freezed,
     Object? serverTime = freezed,
     Object? vipRemainNotice = freezed,
     Object? upgradeNoticeTime = freezed,
@@ -651,9 +651,9 @@ class __$$AppConfigImplCopyWithImpl<$Res>
             ? _value.adTimeoutDuration
             : adTimeoutDuration // ignore: cast_nullable_to_non_nullable
                   as int?,
-        reportActiveInterval: freezed == reportActiveInterval
-            ? _value.reportActiveInterval
-            : reportActiveInterval // ignore: cast_nullable_to_non_nullable
+        activeInterval: freezed == activeInterval
+            ? _value.activeInterval
+            : activeInterval // ignore: cast_nullable_to_non_nullable
                   as int?,
         serverTime: freezed == serverTime
             ? _value.serverTime
@@ -721,7 +721,7 @@ class _$AppConfigImpl with DiagnosticableTreeMixin implements _AppConfig {
     this.peekTimeInterval,
     this.enableAd,
     this.adTimeoutDuration,
-    this.reportActiveInterval,
+    this.activeInterval,
     this.serverTime,
     this.vipRemainNotice,
     this.upgradeNoticeTime,
@@ -985,7 +985,7 @@ class _$AppConfigImpl with DiagnosticableTreeMixin implements _AppConfig {
   @override
   final int? adTimeoutDuration;
   @override
-  final int? reportActiveInterval;
+  final int? activeInterval;
   @override
   final int? serverTime;
   @override
@@ -999,7 +999,7 @@ class _$AppConfigImpl with DiagnosticableTreeMixin implements _AppConfig {
 
   @override
   String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
-    return 'AppConfig(apiIps: $apiIps, apiUrls: $apiUrls, routerApiUrls: $routerApiUrls, appStatUrls: $appStatUrls, assetUrls: $assetUrls, logFileUploadUrls: $logFileUploadUrls, realityApiUrls: $realityApiUrls, realityAppStatUrls: $realityAppStatUrls, realityLogFileUploadUrls: $realityLogFileUploadUrls, autoPing: $autoPing, autoPingInterval: $autoPingInterval, backupApiUrls: $backupApiUrls, cacheDataEffectiveDays: $cacheDataEffectiveDays, contacts: $contacts, follows: $follows, providers: $providers, signalThresholds: $signalThresholds, packetLossThresholds: $packetLossThresholds, skipGeo: $skipGeo, speedTestTargetList: $speedTestTargetList, websiteUrl: $websiteUrl, visitorDisabled: $visitorDisabled, privacyAgreement: $privacyAgreement, email: $email, blackPkgs: $blackPkgs, whitePkgs: $whitePkgs, accelerationSampleCount: $accelerationSampleCount, minAccelerationSampleCount: $minAccelerationSampleCount, connectionWarningThreshold: $connectionWarningThreshold, connectiveTestUrl: $connectiveTestUrl, disabledLogModules: $disabledLogModules, realTimeDbPath: $realTimeDbPath, boostTimeInterval: $boostTimeInterval, pingDisplayMode: $pingDisplayMode, peekTimeInterval: $peekTimeInterval, enableAd: $enableAd, adTimeoutDuration: $adTimeoutDuration, reportActiveInterval: $reportActiveInterval, serverTime: $serverTime, vipRemainNotice: $vipRemainNotice, upgradeNoticeTime: $upgradeNoticeTime, pushNoticeTime: $pushNoticeTime, smartGeo: $smartGeo)';
+    return 'AppConfig(apiIps: $apiIps, apiUrls: $apiUrls, routerApiUrls: $routerApiUrls, appStatUrls: $appStatUrls, assetUrls: $assetUrls, logFileUploadUrls: $logFileUploadUrls, realityApiUrls: $realityApiUrls, realityAppStatUrls: $realityAppStatUrls, realityLogFileUploadUrls: $realityLogFileUploadUrls, autoPing: $autoPing, autoPingInterval: $autoPingInterval, backupApiUrls: $backupApiUrls, cacheDataEffectiveDays: $cacheDataEffectiveDays, contacts: $contacts, follows: $follows, providers: $providers, signalThresholds: $signalThresholds, packetLossThresholds: $packetLossThresholds, skipGeo: $skipGeo, speedTestTargetList: $speedTestTargetList, websiteUrl: $websiteUrl, visitorDisabled: $visitorDisabled, privacyAgreement: $privacyAgreement, email: $email, blackPkgs: $blackPkgs, whitePkgs: $whitePkgs, accelerationSampleCount: $accelerationSampleCount, minAccelerationSampleCount: $minAccelerationSampleCount, connectionWarningThreshold: $connectionWarningThreshold, connectiveTestUrl: $connectiveTestUrl, disabledLogModules: $disabledLogModules, realTimeDbPath: $realTimeDbPath, boostTimeInterval: $boostTimeInterval, pingDisplayMode: $pingDisplayMode, peekTimeInterval: $peekTimeInterval, enableAd: $enableAd, adTimeoutDuration: $adTimeoutDuration, activeInterval: $activeInterval, serverTime: $serverTime, vipRemainNotice: $vipRemainNotice, upgradeNoticeTime: $upgradeNoticeTime, pushNoticeTime: $pushNoticeTime, smartGeo: $smartGeo)';
   }
 
   @override
@@ -1063,7 +1063,7 @@ class _$AppConfigImpl with DiagnosticableTreeMixin implements _AppConfig {
       ..add(DiagnosticsProperty('peekTimeInterval', peekTimeInterval))
       ..add(DiagnosticsProperty('enableAd', enableAd))
       ..add(DiagnosticsProperty('adTimeoutDuration', adTimeoutDuration))
-      ..add(DiagnosticsProperty('reportActiveInterval', reportActiveInterval))
+      ..add(DiagnosticsProperty('activeInterval', activeInterval))
       ..add(DiagnosticsProperty('serverTime', serverTime))
       ..add(DiagnosticsProperty('vipRemainNotice', vipRemainNotice))
       ..add(DiagnosticsProperty('upgradeNoticeTime', upgradeNoticeTime))
@@ -1185,8 +1185,8 @@ class _$AppConfigImpl with DiagnosticableTreeMixin implements _AppConfig {
                 other.enableAd == enableAd) &&
             (identical(other.adTimeoutDuration, adTimeoutDuration) ||
                 other.adTimeoutDuration == adTimeoutDuration) &&
-            (identical(other.reportActiveInterval, reportActiveInterval) ||
-                other.reportActiveInterval == reportActiveInterval) &&
+            (identical(other.activeInterval, activeInterval) ||
+                other.activeInterval == activeInterval) &&
             (identical(other.serverTime, serverTime) ||
                 other.serverTime == serverTime) &&
             (identical(other.vipRemainNotice, vipRemainNotice) ||
@@ -1240,7 +1240,7 @@ class _$AppConfigImpl with DiagnosticableTreeMixin implements _AppConfig {
     peekTimeInterval,
     enableAd,
     adTimeoutDuration,
-    reportActiveInterval,
+    activeInterval,
     serverTime,
     vipRemainNotice,
     upgradeNoticeTime,
@@ -1301,7 +1301,7 @@ abstract class _AppConfig implements AppConfig {
     final int? peekTimeInterval,
     final bool? enableAd,
     final int? adTimeoutDuration,
-    final int? reportActiveInterval,
+    final int? activeInterval,
     final int? serverTime,
     final int? vipRemainNotice,
     final int? upgradeNoticeTime,
@@ -1387,7 +1387,7 @@ abstract class _AppConfig implements AppConfig {
   @override
   int? get adTimeoutDuration;
   @override
-  int? get reportActiveInterval;
+  int? get activeInterval;
   @override
   int? get serverTime;
   @override

+ 2 - 2
lib/app/data/models/launch/app_config.g.dart

@@ -88,7 +88,7 @@ _$AppConfigImpl _$$AppConfigImplFromJson(
   peekTimeInterval: (json['peekTimeInterval'] as num?)?.toInt(),
   enableAd: json['enableAd'] as bool?,
   adTimeoutDuration: (json['adTimeoutDuration'] as num?)?.toInt(),
-  reportActiveInterval: (json['reportActiveInterval'] as num?)?.toInt(),
+  activeInterval: (json['activeInterval'] as num?)?.toInt(),
   serverTime: (json['serverTime'] as num?)?.toInt(),
   vipRemainNotice: (json['vipRemainNotice'] as num?)?.toInt(),
   upgradeNoticeTime: (json['upgradeNoticeTime'] as num?)?.toInt(),
@@ -137,7 +137,7 @@ Map<String, dynamic> _$$AppConfigImplToJson(_$AppConfigImpl instance) =>
       'peekTimeInterval': instance.peekTimeInterval,
       'enableAd': instance.enableAd,
       'adTimeoutDuration': instance.adTimeoutDuration,
-      'reportActiveInterval': instance.reportActiveInterval,
+      'activeInterval': instance.activeInterval,
       'serverTime': instance.serverTime,
       'vipRemainNotice': instance.vipRemainNotice,
       'upgradeNoticeTime': instance.upgradeNoticeTime,

+ 44 - 76
lib/app/modules/home/widgets/connection_theme_button.dart

@@ -13,41 +13,24 @@ import '../../../constants/enums.dart';
 /// 连接中状态的流光边框画笔
 class ConnectingBorderPainter extends CustomPainter {
   final double rotationAngle;
-  final Color primaryColor;
-  final Color secondaryColor;
+  final List<Color> colors;
 
-  ConnectingBorderPainter({
-    required this.rotationAngle,
-    required this.primaryColor,
-    required this.secondaryColor,
-  });
+  ConnectingBorderPainter({required this.rotationAngle, required this.colors});
 
   @override
   void paint(Canvas canvas, Size size) {
     final center = Offset(size.width / 2, size.height / 2);
-    final radius = size.width / 2 - 2;
-    const strokeWidth = 4.0;
+    final radius = size.width / 2 - 1;
+    const strokeWidth = 2.0;
 
     final rect = Rect.fromCircle(center: center, radius: radius);
 
-    // 连接中状态:绘制平滑的流光尾巴效果
+    // 连接中状态:绘制三色渐变流光效果
     final gradient = SweepGradient(
       startAngle: 0,
       endAngle: 2 * math.pi,
-      colors: [
-        primaryColor.withValues(alpha: 0.0),
-        primaryColor.withValues(alpha: 0.05),
-        primaryColor.withValues(alpha: 0.2),
-        primaryColor.withValues(alpha: 0.5),
-        primaryColor.withValues(alpha: 0.8),
-        primaryColor,
-        secondaryColor,
-        secondaryColor.withValues(alpha: 0.8),
-        secondaryColor.withValues(alpha: 0.4),
-        secondaryColor.withValues(alpha: 0.1),
-        primaryColor.withValues(alpha: 0.0),
-      ],
-      stops: const [0.0, 0.1, 0.2, 0.35, 0.45, 0.5, 0.55, 0.65, 0.8, 0.9, 1.0],
+      colors: colors,
+      stops: const [0.2, 0.6, 1.0],
       transform: GradientRotation(rotationAngle - math.pi / 2),
     );
 
@@ -64,8 +47,7 @@ class ConnectingBorderPainter extends CustomPainter {
   @override
   bool shouldRepaint(covariant ConnectingBorderPainter oldDelegate) {
     return oldDelegate.rotationAngle != rotationAngle ||
-        oldDelegate.primaryColor != primaryColor ||
-        oldDelegate.secondaryColor != secondaryColor;
+        oldDelegate.colors != colors;
   }
 }
 
@@ -86,20 +68,19 @@ class _ConnectionThemeButtonState extends State<ConnectionThemeButton>
   Timer? _connectingTimer; // 连接中状态的计时器
   int _connectingTextIndex = 0; // 当前显示的连接文本索引(0-4)
   ConnectionState? _previousState; // 保存前一个连接状态
-  bool _isStoppingRotation = false; // 是否正在停止旋转
 
   @override
   void initState() {
     super.initState();
     // 初始化旋转动画控制器
     _rotationController = AnimationController(
-      duration: const Duration(milliseconds: 500),
+      duration: const Duration(milliseconds: 350),
       vsync: this,
     );
 
     // 初始化淡入淡出控制器
     _fadeController = AnimationController(
-      duration: const Duration(milliseconds: 600),
+      duration: const Duration(milliseconds: 450),
       vsync: this,
       value: 1.0,
     );
@@ -129,9 +110,7 @@ class _ConnectionThemeButtonState extends State<ConnectionThemeButton>
     if (widget.state == ConnectionState.connectingVirtual ||
         widget.state == ConnectionState.connecting ||
         widget.state == ConnectionState.disconnecting) {
-      // 进入旋转状态时,确保立即开始旋转
-      _isStoppingRotation = false;
-      // 先停止任何正在进行的动画,然后立即重新开始
+      // 进入旋转状态时,立即开始旋转
       _rotationController.stop();
       _rotationController.repeat();
 
@@ -144,32 +123,19 @@ class _ConnectionThemeButtonState extends State<ConnectionThemeButton>
         _stopConnectingTimer();
       }
     } else {
-      // 从连接中/断开中切换到其他状态时,平滑停止旋转
-      if (_rotationController.isAnimating && !_isStoppingRotation) {
-        _isStoppingRotation = true;
-        // 计算剩余角度,让动画平滑停止在顶部(0度位置)
-        final currentValue = _rotationController.value;
-        // 停止重复,然后平滑减速到完整的一圈
-        _rotationController.stop();
-        _rotationController
-            .animateTo(
-              1.0,
-              duration: Duration(
-                milliseconds: ((1.0 - currentValue) * 400).toInt().clamp(
-                  100,
-                  400,
-                ),
-              ),
-              curve: Curves.easeOutCubic,
-            )
-            .then((_) {
-              if (mounted) {
-                _rotationController.reset();
-                _isStoppingRotation = false;
-              }
-            });
-      }
+      // 从连接中/断开中切换到其他状态时
+      // 延迟停止旋转动画,让流光在 AnimatedSwitcher 淡出过程中继续旋转
+      // 避免看到停止的线
       _stopConnectingTimer();
+      Future.delayed(const Duration(milliseconds: 650), () {
+        if (mounted &&
+            widget.state != ConnectionState.connectingVirtual &&
+            widget.state != ConnectionState.connecting &&
+            widget.state != ConnectionState.disconnecting) {
+          _rotationController.stop();
+          _rotationController.reset();
+        }
+      });
     }
   }
 
@@ -226,13 +192,19 @@ class _ConnectionThemeButtonState extends State<ConnectionThemeButton>
     }
   }
 
-  // 连接中状态的流光边框颜色
-  static const Color _connectingPrimaryColor = Color(0xFF4FC3F7); // 浅蓝色
-  static const Color _connectingSecondaryColor = Color(0xFF7E57C2); // 紫色
+  // 连接中状态的流光边框颜色(紫色 → 蓝色 → 浅蓝色)
+  static const List<Color> _connectingColors = [
+    Color(0xFFAC27FF), // 紫色
+    Color(0xFF0EA5E9), // 蓝色
+    Color(0xFF2ECBFF), // 浅蓝色
+  ];
 
-  // 断开中状态的流光边框颜色
-  static const Color _disconnectingPrimaryColor = Color(0xFFFF7043); // 橙色
-  static const Color _disconnectingSecondaryColor = Color(0xFFFFCA28); // 黄色
+  // 断开中状态的流光边框颜色(浅黄色 → 橙色 → 红色)
+  static const List<Color> _disconnectingColors = [
+    Color(0xFFF5D89F), // 浅黄色
+    Color(0xFFF19021), // 橙色
+    Color(0xFFEF0000), // 红色
+  ];
 
   // 连接成功状态的渐变色
   static const Color _connectedGradientStart = Color(0xFF0EA5E9);
@@ -252,8 +224,7 @@ class _ConnectionThemeButtonState extends State<ConnectionThemeButton>
   Widget _buildAnimatingBackground({
     required double size,
     required ValueKey key,
-    required Color primaryColor,
-    required Color secondaryColor,
+    required List<Color> colors,
   }) {
     return Container(
       key: key,
@@ -274,16 +245,15 @@ class _ConnectionThemeButtonState extends State<ConnectionThemeButton>
                 size: Size(size, size),
                 painter: ConnectingBorderPainter(
                   rotationAngle: _rotationController.value * 2 * math.pi,
-                  primaryColor: primaryColor,
-                  secondaryColor: secondaryColor,
+                  colors: colors,
                 ),
               );
             },
           ),
           // 内层背景圆(遮住边框内侧)
           Container(
-            width: size - 8.w,
-            height: size - 8.w,
+            width: size - 4.w,
+            height: size - 4.w,
             decoration: BoxDecoration(
               color: Get.reactiveTheme.highlightColor,
               shape: BoxShape.circle,
@@ -311,7 +281,7 @@ class _ConnectionThemeButtonState extends State<ConnectionThemeButton>
             shape: BoxShape.circle,
             border: Border.all(
               color: Get.reactiveTheme.dividerColor,
-              width: 4.w,
+              width: 2.w,
             ),
             boxShadow: [
               BoxShadow(
@@ -326,21 +296,19 @@ class _ConnectionThemeButtonState extends State<ConnectionThemeButton>
 
       case ConnectionState.connectingVirtual:
       case ConnectionState.connecting:
-        // 连接中状态:highlightColor 背景 + 蓝紫色流光边框
+        // 连接中状态:highlightColor 背景 + 紫蓝渐变流光边框
         return _buildAnimatingBackground(
           size: size,
           key: const ValueKey('bg_connecting'),
-          primaryColor: _connectingPrimaryColor,
-          secondaryColor: _connectingSecondaryColor,
+          colors: _connectingColors,
         );
 
       case ConnectionState.disconnecting:
-        // 断开中状态:highlightColor 背景 + 橙黄色流光边框
+        // 断开中状态:highlightColor 背景 + 黄橙红渐变流光边框
         return _buildAnimatingBackground(
           size: size,
           key: const ValueKey('bg_disconnecting'),
-          primaryColor: _disconnectingPrimaryColor,
-          secondaryColor: _disconnectingSecondaryColor,
+          colors: _disconnectingColors,
         );
 
       case ConnectionState.connected:

+ 0 - 1
lib/app/modules/home/widgets/menu_list.dart

@@ -4,7 +4,6 @@ import 'package:get/get.dart';
 import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
 
 import '../../../data/models/banner/banner_list.dart';
-import '../../../data/sp/ix_sp.dart';
 import '../../../widgets/ix_image.dart';
 import '../controllers/home_controller.dart';
 

+ 29 - 19
lib/app/modules/node/views/node_view.dart

@@ -26,7 +26,6 @@ class NodeView extends BaseView<NodeController> {
       child: Column(
         children: [
           _buildTabs(),
-          Divider(color: Get.reactiveTheme.dividerColor, height: 0.5),
           Expanded(child: _buildTabBarView()),
         ],
       ),
@@ -39,13 +38,13 @@ class NodeView extends BaseView<NodeController> {
       overlayColor: WidgetStateProperty.all(Colors.transparent),
       isScrollable: true,
       tabAlignment: TabAlignment.start,
-      dividerColor: Colors.transparent,
-      indicatorSize: TabBarIndicatorSize.tab,
-      indicatorColor: Get.reactiveTheme.primaryColor,
-      indicator: BoxDecoration(
-        color: Get.reactiveTheme.primaryColor,
-        borderRadius: BorderRadius.circular(8.r),
-      ),
+      dividerColor: Get.reactiveTheme.dividerColor,
+      indicatorSize: TabBarIndicatorSize.label,
+      indicatorColor: Colors.transparent,
+      // indicator: BoxDecoration(
+      //   color: Get.reactiveTheme.primaryColor,
+      //   borderRadius: BorderRadius.circular(8.r),
+      // ),
       // indicatorWeight: 2,
       labelColor: Colors.white,
       unselectedLabelColor: Get.reactiveTheme.hintColor,
@@ -59,22 +58,32 @@ class NodeView extends BaseView<NodeController> {
         fontWeight: FontWeight.w400,
         fontFamily: 'FiraSans',
       ),
-      padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.w),
-      labelPadding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.w),
+      padding: EdgeInsets.symmetric(horizontal: 7.w, vertical: 10.w),
+      labelPadding: EdgeInsets.symmetric(horizontal: 7.w, vertical: 0.w),
       // 监听 Tab 切换,保存当前索引
       onTap: (index) {
         controller.setTabSelected(index);
       },
       tabs: controller.tabTextList.map((e) {
-        return Row(
-          children: [
-            Icon(
-              controller.getTabIcon(controller.tabTextList.indexOf(e)),
-              size: 14.w,
-            ),
-            4.horizontalSpace,
-            Text(e),
-          ],
+        return Container(
+          padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.w),
+          decoration: BoxDecoration(
+            color:
+                controller.currentTabIndex == controller.tabTextList.indexOf(e)
+                ? Get.reactiveTheme.primaryColor
+                : Get.reactiveTheme.cardColor,
+            borderRadius: BorderRadius.circular(8.r),
+          ),
+          child: Row(
+            children: [
+              Icon(
+                controller.getTabIcon(controller.tabTextList.indexOf(e)),
+                size: 14.w,
+              ),
+              4.horizontalSpace,
+              Text(e),
+            ],
+          ),
         );
       }).toList(),
     );
@@ -82,6 +91,7 @@ class NodeView extends BaseView<NodeController> {
 
   Widget _buildTabBarView() {
     return TabBarView(
+      physics: const NeverScrollableScrollPhysics(), // 禁用左右滑动
       children: List.generate(
         controller.tabTextList.length,
         (index) => NodeList(tabIndex: index),

+ 6 - 1
lib/utils/api_statistics.dart

@@ -526,13 +526,18 @@ class ApiStatistics {
       final isRouterDisabled = _disabledModules.contains(
         LogModule.NM_ApiRouterLog.name,
       );
+      final isOtherDisabled = _disabledModules.contains(
+        LogModule.NM_ApiOtherLog.name,
+      );
 
       // 过滤掉禁用模块的记录
       final enabledRecords = records.where((record) {
         if (record.path == ApiCorePaths.launch) {
           return !isLaunchDisabled;
-        } else {
+        } else if (record.path == ApiCorePaths.getDispatchInfo) {
           return !isRouterDisabled;
+        } else {
+          return !isOtherDisabled;
         }
       }).toList();