feat: 提交国家分组功能和debug功能

This commit is contained in:
2025-11-16 22:50:09 -08:00
parent 76e83e0135
commit 2a1ee3018d
9 changed files with 762 additions and 269 deletions
@@ -12,6 +12,15 @@ class HINodeListController extends GetxController {
/// 首页服务
final KRHomeController homeController = Get.find<KRHomeController>();
/// 调试模式状态
final RxBool isDebugMode = false.obs;
/// 模式按钮点击计数器
int modeButtonClickCount = 0;
/// 最后一次点击时间
DateTime? lastModeButtonClickTime;
/// 获取连接类型字符串
String kr_getConnectionTypeString() {
final connectionType = KRSingBoxImp.instance.kr_connectionType.value;
@@ -41,4 +50,48 @@ class HINodeListController extends GetxController {
}
}
/// 处理模式按钮点击(用于激活调试模式)
void kr_handleModeButtonClick() {
final now = DateTime.now();
// 检查是否在2秒内连续点击
if (lastModeButtonClickTime != null &&
now.difference(lastModeButtonClickTime!).inSeconds > 2) {
// 超过2秒,重置计数器
modeButtonClickCount = 0;
}
modeButtonClickCount++;
lastModeButtonClickTime = now;
KRLogUtil.kr_i('模式按钮点击次数: $modeButtonClickCount', tag: 'HINodeListController');
if (modeButtonClickCount >= 5) {
// 激活调试模式
isDebugMode.value = true;
modeButtonClickCount = 0; // 重置计数器
KRLogUtil.kr_i('🐛 调试模式已激活!', tag: 'HINodeListController');
}
}
/// 获取要显示的节点列表(根据调试模式过滤)
List<dynamic> kr_getFilteredNodeList() {
if (isDebugMode.value) {
// 调试模式:显示所有节点
return kr_subscribeService.allList;
} else {
// 正常模式:只显示 country-auto 节点
return kr_subscribeService.allList.where((node) => node.tag.endsWith('-auto')).toList();
}
}
/// 重置调试模式
void kr_resetDebugMode() {
isDebugMode.value = false;
modeButtonClickCount = 0;
lastModeButtonClickTime = null;
KRLogUtil.kr_i('调试模式已重置', tag: 'HINodeListController');
}
}
@@ -231,8 +231,9 @@ class HINodeListView extends GetView<HINodeListController> {
padding: EdgeInsets.symmetric(vertical: 8.w),
// 2. 使用 children 属性,并一次性构建所有列表项
children: [
if (controller.kr_subscribeService.allList.isEmpty)
_buildEmptyListPlaceholder(context, AppTranslations.kr_home.noNodes)
if (controller.kr_getFilteredNodeList().isEmpty)
_buildEmptyListPlaceholder(context,
controller.isDebugMode.value ? '调试模式:无节点数据' : AppTranslations.kr_home.noNodes)
else ...[
InkWell(
// 🔧 修复:改为 async,等待节点切换完成后再关闭列表
@@ -292,13 +293,28 @@ class HINodeListView extends GetView<HINodeListController> {
),
),
// 2. 第二个 Text: "根据网络IP自动匹配最快线路"
Text(
'根据网络IP自动匹配最快线路', // 您指定的文本
style: KrAppTextStyle(
fontSize: 10,
color: Colors.white,
),
),
Obx(() {
// 当选择全局 auto 时,显示当前选中的节点信息
if (controller.homeController.kr_cutTag.value == 'auto') {
final autoNodeInfo = controller.homeController.kr_getGlobalAutoSelectedNode();
if (autoNodeInfo != null) {
return Text(
'当前: ${autoNodeInfo['tag']} (${autoNodeInfo['delay']}ms)',
style: KrAppTextStyle(
fontSize: 10,
color: Colors.white.withOpacity(0.8),
),
);
}
}
return Text(
'根据网络IP自动匹配最快线路', // 默认文本
style: KrAppTextStyle(
fontSize: 10,
color: Colors.white,
),
);
}),
],
),
),
@@ -319,7 +335,7 @@ class HINodeListView extends GetView<HINodeListController> {
),
),
),
...controller.kr_subscribeService.allList.map((item) {
...controller.kr_getFilteredNodeList().map((item) {
return InkWell(
// 🔧 修复:改为 async,等待节点切换完成后再关闭列表
onTap: () async {
@@ -390,78 +406,75 @@ class HINodeListView extends GetView<HINodeListController> {
KRCountryFlag(countryCode: item.country, width: 30.w, height: 20.w, isCircle: false, maintainSize: false),
SizedBox(width: 12.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Flexible(
child: Text(
'${controller.homeController.kr_getCountryFullName(item.country)}-${item.tag}',
style: KrAppTextStyle(fontSize: 14, color: Colors.white),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
Obx(() => controller.homeController.kr_cutTag.value == item.tag
? Container(
margin: EdgeInsets.only(left: 4.w),
padding: EdgeInsets.symmetric(horizontal: 4.w, vertical: 1.w),
decoration: BoxDecoration(
color: krModernGreenLight.withOpacity(0.1),
borderRadius: BorderRadius.circular(4.w),
),
child: Text(
AppTranslations.kr_home.selected,
style: KrAppTextStyle(fontSize: 10, color: krModernGreen, fontWeight: FontWeight.w500),
),
)
: const SizedBox.shrink()),
],
child: Obx(() {
final isDebug = controller.isDebugMode.value;
final text = isDebug
? '${controller.homeController.kr_getCountryFullName(item.country)} - ${item.tag}'
: item.country;
return Text(
text,
style: KrAppTextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.white,
),
SizedBox(height: 2.w),
Obx(() {
// 1. 获取延迟值和测速状态
int displayDelay = item.urlTestDelay.value;
bool isTesting = controller.homeController.kr_isLatency.value;
// 2. 声明文本和颜色变量
String delayText;
Color delayColor;
// 3. 根据状态设置文本和颜色
if (isTesting && displayDelay == 0) {
delayText = '测速中...';
delayColor = Colors.grey; // 测速时使用灰色
} else if (displayDelay == 0) {
delayText = '- ms'; // 未测速或初始状态
delayColor = Colors.grey;
} else if (displayDelay >= 3000) {
delayText = AppTranslations.kr_home.timeout; // "超时"
delayColor = Colors.red; // 超时状态使用红色
} else {
delayText = '${displayDelay}ms';
// 正常延迟,根据快慢设置不同颜色
delayColor = (displayDelay < 500) ? krModernGreen : Colors.orange;
}
// 4. 返回最终的 Text 组件
return Text(
delayText,
style: KrAppTextStyle(
fontSize: 10,
color: delayColor, // 使用动态计算出的颜色
fontWeight: FontWeight.w500,
),
);
}),
Text(
item.city,
style: KrAppTextStyle(fontSize: 12, color: Theme.of(context).textTheme.bodySmall?.color),
),
],
),
);
}),
),
Obx(() {
// 1. 获取延迟值和测速状态
int displayDelay;
bool isTesting = controller.homeController.kr_isLatency.value;
// 极简逻辑:只根据节点类型决定显示方式
print('🔄 _kr_buildNodeListItem节点: item.tag=${item.tag}, country=${item.country}');
// 如果节点本身是auto组节点,显示组内最快节点的速度
if (item.tag.endsWith('-auto')) {
print('🎯 检测到auto组节点,获取最快节点信息');
final autoNodeInfo = controller.homeController.kr_getCountryAutoSelectedNode(item.country);
print('📊 _kr_buildNodeListItem获取auto最快节点: $autoNodeInfo');
displayDelay = autoNodeInfo?['delay'] ?? 0;
print('✅ _kr_buildNodeListItem使用auto最快节点延迟: $displayDelay');
} else {
// 普通节点,直接显示节点自身的速度
displayDelay = item.urlTestDelay.value;
print('🔄 _kr_buildNodeListItem使用普通节点延迟: $displayDelay');
}
// 2. 声明文本和颜色变量
String delayText;
Color delayColor;
// 3. 根据状态设置文本和颜色
if (isTesting && displayDelay == 0) {
delayText = '测速中...';
delayColor = Colors.grey; // 测速时使用灰色
} else if (displayDelay == 0) {
delayText = '- ms'; // 未测速或初始状态
delayColor = Colors.grey;
} else if (displayDelay >= 3000) {
delayText = AppTranslations.kr_home.timeout; // "超时"
delayColor = Colors.red; // 超时状态使用红色
} else {
delayText = '${displayDelay}ms';
// 正常延迟,根据快慢设置不同颜色
delayColor = (displayDelay < 500) ? krModernGreen : Colors.orange;
}
// 4. 返回最终的 Text 组件
return Text(
delayText,
style: KrAppTextStyle(
fontSize: 10,
color: delayColor, // 使用动态计算出的颜色
fontWeight: FontWeight.w500,
),
);
}),
SizedBox(width: 12.w),
Obx(() => controller.homeController.kr_cutTag.value == item.tag
? KrLocalImage(
imageName: 'radio-active-icon',
@@ -23,7 +23,49 @@ class HINodePageView extends GetView<HINodeListController> {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 模式切换器
Positioned(
left: 0, // ⭐ 所有内容整体贴到左边
child: Obx(() => controller.isDebugMode.value
? GestureDetector(
onTap: () {
controller.kr_resetDebugMode();
Get.snackbar(
'调试模式',
'已关闭调试模式',
snackPosition: SnackPosition.BOTTOM,
duration: const Duration(seconds: 2),
);
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 4.w),
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.8),
borderRadius: BorderRadius.circular(12.w),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.bug_report,
size: 12.w,
color: Colors.white,
),
SizedBox(width: 3.w),
Text(
'关闭调试',
style: TextStyle(
fontSize: 10.sp,
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
],
),
),
)
: const SizedBox.shrink()),
),
// 模式切换器
Padding(
padding: EdgeInsets.only(left: 100.w, right: 60.w),
child: Row(
@@ -159,7 +201,12 @@ class HINodePageView extends GetView<HINodeListController> {
}) {
return Expanded(
child: GestureDetector(
onTap: onTap,
onTap: () {
// 处理模式按钮点击(用于调试模式激活)
controller.kr_handleModeButtonClick();
// 执行原有的点击逻辑
onTap();
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: EdgeInsets.symmetric(vertical: 4.w),