Compare commits

..

No commits in common. "c7b77c1ad817f6afaa197abcca48938e7e5889da" and "7a223d614b9bf80a80bc78d800ddb32d1dfcca49" have entirely different histories.

5 changed files with 62 additions and 184 deletions

View File

@ -1,8 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
@ -530,6 +527,8 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
void _bindConnectionStatus() { void _bindConnectionStatus() {
// //
ever(KRSingBoxImp.instance.kr_status, (status) { ever(KRSingBoxImp.instance.kr_status, (status) {
if (kDebugMode) {
}
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');
@ -1076,7 +1075,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
// UI // UI
kr_cutSeletedTag.value = tag; kr_cutSeletedTag.value = tag;
kr_updateConnectionInfo(); kr_updateConnectionInfo();
// kr_moveToSelectedNode(); kr_moveToSelectedNode();
// 🚀 A增强 // 🚀 A增强
KRLogUtil.kr_i('⏳ [增强] 等待活动组更新500ms...', tag: 'HomeController'); KRLogUtil.kr_i('⏳ [增强] 等待活动组更新500ms...', tag: 'HomeController');
@ -1157,110 +1156,50 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
} }
/// ///
/// 🔧 使 kr_cutSeletedTag kr_activeGroups /// 🔧 使 kr_cutTag kr_cutSeletedTagUI立即响应
/// /// 🔧 "auto"
/// 1. kr_cutTag auto使
/// 2. auto使 kr_cutSeletedTag
/// 3. kr_cutSeletedTag auto kr_activeGroups
String kr_getCurrentNodeCountry() { String kr_getCurrentNodeCountry() {
KRLogUtil.kr_i('========== 开始获取国家代码 ==========', tag: 'getCurrentNodeCountry'); KRLogUtil.kr_i('========== 开始获取国家代码 ==========', tag: 'getCurrentNodeCountry');
KRLogUtil.kr_i('kr_cutTag: ${kr_cutTag.value}', 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('kr_cutSeletedTag: ${kr_cutSeletedTag.value}', tag: 'getCurrentNodeCountry');
KRLogUtil.kr_i('keyList 节点总数: ${kr_subscribeService.keyList.length}', tag: 'getCurrentNodeCountry'); KRLogUtil.kr_i('keyList 节点总数: ${kr_subscribeService.keyList.length}', tag: 'getCurrentNodeCountry');
String actualTag; if (kr_cutTag.isEmpty) {
KRLogUtil.kr_w('kr_cutTag 为空,返回空字符串', tag: 'getCurrentNodeCountry');
return '';
}
// 🔧 String actualTag = kr_cutTag.value;
// 1. kr_cutTag auto使
if (kr_cutTag.value != 'auto' && kr_cutTag.value != 'select' && kr_cutTag.value.isNotEmpty) { // 🔧 "auto"
// if (actualTag == 'auto' || actualTag == 'select') {
actualTag = kr_cutTag.value;
KRLogUtil.kr_i('✅ 使用手动选择的节点: $actualTag', tag: 'getCurrentNodeCountry');
}
// 2. auto使 kr_cutSeletedTag
else if (kr_cutSeletedTag.value.isNotEmpty &&
kr_cutSeletedTag.value != 'auto' &&
kr_cutSeletedTag.value != 'select') {
// auto 使
actualTag = kr_cutSeletedTag.value;
KRLogUtil.kr_i('✅ 使用 auto 模式下的实际节点 (kr_cutSeletedTag): $actualTag', tag: 'getCurrentNodeCountry');
}
// 3.
else {
try { try {
KRLogUtil.kr_i('⚠️ 尝试从活动组获取实际节点', tag: 'getCurrentNodeCountry'); KRLogUtil.kr_i('检测到特殊标签: $actualTag,尝试从活动组获取实际节点', tag: 'getCurrentNodeCountry');
KRLogUtil.kr_i('活动组数量: ${KRSingBoxImp.instance.kr_activeGroups.length}', tag: 'getCurrentNodeCountry'); KRLogUtil.kr_i('活动组数量: ${KRSingBoxImp.instance.kr_activeGroups.length}', tag: 'getCurrentNodeCountry');
// 🔧 使 allGroups // SingBox "select"
if (KRSingBoxImp.instance.kr_activeGroups.isEmpty) { final selectGroup = KRSingBoxImp.instance.kr_activeGroups.firstWhere(
print('[getCurrentNodeCountry] ⚠️ 活动组为空,尝试使用 allGroups'); (group) => group.tag == 'select',
KRLogUtil.kr_w('⚠️ 活动组为空,尝试使用 allGroups', tag: 'getCurrentNodeCountry'); orElse: () => throw Exception('未找到 select 组'),
);
final allGroups = KRSingBoxImp.instance.kr_allGroups; KRLogUtil.kr_i('找到 select 组,当前选中: ${selectGroup.selected}', tag: 'getCurrentNodeCountry');
print('[getCurrentNodeCountry] allGroups 数量: ${allGroups.length}');
if (allGroups.isEmpty) {
print('[getCurrentNodeCountry] ❌ allGroups 也为空,返回空字符串');
KRLogUtil.kr_w('❌ allGroups 也为空,返回空字符串', tag: 'getCurrentNodeCountry');
return '';
}
// allGroups select
final selectGroup = allGroups.firstWhere(
(group) => group.tag == 'select',
orElse: () => throw Exception('未找到 select 组'),
);
print('[getCurrentNodeCountry] selectGroup.selected: ${selectGroup.selected}');
if (selectGroup.selected.isEmpty || selectGroup.selected == 'auto' || selectGroup.selected == 'select') {
print('[getCurrentNodeCountry] select 组选中的是 auto查找 urltest 组');
// select auto urltest
final urlTestGroup = allGroups.firstWhere(
(group) => group.type == ProxyType.urltest,
orElse: () => throw Exception('未找到 urltest 组'),
);
if (urlTestGroup.selected.isNotEmpty) {
actualTag = urlTestGroup.selected;
print('[getCurrentNodeCountry] ✅ 从 allGroups 的 urltest 组获取节点: $actualTag');
KRLogUtil.kr_i('✅ 从 allGroups 的 urltest 组获取节点: $actualTag', tag: 'getCurrentNodeCountry');
} else {
print('[getCurrentNodeCountry] ❌ urltest 组的 selected 也为空');
KRLogUtil.kr_w('❌ urltest 组的 selected 也为空', tag: 'getCurrentNodeCountry');
return '';
}
} else {
actualTag = selectGroup.selected;
print('[getCurrentNodeCountry] ✅ 从 allGroups 的 select 组获取节点: $actualTag');
KRLogUtil.kr_i('✅ 从 allGroups 的 select 组获取节点: $actualTag', tag: 'getCurrentNodeCountry');
}
} else {
//
// SingBox "select"
final selectGroup = KRSingBoxImp.instance.kr_activeGroups.firstWhere(
(group) => group.tag == 'select',
orElse: () => throw Exception('未找到 select 组'),
);
if (selectGroup.selected.isEmpty) {
KRLogUtil.kr_w('❌ select 组的 selected 为空', tag: 'getCurrentNodeCountry');
return '';
}
//
if (selectGroup.selected.isNotEmpty) {
actualTag = selectGroup.selected; actualTag = selectGroup.selected;
KRLogUtil.kr_i('✅ 从活动组获取节点: $actualTag', tag: 'getCurrentNodeCountry'); KRLogUtil.kr_i('从 select 组获取实际节点: $actualTag', tag: 'getCurrentNodeCountry');
} }
} catch (e) { } catch (e) {
KRLogUtil.kr_e('❌ 从活动组获取节点失败: $e', tag: 'getCurrentNodeCountry'); KRLogUtil.kr_w('获取实际节点失败: $e', tag: 'getCurrentNodeCountry');
return ''; // 使 kr_cutSeletedTag
if (kr_cutSeletedTag.value.isNotEmpty && kr_cutSeletedTag.value != 'auto') {
actualTag = kr_cutSeletedTag.value;
KRLogUtil.kr_i('使用 kr_cutSeletedTag 作为备选: $actualTag', tag: 'getCurrentNodeCountry');
}
} }
} }
// actualTag
if (actualTag.isEmpty) {
KRLogUtil.kr_w('❌ 节点标签为空', tag: 'getCurrentNodeCountry');
return '';
}
// 使 // 使
KRLogUtil.kr_i('查找节点: $actualTag', tag: 'getCurrentNodeCountry'); KRLogUtil.kr_i('查找节点: $actualTag', tag: 'getCurrentNodeCountry');
final node = kr_subscribeService.keyList[actualTag]; final node = kr_subscribeService.keyList[actualTag];
@ -1290,7 +1229,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
return node.country; return node.country;
} }
/// auto /// auto
Map<String, dynamic> kr_getRealConnectedNodeInfo() { Map<String, dynamic> kr_getRealConnectedNodeInfo() {
// auto // auto
@ -1343,8 +1281,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
String kr_getRealConnectedNodeCountry() { String kr_getRealConnectedNodeCountry() {
final info = kr_getRealConnectedNodeInfo(); final info = kr_getRealConnectedNodeInfo();
final delay = kr_currentNodeLatency.value; final delay = kr_currentNodeLatency.value;
final country1 = kr_getCurrentNodeCountry();
print('country----$country1');
final country = kr_getCountryFullName(info['country']); final country = kr_getCountryFullName(info['country']);
if (delay == -2) { if (delay == -2) {
return '--'; return '--';

View File

@ -7,8 +7,6 @@ import 'package:kaer_with_panels/app/widgets/kr_local_image.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/services/global_overlay_service.dart'; import 'package:kaer_with_panels/app/services/global_overlay_service.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';
/// ///
class HIAnimatedConnectButton extends GetView<KRHomeController> { class HIAnimatedConnectButton extends GetView<KRHomeController> {
@ -22,18 +20,9 @@ class HIAnimatedConnectButton extends GetView<KRHomeController> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Obx(() { return Obx(() {
final isConnected = controller.kr_isConnected.value;
final delay = controller.kr_currentNodeLatency.value; final delay = controller.kr_currentNodeLatency.value;
print('当前连接情况$delay----$isConnected');
// 🔧 : 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');
final isShow = isConnected; // delay == -1 || isConnected; final isShow = isConnected; // delay == -1 || isConnected;
final Color buttonColor = Theme.of(context).primaryColor; final Color buttonColor = Theme.of(context).primaryColor;
@ -82,10 +71,6 @@ class HIAnimatedConnectButton extends GetView<KRHomeController> {
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: InkWell( child: InkWell(
onTap: () { onTap: () {
if(isSwitching) {
print('🔵 Switch UI 正在更新,切换中点击了按钮: status=${status.runtimeType}, isConnected=$isConnected, isSwitching=$isSwitching');
return;
}
final hasValidSubscription = final hasValidSubscription =
controller.kr_subscribeService.kr_availableSubscribes.isNotEmpty; controller.kr_subscribeService.kr_availableSubscribes.isNotEmpty;
if (hasValidSubscription) { if (hasValidSubscription) {

View File

@ -15,7 +15,6 @@ import 'package:kaer_with_panels/app/widgets/dialogs/kr_dialog.dart';
import 'package:kaer_with_panels/app/widgets/kr_local_image.dart'; import 'package:kaer_with_panels/app/widgets/kr_local_image.dart';
import 'package:kaer_with_panels/app/utils/kr_log_util.dart'; import 'package:kaer_with_panels/app/utils/kr_log_util.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter_screenutil/flutter_screenutil.dart';

View File

@ -77,6 +77,8 @@ class KRSingBoxImp {
/// 线 /// 线
final kr_isAutoOutbound = false.obs; final kr_isAutoOutbound = false.obs;
bool _initialized = false;
/// ///
final kr_connectionType = KRConnectionType.rule.obs; final kr_connectionType = KRConnectionType.rule.obs;
@ -146,6 +148,12 @@ class KRSingBoxImp {
} }
try { try {
if (_initialized) {
KRLogUtil.kr_i('SingBox 已经初始化,跳过重复初始化');
return;
}
_initialized = true;
KRLogUtil.kr_i('开始初始化 SingBox'); KRLogUtil.kr_i('开始初始化 SingBox');
// //
await KRCountryUtil.kr_init(); await KRCountryUtil.kr_init();
@ -612,7 +620,8 @@ class KRSingBoxImp {
/// ///
void _kr_subscribeToGroups() { void _kr_subscribeToGroups() {
print('[_kr_subscribeToGroups] 🚀 开始订阅分组数据流'); KRLogUtil.kr_i('🛰 启动分组监听 watchActiveGroups / watchGroups', tag: 'SingBox');
// //
for (var sub in _kr_subscriptions) { for (var sub in _kr_subscriptions) {
if (sub.hashCode.toString().contains('Groups')) { if (sub.hashCode.toString().contains('Groups')) {
@ -625,7 +634,6 @@ class KRSingBoxImp {
_kr_subscriptions.add( _kr_subscriptions.add(
kr_singBox.watchActiveGroups().listen( kr_singBox.watchActiveGroups().listen(
(groups) { (groups) {
print('[watchActiveGroups] 📡 收到活动组更新,数量: ${groups.length}');
KRLogUtil.kr_i('📡 收到活动组更新,数量: ${groups.length}', tag: 'SingBox'); KRLogUtil.kr_i('📡 收到活动组更新,数量: ${groups.length}', tag: 'SingBox');
kr_activeGroups.value = groups; kr_activeGroups.value = groups;
@ -642,7 +650,6 @@ class KRSingBoxImp {
KRLogUtil.kr_i('✅ 活动组处理完成', tag: 'SingBox'); KRLogUtil.kr_i('✅ 活动组处理完成', tag: 'SingBox');
}, },
onError: (error) { onError: (error) {
print('[watchActiveGroups] ❌ 活动分组监听错误: $error');
KRLogUtil.kr_e('❌ 活动分组监听错误: $error', tag: 'SingBox'); KRLogUtil.kr_e('❌ 活动分组监听错误: $error', tag: 'SingBox');
}, },
cancelOnError: false, cancelOnError: false,
@ -652,22 +659,14 @@ class KRSingBoxImp {
_kr_subscriptions.add( _kr_subscriptions.add(
kr_singBox.watchGroups().listen( kr_singBox.watchGroups().listen(
(groups) { (groups) {
print('[watchGroups] 📡 收到所有组更新,数量: ${groups.length}');
kr_allGroups.value = groups; kr_allGroups.value = groups;
//
for (int i = 0; i < groups.length; i++) {
final group = groups[i];
print('[watchGroups] 组[$i]: tag=${group.tag}, type=${group.type}, selected=${group.selected}');
}
}, },
onError: (error) { onError: (error) {
print('[watchGroups] ❌ 所有分组监听错误: $error');
KRLogUtil.kr_e('所有分组监听错误: $error'); KRLogUtil.kr_e('所有分组监听错误: $error');
}, },
cancelOnError: false, cancelOnError: false,
), ),
); );
print('[_kr_subscribeToGroups] ✅ 分组数据流订阅完成,当前订阅数: ${_kr_subscriptions.length}');
} }
/// ///
@ -1129,7 +1128,7 @@ class KRSingBoxImp {
KRLogUtil.kr_i('✅ SingBox 核心已启动,开始初始化 command client', tag: 'SingBox'); KRLogUtil.kr_i('✅ SingBox 核心已启动,开始初始化 command client', tag: 'SingBox');
// 🔑 UI // 🔑 UI
Future.delayed(const Duration(milliseconds: 1000), () async { Future.delayed(const Duration(milliseconds: 1000), () async {
try { try {
KRLogUtil.kr_i('📊 开始订阅统计数据流...', tag: 'SingBox'); KRLogUtil.kr_i('📊 开始订阅统计数据流...', tag: 'SingBox');
@ -1148,24 +1147,6 @@ class KRSingBoxImp {
}); });
} }
// 🔧
try {
KRLogUtil.kr_i('📋 开始订阅分组数据流...', tag: 'SingBox');
_kr_subscribeToGroups();
KRLogUtil.kr_i('✅ 分组数据流订阅成功', tag: 'SingBox');
} catch (e) {
KRLogUtil.kr_w('⚠️ 分组数据流订阅失败(稍后重试): $e', tag: 'SingBox');
//
Future.delayed(const Duration(milliseconds: 2000), () {
try {
_kr_subscribeToGroups();
KRLogUtil.kr_i('✅ 分组数据流重试订阅成功', tag: 'SingBox');
} catch (e2) {
KRLogUtil.kr_e('❌ 分组数据流重试订阅失败: $e2', tag: 'SingBox');
}
});
}
// 🔧 // 🔧
try { try {
final selectedNode = await KRSecureStorage().kr_readData(key: _keySelectedNode); final selectedNode = await KRSecureStorage().kr_readData(key: _keySelectedNode);

View File

@ -100,38 +100,24 @@ class KRSecureStorage {
return hash.bytes; return hash.bytes;
} }
// 🔧 box //
Future<Box<dynamic>> _ensureBoxOpen() async { Box<dynamic> get _box => Hive.box(_boxName);
if (!Hive.isBoxOpen(_boxName)) {
KRLogUtil.kr_w('⚠️ Box 未打开,重新打开: $_boxName', tag: 'SecureStorage');
final key = HiveAesCipher(_generateKey());
await Hive.openBox(_boxName, encryptionCipher: key);
KRLogUtil.kr_i('✅ Box 已重新打开', tag: 'SecureStorage');
}
return Hive.box(_boxName);
}
// //
Future<void> kr_saveData({required String key, required String value}) async { Future<void> kr_saveData({required String key, required String value}) async {
try { try {
final box = await _ensureBoxOpen(); await _box.put(key, value);
await box.put(key, value);
KRLogUtil.kr_i('✅ 数据已保存: $key', tag: 'SecureStorage');
} catch (e) { } catch (e) {
KRLogUtil.kr_e('❌ 存储数据失败: $e', tag: 'SecureStorage'); KRLogUtil.kr_e('存储数据失败: $e', tag: 'SecureStorage');
rethrow; //
} }
} }
// //
Future<String?> kr_readData({required String key}) async { Future<String?> kr_readData({required String key}) async {
try { try {
final box = await _ensureBoxOpen(); return _box.get(key) as String?;
final value = box.get(key) as String?;
KRLogUtil.kr_i('📖 读取数据: $key = ${value != null ? "存在" : "null"}', tag: 'SecureStorage');
return value;
} catch (e) { } catch (e) {
KRLogUtil.kr_e('读取数据失败: $e', tag: 'SecureStorage'); KRLogUtil.kr_e('读取数据失败: $e', tag: 'SecureStorage');
return null; return null;
} }
} }
@ -139,32 +125,27 @@ class KRSecureStorage {
// //
Future<void> kr_deleteData({required String key}) async { Future<void> kr_deleteData({required String key}) async {
try { try {
final box = await _ensureBoxOpen(); await _box.delete(key);
await box.delete(key);
KRLogUtil.kr_i('🗑️ 数据已删除: $key', tag: 'SecureStorage');
} catch (e) { } catch (e) {
KRLogUtil.kr_e('删除数据失败: $e', tag: 'SecureStorage'); KRLogUtil.kr_e('删除数据失败: $e', tag: 'SecureStorage');
} }
} }
// //
Future<void> kr_clearAllData() async { Future<void> kr_clearAllData() async {
try { try {
final box = await _ensureBoxOpen(); await _box.clear();
await box.clear();
KRLogUtil.kr_i('🧹 所有数据已清除', tag: 'SecureStorage');
} catch (e) { } catch (e) {
KRLogUtil.kr_e('清除数据失败: $e', tag: 'SecureStorage'); KRLogUtil.kr_e('清除数据失败: $e', tag: 'SecureStorage');
} }
} }
// //
Future<bool> kr_hasKey({required String key}) async { Future<bool> kr_hasKey({required String key}) async {
try { try {
final box = await _ensureBoxOpen(); return _box.containsKey(key);
return box.containsKey(key);
} catch (e) { } catch (e) {
KRLogUtil.kr_e('检查键失败: $e', tag: 'SecureStorage'); KRLogUtil.kr_e('检查键失败: $e', tag: 'SecureStorage');
return false; return false;
} }
} }
@ -172,20 +153,18 @@ class KRSecureStorage {
// //
Future<void> kr_saveBool({required String key, required bool value}) async { Future<void> kr_saveBool({required String key, required bool value}) async {
try { try {
final box = await _ensureBoxOpen(); await _box.put(key, value);
await box.put(key, value);
} catch (e) { } catch (e) {
KRLogUtil.kr_e('存储布尔值失败: $e', tag: 'SecureStorage'); KRLogUtil.kr_e('存储布尔值失败: $e', tag: 'SecureStorage');
} }
} }
// //
Future<bool?> kr_getBool({required String key}) async { Future<bool?> kr_getBool({required String key}) async {
try { try {
final box = await _ensureBoxOpen(); return _box.get(key) as bool?;
return box.get(key) as bool?;
} catch (e) { } catch (e) {
KRLogUtil.kr_e('读取布尔值失败: $e', tag: 'SecureStorage'); KRLogUtil.kr_e('读取布尔值失败: $e', tag: 'SecureStorage');
return null; return null;
} }
} }
@ -193,20 +172,18 @@ class KRSecureStorage {
// //
Future<void> kr_saveInt({required String key, required int value}) async { Future<void> kr_saveInt({required String key, required int value}) async {
try { try {
final box = await _ensureBoxOpen(); await _box.put(key, value);
await box.put(key, value);
} catch (e) { } catch (e) {
KRLogUtil.kr_e('存储整数失败: $e', tag: 'SecureStorage'); KRLogUtil.kr_e('存储整数失败: $e', tag: 'SecureStorage');
} }
} }
// //
Future<int?> kr_getInt({required String key}) async { Future<int?> kr_getInt({required String key}) async {
try { try {
final box = await _ensureBoxOpen(); return _box.get(key) as int?;
return box.get(key) as int?;
} catch (e) { } catch (e) {
KRLogUtil.kr_e('读取整数失败: $e', tag: 'SecureStorage'); KRLogUtil.kr_e('读取整数失败: $e', tag: 'SecureStorage');
return null; return null;
} }
} }