feat: 1.调整项目初始化,不用等待site/config接口,仅在hi_user_info中调用;将site_config_service拆成loadDomain和获取配置,在splash中只做loadDomain
2. 优化接口拦截的解密日志 3. 调整获取订阅到kr_home,与源版一致 4. 修复闪连抖动问题,增加套餐有效期判断
This commit is contained in:
@@ -12,8 +12,10 @@ import 'package:kaer_with_panels/app/model/enum/kr_request_type.dart';
|
||||
import 'package:kaer_with_panels/app/localization/app_translations.dart';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'dart:convert';
|
||||
import 'package:kaer_with_panels/utils/snackbar_util.dart';
|
||||
import 'package:kaer_with_panels/app/routes/app_pages.dart';
|
||||
import 'package:kaer_with_panels/app/common/app_config.dart';
|
||||
|
||||
class HIUserInfoController extends GetxController {
|
||||
/// 订阅服务
|
||||
@@ -32,6 +34,7 @@ class HIUserInfoController extends GetxController {
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
_initDeviceId();
|
||||
_initDeviceLimit();
|
||||
loadDeviceList();
|
||||
}
|
||||
|
||||
@@ -55,13 +58,13 @@ class HIUserInfoController extends GetxController {
|
||||
final result = await KRUserApi().kr_getUserDevices();
|
||||
|
||||
result.fold(
|
||||
(error) {
|
||||
(error) {
|
||||
KRLogUtil.kr_e('加载设备列表失败: ${error.msg}', tag: 'DeviceManagement');
|
||||
KRSnackBarUtil.show(AppTranslations.kr_dialog.error, error.msg);
|
||||
},
|
||||
(deviceList) {
|
||||
KRLogUtil.kr_i('获取到 ${deviceList.length} 个设备', tag: 'DeviceManagement');
|
||||
|
||||
(deviceList) {
|
||||
KRLogUtil.kr_i('获取到 ${deviceList.length} 个设备',
|
||||
tag: 'DeviceManagement');
|
||||
|
||||
// 转换设备数据格式
|
||||
devices.value = deviceList.map((device) {
|
||||
@@ -89,7 +92,8 @@ class HIUserInfoController extends GetxController {
|
||||
} catch (e, stackTrace) {
|
||||
KRLogUtil.kr_e('加载设备列表异常: $e', tag: 'DeviceManagement');
|
||||
KRLogUtil.kr_e('堆栈跟踪: $stackTrace', tag: 'DeviceManagement');
|
||||
KRSnackBarUtil.show(AppTranslations.kr_dialog.error, AppTranslations.kr_deviceManagement.loadDeviceListFailed);
|
||||
KRSnackBarUtil.show(AppTranslations.kr_dialog.error,
|
||||
AppTranslations.kr_deviceManagement.loadDeviceListFailed);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
@@ -99,24 +103,26 @@ class HIUserInfoController extends GetxController {
|
||||
Future<bool> deleteDevice(String id) async {
|
||||
try {
|
||||
final device = devices.firstWhere(
|
||||
(d) => d['id'] == id,
|
||||
(d) => d['id'] == id,
|
||||
orElse: () => {},
|
||||
);
|
||||
if (device.isEmpty) return false;
|
||||
|
||||
final isCurrent = device['is_current'] ?? false;
|
||||
|
||||
KRLogUtil.kr_i('开始解绑设备 - id: $id, isCurrent: $isCurrent', tag: 'DeviceManagement');
|
||||
KRLogUtil.kr_i('开始解绑设备 - id: $id, isCurrent: $isCurrent',
|
||||
tag: 'DeviceManagement');
|
||||
|
||||
final result = await KRUserApi().kr_unbindUserDevice(id);
|
||||
|
||||
bool success = false;
|
||||
result.fold(
|
||||
(error) {
|
||||
(error) {
|
||||
KRLogUtil.kr_e('删除设备失败: ${error.msg}', tag: 'DeviceManagement');
|
||||
KRSnackBarUtil.show(AppTranslations.kr_dialog.error, AppTranslations.kr_deviceManagement.deleteFailed(error.msg));
|
||||
KRSnackBarUtil.show(AppTranslations.kr_dialog.error,
|
||||
AppTranslations.kr_deviceManagement.deleteFailed(error.msg));
|
||||
},
|
||||
(_) async {
|
||||
(_) async {
|
||||
KRLogUtil.kr_i('设备删除成功', tag: 'DeviceManagement');
|
||||
success = true;
|
||||
|
||||
@@ -127,7 +133,8 @@ class HIUserInfoController extends GetxController {
|
||||
await _reloginWithDevice();
|
||||
} else {
|
||||
devices.removeWhere((device) => device['id'] == id);
|
||||
KRSnackBarUtil.show(AppTranslations.kr_dialog.success, AppTranslations.kr_deviceManagement.deleteSuccess);
|
||||
KRSnackBarUtil.show(AppTranslations.kr_dialog.success,
|
||||
AppTranslations.kr_deviceManagement.deleteSuccess);
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -136,18 +143,20 @@ class HIUserInfoController extends GetxController {
|
||||
} catch (e, stackTrace) {
|
||||
KRLogUtil.kr_e('删除设备异常: $e', tag: 'DeviceManagement');
|
||||
KRLogUtil.kr_e('堆栈跟踪: $stackTrace', tag: 'DeviceManagement');
|
||||
KRSnackBarUtil.show(AppTranslations.kr_dialog.error, AppTranslations.kr_deviceManagement.deleteFailed(e.toString()));
|
||||
KRSnackBarUtil.show(AppTranslations.kr_dialog.error,
|
||||
AppTranslations.kr_deviceManagement.deleteFailed(e.toString()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 重新使用设备登录
|
||||
Future<void> _reloginWithDevice() async {
|
||||
try {
|
||||
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'DeviceManagement');
|
||||
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
|
||||
tag: 'DeviceManagement');
|
||||
KRLogUtil.kr_i('开始重新进行设备登录', tag: 'DeviceManagement');
|
||||
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'DeviceManagement');
|
||||
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
|
||||
tag: 'DeviceManagement');
|
||||
|
||||
// 先清除当前的用户信息(但不调用 kr_loginOut,避免显示登录界面)
|
||||
final appRunData = KRAppRunData.getInstance();
|
||||
@@ -166,26 +175,27 @@ class HIUserInfoController extends GetxController {
|
||||
final result = await authApi.kr_deviceLogin();
|
||||
|
||||
result.fold(
|
||||
(error) {
|
||||
(error) {
|
||||
// 设备登录失败
|
||||
KRLogUtil.kr_e('设备登录失败: ${error.msg}', tag: 'DeviceManagement');
|
||||
KRSnackBarUtil.show(AppTranslations.kr_dialog.error, AppTranslations.kr_deviceManagement.reloginFailed(error.msg));
|
||||
KRSnackBarUtil.show(AppTranslations.kr_dialog.error,
|
||||
AppTranslations.kr_deviceManagement.reloginFailed(error.msg));
|
||||
|
||||
// 执行完整退出登录,显示登录界面
|
||||
appRunData.kr_loginOut();
|
||||
},
|
||||
(token) async {
|
||||
(token) async {
|
||||
// 设备登录成功
|
||||
KRLogUtil.kr_i('✅ 设备登录成功!', tag: 'DeviceManagement');
|
||||
KRLogUtil.kr_i('🎫 Token: ${token.substring(0, min(20, token.length))}...', tag: 'DeviceManagement');
|
||||
KRLogUtil.kr_i(
|
||||
'🎫 Token: ${token.substring(0, min(20, token.length))}...',
|
||||
tag: 'DeviceManagement');
|
||||
|
||||
// 保存新的用户信息
|
||||
final deviceId = KRDeviceInfoService().deviceId ?? 'unknown';
|
||||
await appRunData.kr_saveUserInfo(
|
||||
token,
|
||||
'device_$deviceId',
|
||||
KRLoginType.kr_email,
|
||||
null,
|
||||
);
|
||||
|
||||
KRLogUtil.kr_i('✅ 设备重新登录成功,已更新用户信息', tag: 'DeviceManagement');
|
||||
@@ -209,35 +219,53 @@ class HIUserInfoController extends GetxController {
|
||||
} catch (e, stackTrace) {
|
||||
KRLogUtil.kr_e('设备重新登录异常: $e', tag: 'DeviceManagement');
|
||||
KRLogUtil.kr_e('堆栈跟踪: $stackTrace', tag: 'DeviceManagement');
|
||||
KRSnackBarUtil.show(AppTranslations.kr_dialog.error, AppTranslations.kr_deviceManagement.reloginFailedGeneric);
|
||||
KRSnackBarUtil.show(AppTranslations.kr_dialog.error,
|
||||
AppTranslations.kr_deviceManagement.reloginFailedGeneric);
|
||||
|
||||
// 发生异常,执行完整退出登录
|
||||
await KRAppRunData.getInstance().kr_loginOut();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _initDeviceLimit() async {
|
||||
await KRSiteConfigService().fetchSiteConfig();
|
||||
}
|
||||
|
||||
/// 获取设备类型和图标
|
||||
Map<String, dynamic> getDeviceTypeInfo(String userAgent) {
|
||||
String deviceType = AppTranslations.kr_deviceManagement.deviceTypeUnknown;
|
||||
String iconName = 'devices';
|
||||
|
||||
if (userAgent.contains('Android') || userAgent.toLowerCase().contains('android')) {
|
||||
deviceType = 'Android' ;// AppTranslations.kr_deviceManagement.deviceTypeAndroid;
|
||||
if (userAgent.contains('Android') ||
|
||||
userAgent.toLowerCase().contains('android')) {
|
||||
deviceType =
|
||||
'Android'; // AppTranslations.kr_deviceManagement.deviceTypeAndroid;
|
||||
iconName = 'phone_android';
|
||||
} else if (userAgent.contains('iOS') || userAgent.contains('iPhone') || userAgent.toLowerCase().contains('ios')) {
|
||||
deviceType = 'iPhone'; // AppTranslations.kr_deviceManagement.deviceTypeIos;
|
||||
} else if (userAgent.contains('iOS') ||
|
||||
userAgent.contains('iPhone') ||
|
||||
userAgent.toLowerCase().contains('ios')) {
|
||||
deviceType =
|
||||
'iPhone'; // AppTranslations.kr_deviceManagement.deviceTypeIos;
|
||||
iconName = 'phone_iphone';
|
||||
} else if (userAgent.contains('iPad')) {
|
||||
deviceType = 'iPad';// AppTranslations.kr_deviceManagement.deviceTypeIpad;
|
||||
deviceType =
|
||||
'iPad'; // AppTranslations.kr_deviceManagement.deviceTypeIpad;
|
||||
iconName = 'tablet';
|
||||
} else if (userAgent.contains('macOS') || userAgent.contains('Mac') || userAgent.toLowerCase().contains('mac')) {
|
||||
deviceType = 'Mac';// AppTranslations.kr_deviceManagement.deviceTypeMacos;
|
||||
} else if (userAgent.contains('macOS') ||
|
||||
userAgent.contains('Mac') ||
|
||||
userAgent.toLowerCase().contains('mac')) {
|
||||
deviceType =
|
||||
'Mac'; // AppTranslations.kr_deviceManagement.deviceTypeMacos;
|
||||
iconName = 'desktop_mac';
|
||||
} else if (userAgent.contains('Windows') || userAgent.toLowerCase().contains('windows')) {
|
||||
deviceType = 'Windows'; //AppTranslations.kr_deviceManagement.deviceTypeWindows;
|
||||
} else if (userAgent.contains('Windows') ||
|
||||
userAgent.toLowerCase().contains('windows')) {
|
||||
deviceType =
|
||||
'Windows'; //AppTranslations.kr_deviceManagement.deviceTypeWindows;
|
||||
iconName = 'computer';
|
||||
} else if (userAgent.contains('Linux') || userAgent.toLowerCase().contains('linux')) {
|
||||
deviceType = 'Linux';//AppTranslations.kr_deviceManagement.deviceTypeLinux;
|
||||
} else if (userAgent.contains('Linux') ||
|
||||
userAgent.toLowerCase().contains('linux')) {
|
||||
deviceType =
|
||||
'Linux'; //AppTranslations.kr_deviceManagement.deviceTypeLinux;
|
||||
iconName = 'computer';
|
||||
}
|
||||
|
||||
@@ -247,8 +275,6 @@ class HIUserInfoController extends GetxController {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
|
||||
@@ -55,7 +55,7 @@ class KRCrispController extends GetxController {
|
||||
|
||||
// 创建原生 SDK 配置
|
||||
_nativeConfig = native_crisp.CrispConfig(
|
||||
websiteID: AppConfig.getInstance().kr_website_id,
|
||||
websiteID: '47fcc1ac-9674-4ab1-9e3c-6b5666f59a38',
|
||||
user: native_crisp.User(
|
||||
email: null,
|
||||
nickName: identifier,
|
||||
|
||||
@@ -33,9 +33,6 @@ import 'package:kaer_with_panels/app/services/singbox_imp/kr_sing_box_imp.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_latency_tester.dart'; // 🔧 新增:导入真实延迟测试工具
|
||||
import 'package:kaer_with_panels/app/utils/account_guard.dart';
|
||||
import 'package:kaer_with_panels/app/services/iap/iap_service.dart';
|
||||
|
||||
|
||||
class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
// 🔧 新增:日志收集器实例
|
||||
@@ -44,7 +41,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
/// 订阅服务
|
||||
final KRSubscribeService kr_subscribeService = KRSubscribeService();
|
||||
|
||||
|
||||
/// 当前视图状态,登录状态
|
||||
final Rx<KRHomeViewsStatus> kr_currentViewStatus =
|
||||
KRHomeViewsStatus.kr_notLoggedIn.obs;
|
||||
@@ -52,25 +48,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
/// 当前列表视图状态
|
||||
final kr_currentListStatus = KRHomeViewsListStatus.kr_loading.obs;
|
||||
|
||||
/// 底部面板高度常量
|
||||
static const double kr_baseHeight = 120.0; // 基础高度(连接选项)
|
||||
static const double kr_subscriptionCardHeight = 200.0; // 订阅卡片高度
|
||||
static const double kr_connectionInfoHeight = 126.0; // 连接信息卡片高度(修复后)
|
||||
static const double kr_trialCardHeight = 120.0; // 试用卡片高度
|
||||
static const double kr_lastDayCardHeight = 120.0; // 最后一天卡片高度
|
||||
static const double kr_nodeListHeight = 400.0; // 节点列表高度
|
||||
static const double kr_errorHeight = 100.0; // 错误状态高度
|
||||
static const double kr_loadingHeight = 100.0; // 加载状态高度
|
||||
|
||||
/// 间距常量
|
||||
static const double kr_marginTop = 12.0; // 顶部间距
|
||||
static const double kr_marginBottom = 12.0; // 底部间距
|
||||
static const double kr_marginHorizontal = 16.0; // 水平间距
|
||||
static const double kr_marginVertical = 12.0; // 垂直间距
|
||||
|
||||
/// 底部面板高度
|
||||
final kr_bottomPanelHeight = 200.0.obs;
|
||||
|
||||
/// 连接字符串
|
||||
final kr_connectText = AppTranslations.kr_home.disconnected.obs;
|
||||
|
||||
@@ -223,6 +200,23 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
return;
|
||||
}
|
||||
|
||||
final current = kr_subscribeService.kr_currentSubscribe.value;
|
||||
if (!KRAppRunData.getInstance().kr_isLogin.value || current == null) {
|
||||
KRLogUtil.kr_w('未登录或无可用订阅,阻止自动连接', tag: 'QuickConnect');
|
||||
return;
|
||||
}
|
||||
bool isExpired = false;
|
||||
if (current.expireTime.isNotEmpty) {
|
||||
try {
|
||||
isExpired =
|
||||
DateTime.parse(current.expireTime).isBefore(DateTime.now());
|
||||
} catch (_) {}
|
||||
}
|
||||
if (isExpired) {
|
||||
KRLogUtil.kr_w('订阅不可用(过期或流量耗尽),阻止自动连接', tag: 'QuickConnect');
|
||||
return;
|
||||
}
|
||||
|
||||
await _kr_prepareCountrySelectionBeforeStart();
|
||||
final selectedAfter =
|
||||
await KRSecureStorage().kr_readData(key: 'SELECTED_NODE_TAG');
|
||||
@@ -260,45 +254,9 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
}
|
||||
}
|
||||
|
||||
/// 检查是否满足自动连接条件(不执行连接)
|
||||
bool canAutoConnect() {
|
||||
return isQuickConnectEnabled.value &&
|
||||
KRAppRunData.getInstance().kr_isLogin.value &&
|
||||
!kr_isConnected.value;
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
// 🔧 紧急诊断:直接写文件验证 onInit 是否被调用
|
||||
try {
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
final debugFile = File('${dir.path}/HOME_CONTROLLER_DEBUG.txt');
|
||||
await debugFile.writeAsString(
|
||||
'=' * 60 +
|
||||
'\n'
|
||||
'HomeController.onInit 被调用!\n'
|
||||
'时间: ${DateTime.now()}\n'
|
||||
'实例 HashCode: ${hashCode}\n'
|
||||
'线程: ${Platform.isAndroid ? "Android" : "Unknown"}\n'
|
||||
'=' *
|
||||
60 +
|
||||
'\n',
|
||||
mode: FileMode.append,
|
||||
);
|
||||
} catch (e) {
|
||||
// 忽略错误,确保不影响主流程
|
||||
}
|
||||
|
||||
// 🔧 新增:记录 HomeController 初始化开始
|
||||
_initLog.logPhaseStart('HomeController 初始化');
|
||||
_initLog.log('KRHomeController.onInit 被调用', tag: 'Home');
|
||||
|
||||
// 🔧 Android 15 紧急修复:立即设置默认高度,确保底部面板可见
|
||||
// kr_updateBottomPanelHeight();
|
||||
|
||||
/// 底部面板高度处理
|
||||
// _kr_initBottomPanelHeight();
|
||||
// 加载闪连状态
|
||||
_loadQuickConnectStatus();
|
||||
// 加载已选择的国家
|
||||
@@ -320,7 +278,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
|
||||
// 延迟同步连接状态,确保状态正确
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
kr_forceSyncConnectionStatus(true);
|
||||
kr_forceSyncConnectionStatus();
|
||||
});
|
||||
|
||||
// 🔧 Android 15 新增:5秒后再次强制更新高度,兜底保护
|
||||
@@ -372,14 +330,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
/// 底部面板高度处理
|
||||
void _kr_initBottomPanelHeight() {
|
||||
ever(kr_currentListStatus, (status) {
|
||||
kr_updateBottomPanelHeight();
|
||||
KRLogUtil.kr_i(status.toString(), tag: "_kr_initBottomPanelHeight");
|
||||
});
|
||||
}
|
||||
|
||||
void _kr_initLoginStatus() {
|
||||
_initLog.log('开始初始化登录状态处理', tag: 'Home');
|
||||
KRLogUtil.kr_i('初始化登录状态', tag: 'HomeController');
|
||||
@@ -392,10 +342,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
KRLogUtil.kr_w('⏱️ 订阅服务初始化超时(8秒),强制设置为无数据状态', tag: 'HomeController');
|
||||
// 🔧 Android 15 优化:超时设置为 none 而非 error,避免底部面板显示错误界面
|
||||
kr_currentListStatus.value = KRHomeViewsListStatus.kr_none;
|
||||
// 强制更新底部面板高度,确保显示正常
|
||||
kr_updateBottomPanelHeight();
|
||||
_initLog.log('已强制切换到默认视图, 底部面板高度: ${kr_bottomPanelHeight.value}',
|
||||
tag: 'Subscribe');
|
||||
|
||||
KRLogUtil.kr_i('✅ 已强制切换到默认视图', tag: 'HomeController');
|
||||
}
|
||||
});
|
||||
@@ -458,8 +405,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
kr_currentViewStatus.value = KRHomeViewsStatus.kr_loggedIn;
|
||||
_initLog.logSuccess('用户已登录,准备加载订阅数据', tag: 'Home');
|
||||
KRLogUtil.kr_i('设置为已登录状态', tag: 'HomeController');
|
||||
|
||||
// 订阅服务已在 splash 页面初始化,此处无需重复初始化
|
||||
_kr_ensureSubscribeServiceInitialized();
|
||||
KRLogUtil.kr_i('订阅服务已在启动页初始化,跳过重复初始化', tag: 'HomeController');
|
||||
} else {
|
||||
kr_currentViewStatus.value = KRHomeViewsStatus.kr_notLoggedIn;
|
||||
@@ -517,6 +463,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
throw TimeoutException('订阅服务初始化超时');
|
||||
},
|
||||
).then((_) async {
|
||||
_checkQuickConnectAutoStart();
|
||||
final elapsed = DateTime.now().difference(startTime).inMilliseconds;
|
||||
_initLog.logSuccess('订阅服务初始化完成, 耗时: ${elapsed}ms', tag: 'Subscribe');
|
||||
_initLog.log('最终列表状态: ${kr_currentListStatus.value}',
|
||||
@@ -594,7 +541,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
kr_currentViewStatus.value = KRHomeViewsStatus.kr_loggedIn;
|
||||
KRLogUtil.kr_i('登录状态变化:设置为已登录', tag: 'HomeController');
|
||||
|
||||
|
||||
// 订阅服务已在 splash 页面初始化,此处无需重复初始化
|
||||
KRLogUtil.kr_i('订阅服务已在启动页初始化,跳过重复初始化', tag: 'HomeController');
|
||||
} else {
|
||||
@@ -681,7 +627,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
} else {
|
||||
// kr_updateBottomPanelHeight();
|
||||
}
|
||||
_checkQuickConnectAutoStart();
|
||||
_kr_testLatencyWithoutVpn();
|
||||
break;
|
||||
case KRSubscribeServiceStatus.kr_none:
|
||||
@@ -1872,18 +1817,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
@override
|
||||
void onReady() {
|
||||
super.onReady();
|
||||
|
||||
Future.delayed(const Duration(milliseconds: 200), () async {
|
||||
ensureAccountExists().then((ok) {
|
||||
print('ok');
|
||||
});
|
||||
});
|
||||
|
||||
Future.delayed(const Duration(milliseconds: 500), () async {
|
||||
if (Get.isRegistered<KRIAPService>()) {
|
||||
KRIAPService.instance.setup();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1958,100 +1891,8 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
});
|
||||
}
|
||||
|
||||
// 更新底部面板高度
|
||||
void kr_updateBottomPanelHeight() {
|
||||
// 🔧 Android 15 优化:加载状态时也允许更新高度,显示加载指示器
|
||||
if (kr_subscribeService.kr_currentStatus ==
|
||||
KRHomeViewsListStatus.kr_loading &&
|
||||
kr_currentListStatus.value != KRHomeViewsListStatus.kr_loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
KRLogUtil.kr_i('更新底部面板高度', tag: 'HomeController');
|
||||
KRLogUtil.kr_i('当前视图状态: ${kr_currentViewStatus.value}',
|
||||
tag: 'HomeController');
|
||||
|
||||
KRLogUtil.kr_i('当前列表状态: ${kr_currentListStatus.value}',
|
||||
tag: 'HomeController');
|
||||
KRLogUtil.kr_i('是否试用: ${kr_subscribeService.kr_isTrial.value}',
|
||||
tag: 'HomeController');
|
||||
KRLogUtil.kr_i(
|
||||
'是否最后一天: ${kr_subscribeService.kr_isLastDayOfSubscription.value}',
|
||||
tag: 'HomeController');
|
||||
|
||||
double targetHeight = 0.0;
|
||||
|
||||
if (kr_currentViewStatus.value == KRHomeViewsStatus.kr_notLoggedIn) {
|
||||
// 未登录状态下,高度由内容撑开
|
||||
targetHeight = kr_subscriptionCardHeight +
|
||||
kr_baseHeight +
|
||||
kr_marginTop +
|
||||
kr_marginBottom +
|
||||
kr_marginVertical * 2;
|
||||
KRLogUtil.kr_i('未登录状态,目标高度: $targetHeight', tag: 'HomeController');
|
||||
} else if (kr_currentListStatus.value ==
|
||||
KRHomeViewsListStatus.kr_serverList ||
|
||||
kr_currentListStatus.value ==
|
||||
KRHomeViewsListStatus.kr_countrySubscribeList ||
|
||||
kr_currentListStatus.value ==
|
||||
KRHomeViewsListStatus.kr_serverSubscribeList ||
|
||||
kr_currentListStatus.value == KRHomeViewsListStatus.kr_subscribeList) {
|
||||
targetHeight = kr_nodeListHeight + kr_marginVertical * 2;
|
||||
KRLogUtil.kr_i('节点列表状态,目标高度: $targetHeight', tag: 'HomeController');
|
||||
}
|
||||
// 🔧 Android 15 新增:处理加载和错误状态
|
||||
else if (kr_currentListStatus.value == KRHomeViewsListStatus.kr_loading ||
|
||||
kr_currentListStatus.value == KRHomeViewsListStatus.kr_error) {
|
||||
// 加载或错误状态下显示最小高度
|
||||
targetHeight = kr_loadingHeight + kr_marginTop + kr_marginBottom;
|
||||
KRLogUtil.kr_i('加载/错误状态,目标高度: $targetHeight', tag: 'HomeController');
|
||||
} else {
|
||||
// 已登录状态下的默认高度计算
|
||||
targetHeight = kr_baseHeight + kr_marginTop + kr_marginBottom;
|
||||
KRLogUtil.kr_i('基础高度: $targetHeight', tag: 'HomeController');
|
||||
|
||||
// 🔧 关键修复:增加防御性检查,确保订阅服务访问异常时高度计算仍正常
|
||||
try {
|
||||
if (kr_subscribeService.kr_currentSubscribe.value != null) {
|
||||
targetHeight += kr_connectionInfoHeight + kr_marginTop;
|
||||
KRLogUtil.kr_i('添加连接信息卡片高度: $targetHeight', tag: 'HomeController');
|
||||
} else {
|
||||
targetHeight += kr_subscriptionCardHeight + kr_marginTop;
|
||||
KRLogUtil.kr_i('添加订阅卡片高度: $targetHeight', tag: 'HomeController');
|
||||
}
|
||||
|
||||
// 如果有试用状态,添加试用卡片高度
|
||||
if (kr_subscribeService.kr_isTrial.value) {
|
||||
targetHeight += kr_trialCardHeight + kr_marginTop;
|
||||
KRLogUtil.kr_i('添加试用卡片高度: $targetHeight', tag: 'HomeController');
|
||||
}
|
||||
// 如果是最后一天,添加最后一天卡片高度
|
||||
else if (kr_subscribeService.kr_isLastDayOfSubscription.value) {
|
||||
targetHeight += kr_lastDayCardHeight + kr_marginTop;
|
||||
KRLogUtil.kr_i('添加最后一天卡片高度: $targetHeight', tag: 'HomeController');
|
||||
}
|
||||
} catch (e) {
|
||||
// 🔧 修复:订阅服务访问异常时,使用默认订阅卡片高度
|
||||
KRLogUtil.kr_e('访问订阅服务数据异常,使用默认高度: $e', tag: 'HomeController');
|
||||
targetHeight += kr_subscriptionCardHeight + kr_marginTop;
|
||||
KRLogUtil.kr_i('使用默认订阅卡片高度: $targetHeight', tag: 'HomeController');
|
||||
}
|
||||
}
|
||||
|
||||
// 🔧 Android 15 优化:确保最小高度,避免出现 0 高度
|
||||
if (targetHeight < 100) {
|
||||
KRLogUtil.kr_w('计算的高度过小($targetHeight),设置为最小高度', tag: 'HomeController');
|
||||
targetHeight = kr_loadingHeight;
|
||||
}
|
||||
|
||||
KRLogUtil.kr_i('最终目标高度: $targetHeight', tag: 'HomeController');
|
||||
kr_bottomPanelHeight.value = targetHeight;
|
||||
}
|
||||
|
||||
// 移动到选中节点
|
||||
void kr_moveToSelectedNode() {
|
||||
|
||||
}
|
||||
void kr_moveToSelectedNode() {}
|
||||
|
||||
// 简化移动地图方法
|
||||
void kr_moveToLocation() {
|
||||
@@ -2436,7 +2277,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
/// 强制同步连接状态
|
||||
void kr_forceSyncConnectionStatus([bool? isQuickConnect]) {
|
||||
void kr_forceSyncConnectionStatus() {
|
||||
try {
|
||||
KRLogUtil.kr_i('🔄 强制同步连接状态...', tag: 'HomeController');
|
||||
|
||||
@@ -2479,10 +2320,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
||||
|
||||
// 强制更新UI
|
||||
update();
|
||||
print('isQuickConnect$isQuickConnect');
|
||||
if (isQuickConnect == true) {
|
||||
_checkQuickConnectAutoStart();
|
||||
}
|
||||
KRLogUtil.kr_i('✅ 连接状态同步完成', tag: 'HomeController');
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('❌ 强制同步连接状态失败: $e', tag: 'HomeController');
|
||||
|
||||
@@ -11,7 +11,6 @@ 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/singbox_imp/kr_sing_box_imp.dart';
|
||||
import 'package:kaer_with_panels/singbox/model/singbox_status.dart';
|
||||
import 'package:kaer_with_panels/app/utils/account_guard.dart';
|
||||
|
||||
DateTime? _hiConnectBtnNextAllowedAt;
|
||||
const Duration _hiConnectBtnDebounce = Duration(milliseconds: 800);
|
||||
@@ -93,8 +92,6 @@ class HIAnimatedConnectButton extends GetView<KRHomeController> {
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
HapticFeedback.lightImpact();
|
||||
final ok = await ensureAccountExists();
|
||||
if (!ok) return;
|
||||
final _now = DateTime.now();
|
||||
if (_hiConnectBtnNextAllowedAt != null &&
|
||||
_now.isBefore(_hiConnectBtnNextAllowedAt!)) {
|
||||
|
||||
@@ -8,7 +8,6 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import '../controllers/kr_home_controller.dart';
|
||||
import '../../../routes/app_pages.dart';
|
||||
import 'package:kaer_with_panels/app/services/global_overlay_service.dart';
|
||||
import 'package:kaer_with_panels/app/utils/account_guard.dart';
|
||||
|
||||
// ======================= 1. Circular Clipper (保持不变) =======================
|
||||
class CircularClipper extends CustomClipper<Path> {
|
||||
@@ -175,8 +174,6 @@ class _HISubscriptionCornerButtonState extends State<HISubscriptionCornerButton>
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
final ok = await ensureAccountExists();
|
||||
if (!ok) return;
|
||||
_startCircularTransition(context);
|
||||
},
|
||||
child: Container(
|
||||
|
||||
@@ -17,7 +17,6 @@ import 'package:kaer_with_panels/app/services/global_overlay_service.dart';
|
||||
import 'package:kaer_with_panels/app/widgets/swipe/has_swipe_config.dart';
|
||||
import 'package:kaer_with_panels/app/widgets/swipe/swipe_config.dart';
|
||||
import 'package:kaer_with_panels/app/routes/app_pages.dart';
|
||||
import 'package:kaer_with_panels/app/utils/account_guard.dart';
|
||||
|
||||
class KRHomeView extends StatefulWidget implements HasSwipeConfig {
|
||||
const KRHomeView({super.key});
|
||||
@@ -26,16 +25,10 @@ class KRHomeView extends StatefulWidget implements HasSwipeConfig {
|
||||
enableLeft: true,
|
||||
enableRight: true,
|
||||
onLeft: () {
|
||||
ensureAccountExists().then((ok) {
|
||||
if (!ok) return;
|
||||
Get.toNamed(Routes.HI_MENU);
|
||||
});
|
||||
Get.toNamed(Routes.HI_MENU);
|
||||
},
|
||||
onRight: () {
|
||||
ensureAccountExists().then((ok) {
|
||||
if (!ok) return;
|
||||
GlobalOverlayService.instance.triggerSubscriptionAnimation();
|
||||
});
|
||||
GlobalOverlayService.instance.triggerSubscriptionAnimation();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -109,43 +102,37 @@ class _KRHomeViewState extends State<KRHomeView> {
|
||||
);
|
||||
|
||||
// 3. 开始条件判断
|
||||
if (currentSubscribe == null) {
|
||||
// --- 情况1: 没有任何订阅信息 ---
|
||||
content = Text(
|
||||
'尚未购买套餐',
|
||||
style: highlightStyle,
|
||||
);
|
||||
final listStatus =
|
||||
controller.kr_currentListStatus.value;
|
||||
if (listStatus == KRHomeViewsListStatus.kr_loading) {
|
||||
content = Text('加载订阅中', style: normalStyle);
|
||||
} else {
|
||||
// --- 情况2: 有订阅信息,需要判断是否过期 ---
|
||||
final now = DateTime.now();
|
||||
DateTime? expireDateTime;
|
||||
try {
|
||||
expireDateTime =
|
||||
DateTime.parse(currentSubscribe.expireTime);
|
||||
} catch (e) {
|
||||
// 日期格式解析失败
|
||||
}
|
||||
|
||||
if (expireDateTime != null &&
|
||||
expireDateTime.isBefore(now)) {
|
||||
// --- 情况2.1: 订阅已过期 ---
|
||||
final formattedExpireDate =
|
||||
'${expireDateTime.year}/${expireDateTime.month.toString().padLeft(2, '0')}/${expireDateTime.day.toString().padLeft(2, '0')}';
|
||||
// 使用换行符 \n 合并为单个 Text 组件
|
||||
content = Text(
|
||||
'您的套餐已于 $formattedExpireDate 到期\n请前往购买新套餐',
|
||||
style: highlightStyle,
|
||||
);
|
||||
if (currentSubscribe == null) {
|
||||
content = Text('尚未购买套餐', style: highlightStyle);
|
||||
} else {
|
||||
// --- 情况2.2: 订阅有效 ---
|
||||
final formattedExpireTime = expireDateTime != null
|
||||
final now = DateTime.now();
|
||||
DateTime? expireDateTime;
|
||||
try {
|
||||
expireDateTime =
|
||||
DateTime.parse(currentSubscribe.expireTime);
|
||||
} catch (e) {}
|
||||
if (expireDateTime != null &&
|
||||
expireDateTime.isBefore(now)) {
|
||||
final formattedExpireDate =
|
||||
'${expireDateTime.year}/${expireDateTime.month.toString().padLeft(2, '0')}/${expireDateTime.day.toString().padLeft(2, '0')}';
|
||||
content = Text(
|
||||
'您的套餐已于 $formattedExpireDate 到期\n请前往购买新套餐',
|
||||
style: highlightStyle);
|
||||
} else {
|
||||
final formattedExpireTime = expireDateTime !=
|
||||
null
|
||||
? '${expireDateTime.year}/${expireDateTime.month.toString().padLeft(2, '0')}/${expireDateTime.day.toString().padLeft(2, '0')} ${expireDateTime.hour.toString().padLeft(2, '0')}:${expireDateTime.minute.toString().padLeft(2, '0')}'
|
||||
: '未知';
|
||||
// 使用换行符 \n 合并为单个 Text 组件
|
||||
content = Text(
|
||||
'套餐到期时间:$formattedExpireTime\n${controller.kr_isConnected.value ? '当前线路:${controller.kr_getRealConnectedNodeCountry()}' : '未连接'}',
|
||||
style: normalStyle,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +220,7 @@ class _KRHomeViewState extends State<KRHomeView> {
|
||||
10.w,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
HIDialog.show(
|
||||
title: '闪连功能',
|
||||
message:
|
||||
|
||||
@@ -88,7 +88,6 @@ class KRLoginController extends GetxController
|
||||
RxBool kr_canSendCode = true.obs;
|
||||
|
||||
/// 国家编码列表
|
||||
late List<KRAreaCodeItem> kr_areaCodeList = KRAreaCode.kr_getCodeList();
|
||||
var kr_cutSeleteCodeIndex = 0.obs;
|
||||
|
||||
/// 是否加密密码
|
||||
@@ -556,8 +555,7 @@ class KRLoginController extends GetxController
|
||||
KRAppRunData.getInstance().kr_saveUserInfo(
|
||||
token,
|
||||
accountController.text,
|
||||
KRLoginType.kr_email,
|
||||
null);
|
||||
);
|
||||
kr_loginStatus.value = KRLoginProgressStatus.kr_check;
|
||||
|
||||
// 登录/注册成功后,发送消息触发订阅服务刷新
|
||||
|
||||
@@ -35,10 +35,10 @@ class KRSplashController extends GetxController {
|
||||
final _initLog = KRInitLogCollector();
|
||||
// 加载状态
|
||||
final RxBool kr_isLoading = true.obs;
|
||||
|
||||
|
||||
// 错误状态
|
||||
final RxBool kr_hasError = false.obs;
|
||||
|
||||
|
||||
// 错误信息
|
||||
final RxString kr_errorMessage = ''.obs;
|
||||
|
||||
@@ -65,14 +65,8 @@ class KRSplashController extends GetxController {
|
||||
_stepStartTime = _startTime;
|
||||
|
||||
// 使用 print 确保日志一定会输出
|
||||
print('[SPLASH_TIMING] ═══════════════════════════════════════');
|
||||
print('[SPLASH_TIMING] 🎬 KRSplashController onInit 被调用了!');
|
||||
print('[SPLASH_TIMING] ⏰ 启动开始时间: ${_startTime.toIso8601String()}');
|
||||
print('[SPLASH_TIMING] ═══════════════════════════════════════');
|
||||
|
||||
KRLogUtil.kr_i('[SPLASH_TIMING] ═══════════════════════════════════════', tag: 'SplashController');
|
||||
KRLogUtil.kr_i('[SPLASH_TIMING] 🎬 启动页控制器 onInit', tag: 'SplashController');
|
||||
KRLogUtil.kr_i('[SPLASH_TIMING] ═══════════════════════════════════════', tag: 'SplashController');
|
||||
|
||||
// 🔧 修复1.0:新增 - DEBUG模式下清理旧数据
|
||||
// ⚠️ 仅在DEBUG模式下执行,防止误删生产环境用户数据
|
||||
@@ -85,15 +79,6 @@ class KRSplashController extends GetxController {
|
||||
print('🧹 清理域名检测状态...');
|
||||
KRDomain.kr_resetDomainState();
|
||||
|
||||
// 🔧 P2优化:网站配置不再后台执行,改为串行执行以确保域名验证完成
|
||||
// print('🌐 启动后台任务:网站配置加载...');
|
||||
// KRLogUtil.kr_i('🌐 后台任务:网站配置和设备登录', tag: 'SplashController');
|
||||
// _kr_initSiteConfig(); // 移至 _kr_continueInitialization 中串行执行
|
||||
|
||||
// 🔧 关键修复:先初始化日志收集器,再开始主流程
|
||||
if (kDebugMode) {
|
||||
print('🔧 初始化日志收集器...');
|
||||
}
|
||||
_initializeAndStart();
|
||||
}
|
||||
|
||||
@@ -130,21 +115,15 @@ class KRSplashController extends GetxController {
|
||||
final totalMs = totalDuration.inMilliseconds;
|
||||
|
||||
print('[SPLASH_TIMING] ⏱️ $stepName 耗时: ${stepMs}ms | 累计: ${totalMs}ms');
|
||||
KRLogUtil.kr_i('[SPLASH_TIMING] ⏱️ $stepName 耗时: ${stepMs}ms | 累计: ${totalMs}ms', tag: 'SplashController');
|
||||
KRLogUtil.kr_i(
|
||||
'[SPLASH_TIMING] ⏱️ $stepName 耗时: ${stepMs}ms | 累计: ${totalMs}ms',
|
||||
tag: 'SplashController');
|
||||
|
||||
_stepStartTime = now; // 更新步骤开始时间
|
||||
}
|
||||
|
||||
/// 初始化网站配置(后台执行,不阻塞主流程)
|
||||
Future<void> _kr_initSiteConfig() async {
|
||||
print('[SPLASH_TIMING] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
print('[SPLASH_TIMING] 🌐 开始初始化网站配置...');
|
||||
print('[SPLASH_TIMING] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
|
||||
KRLogUtil.kr_i('[SPLASH_TIMING] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
||||
KRLogUtil.kr_i('[SPLASH_TIMING] 🌐 初始化网站配置...', tag: 'SplashController');
|
||||
KRLogUtil.kr_i('[SPLASH_TIMING] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
||||
|
||||
try {
|
||||
// 🔧 Android 15 优化:延长超时保护到25秒,匹配网络请求超时(20秒 + 5秒缓冲)
|
||||
await Future.any([
|
||||
@@ -162,116 +141,20 @@ class KRSplashController extends GetxController {
|
||||
}
|
||||
|
||||
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
||||
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
|
||||
tag: 'SplashController');
|
||||
}
|
||||
|
||||
/// 执行网站配置初始化
|
||||
Future<void> _executeSiteConfigInit() async {
|
||||
print('📞 准备调用 KRSiteConfigService().initialize()...');
|
||||
final success = await KRSiteConfigService().initialize();
|
||||
final crispId = await KRSiteConfigService().getCrispId();
|
||||
final device_limit = await KRSiteConfigService().getDeviceLimit();
|
||||
print('📞 KRSiteConfigService().initialize() 返回: $success');
|
||||
|
||||
if (success) {
|
||||
final config = AppConfig.getInstance();
|
||||
config.kr_website_id = crispId;
|
||||
config.device_limit = device_limit;
|
||||
print('📞 KRSiteConfigService().initialize() 返回: $crispId');
|
||||
print('AppConfig website_id 已更新为: ${config.kr_website_id}');
|
||||
print('AppConfig device_limit 已更新为: ${config.device_limit}');
|
||||
|
||||
// print('[SPLASH_TIMING] ✅ 网站配置初始化成功');
|
||||
// await _kr_checkAndPerformDeviceLogin();
|
||||
} else {
|
||||
print('⚠️ 网站配置初始化失败,将使用默认配置');
|
||||
KRLogUtil.kr_w('⚠️ 网站配置初始化失败,将使用默认配置', tag: 'SplashController');
|
||||
}
|
||||
print('📞 准备调用 KRDomain.kr_loadBaseDomain()...');
|
||||
await KRDomain.kr_loadBaseDomain();
|
||||
print('📞 KRDomain.kr_loadBaseDomain() 完成');
|
||||
}
|
||||
|
||||
/// 检查并执行设备登录(后台执行,有超时保护)
|
||||
Future<void> _kr_checkAndPerformDeviceLogin() async {
|
||||
try {
|
||||
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
print('🔍 检查是否支持设备登录...');
|
||||
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
|
||||
final siteConfigService = KRSiteConfigService();
|
||||
|
||||
// 检查是否启用设备登录
|
||||
final isDeviceLoginEnabled = siteConfigService.isDeviceLoginEnabled();
|
||||
print('📱 设备登录状态: ${isDeviceLoginEnabled ? "已启用" : "未启用"}');
|
||||
KRLogUtil.kr_i('📱 设备登录状态: $isDeviceLoginEnabled', tag: 'SplashController');
|
||||
|
||||
if (!isDeviceLoginEnabled) {
|
||||
print('⚠️ 设备登录未启用,跳过自动登录');
|
||||
KRLogUtil.kr_w('⚠️ 设备登录未启用', tag: 'SplashController');
|
||||
return;
|
||||
}
|
||||
|
||||
print('✅ 设备登录已启用,开始初始化设备信息...');
|
||||
|
||||
// 🔧 Android 15 优化:延长设备登录超时到15秒,匹配网络请求超时
|
||||
await Future.any([
|
||||
_executeDeviceLogin(),
|
||||
Future.delayed(const Duration(seconds: 15), () {
|
||||
throw TimeoutException('设备登录超时(15秒)');
|
||||
}),
|
||||
]);
|
||||
|
||||
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
} on TimeoutException catch (e) {
|
||||
print('⏱️ 设备登录超时,应用将继续启动: $e');
|
||||
KRLogUtil.kr_w('⏱️ 设备登录超时: $e', tag: 'SplashController');
|
||||
} catch (e, stackTrace) {
|
||||
print('❌ 设备登录检查异常: $e');
|
||||
print('📚 堆栈跟踪: $stackTrace');
|
||||
KRLogUtil.kr_e('❌ 设备登录检查异常: $e', tag: 'SplashController');
|
||||
}
|
||||
}
|
||||
|
||||
/// 执行设备登录
|
||||
Future<void> _executeDeviceLogin() async {
|
||||
// 初始化设备信息服务
|
||||
await KRDeviceInfoService().initialize();
|
||||
|
||||
print('🔐 开始执行设备登录...');
|
||||
KRLogUtil.kr_i('🔐 开始执行设备登录', tag: 'SplashController');
|
||||
|
||||
// 执行设备登录
|
||||
final authApi = KRAuthApi();
|
||||
final result = await authApi.kr_deviceLogin();
|
||||
|
||||
result.fold(
|
||||
(error) {
|
||||
print('❌ 设备登录失败: ${error.msg}');
|
||||
KRLogUtil.kr_e('❌ 设备登录失败: ${error.msg}', tag: 'SplashController');
|
||||
},
|
||||
(token) async {
|
||||
print('✅ 设备登录成功!');
|
||||
print('🎫 Token: ${token.substring(0, min(20, token.length))}...');
|
||||
KRLogUtil.kr_i('✅ 设备登录成功', tag: 'SplashController');
|
||||
|
||||
// 使用 saveUserInfo 保存完整的用户信息
|
||||
// 设备登录使用特殊的账号标识,登录类型设为邮箱(后续可以绑定真实账号)
|
||||
final deviceId = KRDeviceInfoService().deviceId ?? 'unknown';
|
||||
await KRAppRunData.getInstance().kr_saveUserInfo(
|
||||
token,
|
||||
'device_$deviceId', // 使用设备ID作为临时账号
|
||||
KRLoginType.kr_email, // 默认登录类型
|
||||
null, // 设备登录无需区号
|
||||
);
|
||||
print('💾 用户信息已保存(包括Token)');
|
||||
print('✅ 已标记为登录状态');
|
||||
KRLogUtil.kr_i('✅ 设备登录流程完成', tag: 'SplashController');
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _kr_initialize() async {
|
||||
try {
|
||||
_initLog.logPhaseStart('主初始化流程');
|
||||
_initLog.log('开始执行 _kr_initialize', tag: 'Splash');
|
||||
KRLogUtil.kr_i('🔧 开始执行 _kr_initialize', tag: 'SplashController');
|
||||
|
||||
// 🔧 Android 15 优化:添加总体超时保护(15秒),更快响应
|
||||
@@ -304,7 +187,8 @@ class KRSplashController extends GetxController {
|
||||
_handleError('网络连接失败', '请检查您的网络连接是否正常,然后重试。');
|
||||
} on DioException catch (e) {
|
||||
// 🔧 P2优化:HTTP请求错误
|
||||
KRLogUtil.kr_e('❌ HTTP请求错误: ${e.type} - ${e.message}', tag: 'SplashController');
|
||||
KRLogUtil.kr_e('❌ HTTP请求错误: ${e.type} - ${e.message}',
|
||||
tag: 'SplashController');
|
||||
final errorMsg = _getDioErrorMessage(e);
|
||||
_handleError('服务请求失败', errorMsg);
|
||||
} catch (e) {
|
||||
@@ -328,10 +212,13 @@ class KRSplashController extends GetxController {
|
||||
// 1. 设置默认域名(确保应用有可用域名)
|
||||
try {
|
||||
_initLog.log('步骤1: 设置默认域名', tag: 'Minimal');
|
||||
if (KRDomain.kr_currentDomain.isEmpty && KRDomain.kr_baseDomains.isNotEmpty) {
|
||||
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');
|
||||
_initLog.logSuccess('设置默认域名: ${KRDomain.kr_currentDomain}',
|
||||
tag: 'Minimal');
|
||||
KRLogUtil.kr_i('✅ 设置默认域名: ${KRDomain.kr_currentDomain}',
|
||||
tag: 'SplashController');
|
||||
if (kDebugMode) {
|
||||
print('✅ 设置默认域名: ${KRDomain.kr_currentDomain}');
|
||||
}
|
||||
@@ -509,21 +396,15 @@ class KRSplashController extends GetxController {
|
||||
|
||||
Future<void> _kr_continueInitialization() async {
|
||||
try {
|
||||
_initLog.logSeparator();
|
||||
_initLog.log('🚀 启动页主流程开始', tag: 'Continue');
|
||||
_initLog.logSeparator();
|
||||
|
||||
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
||||
KRLogUtil.kr_i('🚀 启动页主流程开始...', tag: 'SplashController');
|
||||
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
||||
|
||||
// 🔧 Android 15 优化:网络连接检查改为非阻塞
|
||||
if (Platform.isIOS || Platform.isAndroid) {
|
||||
_initLog.log('📱 检查网络连接状态(超时5秒)', tag: 'Continue');
|
||||
KRLogUtil.kr_i('📱 检查网络连接...', tag: 'SplashController');
|
||||
try {
|
||||
// 添加5秒超时保护
|
||||
final bool isConnected = await KRNetworkCheck.kr_checkNetworkConnection().timeout(
|
||||
final bool isConnected =
|
||||
await KRNetworkCheck.kr_checkNetworkConnection().timeout(
|
||||
const Duration(seconds: 5),
|
||||
onTimeout: () {
|
||||
_initLog.logWarning('网络连接检查超时(5秒),继续初始化', tag: 'Continue');
|
||||
@@ -550,8 +431,6 @@ class KRSplashController extends GetxController {
|
||||
KRLogUtil.kr_i('💻 桌面平台,跳过网络连接检查', tag: 'SplashController');
|
||||
}
|
||||
|
||||
// 网络检查完成后执行设备登录(始终支持)
|
||||
|
||||
// 🔧 关键修复:在设备登录前先初始化站点配置,确保域名可用
|
||||
// 这样如果主域名不可用,initSiteConfig 会切换到备用域名
|
||||
// 后续的设备登录就能使用正确的域名
|
||||
@@ -561,7 +440,8 @@ class KRSplashController extends GetxController {
|
||||
|
||||
_logStepTiming('开始设备登录检查');
|
||||
// 5️⃣ 执行设备登录
|
||||
final success = await KRAppRunData.getInstance().kr_checkAndPerformDeviceLogin();
|
||||
final success =
|
||||
await KRAppRunData.getInstance().kr_checkAndPerformDeviceLogin();
|
||||
|
||||
if (!success) {
|
||||
// 设备登录失败 → 提示用户重试
|
||||
@@ -582,7 +462,7 @@ class KRSplashController extends GetxController {
|
||||
// 下面AppConfig().initConfig主要是做AppConfig层面的配置加载,可能包含重复的请求。
|
||||
// 鉴于 AppConfig().initConfig 也会调用 API,为了保险起见,
|
||||
// 我们可以让 AppConfig().initConfig 使用已经切换好的域名。)
|
||||
|
||||
|
||||
_initLog.log('⚙️ 开始初始化应用配置(域名加载等)', tag: 'Continue');
|
||||
KRLogUtil.kr_i('⚙️ 开始初始化应用配置...', tag: 'SplashController');
|
||||
await AppConfig().initConfig(
|
||||
@@ -605,12 +485,7 @@ class KRSplashController extends GetxController {
|
||||
// 配置初始化成功后的后续步骤
|
||||
Future<void> _kr_continueAfterConfig() async {
|
||||
try {
|
||||
// 用户信息初始化完成后,立即初始化订阅服务
|
||||
print('[SPLASH_TIMING] 🔄 开始初始化订阅服务...');
|
||||
KRLogUtil.kr_i('[SPLASH_TIMING] 🔄 开始初始化订阅服务', tag: 'SplashController');
|
||||
_kr_ensureSubscribeServiceInitialized();
|
||||
|
||||
// 初始化SingBox
|
||||
// 初始化SingBox(必须先于订阅服务,避免目录未初始化)
|
||||
_logStepTiming('开始SingBox初始化');
|
||||
await KRSingBoxImp.instance.init();
|
||||
_logStepTiming('SingBox初始化完成');
|
||||
@@ -620,20 +495,12 @@ class KRSplashController extends GetxController {
|
||||
final token = KRAppRunData.getInstance().kr_token;
|
||||
final hasToken = token != null && token.isNotEmpty;
|
||||
|
||||
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
print('🎯 准备进入主页');
|
||||
print('📊 最终登录状态: $loginStatus');
|
||||
print('🎫 Token存在: $hasToken');
|
||||
if (hasToken) {
|
||||
print('🎫 Token前缀: ${token.substring(0, min(20, token.length))}...');
|
||||
}
|
||||
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
|
||||
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
||||
KRLogUtil.kr_i('🎯 准备进入主页', tag: 'SplashController');
|
||||
KRLogUtil.kr_i('📊 最终登录状态: $loginStatus', tag: 'SplashController');
|
||||
KRLogUtil.kr_i('🎫 Token存在: $hasToken', tag: 'SplashController');
|
||||
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
|
||||
|
||||
// 🔧 记录最终状态到日志
|
||||
_initLog.logSeparator();
|
||||
@@ -652,12 +519,13 @@ class KRSplashController extends GetxController {
|
||||
|
||||
// 直接导航到主页(无论是否登录,主页会根据登录状态显示不同内容)
|
||||
_logStepTiming('开始页面导航');
|
||||
if(loginStatus) {
|
||||
if (loginStatus) {
|
||||
// 直接导航到主页
|
||||
Get.offAllNamed(Routes.KR_HOME);
|
||||
}else {
|
||||
} else {
|
||||
kr_hasError.value = true;
|
||||
kr_errorMessage.value = '登录:${AppTranslations.kr_splash.kr_initializationFailed}';
|
||||
kr_errorMessage.value =
|
||||
'登录:${AppTranslations.kr_splash.kr_initializationFailed}';
|
||||
}
|
||||
_logStepTiming('页面导航完成');
|
||||
} catch (e) {
|
||||
@@ -667,63 +535,22 @@ class KRSplashController extends GetxController {
|
||||
final totalMs = totalDuration.inMilliseconds;
|
||||
|
||||
print('❌ 启动失败时间: ${endTime.toIso8601String()}');
|
||||
print('🕐 启动失败总耗时: ${totalMs}ms (${totalDuration.inSeconds}.${(totalMs % 1000).toString().padLeft(3, '0')}s)');
|
||||
print(
|
||||
'🕐 启动失败总耗时: ${totalMs}ms (${totalDuration.inSeconds}.${(totalMs % 1000).toString().padLeft(3, '0')}s)');
|
||||
|
||||
// 后续步骤失败,显示错误信息
|
||||
_initLog.logError('启动初始化失败', tag: 'Splash', error: e);
|
||||
KRLogUtil.kr_e('启动初始化失败: $e', tag: 'SplashController');
|
||||
KRLogUtil.kr_e('⏰ 启动失败总耗时: ${totalMs}ms', tag: 'SplashController');
|
||||
kr_hasError.value = true;
|
||||
kr_errorMessage.value = '${AppTranslations.kr_splash.kr_initializationFailed}$e';
|
||||
kr_errorMessage.value =
|
||||
'${AppTranslations.kr_splash.kr_initializationFailed}$e';
|
||||
|
||||
// 🔧 错误情况下也不关闭日志,让后续的错误处理也能写入
|
||||
// await _initLog.finalize(); // ❌ 注释掉
|
||||
}
|
||||
}
|
||||
|
||||
/// 确保订阅服务初始化
|
||||
Future<void> _kr_ensureSubscribeServiceInitialized() async {
|
||||
try {
|
||||
// 检查订阅服务状态
|
||||
final currentStatus = kr_subscribeService.kr_currentStatus.value;
|
||||
KRLogUtil.kr_i('订阅服务当前状态: $currentStatus', tag: 'SplashController');
|
||||
|
||||
if (currentStatus == KRSubscribeServiceStatus.kr_none ||
|
||||
currentStatus == KRSubscribeServiceStatus.kr_error) {
|
||||
KRLogUtil.kr_i(
|
||||
'订阅服务未初始化或错误,开始初始化', tag: 'SplashController');
|
||||
|
||||
// 初始化订阅服务并等待完成
|
||||
// 设置加载状态
|
||||
KRHomeController().kr_currentListStatus.value = KRHomeViewsListStatus.kr_loading;
|
||||
try {
|
||||
await kr_subscribeService.kr_refreshAll();
|
||||
KRLogUtil.kr_i('订阅服务初始化完成', tag: 'SplashController');
|
||||
} catch (error) {
|
||||
KRLogUtil.kr_e('订阅服务初始化失败: $error', tag: 'SplashController');
|
||||
// 重新抛出异常,让调用方知道初始化失败
|
||||
KRHomeController().kr_currentListStatus.value = KRHomeViewsListStatus.kr_error;
|
||||
rethrow;
|
||||
}
|
||||
} else if (currentStatus == KRSubscribeServiceStatus.kr_loading) {
|
||||
KRLogUtil.kr_i('订阅服务正在初始化中', tag: 'SplashController');
|
||||
// 如果正在加载中,等待加载完成
|
||||
while (kr_subscribeService.kr_currentStatus.value == KRSubscribeServiceStatus.kr_loading) {
|
||||
await Future.delayed(Duration(milliseconds: 100));
|
||||
}
|
||||
KRLogUtil.kr_i('订阅服务加载完成,最终状态: ${kr_subscribeService.kr_currentStatus.value}', tag: 'SplashController');
|
||||
KRHomeController().kr_currentListStatus.value = KRHomeViewsListStatus.kr_loading;
|
||||
} else if (currentStatus == KRSubscribeServiceStatus.kr_success) {
|
||||
KRHomeController().kr_currentListStatus.value = KRHomeViewsListStatus.kr_none;
|
||||
KRLogUtil.kr_i('订阅服务已成功初始化', tag: 'SplashController');
|
||||
}
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('确保订阅服务初始化失败: $e', tag: 'SplashController');
|
||||
KRHomeController().kr_currentListStatus.value = KRHomeViewsListStatus.kr_error;
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// 重试按钮点击事件
|
||||
void kr_retry() {
|
||||
kr_hasError.value = false;
|
||||
@@ -749,15 +576,15 @@ class KRSplashController extends GetxController {
|
||||
/// 防止旧的测试账号在新安装时被恢复
|
||||
Future<void> _kr_clearOldLocalData() async {
|
||||
try {
|
||||
KRLogUtil.kr_i('🧹 开始清理旧本地存储数据...', tag: 'SplashController');
|
||||
// KRLogUtil.kr_i('🧹 开始清理旧本地存储数据...', tag: 'SplashController');
|
||||
|
||||
// 清理用户信息存储
|
||||
await KRSecureStorage().kr_deleteData(key: 'USER_INFO');
|
||||
KRLogUtil.kr_i('✅ 已清理USER_INFO', tag: 'SplashController');
|
||||
// KRLogUtil.kr_i('✅ 已清理USER_INFO', tag: 'SplashController');
|
||||
|
||||
// 清理设备登录状态
|
||||
await KRSecureStorage().kr_deleteData(key: 'DEVICE_INFO');
|
||||
KRLogUtil.kr_i('✅ 已清理DEVICE_INFO', tag: 'SplashController');
|
||||
// KRLogUtil.kr_i('✅ 已清理DEVICE_INFO', tag: 'SplashController');
|
||||
|
||||
KRLogUtil.kr_i('✅ 旧本地存储数据已全部清理', tag: 'SplashController');
|
||||
} catch (e) {
|
||||
@@ -775,4 +602,4 @@ class KRSplashController extends GetxController {
|
||||
void onClose() {
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user