|
|
@ -5,6 +5,7 @@ import 'dart:math'; |
|
|
import '../controllers/chat_controller.dart'; |
|
|
import '../controllers/chat_controller.dart'; |
|
|
import '../models/message_model.dart'; |
|
|
import '../models/message_model.dart'; |
|
|
import '../../../core/theme/app_colors.dart'; |
|
|
import '../../../core/theme/app_colors.dart'; |
|
|
|
|
|
import 'animated_gradient_background.dart'; |
|
|
import 'chat_music_card.dart'; |
|
|
import 'chat_music_card.dart'; |
|
|
import 'chat_navigation_card.dart'; |
|
|
import 'chat_navigation_card.dart'; |
|
|
import 'weather_day_card.dart'; |
|
|
import 'weather_day_card.dart'; |
|
|
@ -16,10 +17,17 @@ class ChatView extends GetView<ChatController> { |
|
|
Widget build(BuildContext context) { |
|
|
Widget build(BuildContext context) { |
|
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
|
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
|
|
|
|
|
|
|
|
return Scaffold( |
|
|
return Obx( |
|
|
backgroundColor: isDarkMode ? AppColors.darkBackground : Colors.grey[50], |
|
|
() => Scaffold( |
|
|
appBar: _buildAppBar(isDarkMode), |
|
|
backgroundColor: |
|
|
body: _buildBody(isDarkMode), |
|
|
isDarkMode ? AppColors.darkBackground : Colors.grey[50], |
|
|
|
|
|
appBar: controller.isVoiceRecognitionActive.value |
|
|
|
|
|
? null |
|
|
|
|
|
: _buildAppBar(isDarkMode), |
|
|
|
|
|
body: controller.isVoiceRecognitionActive.value |
|
|
|
|
|
? _buildVoiceInputPanel(isDarkMode) |
|
|
|
|
|
: _buildBody(isDarkMode), |
|
|
|
|
|
), |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -47,7 +55,7 @@ class ChatView extends GetView<ChatController> { |
|
|
BoxShadow( |
|
|
BoxShadow( |
|
|
color: Colors.black.withOpacity(0.1), |
|
|
color: Colors.black.withOpacity(0.1), |
|
|
blurRadius: 3, |
|
|
blurRadius: 3, |
|
|
offset: Offset(0, 1), |
|
|
offset: const Offset(0, 1), |
|
|
), |
|
|
), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
@ -92,7 +100,7 @@ class ChatView extends GetView<ChatController> { |
|
|
Container( |
|
|
Container( |
|
|
width: 6.r, |
|
|
width: 6.r, |
|
|
height: 6.r, |
|
|
height: 6.r, |
|
|
decoration: BoxDecoration( |
|
|
decoration: const BoxDecoration( |
|
|
color: Colors.green, |
|
|
color: Colors.green, |
|
|
shape: BoxShape.circle, |
|
|
shape: BoxShape.circle, |
|
|
), |
|
|
), |
|
|
@ -113,6 +121,13 @@ class ChatView extends GetView<ChatController> { |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
actions: [ |
|
|
actions: [ |
|
|
|
|
|
IconButton( |
|
|
|
|
|
icon: Icon( |
|
|
|
|
|
Icons.phone, |
|
|
|
|
|
color: isDarkMode ? Colors.white : Colors.black87, |
|
|
|
|
|
), |
|
|
|
|
|
onPressed: controller.startVoiceRecognition, |
|
|
|
|
|
), |
|
|
// TTS开关 |
|
|
// TTS开关 |
|
|
Obx(() => IconButton( |
|
|
Obx(() => IconButton( |
|
|
icon: Icon( |
|
|
icon: Icon( |
|
|
@ -157,7 +172,7 @@ class ChatView extends GetView<ChatController> { |
|
|
value: 'clear', |
|
|
value: 'clear', |
|
|
child: Row( |
|
|
child: Row( |
|
|
children: [ |
|
|
children: [ |
|
|
Icon(Icons.delete_outline, color: Colors.red), |
|
|
const Icon(Icons.delete_outline, color: Colors.red), |
|
|
SizedBox(width: 8.w), |
|
|
SizedBox(width: 8.w), |
|
|
Text( |
|
|
Text( |
|
|
'clearChatHistory'.tr, // 清空聊天记录 |
|
|
'clearChatHistory'.tr, // 清空聊天记录 |
|
|
@ -198,7 +213,7 @@ class ChatView extends GetView<ChatController> { |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
// 底部输入区域 |
|
|
// 底部输入区域 |
|
|
_buildInputArea(isDarkMode), |
|
|
_buildTextInputPanel(isDarkMode), |
|
|
], |
|
|
], |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
@ -370,139 +385,128 @@ class ChatView extends GetView<ChatController> { |
|
|
return box; |
|
|
return box; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 构建输入区域 |
|
|
// 构建文本输入面板 |
|
|
Widget _buildInputArea(bool isDarkMode) { |
|
|
Widget _buildTextInputPanel(bool isDarkMode) { |
|
|
final textController = |
|
|
final textController = |
|
|
TextEditingController(text: controller.inputText.value); |
|
|
TextEditingController(text: controller.inputText.value); |
|
|
|
|
|
|
|
|
// 检查是否处于语音识别模式 |
|
|
|
|
|
return Obx(() { |
|
|
|
|
|
if (controller.isVoiceRecognitionActive.value) { |
|
|
|
|
|
return _buildVoiceInputPanel(isDarkMode); |
|
|
|
|
|
} else { |
|
|
|
|
|
return _buildTextInputPanel(isDarkMode, textController); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 构建文本输入面板 |
|
|
|
|
|
Widget _buildTextInputPanel( |
|
|
|
|
|
bool isDarkMode, TextEditingController textController) { |
|
|
|
|
|
return Container( |
|
|
return Container( |
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), |
|
|
height: 48.w, |
|
|
|
|
|
margin: EdgeInsets.only(left: 16.w, right: 16.w, top: 10.w, bottom: 20.w), |
|
|
|
|
|
clipBehavior: Clip.hardEdge, |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: isDarkMode ? AppColors.cardBackground : Colors.white, |
|
|
color: controller.isHoldSpeak.value |
|
|
|
|
|
? AppColors.primary |
|
|
|
|
|
: isDarkMode |
|
|
|
|
|
? AppColors.cardBackground |
|
|
|
|
|
: Colors.white, |
|
|
|
|
|
borderRadius: BorderRadius.circular(12.w), |
|
|
boxShadow: [ |
|
|
boxShadow: [ |
|
|
BoxShadow( |
|
|
BoxShadow( |
|
|
color: Colors.black.withOpacity(0.05), |
|
|
color: Colors.black.withOpacity(0.05), |
|
|
blurRadius: 3, |
|
|
blurRadius: 3, |
|
|
offset: Offset(0, -1), |
|
|
offset: const Offset(0, -1), |
|
|
), |
|
|
), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
child: SafeArea( |
|
|
child: Row( |
|
|
child: Row( |
|
|
children: [ |
|
|
children: [ |
|
|
Expanded( |
|
|
// 语音识别按钮 |
|
|
child: Obx( |
|
|
Container( |
|
|
() => controller.isTextInput.value |
|
|
width: 40.w, |
|
|
? Center( |
|
|
height: 40.w, |
|
|
child: TextField( |
|
|
decoration: BoxDecoration( |
|
|
controller: textController, |
|
|
color: isDarkMode |
|
|
style: TextStyle( |
|
|
? Colors.white.withOpacity(0.1) |
|
|
fontSize: 15.sp, |
|
|
: Colors.grey[100], |
|
|
color: isDarkMode ? Colors.white : Colors.black87, |
|
|
shape: BoxShape.circle, |
|
|
), |
|
|
), |
|
|
textInputAction: TextInputAction.send, |
|
|
child: IconButton( |
|
|
decoration: InputDecoration( |
|
|
icon: Icon( |
|
|
hintText: 'inputMessage'.tr, // 输入消息... |
|
|
Icons.mic_none, |
|
|
hintStyle: TextStyle(color: Colors.grey[500]), |
|
|
color: isDarkMode ? Colors.white : Colors.grey[700], |
|
|
filled: false, |
|
|
size: 20.r, |
|
|
border: InputBorder.none, |
|
|
), |
|
|
focusedBorder: InputBorder.none, |
|
|
padding: EdgeInsets.zero, |
|
|
contentPadding: EdgeInsets.only(left: 10.w), |
|
|
onPressed: controller.startVoiceRecognition, |
|
|
), |
|
|
), |
|
|
onSubmitted: (value) { |
|
|
|
|
|
if (value.trim().isNotEmpty) { |
|
|
|
|
|
controller.sendMessage(value); |
|
|
|
|
|
textController.clear(); |
|
|
|
|
|
controller.inputText.value = ''; // 清空输入框 |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
), |
|
|
|
|
|
) |
|
|
|
|
|
: Listener( |
|
|
|
|
|
onPointerDown: (event) { |
|
|
|
|
|
controller.talkLongPress(); |
|
|
|
|
|
}, |
|
|
|
|
|
onPointerUp: (event) { |
|
|
|
|
|
controller.talkLongPressUp(); |
|
|
|
|
|
}, |
|
|
|
|
|
child: Container( |
|
|
|
|
|
padding: EdgeInsets.only( |
|
|
|
|
|
left: controller.isHoldSpeak.value ? 0 : 46.w), |
|
|
|
|
|
color: Colors.transparent, |
|
|
|
|
|
child: controller.isHoldSpeak.value |
|
|
|
|
|
? Row( |
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center, |
|
|
|
|
|
children: List.generate(40, (int index) { |
|
|
|
|
|
return Container( |
|
|
|
|
|
width: 3.w, |
|
|
|
|
|
height: 10.w, |
|
|
|
|
|
margin: |
|
|
|
|
|
EdgeInsets.symmetric(horizontal: 2.w), |
|
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
|
color: Colors.white, |
|
|
|
|
|
borderRadius: BorderRadius.circular(3.r), |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
}), |
|
|
|
|
|
) |
|
|
|
|
|
: Center( |
|
|
|
|
|
child: Text( |
|
|
|
|
|
'按住说话', |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 16.sp, |
|
|
|
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.white |
|
|
|
|
|
: Colors.black87, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
|
|
|
), |
|
|
SizedBox(width: 8.w), |
|
|
if (!controller.isHoldSpeak.value) |
|
|
|
|
|
GestureDetector( |
|
|
// 输入框 |
|
|
onTap: () { |
|
|
Expanded( |
|
|
controller.isTextInput.value = !controller.isTextInput.value; |
|
|
child: TextField( |
|
|
}, |
|
|
controller: textController, |
|
|
child: Container( |
|
|
decoration: InputDecoration( |
|
|
width: 30.w, |
|
|
hintText: 'inputMessage'.tr, // 输入消息... |
|
|
height: 30.w, |
|
|
hintStyle: TextStyle( |
|
|
margin: EdgeInsets.all(8.w), |
|
|
color: isDarkMode ? Colors.grey[500] : Colors.grey[500]), |
|
|
alignment: Alignment.center, |
|
|
filled: true, |
|
|
decoration: BoxDecoration( |
|
|
fillColor: isDarkMode |
|
|
borderRadius: BorderRadius.circular(30.r), |
|
|
? Colors.white.withOpacity(0.1) |
|
|
border: Border.all( |
|
|
: Colors.grey[100], |
|
|
color: isDarkMode ? Colors.white : Colors.black87, |
|
|
border: OutlineInputBorder( |
|
|
width: 2, |
|
|
borderRadius: BorderRadius.circular(20.r), |
|
|
|
|
|
borderSide: BorderSide.none, |
|
|
|
|
|
), |
|
|
|
|
|
contentPadding: EdgeInsets.symmetric( |
|
|
|
|
|
horizontal: 16.w, |
|
|
|
|
|
vertical: 10.h, |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
maxLines: null, |
|
|
child: Obx( |
|
|
textInputAction: TextInputAction.newline, |
|
|
() => Icon( |
|
|
style: TextStyle( |
|
|
controller.isTextInput.value ? Icons.mic : Icons.keyboard, |
|
|
fontSize: 15.sp, |
|
|
size: 20.w, |
|
|
color: isDarkMode ? Colors.white : Colors.black87, |
|
|
), |
|
|
), |
|
|
), |
|
|
onChanged: (value) => controller.inputText.value = value, |
|
|
|
|
|
onSubmitted: (value) { |
|
|
|
|
|
if (value.trim().isNotEmpty) { |
|
|
|
|
|
controller.sendMessage(value); |
|
|
|
|
|
textController.clear(); |
|
|
|
|
|
controller.inputText.value = ''; // 清空输入框 |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
|
|
|
], |
|
|
SizedBox(width: 8.w), |
|
|
|
|
|
|
|
|
|
|
|
// 发送按钮 |
|
|
|
|
|
Obx(() { |
|
|
|
|
|
final hasText = controller.inputText.value.isNotEmpty; |
|
|
|
|
|
return Container( |
|
|
|
|
|
width: 40.w, |
|
|
|
|
|
height: 40.w, |
|
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
|
color: hasText |
|
|
|
|
|
? AppColors.primary |
|
|
|
|
|
: isDarkMode |
|
|
|
|
|
? Colors.white.withOpacity(0.1) |
|
|
|
|
|
: Colors.grey[200], |
|
|
|
|
|
shape: BoxShape.circle, |
|
|
|
|
|
), |
|
|
|
|
|
child: IconButton( |
|
|
|
|
|
icon: Icon( |
|
|
|
|
|
Icons.send, |
|
|
|
|
|
color: hasText |
|
|
|
|
|
? Colors.white |
|
|
|
|
|
: isDarkMode |
|
|
|
|
|
? Colors.white.withOpacity(0.5) |
|
|
|
|
|
: Colors.grey[400], |
|
|
|
|
|
size: 18.r, |
|
|
|
|
|
), |
|
|
|
|
|
padding: EdgeInsets.zero, |
|
|
|
|
|
onPressed: hasText |
|
|
|
|
|
? () { |
|
|
|
|
|
controller.sendMessage(controller.inputText.value); |
|
|
|
|
|
textController.clear(); |
|
|
|
|
|
controller.inputText.value = ''; // 清空输入框 |
|
|
|
|
|
} |
|
|
|
|
|
: null, |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
}), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
), |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
@ -512,158 +516,166 @@ class ChatView extends GetView<ChatController> { |
|
|
return Container( |
|
|
return Container( |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: isDarkMode ? AppColors.cardBackground : Colors.white, |
|
|
color: isDarkMode ? AppColors.cardBackground : Colors.white, |
|
|
boxShadow: [ |
|
|
|
|
|
BoxShadow( |
|
|
|
|
|
color: Colors.black.withOpacity(0.05), |
|
|
|
|
|
blurRadius: 3, |
|
|
|
|
|
offset: Offset(0, -1), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
), |
|
|
child: SafeArea( |
|
|
child: SafeArea( |
|
|
child: SizedBox( |
|
|
child: Column( |
|
|
height: 80.h, |
|
|
children: [ |
|
|
child: Padding( |
|
|
Row( |
|
|
padding: EdgeInsets.symmetric(horizontal: 20.w), |
|
|
children: [], |
|
|
child: Row( |
|
|
), |
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
|
Expanded( |
|
|
crossAxisAlignment: CrossAxisAlignment.center, |
|
|
child: AnimatedGradientBackground(), |
|
|
children: [ |
|
|
), |
|
|
// 语音录制按钮 |
|
|
SizedBox( |
|
|
Container( |
|
|
height: 80.h, |
|
|
width: 60.r, |
|
|
child: Padding( |
|
|
height: 60.r, |
|
|
padding: EdgeInsets.symmetric(horizontal: 20.w), |
|
|
decoration: BoxDecoration( |
|
|
child: Row( |
|
|
color: isDarkMode |
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
|
? Colors.white.withOpacity(0.1) |
|
|
crossAxisAlignment: CrossAxisAlignment.center, |
|
|
: Colors.white, |
|
|
children: [ |
|
|
shape: BoxShape.circle, |
|
|
// 语音录制按钮 |
|
|
boxShadow: [ |
|
|
Container( |
|
|
BoxShadow( |
|
|
width: 60.r, |
|
|
color: Colors.black.withOpacity(0.1), |
|
|
height: 60.r, |
|
|
blurRadius: 8, |
|
|
decoration: BoxDecoration( |
|
|
spreadRadius: 1, |
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.white.withOpacity(0.1) |
|
|
|
|
|
: Colors.white, |
|
|
|
|
|
shape: BoxShape.circle, |
|
|
|
|
|
boxShadow: [ |
|
|
|
|
|
BoxShadow( |
|
|
|
|
|
color: Colors.black.withOpacity(0.1), |
|
|
|
|
|
blurRadius: 8, |
|
|
|
|
|
spreadRadius: 1, |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
], |
|
|
child: Center( |
|
|
), |
|
|
child: Obx(() => Icon( |
|
|
child: Center( |
|
|
controller.isListening.value |
|
|
child: Obx(() => Icon( |
|
|
? Icons.mic |
|
|
controller.isListening.value |
|
|
: Icons.mic_none, |
|
|
? Icons.mic |
|
|
color: controller.isListening.value |
|
|
: Icons.mic_none, |
|
|
? AppColors.primary |
|
|
color: controller.isListening.value |
|
|
: Colors.grey.shade400, |
|
|
? AppColors.primary |
|
|
size: 28.r, |
|
|
: Colors.grey.shade400, |
|
|
)), |
|
|
size: 28.r, |
|
|
), |
|
|
)), |
|
|
), |
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
// 中间音频波形和状态文本 |
|
|
// 中间音频波形和状态文本 |
|
|
Expanded( |
|
|
Expanded( |
|
|
child: Column( |
|
|
child: Column( |
|
|
mainAxisSize: MainAxisSize.min, |
|
|
mainAxisSize: MainAxisSize.min, |
|
|
mainAxisAlignment: MainAxisAlignment.center, |
|
|
mainAxisAlignment: MainAxisAlignment.center, |
|
|
children: [ |
|
|
children: [ |
|
|
// 音频波形区域 |
|
|
// 音频波形区域 |
|
|
Container( |
|
|
Container( |
|
|
height: 50.h, |
|
|
height: 50.h, |
|
|
child: Obx(() { |
|
|
child: Obx(() { |
|
|
final isSpeaking = controller.isSpeechDetected.value; |
|
|
final isSpeaking = |
|
|
return Center( |
|
|
controller.isSpeechDetected.value; |
|
|
child: Container( |
|
|
return Center( |
|
|
width: 220.w, |
|
|
child: Container( |
|
|
height: 30.h, |
|
|
width: 220.w, |
|
|
child: Row( |
|
|
height: 30.h, |
|
|
mainAxisSize: MainAxisSize.min, |
|
|
child: Row( |
|
|
mainAxisAlignment: MainAxisAlignment.center, |
|
|
mainAxisSize: MainAxisSize.min, |
|
|
children: List.generate( |
|
|
mainAxisAlignment: MainAxisAlignment.center, |
|
|
23, |
|
|
children: List.generate( |
|
|
(index) { |
|
|
23, |
|
|
// 随机高度模拟波形 |
|
|
(index) { |
|
|
double height = isSpeaking |
|
|
// 随机高度模拟波形 |
|
|
? (Random().nextDouble() * 20.0 + 5.0).h |
|
|
double height = isSpeaking |
|
|
: 2.h; |
|
|
? (Random().nextDouble() * 20.0 + |
|
|
|
|
|
5.0) |
|
|
|
|
|
.h |
|
|
|
|
|
: 2.h; |
|
|
|
|
|
|
|
|
return SizedBox( |
|
|
return SizedBox( |
|
|
width: 6.w, |
|
|
width: 6.w, |
|
|
child: Center( |
|
|
child: Center( |
|
|
child: AnimatedContainer( |
|
|
child: AnimatedContainer( |
|
|
duration: Duration(milliseconds: 500), |
|
|
duration: const Duration( |
|
|
width: 2.5.w, |
|
|
milliseconds: 500), |
|
|
height: height, |
|
|
width: 2.5.w, |
|
|
margin: EdgeInsets.symmetric( |
|
|
height: height, |
|
|
horizontal: 1.5.w), |
|
|
margin: EdgeInsets.symmetric( |
|
|
decoration: BoxDecoration( |
|
|
horizontal: 1.5.w), |
|
|
color: isSpeaking |
|
|
decoration: BoxDecoration( |
|
|
? AppColors.primary |
|
|
color: isSpeaking |
|
|
: isDarkMode |
|
|
? AppColors.primary |
|
|
? Colors.grey.shade600 |
|
|
: isDarkMode |
|
|
: Colors.grey.shade400, |
|
|
? Colors.grey.shade600 |
|
|
borderRadius: |
|
|
: Colors.grey.shade400, |
|
|
BorderRadius.circular(2.r), |
|
|
borderRadius: |
|
|
|
|
|
BorderRadius.circular(2.r), |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
); |
|
|
), |
|
|
}, |
|
|
); |
|
|
), |
|
|
}, |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
); |
|
|
), |
|
|
}), |
|
|
); |
|
|
), |
|
|
}), |
|
|
|
|
|
), |
|
|
|
|
|
SizedBox(height: 8.h), |
|
|
|
|
|
|
|
|
|
|
|
// 语音状态文本 |
|
|
// 语音状态文本 |
|
|
Obx(() => Text( |
|
|
Obx(() => Text( |
|
|
controller.isSpeechDetected.value |
|
|
controller.isSpeechDetected.value |
|
|
? 'imListening'.tr // 正在聆听... |
|
|
? 'imListening'.tr // 正在聆听... |
|
|
: 'canStartTalking'.tr, // 你可以开始说话 |
|
|
: 'canStartTalking'.tr, // 你可以开始说话 |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
fontSize: 14.sp, |
|
|
fontSize: 14.sp, |
|
|
color: isDarkMode |
|
|
color: isDarkMode |
|
|
? Colors.grey[400] |
|
|
? Colors.grey[400] |
|
|
: Colors.grey[700], |
|
|
: Colors.grey[700], |
|
|
fontWeight: FontWeight.w500, |
|
|
fontWeight: FontWeight.w500, |
|
|
), |
|
|
), |
|
|
)), |
|
|
)), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
// 关闭按钮 |
|
|
// 关闭按钮 |
|
|
Container( |
|
|
Container( |
|
|
width: 60.r, |
|
|
width: 60.r, |
|
|
height: 60.r, |
|
|
height: 60.r, |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: isDarkMode |
|
|
color: isDarkMode |
|
|
? Colors.white.withOpacity(0.1) |
|
|
? Colors.white.withOpacity(0.1) |
|
|
: Colors.white, |
|
|
: Colors.white, |
|
|
shape: BoxShape.circle, |
|
|
shape: BoxShape.circle, |
|
|
boxShadow: [ |
|
|
boxShadow: [ |
|
|
BoxShadow( |
|
|
BoxShadow( |
|
|
color: Colors.black.withOpacity(0.1), |
|
|
color: Colors.black.withOpacity(0.1), |
|
|
blurRadius: 8, |
|
|
blurRadius: 8, |
|
|
spreadRadius: 1, |
|
|
spreadRadius: 1, |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
], |
|
|
child: Center( |
|
|
), |
|
|
child: IconButton( |
|
|
child: Center( |
|
|
icon: Icon( |
|
|
child: IconButton( |
|
|
Icons.close, |
|
|
icon: Icon( |
|
|
color: isDarkMode |
|
|
Icons.close, |
|
|
? Colors.white |
|
|
color: isDarkMode ? Colors.white : Colors.grey.shade600, |
|
|
: Colors.grey.shade600, |
|
|
size: 28.r, |
|
|
size: 28.r, |
|
|
|
|
|
), |
|
|
|
|
|
padding: EdgeInsets.zero, |
|
|
|
|
|
onPressed: controller.stopVoiceRecognition, |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
padding: EdgeInsets.zero, |
|
|
|
|
|
onPressed: controller.stopVoiceRecognition, |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
], |
|
|
), |
|
|
), |
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
); |
|
|
); |
|
|
@ -683,7 +695,7 @@ class ChatView extends GetView<ChatController> { |
|
|
BoxShadow( |
|
|
BoxShadow( |
|
|
color: Colors.black.withOpacity(0.05), |
|
|
color: Colors.black.withOpacity(0.05), |
|
|
blurRadius: 2, |
|
|
blurRadius: 2, |
|
|
offset: Offset(0, 1), |
|
|
offset: const Offset(0, 1), |
|
|
), |
|
|
), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
@ -721,7 +733,7 @@ class ChatView extends GetView<ChatController> { |
|
|
// 构建加载动画点 |
|
|
// 构建加载动画点 |
|
|
Widget _buildLoadingDot(int index, bool isDarkMode) { |
|
|
Widget _buildLoadingDot(int index, bool isDarkMode) { |
|
|
return AnimatedBuilder( |
|
|
return AnimatedBuilder( |
|
|
animation: AlwaysStoppedAnimation(0), |
|
|
animation: const AlwaysStoppedAnimation(0), |
|
|
builder: (context, child) { |
|
|
builder: (context, child) { |
|
|
return Container( |
|
|
return Container( |
|
|
margin: EdgeInsets.symmetric(horizontal: 2.w), |
|
|
margin: EdgeInsets.symmetric(horizontal: 2.w), |
|
|
|