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(
mainAxisSize: MainAxisSize.min,
children: [
// 图片预览区域 - 仅在图片输入模式下显示
Obx(() {
if (controller.isImageInputActive.value &&
controller.selectedImagePath.value != null) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// 图片预览和关闭按钮
Stack(
@ -421,454 +419,432 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
// 输入控件区域 - 包含输入行和展开的选项
Column(
children: [
// 输入控件行 - 使用IntrinsicHeight确保按钮与输入框底部对齐
IntrinsicHeight(
child: Row(
crossAxisAlignment:
CrossAxisAlignment.end, // 所有元素底部对齐
children: [
// 键盘/语音切换按钮
Obx(() {
final isTextMode =
controller.isTextInputMode.value;
return GestureDetector(
onTap: () {
controller.toggleInputMode();
},
child: Container(
width: 44.w,
height: 44.w,
decoration: BoxDecoration(
color: isDarkMode
? Colors.grey[800]
: Colors.grey[200],
borderRadius: BorderRadius.circular(22),
),
child: Icon(
isTextMode
? Icons.mic_none
: Icons.keyboard,
color: isDarkMode
? Colors.grey[300]
: Colors.grey[700],
size: 22.sp,
),
Row(
crossAxisAlignment:
CrossAxisAlignment.end, // 所有元素底部对齐
children: [
// 键盘/语音切换按钮
Obx(() {
final isTextMode =
controller.isTextInputMode.value;
return GestureDetector(
onTap: () {
controller.toggleInputMode();
},
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),
),
);
}),
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(
child: Obx(() {
final isTextMode =
controller.isTextInputMode.value;
// 文本输入框或语音波形图
Expanded(
child: Obx(() {
final isTextMode =
controller.isTextInputMode.value;
if (controller.isTextInputMode.value) {
// 文本输入模式 - 限制最大高度并只向上扩展
return IntroStepBuilder(
group: 'ai',
order: 1,
overlayBuilder: (params) {
return IntroOverlayBuilder.aiBuilder(
params,
controller.noviceGuideService
.aiStepsList[
if (controller.isTextInputMode.value) {
// 文本输入模式 - 限制最大高度并只向上扩展
return IntroStepBuilder(
group: 'ai',
order: 1,
overlayBuilder: (params) {
return IntroOverlayBuilder.aiBuilder(
params,
controller
.noviceGuideService.aiStepsList[
controller.noviceGuideService
.aiStep]['start'],
buttonText: '确定输入',
onNext: () {
controller.textController.text =
controller.noviceGuideService
.aiStep]['start'],
buttonText: '确定输入',
onNext: () {
controller.textController.text =
controller.noviceGuideService
.aiStepsList[
controller
.noviceGuideService
.aiStep]['input'];
.aiStepsList[
controller.noviceGuideService
.aiStep]['input'];
},
);
},
onWidgetLoad: () {
controller.noviceGuideService
.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();
},
builder: (BuildContext context,
GlobalKey key) =>
Container(
key: key,
constraints: BoxConstraints(
minHeight: 44.h,
maxHeight: 120.h,
),
}),
),
);
} 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: 48.w,
padding: EdgeInsets.symmetric(
horizontal: 16.w),
decoration: BoxDecoration(
color: isDarkMode
? Colors.grey[800]
: Colors.grey[200],
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: isDarkMode
? Colors.grey[800]!
: Colors.grey.withOpacity(0.1),
width: 1.w,
color: isPushToTalkActive
? Colors.blue
: (isDarkMode
? Colors.grey[800]!
: Colors.grey
.withOpacity(0.1)),
width:
isPushToTalkActive ? 2.w : 1.w,
),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment
.end, // 对齐到底部,实现向上扩展
children: [
Expanded(
child: Obx(() {
// 图片模式下使用更高的输入框
final isImageActive = controller
.isImageInputActive.value;
// 语音波形图 - 只在按住时显示
if (isPushToTalkActive) ...[
const AgentSoundBarsWidget(),
//const Spacer(),
],
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],
// 状态文字和图标
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],
),
decoration: InputDecoration(
hintText: isImageActive
? 'addQuestionAboutImage'
.tr // 添加对图片的问题或描述...
: 'inputMessage'
.tr, // 输入消息...
hintStyle: TextStyle(
color: Colors.grey[500],
fontSize: 15.sp,
),
filled: false,
border: InputBorder.none,
focusedBorder:
OutlineInputBorder(
borderSide: BorderSide(
color: isDarkMode
? Colors.grey[800]!
: Colors.grey[200]!,
width: 1.w,
),
const SizedBox(width: 6),
Text(
isPushToTalkActive
? 'recording'
.tr // 正在录音...
: 'holdToSpeak'
.tr, // 按住说话
style: TextStyle(
fontSize: 14,
fontWeight:
FontWeight.w500,
color: isPushToTalkActive
? Colors.blue
: Colors.grey[600],
),
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) {
StepWidgetParams? widgetParams;
return IntroStepBuilder(
group: 'ai',
order: 2,
onHighlightWidgetTap: () async {
await controller
.noviceGuideService.aiStepsList[
controller.noviceGuideService
.aiStep]['method']();
widgetParams!.onNext!();
controller.sendMessage();
},
overlayBuilder: (params) {
widgetParams = params;
return IntroOverlayBuilder.aiBuilder(
params,
'点击发送,${controller.noviceGuideService.aiStepsList[controller.noviceGuideService.aiStep]['send']}',
alignment: false,
);
},
builder:
(BuildContext context, GlobalKey key) =>
Obx(
key: key,
() {
final hasText =
controller.hasTextInput.value;
final hasImage =
controller.isImageInputActive.value;
final shouldShowSend =
hasText || hasImage;
final shouldShowExpand = controller
.shouldShowExpandButton.value;
// 动态按钮区域:展开按钮 + 发送按钮 或 图片选择按钮
Builder(builder: (context) {
StepWidgetParams? widgetParams;
return IntroStepBuilder(
group: 'ai',
order: 2,
onHighlightWidgetTap: () async {
await controller
.noviceGuideService.aiStepsList[
controller.noviceGuideService.aiStep]
['method']();
widgetParams!.onNext!();
controller.sendMessage();
},
overlayBuilder: (params) {
widgetParams = params;
return IntroOverlayBuilder.aiBuilder(
params,
'点击发送,${controller.noviceGuideService.aiStepsList[controller.noviceGuideService.aiStep]['send']}',
alignment: false,
);
},
builder:
(BuildContext context, GlobalKey key) =>
Obx(
key: key,
() {
final hasText =
controller.hasTextInput.value;
final hasImage =
controller.isImageInputActive.value;
final shouldShowSend = hasText || hasImage;
final shouldShowExpand =
controller.shouldShowExpandButton.value;
if (shouldShowSend) {
// 显示发送按钮(可能还有展开按钮)
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// 展开按钮(在发送按钮上方)
if (shouldShowExpand && hasText)
Padding(
padding: EdgeInsets.only(
bottom: 40.h),
child: GestureDetector(
onTap: () {
// 打开底部弹出编辑模式
if (shouldShowSend) {
// 显示发送按钮(可能还有展开按钮)
return Column(
children: [
// 展开按钮(在发送按钮上方)
if (shouldShowExpand && hasText)
Padding(
padding:
EdgeInsets.only(bottom: 40.h),
child: GestureDetector(
onTap: () {
// 打开底部弹出编辑模式
controller
.openFullScreenEdit();
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor:
Colors.transparent,
builder: (context) =>
const FullScreenEditor(),
).then((_) {
// 弹出页关闭时的回调
controller
.openFullScreenEdit();
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor:
Colors.transparent,
builder: (context) =>
const FullScreenEditor(),
).then((_) {
// 弹出页关闭时的回调
controller
.closeFullScreenEdit();
});
},
child: Container(
width: 32.w,
height: 32.w,
decoration: BoxDecoration(
color: isDarkMode
? Colors.grey[700]
: Colors.grey[300],
borderRadius:
BorderRadius.circular(
16.w),
),
child: Icon(
Icons.expand_less,
color: isDarkMode
? Colors.grey[300]
: Colors.grey[700],
size: 20.sp,
),
.closeFullScreenEdit();
});
},
child: Container(
width: 32.w,
height: 32.w,
decoration: BoxDecoration(
color: isDarkMode
? Colors.grey[700]
: 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,
),
),
),
],
);
} else {
// 显示'+'选择按钮
return Obx(() {
final isExpanded = controller
.isPlusOptionsExpanded.value;
return GestureDetector(
onTap: () {
controller.togglePlusOptions();
},
// 发送按钮
GestureDetector(
onTap: () =>
controller.sendMessage(),
child: Container(
width: 44.w,
height: 44.w,
margin: EdgeInsets.symmetric(
vertical: 2.w),
decoration: BoxDecoration(
color: isDarkMode
? Colors.grey[800]
: Colors.grey[200],
color: primaryColor,
borderRadius:
BorderRadius.circular(22.w),
),
child: Icon(
isExpanded
? Icons.close
: Icons.add,
color: isDarkMode
? Colors.grey[300]
: Colors.grey[700],
Icons.send,
color: Colors.white,
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