feat: 提交国家分组功能和debug功能
This commit is contained in:
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user