解决开启关闭后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
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:
parent
5c8f0ca1fc
commit
74df08144f
@ -103,9 +103,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
// 添加最后的地图中心点
|
// 添加最后的地图中心点
|
||||||
final kr_lastMapCenter = LatLng(35.0, 105.0).obs;
|
final kr_lastMapCenter = LatLng(35.0, 105.0).obs;
|
||||||
|
|
||||||
// 添加一个标志来防止重复操作
|
|
||||||
bool kr_isSwitching = false;
|
|
||||||
|
|
||||||
// 为"闪连"Checkbox添加一个响应式变量,默认为 false
|
// 为"闪连"Checkbox添加一个响应式变量,默认为 false
|
||||||
final isQuickConnectEnabled = false.obs;
|
final isQuickConnectEnabled = false.obs;
|
||||||
|
|
||||||
@ -206,7 +203,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
KRLogUtil.kr_i('开始执行闪连自动连接', tag: 'QuickConnect');
|
KRLogUtil.kr_i('开始执行闪连自动连接', tag: 'QuickConnect');
|
||||||
|
|
||||||
// 防止重复操作
|
// 防止重复操作
|
||||||
if (kr_isSwitching) {
|
if (KRSingBoxImp.instance.kr_status == SingboxStarted) {
|
||||||
KRLogUtil.kr_w('连接操作正在进行中,跳过自动连接', tag: 'QuickConnect');
|
KRLogUtil.kr_w('连接操作正在进行中,跳过自动连接', tag: 'QuickConnect');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -503,6 +500,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
void _bindConnectionStatus() {
|
void _bindConnectionStatus() {
|
||||||
// 添加更详细的状态监听
|
// 添加更详细的状态监听
|
||||||
ever(KRSingBoxImp.instance.kr_status, (status) {
|
ever(KRSingBoxImp.instance.kr_status, (status) {
|
||||||
|
print('🔵 Controller 收到状态变化: ${status.runtimeType}');
|
||||||
KRLogUtil.kr_i('🔄 连接状态变化: $status', tag: 'HomeController');
|
KRLogUtil.kr_i('🔄 连接状态变化: $status', tag: 'HomeController');
|
||||||
KRLogUtil.kr_i('📊 当前状态类型: ${status.runtimeType}', tag: 'HomeController');
|
KRLogUtil.kr_i('📊 当前状态类型: ${status.runtimeType}', tag: 'HomeController');
|
||||||
|
|
||||||
@ -656,54 +654,79 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
***/
|
***/
|
||||||
}
|
}
|
||||||
|
|
||||||
void kr_toggleSwitch(bool value) async {
|
/// 🔧 重构: 参考 hiddify-app 的 toggleConnection 实现
|
||||||
// 如果正在切换中,直接返回
|
Future<void> kr_toggleSwitch(bool value) async {
|
||||||
if (kr_isSwitching) {
|
final currentStatus = KRSingBoxImp.instance.kr_status.value;
|
||||||
KRLogUtil.kr_i('正在切换中,忽略本次操作', tag: 'HomeController');
|
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
kr_isSwitching = true;
|
|
||||||
KRLogUtil.kr_i('🔄 开始切换连接状态: $value', tag: 'HomeController');
|
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
|
// 开启连接
|
||||||
|
KRLogUtil.kr_i('🔄 开始连接...', tag: 'HomeController');
|
||||||
|
print('🔵 执行 kr_start()');
|
||||||
await KRSingBoxImp.instance.kr_start();
|
await KRSingBoxImp.instance.kr_start();
|
||||||
|
KRLogUtil.kr_i('✅ 连接命令已发送', tag: 'HomeController');
|
||||||
|
print('🔵 kr_start() 完成');
|
||||||
|
|
||||||
// 启动成功后立即同步一次,确保UI及时更新
|
// 🔧 修复: 等待状态更新,最多3秒
|
||||||
Future.delayed(const Duration(milliseconds: 300), () {
|
await _waitForStatus(SingboxStarted, maxSeconds: 3);
|
||||||
kr_forceSyncConnectionStatus();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 再次延迟验证,确保状态稳定
|
|
||||||
Future.delayed(const Duration(seconds: 2), () {
|
|
||||||
kr_forceSyncConnectionStatus();
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
KRLogUtil.kr_i('🛑 准备停止连接...', tag: 'HomeController');
|
// 关闭连接
|
||||||
// 添加超时保护
|
KRLogUtil.kr_i('🛑 开始断开连接...', tag: 'HomeController');
|
||||||
|
print('🔵 执行 kr_stop()');
|
||||||
await KRSingBoxImp.instance.kr_stop().timeout(
|
await KRSingBoxImp.instance.kr_stop().timeout(
|
||||||
const Duration(seconds: 10),
|
const Duration(seconds: 10),
|
||||||
onTimeout: () {
|
onTimeout: () {
|
||||||
KRLogUtil.kr_e('⚠️ 停止操作超时', tag: 'HomeController');
|
KRLogUtil.kr_e('⚠️ 停止操作超时', tag: 'HomeController');
|
||||||
// 强制同步状态
|
|
||||||
kr_forceSyncConnectionStatus();
|
|
||||||
throw TimeoutException('Stop operation timeout');
|
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) {
|
} catch (e) {
|
||||||
KRLogUtil.kr_e('切换失败: $e', tag: 'HomeController');
|
KRLogUtil.kr_e('❌ 切换失败: $e', tag: 'HomeController');
|
||||||
// 当启动或停止失败时,强制同步状态
|
print('🔵 切换失败: $e');
|
||||||
Future.delayed(const Duration(milliseconds: 100), () {
|
// 发生错误时强制同步状态
|
||||||
kr_forceSyncConnectionStatus();
|
kr_forceSyncConnectionStatus();
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
// 确保在任何情况下都会重置标志
|
|
||||||
KRLogUtil.kr_i('🔓 重置切换标志', tag: 'HomeController');
|
|
||||||
kr_isSwitching = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 处理选择器代理
|
/// 处理选择器代理
|
||||||
|
|||||||
@ -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/widgets/kr_app_text_style.dart';
|
||||||
import 'package:kaer_with_panels/app/localization/app_translations.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/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 '../controllers/kr_home_controller.dart';
|
||||||
import '../models/kr_home_views_status.dart';
|
import '../models/kr_home_views_status.dart';
|
||||||
|
|
||||||
@ -209,13 +210,31 @@ class KRHomeConnectionInfoView extends GetView<KRHomeController> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
CupertinoSwitch(
|
// 🔧 修复: 使用多层监听确保状态更新
|
||||||
value: controller.kr_isConnected.value,
|
Obx(() {
|
||||||
onChanged: (bool value) {
|
// 🔧 关键: 强制读取两个 observable 确保追踪
|
||||||
controller.kr_toggleSwitch(value);
|
final _ = KRSingBoxImp.instance.kr_status.value; // 强制追踪
|
||||||
},
|
final isConnected = controller.kr_isConnected.value; // 使用 controller 的状态
|
||||||
activeColor: Colors.blue,
|
|
||||||
),
|
// 再次读取状态用于判断
|
||||||
|
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 为 null,Switch 自动禁用
|
||||||
|
onChanged: isSwitching
|
||||||
|
? null
|
||||||
|
: (bool value) {
|
||||||
|
print('🔵 Switch onChanged 触发: 请求=$value, 当前状态=$status');
|
||||||
|
controller.kr_toggleSwitch(value);
|
||||||
|
},
|
||||||
|
activeColor: Colors.blue,
|
||||||
|
);
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -548,10 +548,14 @@ class KRSingBoxImp {
|
|||||||
/// 订阅状态变化流
|
/// 订阅状态变化流
|
||||||
/// 参考 hiddify-app: 监听 libcore 发送的状态事件来自动更新 UI
|
/// 参考 hiddify-app: 监听 libcore 发送的状态事件来自动更新 UI
|
||||||
void _kr_subscribeToStatus() {
|
void _kr_subscribeToStatus() {
|
||||||
|
print('🔵 _kr_subscribeToStatus 被调用,重新订阅状态流');
|
||||||
|
KRLogUtil.kr_i('🔵 _kr_subscribeToStatus 被调用', tag: 'SingBox');
|
||||||
|
|
||||||
// 取消之前的状态订阅
|
// 取消之前的状态订阅
|
||||||
for (var sub in _kr_subscriptions) {
|
for (var sub in _kr_subscriptions) {
|
||||||
if (sub.hashCode.toString().contains('Status')) {
|
if (sub.hashCode.toString().contains('Status')) {
|
||||||
sub.cancel();
|
sub.cancel();
|
||||||
|
print('🔵 已取消旧的状态订阅');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_kr_subscriptions
|
_kr_subscriptions
|
||||||
@ -560,15 +564,19 @@ class KRSingBoxImp {
|
|||||||
_kr_subscriptions.add(
|
_kr_subscriptions.add(
|
||||||
kr_singBox.watchStatus().listen(
|
kr_singBox.watchStatus().listen(
|
||||||
(status) {
|
(status) {
|
||||||
|
print('🔵 收到 Native 状态更新: ${status.runtimeType}');
|
||||||
KRLogUtil.kr_i('📡 收到状态更新: $status', tag: 'SingBox');
|
KRLogUtil.kr_i('📡 收到状态更新: $status', tag: 'SingBox');
|
||||||
kr_status.value = status;
|
kr_status.value = status;
|
||||||
},
|
},
|
||||||
onError: (error) {
|
onError: (error) {
|
||||||
|
print('🔵 状态流错误: $error');
|
||||||
KRLogUtil.kr_e('📡 状态流错误: $error', tag: 'SingBox');
|
KRLogUtil.kr_e('📡 状态流错误: $error', tag: 'SingBox');
|
||||||
},
|
},
|
||||||
cancelOnError: false,
|
cancelOnError: false,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
print('🔵 状态流订阅完成');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 订阅统计数据流
|
/// 订阅统计数据流
|
||||||
@ -1034,6 +1042,9 @@ class KRSingBoxImp {
|
|||||||
KRLogUtil.kr_w('⚠️ 配置文件不存在: $_cutPath', tag: 'SingBox');
|
KRLogUtil.kr_w('⚠️ 配置文件不存在: $_cutPath', tag: 'SingBox');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔧 修复: 在启动前重新订阅状态流,确保能收到状态更新
|
||||||
|
_kr_subscribeToStatus();
|
||||||
|
|
||||||
await kr_singBox.start(_cutPath, kr_configName, false).map(
|
await kr_singBox.start(_cutPath, kr_configName, false).map(
|
||||||
(r) {
|
(r) {
|
||||||
KRLogUtil.kr_i('✅ SingBox 启动成功', tag: 'SingBox');
|
KRLogUtil.kr_i('✅ SingBox 启动成功', tag: 'SingBox');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user