Compare commits

..

No commits in common. "5bd77511cc8b5f2c17cd8c2821533250b8f57fd9" and "c87d5d4d38848d48525c0d9f388106e34996e75e" have entirely different histories.

8 changed files with 199 additions and 222 deletions

View File

@ -208,10 +208,7 @@ class VPNManager: ObservableObject {
} }
func disconnect() { func disconnect() {
if state != .disconnected && state != .invalid { guard state == .connected else { return }
manager.connection.stopVPNTunnel() manager.connection.stopVPNTunnel()
} else {
alert = VPNManagerAlert(alert: nil, message: nil)
}
} }
} }

View File

@ -561,7 +561,15 @@ class HINodeListView extends GetView<HINodeListController> {
SizedBox(width: 12.w), SizedBox(width: 12.w),
Obx(() { Obx(() {
final selectedCountryField = final selectedCountryField =
controller.homeController.kr_selectedCountryTag.value; controller.homeController.kr_coutryText.value;
if (selectedCountryField == 'auto') {
return KrLocalImage(
imageName: 'radio-icon',
imageType: ImageType.svg,
width: 16.w,
height: 16.h,
);
}
final selected = selectedCountryField == country.country; final selected = selectedCountryField == country.country;
return selected return selected
? KrLocalImage( ? KrLocalImage(

View File

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

View File

@ -502,11 +502,11 @@ class _KRSimpleHttpInterceptor extends Interceptor {
} }
// JSON // JSON
try { try {
// final jsonData = jsonDecode(decrypted); final jsonData = jsonDecode(decrypted);
// final prettyJson = JsonEncoder.withIndent(' ').convert(jsonData); final prettyJson = JsonEncoder.withIndent(' ').convert(jsonData);
// if (kDebugMode) { if (kDebugMode) {
// print(prettyJson); print(prettyJson);
// } }
} catch (_) { } catch (_) {
if (kDebugMode) { if (kDebugMode) {
print(decrypted); print(decrypted);

View File

@ -108,8 +108,6 @@ class KRSingBoxImp {
/// Stream /// Stream
final List<StreamSubscription<dynamic>> _kr_subscriptions = []; final List<StreamSubscription<dynamic>> _kr_subscriptions = [];
StreamSubscription<SingboxStatus>? _kr_statusSubscription;
/// ///
bool _kr_isInitialized = false; bool _kr_isInitialized = false;
@ -738,12 +736,21 @@ class KRSingBoxImp {
} }
KRLogUtil.kr_i('🔵 _kr_subscribeToStatus 被调用', tag: 'SingBox'); KRLogUtil.kr_i('🔵 _kr_subscribeToStatus 被调用', tag: 'SingBox');
_kr_statusSubscription?.cancel(); //
_kr_statusSubscription = kr_singBox.watchStatus().listen( for (var sub in _kr_subscriptions) {
(status) { if (sub.hashCode.toString().contains('Status')) {
if (status == kr_status.value) { sub.cancel();
return; if (kDebugMode) {
print('🔵 已取消旧的状态订阅');
} }
}
}
_kr_subscriptions
.removeWhere((sub) => sub.hashCode.toString().contains('Status'));
_kr_subscriptions.add(
kr_singBox.watchStatus().listen(
(status) {
if (kDebugMode) { if (kDebugMode) {
print('🔵 收到 Native 状态更新: ${status.runtimeType}'); print('🔵 收到 Native 状态更新: ${status.runtimeType}');
} }
@ -757,6 +764,7 @@ class KRSingBoxImp {
KRLogUtil.kr_e('📡 状态流错误: $error', tag: 'SingBox'); KRLogUtil.kr_e('📡 状态流错误: $error', tag: 'SingBox');
}, },
cancelOnError: false, cancelOnError: false,
),
); );
if (kDebugMode) { if (kDebugMode) {
@ -1193,32 +1201,32 @@ class KRSingBoxImp {
KRLogUtil.kr_i('📊 出站节点数量: ${outbounds.length}', tag: 'SingBox'); KRLogUtil.kr_i('📊 出站节点数量: ${outbounds.length}', tag: 'SingBox');
// //
// for (int i = 0; i < outbounds.length; i++) { for (int i = 0; i < outbounds.length; i++) {
// final outbound = outbounds[i]; final outbound = outbounds[i];
// KRLogUtil.kr_i('📋 节点[$i] 配置:', tag: 'SingBox'); KRLogUtil.kr_i('📋 节点[$i] 配置:', tag: 'SingBox');
// KRLogUtil.kr_i(' - type: ${outbound['type']}', tag: 'SingBox'); KRLogUtil.kr_i(' - type: ${outbound['type']}', tag: 'SingBox');
// KRLogUtil.kr_i(' - tag: ${outbound['tag']}', tag: 'SingBox'); KRLogUtil.kr_i(' - tag: ${outbound['tag']}', tag: 'SingBox');
// KRLogUtil.kr_i(' - server: ${outbound['server']}', tag: 'SingBox'); KRLogUtil.kr_i(' - server: ${outbound['server']}', tag: 'SingBox');
// KRLogUtil.kr_i(' - server_port: ${outbound['server_port']}', KRLogUtil.kr_i(' - server_port: ${outbound['server_port']}',
// tag: 'SingBox'); tag: 'SingBox');
// if (outbound['method'] != null) { if (outbound['method'] != null) {
// KRLogUtil.kr_i(' - method: ${outbound['method']}', tag: 'SingBox'); KRLogUtil.kr_i(' - method: ${outbound['method']}', tag: 'SingBox');
// } }
// if (outbound['interval'] != null) { if (outbound['interval'] != null) {
// KRLogUtil.kr_i(' - interval: ${outbound['interval']}', tag: 'SingBox'); KRLogUtil.kr_i(' - interval: ${outbound['interval']}', tag: 'SingBox');
// } }
// if (outbound['password'] != null) { if (outbound['password'] != null) {
// KRLogUtil.kr_i( KRLogUtil.kr_i(
// ' - password: ${outbound['password']?.toString().substring(0, 8)}...', ' - password: ${outbound['password']?.toString().substring(0, 8)}...',
// tag: 'SingBox'); tag: 'SingBox');
// } }
// if (outbound['uuid'] != null) { if (outbound['uuid'] != null) {
// KRLogUtil.kr_i( KRLogUtil.kr_i(
// ' - uuid: ${outbound['uuid']?.toString().substring(0, 8)}...', ' - uuid: ${outbound['uuid']?.toString().substring(0, 8)}...',
// tag: 'SingBox'); tag: 'SingBox');
// } }
// KRLogUtil.kr_i(' - 完整配置: ${jsonEncode(outbound)}', tag: 'SingBox'); KRLogUtil.kr_i(' - 完整配置: ${jsonEncode(outbound)}', tag: 'SingBox');
// } }
// Hysteria2 libcore // Hysteria2 libcore
kr_outbounds = outbounds.where((outbound) { kr_outbounds = outbounds.where((outbound) {
@ -1517,9 +1525,9 @@ class KRSingBoxImp {
if (await configFile.exists()) { if (await configFile.exists()) {
final configContent = await configFile.readAsString(); final configContent = await configFile.readAsString();
KRLogUtil.kr_i('📄 配置文件内容长度: ${configContent.length}', tag: 'SingBox'); KRLogUtil.kr_i('📄 配置文件内容长度: ${configContent.length}', tag: 'SingBox');
// KRLogUtil.kr_i( KRLogUtil.kr_i(
// '📄 配置文件前500字符: ${configContent.substring(0, configContent.length > 500 ? 500 : configContent.length)}', '📄 配置文件前500字符: ${configContent.substring(0, configContent.length > 500 ? 500 : configContent.length)}',
// tag: 'SingBox'); tag: 'SingBox');
} else { } else {
KRLogUtil.kr_w('⚠️ 配置文件不存在: $_cutPath', tag: 'SingBox'); KRLogUtil.kr_w('⚠️ 配置文件不存在: $_cutPath', tag: 'SingBox');
} }

View File

@ -35,6 +35,7 @@ class _HIEdgeSwipeDetectorState extends State<HIEdgeSwipeDetector> {
bool _fromRight = false; bool _fromRight = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
KRLogUtil.kr_d('HIEdgeSwipeDetector build');
return Stack( return Stack(
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [

View File

@ -39,23 +39,23 @@ class KRCountryFlag extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// 🔍 // 🔍
// if (kDebugMode) { if (kDebugMode) {
// print('🏳️ KRCountryFlag.build 被调用'); print('🏳️ KRCountryFlag.build 被调用');
// } }
// if (kDebugMode) { if (kDebugMode) {
// print(' - 原始 countryCode: "$countryCode"'); print(' - 原始 countryCode: "$countryCode"');
// } }
// if (kDebugMode) { if (kDebugMode) {
// print(' - countryCode.isEmpty: ${countryCode.isEmpty}'); print(' - countryCode.isEmpty: ${countryCode.isEmpty}');
// } }
// if (kDebugMode) { if (kDebugMode) {
// print(' - countryCode.length: ${countryCode.length}'); print(' - countryCode.length: ${countryCode.length}');
// } }
final processedCode = _getCountryCode(countryCode); final processedCode = _getCountryCode(countryCode);
// if (kDebugMode) { if (kDebugMode) {
// print(' - 处理后 code: "$processedCode"'); print(' - 处理后 code: "$processedCode"');
// } }
// //
if (countryCode.isEmpty) { if (countryCode.isEmpty) {

View File

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 0.0.4+101 version: 0.0.4+100
environment: environment:
sdk: '>=3.5.0 <4.0.0' sdk: '>=3.5.0 <4.0.0'