import 'package:get/get.dart'; import 'dart:async'; import '../../../data/services/novice_guide_service.dart'; import '../../../routes/app_routes.dart'; import '../../../core/utils/logger.dart'; import 'package:flutter/material.dart'; import '../../../data/services/bluetooth_manager.dart'; import '../../../data/services/ble_manager.dart'; import '../../../data/services/version_update_service.dart'; import '../../common/widgets/version_update_dialog.dart'; import 'package:get_storage/get_storage.dart'; /// 连接状态枚举 enum ConnectionStatus { disconnected, // 未连接 connecting, // 连接中 connected, // 已连接 failed // 连接失败 } /// 主页控制器,管理设备连接状态和信息展示 class HomeController extends GetxController { static const String _tag = 'HomeCtrl'; static HomeController get to => Get.find(); final _isFullyConnected = false.obs; String? _lastConnectedDeviceName; bool get isFullyConnected => _isFullyConnected.value; RxBool get isFullyConnectedRx => _isFullyConnected; BluetoothDevice? get currentDevice => _bluetoothManager.currentDevice; Rx get deviceInfo => _bleManager.deviceInfo; final leftEarBattery = 0.obs; final rightEarBattery = 0.obs; final caseBattery = 0.obs; final leftEarCharging = false.obs; final rightEarCharging = false.obs; final caseCharging = false.obs; final firmwareVersion = ''.obs; void updateDeviceInfo(DeviceInfo? newDeviceInfo) { leftEarBattery.value = newDeviceInfo?.leftEarBattery ?? 0; rightEarBattery.value = newDeviceInfo?.rightEarBattery ?? 0; caseBattery.value = newDeviceInfo?.caseBattery ?? 0; leftEarCharging.value = newDeviceInfo?.leftEarCharging ?? false; rightEarCharging.value = newDeviceInfo?.rightEarCharging ?? false; caseCharging.value = newDeviceInfo?.caseCharging ?? false; firmwareVersion.value = newDeviceInfo?.firmwareVersion ?? ''; } Worker? _deviceInfoWorker; Worker? _classicBluetoothWorker; Worker? _bleConnectionWorker; final _bluetoothManager = Get.find(); final _bleManager = Get.find(); final _storage = GetStorage(); final noviceGuideService = Get.find(); // 会话级别的版本检查标记(静态变量,整个应用会话期间保持) static bool _hasCheckedVersionInSession = false; // 版本检查相关常量 static const String _lastVersionCheckKey = 'last_version_check_timestamp'; static const int _versionCheckIntervalHours = 24; // 24小时间隔 @override void onInit() { super.onInit(); _initWithCachedInfo(); } @override void onClose() { _deviceInfoWorker?.dispose(); _classicBluetoothWorker?.dispose(); _bleConnectionWorker?.dispose(); super.onClose(); } void _initWithCachedInfo() { _setupStateListeners(); _checkConnectionStatus(); // 延迟检查版本更新,避免影响页面加载 // 混合检查机制:会话检查 + 24小时间隔检查 Future.delayed(const Duration(seconds: 2), () { _checkVersionUpdateIfNeeded(); }); } void _setupStateListeners() { _deviceInfoWorker = ever(_bleManager.deviceInfo, (DeviceInfo? info) { if (info != null) { updateDeviceInfo(info); } update(); }); _classicBluetoothWorker = ever(_bluetoothManager.currentDeviceRx, (BluetoothDevice? device) { if (device != null) { _lastConnectedDeviceName = device.name; } _checkConnectionStatus(); }); _bleConnectionWorker = ever(_bleManager.connectionStateRx, (int state) { _checkConnectionStatus(); }); } Future refreshDeviceConnection() async { await _checkConnectionStatus(); } void rescanDevices() { Get.toNamed(Routes.pairing); } void openTranslation() { Get.toNamed(Routes.translation); } void exploreAIFeatures() { Get.toNamed(Routes.agent); } Future _checkConnectionStatus() async { try { final currentBleState = await _bleManager.getConnectionState(); bool hasClassicBluetooth = currentDevice != null; bool hasBleConnection = currentBleState == 2; bool wasConnected = _isFullyConnected.value; bool isNowConnected = hasClassicBluetooth && hasBleConnection; if (isNowConnected && currentDevice == null) { isNowConnected = false; } if (_isFullyConnected.value != isNowConnected) { _isFullyConnected.value = isNowConnected; _isFullyConnected.refresh(); update(); if (!wasConnected && isNowConnected) { await _bleManager.fetchDeviceInfo(); } } update(); } catch (e) { Logger.e(_tag, '${'checkConnectionStatusFailed'.tr}: $e'); if (_isFullyConnected.value) { _isFullyConnected.value = false; _isFullyConnected.refresh(); update(); } } } Color getConnectionStatusColor() { return _isFullyConnected.value ? Colors.green : Colors.grey; } String getConnectionStatusText() { return _isFullyConnected.value ? 'connected'.tr : 'unconnected'.tr; } bool get shouldShowDeviceInfo => currentDevice != null; String getDeviceName() { if (_isFullyConnected.value && currentDevice == null) { _checkConnectionStatus(); } final deviceName = currentDevice?.name; if (deviceName != null && deviceName.isNotEmpty) { return deviceName; } final bleDeviceName = deviceInfo.value?.name; if (bleDeviceName != null && bleDeviceName.isNotEmpty) { return bleDeviceName; } if (!_isFullyConnected.value && _lastConnectedDeviceName != null && _lastConnectedDeviceName!.isNotEmpty) { return _lastConnectedDeviceName!; } return 'unknownEquipment'.tr; } String getSignalStrength() { if (!_isFullyConnected.value) { return 'zeroSignal'.tr; } final random = DateTime.now().millisecondsSinceEpoch % 3; switch (random) { case 0: return 'good'.tr; case 1: return 'fine'.tr; default: return 'excellent'.tr; } } String getDeviceId() { return deviceInfo.value?.address ?? currentDevice?.address ?? 'unknown'.tr; } String getBatteryText() { return deviceInfo.value?.batteryLevel != null && deviceInfo.value!.batteryLevel > 0 ? '${deviceInfo.value?.batteryLevel}%' : 'unknown'.tr; } String getEarbudsText() { if (deviceInfo.value == null || (deviceInfo.value!.leftEarBattery <= 0 && deviceInfo.value!.rightEarBattery <= 0 || deviceInfo.value!.caseBattery > 100)) { return 'unknown'.tr; } String leftStatus = deviceInfo.value!.leftEarBattery > 0 ? '${deviceInfo.value!.leftEarBattery}%' : 'N/A'; String rightStatus = deviceInfo.value!.rightEarBattery > 0 ? '${deviceInfo.value!.rightEarBattery}%' : 'N/A'; leftStatus = deviceInfo.value!.leftEarCharging ? '$leftStatus ⚡' : leftStatus; rightStatus = deviceInfo.value!.rightEarCharging ? '$rightStatus ⚡' : rightStatus; return '${'leftEar'.tr}: $leftStatus / ${'rightEar'.tr}: $rightStatus'; // 左耳: xxx / 右耳: xxx } String getCaseText() { if (deviceInfo.value == null || deviceInfo.value!.caseBattery <= 0 || deviceInfo.value!.caseBattery > 100) { return 'unknown'.tr; } String caseStatus = '${deviceInfo.value!.caseBattery}%'; if (deviceInfo.value!.caseCharging) { caseStatus = '$caseStatus ⚡'; } return '${'chargingCase'.tr}: $caseStatus'; // 充电仓: xxx } String getChargingText() { if (deviceInfo.value == null) { return 'unknown'.tr; } bool isCharging = deviceInfo.value!.leftEarCharging || deviceInfo.value!.rightEarCharging || deviceInfo.value!.caseCharging; return isCharging ? 'charging'.tr : 'notCharging'.tr; } String getVersionText() { return deviceInfo.value?.firmwareVersion.isNotEmpty == true ? deviceInfo.value!.firmwareVersion : 'unknown'.tr; } /// 混合检查机制:判断是否需要进行版本检查 /// 检查条件:1. 会话内未检查过 OR 2. 距离上次检查超过24小时 void _checkVersionUpdateIfNeeded() { try { final now = DateTime.now(); final lastCheckTimestamp = _storage.read(_lastVersionCheckKey); bool shouldCheck = false; String reason = ''; // 条件1:会话内未检查过 if (!_hasCheckedVersionInSession) { shouldCheck = true; reason = '会话内首次检查'; } // 条件2:距离上次检查超过24小时 else if (lastCheckTimestamp != null) { final lastCheckTime = DateTime.fromMillisecondsSinceEpoch(lastCheckTimestamp); final timeDifference = now.difference(lastCheckTime); if (timeDifference.inHours >= _versionCheckIntervalHours) { shouldCheck = true; reason = '距离上次检查已超过${_versionCheckIntervalHours}小时'; } } // 条件3:从未检查过(首次使用应用) else { shouldCheck = true; reason = '首次使用应用'; } if (shouldCheck) { Logger.i(_tag, '开始版本检查 - 原因: $reason'); _performVersionCheck(); } else { Logger.i(_tag, '跳过版本检查 - 会话内已检查且未超过时间间隔'); } } catch (e) { Logger.e(_tag, '版本检查判断失败: $e'); } } /// 执行版本检查(在后台进行,不阻塞启动流程) Future _performVersionCheck() async { try { final versionService = VersionUpdateService.to; final updateInfo = await versionService.checkForUpdate(); if (updateInfo.hasUpdate) { Logger.i(_tag, '发现新版本: ${updateInfo.latestVersion}'); // 显示更新对话框 await VersionUpdateDialog.show(updateInfo); } else { Logger.i(_tag, '当前已是最新版本: ${updateInfo.currentVersion}'); } // 更新检查记录 _updateVersionCheckRecord(); } catch (e) { Logger.e(_tag, '版本检查失败: $e'); // 即使检查失败,也更新记录,避免频繁重试 _updateVersionCheckRecord(); } } /// 更新版本检查记录 void _updateVersionCheckRecord() { try { // 更新时间戳 final now = DateTime.now(); _storage.write(_lastVersionCheckKey, now.millisecondsSinceEpoch); // 标记本次会话已检查过版本 _hasCheckedVersionInSession = true; Logger.i(_tag, '版本检查记录已更新: ${now.toIso8601String()}'); } catch (e) { Logger.e(_tag, '更新版本检查记录失败: $e'); } } /// 重置版本检查标记(可用于强制重新检查) /// 注意:这会清除会话标记,但不会清除时间戳记录 static void resetVersionCheckFlag() { _hasCheckedVersionInSession = false; Logger.i('HomeCtrl', '版本检查会话标记已重置'); } /// 完全重置版本检查状态(包括时间戳) /// 用于测试或特殊情况下强制重新检查 void forceResetVersionCheck() { try { _hasCheckedVersionInSession = false; _storage.remove(_lastVersionCheckKey); Logger.i(_tag, '版本检查状态已完全重置'); } catch (e) { Logger.e(_tag, '重置版本检查状态失败: $e'); } } }