You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

490 lines
15 KiB

import 'package:flutter_screenutil/flutter_screenutil.dart';
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 '../../ota_upgrade/controllers/ota_core_contropller.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;
// 添加电池信息定时刷新相关变量
Timer? _batteryRefreshTimer;
static const Duration _batteryRefreshInterval =
Duration(seconds: 2); // 2秒刷新一次
// 添加OTA升级检查相关变量
final _otaCoreService = OtaCoreService();
static bool _hasCheckedOta = false; // 防止重复检查
bool get isFullyConnected => _isFullyConnected.value;
RxBool get isFullyConnectedRx => _isFullyConnected;
BluetoothDevice? get currentDevice => _bluetoothManager.currentDevice;
Rx<DeviceInfo?> 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<BluetoothManager>();
final _bleManager = Get.find<BleManager>();
final noviceGuideService = Get.find<NoviceGuideService>();
@override
void onInit() {
super.onInit();
_initWithCachedInfo();
_startBatteryRefreshTimer(); // 启动电池信息定时刷新
}
@override
void onClose() {
_deviceInfoWorker?.dispose();
_classicBluetoothWorker?.dispose();
_bleConnectionWorker?.dispose();
_stopBatteryRefreshTimer(); // 停止定时器
super.onClose();
}
void _initWithCachedInfo() {
_setupStateListeners();
_checkConnectionStatus();
}
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<void> refreshDeviceConnection() async {
await _checkConnectionStatus();
// 如果设备已连接,立即刷新电池信息
if (_isFullyConnected.value) {
await _refreshBatteryInfo();
}
}
void rescanDevices() {
Get.toNamed(Routes.pairing);
}
void openTranslation() {
Get.toNamed(Routes.translation);
}
void exploreAIFeatures() {
Get.toNamed(Routes.agent);
}
Future<void> _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();
// 连接成功后立即刷新一次电池信息
Future.delayed(const Duration(milliseconds: 500), () {
_refreshBatteryInfo();
});
// 连接成功后检查OTA升级
Future.delayed(const Duration(seconds: 2), () {
_checkOtaUpgrade();
});
}
// 根据连接状态控制定时器
if (isNowConnected) {
_startBatteryRefreshTimer(); // 连接时启动定时器
} else {
_stopBatteryRefreshTimer(); // 断开时停止定时器
_hasCheckedOta = false; // 重置OTA检查状态
}
}
update();
} catch (e) {
Logger.e(_tag, '${'checkConnectionStatusFailed'.tr}: $e');
if (_isFullyConnected.value) {
_isFullyConnected.value = false;
_isFullyConnected.refresh();
_stopBatteryRefreshTimer(); // 发生错误时停止定时器
_hasCheckedOta = false; // 重置OTA检查状态
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;
}
/// 启动电池信息定时刷新
void _startBatteryRefreshTimer() {
_stopBatteryRefreshTimer(); // 先停止现有定时器
_batteryRefreshTimer = Timer.periodic(_batteryRefreshInterval, (timer) {
// 只有在设备完全连接时才刷新电池信息
if (_isFullyConnected.value) {
_refreshBatteryInfo();
}
});
Logger.d(_tag, '电池信息定时刷新已启动,间隔: ${_batteryRefreshInterval.inSeconds}秒');
}
/// 停止电池信息定时刷新
void _stopBatteryRefreshTimer() {
if (_batteryRefreshTimer != null) {
_batteryRefreshTimer!.cancel();
_batteryRefreshTimer = null;
Logger.d(_tag, '电池信息定时刷新已停止');
}
}
/// 刷新电池信息
Future<void> _refreshBatteryInfo() async {
try {
if (!_isFullyConnected.value) {
return;
}
//Logger.d(_tag, '开始刷新电池信息...');
// 通过BLE管理器获取最新的电池信息
final success = await _bleManager.fetchBatteryInfo();
if (success) {
//Logger.d(_tag, '电池信息刷新请求发送成功');
} else {
//Logger.w(_tag, '电池信息刷新请求发送失败');
}
} catch (e) {
//Logger.e(_tag, '刷新电池信息时发生错误: $e');
}
}
/// 检查OTA固件升级
/// 在BLE连接成功后调用,检查是否需要升级
Future<void> _checkOtaUpgrade() async {
try {
// 防止重复检查
if (_hasCheckedOta) {
return;
}
Logger.d(_tag, '开始检查OTA固件升级...');
// 检查BLE连接状态
if (!_isFullyConnected.value) {
Logger.d(_tag, '设备未完全连接,跳过OTA检查');
return;
}
// 获取当前版本信息
final currentInfo = await _otaCoreService.getCurrentVersionInfo();
final currentVersion = currentInfo['currentVersion'] as String;
// 获取最新版本信息
final latestInfo = await _otaCoreService.getLatestVersionInfo();
final latestVersion = latestInfo['latestVersion'] as String;
Logger.d(_tag, '当前版本: $currentVersion, 最新版本: $latestVersion');
// 检查是否有更新
final hasUpdate =
_otaCoreService.isNewVersionAvailable(currentVersion, latestVersion);
if (hasUpdate) {
Logger.d(_tag, '发现新版本,显示升级提醒');
_showOtaUpgradeDialog(
latestVersion, latestInfo['updateDescription'] as String?);
} else {
Logger.d(_tag, '当前已是最新版本');
}
_hasCheckedOta = true;
} catch (e) {
Logger.e(_tag, '检查OTA升级失败: $e');
// 即使检查失败,也标记为已检查,避免重复尝试
_hasCheckedOta = true;
}
}
/// 显示OTA升级提醒对话框
/// [latestVersion] 最新版本号
/// [updateDescription] 更新描述
void _showOtaUpgradeDialog(String latestVersion, String? updateDescription) {
Get.dialog(
AlertDialog(
title: Row(
children: [
Icon(
Icons.headset,
color: Colors.blue[600],
size: 24.sp,
),
SizedBox(width: 8.w),
Text(
'ota_newVersionFound'.tr,
style: TextStyle(
color: Colors.blue[700],
fontWeight: FontWeight.w600,
),
),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${'latestFirmwareVersion'.tr}: $latestVersion',
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 16.sp,
),
),
// if (updateDescription != null && updateDescription.isNotEmpty)
// SizedBox(height: 8.sp),
// if (updateDescription != null && updateDescription.isNotEmpty)
// Text(
// updateDescription,
// style: TextStyle(
// color: Colors.grey[600],
// fontSize: 14.sp,
// ),
// ),
// if (updateDescription != null && updateDescription.isNotEmpty)
// SizedBox(height: 8.sp),
// Text(
// '建议及时升级以获得更好的使用体验',
// style: TextStyle(
// color: Colors.orange[700],
// fontSize: 12.sp,
// ),
// ),
],
),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// 稍后再说 (靠左)
TextButton(
onPressed: () {
Logger.d(_tag, '用户取消OTA升级');
Get.back();
},
child: Text(
'talkLater'.tr,
style: TextStyle(color: Colors.grey[600]),
),
),
// 立即升级 (靠右)
ElevatedButton(
onPressed: () {
Logger.d(_tag, '用户确认OTA升级,跳转到升级页面');
Get.back();
Get.toNamed(Routes.OTA_UPGRADE);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue[600],
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.sp),
),
),
child: Text(
'ota_updateNow'.tr,
style: TextStyle(fontSize: 14.sp),
),
),
],
),
],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.sp),
),
backgroundColor: Colors.white,
),
);
}
}