import 'dart:ui'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:haptic_feedback/haptic_feedback.dart'; import '../controllers/translation_controller.dart'; import '../models/translation_models.dart'; import '../views/translation_history_view.dart'; import '../bindings/translation_history_binding.dart'; import '../../../core/theme/app_colors.dart'; import '../../../routes/app_routes.dart'; import '../../common/widgets/language_selector_bar.dart'; // 导入拆分后的组件 import 'widgets/face_to_face_layout.dart'; // 面对面翻译布局 import 'widgets/draggable_floating_button.dart'; // 可拖拽的悬浮按钮 import 'widgets/translation_item_widget.dart'; // 翻译项组件 import 'dialogs/language_selection_dialog.dart'; // 语言选择对话框 import 'dialogs/translation_mode_selector.dart'; // 翻译模式选择器 import 'dialogs/translation_long_press_menu.dart'; // 长按菜单 // import 'package:intl/intl.dart'; //主页面 class TranslationView extends GetView { const TranslationView({Key? key}) : super(key: key); // 本地交互状态:当前显示操作按钮的消息时间戳(不改动控制器) static final Rx _activeActionTimestamp = Rx(null); // 切换当前操作按钮展示的项(再次点击同一项则隐藏) void _toggleActiveActionItem(TranslationItem item) { final DateTime ts = item.timestamp; final DateTime? current = _activeActionTimestamp.value; _activeActionTimestamp.value = (current != null && current.isAtSameMomentAs(ts)) ? null : ts; } @override Widget build(BuildContext context) { final isDarkMode = Theme.of(context).brightness == Brightness.dark; return Obx(() { // 面对面翻译模式使用特殊布局 if (controller.currentMode.value == 'faceToFace') { return _buildFaceToFaceScaffold(isDarkMode); } // 其他模式使用原有布局 return Scaffold( backgroundColor: isDarkMode ? AppColors.darkBackground : Colors.grey[50], appBar: _buildAppBar(isDarkMode), body: SafeArea( top: false, child: Stack( children: [ _buildBody(isDarkMode), // 可拖拽的悬浮按钮 // DraggableFloatingButton( // isDarkMode: isDarkMode, // controller: controller, // ), ], ), ), ); }); } // 构建面对面翻译模式的专用Scaffold Widget _buildFaceToFaceScaffold(bool isDarkMode) { return Scaffold( backgroundColor: isDarkMode ? AppColors.darkBackground : Colors.grey[50], body: SafeArea( top: false, child: Stack( children: [ // 主要内容区域 FaceToFaceLayout( isDarkMode: isDarkMode, controller: controller, ), Positioned( top: 2, left: 0, right: 0, child: SafeArea( top: true, child: Container( height: 56.h, padding: EdgeInsets.symmetric(horizontal: 8.w), color: Colors.transparent, child: Align( alignment: Alignment.centerLeft, child: IconButton( icon: Icon( Icons.arrow_back_ios, color: isDarkMode ? Colors.white : Colors.black, size: 20.sp, ), onPressed: () => Get.back(), ), ), ), ), ), // 顶部按钮(倒过来) Positioned( top: 50.h, left: 0, right: 0, child: Transform.rotate( angle: 3.14159, // 180度旋转 child: _buildFaceToFaceTopButton(isDarkMode), ), ), // 底部按钮 Positioned( bottom: 40.h, left: 0, right: 0, child: _buildFaceToFaceBottomButton(isDarkMode), ), // 可拖拽的悬浮按钮 - 在所有模式下都显示 // DraggableFloatingButton( // isDarkMode: isDarkMode, // controller: controller, // ), ], ), ), ); } // 构建面对面翻译顶部按钮(原右边按钮,现在移到顶部并旋转) Widget _buildFaceToFaceTopButton(bool isDarkMode) { return Center( child: Transform.rotate( angle: 0, // 180度旋转 child: _buildHoldToTalkButton( isDarkMode: isDarkMode, speakerId: 2, // 说话者2(原右边按钮) activeSpeaker: controller.activeSpeaker.value, icon: Icons.mic_none, label: controller.targetLanguage.value.split(' ')[0].tr, // 目标语言名称 ), ), ); } // 构建面对面翻译底部按钮(原左边按钮,保留在底部) Widget _buildFaceToFaceBottomButton(bool isDarkMode) { return Center( child: _buildHoldToTalkButton( isDarkMode: isDarkMode, speakerId: 1, // 说话者1(原左边按钮) activeSpeaker: controller.activeSpeaker.value, icon: Icons.mic_none, label: controller.sourceLanguage.value.split(' ')[0].tr, // 源语言名称 ), ); } PreferredSizeWidget _buildAppBar(bool isDarkMode) { return AppBar( backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white, elevation: 1, leading: IconButton( icon: Icon( Icons.arrow_back_ios, color: isDarkMode ? Colors.white : Colors.black, size: 20.sp, ), onPressed: () { // 点击返回时,停止所有语音识别和TTS controller.stopAll(); Get.back(); }, ), title: Obx(() => GestureDetector( onTap: () { TranslationModeSelector.show(isDarkMode); }, child: Text( controller.currentModeTitle.value.tr, style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.w600, color: isDarkMode ? Colors.white : Colors.black, ), overflow: TextOverflow.ellipsis, maxLines: 1, ), )), centerTitle: true, actions: [ Obx(() { if (controller.isRecording.value) { // 录音中:显示红色计时器样式,点击可停止录音 return Padding( padding: EdgeInsets.only(right: 16.w), child: GestureDetector( onTap: controller.toggleisRecord, // 点击结束录音 child: Container( padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h), decoration: BoxDecoration( color: Colors.red, borderRadius: BorderRadius.circular(20.r), ), child: Row( children: [ Icon( Icons.fiber_manual_record, color: Colors.white, size: 18.sp, ), SizedBox(width: 4.w), Text( controller.recordDurationText.value, style: TextStyle( color: Colors.white, fontSize: 14.sp, fontWeight: FontWeight.bold, ), ), ], ), ), ), ); } else { // 未录音:显示红色录音按钮 + 文件夹按钮 + 悬浮窗按钮 return Row( children: [ // 悬浮窗切换按钮(仅在支持的模式下显示) Obx(() { if (controller.currentMode.value == 'call' || controller.currentMode.value == 'audioVideo') { return IconButton( icon: Icon( controller.isFloatingWindowEnabled.value ? Icons.picture_in_picture : Icons.picture_in_picture_alt_outlined, color: controller.isFloatingWindowEnabled.value ? Colors.blue : (isDarkMode ? Colors.white : Colors.black), size: 24.sp, ), onPressed: controller.toggleFloatingWindow, tooltip: controller.isFloatingWindowEnabled.value ? '禁用悬浮窗' : '启用悬浮窗', ); } return const SizedBox.shrink(); }), IconButton( icon: Icon( Icons.radio_button_checked, color: Colors.red, size: 24.sp, ), onPressed: controller.toggleisRecord, tooltip: 'enableRecording'.tr, // 是否开启录音 ), IconButton( icon: Icon( Icons.folder, color: isDarkMode ? Colors.white : Colors.black, size: 24.sp, ), onPressed: () async { await controller.stopAll(); Get.toNamed(Routes.translationList); controller.setupScrollListener(); }, tooltip: 'viewAudioFiles'.tr, // 查看录音文件 ), // 历史记录按钮 // IconButton( // icon: Icon( // Icons.history, // color: isDarkMode ? Colors.white : Colors.black, // size: 24.sp, // ), // onPressed: () async { // await controller.stopAll(); // Get.toNamed(Routes.translationHistory); // }, // tooltip: 'translationHistory'.tr, // 翻译历史 // ), ], ); } }), ], bottom: PreferredSize( preferredSize: Size.fromHeight( controller.currentMode.value == 'call' ? 70.h : 50.h, ), child: Padding( padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), child: Column( mainAxisSize: MainAxisSize.min, children: [ // 统一通用语言选择栏组件 LanguageSelectorBar( sourceText: () => controller.sourceLanguage.value.split(' ')[0], targetText: () => controller.targetLanguage.value.split(' ')[0], onTapSource: () => LanguageSelectionDialog.show(true, isDarkMode), onTapTarget: () => LanguageSelectionDialog.show(false, isDarkMode), onSwap: controller.swapLanguages, translateLanguageNames: true, // 是否翻译语言名称 fontSizeSp: 15, targetSuffix: controller.currentMode.value == 'call' ? Icon( Icons.phone_in_talk, size: 20.sp, color: isDarkMode ? Colors.white70 : Colors.grey[600], ) : null, ), // 通话模式下的“对方 / 我”标签行 if (controller.currentMode.value == 'call') ...[ SizedBox(height: 6.h), Row( children: [ Expanded( child: Text( 'me'.tr, //我 style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.black54, fontWeight: FontWeight.w500, ), textAlign: TextAlign.center, ), ), // 预留与上方互换按钮大致等宽的间距,保证对齐 SizedBox(width: 44.w), Expanded( child: Text( 'counterPart'.tr, //对方 style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.black54, fontWeight: FontWeight.w500, ), textAlign: TextAlign.center, ), ), ], ), ], ], ), ), ), ); } Widget _buildBody(bool isDarkMode) { return // GestureDetector( // onPanUpdate: (details) { // // 检测左滑手势 // if (details.delta.dx < -10) { // // 左滑距离超过10像素时触发 // _handleSwipeLeft(); // } // }, // child: Column( children: [ Expanded( child: _buildTranslationContent(isDarkMode), ), _buildControlBar(isDarkMode), ], ); // ); } // 处理左滑手势 // void _handleSwipeLeft() async { // await controller.stopAll(); // Get.toNamed(Routes.translationHistory); // } Widget _buildTranslationContent(bool isDarkMode) { return Obx(() { // 其他模式使用原有的列表布局 final itemCount = controller.translationHistory.length + (controller.hasMoreHistory.value ? 1 : 0); return ListView.builder( controller: controller.scrollController, reverse: true, // 🔑 关键优化:采用reverse模式,参考Agent模块 padding: EdgeInsets.only( left: 16.w, right: 16.w, top: 16.h, bottom: 16.h, ), itemCount: itemCount, itemBuilder: (context, index) { // 如果是最后一项且有更多历史记录,显示加载指示器(reverse模式下) if (index == controller.translationHistory.length && controller.hasMoreHistory.value) { return _buildLoadMoreIndicator(); } // reverse模式下需要反转索引来获取正确的历史记录 final historyIndex = controller.translationHistory.length - 1 - index; // 检查索引是否有效(reverse模式下的索引验证) if (historyIndex < 0 || historyIndex >= controller.translationHistory.length) { return const SizedBox.shrink(); } // 获取当前项 final historyItem = controller.translationHistory[historyIndex]; // 构建项目widget return TranslationItemWidget( item: historyItem, activeActionTimestamp: _activeActionTimestamp, onToggleActionItem: _toggleActiveActionItem, onLongPressStart: _onLongPressTranslationItem, onDeleteItemConfirm: _showDeleteItemConfirmDialog, ); }, ); }); } Widget _buildControlBar(bool isDarkMode) { // 使用GlobalKey来获取控制栏的高度 final controlBarKey = GlobalKey(); // 在构建完成后获取控制栏的高度并设置到控制器中 WidgetsBinding.instance.addPostFrameCallback((_) { if (controlBarKey.currentContext != null) { final RenderBox renderBox = controlBarKey.currentContext!.findRenderObject() as RenderBox; final height = renderBox.size.height; controller.setBottomBarHeight(height); } }); return Container( key: controlBarKey, padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h), decoration: BoxDecoration( color: isDarkMode ? AppColors.cardBackground : Colors.white, boxShadow: [ BoxShadow( color: Colors.black.withAlpha(isDarkMode ? 30 : 13), blurRadius: 4, offset: const Offset(0, -2), ), ], ), child: Column( mainAxisSize: MainAxisSize.min, children: [ // 原有的按钮区域 Row( mainAxisAlignment: MainAxisAlignment.center, children: [ // 主要控制按钮 - 开始/暂停语音识别 Obx(() { final isRecognizing = controller.isRecognizing.value; final isPreparing = controller.isPreparing.value; return GestureDetector( onTap: () { if (isRecognizing) { controller.stopAll(); } else { controller.startRecognition(); } }, child: AnimatedContainer( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, width: 60.w, height: 60.w, transform: isPreparing ? (Matrix4.identity()..scale(1.08)) : Matrix4.identity(), decoration: BoxDecoration( color: isRecognizing ? (isDarkMode ? Colors.red[700] : Colors.red) : (isDarkMode ? AppColors.primary : Colors.blue), shape: BoxShape.circle, boxShadow: isPreparing ? [ BoxShadow( color: (isDarkMode ? AppColors.primary : Colors.blue) .withOpacity(0.5), blurRadius: 12, spreadRadius: 2, ) ] : [], ), child: Icon( isRecognizing ? Icons.pause : Icons.play_arrow, color: Colors.white, size: 30.sp, ), ), ); }), ], ), // 添加间距 //SizedBox(height: 16.h), // 语音识别结果显示框 // Container( // width: double.infinity, // padding: EdgeInsets.all(12.w), // decoration: BoxDecoration( // color: isDarkMode ? Colors.grey[800] : Colors.grey[100], // borderRadius: BorderRadius.circular(8.r), // border: Border.all( // color: isDarkMode ? Colors.grey[600]! : Colors.grey[300]!, // width: 1, // ), // ), // child: Obx(() { // // 显示最新的语音识别结果 // final recognitionText = controller.latestRecognitionText.value; // final detectedLanguage = controller.detectedLanguageCode1.value; // return Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // // 标题 // Text( // '麦头语音识别结果', // style: TextStyle( // fontSize: 12.sp, // color: isDarkMode ? Colors.grey[400] : Colors.grey[600], // fontWeight: FontWeight.w500, // ), // ), // SizedBox(height: 4.h), // // 识别文本 - 这里显示 finalResult1 的内容 // Text( // recognitionText.isEmpty ? '等待语音输入...' : recognitionText, // style: TextStyle( // fontSize: 14.sp, // color: isDarkMode ? Colors.white : Colors.black87, // height: 1.3, // ), // ), // // 检测到的语言(如果有) // if (detectedLanguage.isNotEmpty) ...[ // SizedBox(height: 4.h), // Text( // '检测语言: $detectedLanguage', // style: TextStyle( // fontSize: 10.sp, // color: // isDarkMode ? Colors.grey[500] : Colors.grey[500], // ), // ), // ], // ], // ); // }), // ), ], ), ); } // 按住说话按钮组件 Widget _buildHoldToTalkButton({ required bool isDarkMode, required int speakerId, required int activeSpeaker, required IconData icon, required String label, }) { bool isActive = activeSpeaker == speakerId; bool isDisabled = activeSpeaker != 0 && activeSpeaker != speakerId; return Listener( onPointerDown: (_) async { // 检查权限 if (!controller.hasRecordPermission.value) { Get.snackbar('权限提示', '需要麦克风权限才能使用录音功能'); return; } // 只有在没有其他按钮激活时才能激活当前按钮 if (activeSpeaker == 0) { await controller.setActiveSpeaker(speakerId); } }, onPointerUp: (_) async { // 松开按钮时,如果当前按钮是激活状态,则停止 if (isActive) { await controller.setActiveSpeaker(0); } }, child: AnimatedContainer( duration: const Duration(milliseconds: 200), width: 160.w, // 长条形宽度 height: 54.h, // 长条形高度 decoration: BoxDecoration( color: isActive ? (isDarkMode ? Colors.green[700] : Colors.green) : (isDisabled ? (isDarkMode ? Colors.grey[800] : Colors.grey[300]) : (isDarkMode ? AppColors.primary : Colors.blue)), borderRadius: BorderRadius.circular(25.r), // 圆角长条形 boxShadow: isActive ? [ BoxShadow( color: Colors.green.withOpacity(0.5), blurRadius: 10, spreadRadius: 3, ) ] : [ BoxShadow( color: (isDarkMode ? Colors.black : Colors.grey) .withOpacity(0.2), blurRadius: 8, spreadRadius: 1, offset: Offset(0, 2), ) ], ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ // 左边图标 Icon( icon, color: isActive ? Colors.white : Colors.white.withOpacity(isDisabled ? 0.3 : 0.9), size: 20.sp, ), SizedBox(width: 8.w), // 图标和文字间距 // 右边语言名称 Flexible( child: Text( label, style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w500, color: isActive ? Colors.white : Colors.white.withOpacity(isDisabled ? 0.3 : 0.9), ), textAlign: TextAlign.center, maxLines: 1, overflow: TextOverflow.ellipsis, // 防止文本溢出 ), ), ], ), ), ); } // 构建加载更多指示器 Widget _buildLoadMoreIndicator() { return Obx(() { if (controller.isLoadingMore.value) { // 正在加载状态 - 增强视觉效果 return Container( padding: const EdgeInsets.symmetric(vertical: 20), child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox( width: 24.w, height: 24.h, child: CircularProgressIndicator( strokeWidth: 2.5.w, valueColor: const AlwaysStoppedAnimation( AppColors.primary, ), ), ), const SizedBox(height: 12), Text( 'loading'.tr, //加载中 style: TextStyle( fontSize: 14.sp, color: Colors.grey[600], fontWeight: FontWeight.w500, ), ), ], ), ), ); } else if (controller.isLoadingMoreError.value) { // 加载失败状态 - 增强视觉效果 return Container( padding: const EdgeInsets.symmetric(vertical: 18), child: Center( child: GestureDetector( onTap: () => controller.loadMoreHistory(), child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: Colors.red[50], borderRadius: BorderRadius.circular(20), border: Border.all(color: Colors.red[200]!, width: 1), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.refresh, size: 18.sp, color: Colors.red[600], ), SizedBox(width: 8.w), Text( 'loadFailedClickRetry'.tr, style: TextStyle( fontSize: 14.sp, color: Colors.red[600], fontWeight: FontWeight.w500, ), ), ], ), ), ), ), ); } else { // 默认状态(有更多记录但未加载)- 增强视觉效果 return Container( padding: const EdgeInsets.symmetric(vertical: 12), child: Center( child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(16), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.keyboard_arrow_up, size: 16.sp, color: Colors.grey[500], ), SizedBox(width: 4.w), Text( 'swipeUpForMore'.tr, style: TextStyle( fontSize: 12.sp, color: Colors.grey[600], ), ), ], ), ), ), ); } }); } /// 处理翻译条目长按事件 void _onLongPressTranslationItem( BuildContext context, bool isDarkMode, LongPressStartDetails details, TranslationItem item, ) { TranslationLongPressMenu.show( context: context, isDarkMode: isDarkMode, details: details, item: item, onCopy: (item) => TranslationLongPressMenu.copyTranslationItem(item), onDeleteItem: (item) => _deleteTranslationItem(item), onClearHistory: _showClearHistoryConfirmDialog, ); } // 显示删除单条记录确认对话框 void _showDeleteItemConfirmDialog(TranslationItem item) { final isDarkMode = Theme.of(Get.context!).brightness == Brightness.dark; Get.dialog( AlertDialog( backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white, title: Text( 'deleteTranslationRecord'.tr, // 删除翻译记录 style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.bold, color: isDarkMode ? Colors.white : Colors.black, ), ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'deleteTranslationConfirm'.tr, // 确定要删除这条翻译记录吗?此操作无法撤销。 style: TextStyle( fontSize: 16.sp, color: isDarkMode ? Colors.grey[300] : Colors.black87, ), ), SizedBox(height: 12.h), // 显示要删除的记录预览 Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( color: isDarkMode ? Colors.grey[800]?.withOpacity(0.5) : Colors.grey[100], borderRadius: BorderRadius.circular(8.r), border: Border.all( color: isDarkMode ? Colors.grey[700]! : Colors.grey[300]!, width: 1, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.sourceText, style: TextStyle( fontSize: 14.sp, color: isDarkMode ? Colors.white : Colors.black, fontWeight: FontWeight.w500, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), if (item.translatedText.isNotEmpty) ...[ SizedBox(height: 4.h), Text( item.translatedText, style: TextStyle( fontSize: 14.sp, color: isDarkMode ? Colors.grey[300] : Colors.grey[700], ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ], ), ), ], ), actions: [ TextButton( onPressed: () => Get.back(), child: Text( 'cancel'.tr, style: TextStyle( fontSize: 16.sp, color: isDarkMode ? Colors.grey[400] : Colors.grey[700], ), ), ), TextButton( onPressed: () { Get.back(); // 删除指定的翻译记录 _deleteTranslationItem(item); }, child: Text( 'confirm'.tr, style: TextStyle( fontSize: 16.sp, color: Colors.red, fontWeight: FontWeight.bold, ), ), ), ], shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.r), ), ), ); } // 删除翻译记录的具体实现 void _deleteTranslationItem(TranslationItem item) { try { // 调用控制器的删除方法 controller.deleteTranslationItem(item.sessionId, item.timestamp); // 显示删除成功提示 // Get.snackbar( // 'success'.tr, // deleteSuccess // '已删除该翻译记录', // deleteTranslationSuccess // snackPosition: SnackPosition.BOTTOM, // backgroundColor: Get.isDarkMode ? Colors.grey[800] : Colors.grey[200], // colorText: Get.isDarkMode ? Colors.white : Colors.black, // duration: const Duration(milliseconds: 800), // ); } catch (e) { // 显示删除失败提示 Get.snackbar( 'error'.tr, // deleteFailed '删除翻译记录时发生错误: ${e.toString()}', // deleteTranslationError snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.red[400], colorText: Colors.white, duration: const Duration(milliseconds: 1500), ); } } // 显示删除所有记录确认对话框 void _showClearHistoryConfirmDialog() { final isDarkMode = Get.isDarkMode; Get.dialog( AlertDialog( backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white, title: Text( 'clearHistory'.tr, style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.bold, color: isDarkMode ? Colors.white : Colors.black, ), ), content: Text( 'clearHistoryConfirm'.tr, style: TextStyle( fontSize: 16.sp, color: isDarkMode ? Colors.grey[300] : Colors.black87, ), ), actions: [ TextButton( onPressed: () => Get.back(), child: Text( 'cancel'.tr, style: TextStyle( fontSize: 16.sp, color: isDarkMode ? Colors.grey[400] : Colors.grey[700], ), ), ), TextButton( onPressed: () { // 清除历史记录 controller.clearTranslationHistory(); Get.back(); }, child: Text( 'confirm'.tr, style: TextStyle( fontSize: 16.sp, color: Colors.red, fontWeight: FontWeight.bold, ), ), ), ], shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.r), ), ), ); } // 构建语言选择栏 Widget _buildLanguageSelectionBar(bool isDarkMode) { return Container( height: 44.h, padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 6.h), decoration: BoxDecoration( color: isDarkMode ? AppColors.cardBackground : Colors.white, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 4, offset: const Offset(0, 2), ), BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 4, offset: const Offset(0, -2), ), ], ), child: LanguageSelectorBar( sourceText: () => controller.sourceLanguage.value.split(' ')[0], targetText: () => controller.targetLanguage.value.split(' ')[0], onTapSource: () => LanguageSelectionDialog.show(true, isDarkMode), onTapTarget: () => LanguageSelectionDialog.show(false, isDarkMode), onSwap: controller.swapLanguages, translateLanguageNames: true, // 是否翻译语言名称 fontSizeSp: 15, ), ); } }