From 62fa015977ec86a3f89ed142f287ec205cbdc7cb Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Mon, 12 May 2025 10:52:56 +0800 Subject: [PATCH 1/5] =?UTF-8?q?refactor:=20=E6=B8=85=E7=90=86=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=B9=B6=E4=BC=98=E5=8C=96=E8=B7=AF=E7=94=B1=E5=92=8C?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E8=B5=84=E6=96=99=E7=BC=96=E8=BE=91=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/modules/home/bindings/home_binding.dart | 1 - lib/modules/home/views/home_view.dart | 168 ++++---- .../controllers/profile_controller.dart | 23 +- lib/modules/profile/views/profile_view.dart | 309 ++++++++------- lib/modules/settings/views/settings_view.dart | 365 +++++++++--------- lib/routes/app_pages.dart | 14 +- lib/routes/app_routes.dart | 61 +-- 7 files changed, 471 insertions(+), 470 deletions(-) diff --git a/lib/modules/home/bindings/home_binding.dart b/lib/modules/home/bindings/home_binding.dart index a8dae0b27..5f976a98b 100644 --- a/lib/modules/home/bindings/home_binding.dart +++ b/lib/modules/home/bindings/home_binding.dart @@ -1,6 +1,5 @@ import '../../explore/controllers/explore_controller.dart'; import 'package:get/get.dart'; -import '../../explore/controllers/explore_controller.dart'; import '../controllers/home_controller.dart'; class HomeBinding extends Bindings { diff --git a/lib/modules/home/views/home_view.dart b/lib/modules/home/views/home_view.dart index abdb2f920..8c10c7d03 100644 --- a/lib/modules/home/views/home_view.dart +++ b/lib/modules/home/views/home_view.dart @@ -160,43 +160,43 @@ class HomeView extends GetView { child: ClipRRect( // 添加 ClipRRect 来实现圆角 borderRadius: BorderRadius.circular(16.r), // 使用与其他部件一致的圆角大小 - child: SizedBox( - width: double.infinity, - height: 200.h, - child: Image.asset( - isDarkMode - ? 'assets/images/robot_light.png' - : 'assets/images/robot_light.png', - fit: BoxFit.fitWidth, + child: SizedBox( + width: double.infinity, + height: 200.h, + child: Image.asset( + isDarkMode + ? 'assets/images/robot_light.png' + : 'assets/images/robot_light.png', + fit: BoxFit.fitWidth, + ), ), ), ), - ), Center( child: ClipRRect( // 添加 ClipRRect borderRadius: BorderRadius.circular(16.r), - child: Image.asset( - isDarkMode - ? 'assets/images/headphone_dark.png' - : 'assets/images/headphone_light.png', - height: 180.h, - fit: BoxFit.contain, + child: Image.asset( + isDarkMode + ? 'assets/images/headphone_dark.png' + : 'assets/images/headphone_light.png', + height: 180.h, + fit: BoxFit.contain, + ), ), ), - ), Center( child: ClipRRect( // 添加 ClipRRect borderRadius: BorderRadius.circular(16.r), - child: SizedBox( - width: double.infinity, - height: 200.h, - child: Image.asset( - isDarkMode - ? 'assets/images/glasses_light.png' - : 'assets/images/glasses_light.png', - fit: BoxFit.fitWidth, + child: SizedBox( + width: double.infinity, + height: 200.h, + child: Image.asset( + isDarkMode + ? 'assets/images/glasses_light.png' + : 'assets/images/glasses_light.png', + fit: BoxFit.fitWidth, ), ), ), @@ -283,50 +283,52 @@ class HomeView extends GetView { ], ), Obx(() => Row( - children: [ - Container( - width: 8.w, - height: 8.w, - decoration: BoxDecoration( - color: controller.getConnectionStatusColor(), - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: controller.getConnectionStatusColor().withOpacity(0.3), - blurRadius: 4, - spreadRadius: 1, + children: [ + Container( + width: 8.w, + height: 8.w, + decoration: BoxDecoration( + color: controller.getConnectionStatusColor(), + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: controller + .getConnectionStatusColor() + .withOpacity(0.3), + blurRadius: 4, + spreadRadius: 1, + ), + ], ), - ], - ), - ), - SizedBox(width: 4.w), - Text( - controller.getConnectionStatusText(), - style: TextStyle( - fontSize: 12.sp, - color: controller.getConnectionStatusColor(), - ), - ), - // 添加刷新按钮 - SizedBox(width: 8.w), - InkWell( - onTap: () => controller.refreshDeviceConnection(), - borderRadius: BorderRadius.circular(12.r), - child: Container( - padding: EdgeInsets.all(4.w), - decoration: BoxDecoration( - color: isDarkMode ? Colors.grey[800] : Colors.grey[200], - shape: BoxShape.circle, ), - child: Icon( - Icons.refresh, - size: 14.sp, - color: isDarkMode ? Colors.grey[400] : Colors.grey[600], + SizedBox(width: 4.w), + Text( + controller.getConnectionStatusText(), + style: TextStyle( + fontSize: 12.sp, + color: controller.getConnectionStatusColor(), + ), ), - ), - ), - ], - )), + // 添加刷新按钮 + SizedBox(width: 8.w), + InkWell( + onTap: () => controller.refreshDeviceConnection(), + borderRadius: BorderRadius.circular(12.r), + child: Container( + padding: EdgeInsets.all(4.w), + decoration: BoxDecoration( + color: isDarkMode ? Colors.grey[800] : Colors.grey[200], + shape: BoxShape.circle, + ), + child: Icon( + Icons.refresh, + size: 14.sp, + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], + ), + ), + ), + ], + )), ], ); } @@ -338,9 +340,8 @@ class HomeView extends GetView { Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( - color: isDarkMode - ? Colors.red[900]!.withOpacity(0.2) - : Colors.red[50], + color: + isDarkMode ? Colors.red[900]!.withOpacity(0.2) : Colors.red[50], borderRadius: BorderRadius.circular(12.r), border: Border.all( color: isDarkMode ? Colors.red[800]! : Colors.red[200]!), @@ -440,12 +441,12 @@ class HomeView extends GetView { final leftBattery = controller.leftEarBattery; final rightBattery = controller.rightEarBattery; final caseBattery = controller.caseBattery; - + // 获取充电状态 final leftEarCharging = controller.leftEarCharging; final rightEarCharging = controller.rightEarCharging; final caseCharging = controller.caseCharging; - + return GridView.count( crossAxisCount: 3, shrinkWrap: true, @@ -461,7 +462,7 @@ class HomeView extends GetView { isCharging: leftEarCharging, isDarkMode: isDarkMode, ), - + // 右耳机 _buildBatteryGridItem( icon: Icons.headphones, @@ -470,7 +471,7 @@ class HomeView extends GetView { isCharging: rightEarCharging, isDarkMode: isDarkMode, ), - + // 充电盒 _buildBatteryGridItem( icon: Icons.charging_station, @@ -483,7 +484,7 @@ class HomeView extends GetView { ); }); } - + // 单个电池网格项 Widget _buildBatteryGridItem({ required IconData icon, @@ -495,7 +496,7 @@ class HomeView extends GetView { // 获取电池图标和颜色 IconData batteryIcon; Color batteryColor; - + if (batteryLevel > 75) { batteryIcon = Icons.battery_full; batteryColor = Colors.green[600]!; @@ -512,16 +513,16 @@ class HomeView extends GetView { batteryIcon = Icons.battery_alert; batteryColor = Colors.red[600]!; } - + return Container( decoration: BoxDecoration( color: isDarkMode ? Colors.grey[900] : Colors.grey[100], borderRadius: BorderRadius.circular(12.r), boxShadow: [ BoxShadow( - color: isDarkMode ? - Colors.black.withOpacity(0.1) : - Colors.grey.withOpacity(0.1), + color: isDarkMode + ? Colors.black.withOpacity(0.1) + : Colors.grey.withOpacity(0.1), blurRadius: 4, spreadRadius: 0, offset: Offset(0, 2), @@ -545,7 +546,7 @@ class HomeView extends GetView { ), ), SizedBox(height: 6.h), - + // 标签 Text( label, @@ -557,7 +558,7 @@ class HomeView extends GetView { textAlign: TextAlign.center, ), SizedBox(height: 6.h), - + // 电池指示器 Row( mainAxisAlignment: MainAxisAlignment.center, @@ -614,7 +615,7 @@ class HomeView extends GetView { isDarkMode: isDarkMode, ), SizedBox(height: 8.h), - + // 固件版本 _buildInfoRow( icon: Icons.info_outline, @@ -622,8 +623,7 @@ class HomeView extends GetView { value: controller.firmwareVersion, isDarkMode: isDarkMode, ), - - + // 连接状态标签 SizedBox(height: 10.h), Container( @@ -763,7 +763,7 @@ class HomeView extends GetView { ), ); } - + // 热门AI体验标题 Widget _buildSectionTitle(bool isDarkMode) { return Row( diff --git a/lib/modules/profile/controllers/profile_controller.dart b/lib/modules/profile/controllers/profile_controller.dart index d3e2645ea..5bee74c6d 100644 --- a/lib/modules/profile/controllers/profile_controller.dart +++ b/lib/modules/profile/controllers/profile_controller.dart @@ -1,7 +1,6 @@ import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import 'package:flutter/material.dart'; -//import 'package:http/http.dart'; import 'package:image_picker/image_picker.dart'; import 'package:logger/logger.dart'; import '../../../data/models/user_Info.dart'; @@ -19,26 +18,17 @@ import '../../../modules/login/controllers/facebookLogin.dart'; class ProfileController extends GetxController { static ProfileController get to => Get.find(); - // final _userName = ''.obs; - // final _email = ''.obs; - // final _avatar = ''.obs; - // final _isEditing = false.obs; - // final _storage = GetStorage(); //用户信息 static const String userKey = 'user_info'; //用户信息存储键 final _storage = GetStorage(); //本地存储 final ImagePicker _picker = ImagePicker(); //图片选择器 final Rx userInfo = User.instance.obs; // 响应式用户信息对象,使用单例模式确保全局唯一性 final RxString localAvatar = ''.obs; // 本地头像路径,便于响应式更新UI + final RxBool hasEdits = false.obs; // 是否有编辑 // 使用响应式变量 final currentLanguage = 'zh'.obs; - // String get userName => _userName.value; - // String get email => _email.value; - // String get avatar => _avatar.value; - // bool get isEditing => _isEditing.value; - @override void onInit() { super.onInit(); @@ -46,16 +36,6 @@ class ProfileController extends GetxController { loadLanguagePreference(); } - // void loadUserData() { - // try { - // _userName.value = _storage.read('userName') ?? 'User Name'; - // _email.value = _storage.read('userEmail') ?? 'user@example.com'; - // _avatar.value = _storage.read('userAvatar') ?? ''; - // } catch (e) { - // Get.snackbar('Error', 'Failed to load user data'); - // } - // } - // 加载用户语言偏好设置 void loadLanguagePreference() { try { @@ -332,6 +312,7 @@ class ProfileController extends GetxController { // if (Get.isRegistered()) { // Get.find().loadUserInfo(); // } + hasEdits.value = true; //表示有编辑 } } diff --git a/lib/modules/profile/views/profile_view.dart b/lib/modules/profile/views/profile_view.dart index a2acf36da..23b3e38ef 100644 --- a/lib/modules/profile/views/profile_view.dart +++ b/lib/modules/profile/views/profile_view.dart @@ -9,130 +9,130 @@ import 'dart:ui'; import '../../common/webview_page.dart'; // ProfileView: 用户设置页面 -class ProfileView extends GetView { - const ProfileView({Key? key}) : super(key: key); +// class ProfileView extends GetView { +// const ProfileView({Key? key}) : super(key: key); - Widget _buildMenuItem({ - required String title, - required IconData icon, - String? subtitle, - required VoidCallback onTap, - }) { - return ListTile( - leading: Icon(icon, size: 24.sp, color: Colors.grey[700]), - title: Text( - title, - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w500, - ), - ), - subtitle: subtitle != null - ? Text( - subtitle, - style: TextStyle( - fontSize: 14.sp, - color: Colors.grey[600], - ), - ) - : null, - trailing: Icon( - Icons.chevron_right, - size: 24.sp, - color: Colors.grey[400], - ), - onTap: onTap, - ); - } +// Widget _buildMenuItem({ +// required String title, +// required IconData icon, +// String? subtitle, +// required VoidCallback onTap, +// }) { +// return ListTile( +// leading: Icon(icon, size: 24.sp, color: Colors.grey[700]), +// title: Text( +// title, +// style: TextStyle( +// fontSize: 16.sp, +// fontWeight: FontWeight.w500, +// ), +// ), +// subtitle: subtitle != null +// ? Text( +// subtitle, +// style: TextStyle( +// fontSize: 14.sp, +// color: Colors.grey[600], +// ), +// ) +// : null, +// trailing: Icon( +// Icons.chevron_right, +// size: 24.sp, +// color: Colors.grey[400], +// ), +// onTap: onTap, +// ); +// } - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.white, - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - title: Text( - '设置'.tr, - style: TextStyle( - fontSize: 17.sp, - fontWeight: FontWeight.w600, - color: Colors.black, - ), - ), - centerTitle: true, - ), - body: ListView( - children: [ - SizedBox(height: 12.h), - const Divider(), - _buildMenuItem( - title: '关于'.tr, - icon: Icons.info_outline, - onTap: () { - // TODO: 实现关于页面 - }, - ), - const Divider(), - _buildMenuItem( - title: '火山语音合成测试'.tr, - icon: Icons.record_voice_over, - subtitle: '测试火山语音TTS功能', - onTap: () { - Get.toNamed(Routes.TTS_TEST); - }, - ), - const Divider(), - _buildMenuItem( - title: '火山语音识别测试'.tr, - icon: Icons.mic_external_on, - subtitle: '测试火山语音ASR功能', - onTap: () { - Get.toNamed(Routes.VOLCANO_ASR_TEST); - }, - ), - const Divider(), - _buildMenuItem( - title: 'Azure语音识别测试'.tr, - icon: Icons.mic, - subtitle: '测试Azure语音ASR功能', - onTap: () { - Get.toNamed(Routes.AZURE_ASR_TEST); - }, - ), - const Divider(), - _buildMenuItem( - title: 'Azure语音合成测试'.tr, - icon: Icons.record_voice_over, - subtitle: '测试Azure语音TTS功能', - onTap: () { - Get.toNamed(Routes.AZURE_TTS_TEST); - }, - ), - const Divider(), - _buildMenuItem( - title: '本地语音合成测试'.tr, - icon: Icons.speaker_phone, - subtitle: '测试Flutter TTS本地语音合成功能', - onTap: () { - Get.toNamed(Routes.FLUTTER_TTS_TEST); - }, - ), - const Divider(), - _buildMenuItem( - title: '本地语音识别测试'.tr, - icon: Icons.mic_none, - subtitle: '测试Flutter本地语音识别功能', - onTap: () { - Get.toNamed(Routes.FLUTTER_ASR_TEST); - }, - ), - ], - ), - bottomNavigationBar: const CommonBottomNav(currentIndex: 2), - ); - } -} +// @override +// Widget build(BuildContext context) { +// return Scaffold( +// backgroundColor: Colors.white, +// appBar: AppBar( +// backgroundColor: Colors.white, +// elevation: 0, +// title: Text( +// '设置'.tr, +// style: TextStyle( +// fontSize: 17.sp, +// fontWeight: FontWeight.w600, +// color: Colors.black, +// ), +// ), +// centerTitle: true, +// ), +// body: ListView( +// children: [ +// SizedBox(height: 12.h), +// const Divider(), +// _buildMenuItem( +// title: '关于'.tr, +// icon: Icons.info_outline, +// onTap: () { +// // TODO: 实现关于页面 +// }, +// ), +// const Divider(), +// _buildMenuItem( +// title: '火山语音合成测试'.tr, +// icon: Icons.record_voice_over, +// subtitle: '测试火山语音TTS功能', +// onTap: () { +// Get.toNamed(Routes.TTS_TEST); +// }, +// ), +// const Divider(), +// _buildMenuItem( +// title: '火山语音识别测试'.tr, +// icon: Icons.mic_external_on, +// subtitle: '测试火山语音ASR功能', +// onTap: () { +// Get.toNamed(Routes.VOLCANO_ASR_TEST); +// }, +// ), +// const Divider(), +// _buildMenuItem( +// title: 'Azure语音识别测试'.tr, +// icon: Icons.mic, +// subtitle: '测试Azure语音ASR功能', +// onTap: () { +// Get.toNamed(Routes.AZURE_ASR_TEST); +// }, +// ), +// const Divider(), +// _buildMenuItem( +// title: 'Azure语音合成测试'.tr, +// icon: Icons.record_voice_over, +// subtitle: '测试Azure语音TTS功能', +// onTap: () { +// Get.toNamed(Routes.AZURE_TTS_TEST); +// }, +// ), +// const Divider(), +// _buildMenuItem( +// title: '本地语音合成测试'.tr, +// icon: Icons.speaker_phone, +// subtitle: '测试Flutter TTS本地语音合成功能', +// onTap: () { +// Get.toNamed(Routes.FLUTTER_TTS_TEST); +// }, +// ), +// const Divider(), +// _buildMenuItem( +// title: '本地语音识别测试'.tr, +// icon: Icons.mic_none, +// subtitle: '测试Flutter本地语音识别功能', +// onTap: () { +// Get.toNamed(Routes.FLUTTER_ASR_TEST); +// }, +// ), +// ], +// ), +// bottomNavigationBar: const CommonBottomNav(currentIndex: 2), +// ); +// } +// } // EditProfileView: 编辑个人资料页面 class EditProfileView extends GetView { @@ -146,19 +146,19 @@ class EditProfileView extends GetView { return Scaffold( resizeToAvoidBottomInset: false, // 添加这一行,防止键盘挤压内容 - 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, + 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(), ), - onPressed: () => Get.back(), - ), // title: Text( // 'editProfile'.tr, // style: TextStyle( @@ -168,22 +168,25 @@ class EditProfileView extends GetView { // ), // ), actions: [ - TextButton( - onPressed: () { - // 保存用户名 - controller.updateUserNameAndAvatar(nameController.text); - // 返回上一级页面 - Get.back(); - }, - child: Text( - 'save'.tr, - style: TextStyle( - fontSize: 16.sp, - color: isDarkMode ? Colors.blue[300] : Colors.blue, - fontWeight: FontWeight.w500, - ), - ), - ), + Obx(() => Visibility( + visible: controller.hasEdits.value, + child: TextButton( + onPressed: () { + // 保存用户名 + controller.updateUserNameAndAvatar(nameController.text); + // 返回上一级页面 + Get.back(); + }, + child: Text( + 'save'.tr, + style: TextStyle( + fontSize: 16.sp, + color: isDarkMode ? Colors.blue[300] : Colors.blue, + fontWeight: FontWeight.w500, + ), + ), + ), + )) ], ), body: Padding( @@ -472,6 +475,12 @@ class EditProfileView extends GetView { onPressed: () { // 确认时,将对话框输入的值更新回主 nameController nameController.text = dialogNameController.text; + controller.userInfo.update((user) { + if (user != null) { + user.name = dialogNameController.text; + } + }); + controller.hasEdits.value = true; // 标记已编辑 Get.back(); // 关闭对话框 // 注意:实际的保存操作由 AppBar 中的保存按钮触发 }, diff --git a/lib/modules/settings/views/settings_view.dart b/lib/modules/settings/views/settings_view.dart index eb7ea7512..350b91b1b 100644 --- a/lib/modules/settings/views/settings_view.dart +++ b/lib/modules/settings/views/settings_view.dart @@ -62,156 +62,155 @@ class SettingsView extends GetView { return GestureDetector( onTap: () => Get.toNamed(Routes.editProfile), child: Container( - padding: EdgeInsets.all(16.w), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: isDarkMode - ? [ - const Color(0xFF1A1A1A).withOpacity(0.7), - const Color(0xFF2A2A2A).withOpacity(0.7) - ] - : [const Color(0xFFE3F2FD), const Color(0xFFF3E5F5)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(16.r), - boxShadow: [ - BoxShadow( - color: isDarkMode - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.05), - blurRadius: 10, - offset: const Offset(0, 2), + padding: EdgeInsets.all(16.w), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: isDarkMode + ? [ + const Color(0xFF1A1A1A).withOpacity(0.7), + const Color(0xFF2A2A2A).withOpacity(0.7) + ] + : [const Color(0xFFE3F2FD), const Color(0xFFF3E5F5)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, ), - ], - ), - child: ClipRRect( - //裁剪圆角矩形 - borderRadius: BorderRadius.circular(16.r), - child: BackdropFilter( - filter: isDarkMode - ? ImageFilter.blur(sigmaX: 10, sigmaY: 10) - : ImageFilter.blur(sigmaX: 0, sigmaY: 0), - child: Row( - children: [ - Obx(() => GestureDetector( - //onTap: ()=>controller.updateUserAvatar(), - child: Container( - //用户头像部分 - width: 60.w, - height: 60.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(30.r), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], - ), - child: ClipRRect( - // 裁剪圆形头像 + borderRadius: BorderRadius.circular(16.r), + boxShadow: [ + BoxShadow( + color: isDarkMode + ? Colors.black.withOpacity(0.2) + : Colors.black.withOpacity(0.05), + blurRadius: 10, + offset: const Offset(0, 2), + ), + ], + ), + child: ClipRRect( + //裁剪圆角矩形 + borderRadius: BorderRadius.circular(16.r), + child: BackdropFilter( + filter: isDarkMode + ? ImageFilter.blur(sigmaX: 10, sigmaY: 10) + : ImageFilter.blur(sigmaX: 0, sigmaY: 0), + child: Row( + children: [ + Obx(() => GestureDetector( + //onTap: ()=>controller.updateUserAvatar(), + child: Container( + //用户头像部分 + width: 60.w, + height: 60.w, + decoration: BoxDecoration( borderRadius: BorderRadius.circular(30.r), - child: controller.userInfo.value.avatar.isEmpty - ? - Container( - decoration: BoxDecoration( - color: Colors.blue[600], - borderRadius: BorderRadius.circular(30.r), - ), - child: Center( - child: Text( - controller - .userInfo.value.name.isNotEmpty - ? controller.userInfo.value.name[0] - .toUpperCase() - : '?', - style: TextStyle( - color: Colors.white, - fontSize: 24.sp, - fontWeight: FontWeight.bold, - ), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: ClipRRect( + // 裁剪圆形头像 + borderRadius: BorderRadius.circular(30.r), + child: controller.userInfo.value.avatar.isEmpty + ? Container( + decoration: BoxDecoration( + color: Colors.blue[600], + borderRadius: BorderRadius.circular(30.r), ), - ), - ) - : Image.network( - controller.userInfo.value.avatar, - fit: BoxFit.cover, - errorBuilder: (context, error, stackTrace) { - // 当图片加载失败时显示用户名首字母 - return Container( - decoration: BoxDecoration( - color: Colors.blue[600], - borderRadius: - BorderRadius.circular(30.r), + child: Center( + child: Text( + controller + .userInfo.value.name.isNotEmpty + ? controller.userInfo.value.name[0] + .toUpperCase() + : '?', + style: TextStyle( + color: Colors.white, + fontSize: 24.sp, + fontWeight: FontWeight.bold, + ), ), - child: Center( - child: Text( - controller.userInfo.value.name - .isNotEmpty - ? controller - .userInfo.value.name[0] - .toUpperCase() - : '?', - style: TextStyle( - color: Colors.white, - fontSize: 24.sp, - fontWeight: FontWeight.bold, + ), + ) + : Image.network( + controller.userInfo.value.avatar, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + // 当图片加载失败时显示用户名首字母 + return Container( + decoration: BoxDecoration( + color: Colors.blue[600], + borderRadius: + BorderRadius.circular(30.r), + ), + child: Center( + child: Text( + controller.userInfo.value.name + .isNotEmpty + ? controller + .userInfo.value.name[0] + .toUpperCase() + : '?', + style: TextStyle( + color: Colors.white, + fontSize: 24.sp, + fontWeight: FontWeight.bold, + ), ), ), - ), - ); - }, - )), - ), - )), - SizedBox(width: 16.w), - Expanded( - // 占据剩余空间 - child: Obx( - () => Column( - crossAxisAlignment: CrossAxisAlignment.start, // 左对齐 - children: [ - Text( - //用户名 - controller.userInfo.value.name, - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black87, - ), - overflow: TextOverflow.ellipsis, + ); + }, + )), ), - SizedBox(height: 4.h), - Row( - children: [ - Container( - padding: EdgeInsets.symmetric( - horizontal: 8.w, vertical: 2.h), - decoration: BoxDecoration( - color: Colors.blue[600], - borderRadius: BorderRadius.circular(10.r), - ), - child: Obx(() { - final membershipMap = { - 0: 'freeUser', //'免费用户' - 1: 'standardUser', //'标准用户' - 2: 'proUser', //'专业用户' - }; - final membershipString = membershipMap[ - controller - .userInfo.value.membershipLevel] ?? - 'Unknown'; - return Text( - membershipString, - style: TextStyle( - fontSize: 10.sp, - color: Colors.white, - ), - ); - }), + )), + SizedBox(width: 16.w), + Expanded( + // 占据剩余空间 + child: Obx( + () => Column( + crossAxisAlignment: CrossAxisAlignment.start, // 左对齐 + children: [ + Text( + //用户名 + controller.userInfo.value.name, + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.w600, + color: isDarkMode ? Colors.white : Colors.black87, ), + overflow: TextOverflow.ellipsis, + ), + SizedBox(height: 4.h), + Row( + children: [ + Container( + padding: EdgeInsets.symmetric( + horizontal: 8.w, vertical: 2.h), + decoration: BoxDecoration( + color: Colors.blue[600], + borderRadius: BorderRadius.circular(10.r), + ), + child: Obx(() { + final membershipMap = { + 0: 'freeUser', //'免费用户' + 1: 'standardUser', //'标准用户' + 2: 'proUser', //'专业用户' + }; + final membershipString = membershipMap[ + controller + .userInfo.value.membershipLevel] ?? + 'Unknown'; + return Text( + membershipString, + style: TextStyle( + fontSize: 10.sp, + color: Colors.white, + ), + ); + }), + ), // SizedBox(width: 8.w), // Flexible( // child: Text( @@ -225,46 +224,46 @@ class SettingsView extends GetView { // overflow: TextOverflow.ellipsis, // ), // ), - ], - ), - SizedBox(height: 4.h), - Text( + ], + ), + SizedBox(height: 4.h), + Text( 'ID:${controller.userInfo.value.uid}', - style: TextStyle( - fontSize: 12.sp, - color: isDarkMode ? Colors.white70 : Colors.black54, + style: TextStyle( + fontSize: 12.sp, + color: isDarkMode ? Colors.white70 : Colors.black54, + ), ), - ), - ], + ], + ), ), ), - ), - Container( - // 编辑按钮 - width: 32.w, - height: 32.w, - decoration: BoxDecoration( - color: isDarkMode - ? Colors.white.withOpacity(0.1) - : Colors.white.withOpacity(0.7), - borderRadius: BorderRadius.circular(16.r), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 1), - ), - ], - ), - child: InkWell( - onTap: () => Get.toNamed(Routes.editProfile), - child: Icon( - Icons.edit, - size: 16.w, - color: isDarkMode ? Colors.white70 : Colors.grey[600], + Container( + // 编辑按钮 + width: 32.w, + height: 32.w, + decoration: BoxDecoration( + color: isDarkMode + ? Colors.white.withOpacity(0.1) + : Colors.white.withOpacity(0.7), + borderRadius: BorderRadius.circular(16.r), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 4, + offset: const Offset(0, 1), + ), + ], ), - )), - ], + child: InkWell( + onTap: () => Get.toNamed(Routes.editProfile), + child: Icon( + Icons.edit, + size: 16.w, + color: isDarkMode ? Colors.white70 : Colors.grey[600], + ), + )), + ], ), ), ), @@ -572,7 +571,7 @@ class SettingsView extends GetView { _buildSimpleNavigationSetting( title: 'ota升级', subtitle: '测试ble耳机固件版本升级', - icon: Icons.record_voice_over, + icon: Icons.system_update_alt, iconBgColor: isDarkMode ? Colors.orange[900]!.withOpacity(0.3) : Colors.orange[100]!, @@ -581,11 +580,11 @@ class SettingsView extends GetView { onTap: () => Get.toNamed(Routes.OTA_UPGRADE), isDarkMode: isDarkMode, ), - Divider( - height: 1, - color: isDarkMode - ? Colors.white.withOpacity(0.1) - : Colors.grey[200]), + // Divider( + // height: 1, + // color: isDarkMode + // ? Colors.white.withOpacity(0.1) + // : Colors.grey[200]), // 退出登录 // _buildSimpleNavigationSetting( diff --git a/lib/routes/app_pages.dart b/lib/routes/app_pages.dart index 8f36c4510..fe3576f12 100644 --- a/lib/routes/app_pages.dart +++ b/lib/routes/app_pages.dart @@ -103,13 +103,13 @@ abstract class AppPages { page: () => const OtaUpgradeView(), binding: OtaUpgradeBinding(), ), - GetPage( - name: Routes.profile, - page: () => const ProfileView(), - binding: ProfileBinding(), - transition: Transition.rightToLeft, - transitionDuration: Duration(milliseconds: 250), - ), + // GetPage( + // name: Routes.profile, + // page: () => const ProfileView(), + // binding: ProfileBinding(), + // transition: Transition.rightToLeft, + // transitionDuration: Duration(milliseconds: 250), + // ), GetPage( name: Routes.editProfile, page: () => const EditProfileView(), diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index d44a5616c..08500199f 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -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'; // 在线客服 } From 6e65df9f769a8f2142d6572b1736d623c00059f4 Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Mon, 12 May 2025 16:27:45 +0800 Subject: [PATCH 2/5] =?UTF-8?q?refactor(home=5Fview):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E8=BF=9E=E6=8E=A5=E7=8A=B6=E6=80=81=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E5=92=8C=E7=94=B5=E6=B1=A0=E4=BF=A1=E6=81=AF=E5=B8=83?= =?UTF-8?q?=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重构设备连接状态显示逻辑,调整电池信息布局为紧凑型设计,提升界面可读性和用户体验。同时修复部分代码格式问题,确保代码风格一致。 --- lib/modules/home/views/home_view.dart | 382 ++++++++++++++------------ 1 file changed, 200 insertions(+), 182 deletions(-) diff --git a/lib/modules/home/views/home_view.dart b/lib/modules/home/views/home_view.dart index dae65616a..fc2f31eea 100644 --- a/lib/modules/home/views/home_view.dart +++ b/lib/modules/home/views/home_view.dart @@ -1,17 +1,17 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'dart:ui'; import '../controllers/home_controller.dart'; import '../../../routes/app_pages.dart'; import '../../../routes/app_routes.dart'; import '../../../core/widgets/common_bottom_nav.dart'; - // 导入枚举 import '../controllers/home_controller.dart' show ConnectionStatus; -// 呼吸光动画组件 +// 呼吸灯动画组件 class AnimatedPulsing extends StatefulWidget { + const AnimatedPulsing({Key? key}) : super(key: key); + @override _AnimatedPulsingState createState() => _AnimatedPulsingState(); } @@ -25,14 +25,11 @@ class _AnimatedPulsingState extends State void initState() { super.initState(); _controller = AnimationController( - duration: Duration(seconds: 2), + duration: const Duration(seconds: 2), vsync: this, )..repeat(reverse: true); _animation = Tween(begin: 0.5, end: 0.8).animate( - CurvedAnimation( - parent: _controller, - curve: Curves.easeInOut, - ), + CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); } @@ -49,36 +46,36 @@ class _AnimatedPulsingState extends State builder: (context, child) { return Opacity( opacity: _animation.value, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16.r), - gradient: RadialGradient( - colors: [ - Colors.white.withOpacity(0.3), - Colors.transparent, - ], - center: Alignment.topRight, - radius: 0.8, - stops: [0.0, 1.0], - ), - ), - ), + child: child, ); }, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16.r), + gradient: RadialGradient( + colors: [ + Colors.white.withOpacity(0.3), + Colors.transparent, + ], + center: Alignment.topRight, + radius: 0.8, + stops: const [0.0, 1.0], + ), + ), + ), ); } } -//首页视图 +// 首页视图 class HomeView extends GetView { const HomeView({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final bool isDarkMode = Theme.of(context).brightness == Brightness.dark; - return Scaffold( - backgroundColor: isDarkMode ? Colors.black : Color(0xFFF9FAFC), + backgroundColor: isDarkMode ? Colors.black : const Color(0xFFF9FAFC), body: SafeArea( child: SingleChildScrollView( padding: EdgeInsets.all(16.w), @@ -210,7 +207,7 @@ class HomeView extends GetView { Widget _buildDeviceStatusCard(bool isDarkMode) { return Container( decoration: BoxDecoration( - color: isDarkMode ? Color(0xFF1A1A1A) : Colors.white, + color: isDarkMode ? const Color(0xFF1A1A1A) : Colors.white, borderRadius: BorderRadius.circular(16.r), boxShadow: [ BoxShadow( @@ -229,20 +226,22 @@ class HomeView extends GetView { // 设备信息 SizedBox(height: 12.h), Obx(() { + print('连接状态: ${controller.connectionStatus}'); // 添加调试打印 + print('错误信息: ${controller.connectionErrorMsg}'); // 添加调试打印 // 如果连接失败且有错误信息,显示错误提示 if (controller.connectionStatus == ConnectionStatus.failed && controller.connectionErrorMsg.isNotEmpty) { - return _buildConnectionErrorSection(isDarkMode); + return _buildConnectionErrorSection(isDarkMode); //错误提示 } // 如果正在连接中,显示连接中提示 if (controller.connectionStatus == ConnectionStatus.connecting) { - return _buildConnectingIndicator(); + return _buildConnectingIndicator(); //连接中提示 } return controller.isConnected - ? _buildConnectedDeviceInfo(isDarkMode) - : _buildDisconnectedInfo(isDarkMode); + ? _buildConnectedDeviceInfo(isDarkMode) //已连接设备信息 + : _buildDisconnectedInfo(isDarkMode); //未连接提示 }), // 连接按钮(仅在未连接时显示) @@ -285,6 +284,7 @@ class HomeView extends GetView { Obx(() => Row( children: [ Container( + //状态指示灯 width: 8.w, height: 8.w, decoration: BoxDecoration( @@ -344,7 +344,8 @@ class HomeView extends GetView { isDarkMode ? Colors.red[900]!.withOpacity(0.2) : Colors.red[50], borderRadius: BorderRadius.circular(12.r), border: Border.all( - color: isDarkMode ? Colors.red[800]! : Colors.red[200]!), + color: isDarkMode ? Colors.red[800]! : Colors.red[200]!, + ), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, @@ -410,7 +411,7 @@ class HomeView extends GetView { ), SizedBox(height: 12.h), Text( - 'connectingDevice'.tr, // 正在连接设备... + 'connectingDevice'.tr, style: TextStyle( fontSize: 13.sp, color: Colors.blue, @@ -423,13 +424,45 @@ class HomeView extends GetView { ); } - // 已连接设备信息 + // 已连接设备信息(新增设备名称 + 信号强度 + 电池信息) Widget _buildConnectedDeviceInfo(bool isDarkMode) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // 电池状态网格布局 + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + '${'connectedTo'.tr}:${controller.getDeviceName()}', + style: TextStyle( + fontSize: 13.sp, + fontWeight: FontWeight.w500, + color: isDarkMode ? Colors.grey[300] : Colors.grey[700], + ), + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h), + decoration: BoxDecoration( + color: Colors.blue.withOpacity(0.1), + borderRadius: BorderRadius.circular(4.r), + ), + child: Text( + '${'signal'.tr}: ${controller.getSignalStrength()}', + style: TextStyle( + fontSize: 11.sp, + color: Colors.blue[700], + ), + ), + ), + ], + ), + SizedBox(height: 12.h), _buildBatteryInfoGrid(isDarkMode), + SizedBox(height: 16.h), + _buildDeviceDetailsCard(isDarkMode), ], ); } @@ -441,53 +474,66 @@ class HomeView extends GetView { final leftBattery = controller.leftEarBattery; final rightBattery = controller.rightEarBattery; final caseBattery = controller.caseBattery; - // 获取充电状态 final leftEarCharging = controller.leftEarCharging; final rightEarCharging = controller.rightEarCharging; final caseCharging = controller.caseCharging; - return GridView.count( - crossAxisCount: 3, - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - crossAxisSpacing: 12.w, - childAspectRatio: 0.85, - children: [ - // 左耳机 - _buildBatteryGridItem( - icon: Icons.headphones, - label: '左耳机', - batteryLevel: leftBattery.value, - isCharging: leftEarCharging.value, - isDarkMode: isDarkMode, - ), + // 使用更紧凑的布局 + return Container( + padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 4.w), + decoration: BoxDecoration( + color: isDarkMode ? Colors.grey[900] : Colors.grey[50], + borderRadius: BorderRadius.circular(12.r), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + // 左耳机 + _buildCompactBatteryItem( + label: '左', + batteryLevel: leftBattery.value, + isCharging: leftEarCharging.value, + isDarkMode: isDarkMode, + ), - // 右耳机 - _buildBatteryGridItem( - icon: Icons.headphones, - label: '右耳机', - batteryLevel: rightBattery.value, - isCharging: rightEarCharging.value, - isDarkMode: isDarkMode, - ), + // 分隔线 + Container( + height: 30.h, + width: 1, + color: isDarkMode ? Colors.grey[800] : Colors.grey[300], + ), - // 充电盒 - _buildBatteryGridItem( - icon: Icons.charging_station, - label: '充电盒', - batteryLevel: caseBattery.value, - isCharging: caseCharging.value, - isDarkMode: isDarkMode, - ), - ], + // 右耳机 + _buildCompactBatteryItem( + label: '右', + batteryLevel: rightBattery.value, + isCharging: rightEarCharging.value, + isDarkMode: isDarkMode, + ), + + // 分隔线 + Container( + height: 30.h, + width: 1, + color: isDarkMode ? Colors.grey[800] : Colors.grey[300], + ), + + // 充电盒 + _buildCompactBatteryItem( + label: '充电盒', + batteryLevel: caseBattery.value, + isCharging: caseCharging.value, + isDarkMode: isDarkMode, + ), + ], + ), ); }); } - // 单个电池网格项 - Widget _buildBatteryGridItem({ - required IconData icon, + // 紧凑型电池项 + Widget _buildCompactBatteryItem({ required String label, required int batteryLevel, required bool isDarkMode, @@ -496,7 +542,6 @@ class HomeView extends GetView { // 获取电池图标和颜色 IconData batteryIcon; Color batteryColor; - if (batteryLevel > 75) { batteryIcon = Icons.battery_full; batteryColor = Colors.green[600]!; @@ -505,7 +550,7 @@ class HomeView extends GetView { batteryColor = Colors.green[600]!; } else if (batteryLevel > 25) { batteryIcon = Icons.battery_4_bar; - batteryColor = Colors.yellow[600]!; + batteryColor = Colors.orange[600]!; } else if (batteryLevel > 10) { batteryIcon = Icons.battery_3_bar; batteryColor = Colors.orange[600]!; @@ -514,80 +559,52 @@ class HomeView extends GetView { batteryColor = Colors.red[600]!; } - return Container( - decoration: BoxDecoration( - color: isDarkMode ? Colors.grey[900] : Colors.grey[100], - borderRadius: BorderRadius.circular(12.r), - boxShadow: [ - BoxShadow( - color: isDarkMode - ? Colors.black.withOpacity(0.1) - : Colors.grey.withOpacity(0.1), - blurRadius: 4, - spreadRadius: 0, - offset: Offset(0, 2), - ), - ], - ), - padding: EdgeInsets.all(10.w), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - // 设备图标 - Container( - padding: EdgeInsets.all(8.w), - decoration: BoxDecoration( - shape: BoxShape.circle, - ), - child: Icon( - icon, - size: 24.sp, - color: isDarkMode ? Colors.grey[300] : Colors.grey[800], - ), - ), - SizedBox(height: 6.h), - - // 标签 - Text( - label, - style: TextStyle( - fontSize: 12.sp, - color: isDarkMode ? Colors.grey[400] : Colors.grey[500], - fontWeight: FontWeight.normal, + return Expanded( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 6.h), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // 标签 + Text( + label, + style: TextStyle( + fontSize: 11.sp, + color: isDarkMode ? Colors.grey[400] : Colors.grey[500], + fontWeight: FontWeight.normal, + ), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - SizedBox(height: 6.h), + SizedBox(height: 4.h), - // 电池指示器 - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - batteryIcon, - size: 14.sp, - color: batteryColor, - ), - SizedBox(width: 4.w), - Text( - '$batteryLevel%', - style: TextStyle( - fontSize: 12.sp, - fontWeight: FontWeight.w500, + // 电池指示器 + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + batteryIcon, + size: 12.sp, color: batteryColor, ), - ), - if (isCharging) ...[ SizedBox(width: 2.w), - Icon( - Icons.bolt, - size: 12.sp, - color: Colors.green[600], + Text( + '$batteryLevel%', + style: TextStyle( + fontSize: 11.sp, + fontWeight: FontWeight.w500, + color: batteryColor, + ), ), + if (isCharging) + Icon( + Icons.bolt, + size: 10.sp, + color: Colors.green[600], + ), ], - ], - ), - ], + ), + ], + ), ), ); } @@ -625,37 +642,37 @@ class HomeView extends GetView { ), // 连接状态标签 - SizedBox(height: 10.h), - Container( - padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h), - decoration: BoxDecoration( - color: controller.getConnectionStatusColor().withOpacity(0.1), - borderRadius: BorderRadius.circular(6.r), - border: Border.all( - color: controller.getConnectionStatusColor().withOpacity(0.3), - width: 1, - ), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.check_circle_outline, - size: 12.sp, - color: controller.getConnectionStatusColor(), - ), - SizedBox(width: 4.w), - Text( - controller.getConnectionStatusText(), - style: TextStyle( - fontSize: 11.sp, - color: controller.getConnectionStatusColor(), - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ), + // SizedBox(height: 10.h), + // Container( + // padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h), + // decoration: BoxDecoration( + // color: controller.getConnectionStatusColor().withOpacity(0.1), + // borderRadius: BorderRadius.circular(6.r), + // border: Border.all( + // color: controller.getConnectionStatusColor().withOpacity(0.3), + // width: 1, + // ), + // ), + // child: Row( + // mainAxisSize: MainAxisSize.min, + // children: [ + // Icon( + // Icons.check_circle_outline, + // size: 12.sp, + // color: controller.getConnectionStatusColor(), + // ), + // SizedBox(width: 4.w), + // Text( + // controller.getConnectionStatusText(), + // style: TextStyle( + // fontSize: 11.sp, + // color: controller.getConnectionStatusColor(), + // fontWeight: FontWeight.w500, + // ), + // ), + // ], + // ), + // ), ], ), ); @@ -701,33 +718,34 @@ class HomeView extends GetView { // 未连接信息 Widget _buildDisconnectedInfo(bool isDarkMode) { return Container( - padding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 12.w), + padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 12.w), alignment: Alignment.center, decoration: BoxDecoration( color: isDarkMode ? Colors.grey[900] : Colors.grey[100], - borderRadius: BorderRadius.circular(12.r), + borderRadius: BorderRadius.circular(10.r), border: Border.all( color: isDarkMode ? Colors.grey[800]! : Colors.grey[300]!, width: 1, ), ), - child: Column( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.bluetooth_disabled, - size: 32.sp, - color: isDarkMode ? Colors.grey[600] : Colors.grey[500], + size: 14.sp, + color: isDarkMode ? Colors.grey[400] : Colors.grey[700], ), SizedBox(height: 12.h), Text( 'disconnectedDevice'.tr, // 未连接设备,点击下方按钮连接 style: TextStyle( - fontSize: 13.sp, + fontSize: 12.sp, color: isDarkMode ? Colors.grey[400] : Colors.grey[700], - height: 1.4, - fontWeight: FontWeight.w500, + // height: 1.4, + // fontWeight: FontWeight.w500, ), - textAlign: TextAlign.center, + //textAlign: TextAlign.center, ), ], ), @@ -750,7 +768,7 @@ class HomeView extends GetView { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.bluetooth_searching, size: 18.sp), + Icon(Icons.bluetooth_searching, size: 16.sp), SizedBox(width: 8.w), Text( 'connectDevice'.tr, // 连接设备 @@ -832,8 +850,8 @@ class HomeView extends GetView { begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ - Color(0xFF4CAF50).withOpacity(0.3), - Color(0xFF009688).withOpacity(0.3), + const Color(0xFF4CAF50).withOpacity(0.3), + const Color(0xFF009688).withOpacity(0.3), ], ), onTap: controller.openTranslation, From a911cba3a63dccd1f17be2ab10ac8278983add1f Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Mon, 12 May 2025 17:58:30 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=A4=A9=E6=B0=94?= =?UTF-8?q?=E9=A2=84=E6=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/modules/agent/views/message_bubble.dart | 86 ++++++++++----------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/lib/modules/agent/views/message_bubble.dart b/lib/modules/agent/views/message_bubble.dart index 0e7be74b9..a5d347169 100644 --- a/lib/modules/agent/views/message_bubble.dart +++ b/lib/modules/agent/views/message_bubble.dart @@ -217,7 +217,7 @@ class MessageBubble extends GetView { final rawList = mate!['card_weather']['dayweather'] as List; final daylist = rawList.map((e) => Map.from(e)).toList(); - final now = daylist[0]; + final now = mate!['card_weather']['day'] as Map; //天气 return _buildWeatherContent( context, @@ -677,7 +677,7 @@ class MessageBubble extends GetView { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '当前天气情况:', + '查询天气情况:', style: TextStyle( color: Colors.black87, fontSize: 14, @@ -714,7 +714,7 @@ class MessageBubble extends GetView { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - city, + "${city} ${now["date"]}", style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, @@ -846,46 +846,46 @@ class MessageBubble extends GetView { ], ), ), - const SizedBox(height: 10), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Expanded( - child: OutlinedButton.icon( - onPressed: () {}, - icon: Icon(Icons.location_on, size: 16), - label: Text('更多地区'), - style: OutlinedButton.styleFrom( - foregroundColor: Theme.of(context).primaryColor, - side: BorderSide( - color: Theme.of(context).primaryColor.withOpacity(0.5)), - padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - textStyle: TextStyle(fontSize: 12), - ), - ), - ), - SizedBox(width: 8), - Expanded( - child: OutlinedButton.icon( - onPressed: () {}, - icon: Icon(Icons.calendar_today, size: 16), - label: Text('15天预报'), - style: OutlinedButton.styleFrom( - foregroundColor: Colors.grey[700], - side: BorderSide(color: Colors.grey[400]!), - padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - textStyle: TextStyle(fontSize: 12), - ), - ), - ), - ], - ), + // const SizedBox(height: 10), + // Row( + // mainAxisSize: MainAxisSize.min, + // children: [ + // Expanded( + // child: OutlinedButton.icon( + // onPressed: () {}, + // icon: Icon(Icons.location_on, size: 16), + // label: Text('更多地区'), + // style: OutlinedButton.styleFrom( + // foregroundColor: Theme.of(context).primaryColor, + // side: BorderSide( + // color: Theme.of(context).primaryColor.withOpacity(0.5)), + // padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(16), + // ), + // textStyle: TextStyle(fontSize: 12), + // ), + // ), + // ), + // SizedBox(width: 8), + // Expanded( + // child: OutlinedButton.icon( + // onPressed: () {}, + // icon: Icon(Icons.calendar_today, size: 16), + // label: Text('15天预报'), + // style: OutlinedButton.styleFrom( + // foregroundColor: Colors.grey[700], + // side: BorderSide(color: Colors.grey[400]!), + // padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(16), + // ), + // textStyle: TextStyle(fontSize: 12), + // ), + // ), + // ), + // ], + // ), ], ); } From 372a5e60dd32a9d4f9eabe0c3a37caf064197750 Mon Sep 17 00:00:00 2001 From: fdp <1286779656@qq.com> Date: Mon, 12 May 2025 18:12:10 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BF=BB=E8=AF=91?= =?UTF-8?q?=E6=94=B6=E5=A4=96=E9=83=A8=E9=9F=B3=E6=BA=90=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/ota_upgrade_controller.dart | 8 +-- .../yunqiinnovation/agent_service/BleAgent.kt | 2 +- .../azure_speech/android/build.gradle.kts | 1 + .../azure_speech/AzureSpeechPlugin.kt | 58 ++++++++++++++++++- .../ble_service/android/build.gradle.kts | 1 - .../yunqiinnovation/ble_service/BleService.kt | 8 +-- .../ble_service/BleServicePlugin.kt | 4 ++ 7 files changed, 68 insertions(+), 14 deletions(-) diff --git a/lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart b/lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart index a59a16289..1e59b45c3 100644 --- a/lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart +++ b/lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart @@ -73,10 +73,8 @@ class OtaUpgradeController extends GetxController { } // 检查固件信息有效性 - if (deviceInfo.firmwareVersion.isEmpty - //|| - // deviceInfo.firmwareProductId.isEmpty - ) { + if (deviceInfo.firmwareVersion.isEmpty || + deviceInfo.firmwareProductId.isEmpty) { throw const FormatException('设备固件信息不完整'); } @@ -85,7 +83,7 @@ class OtaUpgradeController extends GetxController { // API请求 final response = await Api.getequipmentinfo({ - "id": "a2", + "id": deviceInfo.firmwareProductId, }); // 处理API响应 diff --git a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleAgent.kt b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleAgent.kt index f362b478d..00e0cdd7e 100644 --- a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleAgent.kt +++ b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleAgent.kt @@ -128,7 +128,7 @@ object BleAgent : BleService.Callback, AgentServiceListener { } override fun onAudioDataReceived(data: ByteArray) { - // FileLogger.d(TAG, "onAudioDataReceived, data: ${data.size}") + FileLogger.d(TAG, "onAudioDataReceived, data: ${data.size}") AgentService.pushAudioData(data) // 可选:处理音频数据 } diff --git a/local_plugins/azure_speech/android/build.gradle.kts b/local_plugins/azure_speech/android/build.gradle.kts index 342b48535..151988920 100644 --- a/local_plugins/azure_speech/android/build.gradle.kts +++ b/local_plugins/azure_speech/android/build.gradle.kts @@ -53,4 +53,5 @@ tasks.withType { dependencies { // 添加Microsoft语音SDK implementation("com.microsoft.cognitiveservices.speech:client-sdk:1.30.0") + implementation(project(":ble_service")) } \ No newline at end of file diff --git a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt index f149fa2be..327d194d4 100644 --- a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt +++ b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt @@ -14,9 +14,10 @@ import io.flutter.plugin.common.EventChannel import kotlinx.coroutines.* import kotlin.coroutines.CoroutineContext import com.microsoft.cognitiveservices.speech.audio.* - +import com.yunqiinnovation.ble_service.BleService +import com.yunqiinnovation.ble_service.BleConst /** AzureSpeechPlugin */ -class AzureSpeechPlugin: FlutterPlugin, CoroutineScope { +class AzureSpeechPlugin: FlutterPlugin,BleService.Callback, CoroutineScope { private val tag = "AzureSpeechPlugin" private lateinit var context: Context private val mainHandler = Handler(Looper.getMainLooper()) @@ -37,7 +38,10 @@ class AzureSpeechPlugin: FlutterPlugin, CoroutineScope { private lateinit var ttsEventChannel: EventChannel private var ttsEventSink: EventChannel.EventSink? = null private lateinit var azureTtsHelper: AzureTtsHelper + // 是否已注册BLE回调 + private var isRegisteredToBle = false + // ASR 事件发送方法 private fun sendAsrEvent(event: Map) { if (asrEventSink == null) { @@ -110,6 +114,19 @@ class AzureSpeechPlugin: FlutterPlugin, CoroutineScope { // 初始化Azure语音服务 azureTtsHelper = AzureTtsHelper(context) azureAsrHelper = AzureAsrHelper(context) + + // 2. 初始化BleService并注册回调 + if (BleService.initialize(context)) { + if (BleService.addCallback(this)) { + isRegisteredToBle = true + FileLogger.d(tag, "已注册BLE回调") + } else { + FileLogger.w(tag, "BLE回调注册失败") + } + } else { + FileLogger.e(tag, "BLE服务初始化失败") + + } } // ASR方法处理器 @@ -359,7 +376,12 @@ class AzureSpeechPlugin: FlutterPlugin, CoroutineScope { try { // 取消所有协程 job.cancel() - + // 取消BLE回调注册 + if (isRegisteredToBle) { + BleService.removeCallback(this) + isRegisteredToBle = false + } + // 释放资源 azureTtsHelper.dispose() azureAsrHelper.dispose() @@ -367,4 +389,34 @@ class AzureSpeechPlugin: FlutterPlugin, CoroutineScope { FileLogger.e(tag, "释放资源失败: ${e.message}") } } + + + override fun onScanResult(devices: List>) { + + } + + override fun onConnectionStateChanged(state: Int) { + // 可选:处理连接状态变化 + if (state == BleConst.STATE_CONNECTED) { + FileLogger.d(tag, "Ble设备已连接,准备好语音交互") + } else if (state == BleConst.STATE_DISCONNECTED) { + FileLogger.d(tag, "Ble设备已断开,停止语音服务") + // 设备断开连接,停止语音服务 + // stopListening() + } + + } + + override fun onAudioDataReceived(data: ByteArray) { + FileLogger.d(tag, "AzureSpeechPlugin onAudioDataReceived, data: ${data.size}") + azureAsrHelper.pushAudioData(data) + } + + override fun onWakeupSignalReceived() { + + } + + override fun onDeviceInfoReceived(infoType: Int, infoData: Map) { + + } } \ No newline at end of file diff --git a/local_plugins/ble_service/android/build.gradle.kts b/local_plugins/ble_service/android/build.gradle.kts index 72a6745e6..29deed814 100644 --- a/local_plugins/ble_service/android/build.gradle.kts +++ b/local_plugins/ble_service/android/build.gradle.kts @@ -31,5 +31,4 @@ dependencies { // 使用从本地Maven仓库引用的AAR依赖 implementation("com.jieli.audio:jl_audio_decode:2.0.0") implementation(project(":deepvoice_utils")) - implementation(project(":azure_speech")) } \ No newline at end of file diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt index dd6d24917..39261ee63 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt @@ -661,10 +661,10 @@ object BleService { "rawData" to responseData ) - if (responseData.isNotEmpty() && responseData.size >= 2) { - val productId = "0x${(responseData[0].toInt() and 0xFF).toString(16)}${ - (responseData[1].toInt() and 0xFF).toString(16) - }" + if (responseData.isNotEmpty()) { + // 转换为字符串前,确认是否是有效的ASCII字符 + val productId = + responseData.joinToString(".") { (it.toInt() and 0xFF).toString() } resultMap["productId"] = productId FileLogger.i(TAG, "接收到产品ID: $productId") } diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt index e8ba005df..960852353 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt @@ -185,6 +185,10 @@ class BleServicePlugin : FlutterPlugin, MethodCallHandler, ActivityAware, "getDeviceVersion" -> { val success = BleService.getDeviceVersion() result.success(success) + } + "getProductId" -> { + val success = BleService.getProductId() + result.success(success) } "getBatteryInfo" -> { val success = BleService.getBatteryInfo() From 132727785fd49bec143aec14d99e23f68b4c236d Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Mon, 12 May 2025 21:15:28 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat(ota=5Fupgrade=5Fview):=20OTA=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E9=A1=B5=E9=9D=A2=E6=B7=BB=E5=8A=A0=E6=9A=97=E9=BB=91?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E6=94=AF=E6=8C=81=E5=B9=B6=E4=BC=98=E5=8C=96?= =?UTF-8?q?UI=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ota_upgrade/views/ota_upgrade_view.dart | 377 +++++++++++++----- 1 file changed, 287 insertions(+), 90 deletions(-) diff --git a/lib/modules/ota_upgrade/views/ota_upgrade_view.dart b/lib/modules/ota_upgrade/views/ota_upgrade_view.dart index a33120845..b524ec1c6 100644 --- a/lib/modules/ota_upgrade/views/ota_upgrade_view.dart +++ b/lib/modules/ota_upgrade/views/ota_upgrade_view.dart @@ -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 { 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])), + ], + ) + ], + ), ); }