Browse Source

feat(消息气泡): 添加长按复制和举报功能

- 在非用户消息上添加长按手势,显示包含复制和举报选项的菜单
- 实现复制功能,将消息内容复制到剪贴板
- 添加举报功能,支持多种举报类型和自定义描述
- 禁用消息气泡的选择功能以优化交互体验
- 引入触觉反馈增强用户操作感知
newdev_shunjiawei
lxm 1 year ago
parent
commit
44b1eac2a1
  1. 260
      lib/modules/agent/views/agent_view.dart
  2. 2
      lib/modules/agent/views/message_bubble.dart

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

@ -3,6 +3,10 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/agent_controller.dart';
import 'message_bubble.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../../core/theme/app_colors.dart';
import 'package:haptic_feedback/haptic_feedback.dart';
class AgentView extends StatelessWidget {
const AgentView({Key? key}) : super(key: key);
@ -163,15 +167,32 @@ class AgentView extends StatelessWidget {
.messages[controller.messages.length - 1 - index];
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: MessageBubble(
isUser: message.isUser,
message: message.text,
timestamp: message.timestamp,
isRecognizing: message.isRecognizing,
hasImage: message.hasImage,
imagePath: message.imagePath,
meta: message.meta,
),
child: !message.isUser
? GestureDetector(
onLongPressStart:
(LongPressStartDetails details) {
_onLongPressMessageContent(
context, isDarkMode, details, message);
},
child: MessageBubble(
isUser: message.isUser,
message: message.text,
timestamp: message.timestamp,
isRecognizing: message.isRecognizing,
hasImage: message.hasImage,
imagePath: message.imagePath,
meta: message.meta,
),
)
: MessageBubble(
isUser: message.isUser,
message: message.text,
timestamp: message.timestamp,
isRecognizing: message.isRecognizing,
hasImage: message.hasImage,
imagePath: message.imagePath,
meta: message.meta,
),
);
},
),
@ -522,6 +543,227 @@ class AgentView extends StatelessWidget {
);
}
void _onLongPressMessageContent(BuildContext context, bool isDarkMode,
LongPressStartDetails details, Message message) {
Haptics.vibrate(HapticsType.success);
RenderBox? renderBox =
Overlay.of(context).context.findRenderObject() as RenderBox;
final RelativeRect position = RelativeRect.fromRect(
Rect.fromLTRB(
details.globalPosition.dx,
details.globalPosition.dy,
details.globalPosition.dx + 110, // 菜单显示位置X轴坐标
details.globalPosition.dy - 40, // 菜单显示位置Y轴坐标
),
Offset.zero & renderBox.size,
);
showMenu(
context: context,
position: position,
color: isDarkMode ? AppColors.cardBackground : Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.r),
),
items: [
_popupMenuEntry(
Icon(
Icons.copy,
size: 20.w,
color: isDarkMode ? Colors.white : Colors.black87,
),
'复制',
isDarkMode ? Colors.white : Colors.black87,
() {
Clipboard.setData(
ClipboardData(
text: message.text,
),
).then((value) => Get.snackbar(
'success'.tr, // 成功
'复制成功',
backgroundColor: Colors.blue.withOpacity(0.8),
colorText: Colors.white,
));
},
),
// 自定义分隔线样式
PopupMenuItem(
height: 1, // 控制间距
enabled: false,
child: Divider(
height: 1,
thickness: 0.8,
indent: 12,
endIndent: 12,
color: isDarkMode ? Colors.grey[700] : Colors.grey[300],
),
),
_popupMenuEntry(
Icon(
Icons.report,
size: 20.w,
color: isDarkMode ? Colors.red[700] : Colors.red,
),
'举报'.tr, // 举报
isDarkMode ? Colors.red[700]! : Colors.red,
() {
// 实现举报功能
showModalBottomSheet(
context: context,
backgroundColor:
isDarkMode ? AppColors.cardBackground : Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16.r)),
),
builder: (BuildContext context) {
return Container(
padding: EdgeInsets.all(16.w),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'举报',
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: isDarkMode ? Colors.white : Colors.black,
),
),
IconButton(
icon: Icon(
Icons.close,
color:
isDarkMode ? Colors.white70 : Colors.black54,
),
onPressed: () => Navigator.pop(context),
),
],
),
SizedBox(height: 16.h),
Wrap(
spacing: 8.w,
runSpacing: 8.h,
children: [
_buildReportChip('有害/不安全', isDarkMode),
_buildReportChip('色情低俗', isDarkMode),
_buildReportChip('误导攻击', isDarkMode),
_buildReportChip('违法犯罪', isDarkMode),
_buildReportChip('隐私相关', isDarkMode),
_buildReportChip('侵犯我的著作权、名誉权等', isDarkMode),
_buildReportChip('其他', isDarkMode),
],
),
SizedBox(height: 16.h),
Container(
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color:
isDarkMode ? Colors.grey[800] : Colors.grey[200],
borderRadius: BorderRadius.circular(8.r),
),
child: TextField(
maxLines: 3,
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black,
),
decoration: InputDecoration(
hintText: '我们想知道你举报的原因,你可以描述你遇到的问题。',
hintStyle: TextStyle(
color:
isDarkMode ? Colors.white70 : Colors.black54,
fontSize: 14.sp,
),
border: InputBorder.none,
),
),
),
SizedBox(height: 14.h),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(vertical: 12.h),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.r),
),
),
child: Text('提交'),
onPressed: () {
// 处理举报提交逻辑
Navigator.pop(context);
Get.snackbar(
'提示',
'举报已提交,我们会尽快处理',
backgroundColor: Colors.green.withOpacity(0.8),
colorText: Colors.white,
);
},
),
SizedBox(height: 8.h),
],
),
);
},
);
},
),
],
);
}
// 添加这个辅助方法来创建举报选项
Widget _buildReportChip(String label, bool isDarkMode) {
return ChoiceChip(
label: Text(
label,
style: TextStyle(
color: isDarkMode ? Colors.white : Colors.black87,
fontSize: 14.sp,
),
),
selected: false,
backgroundColor: isDarkMode ? Colors.grey[800] : Colors.grey[200],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.r),
),
onSelected: (bool selected) {
// 可以在这里处理选择逻辑
},
);
}
PopupMenuEntry _popupMenuEntry(
Icon icon,
String title,
Color color,
Function() onTap,
) {
return PopupMenuItem(
onTap: onTap,
child: SizedBox(
width: 140.w,
child: Row(
children: [
icon,
8.horizontalSpace,
Text(
title,
style: TextStyle(
color: color,
fontSize: 14.sp,
),
),
],
),
),
);
}
// 构建提示选项芯片
Widget _buildPromptChip({
required BuildContext context,

2
lib/modules/agent/views/message_bubble.dart

@ -406,7 +406,7 @@ class MessageBubble extends GetView<AgentController> {
fontSize: 14,
),
),
selectable: true,
//selectable: true,
);
}
// 用户消息仍然使用普通文本

Loading…
Cancel
Save