Compare commits
4 Commits
b8d0417d0f
...
7a223d614b
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a223d614b | |||
| 0ec2f72a93 | |||
| 1a1c692ae0 | |||
| dee7f0a591 |
@ -1,4 +1,4 @@
|
|||||||
org.gradle.jvmargs=-Xlint:-options
|
org.gradle.jvmargs=-Xmx4048m -Dfile.encoding=UTF-8
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
# org.gradle.java.home=/Users/mac/Library/Java/JavaVirtualMachines/ms-17.0.16/Contents/Home
|
# org.gradle.java.home=/Users/mac/Library/Java/JavaVirtualMachines/ms-17.0.16/Contents/Home
|
||||||
|
|||||||
BIN
assets/geosite/geoip-cn.srs
Normal file
BIN
assets/geosite/geoip-cn.srs
Normal file
Binary file not shown.
BIN
assets/geosite/geosite-cn.srs
Normal file
BIN
assets/geosite/geosite-cn.srs
Normal file
Binary file not shown.
@ -75,7 +75,7 @@
|
|||||||
"codeSentCountdown": "验证码已发送 {seconds}s",
|
"codeSentCountdown": "验证码已发送 {seconds}s",
|
||||||
"and": "和",
|
"and": "和",
|
||||||
"enterInviteCode": "请输入邀请码",
|
"enterInviteCode": "请输入邀请码",
|
||||||
"registerSuccess": "注册成功"
|
"registerSuccess": "注册成功",
|
||||||
"search": "搜索",
|
"search": "搜索",
|
||||||
"selectOtherRegion": "选择其他地区"
|
"selectOtherRegion": "选择其他地区"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1255,7 +1255,7 @@ class AppConfig {
|
|||||||
/// 建议:
|
/// 建议:
|
||||||
/// - 测试版本、Beta 版本:设置为 true
|
/// - 测试版本、Beta 版本:设置为 true
|
||||||
/// - 正式生产版本:根据需要设置为 false(或在遇到问题时临时开启)
|
/// - 正式生产版本:根据需要设置为 false(或在遇到问题时临时开启)
|
||||||
static const bool enableInitLogCollection = true;
|
static const bool enableInitLogCollection = false;
|
||||||
|
|
||||||
/// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
/// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
/// 加密密钥配置
|
/// 加密密钥配置
|
||||||
|
|||||||
@ -528,8 +528,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
// 添加更详细的状态监听
|
// 添加更详细的状态监听
|
||||||
ever(KRSingBoxImp.instance.kr_status, (status) {
|
ever(KRSingBoxImp.instance.kr_status, (status) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
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');
|
||||||
|
|
||||||
@ -558,8 +557,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
case SingboxStarted():
|
case SingboxStarted():
|
||||||
KRLogUtil.kr_i('🟢 状态: 已启动', tag: 'HomeController');
|
KRLogUtil.kr_i('🟢 状态: 已启动', tag: 'HomeController');
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 状态变为 Started, 当前延迟=${kr_currentNodeLatency.value}');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 取消连接超时处理
|
// 取消连接超时处理
|
||||||
_cancelConnectionTimeout();
|
_cancelConnectionTimeout();
|
||||||
@ -572,13 +570,11 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
// 🔧 关键修复:如果延迟还是-1(连接中状态),立即设置为0(已连接但延迟未知)
|
// 🔧 关键修复:如果延迟还是-1(连接中状态),立即设置为0(已连接但延迟未知)
|
||||||
if (kr_currentNodeLatency.value == -1) {
|
if (kr_currentNodeLatency.value == -1) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 强制将延迟从 -1 更新为 0');
|
}
|
||||||
}
|
|
||||||
kr_currentNodeLatency.value = 0;
|
kr_currentNodeLatency.value = 0;
|
||||||
kr_currentNodeLatency.refresh(); // 强制刷新延迟值
|
kr_currentNodeLatency.refresh(); // 强制刷新延迟值
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 延迟值已刷新');
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔧 修复:立即尝试更新延迟值
|
// 🔧 修复:立即尝试更新延迟值
|
||||||
@ -589,8 +585,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
// 强制更新UI
|
// 强制更新UI
|
||||||
update();
|
update();
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 状态更新完成,当前延迟=${kr_currentNodeLatency.value}');
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SingboxStopping():
|
case SingboxStopping():
|
||||||
KRLogUtil.kr_i('🟠 状态: 正在停止', tag: 'HomeController');
|
KRLogUtil.kr_i('🟠 状态: 正在停止', tag: 'HomeController');
|
||||||
@ -677,15 +672,13 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
|
|
||||||
KRLogUtil.kr_i('🔵 toggleSwitch 被调用: value=$value, currentStatus=$currentStatus', tag: 'HomeController');
|
KRLogUtil.kr_i('🔵 toggleSwitch 被调用: value=$value, currentStatus=$currentStatus', tag: 'HomeController');
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 toggleSwitch: value=$value, currentStatus=$currentStatus');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 🔧 关键: 如果正在切换中,直接忽略(参考 hiddify-app 的 "switching status, debounce")
|
// 🔧 关键: 如果正在切换中,直接忽略(参考 hiddify-app 的 "switching status, debounce")
|
||||||
if (currentStatus is SingboxStarting || currentStatus is SingboxStopping) {
|
if (currentStatus is SingboxStarting || currentStatus is SingboxStopping) {
|
||||||
KRLogUtil.kr_i('🔄 正在切换中,忽略本次操作 (当前状态: $currentStatus)', tag: 'HomeController');
|
KRLogUtil.kr_i('🔄 正在切换中,忽略本次操作 (当前状态: $currentStatus)', tag: 'HomeController');
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 忽略操作:正在切换中');
|
}
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,13 +687,11 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
// 开启连接
|
// 开启连接
|
||||||
KRLogUtil.kr_i('🔄 开始连接...', tag: 'HomeController');
|
KRLogUtil.kr_i('🔄 开始连接...', tag: 'HomeController');
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 执行 kr_start()');
|
}
|
||||||
}
|
|
||||||
await KRSingBoxImp.instance.kr_start();
|
await KRSingBoxImp.instance.kr_start();
|
||||||
KRLogUtil.kr_i('✅ 连接命令已发送', tag: 'HomeController');
|
KRLogUtil.kr_i('✅ 连接命令已发送', tag: 'HomeController');
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 kr_start() 完成');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 🔧 修复: 等待状态更新,最多3秒
|
// 🔧 修复: 等待状态更新,最多3秒
|
||||||
await _waitForStatus(SingboxStarted, maxSeconds: 3);
|
await _waitForStatus(SingboxStarted, maxSeconds: 3);
|
||||||
@ -708,8 +699,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
// 关闭连接
|
// 关闭连接
|
||||||
KRLogUtil.kr_i('🛑 开始断开连接...', tag: 'HomeController');
|
KRLogUtil.kr_i('🛑 开始断开连接...', tag: 'HomeController');
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
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: () {
|
||||||
@ -719,8 +709,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
);
|
);
|
||||||
KRLogUtil.kr_i('✅ 断开命令已发送', tag: 'HomeController');
|
KRLogUtil.kr_i('✅ 断开命令已发送', tag: 'HomeController');
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 kr_stop() 完成');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 🔧 修复: 等待状态更新,最多2秒
|
// 🔧 修复: 等待状态更新,最多2秒
|
||||||
await _waitForStatus(SingboxStopped, maxSeconds: 2);
|
await _waitForStatus(SingboxStopped, maxSeconds: 2);
|
||||||
@ -728,34 +717,29 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
KRLogUtil.kr_e('❌ 切换失败: $e', tag: 'HomeController');
|
KRLogUtil.kr_e('❌ 切换失败: $e', tag: 'HomeController');
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 切换失败: $e');
|
}
|
||||||
}
|
|
||||||
// 发生错误时强制同步状态
|
// 发生错误时强制同步状态
|
||||||
kr_forceSyncConnectionStatus();
|
kr_forceSyncConnectionStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 toggleSwitch 完成,当前 kr_isConnected=${kr_isConnected.value}');
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 🔧 等待状态达到预期值
|
/// 🔧 等待状态达到预期值
|
||||||
Future<void> _waitForStatus(Type expectedType, {int maxSeconds = 3}) async {
|
Future<void> _waitForStatus(Type expectedType, {int maxSeconds = 3}) async {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 等待状态变为: $expectedType');
|
}
|
||||||
}
|
|
||||||
final startTime = DateTime.now();
|
final startTime = DateTime.now();
|
||||||
|
|
||||||
while (DateTime.now().difference(startTime).inSeconds < maxSeconds) {
|
while (DateTime.now().difference(startTime).inSeconds < maxSeconds) {
|
||||||
final currentStatus = KRSingBoxImp.instance.kr_status.value;
|
final currentStatus = KRSingBoxImp.instance.kr_status.value;
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 当前状态: ${currentStatus.runtimeType}');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (currentStatus.runtimeType == expectedType) {
|
if (currentStatus.runtimeType == expectedType) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 状态已达到: $expectedType');
|
}
|
||||||
}
|
|
||||||
// 强制同步确保 kr_isConnected 正确
|
// 强制同步确保 kr_isConnected 正确
|
||||||
kr_forceSyncConnectionStatus();
|
kr_forceSyncConnectionStatus();
|
||||||
return;
|
return;
|
||||||
@ -765,8 +749,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
print('🔵 等待超时,强制同步状态');
|
}
|
||||||
}
|
|
||||||
kr_forceSyncConnectionStatus();
|
kr_forceSyncConnectionStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
||||||
import '../../../localization/app_translations.dart';
|
import '../../../localization/app_translations.dart';
|
||||||
import '../../../widgets/kr_app_text_style.dart';
|
import '../../../widgets/kr_app_text_style.dart';
|
||||||
import '../../../widgets/kr_loading_animation.dart';
|
import '../../../widgets/kr_loading_animation.dart';
|
||||||
@ -107,6 +106,7 @@ class KRHomeBottomPanel extends GetView<KRHomeController> {
|
|||||||
// 未订阅(包括未登录):始终显示订阅卡片
|
// 未订阅(包括未登录):始终显示订阅卡片
|
||||||
Builder(builder: (context) {
|
Builder(builder: (context) {
|
||||||
KRLogUtil.kr_i('🔹 渲染订阅卡片,margin: top=${12}, left=${12}, right=${12}', tag: 'HomeBottomPanel');
|
KRLogUtil.kr_i('🔹 渲染订阅卡片,margin: top=${12}, left=${12}, right=${12}', tag: 'HomeBottomPanel');
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.only(top: 12, left: 12, right: 12),
|
margin: EdgeInsets.only(top: 12, left: 12, right: 12),
|
||||||
child: const KRSubscriptionCard(),
|
child: const KRSubscriptionCard(),
|
||||||
@ -160,7 +160,7 @@ class KRHomeBottomPanel extends GetView<KRHomeController> {
|
|||||||
padding: EdgeInsets.all(16),
|
padding: EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Get.context!.theme.cardColor,
|
color: Get.context!.theme.cardColor,
|
||||||
borderRadius: BorderRadius.circular(12.r),
|
borderRadius: BorderRadius.circular(12),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withOpacity(0.1),
|
color: Colors.black.withOpacity(0.1),
|
||||||
@ -180,7 +180,7 @@ class KRHomeBottomPanel extends GetView<KRHomeController> {
|
|||||||
Text(
|
Text(
|
||||||
'正在加载...',
|
'正在加载...',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.sp,
|
fontSize: 14,
|
||||||
color: Get.context!.theme.textTheme.bodyMedium?.color,
|
color: Get.context!.theme.textTheme.bodyMedium?.color,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -233,7 +233,7 @@ class KRHomeBottomPanel extends GetView<KRHomeController> {
|
|||||||
foregroundColor: Theme.of(context).colorScheme.onPrimary,
|
foregroundColor: Theme.of(context).colorScheme.onPrimary,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8.r),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
||||||
import '../../../widgets/kr_simple_loading.dart';
|
import '../../../widgets/kr_simple_loading.dart';
|
||||||
import 'package:kaer_with_panels/app/widgets/kr_country_flag.dart';
|
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';
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.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/widgets/kr_app_text_style.dart';
|
import 'package:kaer_with_panels/app/widgets/kr_app_text_style.dart';
|
||||||
import 'package:kaer_with_panels/app/widgets/kr_local_image.dart';
|
import 'package:kaer_with_panels/app/widgets/kr_local_image.dart';
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.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/widgets/kr_app_text_style.dart';
|
import 'package:kaer_with_panels/app/widgets/kr_app_text_style.dart';
|
||||||
import 'package:kaer_with_panels/app/widgets/kr_country_flag.dart';
|
import 'package:kaer_with_panels/app/widgets/kr_country_flag.dart';
|
||||||
@ -71,20 +70,20 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
/// 构建专用服务器列表
|
/// 构建专用服务器列表
|
||||||
Widget _buildServerList(BuildContext context) {
|
Widget _buildServerList(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
width: ScreenUtil().screenWidth,
|
width: MediaQuery.of(context).size.width,
|
||||||
height: 360.h, // 减小高度比例
|
height: 360, // 减小高度比例
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).primaryColor,
|
color: Theme.of(context).primaryColor,
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(20.w),
|
topLeft: Radius.circular(20),
|
||||||
topRight: Radius.circular(20.w),
|
topRight: Radius.circular(20),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// 标题栏
|
// 标题栏
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
@ -103,7 +102,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
},
|
},
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.close,
|
Icons.close,
|
||||||
size: 24.w,
|
size: 24,
|
||||||
color: Theme.of(context).textTheme.bodyMedium?.color,
|
color: Theme.of(context).textTheme.bodyMedium?.color,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -125,19 +124,19 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||||
itemCount: controller.kr_subscribeService.groupOutboundList.length,
|
itemCount: controller.kr_subscribeService.groupOutboundList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final group =
|
final group =
|
||||||
controller.kr_subscribeService.groupOutboundList[index];
|
controller.kr_subscribeService.groupOutboundList[index];
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.only(bottom: 8.w),
|
margin: EdgeInsets.only(bottom: 8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).cardColor,
|
color: Theme.of(context).cardColor,
|
||||||
borderRadius: BorderRadius.circular(12.w),
|
borderRadius: BorderRadius.circular(12),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||||
width: 1.w,
|
width: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
@ -146,18 +145,18 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
controller.kr_currentListStatus.value =
|
controller.kr_currentListStatus.value =
|
||||||
KRHomeViewsListStatus.kr_serverSubscribeList;
|
KRHomeViewsListStatus.kr_serverSubscribeList;
|
||||||
},
|
},
|
||||||
borderRadius: BorderRadius.circular(12.w),
|
borderRadius: BorderRadius.circular(12),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(12.w),
|
padding: EdgeInsets.all(12),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
KRNetworkImage(
|
KRNetworkImage(
|
||||||
kr_imageUrl: group.icon,
|
kr_imageUrl: group.icon,
|
||||||
kr_width: 32.w,
|
kr_width: 32,
|
||||||
kr_height: 32.w,
|
kr_height: 32,
|
||||||
kr_fit: BoxFit.cover,
|
kr_fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
SizedBox(width: 12.w),
|
SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
group.tag,
|
group.tag,
|
||||||
@ -171,7 +170,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
),
|
),
|
||||||
Icon(
|
Icon(
|
||||||
Icons.arrow_forward_ios,
|
Icons.arrow_forward_ios,
|
||||||
size: 16.w,
|
size: 16,
|
||||||
color: Theme.of(context).textTheme.bodySmall?.color,
|
color: Theme.of(context).textTheme.bodySmall?.color,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -208,7 +207,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
return _kr_buildListContainer(
|
return _kr_buildListContainer(
|
||||||
context,
|
context,
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
padding: EdgeInsets.fromLTRB(16.w, 8.w, 16.w, 0),
|
padding: EdgeInsets.fromLTRB(16, 8, 16, 0),
|
||||||
itemCount:
|
itemCount:
|
||||||
controller.kr_subscribeService.countryOutboundList.length,
|
controller.kr_subscribeService.countryOutboundList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
@ -222,15 +221,15 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
country.isExpand.value = !country.isExpand.value;
|
country.isExpand.value = !country.isExpand.value;
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(vertical: 12.h),
|
padding: EdgeInsets.symmetric(vertical: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
KRCountryFlag(
|
KRCountryFlag(
|
||||||
countryCode: country.country,
|
countryCode: country.country,
|
||||||
width: 40.w,
|
width: 40,
|
||||||
height: 40.w,
|
height: 40,
|
||||||
),
|
),
|
||||||
SizedBox(width: 12.w),
|
SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -255,7 +254,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
country.isExpand.value
|
country.isExpand.value
|
||||||
? Icons.keyboard_arrow_down
|
? Icons.keyboard_arrow_down
|
||||||
: Icons.arrow_forward_ios,
|
: Icons.arrow_forward_ios,
|
||||||
size: 16.w,
|
size: 16,
|
||||||
color:
|
color:
|
||||||
Theme.of(context).textTheme.bodySmall?.color,
|
Theme.of(context).textTheme.bodySmall?.color,
|
||||||
);
|
);
|
||||||
@ -272,7 +271,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: NeverScrollableScrollPhysics(),
|
physics: NeverScrollableScrollPhysics(),
|
||||||
padding: EdgeInsets.only(left: 24.w),
|
padding: EdgeInsets.only(left: 24),
|
||||||
itemCount: country.outboundList.length,
|
itemCount: country.outboundList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final server = country.outboundList[index];
|
final server = country.outboundList[index];
|
||||||
@ -311,13 +310,13 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
vertical: 8.h,
|
vertical: 8,
|
||||||
horizontal: 16.w,
|
horizontal: 16,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
// 添加轻微的背景色以区分点击区域
|
// 添加轻微的背景色以区分点击区域
|
||||||
color: Theme.of(context).cardColor,
|
color: Theme.of(context).cardColor,
|
||||||
borderRadius: BorderRadius.circular(8.w),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: _kr_buildNodeListItem(
|
child: _kr_buildNodeListItem(
|
||||||
context,
|
context,
|
||||||
@ -328,9 +327,9 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
// 添加分隔线
|
// 添加分隔线
|
||||||
if (index < country.outboundList.length - 1)
|
if (index < country.outboundList.length - 1)
|
||||||
Divider(
|
Divider(
|
||||||
height: 1.w,
|
height: 1,
|
||||||
indent: 16.w,
|
indent: 16,
|
||||||
endIndent: 16.w,
|
endIndent: 16,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.dividerColor
|
.dividerColor
|
||||||
.withOpacity(0.1),
|
.withOpacity(0.1),
|
||||||
@ -341,7 +340,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
Divider(
|
Divider(
|
||||||
height: 1.w,
|
height: 1,
|
||||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -377,7 +376,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
return _kr_buildListContainer(
|
return _kr_buildListContainer(
|
||||||
context,
|
context,
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
padding: EdgeInsets.fromLTRB(16.w, 16.w, 16.w, 0),
|
padding: EdgeInsets.fromLTRB(16, 16, 16, 0),
|
||||||
itemCount: servers.length,
|
itemCount: servers.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final server = servers[index];
|
final server = servers[index];
|
||||||
@ -406,7 +405,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(vertical: 4.h),
|
padding: EdgeInsets.symmetric(vertical: 4),
|
||||||
child: _kr_buildNodeListItem(
|
child: _kr_buildNodeListItem(
|
||||||
context,
|
context,
|
||||||
item: server,
|
item: server,
|
||||||
@ -415,7 +414,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
),
|
),
|
||||||
if (index < servers.length - 1)
|
if (index < servers.length - 1)
|
||||||
Divider(
|
Divider(
|
||||||
height: 1.w,
|
height: 1,
|
||||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -435,12 +434,12 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
required Widget listContent,
|
required Widget listContent,
|
||||||
}) {
|
}) {
|
||||||
return Container(
|
return Container(
|
||||||
width: ScreenUtil().screenWidth,
|
width: MediaQuery.of(context).size.width,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).primaryColor,
|
color: Theme.of(context).primaryColor,
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(20.w),
|
topLeft: Radius.circular(20),
|
||||||
topRight: Radius.circular(20.w),
|
topRight: Radius.circular(20),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -453,13 +452,13 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
onClose: () =>
|
onClose: () =>
|
||||||
controller.kr_currentListStatus.value = KRHomeViewsListStatus.kr_none,
|
controller.kr_currentListStatus.value = KRHomeViewsListStatus.kr_none,
|
||||||
),
|
),
|
||||||
SizedBox(height: 16.h),
|
SizedBox(height: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(child: listContent),
|
Expanded(child: listContent),
|
||||||
// 添加底部间距
|
// 添加底部间距
|
||||||
SizedBox(height: 12.h),
|
SizedBox(height: 12),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -476,7 +475,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
VoidCallback? onClose,
|
VoidCallback? onClose,
|
||||||
}) {
|
}) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 16.w),
|
padding: EdgeInsets.only(left: 16, right: 16, top: 16),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
@ -487,11 +486,11 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
onTap: onBack,
|
onTap: onBack,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.arrow_back_ios,
|
Icons.arrow_back_ios,
|
||||||
size: 20.w,
|
size: 20,
|
||||||
color: Theme.of(context).textTheme.bodyMedium?.color,
|
color: Theme.of(context).textTheme.bodyMedium?.color,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 8.w),
|
SizedBox(width: 8),
|
||||||
],
|
],
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
@ -508,7 +507,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
onTap: onClose,
|
onTap: onClose,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.close,
|
Icons.close,
|
||||||
size: 24.w,
|
size: 24,
|
||||||
color: Theme.of(context).textTheme.bodyMedium?.color,
|
color: Theme.of(context).textTheme.bodyMedium?.color,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -524,10 +523,10 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
required Widget child,
|
required Widget child,
|
||||||
}) {
|
}) {
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.symmetric(horizontal: 16.w),
|
margin: EdgeInsets.symmetric(horizontal: 16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).cardColor,
|
color: Theme.of(context).cardColor,
|
||||||
borderRadius: BorderRadius.circular(12.w),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
@ -553,17 +552,17 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
key: ValueKey(item.id),
|
key: ValueKey(item.id),
|
||||||
padding: EdgeInsets.symmetric(vertical: 8.h),
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
// 🔧 修改:显示国旗代替图标
|
// 🔧 修改:显示国旗代替图标
|
||||||
KRCountryFlag(
|
KRCountryFlag(
|
||||||
countryCode: item.country,
|
countryCode: item.country,
|
||||||
width: 36.w,
|
width: 36,
|
||||||
height: 36.w,
|
height: 36,
|
||||||
),
|
),
|
||||||
SizedBox(width: 8.w),
|
SizedBox(width: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -582,12 +581,12 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
Obx(
|
Obx(
|
||||||
() => controller.kr_cutTag.value == item.tag
|
() => controller.kr_cutTag.value == item.tag
|
||||||
? Container(
|
? Container(
|
||||||
margin: EdgeInsets.only(left: 4.w),
|
margin: EdgeInsets.only(left: 4),
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
horizontal: 4.w, vertical: 1.h),
|
horizontal: 4, vertical: 1),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: krModernGreenLight.withOpacity(0.1),
|
color: krModernGreenLight.withOpacity(0.1),
|
||||||
borderRadius: BorderRadius.circular(4.w),
|
borderRadius: BorderRadius.circular(4),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
AppTranslations.kr_home.selected,
|
AppTranslations.kr_home.selected,
|
||||||
@ -602,7 +601,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 2.h),
|
SizedBox(height: 2),
|
||||||
Text(
|
Text(
|
||||||
item.city,
|
item.city,
|
||||||
style: KrAppTextStyle(
|
style: KrAppTextStyle(
|
||||||
@ -669,20 +668,20 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
return _kr_buildListContainer(
|
return _kr_buildListContainer(
|
||||||
context,
|
context,
|
||||||
child: ListView(
|
child: ListView(
|
||||||
padding: EdgeInsets.fromLTRB(16.w, 0, 16.w, 0),
|
padding: EdgeInsets.fromLTRB(16, 0, 16, 0),
|
||||||
children: [
|
children: [
|
||||||
// 延迟测试按钮作为第一个列表项
|
// 延迟测试按钮作为第一个列表项
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () => controller.kr_urlTest(),
|
onTap: () => controller.kr_urlTest(),
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(vertical: 8.h),
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
margin: EdgeInsets.only(top: 8.w), // 添加上方间距
|
margin: EdgeInsets.only(top: 8), // 添加上方间距
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
width: 36.w,
|
width: 36,
|
||||||
height: 36.w,
|
height: 36,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: krModernGreenLight.withOpacity(0.1),
|
color: krModernGreenLight.withOpacity(0.1),
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
@ -691,17 +690,17 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
child: controller.kr_isLatency.value
|
child: controller.kr_isLatency.value
|
||||||
? KRSimpleLoading(
|
? KRSimpleLoading(
|
||||||
color: krModernGreen,
|
color: krModernGreen,
|
||||||
size: 24.w,
|
size: 24,
|
||||||
duration: const Duration(milliseconds: 800),
|
duration: const Duration(milliseconds: 800),
|
||||||
)
|
)
|
||||||
: Icon(
|
: Icon(
|
||||||
Icons.speed,
|
Icons.speed,
|
||||||
size: 24.w,
|
size: 24,
|
||||||
color: krModernGreen,
|
color: krModernGreen,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 8.w),
|
SizedBox(width: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
@ -728,7 +727,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!controller.kr_isLatency.value) ...[
|
if (!controller.kr_isLatency.value) ...[
|
||||||
SizedBox(height: 2.h),
|
SizedBox(height: 2),
|
||||||
Text(
|
Text(
|
||||||
AppTranslations.kr_home.refreshLatencyDesc,
|
AppTranslations.kr_home.refreshLatencyDesc,
|
||||||
style: KrAppTextStyle(
|
style: KrAppTextStyle(
|
||||||
@ -746,7 +745,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
if (!controller.kr_isLatency.value)
|
if (!controller.kr_isLatency.value)
|
||||||
Icon(
|
Icon(
|
||||||
Icons.arrow_forward_ios,
|
Icons.arrow_forward_ios,
|
||||||
size: 12.w,
|
size: 12,
|
||||||
color: Theme.of(context).textTheme.bodySmall?.color,
|
color: Theme.of(context).textTheme.bodySmall?.color,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -755,7 +754,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
),
|
),
|
||||||
// 分隔线
|
// 分隔线
|
||||||
Divider(
|
Divider(
|
||||||
height: 16.w,
|
height: 16,
|
||||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||||
),
|
),
|
||||||
// Auto 选项
|
// Auto 选项
|
||||||
@ -775,19 +774,19 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(vertical: 8.h),
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
KrLocalImage(
|
KrLocalImage(
|
||||||
imageName: "home_list_location",
|
imageName: "home_list_location",
|
||||||
width: 36.w,
|
width: 36,
|
||||||
height: 36.w,
|
height: 36,
|
||||||
color: controller.kr_cutTag.value == 'auto'
|
color: controller.kr_cutTag.value == 'auto'
|
||||||
? Colors.green
|
? Colors.green
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
SizedBox(width: 8.w),
|
SizedBox(width: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -808,13 +807,13 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
),
|
),
|
||||||
if (controller.kr_cutTag.value == 'auto')
|
if (controller.kr_cutTag.value == 'auto')
|
||||||
Container(
|
Container(
|
||||||
margin: EdgeInsets.only(left: 4.w),
|
margin: EdgeInsets.only(left: 4),
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
horizontal: 4.w, vertical: 1.h),
|
horizontal: 4, vertical: 1),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color:
|
color:
|
||||||
krModernGreenLight.withOpacity(0.1),
|
krModernGreenLight.withOpacity(0.1),
|
||||||
borderRadius: BorderRadius.circular(4.w),
|
borderRadius: BorderRadius.circular(4),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
AppTranslations.kr_home.selected,
|
AppTranslations.kr_home.selected,
|
||||||
@ -827,7 +826,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 2.h),
|
SizedBox(height: 2),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
// 获取当前自动选择的节点
|
// 获取当前自动选择的节点
|
||||||
String selectedNode =
|
String selectedNode =
|
||||||
@ -903,7 +902,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
),
|
),
|
||||||
// 分隔线
|
// 分隔线
|
||||||
Divider(
|
Divider(
|
||||||
height: 16.w,
|
height: 16,
|
||||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||||
),
|
),
|
||||||
// 节点列表
|
// 节点列表
|
||||||
@ -929,7 +928,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(vertical: 4.h),
|
padding: EdgeInsets.symmetric(vertical: 4),
|
||||||
child: _kr_buildNodeListItem(
|
child: _kr_buildNodeListItem(
|
||||||
context,
|
context,
|
||||||
item: node,
|
item: node,
|
||||||
@ -939,7 +938,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
|
|||||||
if (node !=
|
if (node !=
|
||||||
controller.kr_subscribeService.allList.last)
|
controller.kr_subscribeService.allList.last)
|
||||||
Divider(
|
Divider(
|
||||||
height: 1.w,
|
height: 1,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.dividerColor
|
.dividerColor
|
||||||
.withOpacity(0.1),
|
.withOpacity(0.1),
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.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/routes/app_pages.dart';
|
import 'package:kaer_with_panels/app/routes/app_pages.dart';
|
||||||
import 'package:kaer_with_panels/app/utils/kr_subscribe_navigation_util.dart';
|
import 'package:kaer_with_panels/app/utils/kr_subscribe_navigation_util.dart';
|
||||||
|
|
||||||
import '../../../widgets/kr_app_text_style.dart';
|
import '../../../widgets/kr_app_text_style.dart';
|
||||||
|
|
||||||
/// 订阅卡片组件
|
/// 订阅卡片组件
|
||||||
@ -24,13 +21,6 @@ class KRSubscriptionCard extends StatelessWidget {
|
|||||||
|
|
||||||
// 构建订阅卡片
|
// 构建订阅卡片
|
||||||
Widget _kr_buildSubscriptionCard(BuildContext context) {
|
Widget _kr_buildSubscriptionCard(BuildContext context) {
|
||||||
// 🔧 新增:订阅卡片渲染日志
|
|
||||||
print('🎴 [SubscriptionCard] 开始构建订阅卡片');
|
|
||||||
print('🎴 [SubscriptionCard] 卡片颜色: ${Theme.of(context).cardColor}');
|
|
||||||
print('🎴 [SubscriptionCard] 主题亮度: ${Theme.of(context).brightness}');
|
|
||||||
print('🎴 [SubscriptionCard] 文本颜色: ${Theme.of(context).textTheme.bodyMedium?.color}');
|
|
||||||
print('🎴 [SubscriptionCard] ScreenUtil 测试 - 12.w=${12.w}, 16.h=${16.h}, 44.w=${44.w}');
|
|
||||||
|
|
||||||
// 🔧 关键修复:完全移除 ScreenUtil,使用固定像素值避免缩放问题
|
// 🔧 关键修复:完全移除 ScreenUtil,使用固定像素值避免缩放问题
|
||||||
return Container(
|
return Container(
|
||||||
// 添加固定高度,确保卡片可见
|
// 添加固定高度,确保卡片可见
|
||||||
@ -82,7 +72,6 @@ class KRSubscriptionCard extends StatelessWidget {
|
|||||||
height: 46,
|
height: 46,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
print('🎴 [SubscriptionCard] 订阅按钮被点击');
|
|
||||||
KRSubscribeNavigationUtil.navigateToPurchase(tag: 'SubscriptionCard');
|
KRSubscribeNavigationUtil.navigateToPurchase(tag: 'SubscriptionCard');
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
@ -114,10 +103,10 @@ class KRSubscriptionCard extends StatelessWidget {
|
|||||||
bool addBottomPadding = true,
|
bool addBottomPadding = true,
|
||||||
}) {
|
}) {
|
||||||
return Container(
|
return Container(
|
||||||
margin: margin ?? EdgeInsets.symmetric(horizontal: 16.w),
|
margin: margin ?? EdgeInsets.symmetric(horizontal: 16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).cardColor,
|
color: Theme.of(context).cardColor,
|
||||||
borderRadius: BorderRadius.circular(12.w),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: IntrinsicWidth(
|
child: IntrinsicWidth(
|
||||||
child: child,
|
child: child,
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import 'package:kaer_with_panels/app/utils/kr_common_util.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/utils/kr_log_util.dart';
|
import 'package:kaer_with_panels/app/utils/kr_log_util.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
import '../../../common/app_run_data.dart';
|
import '../../../common/app_run_data.dart';
|
||||||
import '../../../common/app_config.dart';
|
import '../../../common/app_config.dart';
|
||||||
@ -13,6 +15,7 @@ import '../../../model/response/kr_payment_methods.dart';
|
|||||||
import '../../../routes/app_pages.dart';
|
import '../../../routes/app_pages.dart';
|
||||||
import '../../../services/api_service/kr_api.user.dart';
|
import '../../../services/api_service/kr_api.user.dart';
|
||||||
import '../../../utils/kr_event_bus.dart';
|
import '../../../utils/kr_event_bus.dart';
|
||||||
|
import '../../../network/http_util.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
/// 会员购买控制器
|
/// 会员购买控制器
|
||||||
@ -47,8 +50,28 @@ class KRPurchaseMembershipController extends GetxController {
|
|||||||
RxInt _kr_balance = 0.obs;
|
RxInt _kr_balance = 0.obs;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() async {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
|
print('💳 [PurchaseMembership] ========== Controller.onInit 被调用 ==========');
|
||||||
|
print('💳 [PurchaseMembership] 当前时间: ${DateTime.now()}');
|
||||||
|
|
||||||
|
// 🔧 紧急诊断:写文件确认购买页面Controller被初始化
|
||||||
|
try {
|
||||||
|
final dir = await getApplicationDocumentsDirectory();
|
||||||
|
final debugFile = File('${dir.path}/PURCHASE_CONTROLLER_DEBUG.txt');
|
||||||
|
await debugFile.writeAsString(
|
||||||
|
'=' * 60 + '\n'
|
||||||
|
'💳 PurchaseMembershipController.onInit 被调用!\n'
|
||||||
|
'时间: ${DateTime.now()}\n'
|
||||||
|
'版本标识: Android15_Fix_v6_Final\n'
|
||||||
|
'=' * 60 + '\n',
|
||||||
|
mode: FileMode.append,
|
||||||
|
);
|
||||||
|
print('💳 [PurchaseMembership] ✅ 调试日志已写入文件: ${debugFile.path}');
|
||||||
|
} catch (e) {
|
||||||
|
print('💳 [PurchaseMembership] ❌ 写入调试日志失败: $e');
|
||||||
|
}
|
||||||
|
|
||||||
kr_initializeData();
|
kr_initializeData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,14 +83,24 @@ class KRPurchaseMembershipController extends GetxController {
|
|||||||
|
|
||||||
/// 初始化数据
|
/// 初始化数据
|
||||||
Future<void> kr_initializeData() async {
|
Future<void> kr_initializeData() async {
|
||||||
|
print('💳 [PurchaseMembership] initializeData 开始');
|
||||||
kr_userEmail.value = KRAppRunData.getInstance().kr_account.toString();
|
kr_userEmail.value = KRAppRunData.getInstance().kr_account.toString();
|
||||||
await kr_getPackageList();
|
print('💳 [PurchaseMembership] 用户邮箱: ${kr_userEmail.value}');
|
||||||
|
|
||||||
|
// 🔧 关键修复:不要在 onInit 中 await,让页面先显示,数据异步加载
|
||||||
|
// 这样可以避免 API 请求卡住导致页面无法显示
|
||||||
|
print('💳 [PurchaseMembership] 开始异步加载套餐数据...');
|
||||||
|
kr_getPackageList().catchError((e) {
|
||||||
|
print('💳 [PurchaseMembership] ❌ 加载套餐数据异常: $e');
|
||||||
|
KRLogUtil.kr_e('加载套餐数据失败: $e', tag: 'PurchaseMembership');
|
||||||
|
});
|
||||||
|
|
||||||
// 监听所有支付相关消息
|
// 监听所有支付相关消息
|
||||||
_kr_eventWorker = KREventBus().kr_listenMessages(
|
_kr_eventWorker = KREventBus().kr_listenMessages(
|
||||||
[KRMessageType.kr_payment, KRMessageType.kr_subscribe_update],
|
[KRMessageType.kr_payment, KRMessageType.kr_subscribe_update],
|
||||||
_kr_handleMessage,
|
_kr_handleMessage,
|
||||||
);
|
);
|
||||||
|
print('💳 [PurchaseMembership] initializeData 完成');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 处理消息
|
/// 处理消息
|
||||||
@ -94,23 +127,102 @@ class KRPurchaseMembershipController extends GetxController {
|
|||||||
|
|
||||||
/// 获取套餐列表和支付方式
|
/// 获取套餐列表和支付方式
|
||||||
Future<void> kr_getPackageList() async {
|
Future<void> kr_getPackageList() async {
|
||||||
|
print('💳 [PurchaseMembership] ========== 开始获取套餐列表 ==========');
|
||||||
|
print('💳 [PurchaseMembership] 当前时间: ${DateTime.now()}');
|
||||||
|
|
||||||
kr_isLoading.value = true;
|
kr_isLoading.value = true;
|
||||||
kr_selectedPlanIndex.value = 0; // 重置套餐选择
|
kr_selectedPlanIndex.value = 0; // 重置套餐选择
|
||||||
kr_selectedDiscountIndex.value = -1; // 重置折扣选择
|
kr_selectedDiscountIndex.value = -1; // 重置折扣选择
|
||||||
kr_selectedPaymentMethodIndex.value = -1; // 重置支付方式选择
|
kr_selectedPaymentMethodIndex.value = -1; // 重置支付方式选择
|
||||||
|
|
||||||
await _iniUserInfo();
|
try {
|
||||||
await kr_getAlreadySubscribe();
|
// 🔧 添加超时保护,避免 API 请求卡死
|
||||||
await kr_fetchPackages();
|
print('💳 [PurchaseMembership] 步骤1: 开始初始化用户信息...');
|
||||||
// await kr_fetchPaymentMethods(); // ⚠️ 后端暂未实现 /v1/app/payment/methods 接口
|
await _iniUserInfo().timeout(
|
||||||
|
const Duration(seconds: 5),
|
||||||
|
onTimeout: () {
|
||||||
|
print('💳 [PurchaseMembership] ⚠️ 初始化用户信息超时');
|
||||||
|
KRLogUtil.kr_w('初始化用户信息超时', tag: 'PurchaseMembership');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
print('💳 [PurchaseMembership] ✓ 步骤1完成');
|
||||||
|
|
||||||
// 获取公开的支付方式
|
print('💳 [PurchaseMembership] 步骤2: 开始获取已订阅套餐...');
|
||||||
await _kr_fetchPublicPaymentMethods();
|
await kr_getAlreadySubscribe().timeout(
|
||||||
|
const Duration(seconds: 5),
|
||||||
|
onTimeout: () {
|
||||||
|
print('💳 [PurchaseMembership] ⚠️ 获取已订阅套餐超时');
|
||||||
|
KRLogUtil.kr_w('获取已订阅套餐超时', tag: 'PurchaseMembership');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
print('💳 [PurchaseMembership] ✓ 步骤2完成');
|
||||||
|
|
||||||
// 根据套餐数量决定是否显示套餐选择器
|
print('💳 [PurchaseMembership] 步骤3: 开始获取套餐列表...');
|
||||||
kr_showPlanSelector.value = kr_plans.length > 1;
|
await kr_fetchPackages().timeout(
|
||||||
|
const Duration(seconds: 8),
|
||||||
|
onTimeout: () {
|
||||||
|
print('💳 [PurchaseMembership] ❌ 获取套餐列表超时');
|
||||||
|
KRLogUtil.kr_e('获取套餐列表超时', tag: 'PurchaseMembership');
|
||||||
|
KRCommonUtil.kr_showToast('获取套餐列表超时,请检查网络');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
print('💳 [PurchaseMembership] ✓ 步骤3完成,套餐数量: ${kr_plans.length}');
|
||||||
|
|
||||||
kr_isLoading.value = false;
|
// 获取公开的支付方式
|
||||||
|
print('💳 [PurchaseMembership] 步骤4: 开始获取支付方式...');
|
||||||
|
await _kr_fetchPublicPaymentMethods().timeout(
|
||||||
|
const Duration(seconds: 5),
|
||||||
|
onTimeout: () {
|
||||||
|
print('💳 [PurchaseMembership] ⚠️ 获取支付方式超时');
|
||||||
|
KRLogUtil.kr_w('获取支付方式超时', tag: 'PurchaseMembership');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
print('💳 [PurchaseMembership] ✓ 步骤4完成,支付方式数量: ${kr_paymentMethods.length}');
|
||||||
|
|
||||||
|
// 根据套餐数量决定是否显示套餐选择器
|
||||||
|
kr_showPlanSelector.value = kr_plans.length > 1;
|
||||||
|
print('💳 [PurchaseMembership] ========== 所有步骤完成 ==========');
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
print('💳 [PurchaseMembership] ❌❌❌ 获取套餐数据失败: $e');
|
||||||
|
print('💳 [PurchaseMembership] StackTrace: $stackTrace');
|
||||||
|
KRLogUtil.kr_e('获取套餐数据失败: $e', tag: 'PurchaseMembership');
|
||||||
|
|
||||||
|
// 🔧 关键修复:API失败时,尝试切换域名并重试
|
||||||
|
print('💳 [PurchaseMembership] 🔄 尝试切换域名并重试...');
|
||||||
|
bool domainSwitched = await KRDomain.kr_switchToNextDomain();
|
||||||
|
|
||||||
|
if (domainSwitched) {
|
||||||
|
print('💳 [PurchaseMembership] ✓ 域名切换成功,当前域名: ${KRDomain.kr_currentDomain}');
|
||||||
|
print('💳 [PurchaseMembership] 🔄 使用新域名重试...');
|
||||||
|
|
||||||
|
// 更新 HttpUtil 的 baseUrl
|
||||||
|
HttpUtil.getInstance().updateBaseUrl();
|
||||||
|
|
||||||
|
// 等待500ms让域名生效
|
||||||
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
|
|
||||||
|
// 重试一次
|
||||||
|
try {
|
||||||
|
await kr_fetchPackages().timeout(
|
||||||
|
const Duration(seconds: 8),
|
||||||
|
onTimeout: () {
|
||||||
|
print('💳 [PurchaseMembership] ❌ 使用新域名后仍然超时');
|
||||||
|
KRLogUtil.kr_e('使用新域名后仍然超时', tag: 'PurchaseMembership');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
print('💳 [PurchaseMembership] ✓ 使用新域名重试成功,套餐数量: ${kr_plans.length}');
|
||||||
|
} catch (retryError) {
|
||||||
|
print('💳 [PurchaseMembership] ❌ 使用新域名重试仍然失败: $retryError');
|
||||||
|
kr_errorMessage.value = '网络连接失败,请检查网络设置';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print('💳 [PurchaseMembership] ❌ 域名切换失败,所有域名都不可用');
|
||||||
|
kr_errorMessage.value = '无法连接服务器,请稍后重试';
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
kr_isLoading.value = false;
|
||||||
|
print('💳 [PurchaseMembership] 加载状态设置为: false');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 初始化用户信息
|
/// 初始化用户信息
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
||||||
import 'dart:io' show Platform;
|
import 'dart:io' show Platform;
|
||||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,7 @@ import 'package:kaer_with_panels/app/modules/kr_home/controllers/kr_home_control
|
|||||||
import 'package:kaer_with_panels/app/modules/kr_home/models/kr_home_views_status.dart';
|
import 'package:kaer_with_panels/app/modules/kr_home/models/kr_home_views_status.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
// import 'package:kaer_with_panels/app/utils/kr_init_log_collector.dart';
|
import 'package:kaer_with_panels/app/utils/kr_init_log_collector.dart';
|
||||||
|
|
||||||
class KRSplashController extends GetxController {
|
class KRSplashController extends GetxController {
|
||||||
// 🔧 新增:初始化日志收集器
|
// 🔧 新增:初始化日志收集器
|
||||||
@ -311,6 +311,115 @@ class KRSplashController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 🔧 Android 15 新增:最小化初始化(降级策略)
|
||||||
|
/// 确保即使网络失败,应用也能启动到可用状态
|
||||||
|
Future<void> _executeMinimalInitialization() async {
|
||||||
|
try {
|
||||||
|
_initLog.logPhaseStart('降级初始化(Minimal Initialization)');
|
||||||
|
_initLog.logWarning('网络初始化失败,执行降级策略', tag: 'Splash');
|
||||||
|
KRLogUtil.kr_i('🛡️ 执行最小化初始化(降级模式)', tag: 'SplashController');
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('🛡️ 执行最小化初始化(降级模式)');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 设置默认域名(确保应用有可用域名)
|
||||||
|
try {
|
||||||
|
_initLog.log('步骤1: 设置默认域名', tag: 'Minimal');
|
||||||
|
if (KRDomain.kr_currentDomain.isEmpty && KRDomain.kr_baseDomains.isNotEmpty) {
|
||||||
|
KRDomain.kr_currentDomain = KRDomain.kr_baseDomains[0];
|
||||||
|
_initLog.logSuccess('设置默认域名: ${KRDomain.kr_currentDomain}', tag: 'Minimal');
|
||||||
|
KRLogUtil.kr_i('✅ 设置默认域名: ${KRDomain.kr_currentDomain}', tag: 'SplashController');
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('✅ 设置默认域名: ${KRDomain.kr_currentDomain}');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_initLog.log('当前域名: ${KRDomain.kr_currentDomain}', tag: 'Minimal');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_initLog.logError('设置默认域名失败', tag: 'Minimal', error: e);
|
||||||
|
KRLogUtil.kr_w('⚠️ 设置默认域名失败: $e', tag: 'SplashController');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 初始化 SingBox(核心功能,不依赖网络)
|
||||||
|
try {
|
||||||
|
_initLog.log('步骤2: 初始化 SingBox', tag: 'Minimal');
|
||||||
|
await KRSingBoxImp.instance.init().timeout(
|
||||||
|
const Duration(seconds: 3),
|
||||||
|
onTimeout: () {
|
||||||
|
_initLog.logWarning('SingBox 初始化超时(3秒)', tag: 'Minimal');
|
||||||
|
KRLogUtil.kr_w('SingBox 初始化超时', tag: 'SplashController');
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('⏱️ SingBox 初始化超时');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
_initLog.logSuccess('SingBox 初始化完成', tag: 'Minimal');
|
||||||
|
KRLogUtil.kr_i('✅ SingBox 初始化完成', tag: 'SplashController');
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('✅ SingBox 初始化完成');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_initLog.logError('SingBox 初始化失败', tag: 'Minimal', error: e);
|
||||||
|
KRLogUtil.kr_w('⚠️ SingBox 初始化失败: $e', tag: 'SplashController');
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('⚠️ SingBox 初始化失败: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 尝试加载本地用户信息(不依赖网络)
|
||||||
|
try {
|
||||||
|
_initLog.log('步骤3: 加载本地用户信息', tag: 'Minimal');
|
||||||
|
await KRAppRunData.getInstance().kr_initializeUserInfo().timeout(
|
||||||
|
const Duration(seconds: 2),
|
||||||
|
onTimeout: () {
|
||||||
|
_initLog.logWarning('用户信息加载超时(2秒)', tag: 'Minimal');
|
||||||
|
KRLogUtil.kr_w('用户信息加载超时', tag: 'SplashController');
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('⏱️ 用户信息加载超时');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
_initLog.logSuccess('本地用户信息加载完成', tag: 'Minimal');
|
||||||
|
KRLogUtil.kr_i('✅ 本地用户信息加载完成', tag: 'SplashController');
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('✅ 本地用户信息加载完成');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_initLog.logError('用户信息加载失败', tag: 'Minimal', error: e);
|
||||||
|
KRLogUtil.kr_w('⚠️ 用户信息加载失败: $e', tag: 'SplashController');
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('⚠️ 用户信息加载失败: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_initLog.logPhaseEnd('降级初始化(Minimal Initialization)', success: true);
|
||||||
|
_initLog.log('应用将以降级模式启动,用户将看到基本UI', tag: 'Minimal');
|
||||||
|
_initLog.log('预期显示:订阅卡片 + 连接选项', tag: 'Minimal');
|
||||||
|
|
||||||
|
KRLogUtil.kr_i('✅ 最小化初始化完成,应用将以降级模式启动', tag: 'SplashController');
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('✅ 最小化初始化完成,应用将以降级模式启动');
|
||||||
|
}
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('📱 用户将看到基本UI(订阅卡片 + 连接选项)');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔧 最小化初始化也不关闭日志
|
||||||
|
// await _initLog.finalize(); // ❌ 注释掉
|
||||||
|
if (kDebugMode && _initLog.getLogFilePath() != null) {
|
||||||
|
print('📁 初始化日志文件(保持打开): ${_initLog.getLogFilePath()}');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_initLog.logError('最小化初始化也失败', tag: 'Minimal', error: e);
|
||||||
|
KRLogUtil.kr_e('❌ 最小化初始化也失败: $e', tag: 'SplashController');
|
||||||
|
if (kDebugMode) {
|
||||||
|
print('❌ 最小化初始化也失败: $e');
|
||||||
|
}
|
||||||
|
// 即使降级初始化失败也不关闭日志
|
||||||
|
// await _initLog.finalize(); // ❌ 注释掉
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 处理错误并显示
|
/// 处理错误并显示
|
||||||
void _handleError(String title, String message) {
|
void _handleError(String title, String message) {
|
||||||
kr_hasError.value = true;
|
kr_hasError.value = true;
|
||||||
|
|||||||
@ -2,16 +2,20 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:loggy/loggy.dart';
|
import 'package:loggy/loggy.dart';
|
||||||
|
|
||||||
/// 日志工具类
|
/// 日志工具类
|
||||||
/// 🔒 Release模式下所有日志都不会输出,确保生产环境的性能和安全
|
/// 🔧 Android 15 诊断模式:临时允许 Release 模式下输出关键日志用于问题诊断
|
||||||
class KRLogUtil {
|
class KRLogUtil {
|
||||||
static final KRLogUtil _instance = KRLogUtil._internal();
|
static final KRLogUtil _instance = KRLogUtil._internal();
|
||||||
factory KRLogUtil() => _instance;
|
factory KRLogUtil() => _instance;
|
||||||
KRLogUtil._internal();
|
KRLogUtil._internal();
|
||||||
|
|
||||||
|
/// 🔧 临时启用 Release 日志用于 Android 15 问题诊断
|
||||||
|
/// ⚠️ 生产环境修复后应该改回 false
|
||||||
|
static const bool _forceEnableReleaseLogging = true;
|
||||||
|
|
||||||
/// 初始化日志
|
/// 初始化日志
|
||||||
static void kr_init() {
|
static void kr_init() {
|
||||||
// 只在 Debug 模式下初始化日志
|
// Debug 模式或强制启用时初始化日志
|
||||||
if (kDebugMode) {
|
if (kDebugMode || _forceEnableReleaseLogging) {
|
||||||
Loggy.initLoggy(
|
Loggy.initLoggy(
|
||||||
logPrinter: PrettyPrinter(),
|
logPrinter: PrettyPrinter(),
|
||||||
);
|
);
|
||||||
@ -19,49 +23,49 @@ class KRLogUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 调试日志
|
/// 调试日志
|
||||||
/// 🔒 只在 Debug 模式下输出
|
/// 🔧 Debug 模式或强制启用时输出
|
||||||
static void kr_d(String message, {String? tag}) {
|
static void kr_d(String message, {String? tag}) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode || _forceEnableReleaseLogging) {
|
||||||
Loggy('${tag ?? 'KRLogUtil'}').debug(message);
|
Loggy('${tag ?? 'KRLogUtil'}').debug(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 信息日志
|
/// 信息日志
|
||||||
/// 🔒 只在 Debug 模式下输出
|
/// 🔧 Debug 模式或强制启用时输出
|
||||||
static void kr_i(String message, {String? tag}) {
|
static void kr_i(String message, {String? tag}) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode || _forceEnableReleaseLogging) {
|
||||||
Loggy('${tag ?? 'KRLogUtil'}').info(message);
|
Loggy('${tag ?? 'KRLogUtil'}').info(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 警告日志
|
/// 警告日志
|
||||||
/// 🔒 只在 Debug 模式下输出
|
/// 🔧 Debug 模式或强制启用时输出
|
||||||
static void kr_w(String message, {String? tag}) {
|
static void kr_w(String message, {String? tag}) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode || _forceEnableReleaseLogging) {
|
||||||
Loggy('${tag ?? 'KRLogUtil'}').warning(message);
|
Loggy('${tag ?? 'KRLogUtil'}').warning(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 错误日志
|
/// 错误日志
|
||||||
/// 🔒 只在 Debug 模式下输出
|
/// 🔧 Debug 模式或强制启用时输出
|
||||||
static void kr_e(String message, {String? tag, Object? error, StackTrace? stackTrace}) {
|
static void kr_e(String message, {String? tag, Object? error, StackTrace? stackTrace}) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode || _forceEnableReleaseLogging) {
|
||||||
Loggy('${tag ?? 'KRLogUtil'}').error(message, error, stackTrace);
|
Loggy('${tag ?? 'KRLogUtil'}').error(message, error, stackTrace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 网络日志
|
/// 网络日志
|
||||||
/// 🔒 只在 Debug 模式下输出
|
/// 🔧 Debug 模式或强制启用时输出
|
||||||
static void kr_network(String message, {String? tag}) {
|
static void kr_network(String message, {String? tag}) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode || _forceEnableReleaseLogging) {
|
||||||
Loggy('${tag ?? 'Network'}').info(message);
|
Loggy('${tag ?? 'Network'}').info(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 性能日志
|
/// 性能日志
|
||||||
/// 🔒 只在 Debug 模式下输出
|
/// 🔧 Debug 模式或强制启用时输出
|
||||||
static void kr_performance(String message, {String? tag}) {
|
static void kr_performance(String message, {String? tag}) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode || _forceEnableReleaseLogging) {
|
||||||
Loggy('${tag ?? 'Performance'}').info(message);
|
Loggy('${tag ?? 'Performance'}').info(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,31 +23,30 @@ class KRSubscribeNavigationUtil {
|
|||||||
KRLogUtil.kr_i('是否设备登录: $isDeviceLogin', tag: tag);
|
KRLogUtil.kr_i('是否设备登录: $isDeviceLogin', tag: tag);
|
||||||
|
|
||||||
if (isDeviceLogin) {
|
if (isDeviceLogin) {
|
||||||
// 设备登录用户需要绑定账号
|
// 设备登录用户 - 显示绑定账号提示对话框
|
||||||
KRLogUtil.kr_i('检测到设备登录,显示绑定提示', tag: tag);
|
KRLogUtil.kr_i('设备登录用户,显示绑定提示', tag: tag);
|
||||||
KRDialog.show(
|
|
||||||
title: AppTranslations.kr_dialog.deviceLoginBindingTitle,
|
try {
|
||||||
message: AppTranslations.kr_dialog.deviceLoginBindingMessage,
|
KRDialog.show(
|
||||||
confirmText: AppTranslations.kr_dialog.kr_ok,
|
title: AppTranslations.kr_dialog.deviceLoginBindingTitle,
|
||||||
cancelText: AppTranslations.kr_dialog.kr_cancel,
|
message: AppTranslations.kr_dialog.deviceLoginBindingMessage,
|
||||||
onConfirm: () {
|
confirmText: AppTranslations.kr_dialog.kr_ok,
|
||||||
Get.back(); // 关闭对话框
|
onConfirm: () {
|
||||||
// 等待对话框完全关闭后再跳转到登录页面
|
|
||||||
Future.delayed(const Duration(milliseconds: 300), () {
|
|
||||||
Get.toNamed(Routes.MR_LOGIN);
|
Get.toNamed(Routes.MR_LOGIN);
|
||||||
});
|
},
|
||||||
},
|
);
|
||||||
onCancel: () => Get.back(),
|
} catch (e) {
|
||||||
);
|
KRLogUtil.kr_e('显示绑定提示对话框失败: $e', tag: tag);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 正常流程 - 跳转到购买页面
|
// 普通登录用户 - 直接跳转到购买页面
|
||||||
KRLogUtil.kr_i('普通用户,跳转到购买页面', tag: tag);
|
KRLogUtil.kr_i('普通用户,跳转到购买页面', tag: tag);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 🔧 添加加载保护,避免页面跳转时卡死
|
|
||||||
Get.toNamed(Routes.KR_PURCHASE_MEMBERSHIP);
|
Get.toNamed(Routes.KR_PURCHASE_MEMBERSHIP);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
KRLogUtil.kr_e('跳转购买页面失败: $e', tag: tag);
|
KRLogUtil.kr_e('跳转购买页面失败: $e', tag: tag);
|
||||||
|
|
||||||
// 如果跳转失败,显示错误提示
|
// 如果跳转失败,显示错误提示
|
||||||
KRDialog.show(
|
KRDialog.show(
|
||||||
title: AppTranslations.kr_dialog.error,
|
title: AppTranslations.kr_dialog.error,
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:kaer_with_panels/app/localization/app_translations.dart';
|
import 'package:kaer_with_panels/app/localization/app_translations.dart';
|
||||||
|
|
||||||
@ -51,35 +50,36 @@ class KRDialog extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildConfirmButton() {
|
Widget _buildConfirmButton() {
|
||||||
|
// 🔧 Android 15 关键修复:完全移除 ScreenUtil,使用固定像素值
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(23.r),
|
borderRadius: BorderRadius.circular(23),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: const Color(0xFF1797FF).withOpacity(0.25),
|
color: const Color(0xFF1797FF).withOpacity(0.25),
|
||||||
blurRadius: 8.r,
|
blurRadius: 8,
|
||||||
offset: Offset(0, 2.w),
|
offset: const Offset(0, 2),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.back();
|
Get.back();
|
||||||
onConfirm?.call();
|
onConfirm?.call();
|
||||||
},
|
},
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
backgroundColor: const Color(0xFF1797FF),
|
backgroundColor: const Color(0xFF1797FF),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(23.r),
|
borderRadius: BorderRadius.circular(23),
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
minimumSize: Size.fromHeight(46.w),
|
minimumSize: const Size.fromHeight(46),
|
||||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
confirmText ?? AppTranslations.kr_dialog.kr_confirm,
|
confirmText ?? AppTranslations.kr_dialog.kr_confirm,
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 15.sp,
|
fontSize: 15,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontFamily: 'AlibabaPuHuiTi-Medium',
|
fontFamily: 'AlibabaPuHuiTi-Medium',
|
||||||
@ -94,26 +94,27 @@ class KRDialog extends StatelessWidget {
|
|||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final isDark = theme.brightness == Brightness.dark;
|
final isDark = theme.brightness == Brightness.dark;
|
||||||
|
|
||||||
|
// 🔧 Android 15 关键修复:完全移除 ScreenUtil,使用固定像素值
|
||||||
return Dialog(
|
return Dialog(
|
||||||
backgroundColor: theme.cardColor,
|
backgroundColor: theme.cardColor,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(12.r),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 280.w,
|
width: 280,
|
||||||
padding: EdgeInsets.all(24.w),
|
padding: const EdgeInsets.all(24),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (icon != null) ...[
|
if (icon != null) ...[
|
||||||
icon!,
|
icon!,
|
||||||
SizedBox(height: 20.h),
|
const SizedBox(height: 20),
|
||||||
],
|
],
|
||||||
if (title != null) ...[
|
if (title != null) ...[
|
||||||
Text(
|
Text(
|
||||||
title!,
|
title!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 17.sp,
|
fontSize: 17,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: isDark ? Colors.white : const Color(0xFF333333),
|
color: isDark ? Colors.white : const Color(0xFF333333),
|
||||||
fontFamily: 'AlibabaPuHuiTi-Medium',
|
fontFamily: 'AlibabaPuHuiTi-Medium',
|
||||||
@ -121,17 +122,17 @@ class KRDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
SizedBox(height: 12.h),
|
const SizedBox(height: 12),
|
||||||
],
|
],
|
||||||
if (message != null || customMessageWidget != null) ...[
|
if (message != null || customMessageWidget != null) ...[
|
||||||
Container(
|
Container(
|
||||||
constraints: BoxConstraints(maxHeight: 200.h),
|
constraints: const BoxConstraints(maxHeight: 200),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: customMessageWidget ?? Text(
|
child: customMessageWidget ?? Text(
|
||||||
message!,
|
message!,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.sp,
|
fontSize: 14,
|
||||||
color: isDark ? const Color(0xFFCCCCCC) : const Color(0xFF666666),
|
color: isDark ? const Color(0xFFCCCCCC) : const Color(0xFF666666),
|
||||||
fontFamily: 'AlibabaPuHuiTi-Regular',
|
fontFamily: 'AlibabaPuHuiTi-Regular',
|
||||||
height: 1.4,
|
height: 1.4,
|
||||||
@ -139,7 +140,7 @@ class KRDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 28.h),
|
const SizedBox(height: 28),
|
||||||
],
|
],
|
||||||
if (cancelText != null) ...[
|
if (cancelText != null) ...[
|
||||||
Row(
|
Row(
|
||||||
@ -147,33 +148,33 @@ class KRDialog extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(23.r),
|
borderRadius: BorderRadius.circular(23),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withOpacity(0.03),
|
color: Colors.black.withOpacity(0.03),
|
||||||
blurRadius: 4.r,
|
blurRadius: 4,
|
||||||
offset: Offset(0, 2.w),
|
offset: const Offset(0, 2),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.back();
|
Get.back();
|
||||||
onCancel?.call();
|
onCancel?.call();
|
||||||
},
|
},
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
backgroundColor: isDark ? const Color(0xFF222222) : const Color(0xFFEEEEEE),
|
backgroundColor: isDark ? const Color(0xFF222222) : const Color(0xFFEEEEEE),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(23.r),
|
borderRadius: BorderRadius.circular(23),
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
minimumSize: Size.fromHeight(46.w),
|
minimumSize: const Size.fromHeight(46),
|
||||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
cancelText ?? AppTranslations.kr_dialog.kr_cancel,
|
cancelText ?? AppTranslations.kr_dialog.kr_cancel,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 15.sp,
|
fontSize: 15,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: isDark ? const Color(0xFFBBBBBB) : const Color(0xFF666666),
|
color: isDark ? const Color(0xFFBBBBBB) : const Color(0xFF666666),
|
||||||
fontFamily: 'AlibabaPuHuiTi-Medium',
|
fontFamily: 'AlibabaPuHuiTi-Medium',
|
||||||
@ -182,7 +183,7 @@ class KRDialog extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 12.w),
|
const SizedBox(width: 12),
|
||||||
Expanded(child: _buildConfirmButton()),
|
Expanded(child: _buildConfirmButton()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user