20 changed files with 1155 additions and 322 deletions
@ -1,10 +1,10 @@ |
|||||
import 'package:get/get.dart'; |
import 'package:get/get.dart'; |
||||
import '../controllers/translation_controller.dart'; |
import '../controllers/translation_controller.dart'; |
||||
|
|
||||
|
//主翻译页面依赖绑定 |
||||
class TranslationBinding implements Bindings { |
class TranslationBinding implements Bindings { |
||||
@override |
@override |
||||
void dependencies() { |
void dependencies() { |
||||
Get.put(TranslationController()); |
Get.put(TranslationController()); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,9 +1,11 @@ |
|||||
import 'package:get/get.dart'; |
import 'package:get/get.dart'; |
||||
import '../controllers/translation_detail_controller.dart'; |
import '../controllers/translation_detail_controller.dart'; |
||||
|
|
||||
|
//翻译详情页面依赖绑定 |
||||
class TranslationDetailBinding extends Bindings { |
class TranslationDetailBinding extends Bindings { |
||||
@override |
@override |
||||
void dependencies() { |
void dependencies() { |
||||
Get.lazyPut<TranslationDetailController>(() => TranslationDetailController()); |
Get.lazyPut<TranslationDetailController>( |
||||
|
() => TranslationDetailController()); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,161 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import '../../controllers/translation_controller.dart'; |
||||
|
|
||||
|
/// 语言选择对话框 |
||||
|
class LanguageSelectionDialog { |
||||
|
/// 显示语言选择对话框 |
||||
|
static void show(bool isSource, bool isDarkMode) { |
||||
|
final controller = Get.find<TranslationController>(); |
||||
|
|
||||
|
Get.dialog(Dialog( |
||||
|
backgroundColor: isDarkMode ? Colors.grey[900] : Colors.white, |
||||
|
shape: RoundedRectangleBorder( |
||||
|
borderRadius: BorderRadius.circular(16.r), // 统一圆角尺寸为16 |
||||
|
), |
||||
|
alignment: isSource ? Alignment.centerLeft : Alignment.centerRight, |
||||
|
insetPadding: EdgeInsets.symmetric(horizontal: 10.w), |
||||
|
child: SizedBox( |
||||
|
width: 0.4.sw, |
||||
|
child: Padding( |
||||
|
// 使用Padding替代Container的padding |
||||
|
padding: EdgeInsets.all(12.w), // 统一内边距 |
||||
|
child: Column( |
||||
|
mainAxisSize: MainAxisSize.min, |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
// 标题区域 |
||||
|
Padding( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 8.w), |
||||
|
child: Text( |
||||
|
isSource |
||||
|
? 'selectSourceLanguage'.tr |
||||
|
: 'selectTargetLanguage'.tr, // 保留源语言/目标语言区分 |
||||
|
style: TextStyle( |
||||
|
fontSize: 18.sp, // 调整字号 |
||||
|
fontWeight: FontWeight.w600, // 使用数字字重 |
||||
|
color: isDarkMode ? Colors.white : Colors.black87, // 优化文本颜色 |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
SizedBox(height: 16.h), |
||||
|
|
||||
|
// 语言列表区域 |
||||
|
Container( |
||||
|
constraints: BoxConstraints(maxHeight: 0.5.sh), |
||||
|
child: SingleChildScrollView( |
||||
|
child: Column( |
||||
|
mainAxisSize: MainAxisSize.min, |
||||
|
children: |
||||
|
controller.supportedLanguages.keys.map((language) { |
||||
|
return Obx(() { |
||||
|
final currentLanguage = isSource |
||||
|
? controller.sourceLanguage.value |
||||
|
: controller.targetLanguage.value; |
||||
|
final isSelected = currentLanguage == language; |
||||
|
|
||||
|
return GestureDetector( |
||||
|
// 改用手势检测器实现点击 |
||||
|
onTap: () { |
||||
|
if (isSource) { |
||||
|
controller.setSourceLanguage(language); |
||||
|
} else { |
||||
|
controller.setTargetLanguage(language); |
||||
|
} |
||||
|
Get.back(); |
||||
|
}, |
||||
|
child: Container( |
||||
|
margin: EdgeInsets.only(bottom: 10.h), // 添加项间距 |
||||
|
padding: EdgeInsets.all(10.w), // 统一内边距 |
||||
|
decoration: BoxDecoration( |
||||
|
color: isSelected // 选中状态背景色 |
||||
|
? (isDarkMode |
||||
|
? const Color(0xFF6200EE).withOpacity(0.2) |
||||
|
: Colors.blue.withOpacity(0.1)) |
||||
|
: (isDarkMode // 未选中状态背景色 |
||||
|
? Colors.white.withOpacity(0.05) |
||||
|
: Colors.grey[200]!), |
||||
|
borderRadius: BorderRadius.circular(12.r), // 项圆角 |
||||
|
border: Border.all( |
||||
|
// 选中状态边框 |
||||
|
color: isSelected |
||||
|
? (isDarkMode |
||||
|
? const Color(0xFF6200EE) |
||||
|
: Colors.blue) |
||||
|
: (isDarkMode // 未选中状态背景色 |
||||
|
? Colors.white.withOpacity(0.05) |
||||
|
: Colors.grey[200]!), |
||||
|
width: 1, |
||||
|
), |
||||
|
), |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
// 语言名称 |
||||
|
Expanded( |
||||
|
child: Text( |
||||
|
language.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
color: isDarkMode |
||||
|
? Colors.white |
||||
|
: Colors.black87, |
||||
|
overflow: TextOverflow.ellipsis, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
// 选中指示器 |
||||
|
Container( |
||||
|
width: 24.w, |
||||
|
height: 24.w, |
||||
|
decoration: BoxDecoration( |
||||
|
color: isSelected // 动态颜色 |
||||
|
? (isDarkMode |
||||
|
? const Color(0xFF6200EE) |
||||
|
: Colors.blue) |
||||
|
: (isDarkMode |
||||
|
? Colors.white.withOpacity(0.1) |
||||
|
: Colors.grey[300]), |
||||
|
shape: BoxShape.circle, // 圆形样式 |
||||
|
), |
||||
|
child: isSelected |
||||
|
? Icon( |
||||
|
// 选中时显示对勾 |
||||
|
Icons.check, |
||||
|
size: 16.w, |
||||
|
color: Colors.white, |
||||
|
) |
||||
|
: null, |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
}); |
||||
|
}).toList(), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
SizedBox(height: 16.h), |
||||
|
|
||||
|
// 取消按钮 |
||||
|
Align( |
||||
|
alignment: Alignment.centerRight, |
||||
|
child: TextButton( |
||||
|
onPressed: () => Get.back(), |
||||
|
child: Text( |
||||
|
'cancel'.tr, |
||||
|
style: TextStyle( |
||||
|
color: isDarkMode ? const Color(0xFF6200EE) : Colors.blue, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,172 @@ |
|||||
|
import 'dart:ui'; |
||||
|
import 'dart:io'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import '../../controllers/translation_controller.dart'; |
||||
|
|
||||
|
/// 翻译模式选择对话框 |
||||
|
class TranslationModeSelector { |
||||
|
/// 显示翻译模式选择器 |
||||
|
static void show(bool isDarkMode) { |
||||
|
final controller = Get.find<TranslationController>(); |
||||
|
|
||||
|
Get.bottomSheet( |
||||
|
BackdropFilter( |
||||
|
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0), |
||||
|
child: _buildTranslationModeSelector(controller), |
||||
|
), |
||||
|
isScrollControlled: true, |
||||
|
backgroundColor: Colors.transparent, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
// 构建翻译模式选择器 - 参考会议模块样式 |
||||
|
static Widget _buildTranslationModeSelector(TranslationController controller) { |
||||
|
return Builder( |
||||
|
builder: (BuildContext context) { |
||||
|
return SafeArea( |
||||
|
child: Column( |
||||
|
mainAxisSize: MainAxisSize.min, |
||||
|
children: [ |
||||
|
_buildModeItem( |
||||
|
context, |
||||
|
'simultaneousTranslation'.tr, |
||||
|
Icons.translate, |
||||
|
Colors.blue, |
||||
|
controller, |
||||
|
onTap: () async { |
||||
|
Get.back(); |
||||
|
await controller.stopAll(); |
||||
|
await controller.changeTranslationMode('simultaneous'); |
||||
|
await controller.startRecognition(); |
||||
|
}, |
||||
|
), |
||||
|
_buildModeItem( |
||||
|
context, |
||||
|
'faceToFaceTranslation'.tr, |
||||
|
Icons.people, |
||||
|
Colors.green, |
||||
|
controller, |
||||
|
onTap: () async { |
||||
|
Get.back(); |
||||
|
await controller.stopAll(); |
||||
|
await controller.changeTranslationMode('faceToFace'); |
||||
|
await controller.startRecognition(); |
||||
|
}, |
||||
|
), |
||||
|
_buildModeItem( |
||||
|
context, |
||||
|
'audioVideoTranslation'.tr, |
||||
|
Icons.videocam, |
||||
|
Colors.orange, |
||||
|
controller, |
||||
|
onTap: controller.bleManager.isConnected |
||||
|
? () async { |
||||
|
Get.back(); |
||||
|
await controller.stopAll(); |
||||
|
await controller.changeTranslationMode('audioVideo'); |
||||
|
await controller.startRecognition(); |
||||
|
} |
||||
|
: null, |
||||
|
), |
||||
|
_buildModeItem( |
||||
|
context, |
||||
|
'callTranslation'.tr, |
||||
|
Icons.phone, |
||||
|
Colors.purple, |
||||
|
controller, |
||||
|
onTap: controller.bleManager.isConnected |
||||
|
? () async { |
||||
|
Get.back(); |
||||
|
await controller.stopAll(); |
||||
|
await controller.changeTranslationMode('call'); |
||||
|
await controller.startRecognition(); |
||||
|
} |
||||
|
: null, |
||||
|
), |
||||
|
SizedBox(height: 24.w), |
||||
|
GestureDetector( |
||||
|
onTap: () => Get.back(), |
||||
|
child: Container( |
||||
|
width: 42, |
||||
|
height: 42, |
||||
|
decoration: BoxDecoration( |
||||
|
color: Colors.black.withValues(alpha: 0.8), |
||||
|
borderRadius: BorderRadius.circular(50), |
||||
|
), |
||||
|
child: const Icon(Icons.close, color: Colors.white), |
||||
|
), |
||||
|
), |
||||
|
if (Platform.isAndroid) SizedBox(height: 20.h), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
// 构建单个模式选项 - 完全参考会议模块的 _buildItem 方法 |
||||
|
static Widget _buildModeItem( |
||||
|
BuildContext context, |
||||
|
String title, |
||||
|
IconData icon, |
||||
|
Color color, |
||||
|
TranslationController controller, { |
||||
|
Function()? onTap, |
||||
|
}) { |
||||
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
||||
|
|
||||
|
return GestureDetector( |
||||
|
onTap: onTap, |
||||
|
child: Container( |
||||
|
width: 220.w, |
||||
|
height: 60.w, |
||||
|
padding: EdgeInsets.all(5.w), |
||||
|
margin: EdgeInsets.only(top: 15.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode |
||||
|
? Colors.grey[800]!.withValues(alpha: onTap != null ? 1 : 0.5) |
||||
|
: Colors.white.withValues(alpha: onTap != null ? 1 : 0.5), |
||||
|
borderRadius: BorderRadius.circular(60.w), |
||||
|
), |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
Container( |
||||
|
width: 46.w, |
||||
|
height: 46.w, |
||||
|
margin: EdgeInsets.only(right: 5.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: color.withValues(alpha: onTap != null ? 0.3 : 0.2), |
||||
|
borderRadius: BorderRadius.circular(60.w), |
||||
|
), |
||||
|
child: Icon( |
||||
|
icon, |
||||
|
color: color.withValues(alpha: onTap != null ? 1 : 0.5), |
||||
|
), |
||||
|
), |
||||
|
Expanded( |
||||
|
child: Text( |
||||
|
title, |
||||
|
style: TextStyle( |
||||
|
fontSize: 15.sp, |
||||
|
color: isDarkMode |
||||
|
? Colors.white.withValues(alpha: onTap != null ? 1 : 0.5) |
||||
|
: Colors.black87 |
||||
|
.withValues(alpha: onTap != null ? 1 : 0.5), |
||||
|
fontWeight: FontWeight.bold, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
Icon( |
||||
|
Icons.arrow_forward_ios, |
||||
|
size: 16.w, |
||||
|
color: Colors.grey.withValues(alpha: onTap != null ? 1 : 0.5), |
||||
|
), |
||||
|
SizedBox(width: 5.w), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,103 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import '../../controllers/translation_controller.dart'; |
||||
|
import '../dialogs/translation_mode_selector.dart'; |
||||
|
|
||||
|
/// 可拖拽悬浮按钮组件 |
||||
|
class DraggableFloatingButton extends StatelessWidget { |
||||
|
final bool isDarkMode; |
||||
|
final TranslationController controller; |
||||
|
|
||||
|
const DraggableFloatingButton({ |
||||
|
Key? key, |
||||
|
required this.isDarkMode, |
||||
|
required this.controller, |
||||
|
}) : super(key: key); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Obx(() => Positioned( |
||||
|
right: controller.floatingButtonPosition.value.dx, // 使用保存的位置 |
||||
|
bottom: controller.floatingButtonPosition.value.dy, // 使用保存的位置 |
||||
|
child: Draggable( |
||||
|
feedback: Material( |
||||
|
color: Colors.transparent, |
||||
|
child: Container( |
||||
|
width: 56.w, |
||||
|
height: 56.w, |
||||
|
decoration: BoxDecoration( |
||||
|
color: (isDarkMode ? Colors.grey[700] : Colors.blue) |
||||
|
?.withOpacity(0.8), |
||||
|
shape: BoxShape.circle, |
||||
|
boxShadow: [ |
||||
|
BoxShadow( |
||||
|
color: Colors.black.withOpacity(0.3), |
||||
|
blurRadius: 8, |
||||
|
offset: const Offset(0, 4), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
child: Icon( |
||||
|
Icons.translate, |
||||
|
color: Colors.white, |
||||
|
size: 24.sp, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
childWhenDragging: Container( |
||||
|
width: 56.w, |
||||
|
height: 56.w, |
||||
|
decoration: BoxDecoration( |
||||
|
color: (isDarkMode ? Colors.grey[700] : Colors.blue) |
||||
|
?.withOpacity(0.3), |
||||
|
shape: BoxShape.circle, |
||||
|
), |
||||
|
), |
||||
|
onDragEnd: (details) { |
||||
|
// 计算新位置(相对于屏幕右下角) |
||||
|
final screenSize = MediaQuery.of(Get.context!).size; |
||||
|
final newRight = screenSize.width - details.offset.dx - 56.w; |
||||
|
final newBottom = screenSize.height - details.offset.dy - 56.w; |
||||
|
|
||||
|
// 边界检查,确保按钮不会超出屏幕 |
||||
|
final clampedRight = newRight.clamp(0.0, screenSize.width - 56.w); |
||||
|
final clampedBottom = |
||||
|
newBottom.clamp(0.0, screenSize.height - 56.w); |
||||
|
|
||||
|
// 保存新位置 |
||||
|
controller.saveFloatingButtonPosition( |
||||
|
Offset(clampedRight, clampedBottom)); |
||||
|
}, |
||||
|
child: GestureDetector( |
||||
|
onTap: () => _showTranslationModeSelector(isDarkMode), |
||||
|
child: Container( |
||||
|
width: 56.w, |
||||
|
height: 56.w, |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode ? Colors.grey[700] : Colors.blue, |
||||
|
shape: BoxShape.circle, |
||||
|
boxShadow: [ |
||||
|
BoxShadow( |
||||
|
color: Colors.black.withOpacity(0.2), |
||||
|
blurRadius: 6, |
||||
|
offset: const Offset(0, 3), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
child: Icon( |
||||
|
Icons.translate, |
||||
|
color: Colors.white, |
||||
|
size: 24.sp, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
)); |
||||
|
} |
||||
|
|
||||
|
/// 显示翻译模式选择器 |
||||
|
void _showTranslationModeSelector(bool isDarkMode) { |
||||
|
TranslationModeSelector.show(isDarkMode); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,219 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import '../../controllers/translation_controller.dart'; |
||||
|
import '../../models/translation_models.dart'; |
||||
|
import '../../../../core/theme/app_colors.dart'; |
||||
|
import '../dialogs/language_selection_dialog.dart'; |
||||
|
|
||||
|
/// 面对面翻译布局组件 |
||||
|
class FaceToFaceLayout extends StatelessWidget { |
||||
|
final bool isDarkMode; |
||||
|
final TranslationController controller; |
||||
|
|
||||
|
const FaceToFaceLayout({ |
||||
|
Key? key, |
||||
|
required this.isDarkMode, |
||||
|
required this.controller, |
||||
|
}) : super(key: key); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Obx(() { |
||||
|
// 获取最新的翻译记录 |
||||
|
final latestItem = controller.translationHistory.isNotEmpty |
||||
|
? controller.translationHistory.last |
||||
|
: null; |
||||
|
|
||||
|
return Column( |
||||
|
children: [ |
||||
|
// 上半部分 - (旋转180度) |
||||
|
Expanded( |
||||
|
child: Transform.rotate( |
||||
|
angle: 3.14159, // 180度 = π弧度 |
||||
|
child: Container( |
||||
|
width: double.infinity, |
||||
|
padding: EdgeInsets.all(24.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode |
||||
|
? AppColors.cardBackground.withValues(alpha: 0.5) |
||||
|
: Colors.blue[50]?.withValues(alpha: 0.3), |
||||
|
border: Border( |
||||
|
bottom: BorderSide( |
||||
|
color: isDarkMode ? Colors.grey[700]! : Colors.grey[300]!, |
||||
|
width: 1, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
child: Column( |
||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||
|
children: [ |
||||
|
// 上半部的文本 |
||||
|
Text( |
||||
|
latestItem?.targetLanguageCode == |
||||
|
controller.targetLanguageCode.value |
||||
|
? latestItem?.translatedText ?? '' //如果为null则显示空字符 |
||||
|
: latestItem?.sourceText ?? '', |
||||
|
style: TextStyle( |
||||
|
fontSize: 20.sp, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
color: isDarkMode ? Colors.white : Colors.black87, |
||||
|
height: 1.4, |
||||
|
), |
||||
|
textAlign: TextAlign.center, |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
|
||||
|
// 语言选择栏 |
||||
|
_buildLanguageSelectionBar(isDarkMode), |
||||
|
|
||||
|
// 下半部分 - (正常方向) |
||||
|
Expanded( |
||||
|
child: Container( |
||||
|
width: double.infinity, |
||||
|
padding: EdgeInsets.all(24.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode |
||||
|
? AppColors.cardBackground.withValues(alpha: 0.5) |
||||
|
: Colors.green[50]?.withValues(alpha: 0.3), |
||||
|
), |
||||
|
child: Column( |
||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||
|
children: [ |
||||
|
// 下半部的文本 |
||||
|
Text( |
||||
|
latestItem?.sourceLanguageCode == |
||||
|
controller.sourceLanguageCode.value |
||||
|
? latestItem?.sourceText ?? |
||||
|
(controller.faceToFaceRecognitionText.value.isEmpty |
||||
|
? '' |
||||
|
: controller.faceToFaceRecognitionText.value) |
||||
|
: latestItem?.translatedText ?? '', |
||||
|
style: TextStyle( |
||||
|
fontSize: 20.sp, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
color: isDarkMode ? Colors.white : Colors.black87, |
||||
|
height: 1.4, |
||||
|
), |
||||
|
textAlign: TextAlign.center, |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 构建语言选择栏 |
||||
|
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: Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||
|
children: [ |
||||
|
// 源语言选择 |
||||
|
Expanded( |
||||
|
child: GestureDetector( |
||||
|
onTap: () => _showLanguageSelectionDialog(true, isDarkMode), |
||||
|
child: Container( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode |
||||
|
? Colors.white.withOpacity(0.1) |
||||
|
: Colors.grey[100], |
||||
|
borderRadius: BorderRadius.circular(16.r), |
||||
|
), |
||||
|
child: Text( |
||||
|
'${controller.sourceLanguage.value.split(' ')[0]}'.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 15.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
textAlign: TextAlign.center, |
||||
|
overflow: TextOverflow.ellipsis, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
|
||||
|
// 语言互换按钮 |
||||
|
GestureDetector( |
||||
|
onTap: controller.swapLanguages, |
||||
|
child: Container( |
||||
|
margin: EdgeInsets.symmetric(horizontal: 8.w), |
||||
|
padding: EdgeInsets.all(4.r), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode |
||||
|
? AppColors.primary.withOpacity(0.2) |
||||
|
: Colors.blue[50], |
||||
|
shape: BoxShape.circle, |
||||
|
), |
||||
|
child: Icon( |
||||
|
Icons.swap_horiz, |
||||
|
color: isDarkMode ? AppColors.primary : Colors.blue, |
||||
|
size: 20.sp, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
|
||||
|
// 目标语言选择 |
||||
|
Expanded( |
||||
|
child: GestureDetector( |
||||
|
onTap: () => _showLanguageSelectionDialog(false, isDarkMode), |
||||
|
child: Container( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode |
||||
|
? Colors.white.withOpacity(0.1) |
||||
|
: Colors.grey[100], |
||||
|
borderRadius: BorderRadius.circular(16.r), |
||||
|
), |
||||
|
child: Transform.rotate( |
||||
|
angle: 3.14159, // 旋转180度 |
||||
|
child: Text( |
||||
|
'${controller.targetLanguage.value.split(' ')[0]}'.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 15.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
textAlign: TextAlign.center, |
||||
|
overflow: TextOverflow.ellipsis, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/// 显示语言选择对话框 |
||||
|
void _showLanguageSelectionDialog(bool isSource, bool isDarkMode) { |
||||
|
LanguageSelectionDialog.show(isSource, isDarkMode); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue