Browse Source

add

newdev_shunjiawei
wolfplus 2 years ago
parent
commit
ed88713bb6
  1. 19
      lib/modules/chat/controllers/chat_controller.dart
  2. 32
      lib/modules/translation/controllers/translation_controller.dart
  3. 136
      lib/modules/translation/views/translation_view.dart

19
lib/modules/chat/controllers/chat_controller.dart

@ -124,9 +124,6 @@ class ChatController extends GetxController {
// 使用微任务在布局完成后自动滚动到底部 // 使用微任务在布局完成后自动滚动到底部
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollToBottom(); _scrollToBottom();
Future.delayed(const Duration(milliseconds: 500), () {
_scrollToBottom();
});
}); });
} }
@ -227,7 +224,7 @@ class ChatController extends GetxController {
if (scrollController.hasClients && messages.isNotEmpty) { if (scrollController.hasClients && messages.isNotEmpty) {
try { try {
scrollController.animateTo( scrollController.animateTo(
scrollController.position.maxScrollExtent + 30, scrollController.position.maxScrollExtent,
duration: Duration(milliseconds: 300), duration: Duration(milliseconds: 300),
curve: Curves.easeOut, curve: Curves.easeOut,
); );
@ -280,7 +277,7 @@ class ChatController extends GetxController {
timestamp: DateTime.now(), timestamp: DateTime.now(),
); );
messages.add(userMessage); messages.add(userMessage);
_scrollToBottom();
// 清空输入框 // 清空输入框
inputText.value = ''; inputText.value = '';
@ -288,7 +285,10 @@ class ChatController extends GetxController {
// 添加加载中的消息 // 添加加载中的消息
final loadingMessage = Message.loading(); final loadingMessage = Message.loading();
messages.add(loadingMessage); messages.add(loadingMessage);
_scrollToBottom();
WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollToBottom();
});
isSending.value = true; isSending.value = true;
@ -549,13 +549,8 @@ class ChatController extends GetxController {
messages.add(tempMessage); messages.add(tempMessage);
_tempMessageIndex = messages.length - 1; _tempMessageIndex = messages.length - 1;
messages.refresh(); messages.refresh();
_scrollToBottom();
} }
// 取消之前的计时器 WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollDebounceTimer?.cancel();
// 设置新的防抖计时器,延迟100毫秒执行滚动
_scrollDebounceTimer = Timer(Duration(milliseconds: 500), () {
_scrollToBottom(); _scrollToBottom();
}); });
} }

32
lib/modules/translation/controllers/translation_controller.dart

@ -90,11 +90,7 @@ class TranslationController extends GetxController {
// 使用微任务在布局完成后自动滚动到底部 // 使用微任务在布局完成后自动滚动到底部
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollToBottom(); _scrollToBottom();
// 额外的延迟滚动,确保在复杂视图中也能正确滚动
Future.delayed(const Duration(milliseconds: 500), () {
_scrollToBottom();
});
}); });
} }
@ -179,20 +175,20 @@ class TranslationController extends GetxController {
currentSessionId = DateTime.now().millisecondsSinceEpoch.toString(); currentSessionId = DateTime.now().millisecondsSinceEpoch.toString();
// 初始化新的翻译项 // // 初始化新的翻译项
final newItem = TranslationItem( // final newItem = TranslationItem(
sourceText: '', // sourceText: '',
translatedText: '', // translatedText: '',
sourceLanguageCode: sourceLanguageCode.value, // sourceLanguageCode: sourceLanguageCode.value,
targetLanguageCode: targetLanguageCode.value, // targetLanguageCode: targetLanguageCode.value,
timestamp: DateTime.now(), // timestamp: DateTime.now(),
sessionId: currentSessionId!, // sessionId: currentSessionId!,
isFirstInSession: true, // isFirstInSession: true,
isIntermediate: true, // isIntermediate: true,
); // );
// 添加到历史记录 // // 添加到历史记录
translationHistory.add(newItem); // translationHistory.add(newItem);
// 开始连续语音识别 // 开始连续语音识别
final recognitionStream = await _asrService.startContinuousRecognition(); final recognitionStream = await _asrService.startContinuousRecognition();

136
lib/modules/translation/views/translation_view.dart

@ -157,16 +157,14 @@ class TranslationView extends GetView<TranslationController> {
return Obx(() { return Obx(() {
final itemCount = controller.translationHistory.length; final itemCount = controller.translationHistory.length;
// 计算底部内边距,确保内容不会被底部框遮住
final bottomPadding = controller.bottomBarHeight + 20.h; // 使用控制栏高度加上额外间距
return ListView.builder( return ListView.builder(
controller: controller.scrollController, controller: controller.scrollController,
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: 16.w, left: 16.w,
right: 16.w, right: 16.w,
top: 16.h, top: 16.h,
bottom: bottomPadding bottom: 16.h,
), ),
itemCount: itemCount, itemCount: itemCount,
itemBuilder: (context, index) { itemBuilder: (context, index) {
@ -175,97 +173,77 @@ class TranslationView extends GetView<TranslationController> {
// 构建项目widget // 构建项目widget
return _buildTranslationItemWidget( return _buildTranslationItemWidget(
historyItem.sourceText, context,
historyItem.translatedText, historyItem
historyItem.isIntermediate, // 如果是中间结果,设置为当前项
item: historyItem,
isIntermediate: historyItem.isIntermediate,
isDarkMode: isDarkMode,
); );
}, },
); );
}); });
} }
Widget _buildTranslationItemWidget( Widget _buildTranslationItemWidget(BuildContext context, TranslationItem item) {
String sourceText, return Container(
String translatedText, margin: const EdgeInsets.only(bottom: 8),
bool isCurrentItem, padding: const EdgeInsets.all(12),
{
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),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? AppColors.cardBackground : Colors.grey[100], color: item.isIntermediate
borderRadius: BorderRadius.circular(12.r), ? 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( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// Source text // 源文本
AnimatedContainer( Text(
duration: const Duration(milliseconds: 300), item.sourceText,
width: double.infinity, style: TextStyle(
padding: EdgeInsets.all(16.r), fontSize: 16,
child: Text( color: Theme.of(context).textTheme.bodyLarge?.color,
sourceText.isEmpty && isCurrentItem ? '等待语音输入...' : sourceText, ),
),
if (item.translatedText.isNotEmpty) ...[
const SizedBox(height: 8),
// 翻译文本
Text(
item.translatedText,
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16,
color: sourceText.isEmpty && isCurrentItem color: Theme.of(context).textTheme.bodyMedium?.color,
? (isDarkMode ? Colors.grey[400] : Colors.grey) fontWeight: FontWeight.w500,
: (isDarkMode ? Colors.white : Colors.black),
fontWeight: FontWeight.normal,
), ),
), ),
), ],
// 语言信息和时间戳
// Divider const SizedBox(height: 4),
Divider(height: 1, thickness: 1, color: isDarkMode ? Colors.grey[800] : Colors.grey[200]), Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
// Translated text children: [
AnimatedContainer( Text(
duration: const Duration(milliseconds: 300), '${item.sourceLanguageName} → ${item.targetLanguageName}',
width: double.infinity, style: TextStyle(
padding: EdgeInsets.all(16.r), fontSize: 12,
child: Row( color: Theme.of(context).textTheme.bodySmall?.color,
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,
),
),
), ),
if (translatedText.isNotEmpty) ),
IconButton( if (!item.isIntermediate)
icon: Icon( GestureDetector(
Icons.volume_up, onTap: () => controller.playTranslationItem(item),
color: isDarkMode ? AppColors.primary : Colors.blue, child: Icon(
size: 20.sp, Icons.volume_up,
), size: 18,
onPressed: () { color: Theme.of(context).colorScheme.primary,
if (item != null) {
controller.playTranslationItem(item);
} else {
controller.playTranslatedText(translatedText);
}
},
), ),
], ),
), ],
), ),
], ],
), ),

Loading…
Cancel
Save