1 changed files with 287 additions and 90 deletions
@ -1,129 +1,326 @@ |
|||||
import 'package:flutter/material.dart'; |
import 'package:flutter/material.dart'; |
||||
import 'package:get/get.dart'; |
import 'package:get/get.dart'; |
||||
import '../controllers/ota_upgrade_controller.dart'; |
import '../controllers/ota_upgrade_controller.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
class OtaUpgradeView extends GetView<OtaUpgradeController> { |
class OtaUpgradeView extends GetView<OtaUpgradeController> { |
||||
const OtaUpgradeView({Key? key}) : super(key: key); |
const OtaUpgradeView({Key? key}) : super(key: key); |
||||
|
|
||||
@override |
@override |
||||
Widget build(BuildContext context) { |
Widget build(BuildContext context) { |
||||
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
||||
|
|
||||
return Scaffold( |
return Scaffold( |
||||
body: Center( |
backgroundColor: isDarkMode ? Colors.black : Colors.grey[100], |
||||
child: ConstrainedBox( |
appBar: AppBar( |
||||
constraints: BoxConstraints(maxWidth: 600), // 限制最大宽度 |
automaticallyImplyLeading: false, |
||||
child: SingleChildScrollView( |
centerTitle: true, |
||||
child: Padding( |
elevation: 0, |
||||
padding: EdgeInsets.all(20), |
backgroundColor: isDarkMode ? Colors.black : Colors.white, |
||||
child: Column( |
leading: IconButton( |
||||
mainAxisSize: MainAxisSize.min, |
icon: Icon( |
||||
children: [ |
Icons.arrow_back_ios, |
||||
// 设备图标 |
size: 20.sp, |
||||
_buildDeviceIcon(), |
color: isDarkMode ? Colors.white : Colors.black, |
||||
SizedBox(height: 30), |
), |
||||
|
onPressed: () => 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), |
||||
|
|
||||
// 版本信息 |
// 更新说明 |
||||
_buildVersionInfo(), |
_buildUpdateNotes(isDarkMode), |
||||
SizedBox(height: 40), |
SizedBox(height: 20), |
||||
|
|
||||
// 状态显示区域 |
// 状态显示区域 |
||||
Obx(() { |
Obx(() { |
||||
if (controller.isFetchingDeviceInfo.value) { |
if (controller.isFetchingDeviceInfo.value) { |
||||
return _buildLoadingIndicator(); |
return _buildLoadingIndicator(isDarkMode); |
||||
} |
} |
||||
if (controller.errorMessage.value.isNotEmpty) { |
if (controller.errorMessage.value.isNotEmpty) { |
||||
return _buildErrorInfo(); |
return _buildErrorInfo(isDarkMode); |
||||
} |
} |
||||
return _buildUpdateButton(); |
return _buildUpdateButton(isDarkMode); |
||||
}), |
}), |
||||
], |
], |
||||
), |
|
||||
), |
|
||||
), |
), |
||||
), |
), |
||||
), |
), |
||||
); |
); |
||||
} |
} |
||||
|
|
||||
// 组件化构建方法 |
// 设备图标 |
||||
Widget _buildDeviceIcon() => CircleAvatar( |
Widget _buildDeviceIcon(bool isDarkMode) => Image.asset( |
||||
radius: 60, |
isDarkMode |
||||
backgroundColor: Colors.blue[100], |
? 'assets/images/headphone_dark.png' |
||||
child: Icon(Icons.phone_iphone, size: 60, color: Colors.blue), |
: 'assets/images/headphone_light.png', |
||||
|
height: 180.h, |
||||
|
fit: BoxFit.contain, |
||||
); |
); |
||||
|
|
||||
Widget _buildVersionInfo() => Column( |
Widget _buildVersionInfo(bool isDarkMode) => Column( |
||||
|
mainAxisAlignment: MainAxisAlignment.start, |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
children: [ |
children: [ |
||||
Text('当前版本', style: TextStyle(fontSize: 18, color: Colors.grey)), |
Row( |
||||
SizedBox(height: 8), |
crossAxisAlignment: CrossAxisAlignment.center, // 改为center对齐 |
||||
Text('v${controller.currentVersion}', |
children: [ |
||||
style: TextStyle( |
Text('当前固件版本:'.tr, |
||||
fontSize: 24, |
style: TextStyle( |
||||
fontWeight: FontWeight.bold, |
fontSize: 18, |
||||
color: Colors.blue)), |
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 |
||||
|
Text('v${controller.latestVersion}', |
||||
|
style: TextStyle( |
||||
|
fontSize: 24, |
||||
|
fontWeight: FontWeight.normal, |
||||
|
color: isDarkMode ? Colors.green[300] : Colors.green)), |
||||
|
], |
||||
|
), |
||||
], |
], |
||||
); |
); |
||||
|
|
||||
Widget _buildLoadingIndicator() => Column( |
// 添加固件更新说明 |
||||
|
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( |
||||
|
'1. 优化音质表现\n2. 提升连接稳定性\n3. 修复已知问题'.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 14, |
||||
|
color: isDarkMode ? Colors.grey[300] : Colors.grey[800], |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
) |
||||
|
: SizedBox.shrink()); |
||||
|
|
||||
|
Widget _buildLoadingIndicator(bool isDarkMode) => Column( |
||||
children: [ |
children: [ |
||||
CircularProgressIndicator(), |
CircularProgressIndicator( |
||||
|
valueColor: AlwaysStoppedAnimation( |
||||
|
isDarkMode ? Colors.blue[300] : Colors.blue), |
||||
|
), |
||||
SizedBox(height: 20), |
SizedBox(height: 20), |
||||
Text('正在连接设备...', style: TextStyle(color: Colors.grey)) |
Text('正在连接设备...', |
||||
|
style: |
||||
|
TextStyle(color: isDarkMode ? Colors.grey[300] : Colors.grey)) |
||||
], |
], |
||||
); |
); |
||||
|
|
||||
Widget _buildErrorInfo() => Column( |
Widget _buildErrorInfo(bool isDarkMode) => Container( |
||||
children: [ |
padding: EdgeInsets.all(16), |
||||
Icon(Icons.error_outline, color: Colors.red, size: 40), |
decoration: BoxDecoration( |
||||
SizedBox(height: 10), |
color: |
||||
Text(controller.errorMessage.value, |
isDarkMode ? Colors.red[900]!.withOpacity(0.2) : Colors.red[50], |
||||
style: TextStyle(color: Colors.red)), |
borderRadius: BorderRadius.circular(12), |
||||
SizedBox(height: 20), |
border: Border.all( |
||||
ElevatedButton( |
color: isDarkMode ? Colors.red[700]! : Colors.red[200]!, |
||||
onPressed: controller.retryConnection, |
width: 1, |
||||
child: Text('重试连接'), |
), |
||||
) |
), |
||||
], |
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() { |
Widget _buildUpdateButton(bool isDarkMode) { |
||||
return controller.isUpdating.value |
return controller.isUpdating.value |
||||
? _buildProgressIndicator() |
? _buildProgressIndicator(isDarkMode) |
||||
: ElevatedButton( |
: Container( |
||||
style: ElevatedButton.styleFrom( |
width: double.infinity, |
||||
backgroundColor: controller.isUpdateAvailable.value |
padding: EdgeInsets.symmetric(vertical: 10), |
||||
? Colors.blue |
child: Column( |
||||
: Colors.grey, |
children: [ |
||||
padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15), |
ElevatedButton.icon( |
||||
shape: RoundedRectangleBorder( |
icon: Icon( |
||||
borderRadius: BorderRadius.circular(30), |
controller.isUpdateAvailable.value |
||||
), |
? Icons.system_update |
||||
), |
: Icons.check_circle, |
||||
onPressed: controller.isUpdateAvailable.value |
), |
||||
? controller.startUpdate |
label: Text( |
||||
: null, |
controller.isUpdateAvailable.value ? '立即更新' : '已是最新版本', |
||||
child: Text( |
style: TextStyle(fontSize: 16), |
||||
controller.isUpdateAvailable.value ? '立即更新' : '已是最新版本', |
), |
||||
style: TextStyle(fontSize: 16, color: Colors.white), |
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( |
||||
|
'建议连接WiFi并保持充电状态'.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 14, |
||||
|
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
], |
||||
), |
), |
||||
); |
); |
||||
} |
} |
||||
|
|
||||
Widget _buildProgressIndicator() => Column( |
Widget _buildProgressIndicator(bool isDarkMode) => Container( |
||||
children: [ |
padding: EdgeInsets.all(20), |
||||
SizedBox( |
decoration: BoxDecoration( |
||||
width: 200, |
color: |
||||
child: LinearProgressIndicator( |
isDarkMode ? Colors.blue[900]!.withOpacity(0.2) : Colors.blue[50], |
||||
value: controller.downloadProgress.value, |
borderRadius: BorderRadius.circular(16), |
||||
backgroundColor: Colors.grey[200], |
), |
||||
valueColor: AlwaysStoppedAnimation(Colors.blue), |
child: Column( |
||||
minHeight: 12, |
children: [ |
||||
borderRadius: BorderRadius.circular(10), |
Text('正在下载更新...'.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 18, |
||||
|
fontWeight: FontWeight.bold, |
||||
|
color: isDarkMode ? Colors.blue[300] : Colors.blue[700])), |
||||
|
SizedBox(height: 16), |
||||
|
SizedBox( |
||||
|
width: 240, |
||||
|
child: LinearProgressIndicator( |
||||
|
value: controller.downloadProgress.value, |
||||
|
backgroundColor: |
||||
|
isDarkMode ? Colors.grey[800] : Colors.grey[200], |
||||
|
valueColor: AlwaysStoppedAnimation( |
||||
|
isDarkMode ? Colors.blue[300] : Colors.blue), |
||||
|
minHeight: 12, |
||||
|
borderRadius: BorderRadius.circular(10), |
||||
|
), |
||||
), |
), |
||||
), |
SizedBox(height: 16), |
||||
SizedBox(height: 20), |
Row( |
||||
Text( |
mainAxisSize: MainAxisSize.min, |
||||
'${(controller.downloadProgress.value * 100).toStringAsFixed(1)}%', |
children: [ |
||||
style: TextStyle(color: Colors.grey)) |
Icon( |
||||
], |
Icons.downloading, |
||||
|
color: isDarkMode ? Colors.blue[300] : Colors.blue, |
||||
|
size: 20, |
||||
|
), |
||||
|
SizedBox(width: 8), |
||||
|
Text( |
||||
|
'${(controller.downloadProgress.value * 100).toStringAsFixed(1)}%', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16, |
||||
|
fontWeight: FontWeight.bold, |
||||
|
color: |
||||
|
isDarkMode ? Colors.blue[300] : Colors.blue[700])), |
||||
|
], |
||||
|
) |
||||
|
], |
||||
|
), |
||||
); |
); |
||||
} |
} |
||||
|
|||||
Loading…
Reference in new issue