|
|
@ -14,15 +14,14 @@ class AgentView extends StatelessWidget { |
|
|
final primaryColor = theme.primaryColor; |
|
|
final primaryColor = theme.primaryColor; |
|
|
final backgroundColor = theme.scaffoldBackgroundColor; |
|
|
final backgroundColor = theme.scaffoldBackgroundColor; |
|
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
|
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
|
|
|
|
|
|
|
|
return Scaffold( |
|
|
return Scaffold( |
|
|
appBar: AppBar( |
|
|
appBar: AppBar( |
|
|
elevation: 1, |
|
|
elevation: 1, |
|
|
backgroundColor: backgroundColor, |
|
|
backgroundColor: backgroundColor, |
|
|
leading: IconButton( |
|
|
leading: IconButton( |
|
|
icon: Icon(Icons.arrow_back_ios, |
|
|
icon: Icon(Icons.arrow_back_ios, |
|
|
color: isDarkMode ? Colors.white : Colors.black87, |
|
|
color: isDarkMode ? Colors.white : Colors.black87, size: 20), |
|
|
size: 20), |
|
|
|
|
|
onPressed: () => Get.back(), |
|
|
onPressed: () => Get.back(), |
|
|
), |
|
|
), |
|
|
titleSpacing: 0, |
|
|
titleSpacing: 0, |
|
|
@ -53,7 +52,7 @@ class AgentView extends StatelessWidget { |
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
children: [ |
|
|
children: [ |
|
|
Text( |
|
|
Text( |
|
|
'DeepVoice AI', |
|
|
'Emma', |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
fontSize: 16, |
|
|
fontSize: 16, |
|
|
fontWeight: FontWeight.bold, |
|
|
fontWeight: FontWeight.bold, |
|
|
@ -72,7 +71,7 @@ class AgentView extends StatelessWidget { |
|
|
), |
|
|
), |
|
|
const SizedBox(width: 4), |
|
|
const SizedBox(width: 4), |
|
|
Text( |
|
|
Text( |
|
|
'在线', |
|
|
'在线'.tr, |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
fontSize: 12, |
|
|
fontSize: 12, |
|
|
color: Colors.green, |
|
|
color: Colors.green, |
|
|
@ -88,26 +87,27 @@ class AgentView extends StatelessWidget { |
|
|
actions: [ |
|
|
actions: [ |
|
|
// TTS开关 |
|
|
// TTS开关 |
|
|
Obx(() => IconButton( |
|
|
Obx(() => IconButton( |
|
|
icon: Icon( |
|
|
icon: Icon( |
|
|
controller.isTtsEnabled.value |
|
|
controller.isTtsEnabled.value |
|
|
? Icons.volume_up |
|
|
? Icons.volume_up |
|
|
: Icons.volume_off, |
|
|
: Icons.volume_off, |
|
|
color: controller.isTtsEnabled.value |
|
|
color: controller.isTtsEnabled.value |
|
|
? primaryColor |
|
|
? primaryColor |
|
|
: isDarkMode |
|
|
: isDarkMode |
|
|
? Colors.grey[400] |
|
|
? Colors.grey[400] |
|
|
: Colors.grey, |
|
|
: Colors.grey, |
|
|
), |
|
|
), |
|
|
onPressed: () => controller.toggleTts(), |
|
|
onPressed: () => controller.toggleTts(), |
|
|
)), |
|
|
)), |
|
|
|
|
|
|
|
|
// 更多选项 |
|
|
// 更多选项 |
|
|
Container( |
|
|
Container( |
|
|
width: 34, |
|
|
width: 34, |
|
|
height: 34, |
|
|
height: 34, |
|
|
margin: const EdgeInsets.only(right: 8), |
|
|
margin: const EdgeInsets.only(right: 8), |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100], |
|
|
color: |
|
|
|
|
|
isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[100], |
|
|
shape: BoxShape.circle, |
|
|
shape: BoxShape.circle, |
|
|
boxShadow: [ |
|
|
boxShadow: [ |
|
|
if (!isDarkMode) |
|
|
if (!isDarkMode) |
|
|
@ -119,9 +119,8 @@ class AgentView extends StatelessWidget { |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
child: PopupMenuButton( |
|
|
child: PopupMenuButton( |
|
|
icon: Icon(Icons.more_vert, |
|
|
icon: Icon(Icons.more_vert, |
|
|
color: isDarkMode ? Colors.white : Colors.black87, |
|
|
color: isDarkMode ? Colors.white : Colors.black87, size: 20), |
|
|
size: 20), |
|
|
|
|
|
shape: RoundedRectangleBorder( |
|
|
shape: RoundedRectangleBorder( |
|
|
borderRadius: BorderRadius.circular(12), |
|
|
borderRadius: BorderRadius.circular(12), |
|
|
), |
|
|
), |
|
|
@ -132,7 +131,7 @@ class AgentView extends StatelessWidget { |
|
|
children: [ |
|
|
children: [ |
|
|
Icon(Icons.delete_outline, color: primaryColor, size: 20), |
|
|
Icon(Icons.delete_outline, color: primaryColor, size: 20), |
|
|
const SizedBox(width: 8), |
|
|
const SizedBox(width: 8), |
|
|
const Text('清除聊天记录', style: TextStyle(fontSize: 14)), |
|
|
Text('清除聊天记录'.tr, style: TextStyle(fontSize: 14)), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
onTap: () => Future.delayed( |
|
|
onTap: () => Future.delayed( |
|
|
@ -153,10 +152,12 @@ class AgentView extends StatelessWidget { |
|
|
() => ListView.builder( |
|
|
() => ListView.builder( |
|
|
controller: controller.scrollController, |
|
|
controller: controller.scrollController, |
|
|
reverse: true, |
|
|
reverse: true, |
|
|
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16), |
|
|
padding: |
|
|
|
|
|
const EdgeInsets.symmetric(vertical: 16, horizontal: 16), |
|
|
itemCount: controller.messages.length, |
|
|
itemCount: controller.messages.length, |
|
|
itemBuilder: (context, index) { |
|
|
itemBuilder: (context, index) { |
|
|
final message = controller.messages[controller.messages.length - 1 - index]; |
|
|
final message = controller |
|
|
|
|
|
.messages[controller.messages.length - 1 - index]; |
|
|
return Padding( |
|
|
return Padding( |
|
|
padding: const EdgeInsets.only(bottom: 8), |
|
|
padding: const EdgeInsets.only(bottom: 8), |
|
|
child: MessageBubble( |
|
|
child: MessageBubble( |
|
|
@ -245,19 +246,19 @@ class AgentView extends StatelessWidget { |
|
|
children: [ |
|
|
children: [ |
|
|
_buildPromptChip( |
|
|
_buildPromptChip( |
|
|
context: context, |
|
|
context: context, |
|
|
label: '总结图片内容', |
|
|
label: '总结图片内容'.tr, |
|
|
onTap: () => controller.summarizeImage(), |
|
|
onTap: () => controller.summarizeImage(), |
|
|
), |
|
|
), |
|
|
const SizedBox(width: 8), |
|
|
const SizedBox(width: 8), |
|
|
_buildPromptChip( |
|
|
_buildPromptChip( |
|
|
context: context, |
|
|
context: context, |
|
|
label: '抽取图像文字', |
|
|
label: '抽取图像文字'.tr, |
|
|
onTap: () => controller.extractTextFromImage(), |
|
|
onTap: () => controller.extractTextFromImage(), |
|
|
), |
|
|
), |
|
|
const SizedBox(width: 8), |
|
|
const SizedBox(width: 8), |
|
|
_buildPromptChip( |
|
|
_buildPromptChip( |
|
|
context: context, |
|
|
context: context, |
|
|
label: '翻译图像文字', |
|
|
label: '翻译图像文字'.tr, |
|
|
onTap: () => controller.translateImageText(), |
|
|
onTap: () => controller.translateImageText(), |
|
|
), |
|
|
), |
|
|
], |
|
|
], |
|
|
@ -307,6 +308,7 @@ class AgentView extends StatelessWidget { |
|
|
if (isTextMode) { |
|
|
if (isTextMode) { |
|
|
// 文本输入模式 - 注意观察图片模式时的高度变化 |
|
|
// 文本输入模式 - 注意观察图片模式时的高度变化 |
|
|
return Container( |
|
|
return Container( |
|
|
|
|
|
height: 44, |
|
|
padding: const EdgeInsets.symmetric(horizontal: 16), |
|
|
padding: const EdgeInsets.symmetric(horizontal: 16), |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: Colors.grey[200], |
|
|
color: Colors.grey[200], |
|
|
@ -330,7 +332,9 @@ class AgentView extends StatelessWidget { |
|
|
minLines: isImageActive ? 2 : 1, |
|
|
minLines: isImageActive ? 2 : 1, |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
fontSize: 15, |
|
|
fontSize: 15, |
|
|
color: isDarkMode ? Colors.white : Colors.black87, |
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.white |
|
|
|
|
|
: Colors.black87, |
|
|
), |
|
|
), |
|
|
decoration: InputDecoration( |
|
|
decoration: InputDecoration( |
|
|
hintText: isImageActive |
|
|
hintText: isImageActive |
|
|
@ -470,7 +474,8 @@ class AgentView extends StatelessWidget { |
|
|
Icon(Icons.camera_alt, |
|
|
Icon(Icons.camera_alt, |
|
|
color: primaryColor, size: 20), |
|
|
color: primaryColor, size: 20), |
|
|
const SizedBox(width: 8), |
|
|
const SizedBox(width: 8), |
|
|
const Text('拍照', style: TextStyle(fontSize: 14)), |
|
|
const Text('拍照', |
|
|
|
|
|
style: TextStyle(fontSize: 14)), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
@ -481,7 +486,8 @@ class AgentView extends StatelessWidget { |
|
|
Icon(Icons.photo_library, |
|
|
Icon(Icons.photo_library, |
|
|
color: primaryColor, size: 20), |
|
|
color: primaryColor, size: 20), |
|
|
const SizedBox(width: 8), |
|
|
const SizedBox(width: 8), |
|
|
const Text('从相册选择', style: TextStyle(fontSize: 14)), |
|
|
const Text('从相册选择', |
|
|
|
|
|
style: TextStyle(fontSize: 14)), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
@ -506,7 +512,7 @@ class AgentView extends StatelessWidget { |
|
|
}) { |
|
|
}) { |
|
|
final theme = Theme.of(context); |
|
|
final theme = Theme.of(context); |
|
|
final primaryColor = theme.primaryColor; |
|
|
final primaryColor = theme.primaryColor; |
|
|
|
|
|
|
|
|
return GestureDetector( |
|
|
return GestureDetector( |
|
|
onTap: onTap, |
|
|
onTap: onTap, |
|
|
child: Container( |
|
|
child: Container( |
|
|
@ -614,14 +620,14 @@ class _SoundBarState extends State<_SoundBar> |
|
|
@override |
|
|
@override |
|
|
Widget build(BuildContext context) { |
|
|
Widget build(BuildContext context) { |
|
|
final primaryColor = Theme.of(context).primaryColor; |
|
|
final primaryColor = Theme.of(context).primaryColor; |
|
|
|
|
|
|
|
|
return Container( |
|
|
return Container( |
|
|
width: 2.5, |
|
|
width: 2.5, |
|
|
height: widget.isActive ? _animation.value : 3, |
|
|
height: widget.isActive ? _animation.value : 3, |
|
|
margin: const EdgeInsets.symmetric(horizontal: 1), |
|
|
margin: const EdgeInsets.symmetric(horizontal: 1), |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: widget.isActive |
|
|
color: widget.isActive |
|
|
? primaryColor.withOpacity(0.8) |
|
|
? primaryColor.withOpacity(0.8) |
|
|
: Colors.grey.withOpacity(0.4), |
|
|
: Colors.grey.withOpacity(0.4), |
|
|
borderRadius: BorderRadius.circular(1.5), |
|
|
borderRadius: BorderRadius.circular(1.5), |
|
|
), |
|
|
), |
|
|
|