@ -24,6 +24,7 @@ import '../../../utils/kr_update_util.dart';
import ' ../../../widgets/dialogs/kr_dialog.dart ' ;
import ' package:kaer_with_panels/app/widgets/dialogs/hi_dialog.dart ' ;
import ' package:kaer_with_panels/app/widgets/kr_app_text_style.dart ' ;
import ' package:kaer_with_panels/app/routes/app_pages.dart ' ;
import ' ../models/kr_home_views_status.dart ' ;
@ -225,13 +226,16 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
await _kr_prepareCountrySelectionBeforeStart ( ) ;
final selectedAfter =
await KRSecureStorage ( ) . kr_readData ( key: ' SELECTED_NODE_TAG ' ) ;
KRLogUtil . kr_i ( ' 准备后 SELECTED_NODE_TAG_autoConnect: ${ selectedAfter ? ? ' ' } ' ,
KRLogUtil . kr_i (
' 准备后 SELECTED_NODE_TAG_autoConnect: ${ selectedAfter ? ? ' ' } ' ,
tag: ' HomeController ' ) ;
KRLogUtil . kr_i ( ' 准备后 kr_currentNodeName_autoConnect: ${ kr_currentNodeName . value } ' ,
KRLogUtil . kr_i (
' 准备后 kr_currentNodeName_autoConnect: ${ kr_currentNodeName . value } ' ,
tag: ' HomeController ' ) ;
KRLogUtil . kr_i ( ' 准备后 kr_cutTag_autoConnect: ${ kr_cutTag . value } ' ,
tag: ' HomeController ' ) ;
KRLogUtil . kr_i ( ' 准备后 kr_cutSeletedTag_autoConnect: ${ kr_cutSeletedTag . value } ' ,
KRLogUtil . kr_i (
' 准备后 kr_cutSeletedTag_autoConnect: ${ kr_cutSeletedTag . value } ' ,
tag: ' HomeController ' ) ;
await kr_performNodeSwitch ( selectedAfter ! ) ;
await KRSingBoxImp . instance . kr_start ( ) ;
@ -266,7 +270,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
@ override
void onInit ( ) async {
super . onInit ( ) ;
/ / 🔧 紧 急 诊 断 : 直 接 写 文 件 验 证 onInit 是 否 被 调 用
try {
final dir = await getApplicationDocumentsDirectory ( ) ;
@ -317,8 +320,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
/ / 延 迟 同 步 连 接 状 态 , 确 保 状 态 正 确
Future . delayed ( const Duration ( milliseconds: 500 ) , ( ) {
kr_forceSyncConnectionStatus ( ) ;
_checkQuickConnectAutoStart ( ) ;
kr_forceSyncConnectionStatus ( true ) ;
} ) ;
/ / 🔧 Android 15 新 增 : 5 秒 后 再 次 强 制 更 新 高 度 , 兜 底 保 护
@ -680,6 +682,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
} else {
/ / kr_updateBottomPanelHeight ( ) ;
}
_kr_testLatencyWithoutVpn ( ) ;
break ;
case KRSubscribeServiceStatus . kr_none:
KRLogUtil . kr_i ( ' 订阅服务未初始化 ' , tag: ' HomeController ' ) ;
@ -888,20 +891,21 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
tag: ' HomeController ' ) ;
if ( kDebugMode ) { }
/ / 🔧 保 守 修 复 : 检 测 状 态 是 否 卡 住 ( 超 过 10 秒 )
/ / 🔧 保 守 修 复 : 检 测 状 态 是 否 卡 住 ( 超 过 5 秒 )
if ( currentStatus is SingboxStarting | | currentStatus is SingboxStopping ) {
final now = DateTime . now ( ) ;
if ( _lastStatusChangeTime ! = null & &
now . difference ( _lastStatusChangeTime ! ) > const Duration ( seconds: 10 ) ) {
now . difference ( _lastStatusChangeTime ! ) > const Duration ( seconds: 5 ) ) {
/ / 状 态 卡 住 , 强 制 重 置
KRLogUtil . kr_w ( ' ⚠️ 检测到状态卡住超过10秒 (当前: $ currentStatus ),执行强制重置 ' , tag: ' HomeController ' ) ;
KRLogUtil . kr_w ( ' ⚠️ 检测到状态卡住超过10秒 (当前: $ currentStatus ),执行强制重置 ' ,
tag: ' HomeController ' ) ;
await _forceResetState ( ) ;
/ / 重 置 后 重 新 尝 试 操 作
KRLogUtil . kr_i ( ' 🔄 状态已重置,继续执行切换操作 ' , tag: ' HomeController ' ) ;
} else {
KRLogUtil . kr_i ( ' 🔄 正在切换中,忽略本次操作 (当前状态: $ currentStatus ) ' , tag: ' HomeController ' ) ;
if ( kDebugMode ) {
}
KRLogUtil . kr_i ( ' 🔄 正在切换中,忽略本次操作 (当前状态: $ currentStatus ) ' ,
tag: ' HomeController ' ) ;
if ( kDebugMode ) { }
return ;
}
}
@ -917,21 +921,22 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
await _kr_prepareCountrySelectionBeforeStart ( ) ;
final selectedAfter =
await KRSecureStorage ( ) . kr_readData ( key: ' SELECTED_NODE_TAG ' ) ;
KRLogUtil . kr_i ( ' 准备后 SELECTED_NODE_TAG: ${ selectedAfter ? ? ' ' } ' ,
tag: ' HomeController ' ) ;
KRLogUtil . kr_i ( ' 准备后 kr_currentNodeName: ${ kr_currentNodeName . value } ' ,
tag: ' HomeController ' ) ;
KRLogUtil . kr_i ( ' 准备后 kr_cutTag: ${ kr_cutTag . value } ' ,
tag: ' HomeController ' ) ;
KRLogUtil . kr_i ( ' 准备后 kr_cutSeletedTag: ${ kr_cutSeletedTag . value } ' ,
tag: ' HomeController ' ) ;
/ / KRLogUtil . kr_i ( ' 准备后 SELECTED_NODE_TAG: ${ selectedAfter ? ? ' ' } ' ,
/ / tag: ' HomeController ' ) ;
/ / KRLogUtil . kr_i ( ' 准备后 kr_currentNodeName: ${ kr_currentNodeName . value } ' ,
/ / tag: ' HomeController ' ) ;
/ / KRLogUtil . kr_i ( ' 准备后 kr_cutTag: ${ kr_cutTag . value } ' ,
/ / tag: ' HomeController ' ) ;
/ / KRLogUtil . kr_i ( ' 准备后 kr_cutSeletedTag: ${ kr_cutSeletedTag . value } ' ,
/ / tag: ' HomeController ' ) ;
await kr_performNodeSwitch ( selectedAfter ! ) ;
await KRSingBoxImp . instance . kr_start ( ) ;
KRLogUtil . kr_i ( ' ✅ 连接命令已发送 ' , tag: ' HomeController ' ) ;
if ( kDebugMode ) { }
/ / 🔧 修 复 : 等 待 状 态 更 新 , 最 多 3 秒
await _waitForStatus ( SingboxStarted , maxSeconds: 3 ) ;
await _waitForStatus ( SingboxStatus . started ( ) . runtimeType ,
maxSeconds: 3 ) ;
} else {
/ / 关 闭 连 接
KRLogUtil . kr_i ( ' 🛑 开始断开连接... ' , tag: ' HomeController ' ) ;
@ -946,8 +951,16 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
KRLogUtil . kr_i ( ' ✅ 断开命令已发送 ' , tag: ' HomeController ' ) ;
if ( kDebugMode ) { }
/ / 🔧 修 复 : 等 待 状 态 更 新 , 最 多 2 秒
await _waitForStatus ( SingboxStopped , maxSeconds: 2 ) ;
/ / 🔧 保 守 修 复 : 等 待 状 态 更 新 , 增 加 超 时 处 理
final success = await _waitForStatus (
SingboxStatus . stopped ( ) . runtimeType ,
maxSeconds: 3 ,
) ;
if ( ! success ) {
/ / 停 止 超 时 , 强 制 同 步 状 态
KRLogUtil . kr_w ( ' ⚠️ VPN 停止超时( 3秒) , 强制同步状态 ' , tag: ' HomeController ' ) ;
kr_forceSyncConnectionStatus ( ) ;
}
}
} catch ( e ) {
KRLogUtil . kr_e ( ' ❌ 切换失败: $ e ' , tag: ' HomeController ' ) ;
@ -962,18 +975,15 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
/ / / 🔧 等 待 状 态 达 到 预 期 值
/ / / 🔧 保 守 修 复 : 返 回 bool 表 示 是 否 成 功 达 到 预 期 状 态
Future < bool > _waitForStatus ( Type expectedType , { int maxSeconds = 3 } ) async {
if ( kDebugMode ) {
}
if ( kDebugMode ) { }
final startTime = DateTime . now ( ) ;
while ( DateTime . now ( ) . difference ( startTime ) . inSeconds < maxSeconds ) {
final currentStatus = KRSingBoxImp . instance . kr_status . value ;
if ( kDebugMode ) {
}
if ( kDebugMode ) { }
if ( currentStatus . runtimeType = = expectedType ) {
if ( kDebugMode ) {
}
if ( kDebugMode ) { }
/ / 强 制 同 步 确 保 kr_isConnected 正 确
kr_forceSyncConnectionStatus ( ) ;
/ / 🔧 更 新 状 态 变 化 时 间
@ -990,47 +1000,38 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
' ⏱️ 等待状态超时: 期望= ${ expectedType . toString ( ) } , 实际= ${ finalStatus . runtimeType } , 耗时= ${ maxSeconds } 秒 ' ,
tag: ' HomeController ' ,
) ;
if ( kDebugMode ) {
}
if ( kDebugMode ) { }
kr_forceSyncConnectionStatus ( ) ;
return false ; / / 超 时 失 败
}
Future < void > _kr_prepareCountrySelectionBeforeStart ( ) async {
try {
KRLogUtil . kr_i ( ' 开始准备国家选择 ' , tag: ' CountrySelect ' ) ;
/ / KRLogUtil . kr_i ( ' 开始准备国家选择 ' , tag: ' CountrySelect ' ) ;
final storedCountry = kr_selectedCountryTag . value ;
KRLogUtil . kr_i ( ' 使用响应式 SELECTED_COUNTRY_TAG: $ storedCountry ' ,
tag: ' CountrySelect ' ) ;
/ / KRLogUtil . kr_i ( ' 使用响应式 SELECTED_COUNTRY_TAG: $ storedCountry ' ,
/ / tag: ' CountrySelect ' ) ;
if ( storedCountry = = ' auto ' ) {
KRLogUtil . kr_w ( ' 当前为 auto, 按全局最优节点进行选择 ' , tag: ' CountrySelect ' ) ;
final best = _kr_selectBestNodeTagGlobal ( ) ;
if ( best ! = null & & best . isNotEmpty ) {
KRLogUtil . kr_i ( ' 选中全局最优节点: $ best ' , tag: ' CountrySelect ' ) ;
/ / KRLogUtil . kr_i ( ' 选中全局最优节点: $ best ' , tag: ' CountrySelect ' ) ;
await KRSecureStorage ( )
. kr_saveData ( key: ' SELECTED_NODE_TAG ' , value: best ) ;
final verify =
await KRSecureStorage ( ) . kr_readData ( key: ' SELECTED_NODE_TAG ' ) ;
KRLogUtil . kr_i ( ' 写入后校验 SELECTED_NODE_TAG: $ verify ' ,
tag: ' CountrySelect ' ) ;
kr_currentNodeName . value = best ;
kr_cutTag . value = best ;
kr_cutSeletedTag . value = best ;
kr_updateConnectionInfo ( ) ;
return ;
}
KRLogUtil . kr_w ( ' 未找到可用的全局最优节点 ' , tag: ' CountrySelect ' ) ;
KRLogUtil . kr_i ( ' 触发直接延迟测试以获取有效延迟 ' , tag: ' CountrySelect ' ) ;
/ / KRLogUtil . kr_w ( ' 未找到可用的全局最优节点 ' , tag: ' CountrySelect ' ) ;
/ / KRLogUtil . kr_i ( ' 触发直接延迟测试以获取有效延迟 ' , tag: ' CountrySelect ' ) ;
await _kr_testLatencyWithoutVpn ( ) ;
final bestAfterTest = _kr_selectBestNodeTagGlobal ( ) ;
if ( bestAfterTest ! = null & & bestAfterTest . isNotEmpty ) {
KRLogUtil . kr_i ( ' 延迟测试后选中全局最优节点: $ bestAfterTest ' , tag: ' CountrySelect ' ) ;
/ / KRLogUtil . kr_i ( ' 延迟测试后选中全局最优节点: $ bestAfterTest ' , tag: ' CountrySelect ' ) ;
await KRSecureStorage ( )
. kr_saveData ( key: ' SELECTED_NODE_TAG ' , value: bestAfterTest ) ;
final verifyA =
await KRSecureStorage ( ) . kr_readData ( key: ' SELECTED_NODE_TAG ' ) ;
KRLogUtil . kr_i ( ' 写入后校验 SELECTED_NODE_TAG: $ verifyA ' ,
tag: ' CountrySelect ' ) ;
kr_currentNodeName . value = bestAfterTest ;
kr_cutTag . value = bestAfterTest ;
kr_cutSeletedTag . value = bestAfterTest ;
@ -1183,7 +1184,9 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
/ / / 处 理 手 动 模 式
void _kr_handleManualMode ( dynamic element ) {
try {
KRLogUtil . kr_d ( ' 处理手动模式 - 内核选择: ${ element . selected } , 用户选择: ${ kr_cutTag . value } ' , tag: ' HomeController ' ) ;
KRLogUtil . kr_d (
' 处理手动模式 - 内核选择: ${ element . selected } , 用户选择: ${ kr_cutTag . value } ' ,
tag: ' HomeController ' ) ;
/ / 🔧 关 键 修 复 : 不 要 用 内 核 返 回 的 selected 覆 盖 用 户 手 动 选 择
/ / 只 有 当 内 核 返 回 的 节 点 与 用 户 选 择 一 致 时 , 才 更 新 相 关 状 态
@ -1195,12 +1198,15 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
/ / 只 有 当 内 核 确 认 切 换 成 功 时 , 才 更 新 UI 状 态
if ( element . selected = = kr_cutTag . value ) {
kr_cutSeletedTag . value = element . selected ;
kr_currentNodeName . value = kr_truncateText ( element . selected , maxLength: 25 ) ;
kr_currentNodeName . value =
kr_truncateText ( element . selected , maxLength: 25 ) ;
/ / kr_moveToSelectedNode ( ) ;
KRLogUtil . kr_d ( ' ✅ 内核确认节点切换成功: ${ element . selected } ' , tag: ' HomeController ' ) ;
KRLogUtil . kr_d ( ' ✅ 内核确认节点切换成功: ${ element . selected } ' ,
tag: ' HomeController ' ) ;
} else {
/ / 内 核 返 回 的 节 点 与 用 户 选 择 不 一 致 , 保 持 用 户 选 择 的 显 示
KRLogUtil . kr_d ( ' ⏳ 等待内核切换到用户选择的节点: ${ kr_cutTag . value } ' , tag: ' HomeController ' ) ;
KRLogUtil . kr_d ( ' ⏳ 等待内核切换到用户选择的节点: ${ kr_cutTag . value } ' ,
tag: ' HomeController ' ) ;
}
} catch ( e ) {
KRLogUtil . kr_e ( ' 处理手动模式出错: $ e ' , tag: ' HomeController ' ) ;
@ -1397,11 +1403,18 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
return false ;
}
if ( kr_cutTag . value = = tag ) {
return false ;
}
/ / 🔒 节 流 控 制 : 2 秒 内 的 重 复 切 换 请 求 直 接 忽 略
final now = DateTime . now ( ) ;
if ( _lastSwitchTime ! = null & & now . difference ( _lastSwitchTime ! ) < _switchThrottleDuration ) {
final remainingTime = _switchThrottleDuration . inMilliseconds - now . difference ( _lastSwitchTime ! ) . inMilliseconds ;
KRLogUtil . kr_w ( ' ⚠️ 切换过于频繁,请等待 ${ remainingTime } ms ' , tag: ' HomeController ' ) ;
if ( _lastSwitchTime ! = null & &
now . difference ( _lastSwitchTime ! ) < _switchThrottleDuration ) {
final remainingTime = _switchThrottleDuration . inMilliseconds -
now . difference ( _lastSwitchTime ! ) . inMilliseconds ;
KRLogUtil . kr_w ( ' ⚠️ 切换过于频繁,请等待 ${ remainingTime } ms ' ,
tag: ' HomeController ' ) ;
KRCommonUtil . kr_showToast ( ' 切换过于频繁,请稍后再试 ' ) ;
return false ;
}
@ -1428,7 +1441,9 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
/ / 🔧 修 复 : 保 存 节 点 选 择 以 便 VPN启动时应用
KRLogUtil . kr_i ( ' 💾 保存节点选择以便稍后应用: $ tag ' , tag: ' HomeController ' ) ;
KRSecureStorage ( ) . kr_saveData ( key: ' SELECTED_NODE_TAG ' , value: tag ) . then ( ( _ ) {
KRSecureStorage ( )
. kr_saveData ( key: ' SELECTED_NODE_TAG ' , value: tag )
. then ( ( _ ) {
KRLogUtil . kr_i ( ' ✅ 节点选择已保存: $ tag ' , tag: ' HomeController ' ) ;
} ) . catchError ( ( e ) {
KRLogUtil . kr_e ( ' ❌ 保存节点选择失败: $ e ' , tag: ' HomeController ' ) ;
@ -1447,11 +1462,13 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
/ / 🔧 保 存 新 节 点 选 择
KRLogUtil . kr_i ( ' 💾 保存新节点选择: $ tag ' , tag: ' HomeController ' ) ;
await KRSecureStorage ( ) . kr_saveData ( key: ' SELECTED_NODE_TAG ' , value: tag ) ;
await KRSecureStorage ( )
. kr_saveData ( key: ' SELECTED_NODE_TAG ' , value: tag ) ;
/ / 🚀 核 心 改 进 : 使 用 selectOutbound 进 行 热 切 换 ( 参 考 hiddify - app )
/ / 优 势 : 不 重 启 VPN , 保 持 连 接 状 态 , 切 换 瞬 间 完 成 , VPN开关不闪烁
KRLogUtil . kr_i ( ' 🔄 [热切换] 调用 selectOutbound 切换节点... ' , tag: ' HomeController ' ) ;
KRLogUtil . kr_i ( ' 🔄 [热切换] 调用 selectOutbound 切换节点... ' ,
tag: ' HomeController ' ) ;
/ / 🔧 关 键 修 复 : 确 定 正 确 的 selector 组 tag
/ / selectOutbound ( groupTag , outboundTag ) - 第 一 个 参 数 是 组 的 tag , 不 是 节 点 的 tag
@ -1462,12 +1479,14 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
for ( var group in activeGroups ) {
if ( group . type = = ProxyType . selector ) {
selectorGroupTag = group . tag ;
KRLogUtil . kr_i ( ' 🔍 找到 selector 组: $ selectorGroupTag ' , tag: ' HomeController ' ) ;
KRLogUtil . kr_i ( ' 🔍 找到 selector 组: $ selectorGroupTag ' ,
tag: ' HomeController ' ) ;
break ;
}
}
KRLogUtil . kr_i ( ' 📡 调用 selectOutbound(" $ selectorGroupTag ", " $ tag ") ' , tag: ' HomeController ' ) ;
KRLogUtil . kr_i ( ' 📡 调用 selectOutbound(" $ selectorGroupTag ", " $ tag ") ' ,
tag: ' HomeController ' ) ;
/ / 调 用 sing - box 的 selectOutbound API
final result = await KRSingBoxImp . instance . kr_singBox
@ -1478,7 +1497,8 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
result . fold (
( error ) {
/ / 切 换 失 败
KRLogUtil . kr_e ( ' ❌ selectOutbound 调用失败: $ error ' , tag: ' HomeController ' ) ;
KRLogUtil . kr_e ( ' ❌ selectOutbound 调用失败: $ error ' ,
tag: ' HomeController ' ) ;
throw Exception ( ' 节点切换失败: $ error ' ) ;
} ,
( _ ) {
@ -1505,11 +1525,14 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
orElse: ( ) = > throw Exception ( ' 未找到 selector 组 ' ) ,
) ;
KRLogUtil . kr_i ( ' 📊 [验证] ${ selectGroup . tag } 组当前选中: ${ selectGroup . selected } ' , tag: ' HomeController ' ) ;
KRLogUtil . kr_i (
' 📊 [验证] ${ selectGroup . tag } 组当前选中: ${ selectGroup . selected } ' ,
tag: ' HomeController ' ) ;
KRLogUtil . kr_i ( ' 📊 [验证] 目标节点: $ tag ' , tag: ' HomeController ' ) ;
if ( selectGroup . selected ! = tag ) {
KRLogUtil . kr_w ( ' ⚠️ [验证] 节点选择验证失败,实际选中: ${ selectGroup . selected } ' , tag: ' HomeController ' ) ;
KRLogUtil . kr_w ( ' ⚠️ [验证] 节点选择验证失败,实际选中: ${ selectGroup . selected } ' ,
tag: ' HomeController ' ) ;
/ / 不 抛 出 异 常 , 但 记 录 警 告
} else {
KRLogUtil . kr_i ( ' ✅ [验证] 节点选择验证成功! ' , tag: ' HomeController ' ) ;
@ -1523,7 +1546,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
KRLogUtil . kr_i ( ' ✅ 节点热切换成功, VPN保持连接: $ tag ' , tag: ' HomeController ' ) ;
return true ;
} catch ( switchError ) {
/ / 后 台 切 换 失 败 , 恢 复 到 原 节 点
KRLogUtil . kr_e ( ' ❌ 后台节点切换失败: $ switchError ' , tag: ' HomeController ' ) ;
@ -1535,7 +1557,8 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
/ / 恢 复 原 节 点 选 择
try {
await KRSecureStorage ( ) . kr_saveData ( key: ' SELECTED_NODE_TAG ' , value: originalTag ) ;
await KRSecureStorage ( )
. kr_saveData ( key: ' SELECTED_NODE_TAG ' , value: originalTag ) ;
} catch ( e ) {
KRLogUtil . kr_e ( ' ❌ 恢复节点选择失败: $ e ' , tag: ' HomeController ' ) ;
}
@ -1573,14 +1596,14 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
/ / / 2. 如 果 是 auto , 优 先 使 用 kr_cutSeletedTag ( 保 存 了 实 际 选 中 的 节 点 )
/ / / 3. 如 果 kr_cutSeletedTag 也 是 auto 或 空 , 再 尝 试 从 kr_activeGroups 获 取
String kr_getCurrentNodeCountry ( ) {
KRLogUtil . kr_i ( ' ========== 开始获取国家代码 ========== ' ,
tag: ' getCurrentNodeCountry ' ) ;
KRLogUtil . kr_i ( ' kr_cutTag: ${ kr_cutTag . value } ' ,
tag: ' getCurrentNodeCountry ' ) ;
KRLogUtil . kr_i ( ' kr_cutSeletedTag: ${ kr_cutSeletedTag . value } ' ,
tag: ' getCurrentNodeCountry ' ) ;
KRLogUtil . kr_i ( ' keyList 节点总数: ${ kr_subscribeService . keyList . length } ' ,
tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' ========== 开始获取国家代码 ========== ' ,
/ / tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' kr_cutTag: ${ kr_cutTag . value } ' ,
/ / tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' kr_cutSeletedTag: ${ kr_cutSeletedTag . value } ' ,
/ / tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' keyList 节点总数: ${ kr_subscribeService . keyList . length } ' ,
/ / tag: ' getCurrentNodeCountry ' ) ;
String actualTag ;
@ -1594,7 +1617,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
kr_cutTag . value . isNotEmpty ) {
/ / 用 户 手 动 选 择 了 具 体 节 点
actualTag = kr_cutTag . value ;
KRLogUtil . kr_i ( ' ✅ 使用手动选择的节点: $ actualTag ' , tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' ✅ 使用手动选择的节点: $ actualTag ' , tag: ' getCurrentNodeCountry ' ) ;
}
/ / 2. 如 果 是 auto , 优 先 使 用 kr_cutSeletedTag ( 保 存 了 实 际 选 中 的 节 点 )
else if ( kr_cutSeletedTag . value . isNotEmpty & &
@ -1602,15 +1625,15 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
kr_cutSeletedTag . value ! = ' select ' ) {
/ / auto 模 式 下 , 使 用 保 存 的 实 际 节 点
actualTag = kr_cutSeletedTag . value ;
KRLogUtil . kr_i ( ' ✅ 使用 auto 模式下的实际节点 (kr_cutSeletedTag): $ actualTag ' ,
tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' ✅ 使用 auto 模式下的实际节点 (kr_cutSeletedTag): $ actualTag ' ,
/ / tag: ' getCurrentNodeCountry ' ) ;
}
/ / 3. 降 级 : 尝 试 从 活 动 组 获 取
else {
try {
KRLogUtil . kr_i ( ' ⚠️ 尝试从活动组获取实际节点 ' , tag: ' getCurrentNodeCountry ' ) ;
KRLogUtil . kr_i ( ' 活动组数量: ${ KRSingBoxImp . instance . kr_activeGroups . length } ' ,
tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' ⚠️ 尝试从活动组获取实际节点 ' , tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' 活动组数量: ${ KRSingBoxImp . instance . kr_activeGroups . length } ' ,
/ / tag: ' getCurrentNodeCountry ' ) ;
/ / 🔧 修 复 : 活 动 组 为 空 时 , 尝 试 使 用 allGroups
if ( KRSingBoxImp . instance . kr_activeGroups . isEmpty ) {
@ -1717,16 +1740,16 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
return ' ' ;
}
KRLogUtil . kr_i ( ' ✅ 找到节点: $ actualTag ' , tag: ' getCurrentNodeCountry ' ) ;
KRLogUtil . kr_i ( ' - city: ${ node . city } ' , tag: ' getCurrentNodeCountry ' ) ;
KRLogUtil . kr_i ( ' - country: " ${ node . country } " ' ,
tag: ' getCurrentNodeCountry ' ) ;
KRLogUtil . kr_i ( ' - country.isEmpty: ${ node . country . isEmpty } ' ,
tag: ' getCurrentNodeCountry ' ) ;
KRLogUtil . kr_i ( ' - country.length: ${ node . country . length } ' ,
tag: ' getCurrentNodeCountry ' ) ;
KRLogUtil . kr_i ( ' ========== 国家代码获取结束 ========== ' ,
tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' ✅ 找到节点: $ actualTag ' , tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' - city: ${ node . city } ' , tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' - country: " ${ node . country } " ' ,
/ / tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' - country.isEmpty: ${ node . country . isEmpty } ' ,
/ / tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' - country.length: ${ node . country . length } ' ,
/ / tag: ' getCurrentNodeCountry ' ) ;
/ / KRLogUtil . kr_i ( ' ========== 国家代码获取结束 ========== ' ,
/ / tag: ' getCurrentNodeCountry ' ) ;
return node . country ;
}
@ -1846,8 +1869,25 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
@ override
void onReady ( ) {
super . onReady ( ) ;
}
Future . delayed ( const Duration ( milliseconds: 200 ) , ( ) async {
final rawAccount = KRAppRunData . getInstance ( ) . kr_account . value ;
final account = rawAccount ? . trim ( ) ;
if ( account = = null | |
account . isEmpty | |
account . toLowerCase ( ) = = ' null ' ) {
await HIDialog . show (
message: ' 未检测到账号信息,请重试初始化 ' ,
confirmText: ' 重试 ' ,
preventBackDismiss: true ,
onConfirm: ( ) {
Get . offAllNamed ( Routes . KR_SPLASH ) ;
} ,
) ;
}
} ) ;
}
@ override
void onClose ( ) {
@ -2340,12 +2380,12 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
/ / / 开 始 连 接 计 时
void kr_startConnectionTimer ( ) {
kr_stopConnectionTimer ( ) ;
_kr_connectionSeconds = 0 ;
_kr_connectionTimer = Timer . periodic ( const Duration ( seconds: 1 ) , ( timer ) {
_kr_connectionSeconds + + ;
kr_connectionTime . value = kr_formatDuration ( _kr_connectionSeconds ) ;
KRLogUtil . kr_i ( kr_connectText . value , tag: ' kr_startConnectionTimer ' ) ;
} ) ;
/ / _kr_connectionSeconds = 0 ;
/ / _kr_connectionTimer = Timer . periodic ( const Duration ( seconds: 1 ) , ( timer ) {
/ / _kr_connectionSeconds + + ;
/ / kr_connectionTime . value = kr_formatDuration ( _kr_connectionSeconds ) ;
/ / KRLogUtil . kr_i ( kr_connectText . value , tag: ' kr_startConnectionTimer ' ) ;
/ / } ) ;
}
/ / / 停 止 连 接 计 时
@ -2426,7 +2466,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
}
/ / / 强 制 同 步 连 接 状 态
void kr_forceSyncConnectionStatus ( ) {
void kr_forceSyncConnectionStatus ( [bool ? isQuickConnect ] ) {
try {
KRLogUtil . kr_i ( ' 🔄 强制同步连接状态... ' , tag: ' HomeController ' ) ;
@ -2469,6 +2509,9 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
/ / 强 制 更 新 UI
update ( ) ;
if ( isQuickConnect = = true ) {
_checkQuickConnectAutoStart ( ) ;
}
KRLogUtil . kr_i ( ' ✅ 连接状态同步完成 ' , tag: ' HomeController ' ) ;
} catch ( e ) {
KRLogUtil . kr_e ( ' ❌ 强制同步连接状态失败: $ e ' , tag: ' HomeController ' ) ;
@ -2525,27 +2568,21 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
final currentStatus = KRSingBoxImp . instance . kr_status . value ;
/ / 只 检 测 中 间 状 态 ( Starting / Stopping )
if ( currentStatus is SingboxStarting | | currentStatus is SingboxStopping ) {
if ( currentStatus is SingboxStarting | |
currentStatus is SingboxStopping ) {
final now = DateTime . now ( ) ;
if ( _lastStatusChangeTime ! = null ) {
final duration = now . difference ( _lastStatusChangeTime ! ) ;
if ( duration > const Duration ( seconds: 1 5) ) {
/ / 状 态 卡 住 超 过 1 5 秒
if ( duration > const Duration ( seconds: 5) ) {
/ / 状 态 卡 住 超 过 5 秒
KRLogUtil . kr_w (
' ⚠️ [Watchdog] 检测到状态卡住: ${ currentStatus . runtimeType } , 持续时间: ${ duration . inSeconds } 秒 ' ,
tag: ' HomeController ' ,
) ;
/ / 自 动 触 发 强 制 重 置
_forceResetState ( ) . then ( ( _ ) {
Get . snackbar (
' 系统提示 ' ,
' VPN 状态异常已自动修复 ' ,
snackPosition: SnackPosition . TOP ,
duration: const Duration ( seconds: 2 ) ,
) ;
} ) ;
_forceResetState ( ) . then ( ( _ ) { } ) ;
}
}
}