解决开启关闭后UI界面状态不同步问题
Some checks failed
Build Android APK / 编译 libcore.aar (push) Has been cancelled
Build Android APK / 编译 Android APK (release) (push) Has been cancelled
Build Android APK / 创建 GitHub Release (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Linux) (push) Has been cancelled
Build Multi-Platform / 构建 Android APK (push) Has been cancelled
Build Multi-Platform / 构建 Windows (push) Has been cancelled
Build Multi-Platform / 构建 macOS (push) Has been cancelled
Build Multi-Platform / 构建 Linux (push) Has been cancelled
Build Multi-Platform / 构建 iOS (push) Has been cancelled
Build Multi-Platform / 创建 Release (push) Has been cancelled
Build Multi-Platform / 编译 libcore (iOS/tvOS) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Android) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Windows) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (macOS) (push) Has been cancelled
Build Windows / 编译 libcore (Windows) (push) Has been cancelled
Build Windows / build (push) Has been cancelled

(cherry picked from commit 23a4a5ce2e46ffbd3b8188333dfa7f4559984e4c)
This commit is contained in:
Rust 2025-10-30 22:33:48 -07:00 committed by speakeloudest
parent 5c8f0ca1fc
commit 74df08144f
3 changed files with 118 additions and 65 deletions

View File

@ -103,9 +103,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
//
final kr_lastMapCenter = LatLng(35.0, 105.0).obs;
//
bool kr_isSwitching = false;
// "闪连"Checkbox添加一个响应式变量 false
final isQuickConnectEnabled = false.obs;
@ -114,7 +111,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
//
static const String _quickConnectKey = 'kr_quick_connect_enabled';
//
final RxString currentSelectedCountry = ''.obs;
final RxBool isCountryReselectionEnabled = true.obs;
@ -206,7 +203,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
KRLogUtil.kr_i('开始执行闪连自动连接', tag: 'QuickConnect');
//
if (kr_isSwitching) {
if (KRSingBoxImp.instance.kr_status == SingboxStarted) {
KRLogUtil.kr_w('连接操作正在进行中,跳过自动连接', tag: 'QuickConnect');
return;
}
@ -503,6 +500,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
void _bindConnectionStatus() {
//
ever(KRSingBoxImp.instance.kr_status, (status) {
print('🔵 Controller 收到状态变化: ${status.runtimeType}');
KRLogUtil.kr_i('🔄 连接状态变化: $status', tag: 'HomeController');
KRLogUtil.kr_i('📊 当前状态类型: ${status.runtimeType}', tag: 'HomeController');
@ -594,7 +592,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
// UI
update();
//
_checkCountryReselection(value);
} catch (e) {
@ -656,54 +654,79 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
***/
}
void kr_toggleSwitch(bool value) async {
//
if (kr_isSwitching) {
KRLogUtil.kr_i('正在切换中,忽略本次操作', tag: 'HomeController');
/// 🔧 : hiddify-app toggleConnection
Future<void> kr_toggleSwitch(bool value) async {
final currentStatus = KRSingBoxImp.instance.kr_status.value;
KRLogUtil.kr_i('🔵 toggleSwitch 被调用: value=$value, currentStatus=$currentStatus', tag: 'HomeController');
print('🔵 toggleSwitch: value=$value, currentStatus=$currentStatus');
// 🔧 : hiddify-app "switching status, debounce"
if (currentStatus is SingboxStarting || currentStatus is SingboxStopping) {
KRLogUtil.kr_i('🔄 正在切换中,忽略本次操作 (当前状态: $currentStatus)', tag: 'HomeController');
print('🔵 忽略操作:正在切换中');
return;
}
try {
kr_isSwitching = true;
KRLogUtil.kr_i('🔄 开始切换连接状态: $value', tag: 'HomeController');
if (value) {
//
KRLogUtil.kr_i('🔄 开始连接...', tag: 'HomeController');
print('🔵 执行 kr_start()');
await KRSingBoxImp.instance.kr_start();
KRLogUtil.kr_i('✅ 连接命令已发送', tag: 'HomeController');
print('🔵 kr_start() 完成');
// UI及时更新
Future.delayed(const Duration(milliseconds: 300), () {
kr_forceSyncConnectionStatus();
});
//
Future.delayed(const Duration(seconds: 2), () {
kr_forceSyncConnectionStatus();
});
// 🔧 : 3
await _waitForStatus(SingboxStarted, maxSeconds: 3);
} else {
KRLogUtil.kr_i('🛑 准备停止连接...', tag: 'HomeController');
//
//
KRLogUtil.kr_i('🛑 开始断开连接...', tag: 'HomeController');
print('🔵 执行 kr_stop()');
await KRSingBoxImp.instance.kr_stop().timeout(
const Duration(seconds: 10),
onTimeout: () {
KRLogUtil.kr_e('⚠️ 停止操作超时', tag: 'HomeController');
//
kr_forceSyncConnectionStatus();
throw TimeoutException('Stop operation timeout');
},
);
KRLogUtil.kr_i('✅ 停止命令已发送', tag: 'HomeController');
KRLogUtil.kr_i('✅ 断开命令已发送', tag: 'HomeController');
print('🔵 kr_stop() 完成');
// 🔧 : 2
await _waitForStatus(SingboxStopped, maxSeconds: 2);
}
} catch (e) {
KRLogUtil.kr_e('切换失败: $e', tag: 'HomeController');
//
Future.delayed(const Duration(milliseconds: 100), () {
kr_forceSyncConnectionStatus();
});
} finally {
//
KRLogUtil.kr_i('🔓 重置切换标志', tag: 'HomeController');
kr_isSwitching = false;
KRLogUtil.kr_e('❌ 切换失败: $e', tag: 'HomeController');
print('🔵 切换失败: $e');
//
kr_forceSyncConnectionStatus();
}
print('🔵 toggleSwitch 完成,当前 kr_isConnected=${kr_isConnected.value}');
}
/// 🔧
Future<void> _waitForStatus(Type expectedType, {int maxSeconds = 3}) async {
print('🔵 等待状态变为: $expectedType');
final startTime = DateTime.now();
while (DateTime.now().difference(startTime).inSeconds < maxSeconds) {
final currentStatus = KRSingBoxImp.instance.kr_status.value;
print('🔵 当前状态: ${currentStatus.runtimeType}');
if (currentStatus.runtimeType == expectedType) {
print('🔵 状态已达到: $expectedType');
// kr_isConnected
kr_forceSyncConnectionStatus();
return;
}
await Future.delayed(const Duration(milliseconds: 100));
}
print('🔵 等待超时,强制同步状态');
kr_forceSyncConnectionStatus();
}
///
@ -914,35 +937,35 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
// 655350
return node.urlTestDelay.value < 65535 && node.urlTestDelay.value > 0;
}
///
void _checkCountryReselection(List<dynamic> activeGroups) {
//
if (!isCountryReselectionEnabled.value) {
return;
}
//
if (!kr_isConnected.value) {
return;
}
//
if (currentSelectedCountry.isEmpty) {
return;
}
try {
//
final currentNodeInfo = kr_getRealConnectedNodeInfo();
final currentDelay = currentNodeInfo['delay'] as int;
//
if (currentDelay > 0 && currentDelay < countryReselectionLatencyThreshold) {
//
return;
}
//
if (currentDelay >= countryReselectionLatencyThreshold || currentDelay <= 0) {
KRLogUtil.kr_w('🔄 当前节点延迟过高(${currentDelay}ms),尝试国家内重选', tag: 'HomeController');
@ -952,7 +975,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
KRLogUtil.kr_e('检查国家内重选时出错: $e', tag: 'HomeController');
}
}
///
void _performCountryReselection(String country) {
try {
@ -960,16 +983,16 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
final countryNodes = kr_subscribeService.allList
.where((node) => node.country == country && node.tag != 'auto')
.toList();
if (countryNodes.isEmpty) {
KRLogUtil.kr_w('⚠️ 国家 $country 内没有可用节点', tag: 'HomeController');
return;
}
//
String? bestNode;
int minDelay = 65535;
for (var node in countryNodes) {
final delay = node.urlTestDelay.value;
if (delay > 0 && delay < 65535 && delay < minDelay) {
@ -977,7 +1000,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
bestNode = node.tag;
}
}
if (bestNode != null && bestNode != kr_cutSeletedTag.value) {
KRLogUtil.kr_i('🎯 国家内重选: $bestNode (${minDelay}ms)', tag: 'HomeController');
kr_selectNode(bestNode);
@ -988,33 +1011,33 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
KRLogUtil.kr_e('执行国家内重选时出错: $e', tag: 'HomeController');
}
}
/// hi_node_list_controller调用
void setCurrentSelectedCountry(String country) {
currentSelectedCountry.value = country;
KRLogUtil.kr_i('🌍 设置当前选择国家: $country', tag: 'HomeController');
}
/// /
void setCountryReselectionEnabled(bool enabled) {
isCountryReselectionEnabled.value = enabled;
KRLogUtil.kr_i('🔄 国家内重选功能已${enabled ? "启用" : "禁用"}', tag: 'HomeController');
}
///
Map<String, dynamic> getCurrentCountryNodeStats() {
if (currentSelectedCountry.isEmpty) {
return {'error': '没有选择国家'};
}
final countryNodes = kr_subscribeService.allList
.where((node) => node.country == currentSelectedCountry.value && node.tag != 'auto')
.toList();
if (countryNodes.isEmpty) {
return {'error': '国家内没有节点'};
}
List<int> validDelays = [];
int totalNodes = countryNodes.length;
int validNodes = 0;
@ -1022,27 +1045,27 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
int maxDelay = 0;
String? fastestNode;
String? slowestNode;
for (var node in countryNodes) {
final delay = node.urlTestDelay.value;
if (delay > 0 && delay < 65535) {
validDelays.add(delay);
validNodes++;
if (delay < minDelay) {
minDelay = delay;
fastestNode = node.tag;
}
if (delay > maxDelay) {
maxDelay = delay;
slowestNode = node.tag;
}
}
}
double avgDelay = validDelays.isEmpty ? 0 : validDelays.reduce((a, b) => a + b) / validDelays.length;
return {
'country': currentSelectedCountry.value,
'totalNodes': totalNodes,

View File

@ -7,6 +7,7 @@ import 'package:kaer_with_panels/app/widgets/kr_country_flag.dart';
import 'package:kaer_with_panels/app/widgets/kr_app_text_style.dart';
import 'package:kaer_with_panels/app/localization/app_translations.dart';
import 'package:kaer_with_panels/app/services/singbox_imp/kr_sing_box_imp.dart';
import 'package:kaer_with_panels/singbox/model/singbox_status.dart';
import '../controllers/kr_home_controller.dart';
import '../models/kr_home_views_status.dart';
@ -209,13 +210,31 @@ class KRHomeConnectionInfoView extends GetView<KRHomeController> {
),
],
),
CupertinoSwitch(
value: controller.kr_isConnected.value,
onChanged: (bool value) {
controller.kr_toggleSwitch(value);
},
activeColor: Colors.blue,
),
// 🔧 : 使
Obx(() {
// 🔧 : observable
final _ = KRSingBoxImp.instance.kr_status.value; //
final isConnected = controller.kr_isConnected.value; // 使 controller
//
final status = KRSingBoxImp.instance.kr_status.value;
final isSwitching = status is SingboxStarting || status is SingboxStopping;
// 🔧
print('🔵 Switch UI 更新: status=${status.runtimeType}, isConnected=$isConnected, isSwitching=$isSwitching');
return CupertinoSwitch(
value: isConnected,
// 🔧 : onChanged nullSwitch
onChanged: isSwitching
? null
: (bool value) {
print('🔵 Switch onChanged 触发: 请求=$value, 当前状态=$status');
controller.kr_toggleSwitch(value);
},
activeColor: Colors.blue,
);
}),
],
),
],

View File

@ -548,10 +548,14 @@ class KRSingBoxImp {
///
/// hiddify-app: libcore UI
void _kr_subscribeToStatus() {
print('🔵 _kr_subscribeToStatus 被调用,重新订阅状态流');
KRLogUtil.kr_i('🔵 _kr_subscribeToStatus 被调用', tag: 'SingBox');
//
for (var sub in _kr_subscriptions) {
if (sub.hashCode.toString().contains('Status')) {
sub.cancel();
print('🔵 已取消旧的状态订阅');
}
}
_kr_subscriptions
@ -560,15 +564,19 @@ class KRSingBoxImp {
_kr_subscriptions.add(
kr_singBox.watchStatus().listen(
(status) {
print('🔵 收到 Native 状态更新: ${status.runtimeType}');
KRLogUtil.kr_i('📡 收到状态更新: $status', tag: 'SingBox');
kr_status.value = status;
},
onError: (error) {
print('🔵 状态流错误: $error');
KRLogUtil.kr_e('📡 状态流错误: $error', tag: 'SingBox');
},
cancelOnError: false,
),
);
print('🔵 状态流订阅完成');
}
///
@ -1034,6 +1042,9 @@ class KRSingBoxImp {
KRLogUtil.kr_w('⚠️ 配置文件不存在: $_cutPath', tag: 'SingBox');
}
// 🔧 :
_kr_subscribeToStatus();
await kr_singBox.start(_cutPath, kr_configName, false).map(
(r) {
KRLogUtil.kr_i('✅ SingBox 启动成功', tag: 'SingBox');