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.

394 lines
14 KiB

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/ota_upgrade_controller.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class OtaUpgradeView extends GetView<OtaUpgradeController> {
const OtaUpgradeView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return WillPopScope(
onWillPop: () async {
if (controller.isUpgrade.value) {
// 显示确认弹窗
await Get.dialog(
AlertDialog(
title: Text('提示'),
content: Text('当前正在升级,退出将中断升级进程,确定要退出吗?'),
actions: [
TextButton(
onPressed: () => Get.back(), // 关闭弹窗
child: Text('取消'),
),
TextButton(
onPressed: () {
controller.stopUpgrading();
Get.back(); // 关闭弹窗
Get.back(); // 返回上一页
},
child: Text('确定'),
),
],
),
);
return false; // 阻止默认返回
}
return true; // 允许返回
},
child: Scaffold(
backgroundColor: isDarkMode ? Colors.black : Colors.grey[100],
appBar: AppBar(
automaticallyImplyLeading: false,
centerTitle: true,
elevation: 0,
backgroundColor: isDarkMode ? Colors.black : Colors.white,
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
size: 20.sp,
color: isDarkMode ? Colors.white : Colors.black,
),
onPressed: () {
if (controller.isUpgrade.value) {
// 显示确认弹窗
Get.dialog(
AlertDialog(
title: Text('提示'),
content: Text('当前正在升级,退出将中断升级进程,确定要退出吗?'),
actions: [
TextButton(
onPressed: () => Get.back(), // 关闭弹窗
child: Text('取消'),
),
TextButton(
onPressed: () {
controller.stopUpgrading();
Get.back(); // 关闭弹窗
Get.back(); // 返回上一页
},
child: Text('确定'),
),
],
),
);
} else {
Get.back(); // 正常返回
}
},
),
title: Text(
'固件升级'.tr,
style: TextStyle(
fontSize: 20.sp,
color: isDarkMode ? Colors.white : Colors.black,
),
),
),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 设备信息卡片
Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
color: isDarkMode ? Colors.grey[900] : Colors.white,
child: Padding(
padding: EdgeInsets.all(20),
child: Column(
children: [
_buildDeviceIcon(isDarkMode),
SizedBox(height: 20),
_buildVersionInfo(isDarkMode),
],
),
),
),
SizedBox(height: 20),
// 更新说明
_buildUpdateNotes(isDarkMode),
SizedBox(height: 20),
// 状态显示区域
Obx(() {
if (controller.isFetchingDeviceInfo.value) {
return _buildLoadingIndicator(isDarkMode);
}
if (controller.errorMessage.value.isNotEmpty) {
return _buildErrorInfo(isDarkMode);
}
return _buildUpdateButton(isDarkMode);
}),
],
),
),
),
),
);
}
// 设备图标
Widget _buildDeviceIcon(bool isDarkMode) => Image.asset(
isDarkMode
? 'assets/images/headphone_dark.png'
: 'assets/images/headphone_light.png',
height: 180.h,
fit: BoxFit.contain,
);
Widget _buildVersionInfo(bool isDarkMode) => Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center, // 改为center对齐
children: [
Text('当前固件版本:'.tr,
style: TextStyle(
fontSize: 18,
color: isDarkMode ? Colors.grey[300] : Colors.black)),
SizedBox(width: 8), // 改为width
Obx(() => Text('V ${controller.currentVersion}',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.normal,
color: isDarkMode ? Colors.blue[300] : Colors.blue))),
],
),
SizedBox(height: 8), // 改为height
Row(
crossAxisAlignment: CrossAxisAlignment.center, // 改为center对齐
children: [
Text('最新固件版本:'.tr,
style: TextStyle(
fontSize: 18,
color: isDarkMode ? Colors.grey[300] : Colors.black)),
SizedBox(width: 8), // 改为width
Obx(() => Text('V ${controller.latestVersion}',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.normal,
color: isDarkMode ? Colors.blue[300] : Colors.blue))),
],
),
],
);
// 添加固件更新说明
Widget _buildUpdateNotes(bool isDarkMode) =>
Obx(() => controller.isUpdateAvailable.value
? Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
color: isDarkMode ? Colors.grey[900] : Colors.white,
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.new_releases,
color: isDarkMode ? Colors.amber[300] : Colors.amber,
size: 20,
),
SizedBox(width: 8),
Text(
'更新内容'.tr,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: isDarkMode ? Colors.white : Colors.black,
),
),
],
),
Divider(),
SizedBox(height: 8),
// 这里可以从controller中获取更新说明,如果有的话
Text(
controller.updatedescription.value,
style: TextStyle(
fontSize: 14,
color: isDarkMode ? Colors.grey[300] : Colors.grey[800],
),
),
],
),
),
)
: SizedBox.shrink());
Widget _buildLoadingIndicator(bool isDarkMode) => Column(
children: [
CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(
isDarkMode ? Colors.blue[300] : Colors.blue),
),
SizedBox(height: 20),
Text('正在获取设备信息...',
style:
TextStyle(color: isDarkMode ? Colors.grey[300] : Colors.grey))
],
);
Widget _buildErrorInfo(bool isDarkMode) => Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color:
isDarkMode ? Colors.red[900]!.withOpacity(0.2) : Colors.red[50],
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isDarkMode ? Colors.red[700]! : Colors.red[200]!,
width: 1,
),
),
child: Column(
children: [
Icon(Icons.error_outline, color: Colors.red, size: 40),
SizedBox(height: 10),
Text(controller.errorMessage.value,
textAlign: TextAlign.center,
style: TextStyle(
color: isDarkMode ? Colors.red[300] : Colors.red,
fontSize: 16)),
SizedBox(height: 20),
ElevatedButton.icon(
icon: Icon(Icons.refresh),
label: Text('重试连接'.tr),
style: ElevatedButton.styleFrom(
backgroundColor: isDarkMode ? Colors.blue[700] : Colors.blue,
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.r),
),
),
onPressed: controller.retryConnection,
)
],
),
);
Widget _buildUpdateButton(bool isDarkMode) {
return controller.isUpgrade.value
? _buildProgressIndicator(isDarkMode)
: Container(
width: double.infinity,
padding: EdgeInsets.symmetric(vertical: 10),
child: Column(
children: [
ElevatedButton.icon(
icon: Icon(
controller.isUpdateAvailable.value
? Icons.system_update
: Icons.check_circle,
),
label: Text(
controller.isUpdateAvailable.value ? '立即更新' : '已是最新版本',
style: TextStyle(fontSize: 16),
),
style: ElevatedButton.styleFrom(
backgroundColor: controller.isUpdateAvailable.value
? (isDarkMode ? Colors.blue[700] : Colors.blue)
: (isDarkMode ? Colors.grey[800] : Colors.grey),
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
minimumSize: Size(240, 50),
),
onPressed: controller.isUpdateAvailable.value
? controller.startUpdate
: null,
),
if (controller.isUpdateAvailable.value) ...[
SizedBox(height: 8),
Text(
'取出双耳机,并保证电量均为30%以上的状态'.tr,
style: TextStyle(
fontSize: 14,
color: isDarkMode ? Colors.grey[400] : Colors.grey[600],
),
),
],
],
),
);
}
Widget _buildProgressIndicator(bool isDarkMode) {
return Obx(() {
final progress = controller.progress.value;
final type = controller.type.value;
// // 处理升级失败状态:弹出 snackbar 并显示错误提示
// if (type == OtaUpgradeController.UPGRADE_FAILED ||
// type == OtaUpgradeController.CONNECTION_DISCONNECTION) {
// // 使用延迟确保在 build 完成后执行
// Future.delayed(Duration.zero, () {
// Get.snackbar('升级失败', '重新连接设备后重试');
// });
// return Container(
// width: double.infinity,
// padding: const EdgeInsets.symmetric(vertical: 10),
// child: Text(
// '升级失败,请重新连接设备',
// style: TextStyle(
// fontSize: 18,
// fontWeight: FontWeight.bold,
// color: Colors.red[700],
// ),
// ),
// );
// }
// 正常升级状态
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 10),
child: Column(
children: [
Text(
controller.getStatusMessage(type),
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: isDarkMode ? Colors.blue[300] : Colors.blue[700],
),
),
const SizedBox(height: 16),
LinearProgressIndicator(
value: progress / 100.0, // 转换为 0.0-1.0
backgroundColor: isDarkMode ? Colors.grey[800] : Colors.grey[200],
valueColor: AlwaysStoppedAnimation<Color>(
isDarkMode ? Colors.blue[300]! : Colors.blue,
),
),
const SizedBox(height: 8),
Text(
'${progress.toStringAsFixed(1)}%',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: isDarkMode ? Colors.blue[300] : Colors.blue[700],
),
),
],
),
);
});
}
}