Browse Source

修改agent输入部件高度抖动问题

weicu
tanlongsheng 1 year ago
parent
commit
4e7b007f2e
  1. 790
      lib/modules/agent/views/agent_view.dart

790
lib/modules/agent/views/agent_view.dart

@ -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,
),
),
);
});
}
},
),
);
}),
],
), ),
// 展开的'+'选择选项 // 展开的'+'选择选项

Loading…
Cancel
Save