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.
733 lines
22 KiB
733 lines
22 KiB
import 'package:classic_bluetooth/classic_bluetooth.dart';
|
|
import 'package:voitrans/data/models/appconfig_model.dart';
|
|
import '/routes/app_routes.dart';
|
|
import 'package:logger/web.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:path/path.dart';
|
|
import 'dart:async';
|
|
import '../../../data/services/network/api.dart';
|
|
import '../model/ota_upgrade_model.dart';
|
|
import 'dart:io';
|
|
import 'package:dio/dio.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'package:ota/ota.dart';
|
|
import '../../../data/services/ble_manager.dart';
|
|
import '../../../data/models/appconfig.dart';
|
|
|
|
class OtaUpgradeController extends GetxController {
|
|
static const int NOT_STARTED = -1; // 未开始
|
|
static const int VALIDATION_FILE = 0; // 验证文件
|
|
static const int ONUPGRADE = 1; // 升级中
|
|
static const int START_UPGRADING = 2; // 开始升级
|
|
static const int UPGRADE_SUCCESS = 3; // 升级成功
|
|
static const int UPGRADE_FAILED = 4; // 升级失败
|
|
static const int CONNECTION_DISCONNECTION = 5; // 连接断开
|
|
static const int CONNECTION_SUCCESS = 6; // 连接成功
|
|
static const int DOWNLOADING_UP_FILES = 7; // 下载升级文件
|
|
|
|
// 错误信息,用于存储错误提示
|
|
final RxString errorMessage = ''.obs;
|
|
|
|
// 最新版本号
|
|
final RxString latestVersion = ''.obs;
|
|
// 最新更新内容
|
|
final RxString updatedescription = ''.obs;
|
|
|
|
// 当前设备固件版本号
|
|
final RxString currentVersion = ''.obs;
|
|
|
|
String _address = '';
|
|
|
|
// 更新包地址,用于下载更新文件
|
|
String updatepackageaddress = '';
|
|
|
|
// 下载进度,范围为 0.0 到 1.0
|
|
final RxDouble downloadProgress = 0.0.obs;
|
|
|
|
// 是否有可用更新的状态
|
|
final isUpdateAvailable = true.obs;
|
|
|
|
// 当前升级进度,范围为 0.0 到 1.0
|
|
// final RxDouble progress = 0.0.obs;
|
|
|
|
// OTA 单例实例,用于处理升级相关逻辑
|
|
final jlota = Ota.instance;
|
|
|
|
// 是否正在下载更新包的状态
|
|
final RxBool isDownloading = false.obs;
|
|
|
|
// 蓝牙管理服务,用于获取设备信息和通信
|
|
final _bleManager = Get.find<BleManager>();
|
|
final maxRetryAttempts = 3; // 最大重试次数
|
|
int currentRetryCount = 0;
|
|
|
|
final RxBool isFetchingDeviceInfo = true.obs;
|
|
|
|
final RxDouble progress = 0.0.obs; // 控制器自己的可观察属性
|
|
final RxInt type = OtaEvent.NOT_STARTED.obs;
|
|
final RxBool isUpgrade = false.obs;
|
|
|
|
// 新增:详细状态提示
|
|
final RxString detailedStatus = ''.obs;
|
|
final RxBool showDetailedStatus = false.obs;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
_getCurrentVersion();
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
jlota.onOtaClose();
|
|
_bleManager.setEnterOta(false);
|
|
isUpgrade.value = false;
|
|
super.onClose();
|
|
}
|
|
|
|
// 添加重试方法
|
|
void retryConnection() {
|
|
errorMessage.value = '';
|
|
_getCurrentVersion();
|
|
}
|
|
|
|
String getStatusMessage(int type) {
|
|
switch (type) {
|
|
case NOT_STARTED: // -1
|
|
return "未开始".tr;
|
|
case VALIDATION_FILE: // 0
|
|
return "验证文件中".tr;
|
|
case ONUPGRADE: // 1
|
|
return "升级中".tr;
|
|
case START_UPGRADING: // 2
|
|
return "开始升级".tr;
|
|
case UPGRADE_SUCCESS: // 3
|
|
return "升级成功".tr;
|
|
case UPGRADE_FAILED: // 4
|
|
return "升级失败".tr;
|
|
case CONNECTION_DISCONNECTION: // 5
|
|
return "连接断开".tr;
|
|
case CONNECTION_SUCCESS: // 6
|
|
return "连接成功".tr;
|
|
case DOWNLOADING_UP_FILES: // 7 (新增)
|
|
return "下载升级文件".tr;
|
|
default:
|
|
return "未知状态".tr; // 更安全的默认值
|
|
}
|
|
}
|
|
|
|
// 添加更新方法
|
|
Future<void> startUpdate() async {
|
|
try {
|
|
checkUpdate();
|
|
|
|
// 实现更新逻辑...
|
|
} catch (e) {
|
|
errorMessage.value = e.toString();
|
|
Get.snackbar(
|
|
'更新失败',
|
|
e.toString(),
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.red[600],
|
|
colorText: Colors.white,
|
|
icon: const Icon(
|
|
Icons.error_outline,
|
|
color: Colors.white,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<void> _getCurrentVersion() async {
|
|
_listenToEvents();
|
|
try {
|
|
isFetchingDeviceInfo.value = true;
|
|
errorMessage.value = '';
|
|
// 添加获取设备信息的重试机制
|
|
DeviceInfo? deviceInfo = _bleManager.deviceInfo.value;
|
|
|
|
// // 第一次检查设备信息
|
|
// if (deviceInfo == null) {
|
|
// // 尝试重新获取设备信息
|
|
// await _bleManager.fetchDeviceInfo();
|
|
// }
|
|
|
|
while (currentRetryCount < maxRetryAttempts) {
|
|
deviceInfo = _bleManager.deviceInfo.value;
|
|
|
|
// 检查信息有效性
|
|
if (deviceInfo != null &&
|
|
deviceInfo.firmwareVersion.isNotEmpty &&
|
|
deviceInfo.firmwareProductId.isNotEmpty) {
|
|
break;
|
|
}
|
|
|
|
// 获取设备信息
|
|
await _bleManager.fetchDeviceInfo();
|
|
await Future.delayed(const Duration(seconds: 5));
|
|
currentRetryCount++;
|
|
}
|
|
// 最终验证
|
|
if (deviceInfo == null ||
|
|
deviceInfo.firmwareVersion.isEmpty ||
|
|
deviceInfo.firmwareProductId.isEmpty) {
|
|
throw "获取设备信息失败,请检查连接";
|
|
}
|
|
// 拆分 firmwareVersion 并判断两边是否一致
|
|
final firmwareParts = deviceInfo.firmwareVersion.split('.');
|
|
|
|
// 从第三个 `.` 开始分割
|
|
final firstPart = firmwareParts.sublist(0, 3).join('.');
|
|
final secondPart = firmwareParts.sublist(3).join('.');
|
|
Logger().d("firstPart${firstPart},secondPart=${secondPart}");
|
|
// 判断两部分是否一致
|
|
if (firstPart != secondPart) {
|
|
throw "固件版本格式错误:${deviceInfo.firmwareVersion}";
|
|
}
|
|
|
|
// 正常流程
|
|
currentVersion.value = firstPart;
|
|
Logger().d('getequipmentinfo,id: ${deviceInfo.firmwareProductId}');
|
|
|
|
final connectedDevices = await ClassicBluetooth.getConnectedDevices();
|
|
if (connectedDevices.isNotEmpty) {
|
|
_address = connectedDevices.first.address;
|
|
}
|
|
|
|
DBProduct? product = AppConfig.getproduct("DeapSound");
|
|
|
|
// // API请求
|
|
// final response = await Api.getproduct({
|
|
// "id": deviceInfo.firmwareProductId,
|
|
// });
|
|
|
|
// // 处理API响应
|
|
// if (response['product'] == null) {
|
|
// throw const FormatException('API 响应格式错误');
|
|
// }
|
|
|
|
// final resp = OtaConfigResp.fromJson(response);
|
|
// Logger().d('getequipmentinfo,resp.systemversion: ${resp.systemversion}');
|
|
latestVersion.value = product?.version ?? "";
|
|
// updatedescription.value = resp.updatedescription!;
|
|
updatepackageaddress = product!.updatepackageaddress!;
|
|
|
|
// 版本检查
|
|
bool isUpdate = _isNewVersionAvailable(product.version!);
|
|
|
|
|
|
isUpdateAvailable.value = isUpdate;
|
|
} catch (e) {
|
|
// 统一错误处理
|
|
errorMessage.value = e.toString();
|
|
Get.snackbar(
|
|
'错误',
|
|
e.toString(),
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.red[600],
|
|
colorText: Colors.white,
|
|
icon: const Icon(
|
|
Icons.error_outline,
|
|
color: Colors.white,
|
|
),
|
|
);
|
|
// 重要:重新抛出异常以便上层处理(可选)
|
|
} finally {
|
|
isFetchingDeviceInfo.value = false;
|
|
}
|
|
}
|
|
|
|
// 版本比较方法优化
|
|
bool _isNewVersionAvailable(String latest) {
|
|
try {
|
|
List<int> currentParts = currentVersion.value
|
|
.split('.')
|
|
.map((e) => int.parse(e.trim()))
|
|
.toList();
|
|
List<int> latestParts =
|
|
latest.split('.').map((e) => int.parse(e.trim())).toList();
|
|
|
|
for (int i = 0; i < latestParts.length; i++) {
|
|
int current = (i < currentParts.length) ? currentParts[i] : 0;
|
|
if (latestParts[i] > current) return true;
|
|
if (latestParts[i] < current) return false;
|
|
}
|
|
return false;
|
|
} catch (e) {
|
|
Logger().d('版本比较错误: $e');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// 版本更新
|
|
Future<void> checkUpdate() async {
|
|
try {
|
|
if (latestVersion.value != "") {
|
|
_showUpdateDialog(latestVersion.value);
|
|
} else {
|
|
Get.snackbar(
|
|
'错误',
|
|
'获取最新版本信息失败',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.orange[800],
|
|
colorText: Colors.white,
|
|
icon: const Icon(
|
|
Icons.error_outline,
|
|
color: Colors.white,
|
|
),
|
|
);
|
|
}
|
|
} catch (e) {
|
|
Get.snackbar(
|
|
'错误',
|
|
'获取版本信息失败',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.orange[800],
|
|
colorText: Colors.white,
|
|
icon: const Icon(
|
|
Icons.error_outline,
|
|
color: Colors.white,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
void _showUpdateDialog(String latest) async {
|
|
Logger().d('显示更新对话框');
|
|
Get.dialog(
|
|
AlertDialog(
|
|
title: Text('发现新版本 $latest'),
|
|
content: Text('是否立即更新?'),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () async {
|
|
Logger().d('取消按钮被点击');
|
|
|
|
Get.back();
|
|
Future.delayed(Duration(milliseconds: 300));
|
|
},
|
|
child: Text('取消'),
|
|
),
|
|
TextButton(
|
|
onPressed: () async {
|
|
Logger().d('更新按钮被点击');
|
|
|
|
Get.back();
|
|
Future.delayed(Duration(milliseconds: 300));
|
|
|
|
// 检查设备电量
|
|
if (!_checkBatteryLevel()) {
|
|
return; // 电量不足,不执行升级
|
|
}
|
|
|
|
startDownload();
|
|
},
|
|
child: Text('更新'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
// 修改后的startDownload方法
|
|
Future<void> startDownload() async {
|
|
await _bleManager.setEnterOta(true);
|
|
await Future.delayed(const Duration(seconds: 2));
|
|
jlota.init();
|
|
|
|
isDownloading.value = true;
|
|
showDetailedStatus.value = true;
|
|
detailedStatus.value = '准备下载固件包...';
|
|
|
|
int lastIndex = updatepackageaddress.lastIndexOf('/');
|
|
String fileName = updatepackageaddress.substring(lastIndex + 1);
|
|
String directoryName = "ota_upgrades";
|
|
|
|
final dio = Dio(BaseOptions(
|
|
connectTimeout: const Duration(seconds: 5),
|
|
receiveTimeout: Duration.zero,
|
|
sendTimeout: const Duration(seconds: 5),
|
|
headers: {'Accept-Encoding': 'gzip'},
|
|
));
|
|
|
|
type.value = DOWNLOADING_UP_FILES;
|
|
try {
|
|
detailedStatus.value = '正在获取下载目录...';
|
|
final Directory? downloadsDir = await getApplicationSupportDirectory();
|
|
if (downloadsDir == null) {
|
|
throw FileSystemException('无法访问下载目录');
|
|
}
|
|
|
|
final targetDir =
|
|
Directory('${downloadsDir.path}/Download/$directoryName');
|
|
if (!await targetDir.exists()) {
|
|
detailedStatus.value = '创建下载目录...';
|
|
await targetDir.create(recursive: true);
|
|
}
|
|
|
|
final savePath = '${targetDir.path}/$fileName';
|
|
|
|
// 新增:检查同名文件逻辑
|
|
detailedStatus.value = '检查本地文件...';
|
|
bool existingSameFile = false;
|
|
try {
|
|
var files = await targetDir.list().toList();
|
|
for (var entity in files) {
|
|
if (await FileSystemEntity.isFile(entity.path)) {
|
|
String name = basename(entity.path); // 使用path包中的basename
|
|
if (name == fileName) {
|
|
existingSameFile = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
Get.snackbar(
|
|
'错误',
|
|
'检查本地文件失败: $e',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.red[600],
|
|
colorText: Colors.white,
|
|
icon: Icon(
|
|
Icons.error_outline,
|
|
color: Colors.white,
|
|
),
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
if (existingSameFile) {
|
|
//Get.snackbar('文件已存在', '跳过下载,直接更新');
|
|
detailedStatus.value = '文件已存在,准备升级...';
|
|
startUpgrading(savePath);
|
|
return;
|
|
}
|
|
|
|
// 新增:删除其他文件逻辑
|
|
detailedStatus.value = '清理旧文件...';
|
|
try {
|
|
var files = await targetDir.list().toList();
|
|
for (var entity in files) {
|
|
if (await FileSystemEntity.isFile(entity.path)) {
|
|
await entity.delete();
|
|
}
|
|
}
|
|
} catch (e) {
|
|
Get.snackbar(
|
|
'错误',
|
|
'删除旧文件失败: $e',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.red[600],
|
|
colorText: Colors.white,
|
|
icon: Icon(
|
|
Icons.error_outline,
|
|
color: Colors.white,
|
|
),
|
|
);
|
|
//isUpgrade.value = false;
|
|
return;
|
|
}
|
|
|
|
Logger().d('文件保存路径: $savePath');
|
|
|
|
detailedStatus.value = '开始下载固件包...';
|
|
final options = Options(
|
|
receiveTimeout: Duration.zero,
|
|
followRedirects: true,
|
|
maxRedirects: 5,
|
|
);
|
|
// 修改下载部分
|
|
await dio.download(
|
|
updatepackageaddress,
|
|
savePath,
|
|
options: options,
|
|
onReceiveProgress: (received, total) {
|
|
if (total != -1) {
|
|
downloadProgress.value = received / total;
|
|
detailedStatus.value =
|
|
'正在下载固件包... ${(received / total * 100).toStringAsFixed(1)}%';
|
|
}
|
|
},
|
|
);
|
|
File file = File(savePath);
|
|
if (await file.exists()) {
|
|
// Get.snackbar('下载完成', '文件已保存至: $savePath');
|
|
detailedStatus.value = '下载完成,准备升级...';
|
|
} else {
|
|
Get.snackbar(
|
|
'错误',
|
|
'文件未找到,请检查写入权限',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.orange[600],
|
|
colorText: Colors.white,
|
|
icon: Icon(
|
|
Icons.error_outline,
|
|
color: Colors.white,
|
|
),
|
|
);
|
|
detailedStatus.value = '下载失败';
|
|
showDetailedStatus.value = false;
|
|
return;
|
|
}
|
|
isDownloading.value = false;
|
|
startUpgrading(savePath);
|
|
return;
|
|
} on DioException catch (e) {
|
|
Get.snackbar(
|
|
'下载失败',
|
|
'错误: ${e.message}',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.orange[600],
|
|
colorText: Colors.white,
|
|
icon: Icon(
|
|
Icons.error_outline,
|
|
color: Colors.white,
|
|
),
|
|
);
|
|
} on FileSystemException catch (e) {
|
|
Get.snackbar(
|
|
'存储失败',
|
|
'无法写入文件: ${e.message}',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.orange[600],
|
|
colorText: Colors.white,
|
|
icon: Icon(
|
|
Icons.error_outline,
|
|
color: Colors.white,
|
|
),
|
|
);
|
|
} catch (e) {
|
|
isDownloading.value = false;
|
|
detailedStatus.value = '下载失败,请检查网络连接';
|
|
showDetailedStatus.value = false;
|
|
Get.snackbar(
|
|
'下载失败',
|
|
'请检查网络连接: $e',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.orange[600],
|
|
colorText: Colors.white,
|
|
icon: Icon(
|
|
Icons.error_outline,
|
|
color: Colors.white,
|
|
),
|
|
);
|
|
Logger().d('下载失败: $e');
|
|
}
|
|
}
|
|
|
|
// 开始升级
|
|
void startUpgrading(String path) async {
|
|
detailedStatus.value = '准备设备连接...';
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
detailedStatus.value = '正在连接设备...';
|
|
jlota.startUpgrading(address: _address, filePath: path);
|
|
return;
|
|
// isUpgrade.value = false;
|
|
}
|
|
|
|
// 停止升级
|
|
void stopUpgrading() async {
|
|
jlota.onOtaClose();
|
|
return;
|
|
// isUpgrade.value = false;
|
|
}
|
|
|
|
// 检查设备电量是否满足升级条件
|
|
bool _checkBatteryLevel() {
|
|
try {
|
|
final deviceInfo = _bleManager.deviceInfo.value;
|
|
|
|
if (deviceInfo == null) {
|
|
Get.snackbar(
|
|
'电量检查失败',
|
|
'无法获取设备信息,请检查设备连接',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.orange[600],
|
|
colorText: Colors.white,
|
|
icon: Icon(
|
|
Icons.warning_amber,
|
|
color: Colors.white,
|
|
),
|
|
);
|
|
return false;
|
|
}
|
|
|
|
final leftBattery = deviceInfo.leftEarBattery;
|
|
final rightBattery = deviceInfo.rightEarBattery;
|
|
|
|
// 检查左右耳电量是否都大于30%
|
|
if (leftBattery <= 30 || rightBattery <= 30) {
|
|
String message = '设备电量不足,无法进行固件升级\n';
|
|
message += '升级要求:左右耳电量均需大于30%\n';
|
|
message += '当前电量:左耳 ${leftBattery}%,右耳 ${rightBattery}%\n';
|
|
message += '请充电后再试';
|
|
|
|
Get.dialog(
|
|
AlertDialog(
|
|
title: Text(
|
|
'电量不足',
|
|
style: TextStyle(
|
|
color: Colors.orange[700],
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
content: Text(
|
|
message,
|
|
style: TextStyle(
|
|
color: Colors.orange[600],
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Get.back(),
|
|
style: TextButton.styleFrom(
|
|
foregroundColor: Colors.orange[700],
|
|
),
|
|
child: const Text('确定'),
|
|
),
|
|
],
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
side: BorderSide(
|
|
color: Colors.orange.withValues(alpha: 0.3),
|
|
width: 1,
|
|
),
|
|
),
|
|
backgroundColor: Colors.orange[50],
|
|
),
|
|
);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
} catch (e) {
|
|
Get.snackbar(
|
|
'电量检查失败',
|
|
'检查设备电量时发生错误:$e',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.orange[600],
|
|
colorText: Colors.white,
|
|
icon: const Icon(
|
|
Icons.warning_amber,
|
|
color: Colors.white,
|
|
),
|
|
);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void _listenToEvents() {
|
|
Ota.instance.eventStream.listen((event) {
|
|
if (event.event == 'onProgress' &&
|
|
event.type != null &&
|
|
event.progress != null) {
|
|
progress.value = event.progress!;
|
|
type.value = event.type!;
|
|
isUpgrade.value = true; // 开始升级
|
|
detailedStatus.value =
|
|
'升级进度: ${(event.progress! * 100).toStringAsFixed(1)}%';
|
|
}
|
|
if (event.event == 'onStartOTA') {
|
|
type.value = START_UPGRADING;
|
|
isUpgrade.value = true; // 开始升级
|
|
detailedStatus.value = 'OTA升级已开始...';
|
|
}
|
|
if (event.event == 'onStopOTA') {
|
|
type.value = UPGRADE_SUCCESS;
|
|
isUpgrade.value = false;
|
|
detailedStatus.value = '升级成功完成';
|
|
showDetailedStatus.value = false;
|
|
|
|
// 升级成功,更新版本信息显示
|
|
currentVersion.value = latestVersion.value;
|
|
isUpdateAvailable.value = false;
|
|
|
|
// 显示升级成功对话框,引导用户重新配对
|
|
Get.dialog(
|
|
AlertDialog(
|
|
title: Row(
|
|
children: [
|
|
Icon(
|
|
Icons.check_circle,
|
|
color: Colors.green[600],
|
|
size: 28,
|
|
),
|
|
SizedBox(width: 12),
|
|
Text(
|
|
'升级成功',
|
|
style: TextStyle(
|
|
color: Colors.green[700],
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
content: Text(
|
|
'固件升级已完成!\n\n设备需要重新配对才能正常使用,现在跳转到配对页面吗?',
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
height: 1.4,
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () {
|
|
Get.back(); // 关闭对话框
|
|
},
|
|
child: Text(
|
|
'稍后配对',
|
|
style: TextStyle(color: Colors.grey[600]),
|
|
),
|
|
),
|
|
ElevatedButton(
|
|
onPressed: () {
|
|
Get.back(); // 关闭对话框
|
|
Get.toNamed(Routes.pairing);
|
|
},
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.green[600],
|
|
foregroundColor: Colors.white,
|
|
),
|
|
child: Text('立即配对'),
|
|
),
|
|
],
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
),
|
|
barrierDismissible: false, // 防止用户意外关闭
|
|
);
|
|
}
|
|
if (event.event == 'onError') {
|
|
type.value = UPGRADE_FAILED;
|
|
isUpgrade.value = false;
|
|
detailedStatus.value = '升级失败,错误码:${event.code}';
|
|
showDetailedStatus.value = false;
|
|
Get.snackbar(
|
|
'升级失败',
|
|
'请检查设备连接或升级包,错误码:${event.code}',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
backgroundColor: Colors.red[600],
|
|
colorText: Colors.white,
|
|
icon: Icon(
|
|
Icons.error_outline,
|
|
color: Colors.white,
|
|
),
|
|
);
|
|
}
|
|
if (event.event == 'NOCONNECTION') {
|
|
type.value = CONNECTION_DISCONNECTION;
|
|
isUpgrade.value = false;
|
|
detailedStatus.value = '设备连接断开';
|
|
showDetailedStatus.value = false;
|
|
}
|
|
if (event.event == 'CONNECTION_SUCCESS') {
|
|
type.value = CONNECTION_SUCCESS;
|
|
isUpgrade.value = true; // 开始升级
|
|
detailedStatus.value = '设备连接成功';
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|