From 44b1eac2a10bdc3a4ce423a304247664f3fc9696 Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Wed, 4 Jun 2025 11:55:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=B6=88=E6=81=AF=E6=B0=94=E6=B3=A1):=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=95=BF=E6=8C=89=E5=A4=8D=E5=88=B6=E5=92=8C?= =?UTF-8?q?=E4=B8=BE=E6=8A=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在非用户消息上添加长按手势,显示包含复制和举报选项的菜单 - 实现复制功能,将消息内容复制到剪贴板 - 添加举报功能,支持多种举报类型和自定义描述 - 禁用消息气泡的选择功能以优化交互体验 - 引入触觉反馈增强用户操作感知 --- lib/modules/agent/views/agent_view.dart | 260 +++++++++++++++++++- lib/modules/agent/views/message_bubble.dart | 2 +- 2 files changed, 252 insertions(+), 10 deletions(-) diff --git a/lib/modules/agent/views/agent_view.dart b/lib/modules/agent/views/agent_view.dart index 54cb541d3..f91b246ac 100644 --- a/lib/modules/agent/views/agent_view.dart +++ b/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, diff --git a/lib/modules/agent/views/message_bubble.dart b/lib/modules/agent/views/message_bubble.dart index 94bbb5415..b4a7a0ed4 100644 --- a/lib/modules/agent/views/message_bubble.dart +++ b/lib/modules/agent/views/message_bubble.dart @@ -406,7 +406,7 @@ class MessageBubble extends GetView { fontSize: 14, ), ), - selectable: true, + //selectable: true, ); } // 用户消息仍然使用普通文本