16 changed files with 985 additions and 715 deletions
@ -1,129 +1,326 @@ |
|||
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 Scaffold( |
|||
body: Center( |
|||
child: ConstrainedBox( |
|||
constraints: BoxConstraints(maxWidth: 600), // 限制最大宽度 |
|||
child: SingleChildScrollView( |
|||
child: Padding( |
|||
padding: EdgeInsets.all(20), |
|||
child: Column( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: [ |
|||
// 设备图标 |
|||
_buildDeviceIcon(), |
|||
SizedBox(height: 30), |
|||
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: () => 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(), |
|||
SizedBox(height: 40), |
|||
// 更新说明 |
|||
_buildUpdateNotes(isDarkMode), |
|||
SizedBox(height: 20), |
|||
|
|||
// 状态显示区域 |
|||
Obx(() { |
|||
if (controller.isFetchingDeviceInfo.value) { |
|||
return _buildLoadingIndicator(); |
|||
} |
|||
if (controller.errorMessage.value.isNotEmpty) { |
|||
return _buildErrorInfo(); |
|||
} |
|||
return _buildUpdateButton(); |
|||
}), |
|||
], |
|||
), |
|||
), |
|||
// 状态显示区域 |
|||
Obx(() { |
|||
if (controller.isFetchingDeviceInfo.value) { |
|||
return _buildLoadingIndicator(isDarkMode); |
|||
} |
|||
if (controller.errorMessage.value.isNotEmpty) { |
|||
return _buildErrorInfo(isDarkMode); |
|||
} |
|||
return _buildUpdateButton(isDarkMode); |
|||
}), |
|||
], |
|||
), |
|||
), |
|||
), |
|||
); |
|||
} |
|||
|
|||
// 组件化构建方法 |
|||
Widget _buildDeviceIcon() => CircleAvatar( |
|||
radius: 60, |
|||
backgroundColor: Colors.blue[100], |
|||
child: Icon(Icons.phone_iphone, size: 60, color: Colors.blue), |
|||
// 设备图标 |
|||
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() => Column( |
|||
Widget _buildVersionInfo(bool isDarkMode) => Column( |
|||
mainAxisAlignment: MainAxisAlignment.start, |
|||
crossAxisAlignment: CrossAxisAlignment.start, |
|||
children: [ |
|||
Text('当前版本', style: TextStyle(fontSize: 18, color: Colors.grey)), |
|||
SizedBox(height: 8), |
|||
Text('v${controller.currentVersion}', |
|||
style: TextStyle( |
|||
fontSize: 24, |
|||
fontWeight: FontWeight.bold, |
|||
color: Colors.blue)), |
|||
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 |
|||
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: [ |
|||
CircularProgressIndicator(), |
|||
CircularProgressIndicator( |
|||
valueColor: AlwaysStoppedAnimation( |
|||
isDarkMode ? Colors.blue[300] : Colors.blue), |
|||
), |
|||
SizedBox(height: 20), |
|||
Text('正在连接设备...', style: TextStyle(color: Colors.grey)) |
|||
Text('正在连接设备...', |
|||
style: |
|||
TextStyle(color: isDarkMode ? Colors.grey[300] : Colors.grey)) |
|||
], |
|||
); |
|||
|
|||
Widget _buildErrorInfo() => Column( |
|||
children: [ |
|||
Icon(Icons.error_outline, color: Colors.red, size: 40), |
|||
SizedBox(height: 10), |
|||
Text(controller.errorMessage.value, |
|||
style: TextStyle(color: Colors.red)), |
|||
SizedBox(height: 20), |
|||
ElevatedButton( |
|||
onPressed: controller.retryConnection, |
|||
child: Text('重试连接'), |
|||
) |
|||
], |
|||
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() { |
|||
Widget _buildUpdateButton(bool isDarkMode) { |
|||
return controller.isUpdating.value |
|||
? _buildProgressIndicator() |
|||
: ElevatedButton( |
|||
style: ElevatedButton.styleFrom( |
|||
backgroundColor: controller.isUpdateAvailable.value |
|||
? Colors.blue |
|||
: Colors.grey, |
|||
padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15), |
|||
shape: RoundedRectangleBorder( |
|||
borderRadius: BorderRadius.circular(30), |
|||
), |
|||
), |
|||
onPressed: controller.isUpdateAvailable.value |
|||
? controller.startUpdate |
|||
: null, |
|||
child: Text( |
|||
controller.isUpdateAvailable.value ? '立即更新' : '已是最新版本', |
|||
style: TextStyle(fontSize: 16, color: Colors.white), |
|||
? _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( |
|||
'建议连接WiFi并保持充电状态'.tr, |
|||
style: TextStyle( |
|||
fontSize: 14, |
|||
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], |
|||
), |
|||
), |
|||
], |
|||
], |
|||
), |
|||
); |
|||
} |
|||
|
|||
Widget _buildProgressIndicator() => Column( |
|||
children: [ |
|||
SizedBox( |
|||
width: 200, |
|||
child: LinearProgressIndicator( |
|||
value: controller.downloadProgress.value, |
|||
backgroundColor: Colors.grey[200], |
|||
valueColor: AlwaysStoppedAnimation(Colors.blue), |
|||
minHeight: 12, |
|||
borderRadius: BorderRadius.circular(10), |
|||
Widget _buildProgressIndicator(bool isDarkMode) => Container( |
|||
padding: EdgeInsets.all(20), |
|||
decoration: BoxDecoration( |
|||
color: |
|||
isDarkMode ? Colors.blue[900]!.withOpacity(0.2) : Colors.blue[50], |
|||
borderRadius: BorderRadius.circular(16), |
|||
), |
|||
child: Column( |
|||
children: [ |
|||
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: 20), |
|||
Text( |
|||
'${(controller.downloadProgress.value * 100).toStringAsFixed(1)}%', |
|||
style: TextStyle(color: Colors.grey)) |
|||
], |
|||
SizedBox(height: 16), |
|||
Row( |
|||
mainAxisSize: MainAxisSize.min, |
|||
children: [ |
|||
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])), |
|||
], |
|||
) |
|||
], |
|||
), |
|||
); |
|||
} |
|||
|
|||
@ -1,35 +1,48 @@ |
|||
abstract class Routes { |
|||
// 认证相关 |
|||
static const splash = '/splash'; |
|||
static const login = '/login'; |
|||
static const pairing = '/pairing'; |
|||
|
|||
// 主功能模块 |
|||
static const initial = '/home'; |
|||
static const home = '/home'; |
|||
static const explore = '/explore'; |
|||
static const chat = '/chat'; |
|||
static const OTA_UPGRADE = '/ota_upgrade'; |
|||
static const recording = '/recording'; |
|||
static const profile = '/profile'; |
|||
static const meeting = '/meeting'; |
|||
static const meetingRecord = '/meetingRecord'; |
|||
static const meetingDetails = '/meetingDetails'; |
|||
static const meetingEdit = '/meetingEdit'; |
|||
static const timbre = '/timbre'; |
|||
static const settings = '/settings'; |
|||
static const speechDemo = '/speech_demo'; |
|||
static const TTS_TEST = '/tts_test'; |
|||
static const ASR_TEST = '/asr_test'; |
|||
static const AZURE_ASR_TEST = '/azure_asr_test'; |
|||
static const AZURE_TTS_TEST = '/azure_tts_test'; |
|||
static const VOLCANO_ASR_TEST = '/volcano_asr_test'; |
|||
static const translation = '/translation'; |
|||
static const translationHistory = '/translation_history'; |
|||
static const FLUTTER_TTS_TEST = '/flutter_tts_test'; |
|||
static const FLUTTER_ASR_TEST = '/flutter_asr_test'; |
|||
static const editProfile = '/edit_profile'; |
|||
static const feedback = '/feedback'; |
|||
static const jieliTest = '/jieli_test'; |
|||
static const opusTest = '/opus_test'; |
|||
static const bleTest = '/ble_test'; |
|||
static const speechTest = '/speech_test'; |
|||
static const agent = '/agent'; |
|||
|
|||
// 设备管理 |
|||
static const OTA_UPGRADE = '/ota_upgrade'; // OTA升级 |
|||
static const timbre = '/timbre'; // 音色设置 |
|||
static const settings = '/settings'; // 系统设置 |
|||
static const recording = '/recording'; // 录音功能 |
|||
|
|||
// 会议相关 |
|||
static const meeting = '/meeting'; |
|||
static const meetingRecord = '/meeting_record'; // 会议记录 |
|||
static const meetingDetails = '/meeting_details'; // 会议详情 |
|||
static const meetingEdit = '/meeting_edit'; // 会议编辑 |
|||
|
|||
// 语言功能 |
|||
static const translation = '/translation'; // 实时翻译 |
|||
static const translationHistory = '/translation_history'; // 翻译历史 |
|||
static const speechDemo = '/speech_demo'; // 语音演示 |
|||
|
|||
// 测试路由(生产环境建议移除) |
|||
static const ttsTest = '/tts_test'; // 文字转语音测试 |
|||
static const asrTest = '/asr_test'; // 语音识别测试 |
|||
static const azureAsrTest = '/azure_asr_test'; // Azure语音识别 |
|||
static const azureTtsTest = '/azure_tts_test'; // Azure文字转语音 |
|||
static const volcanoAsrTest = '/volcano_asr_test'; // 火山引擎语音识别 |
|||
static const flutterTtsTest = '/flutter_tts_test'; // Flutter TTS测试 |
|||
static const flutterAsrTest = '/flutter_asr_test'; // Flutter ASR测试 |
|||
static const jieliTest = '/jieli_test'; // 杰理芯片测试 |
|||
static const opusTest = '/opus_test'; // Opus编码测试 |
|||
static const bleTest = '/ble_test'; // 蓝牙测试 |
|||
static const speechTest = '/speech_test'; // 综合语音测试 |
|||
|
|||
// 支持服务 |
|||
static const feedback = '/feedback'; // 用户反馈 |
|||
static const agent = '/agent'; // 在线客服 |
|||
} |
|||
|
|||
Loading…
Reference in new issue