import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:haptic_feedback/haptic_feedback.dart'; import '../../../core/theme/app_colors.dart'; import '../../../data/models/message_model.dart'; import '../../../data/services/network/api.dart'; /// 消息操作控制器 /// 负责处理消息长按、复制、举报等操作 class MessageActionController extends GetxController { // 当前举报的消息 final reportingMessage = Rxn(); // 选择的举报原因 List selectedReasons = []; // 举报描述 final reportDescription = ''.obs; /// 处理消息长按事件 void onLongPressMessage( 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: _buildMenuItems(context, isDarkMode, message), ); } /// 构建弹出菜单项 List _buildMenuItems( BuildContext context, bool isDarkMode, Message message, ) { final List items = [ // 复制选项 _buildPopupMenuItem( Icon( Icons.copy, size: 20.w, color: isDarkMode ? Colors.white : Colors.black87, ), '复制', isDarkMode ? Colors.white : Colors.black87, () => _copyMessage(message), ), ]; // 如果不是用户消息,添加举报选项 if (!message.isUser) { items.addAll([ // 分隔线 PopupMenuItem( height: 1, enabled: false, child: Divider( height: 1, thickness: 0.8, indent: 0, endIndent: 0, color: isDarkMode ? Colors.grey[700] : Colors.grey[300], ), ), // 举报选项 _buildPopupMenuItem( Icon( Icons.report, size: 20.w, color: isDarkMode ? Colors.red[700] : Colors.red, ), '举报'.tr, isDarkMode ? Colors.red[700]! : Colors.red, () => _showReportForm(context, isDarkMode, message), ), ]); } return items; } /// 构建弹出菜单项 PopupMenuEntry _buildPopupMenuItem( 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, ), ), ], ), ), ); } /// 复制消息内容 void _copyMessage(Message message) { Clipboard.setData(ClipboardData(text: message.text)).then((_) { Get.snackbar( 'success'.tr, '复制成功', backgroundColor: Colors.blue.withOpacity(0.8), colorText: Colors.white, ); }); } /// 显示举报表单 void _showReportForm(BuildContext context, bool isDarkMode, Message message) { // 初始化举报状态 initReport(message); showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16.r)), ), builder: (BuildContext context) { return Padding( padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, ), child: _ReportForm(isDarkMode: isDarkMode), ); }, ); } /// 初始化举报状态 void initReport(Message message) { reportingMessage.value = message; selectedReasons.clear(); reportDescription.value = ''; } /// 切换举报原因选择状态 void toggleReason(String reason) { if (selectedReasons.contains(reason)) { selectedReasons.remove(reason); } else { selectedReasons.add(reason); } update(); } /// 更新举报描述 void updateDescription(String text) { reportDescription.value = text; } /// 提交举报 Future submitReport() async { if (reportingMessage.value == null) return; // 构建举报数据 final reportData = { 'describe': reportDescription.value, 'message': [], 'reportContext': reportingMessage.value!.text, 'reporttype': selectedReasons.toString(), }; try { // 调用API提交举报 var response = await Api.reportAiContent(reportData); if (response != null) { print('提交举报响应: $response'); } // 提交成功后重置状态 selectedReasons.clear(); reportDescription.value = ''; reportingMessage.value = null; // 关闭举报表单 Navigator.of(Get.context!).pop(); // 显示成功通知 Get.snackbar( '提交成功', '举报已提交,我们会尽快处理', backgroundColor: Colors.green.withOpacity(0.8), colorText: Colors.white, duration: const Duration(seconds: 2), ); } catch (e) { // 显示错误通知 Get.snackbar( '提交失败', '网络错误,请稍后重试', backgroundColor: Colors.red.withOpacity(0.8), colorText: Colors.white, duration: const Duration(seconds: 2), ); } } } /// 举报表单组件 class _ReportForm extends StatelessWidget { final bool isDarkMode; final MessageActionController controller = Get.find(); _ReportForm({required this.isDarkMode}); @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(16.w), child: SingleChildScrollView( child: GetBuilder( builder: (_) => Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // 标题栏 Stack( alignment: Alignment.center, children: [ Center( child: Text( '举报', style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.bold, color: isDarkMode ? Colors.white : Colors.black, ), ), ), Positioned( right: 0, child: IconButton( icon: Icon( Icons.close, color: isDarkMode ? Colors.grey[400] : Colors.black54, ), onPressed: () => Navigator.pop(context), ), ), ], ), // 分隔线 Container( padding: EdgeInsets.symmetric(horizontal: 12.w), margin: EdgeInsets.only(bottom: 10.w), child: Divider( height: 1, color: Colors.grey[300], ), ), // 举报原因选择 GetBuilder( builder: (controller) { return Wrap( spacing: 8.w, runSpacing: 8.h, children: [ _buildReportChip('有害/不安全', isDarkMode, controller), _buildReportChip('色情低俗', isDarkMode, controller), _buildReportChip('误导攻击', isDarkMode, controller), _buildReportChip('违法犯罪', isDarkMode, controller), _buildReportChip('隐私相关', isDarkMode, controller), _buildReportChip('侵犯我的著作权、名誉权等', isDarkMode, controller), _buildReportChip('其他', isDarkMode, controller), ], ); }, ), 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, onChanged: controller.updateDescription, 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: () => controller.submitReport(), ), SizedBox(height: 8.h), ], ), ), ), ); } /// 构建举报原因芯片 Widget _buildReportChip( String label, bool isDarkMode, MessageActionController controller, ) { final isSelected = controller.selectedReasons.contains(label); return GestureDetector( onTap: () => controller.toggleReason(label), child: Container( padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h), decoration: BoxDecoration( color: isSelected ? Colors.red : (isDarkMode ? Colors.grey[800] : Colors.grey[200]), borderRadius: BorderRadius.circular(16.r), border: Border.all( color: isSelected ? Colors.red[700]! : (isDarkMode ? Colors.grey[700]! : Colors.grey[300]!), width: isSelected ? 1.0 : 0.5, ), ), child: Text( label, style: TextStyle( color: isSelected ? Colors.white : (isDarkMode ? Colors.white : Colors.black87), fontSize: 14.sp, fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, ), ), ), ); } }