From ed88713bb60846aa4deb1a674c4d7baf0ba01dbe Mon Sep 17 00:00:00 2001 From: wolfplus Date: Mon, 24 Mar 2025 14:33:36 +0000 Subject: [PATCH] add --- .../chat/controllers/chat_controller.dart | 19 +-- .../controllers/translation_controller.dart | 32 ++--- .../translation/views/translation_view.dart | 136 ++++++++---------- 3 files changed, 78 insertions(+), 109 deletions(-) diff --git a/lib/modules/chat/controllers/chat_controller.dart b/lib/modules/chat/controllers/chat_controller.dart index 6bc878c8f..25d567714 100644 --- a/lib/modules/chat/controllers/chat_controller.dart +++ b/lib/modules/chat/controllers/chat_controller.dart @@ -124,9 +124,6 @@ class ChatController extends GetxController { // 使用微任务在布局完成后自动滚动到底部 WidgetsBinding.instance.addPostFrameCallback((_) { _scrollToBottom(); - Future.delayed(const Duration(milliseconds: 500), () { - _scrollToBottom(); - }); }); } @@ -227,7 +224,7 @@ class ChatController extends GetxController { if (scrollController.hasClients && messages.isNotEmpty) { try { scrollController.animateTo( - scrollController.position.maxScrollExtent + 30, + scrollController.position.maxScrollExtent, duration: Duration(milliseconds: 300), curve: Curves.easeOut, ); @@ -280,7 +277,7 @@ class ChatController extends GetxController { timestamp: DateTime.now(), ); messages.add(userMessage); - _scrollToBottom(); + // 清空输入框 inputText.value = ''; @@ -288,7 +285,10 @@ class ChatController extends GetxController { // 添加加载中的消息 final loadingMessage = Message.loading(); messages.add(loadingMessage); - _scrollToBottom(); + + WidgetsBinding.instance.addPostFrameCallback((_) { + _scrollToBottom(); + }); isSending.value = true; @@ -549,13 +549,8 @@ class ChatController extends GetxController { messages.add(tempMessage); _tempMessageIndex = messages.length - 1; messages.refresh(); - _scrollToBottom(); } - // 取消之前的计时器 - _scrollDebounceTimer?.cancel(); - - // 设置新的防抖计时器,延迟100毫秒执行滚动 - _scrollDebounceTimer = Timer(Duration(milliseconds: 500), () { + WidgetsBinding.instance.addPostFrameCallback((_) { _scrollToBottom(); }); } diff --git a/lib/modules/translation/controllers/translation_controller.dart b/lib/modules/translation/controllers/translation_controller.dart index 940966590..59822e45f 100644 --- a/lib/modules/translation/controllers/translation_controller.dart +++ b/lib/modules/translation/controllers/translation_controller.dart @@ -90,11 +90,7 @@ class TranslationController extends GetxController { // 使用微任务在布局完成后自动滚动到底部 WidgetsBinding.instance.addPostFrameCallback((_) { _scrollToBottom(); - - // 额外的延迟滚动,确保在复杂视图中也能正确滚动 - Future.delayed(const Duration(milliseconds: 500), () { - _scrollToBottom(); - }); + }); } @@ -179,20 +175,20 @@ class TranslationController extends GetxController { currentSessionId = DateTime.now().millisecondsSinceEpoch.toString(); - // 初始化新的翻译项 - final newItem = TranslationItem( - sourceText: '', - translatedText: '', - sourceLanguageCode: sourceLanguageCode.value, - targetLanguageCode: targetLanguageCode.value, - timestamp: DateTime.now(), - sessionId: currentSessionId!, - isFirstInSession: true, - isIntermediate: true, - ); + // // 初始化新的翻译项 + // final newItem = TranslationItem( + // sourceText: '', + // translatedText: '', + // sourceLanguageCode: sourceLanguageCode.value, + // targetLanguageCode: targetLanguageCode.value, + // timestamp: DateTime.now(), + // sessionId: currentSessionId!, + // isFirstInSession: true, + // isIntermediate: true, + // ); - // 添加到历史记录 - translationHistory.add(newItem); + // // 添加到历史记录 + // translationHistory.add(newItem); // 开始连续语音识别 final recognitionStream = await _asrService.startContinuousRecognition(); diff --git a/lib/modules/translation/views/translation_view.dart b/lib/modules/translation/views/translation_view.dart index befc39503..eb606da19 100644 --- a/lib/modules/translation/views/translation_view.dart +++ b/lib/modules/translation/views/translation_view.dart @@ -157,16 +157,14 @@ class TranslationView extends GetView { return Obx(() { final itemCount = controller.translationHistory.length; - // 计算底部内边距,确保内容不会被底部框遮住 - final bottomPadding = controller.bottomBarHeight + 20.h; // 使用控制栏高度加上额外间距 - + return ListView.builder( controller: controller.scrollController, padding: EdgeInsets.only( left: 16.w, right: 16.w, top: 16.h, - bottom: bottomPadding + bottom: 16.h, ), itemCount: itemCount, itemBuilder: (context, index) { @@ -175,97 +173,77 @@ class TranslationView extends GetView { // 构建项目widget return _buildTranslationItemWidget( - historyItem.sourceText, - historyItem.translatedText, - historyItem.isIntermediate, // 如果是中间结果,设置为当前项 - item: historyItem, - isIntermediate: historyItem.isIntermediate, - isDarkMode: isDarkMode, + context, + historyItem ); }, ); }); } - Widget _buildTranslationItemWidget( - String sourceText, - String translatedText, - bool isCurrentItem, - { - TranslationItem? item, - bool isIntermediate = false, - required bool isDarkMode, - } - ) { - // 使用AnimatedContainer实现平滑过渡,但恢复原来的视觉样式 - return AnimatedContainer( - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - margin: EdgeInsets.only(bottom: 24.h), + Widget _buildTranslationItemWidget(BuildContext context, TranslationItem item) { + return Container( + margin: const EdgeInsets.only(bottom: 8), + padding: const EdgeInsets.all(12), decoration: BoxDecoration( - color: isDarkMode ? AppColors.cardBackground : Colors.grey[100], - borderRadius: BorderRadius.circular(12.r), + color: item.isIntermediate + ? Colors.grey.withOpacity(0.1) // 中间结果使用浅灰色底色 + : (item.sourceLanguageCode == controller.sourceLanguageCode.value + ? Theme.of(context).colorScheme.primary.withOpacity(0.08) // 源语言匹配时使用主题色底色 + : Theme.of(context).colorScheme.secondary.withOpacity(0.08)), // 否则使用次要色底色 + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: item.isIntermediate + ? Colors.grey.withOpacity(0.2) + : Colors.transparent, + width: 1, + ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Source text - AnimatedContainer( - duration: const Duration(milliseconds: 300), - width: double.infinity, - padding: EdgeInsets.all(16.r), - child: Text( - sourceText.isEmpty && isCurrentItem ? '等待语音输入...' : sourceText, + // 源文本 + Text( + item.sourceText, + style: TextStyle( + fontSize: 16, + color: Theme.of(context).textTheme.bodyLarge?.color, + ), + ), + if (item.translatedText.isNotEmpty) ...[ + const SizedBox(height: 8), + // 翻译文本 + Text( + item.translatedText, style: TextStyle( - fontSize: 16.sp, - color: sourceText.isEmpty && isCurrentItem - ? (isDarkMode ? Colors.grey[400] : Colors.grey) - : (isDarkMode ? Colors.white : Colors.black), - fontWeight: FontWeight.normal, + fontSize: 16, + color: Theme.of(context).textTheme.bodyMedium?.color, + fontWeight: FontWeight.w500, ), ), - ), - - // Divider - Divider(height: 1, thickness: 1, color: isDarkMode ? Colors.grey[800] : Colors.grey[200]), - - // Translated text - AnimatedContainer( - duration: const Duration(milliseconds: 300), - width: double.infinity, - padding: EdgeInsets.all(16.r), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Text( - translatedText.isEmpty && isCurrentItem ? '翻译结果将显示在这里...' : translatedText, - style: TextStyle( - fontSize: 16.sp, - color: translatedText.isEmpty && isCurrentItem - ? (isDarkMode ? Colors.grey[400] : Colors.grey) - : (isDarkMode ? Colors.white : Colors.black), - fontStyle: FontStyle.normal, - ), - ), + ], + // 语言信息和时间戳 + const SizedBox(height: 4), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '${item.sourceLanguageName} → ${item.targetLanguageName}', + style: TextStyle( + fontSize: 12, + color: Theme.of(context).textTheme.bodySmall?.color, ), - if (translatedText.isNotEmpty) - IconButton( - icon: Icon( - Icons.volume_up, - color: isDarkMode ? AppColors.primary : Colors.blue, - size: 20.sp, - ), - onPressed: () { - if (item != null) { - controller.playTranslationItem(item); - } else { - controller.playTranslatedText(translatedText); - } - }, + ), + if (!item.isIntermediate) + GestureDetector( + onTap: () => controller.playTranslationItem(item), + child: Icon( + Icons.volume_up, + size: 18, + color: Theme.of(context).colorScheme.primary, ), - ], - ), + ), + ], ), ], ),