|
|
@ -197,8 +197,8 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
controller: controller.scrollController, |
|
|
controller: controller.scrollController, |
|
|
shrinkWrap: true, |
|
|
shrinkWrap: true, |
|
|
reverse: true, |
|
|
reverse: true, |
|
|
padding: |
|
|
padding: const EdgeInsets.symmetric( |
|
|
const EdgeInsets.symmetric(vertical: 16, horizontal: 16), |
|
|
vertical: 16, horizontal: 16), |
|
|
itemCount: controller.messages.length, |
|
|
itemCount: controller.messages.length, |
|
|
itemBuilder: (context, index) { |
|
|
itemBuilder: (context, index) { |
|
|
final message = controller |
|
|
final message = controller |
|
|
@ -206,7 +206,8 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
return Padding( |
|
|
return Padding( |
|
|
padding: const EdgeInsets.only(bottom: 8), |
|
|
padding: const EdgeInsets.only(bottom: 8), |
|
|
child: GestureDetector( |
|
|
child: GestureDetector( |
|
|
onLongPressStart: (LongPressStartDetails details) { |
|
|
onLongPressStart: |
|
|
|
|
|
(LongPressStartDetails details) { |
|
|
messageActionController.onLongPressMessage( |
|
|
messageActionController.onLongPressMessage( |
|
|
context, isDarkMode, details, message); |
|
|
context, isDarkMode, details, message); |
|
|
}, |
|
|
}, |
|
|
@ -228,7 +229,8 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
|
|
|
|
|
|
// 输入区域 |
|
|
// 输入区域 |
|
|
Container( |
|
|
Container( |
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), |
|
|
padding: |
|
|
|
|
|
const EdgeInsets.symmetric(horizontal: 16, vertical: 12), |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: backgroundColor, |
|
|
color: backgroundColor, |
|
|
boxShadow: [ |
|
|
boxShadow: [ |
|
|
@ -304,13 +306,15 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
_buildPromptChip( |
|
|
_buildPromptChip( |
|
|
context: context, |
|
|
context: context, |
|
|
label: '抽取图像文字'.tr, |
|
|
label: '抽取图像文字'.tr, |
|
|
onTap: () => controller.extractTextFromImage(), |
|
|
onTap: () => |
|
|
|
|
|
controller.extractTextFromImage(), |
|
|
), |
|
|
), |
|
|
const SizedBox(width: 8), |
|
|
const SizedBox(width: 8), |
|
|
_buildPromptChip( |
|
|
_buildPromptChip( |
|
|
context: context, |
|
|
context: context, |
|
|
label: '翻译图像文字'.tr, |
|
|
label: '翻译图像文字'.tr, |
|
|
onTap: () => controller.translateImageText(), |
|
|
onTap: () => |
|
|
|
|
|
controller.translateImageText(), |
|
|
), |
|
|
), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
@ -329,11 +333,13 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
// 输入控件行 - 使用IntrinsicHeight确保按钮与输入框底部对齐 |
|
|
// 输入控件行 - 使用IntrinsicHeight确保按钮与输入框底部对齐 |
|
|
IntrinsicHeight( |
|
|
IntrinsicHeight( |
|
|
child: Row( |
|
|
child: Row( |
|
|
crossAxisAlignment: CrossAxisAlignment.end, // 所有元素底部对齐 |
|
|
crossAxisAlignment: |
|
|
|
|
|
CrossAxisAlignment.end, // 所有元素底部对齐 |
|
|
children: [ |
|
|
children: [ |
|
|
// 键盘/语音切换按钮 |
|
|
// 键盘/语音切换按钮 |
|
|
Obx(() { |
|
|
Obx(() { |
|
|
final isTextMode = controller.isTextInputMode.value; |
|
|
final isTextMode = |
|
|
|
|
|
controller.isTextInputMode.value; |
|
|
return GestureDetector( |
|
|
return GestureDetector( |
|
|
onTap: () { |
|
|
onTap: () { |
|
|
controller.toggleInputMode(); |
|
|
controller.toggleInputMode(); |
|
|
@ -348,7 +354,9 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
borderRadius: BorderRadius.circular(22), |
|
|
borderRadius: BorderRadius.circular(22), |
|
|
), |
|
|
), |
|
|
child: Icon( |
|
|
child: Icon( |
|
|
isTextMode ? Icons.mic_none : Icons.keyboard, |
|
|
isTextMode |
|
|
|
|
|
? Icons.mic_none |
|
|
|
|
|
: Icons.keyboard, |
|
|
color: isDarkMode |
|
|
color: isDarkMode |
|
|
? Colors.grey[300] |
|
|
? Colors.grey[300] |
|
|
: Colors.grey[700], |
|
|
: Colors.grey[700], |
|
|
@ -389,8 +397,8 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
child: Row( |
|
|
child: Row( |
|
|
crossAxisAlignment: |
|
|
crossAxisAlignment: CrossAxisAlignment |
|
|
CrossAxisAlignment.end, // 对齐到底部,实现向上扩展 |
|
|
.end, // 对齐到底部,实现向上扩展 |
|
|
children: [ |
|
|
children: [ |
|
|
Expanded( |
|
|
Expanded( |
|
|
child: Obx(() { |
|
|
child: Obx(() { |
|
|
@ -434,7 +442,8 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
), |
|
|
), |
|
|
filled: false, |
|
|
filled: false, |
|
|
border: InputBorder.none, |
|
|
border: InputBorder.none, |
|
|
focusedBorder: OutlineInputBorder( |
|
|
focusedBorder: |
|
|
|
|
|
OutlineInputBorder( |
|
|
borderSide: BorderSide( |
|
|
borderSide: BorderSide( |
|
|
color: isDarkMode |
|
|
color: isDarkMode |
|
|
? Colors.grey[800]! |
|
|
? Colors.grey[800]! |
|
|
@ -458,22 +467,24 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
); |
|
|
); |
|
|
} else { |
|
|
} else { |
|
|
// 语音输入模式 - 按住说话模式 |
|
|
// 语音输入模式 - 按住说话模式 |
|
|
return GestureDetector( |
|
|
return Listener( |
|
|
onLongPressStart: (_) { |
|
|
onPointerDown: (_) { |
|
|
// 开始按住说话 |
|
|
// 开始按住说话 |
|
|
controller.startPushToTalk(); |
|
|
controller.startPushToTalk(); |
|
|
}, |
|
|
}, |
|
|
onLongPressEnd: (_) { |
|
|
onPointerUp: (_) { |
|
|
// 结束按住说话 |
|
|
// 结束按住说话 |
|
|
controller.endPushToTalk(); |
|
|
controller.endPushToTalk(); |
|
|
}, |
|
|
}, |
|
|
onLongPressCancel: () { |
|
|
// onLongPressCancel: () { |
|
|
// 取消按住说话 |
|
|
// // 取消按住说话 |
|
|
controller.endPushToTalk(); |
|
|
// controller.endPushToTalk(); |
|
|
}, |
|
|
// }, |
|
|
child: Obx(() { |
|
|
child: Obx(() { |
|
|
final isPushToTalkActive = controller.isPushToTalkActive.value; |
|
|
final isPushToTalkActive = |
|
|
final isListening = controller.isListening.value; |
|
|
controller.isPushToTalkActive.value; |
|
|
|
|
|
final isListening = |
|
|
|
|
|
controller.isListening.value; |
|
|
|
|
|
|
|
|
return Container( |
|
|
return Container( |
|
|
height: 50, |
|
|
height: 50, |
|
|
@ -481,16 +492,24 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
horizontal: 16), |
|
|
horizontal: 16), |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: isPushToTalkActive |
|
|
color: isPushToTalkActive |
|
|
? (isDarkMode ? Colors.blue[900] : Colors.blue[100]) |
|
|
? (isDarkMode |
|
|
: (isDarkMode ? Colors.grey[800] : Colors.grey[200]), |
|
|
? Colors.blue[900] |
|
|
borderRadius: BorderRadius.circular(22), |
|
|
: Colors.blue[100]) |
|
|
|
|
|
: (isDarkMode |
|
|
|
|
|
? Colors.grey[800] |
|
|
|
|
|
: Colors.grey[200]), |
|
|
|
|
|
borderRadius: |
|
|
|
|
|
BorderRadius.circular(22), |
|
|
border: Border.all( |
|
|
border: Border.all( |
|
|
color: isPushToTalkActive |
|
|
color: isPushToTalkActive |
|
|
? Colors.blue |
|
|
? Colors.blue |
|
|
: (isDarkMode |
|
|
: (isDarkMode |
|
|
? Colors.grey[800]! |
|
|
? Colors.grey[800]! |
|
|
: Colors.grey.withOpacity(0.1)), |
|
|
: Colors.grey |
|
|
width: isPushToTalkActive ? 2.0 : 1.0, |
|
|
.withOpacity(0.1)), |
|
|
|
|
|
width: isPushToTalkActive |
|
|
|
|
|
? 2.0 |
|
|
|
|
|
: 1.0, |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
child: Row( |
|
|
child: Row( |
|
|
@ -498,18 +517,23 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
// 语音波形图 - 只在按住时显示 |
|
|
// 语音波形图 - 只在按住时显示 |
|
|
if (isPushToTalkActive) ...[ |
|
|
if (isPushToTalkActive) ...[ |
|
|
const AgentSoundBarsWidget(), |
|
|
const AgentSoundBarsWidget(), |
|
|
const Spacer(), |
|
|
//const Spacer(), |
|
|
], |
|
|
], |
|
|
|
|
|
|
|
|
// 状态文字和图标 |
|
|
// 状态文字和图标 |
|
|
Expanded( |
|
|
Expanded( |
|
|
child: Row( |
|
|
child: Row( |
|
|
mainAxisAlignment: isPushToTalkActive |
|
|
mainAxisAlignment: |
|
|
? MainAxisAlignment.end |
|
|
isPushToTalkActive |
|
|
: MainAxisAlignment.center, |
|
|
? MainAxisAlignment |
|
|
|
|
|
.center |
|
|
|
|
|
: MainAxisAlignment |
|
|
|
|
|
.center, |
|
|
children: [ |
|
|
children: [ |
|
|
Icon( |
|
|
Icon( |
|
|
isPushToTalkActive ? Icons.mic : Icons.mic_none, |
|
|
isPushToTalkActive |
|
|
|
|
|
? Icons.mic |
|
|
|
|
|
: Icons.mic_none, |
|
|
size: 16, |
|
|
size: 16, |
|
|
color: isPushToTalkActive |
|
|
color: isPushToTalkActive |
|
|
? Colors.blue |
|
|
? Colors.blue |
|
|
@ -522,10 +546,13 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
: '按住说话', |
|
|
: '按住说话', |
|
|
style: TextStyle( |
|
|
style: TextStyle( |
|
|
fontSize: 14, |
|
|
fontSize: 14, |
|
|
fontWeight: FontWeight.w500, |
|
|
fontWeight: |
|
|
color: isPushToTalkActive |
|
|
FontWeight.w500, |
|
|
|
|
|
color: |
|
|
|
|
|
isPushToTalkActive |
|
|
? Colors.blue |
|
|
? Colors.blue |
|
|
: Colors.grey[600], |
|
|
: Colors |
|
|
|
|
|
.grey[600], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
], |
|
|
], |
|
|
@ -568,12 +595,14 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
showModalBottomSheet( |
|
|
showModalBottomSheet( |
|
|
context: context, |
|
|
context: context, |
|
|
isScrollControlled: true, |
|
|
isScrollControlled: true, |
|
|
backgroundColor: Colors.transparent, |
|
|
backgroundColor: |
|
|
|
|
|
Colors.transparent, |
|
|
builder: (context) => |
|
|
builder: (context) => |
|
|
const FullScreenEditor(), |
|
|
const FullScreenEditor(), |
|
|
).then((_) { |
|
|
).then((_) { |
|
|
// 弹出页关闭时的回调 |
|
|
// 弹出页关闭时的回调 |
|
|
controller.closeFullScreenEdit(); |
|
|
controller |
|
|
|
|
|
.closeFullScreenEdit(); |
|
|
}); |
|
|
}); |
|
|
}, |
|
|
}, |
|
|
child: Container( |
|
|
child: Container( |
|
|
@ -604,7 +633,8 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
height: 44, |
|
|
height: 44, |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: primaryColor, |
|
|
color: primaryColor, |
|
|
borderRadius: BorderRadius.circular(22), |
|
|
borderRadius: |
|
|
|
|
|
BorderRadius.circular(22), |
|
|
), |
|
|
), |
|
|
child: const Icon( |
|
|
child: const Icon( |
|
|
Icons.send, |
|
|
Icons.send, |
|
|
@ -631,7 +661,8 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
color: isDarkMode |
|
|
color: isDarkMode |
|
|
? Colors.grey[800] |
|
|
? Colors.grey[800] |
|
|
: Colors.grey[200], |
|
|
: Colors.grey[200], |
|
|
borderRadius: BorderRadius.circular(22), |
|
|
borderRadius: |
|
|
|
|
|
BorderRadius.circular(22), |
|
|
), |
|
|
), |
|
|
child: Icon( |
|
|
child: Icon( |
|
|
isExpanded ? Icons.close : Icons.add, |
|
|
isExpanded ? Icons.close : Icons.add, |
|
|
@ -660,9 +691,11 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
child: isExpanded |
|
|
child: isExpanded |
|
|
? Container( |
|
|
? Container( |
|
|
margin: EdgeInsets.only(top: 8.h), |
|
|
margin: EdgeInsets.only(top: 8.h), |
|
|
padding: EdgeInsets.symmetric(horizontal:16.w), // 添加左右边距 |
|
|
padding: EdgeInsets.symmetric( |
|
|
|
|
|
horizontal: 16.w), // 添加左右边距 |
|
|
child: Row( |
|
|
child: Row( |
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly, // 改为均匀分布 |
|
|
mainAxisAlignment: MainAxisAlignment |
|
|
|
|
|
.spaceEvenly, // 改为均匀分布 |
|
|
children: [ |
|
|
children: [ |
|
|
// 相机按钮 |
|
|
// 相机按钮 |
|
|
_buildPlusOptionButton( |
|
|
_buildPlusOptionButton( |
|
|
@ -734,12 +767,6 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 构建提示选项芯片 |
|
|
// 构建提示选项芯片 |
|
|
Widget _buildPromptChip({ |
|
|
Widget _buildPromptChip({ |
|
|
required BuildContext context, |
|
|
required BuildContext context, |
|
|
@ -773,8 +800,6 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 构建"+"号展开选项按钮 |
|
|
// 构建"+"号展开选项按钮 |
|
|
Widget _buildPlusOptionButton({ |
|
|
Widget _buildPlusOptionButton({ |
|
|
required BuildContext context, |
|
|
required BuildContext context, |
|
|
@ -923,7 +948,8 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
children: [ |
|
|
children: [ |
|
|
// 音频可视化圆圈 |
|
|
// 音频可视化圆圈 |
|
|
Obx(() { |
|
|
Obx(() { |
|
|
final isActive = controller.isListening.value || controller.isSpeaking.value; |
|
|
final isActive = |
|
|
|
|
|
controller.isListening.value || controller.isSpeaking.value; |
|
|
return AnimatedContainer( |
|
|
return AnimatedContainer( |
|
|
duration: const Duration(milliseconds: 300), |
|
|
duration: const Duration(milliseconds: 300), |
|
|
width: isActive ? 200 : 160, |
|
|
width: isActive ? 200 : 160, |
|
|
@ -982,7 +1008,9 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
children: [ |
|
|
children: [ |
|
|
// 静音按钮 |
|
|
// 静音按钮 |
|
|
Obx(() => _buildPhoneControlButton( |
|
|
Obx(() => _buildPhoneControlButton( |
|
|
icon: controller.isTtsEnabled.value ? Icons.volume_up : Icons.volume_off, |
|
|
icon: controller.isTtsEnabled.value |
|
|
|
|
|
? Icons.volume_up |
|
|
|
|
|
: Icons.volume_off, |
|
|
onTap: () => controller.toggleTts(), |
|
|
onTap: () => controller.toggleTts(), |
|
|
isDarkMode: isDarkMode, |
|
|
isDarkMode: isDarkMode, |
|
|
isActive: controller.isTtsEnabled.value, |
|
|
isActive: controller.isTtsEnabled.value, |
|
|
@ -1007,7 +1035,8 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
color: isActive ? Colors.red : Colors.green, |
|
|
color: isActive ? Colors.red : Colors.green, |
|
|
boxShadow: [ |
|
|
boxShadow: [ |
|
|
BoxShadow( |
|
|
BoxShadow( |
|
|
color: (isActive ? Colors.red : Colors.green).withOpacity(0.3), |
|
|
color: (isActive ? Colors.red : Colors.green) |
|
|
|
|
|
.withOpacity(0.3), |
|
|
blurRadius: 12, |
|
|
blurRadius: 12, |
|
|
spreadRadius: 2, |
|
|
spreadRadius: 2, |
|
|
), |
|
|
), |
|
|
@ -1050,7 +1079,8 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
height: 56, |
|
|
height: 56, |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
shape: BoxShape.circle, |
|
|
shape: BoxShape.circle, |
|
|
color: backgroundColor ?? (isDarkMode ? Colors.grey[800] : Colors.grey[200]), |
|
|
color: backgroundColor ?? |
|
|
|
|
|
(isDarkMode ? Colors.grey[800] : Colors.grey[200]), |
|
|
border: isActive ? Border.all(color: Colors.blue, width: 2) : null, |
|
|
border: isActive ? Border.all(color: Colors.blue, width: 2) : null, |
|
|
), |
|
|
), |
|
|
child: Icon( |
|
|
child: Icon( |
|
|
@ -1064,7 +1094,3 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|