|
|
|
@ -7,7 +7,7 @@ import '../../../../core/theme/app_colors.dart'; |
|
|
|
import '../dialogs/language_selection_dialog.dart'; |
|
|
|
|
|
|
|
/// 面对面翻译布局组件 |
|
|
|
class FaceToFaceLayout extends StatelessWidget { |
|
|
|
class FaceToFaceLayout extends StatefulWidget { |
|
|
|
final bool isDarkMode; |
|
|
|
final TranslationController controller; |
|
|
|
|
|
|
|
@ -17,13 +17,60 @@ class FaceToFaceLayout extends StatelessWidget { |
|
|
|
required this.controller, |
|
|
|
}) : super(key: key); |
|
|
|
|
|
|
|
@override |
|
|
|
State<FaceToFaceLayout> createState() => _FaceToFaceLayoutState(); |
|
|
|
} |
|
|
|
|
|
|
|
class _FaceToFaceLayoutState extends State<FaceToFaceLayout> { |
|
|
|
final ScrollController _topScrollController = ScrollController(); |
|
|
|
final ScrollController _bottomScrollController = ScrollController(); |
|
|
|
|
|
|
|
@override |
|
|
|
void dispose() { |
|
|
|
_topScrollController.dispose(); |
|
|
|
_bottomScrollController.dispose(); |
|
|
|
super.dispose(); |
|
|
|
} |
|
|
|
|
|
|
|
void _scrollToBottom({bool animate = false}) { |
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) { |
|
|
|
if (_topScrollController.hasClients) { |
|
|
|
final m = _topScrollController.position.maxScrollExtent; |
|
|
|
if (animate) { |
|
|
|
_topScrollController.animateTo( |
|
|
|
m, |
|
|
|
duration: const Duration(milliseconds: 200), |
|
|
|
curve: Curves.easeOut, |
|
|
|
); |
|
|
|
} else { |
|
|
|
_topScrollController.jumpTo(m); |
|
|
|
} |
|
|
|
} |
|
|
|
if (_bottomScrollController.hasClients) { |
|
|
|
final m2 = _bottomScrollController.position.maxScrollExtent; |
|
|
|
if (animate) { |
|
|
|
_bottomScrollController.animateTo( |
|
|
|
m2, |
|
|
|
duration: const Duration(milliseconds: 200), |
|
|
|
curve: Curves.easeOut, |
|
|
|
); |
|
|
|
} else { |
|
|
|
_bottomScrollController.jumpTo(m2); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
@override |
|
|
|
Widget build(BuildContext context) { |
|
|
|
final isDarkMode = widget.isDarkMode; |
|
|
|
final controller = widget.controller; |
|
|
|
return Obx(() { |
|
|
|
// 获取最新的翻译记录 |
|
|
|
final latestItem = controller.translationHistory.isNotEmpty |
|
|
|
? controller.translationHistory.last |
|
|
|
: null; |
|
|
|
_scrollToBottom(animate: false); |
|
|
|
|
|
|
|
return Column( |
|
|
|
children: [ |
|
|
|
@ -33,7 +80,7 @@ class FaceToFaceLayout extends StatelessWidget { |
|
|
|
angle: 3.14159, // 180度 = π弧度 |
|
|
|
child: Container( |
|
|
|
width: double.infinity, |
|
|
|
padding: EdgeInsets.all(24.w), |
|
|
|
padding: EdgeInsets.fromLTRB(24.w, 24.w, 24.w, 24.w + 96.h), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: isDarkMode |
|
|
|
? AppColors.cardBackground.withValues(alpha: 0.5) |
|
|
|
@ -45,14 +92,13 @@ class FaceToFaceLayout extends StatelessWidget { |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
child: Column( |
|
|
|
mainAxisAlignment: MainAxisAlignment.center, |
|
|
|
children: [ |
|
|
|
// 上半部的文本 |
|
|
|
Text( |
|
|
|
child: SingleChildScrollView( |
|
|
|
controller: _topScrollController, |
|
|
|
physics: const BouncingScrollPhysics(), |
|
|
|
child: Text( |
|
|
|
latestItem?.targetLanguageCode == |
|
|
|
controller.targetLanguageCode.value |
|
|
|
? latestItem?.translatedText ?? '' //如果为null则显示空字符 |
|
|
|
? latestItem?.translatedText ?? '' |
|
|
|
: latestItem?.sourceText ?? '', |
|
|
|
style: TextStyle( |
|
|
|
fontSize: 20.sp, |
|
|
|
@ -62,7 +108,6 @@ class FaceToFaceLayout extends StatelessWidget { |
|
|
|
), |
|
|
|
textAlign: TextAlign.center, |
|
|
|
), |
|
|
|
], |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
@ -75,17 +120,16 @@ class FaceToFaceLayout extends StatelessWidget { |
|
|
|
Expanded( |
|
|
|
child: Container( |
|
|
|
width: double.infinity, |
|
|
|
padding: EdgeInsets.all(24.w), |
|
|
|
padding: EdgeInsets.fromLTRB(24.w, 24.w, 24.w, 24.w + 96.h), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: isDarkMode |
|
|
|
? AppColors.cardBackground.withValues(alpha: 0.5) |
|
|
|
: Colors.green[50]?.withValues(alpha: 0.3), |
|
|
|
), |
|
|
|
child: Column( |
|
|
|
mainAxisAlignment: MainAxisAlignment.center, |
|
|
|
children: [ |
|
|
|
// 下半部的文本 |
|
|
|
Text( |
|
|
|
child: SingleChildScrollView( |
|
|
|
controller: _bottomScrollController, |
|
|
|
physics: const BouncingScrollPhysics(), |
|
|
|
child: Text( |
|
|
|
latestItem?.sourceLanguageCode == |
|
|
|
controller.sourceLanguageCode.value |
|
|
|
? latestItem?.sourceText ?? |
|
|
|
@ -101,7 +145,6 @@ class FaceToFaceLayout extends StatelessWidget { |
|
|
|
), |
|
|
|
textAlign: TextAlign.center, |
|
|
|
), |
|
|
|
], |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
@ -146,7 +189,7 @@ class FaceToFaceLayout extends StatelessWidget { |
|
|
|
borderRadius: BorderRadius.circular(16.r), |
|
|
|
), |
|
|
|
child: Text( |
|
|
|
'${controller.sourceLanguage.value.split(' ')[0]}'.tr, |
|
|
|
'${widget.controller.sourceLanguage.value.split(' ')[0]}'.tr, |
|
|
|
style: TextStyle( |
|
|
|
fontSize: 15.sp, |
|
|
|
fontWeight: FontWeight.w600, |
|
|
|
@ -161,7 +204,7 @@ class FaceToFaceLayout extends StatelessWidget { |
|
|
|
|
|
|
|
// 语言互换按钮 |
|
|
|
GestureDetector( |
|
|
|
onTap: controller.swapLanguages, |
|
|
|
onTap: widget.controller.swapLanguages, |
|
|
|
child: Container( |
|
|
|
margin: EdgeInsets.symmetric(horizontal: 8.w), |
|
|
|
padding: EdgeInsets.all(4.r), |
|
|
|
@ -194,7 +237,8 @@ class FaceToFaceLayout extends StatelessWidget { |
|
|
|
child: Transform.rotate( |
|
|
|
angle: 3.14159, // 旋转180度 |
|
|
|
child: Text( |
|
|
|
'${controller.targetLanguage.value.split(' ')[0]}'.tr, |
|
|
|
'${widget.controller.targetLanguage.value.split(' ')[0]}' |
|
|
|
.tr, |
|
|
|
style: TextStyle( |
|
|
|
fontSize: 15.sp, |
|
|
|
fontWeight: FontWeight.w600, |
|
|
|
|