|
|
@ -339,14 +339,12 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
child: Column( |
|
|
child: Column( |
|
|
mainAxisSize: MainAxisSize.min, |
|
|
|
|
|
children: [ |
|
|
children: [ |
|
|
// 图片预览区域 - 仅在图片输入模式下显示 |
|
|
// 图片预览区域 - 仅在图片输入模式下显示 |
|
|
Obx(() { |
|
|
Obx(() { |
|
|
if (controller.isImageInputActive.value && |
|
|
if (controller.isImageInputActive.value && |
|
|
controller.selectedImagePath.value != null) { |
|
|
controller.selectedImagePath.value != null) { |
|
|
return Column( |
|
|
return Column( |
|
|
mainAxisSize: MainAxisSize.min, |
|
|
|
|
|
children: [ |
|
|
children: [ |
|
|
// 图片预览和关闭按钮 |
|
|
// 图片预览和关闭按钮 |
|
|
Stack( |
|
|
Stack( |
|
|
@ -421,454 +419,432 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver { |
|
|
// 输入控件区域 - 包含输入行和展开的选项 |
|
|
// 输入控件区域 - 包含输入行和展开的选项 |
|
|
Column( |
|
|
Column( |
|
|
children: [ |
|
|
children: [ |
|
|
// 输入控件行 - 使用IntrinsicHeight确保按钮与输入框底部对齐 |
|
|
Row( |
|
|
IntrinsicHeight( |
|
|
crossAxisAlignment: |
|
|
child: Row( |
|
|
CrossAxisAlignment.end, // 所有元素底部对齐 |
|
|
crossAxisAlignment: |
|
|
children: [ |
|
|
CrossAxisAlignment.end, // 所有元素底部对齐 |
|
|
// 键盘/语音切换按钮 |
|
|
children: [ |
|
|
Obx(() { |
|
|
// 键盘/语音切换按钮 |
|
|
final isTextMode = |
|
|
Obx(() { |
|
|
controller.isTextInputMode.value; |
|
|
final isTextMode = |
|
|
return GestureDetector( |
|
|
controller.isTextInputMode.value; |
|
|
onTap: () { |
|
|
return GestureDetector( |
|
|
controller.toggleInputMode(); |
|
|
onTap: () { |
|
|
}, |
|
|
controller.toggleInputMode(); |
|
|
child: Container( |
|
|
}, |
|
|
width: 44.w, |
|
|
child: Container( |
|
|
height: 44.w, |
|
|
width: 44.w, |
|
|
margin: EdgeInsets.symmetric(vertical: 2.w), |
|
|
height: 44.w, |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
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( |
|
|
|
|
|
isTextMode |
|
|
|
|
|
? Icons.mic_none |
|
|
|
|
|
: Icons.keyboard, |
|
|
|
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.grey[300] |
|
|
|
|
|
: Colors.grey[700], |
|
|
|
|
|
size: 22.sp, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
), |
|
|
); |
|
|
child: Icon( |
|
|
}), |
|
|
isTextMode |
|
|
|
|
|
? Icons.mic_none |
|
|
|
|
|
: Icons.keyboard, |
|
|
|
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.grey[300] |
|
|
|
|
|
: Colors.grey[700], |
|
|
|
|
|
size: 22.sp, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
}), |
|
|
|
|
|
|
|
|
SizedBox(width: 8.w), |
|
|
SizedBox(width: 8.w), |
|
|
|
|
|
|
|
|
// 文本输入框或语音波形图 |
|
|
// 文本输入框或语音波形图 |
|
|
Expanded( |
|
|
Expanded( |
|
|
child: Obx(() { |
|
|
child: Obx(() { |
|
|
final isTextMode = |
|
|
final isTextMode = |
|
|
controller.isTextInputMode.value; |
|
|
controller.isTextInputMode.value; |
|
|
|
|
|
|
|
|
if (controller.isTextInputMode.value) { |
|
|
if (controller.isTextInputMode.value) { |
|
|
// 文本输入模式 - 限制最大高度并只向上扩展 |
|
|
// 文本输入模式 - 限制最大高度并只向上扩展 |
|
|
return IntroStepBuilder( |
|
|
return IntroStepBuilder( |
|
|
group: 'ai', |
|
|
group: 'ai', |
|
|
order: 1, |
|
|
order: 1, |
|
|
overlayBuilder: (params) { |
|
|
overlayBuilder: (params) { |
|
|
return IntroOverlayBuilder.aiBuilder( |
|
|
return IntroOverlayBuilder.aiBuilder( |
|
|
params, |
|
|
params, |
|
|
controller.noviceGuideService |
|
|
controller |
|
|
.aiStepsList[ |
|
|
.noviceGuideService.aiStepsList[ |
|
|
|
|
|
controller.noviceGuideService |
|
|
|
|
|
.aiStep]['start'], |
|
|
|
|
|
buttonText: '确定输入', |
|
|
|
|
|
onNext: () { |
|
|
|
|
|
controller.textController.text = |
|
|
controller.noviceGuideService |
|
|
controller.noviceGuideService |
|
|
.aiStep]['start'], |
|
|
.aiStepsList[ |
|
|
buttonText: '确定输入', |
|
|
controller.noviceGuideService |
|
|
onNext: () { |
|
|
.aiStep]['input']; |
|
|
controller.textController.text = |
|
|
}, |
|
|
controller.noviceGuideService |
|
|
); |
|
|
.aiStepsList[ |
|
|
}, |
|
|
controller |
|
|
onWidgetLoad: () { |
|
|
.noviceGuideService |
|
|
controller.noviceGuideService |
|
|
.aiStep]['input']; |
|
|
.startAIGuide(); |
|
|
|
|
|
}, |
|
|
|
|
|
builder: |
|
|
|
|
|
(BuildContext context, GlobalKey key) => |
|
|
|
|
|
Container( |
|
|
|
|
|
key: key, |
|
|
|
|
|
constraints: BoxConstraints( |
|
|
|
|
|
minHeight: 48.w, |
|
|
|
|
|
), |
|
|
|
|
|
padding: EdgeInsets.symmetric( |
|
|
|
|
|
horizontal: 16.w, |
|
|
|
|
|
vertical: 5.w, |
|
|
|
|
|
), |
|
|
|
|
|
alignment: Alignment.center, |
|
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.grey[800] |
|
|
|
|
|
: Colors.grey[200], |
|
|
|
|
|
borderRadius: |
|
|
|
|
|
BorderRadius.circular(22.w), |
|
|
|
|
|
border: Border.all( |
|
|
|
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.grey[800]! |
|
|
|
|
|
: Colors.grey.withOpacity(0.1), |
|
|
|
|
|
width: 1.w, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
child: Obx(() { |
|
|
|
|
|
// 图片模式下使用更高的输入框 |
|
|
|
|
|
final isImageActive = |
|
|
|
|
|
controller.isImageInputActive.value; |
|
|
|
|
|
|
|
|
|
|
|
return TextField( |
|
|
|
|
|
controller: controller.textController, |
|
|
|
|
|
maxLines: isImageActive |
|
|
|
|
|
? 3 |
|
|
|
|
|
: 5, // 设置合理的最大行数 |
|
|
|
|
|
minLines: isImageActive ? 2 : 1, |
|
|
|
|
|
keyboardType: |
|
|
|
|
|
TextInputType.multiline, // 启用多行键盘 |
|
|
|
|
|
textInputAction: |
|
|
|
|
|
TextInputAction.newline, // 支持回车换行 |
|
|
|
|
|
onTap: () { |
|
|
|
|
|
// 当点击输入框时,如果'+'选项已展开,则收缩 |
|
|
|
|
|
if (controller |
|
|
|
|
|
.isPlusOptionsExpanded.value) { |
|
|
|
|
|
controller.collapsePlusOptions(); |
|
|
|
|
|
} |
|
|
}, |
|
|
}, |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 15.sp, |
|
|
|
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.white |
|
|
|
|
|
: Colors.grey[800], |
|
|
|
|
|
), |
|
|
|
|
|
decoration: InputDecoration( |
|
|
|
|
|
hintText: isImageActive |
|
|
|
|
|
? 'addQuestionAboutImage' |
|
|
|
|
|
.tr // 添加对图片的问题或描述... |
|
|
|
|
|
: 'inputMessage'.tr, // 输入消息... |
|
|
|
|
|
hintStyle: TextStyle( |
|
|
|
|
|
color: Colors.grey[500], |
|
|
|
|
|
fontSize: 15.sp, |
|
|
|
|
|
), |
|
|
|
|
|
filled: false, |
|
|
|
|
|
isDense: true, |
|
|
|
|
|
border: InputBorder.none, |
|
|
|
|
|
focusedBorder: OutlineInputBorder( |
|
|
|
|
|
borderSide: BorderSide( |
|
|
|
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.grey[800]! |
|
|
|
|
|
: Colors.grey[200]!, |
|
|
|
|
|
width: 1.w, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
contentPadding: EdgeInsets.zero, |
|
|
|
|
|
), |
|
|
|
|
|
onSubmitted: (_) => |
|
|
|
|
|
controller.sendMessage(), |
|
|
); |
|
|
); |
|
|
}, |
|
|
}), |
|
|
onWidgetLoad: () { |
|
|
), |
|
|
controller.noviceGuideService |
|
|
); |
|
|
.startAIGuide(); |
|
|
} else { |
|
|
}, |
|
|
Timer? _holdTimer; // 增加延迟触发的计时器 |
|
|
builder: (BuildContext context, |
|
|
// 语音输入模式 - 按住说话模式 |
|
|
GlobalKey key) => |
|
|
return Listener( |
|
|
Container( |
|
|
onPointerDown: (_) { |
|
|
key: key, |
|
|
// 设置300ms延迟防止误触 |
|
|
constraints: BoxConstraints( |
|
|
_holdTimer = Timer( |
|
|
minHeight: 44.h, |
|
|
const Duration(milliseconds: 200), |
|
|
maxHeight: 120.h, |
|
|
() { |
|
|
), |
|
|
controller.startPushToTalk(); |
|
|
|
|
|
// if (activeSpeaker == 0) { |
|
|
|
|
|
// if (speakerId == 1) { |
|
|
|
|
|
// controller |
|
|
|
|
|
// .restoreOriginalAudioState(); |
|
|
|
|
|
// } else { |
|
|
|
|
|
// controller |
|
|
|
|
|
// .disableBluetoothAudio(); |
|
|
|
|
|
// } |
|
|
|
|
|
// controller |
|
|
|
|
|
// .setActiveSpeaker(speakerId); |
|
|
|
|
|
// } |
|
|
|
|
|
}); |
|
|
|
|
|
}, |
|
|
|
|
|
onPointerUp: (_) { |
|
|
|
|
|
_holdTimer?.cancel(); |
|
|
|
|
|
controller.endPushToTalk(); |
|
|
|
|
|
}, |
|
|
|
|
|
onPointerCancel: (_) { |
|
|
|
|
|
_holdTimer?.cancel(); |
|
|
|
|
|
controller.endPushToTalk(); |
|
|
|
|
|
}, |
|
|
|
|
|
// onLongPressStart: (_) { |
|
|
|
|
|
// // 开始按住说话 |
|
|
|
|
|
// controller.startPushToTalk(); |
|
|
|
|
|
// }, |
|
|
|
|
|
// onLongPressEnd: (_) { |
|
|
|
|
|
// // 结束按住说话 |
|
|
|
|
|
// controller.endPushToTalk(); |
|
|
|
|
|
// }, |
|
|
|
|
|
// onLongPressCancel: () { |
|
|
|
|
|
// // 取消按住说话 |
|
|
|
|
|
// controller.endPushToTalk(); |
|
|
|
|
|
// }, |
|
|
|
|
|
child: Obx(() { |
|
|
|
|
|
final isPushToTalkActive = |
|
|
|
|
|
controller.isPushToTalkActive.value; |
|
|
|
|
|
final isListening = |
|
|
|
|
|
controller.isListening.value; |
|
|
|
|
|
|
|
|
|
|
|
return Container( |
|
|
|
|
|
height: 48.w, |
|
|
padding: EdgeInsets.symmetric( |
|
|
padding: EdgeInsets.symmetric( |
|
|
horizontal: 16.w), |
|
|
horizontal: 16.w), |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: isDarkMode |
|
|
color: isPushToTalkActive |
|
|
? Colors.grey[800] |
|
|
? (isDarkMode |
|
|
: Colors.grey[200], |
|
|
? Colors.blue[900] |
|
|
|
|
|
: Colors.blue[100]) |
|
|
|
|
|
: (isDarkMode |
|
|
|
|
|
? Colors.grey[800] |
|
|
|
|
|
: Colors.grey[200]), |
|
|
borderRadius: |
|
|
borderRadius: |
|
|
BorderRadius.circular(22.w), |
|
|
BorderRadius.circular(22.w), |
|
|
border: Border.all( |
|
|
border: Border.all( |
|
|
color: isDarkMode |
|
|
color: isPushToTalkActive |
|
|
? Colors.grey[800]! |
|
|
? Colors.blue |
|
|
: Colors.grey.withOpacity(0.1), |
|
|
: (isDarkMode |
|
|
width: 1.w, |
|
|
? Colors.grey[800]! |
|
|
|
|
|
: Colors.grey |
|
|
|
|
|
.withOpacity(0.1)), |
|
|
|
|
|
width: |
|
|
|
|
|
isPushToTalkActive ? 2.w : 1.w, |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
child: Row( |
|
|
child: Row( |
|
|
crossAxisAlignment: CrossAxisAlignment |
|
|
|
|
|
.end, // 对齐到底部,实现向上扩展 |
|
|
|
|
|
children: [ |
|
|
children: [ |
|
|
Expanded( |
|
|
// 语音波形图 - 只在按住时显示 |
|
|
child: Obx(() { |
|
|
if (isPushToTalkActive) ...[ |
|
|
// 图片模式下使用更高的输入框 |
|
|
const AgentSoundBarsWidget(), |
|
|
final isImageActive = controller |
|
|
//const Spacer(), |
|
|
.isImageInputActive.value; |
|
|
], |
|
|
|
|
|
|
|
|
return TextField( |
|
|
// 状态文字和图标 |
|
|
controller: |
|
|
Expanded( |
|
|
controller.textController, |
|
|
child: Row( |
|
|
maxLines: isImageActive |
|
|
mainAxisAlignment: |
|
|
? 3 |
|
|
isPushToTalkActive |
|
|
: 5, // 设置合理的最大行数 |
|
|
? MainAxisAlignment |
|
|
minLines: |
|
|
.center |
|
|
isImageActive ? 2 : 1, |
|
|
: MainAxisAlignment |
|
|
keyboardType: TextInputType |
|
|
.center, |
|
|
.multiline, // 启用多行键盘 |
|
|
children: [ |
|
|
textInputAction: |
|
|
Icon( |
|
|
TextInputAction |
|
|
isPushToTalkActive |
|
|
.newline, // 支持回车换行 |
|
|
? Icons.mic |
|
|
onTap: () { |
|
|
: Icons.mic_none, |
|
|
// 当点击输入框时,如果'+'选项已展开,则收缩 |
|
|
size: 16.sp, |
|
|
if (controller |
|
|
color: isPushToTalkActive |
|
|
.isPlusOptionsExpanded |
|
|
? Colors.blue |
|
|
.value) { |
|
|
: Colors.grey[500], |
|
|
controller |
|
|
|
|
|
.collapsePlusOptions(); |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 15.sp, |
|
|
|
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.white |
|
|
|
|
|
: Colors.grey[800], |
|
|
|
|
|
), |
|
|
), |
|
|
decoration: InputDecoration( |
|
|
const SizedBox(width: 6), |
|
|
hintText: isImageActive |
|
|
Text( |
|
|
? 'addQuestionAboutImage' |
|
|
isPushToTalkActive |
|
|
.tr // 添加对图片的问题或描述... |
|
|
? 'recording' |
|
|
: 'inputMessage' |
|
|
.tr // 正在录音... |
|
|
.tr, // 输入消息... |
|
|
: 'holdToSpeak' |
|
|
hintStyle: TextStyle( |
|
|
.tr, // 按住说话 |
|
|
color: Colors.grey[500], |
|
|
style: TextStyle( |
|
|
fontSize: 15.sp, |
|
|
fontSize: 14, |
|
|
), |
|
|
fontWeight: |
|
|
filled: false, |
|
|
FontWeight.w500, |
|
|
border: InputBorder.none, |
|
|
color: isPushToTalkActive |
|
|
focusedBorder: |
|
|
? Colors.blue |
|
|
OutlineInputBorder( |
|
|
: Colors.grey[600], |
|
|
borderSide: BorderSide( |
|
|
|
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.grey[800]! |
|
|
|
|
|
: Colors.grey[200]!, |
|
|
|
|
|
width: 1.w, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
), |
|
|
contentPadding: |
|
|
|
|
|
EdgeInsets.symmetric( |
|
|
|
|
|
vertical: |
|
|
|
|
|
isImageActive |
|
|
|
|
|
? 12.h |
|
|
|
|
|
: 8.h), |
|
|
|
|
|
), |
|
|
), |
|
|
onSubmitted: (_) => |
|
|
], |
|
|
controller.sendMessage(), |
|
|
), |
|
|
); |
|
|
|
|
|
}), |
|
|
|
|
|
), |
|
|
), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
); |
|
|
); |
|
|
}), |
|
|
} else { |
|
|
); |
|
|
Timer? _holdTimer; // 增加延迟触发的计时器 |
|
|
} |
|
|
// 语音输入模式 - 按住说话模式 |
|
|
}), |
|
|
return Listener( |
|
|
), |
|
|
onPointerDown: (_) { |
|
|
|
|
|
// 设置300ms延迟防止误触 |
|
|
|
|
|
_holdTimer = Timer( |
|
|
|
|
|
const Duration(milliseconds: 200), |
|
|
|
|
|
() { |
|
|
|
|
|
controller.startPushToTalk(); |
|
|
|
|
|
// if (activeSpeaker == 0) { |
|
|
|
|
|
// if (speakerId == 1) { |
|
|
|
|
|
// controller |
|
|
|
|
|
// .restoreOriginalAudioState(); |
|
|
|
|
|
// } else { |
|
|
|
|
|
// controller |
|
|
|
|
|
// .disableBluetoothAudio(); |
|
|
|
|
|
// } |
|
|
|
|
|
// controller |
|
|
|
|
|
// .setActiveSpeaker(speakerId); |
|
|
|
|
|
// } |
|
|
|
|
|
}); |
|
|
|
|
|
}, |
|
|
|
|
|
onPointerUp: (_) { |
|
|
|
|
|
_holdTimer?.cancel(); |
|
|
|
|
|
controller.endPushToTalk(); |
|
|
|
|
|
}, |
|
|
|
|
|
onPointerCancel: (_) { |
|
|
|
|
|
_holdTimer?.cancel(); |
|
|
|
|
|
controller.endPushToTalk(); |
|
|
|
|
|
}, |
|
|
|
|
|
// onLongPressStart: (_) { |
|
|
|
|
|
// // 开始按住说话 |
|
|
|
|
|
// controller.startPushToTalk(); |
|
|
|
|
|
// }, |
|
|
|
|
|
// onLongPressEnd: (_) { |
|
|
|
|
|
// // 结束按住说话 |
|
|
|
|
|
// controller.endPushToTalk(); |
|
|
|
|
|
// }, |
|
|
|
|
|
// onLongPressCancel: () { |
|
|
|
|
|
// // 取消按住说话 |
|
|
|
|
|
// controller.endPushToTalk(); |
|
|
|
|
|
// }, |
|
|
|
|
|
child: Obx(() { |
|
|
|
|
|
final isPushToTalkActive = |
|
|
|
|
|
controller.isPushToTalkActive.value; |
|
|
|
|
|
final isListening = |
|
|
|
|
|
controller.isListening.value; |
|
|
|
|
|
|
|
|
|
|
|
return Container( |
|
|
|
|
|
height: 52.h, |
|
|
|
|
|
padding: EdgeInsets.symmetric( |
|
|
|
|
|
horizontal: 16.w), |
|
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
|
color: isPushToTalkActive |
|
|
|
|
|
? (isDarkMode |
|
|
|
|
|
? Colors.blue[900] |
|
|
|
|
|
: Colors.blue[100]) |
|
|
|
|
|
: (isDarkMode |
|
|
|
|
|
? Colors.grey[800] |
|
|
|
|
|
: Colors.grey[200]), |
|
|
|
|
|
borderRadius: |
|
|
|
|
|
BorderRadius.circular(22.w), |
|
|
|
|
|
border: Border.all( |
|
|
|
|
|
color: isPushToTalkActive |
|
|
|
|
|
? Colors.blue |
|
|
|
|
|
: (isDarkMode |
|
|
|
|
|
? Colors.grey[800]! |
|
|
|
|
|
: Colors.grey |
|
|
|
|
|
.withOpacity(0.1)), |
|
|
|
|
|
width: isPushToTalkActive |
|
|
|
|
|
? 2.w |
|
|
|
|
|
: 1.w, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
child: Row( |
|
|
|
|
|
children: [ |
|
|
|
|
|
// 语音波形图 - 只在按住时显示 |
|
|
|
|
|
if (isPushToTalkActive) ...[ |
|
|
|
|
|
const AgentSoundBarsWidget(), |
|
|
|
|
|
//const Spacer(), |
|
|
|
|
|
], |
|
|
|
|
|
|
|
|
|
|
|
// 状态文字和图标 |
|
|
|
|
|
Expanded( |
|
|
|
|
|
child: Row( |
|
|
|
|
|
mainAxisAlignment: |
|
|
|
|
|
isPushToTalkActive |
|
|
|
|
|
? MainAxisAlignment |
|
|
|
|
|
.center |
|
|
|
|
|
: MainAxisAlignment |
|
|
|
|
|
.center, |
|
|
|
|
|
children: [ |
|
|
|
|
|
Icon( |
|
|
|
|
|
isPushToTalkActive |
|
|
|
|
|
? Icons.mic |
|
|
|
|
|
: Icons.mic_none, |
|
|
|
|
|
size: 16.sp, |
|
|
|
|
|
color: isPushToTalkActive |
|
|
|
|
|
? Colors.blue |
|
|
|
|
|
: Colors.grey[500], |
|
|
|
|
|
), |
|
|
|
|
|
const SizedBox(width: 6), |
|
|
|
|
|
Text( |
|
|
|
|
|
isPushToTalkActive |
|
|
|
|
|
? 'recording' |
|
|
|
|
|
.tr // 正在录音... |
|
|
|
|
|
: 'holdToSpeak' |
|
|
|
|
|
.tr, // 按住说话 |
|
|
|
|
|
style: TextStyle( |
|
|
|
|
|
fontSize: 14, |
|
|
|
|
|
fontWeight: |
|
|
|
|
|
FontWeight.w500, |
|
|
|
|
|
color: |
|
|
|
|
|
isPushToTalkActive |
|
|
|
|
|
? Colors.blue |
|
|
|
|
|
: Colors |
|
|
|
|
|
.grey[600], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
], |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
}), |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
}), |
|
|
|
|
|
), |
|
|
|
|
|
|
|
|
|
|
|
SizedBox(width: 8.w), |
|
|
SizedBox(width: 8.w), |
|
|
|
|
|
|
|
|
// 动态按钮区域:展开按钮 + 发送按钮 或 图片选择按钮 |
|
|
// 动态按钮区域:展开按钮 + 发送按钮 或 图片选择按钮 |
|
|
Builder(builder: (context) { |
|
|
Builder(builder: (context) { |
|
|
StepWidgetParams? widgetParams; |
|
|
StepWidgetParams? widgetParams; |
|
|
return IntroStepBuilder( |
|
|
return IntroStepBuilder( |
|
|
group: 'ai', |
|
|
group: 'ai', |
|
|
order: 2, |
|
|
order: 2, |
|
|
onHighlightWidgetTap: () async { |
|
|
onHighlightWidgetTap: () async { |
|
|
await controller |
|
|
await controller |
|
|
.noviceGuideService.aiStepsList[ |
|
|
.noviceGuideService.aiStepsList[ |
|
|
controller.noviceGuideService |
|
|
controller.noviceGuideService.aiStep] |
|
|
.aiStep]['method'](); |
|
|
['method'](); |
|
|
widgetParams!.onNext!(); |
|
|
widgetParams!.onNext!(); |
|
|
controller.sendMessage(); |
|
|
controller.sendMessage(); |
|
|
}, |
|
|
}, |
|
|
overlayBuilder: (params) { |
|
|
overlayBuilder: (params) { |
|
|
widgetParams = params; |
|
|
widgetParams = params; |
|
|
return IntroOverlayBuilder.aiBuilder( |
|
|
return IntroOverlayBuilder.aiBuilder( |
|
|
params, |
|
|
params, |
|
|
'点击发送,${controller.noviceGuideService.aiStepsList[controller.noviceGuideService.aiStep]['send']}', |
|
|
'点击发送,${controller.noviceGuideService.aiStepsList[controller.noviceGuideService.aiStep]['send']}', |
|
|
alignment: false, |
|
|
alignment: false, |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
builder: |
|
|
builder: |
|
|
(BuildContext context, GlobalKey key) => |
|
|
(BuildContext context, GlobalKey key) => |
|
|
Obx( |
|
|
Obx( |
|
|
key: key, |
|
|
key: key, |
|
|
() { |
|
|
() { |
|
|
final hasText = |
|
|
final hasText = |
|
|
controller.hasTextInput.value; |
|
|
controller.hasTextInput.value; |
|
|
final hasImage = |
|
|
final hasImage = |
|
|
controller.isImageInputActive.value; |
|
|
controller.isImageInputActive.value; |
|
|
final shouldShowSend = |
|
|
final shouldShowSend = hasText || hasImage; |
|
|
hasText || hasImage; |
|
|
final shouldShowExpand = |
|
|
final shouldShowExpand = controller |
|
|
controller.shouldShowExpandButton.value; |
|
|
.shouldShowExpandButton.value; |
|
|
|
|
|
|
|
|
|
|
|
if (shouldShowSend) { |
|
|
if (shouldShowSend) { |
|
|
// 显示发送按钮(可能还有展开按钮) |
|
|
// 显示发送按钮(可能还有展开按钮) |
|
|
return Column( |
|
|
return Column( |
|
|
mainAxisSize: MainAxisSize.min, |
|
|
children: [ |
|
|
children: [ |
|
|
// 展开按钮(在发送按钮上方) |
|
|
// 展开按钮(在发送按钮上方) |
|
|
if (shouldShowExpand && hasText) |
|
|
if (shouldShowExpand && hasText) |
|
|
Padding( |
|
|
Padding( |
|
|
padding: |
|
|
padding: EdgeInsets.only( |
|
|
EdgeInsets.only(bottom: 40.h), |
|
|
bottom: 40.h), |
|
|
child: GestureDetector( |
|
|
child: GestureDetector( |
|
|
onTap: () { |
|
|
onTap: () { |
|
|
// 打开底部弹出编辑模式 |
|
|
// 打开底部弹出编辑模式 |
|
|
controller |
|
|
|
|
|
.openFullScreenEdit(); |
|
|
|
|
|
showModalBottomSheet( |
|
|
|
|
|
context: context, |
|
|
|
|
|
isScrollControlled: true, |
|
|
|
|
|
backgroundColor: |
|
|
|
|
|
Colors.transparent, |
|
|
|
|
|
builder: (context) => |
|
|
|
|
|
const FullScreenEditor(), |
|
|
|
|
|
).then((_) { |
|
|
|
|
|
// 弹出页关闭时的回调 |
|
|
controller |
|
|
controller |
|
|
.openFullScreenEdit(); |
|
|
.closeFullScreenEdit(); |
|
|
showModalBottomSheet( |
|
|
}); |
|
|
context: context, |
|
|
}, |
|
|
isScrollControlled: true, |
|
|
child: Container( |
|
|
backgroundColor: |
|
|
width: 32.w, |
|
|
Colors.transparent, |
|
|
height: 32.w, |
|
|
builder: (context) => |
|
|
decoration: BoxDecoration( |
|
|
const FullScreenEditor(), |
|
|
color: isDarkMode |
|
|
).then((_) { |
|
|
? Colors.grey[700] |
|
|
// 弹出页关闭时的回调 |
|
|
: Colors.grey[300], |
|
|
controller |
|
|
borderRadius: |
|
|
.closeFullScreenEdit(); |
|
|
BorderRadius.circular( |
|
|
}); |
|
|
16.w), |
|
|
}, |
|
|
), |
|
|
child: Container( |
|
|
child: Icon( |
|
|
width: 32.w, |
|
|
Icons.expand_less, |
|
|
height: 32.w, |
|
|
color: isDarkMode |
|
|
decoration: BoxDecoration( |
|
|
? Colors.grey[300] |
|
|
color: isDarkMode |
|
|
: Colors.grey[700], |
|
|
? Colors.grey[700] |
|
|
size: 20.sp, |
|
|
: Colors.grey[300], |
|
|
|
|
|
borderRadius: |
|
|
|
|
|
BorderRadius.circular( |
|
|
|
|
|
16.w), |
|
|
|
|
|
), |
|
|
|
|
|
child: Icon( |
|
|
|
|
|
Icons.expand_less, |
|
|
|
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.grey[300] |
|
|
|
|
|
: Colors.grey[700], |
|
|
|
|
|
size: 20.sp, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
// 发送按钮 |
|
|
|
|
|
GestureDetector( |
|
|
|
|
|
onTap: () => |
|
|
|
|
|
controller.sendMessage(), |
|
|
|
|
|
child: Container( |
|
|
|
|
|
width: 44.w, |
|
|
|
|
|
height: 44.w, |
|
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
|
color: primaryColor, |
|
|
|
|
|
borderRadius: |
|
|
|
|
|
BorderRadius.circular( |
|
|
|
|
|
22.w), |
|
|
|
|
|
), |
|
|
|
|
|
child: Icon( |
|
|
|
|
|
Icons.send, |
|
|
|
|
|
color: Colors.white, |
|
|
|
|
|
size: 22.sp, |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
], |
|
|
// 发送按钮 |
|
|
); |
|
|
GestureDetector( |
|
|
} else { |
|
|
onTap: () => |
|
|
// 显示'+'选择按钮 |
|
|
controller.sendMessage(), |
|
|
return Obx(() { |
|
|
|
|
|
final isExpanded = controller |
|
|
|
|
|
.isPlusOptionsExpanded.value; |
|
|
|
|
|
return GestureDetector( |
|
|
|
|
|
onTap: () { |
|
|
|
|
|
controller.togglePlusOptions(); |
|
|
|
|
|
}, |
|
|
|
|
|
child: Container( |
|
|
child: Container( |
|
|
width: 44.w, |
|
|
width: 44.w, |
|
|
height: 44.w, |
|
|
height: 44.w, |
|
|
|
|
|
margin: EdgeInsets.symmetric( |
|
|
|
|
|
vertical: 2.w), |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: isDarkMode |
|
|
color: primaryColor, |
|
|
? Colors.grey[800] |
|
|
|
|
|
: Colors.grey[200], |
|
|
|
|
|
borderRadius: |
|
|
borderRadius: |
|
|
BorderRadius.circular(22.w), |
|
|
BorderRadius.circular(22.w), |
|
|
), |
|
|
), |
|
|
child: Icon( |
|
|
child: Icon( |
|
|
isExpanded |
|
|
Icons.send, |
|
|
? Icons.close |
|
|
color: Colors.white, |
|
|
: Icons.add, |
|
|
|
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.grey[300] |
|
|
|
|
|
: Colors.grey[700], |
|
|
|
|
|
size: 22.sp, |
|
|
size: 22.sp, |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
); |
|
|
), |
|
|
}); |
|
|
], |
|
|
} |
|
|
); |
|
|
}, |
|
|
} else { |
|
|
), |
|
|
// 显示'+'选择按钮 |
|
|
); |
|
|
return Obx(() { |
|
|
}), |
|
|
final isExpanded = controller |
|
|
], |
|
|
.isPlusOptionsExpanded.value; |
|
|
), |
|
|
return GestureDetector( |
|
|
|
|
|
onTap: () { |
|
|
|
|
|
controller.togglePlusOptions(); |
|
|
|
|
|
}, |
|
|
|
|
|
child: Container( |
|
|
|
|
|
width: 44.w, |
|
|
|
|
|
height: 44.w, |
|
|
|
|
|
margin: EdgeInsets.symmetric( |
|
|
|
|
|
vertical: 2.w), |
|
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.grey[800] |
|
|
|
|
|
: Colors.grey[200], |
|
|
|
|
|
borderRadius: |
|
|
|
|
|
BorderRadius.circular(22.w), |
|
|
|
|
|
), |
|
|
|
|
|
child: Icon( |
|
|
|
|
|
isExpanded |
|
|
|
|
|
? Icons.close |
|
|
|
|
|
: Icons.add, |
|
|
|
|
|
color: isDarkMode |
|
|
|
|
|
? Colors.grey[300] |
|
|
|
|
|
: Colors.grey[700], |
|
|
|
|
|
size: 22.sp, |
|
|
|
|
|
), |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
), |
|
|
|
|
|
); |
|
|
|
|
|
}), |
|
|
|
|
|
], |
|
|
), |
|
|
), |
|
|
|
|
|
|
|
|
// 展开的'+'选择选项 |
|
|
// 展开的'+'选择选项 |
|
|
|