Теперь можно жаловаться на сообщения!!!
This commit is contained in:
@@ -176,6 +176,7 @@ class ChatMessageBubble extends StatelessWidget {
|
||||
final VoidCallback? onRemoveReaction;
|
||||
final VoidCallback? onReply;
|
||||
final VoidCallback? onForward;
|
||||
final VoidCallback? onComplain;
|
||||
final int? myUserId;
|
||||
final bool? canEditMessage;
|
||||
final bool isGroupChat;
|
||||
@@ -207,6 +208,7 @@ class ChatMessageBubble extends StatelessWidget {
|
||||
this.onRemoveReaction,
|
||||
this.onReply,
|
||||
this.onForward,
|
||||
this.onComplain,
|
||||
this.myUserId,
|
||||
this.canEditMessage,
|
||||
this.isGroupChat = false,
|
||||
@@ -890,6 +892,7 @@ class ChatMessageBubble extends StatelessWidget {
|
||||
onReaction: onReaction,
|
||||
onRemoveReaction: onRemoveReaction,
|
||||
onForward: onForward,
|
||||
onComplain: onComplain,
|
||||
canEditMessage: canEditMessage ?? false,
|
||||
hasUserReaction: hasUserReaction,
|
||||
isChannel: isChannel,
|
||||
@@ -1541,7 +1544,9 @@ class ChatMessageBubble extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _buildPhotoOnlyMessage(BuildContext context) {
|
||||
final photos = message.attaches.where((a) => a['_type'] == 'PHOTO').toList();
|
||||
final photos = message.attaches
|
||||
.where((a) => a['_type'] == 'PHOTO')
|
||||
.toList();
|
||||
final themeProvider = Provider.of<ThemeProvider>(context);
|
||||
final isUltraOptimized = themeProvider.ultraOptimizeChats;
|
||||
final messageOpacity = themeProvider.messageBubbleOpacity;
|
||||
@@ -1586,7 +1591,12 @@ class ChatMessageBubble extends StatelessWidget {
|
||||
? CrossAxisAlignment.end
|
||||
: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildSmartPhotoGroup(context, photos, textColor, isUltraOptimized),
|
||||
_buildSmartPhotoGroup(
|
||||
context,
|
||||
photos,
|
||||
textColor,
|
||||
isUltraOptimized,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 4, right: 6),
|
||||
child: Row(
|
||||
@@ -1620,7 +1630,9 @@ class ChatMessageBubble extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _buildVideoOnlyMessage(BuildContext context) {
|
||||
final videos = message.attaches.where((a) => a['_type'] == 'VIDEO').toList();
|
||||
final videos = message.attaches
|
||||
.where((a) => a['_type'] == 'VIDEO')
|
||||
.toList();
|
||||
|
||||
final timeColor = Theme.of(context).brightness == Brightness.dark
|
||||
? const Color(0xFF9bb5c7)
|
||||
@@ -1714,7 +1726,10 @@ class ChatMessageBubble extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
_formatMessageTime(context, message.time),
|
||||
style: TextStyle(fontSize: 12, color: timeColor),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: timeColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -3925,6 +3940,7 @@ class _MessageContextMenu extends StatefulWidget {
|
||||
final Function(String)? onReaction;
|
||||
final VoidCallback? onRemoveReaction;
|
||||
final VoidCallback? onForward;
|
||||
final VoidCallback? onComplain;
|
||||
final bool canEditMessage;
|
||||
final bool hasUserReaction;
|
||||
final bool isChannel;
|
||||
@@ -3939,6 +3955,7 @@ class _MessageContextMenu extends StatefulWidget {
|
||||
this.onReaction,
|
||||
this.onRemoveReaction,
|
||||
this.onForward,
|
||||
this.onComplain,
|
||||
required this.canEditMessage,
|
||||
required this.hasUserReaction,
|
||||
this.isChannel = false,
|
||||
@@ -4267,6 +4284,16 @@ class _MessageContextMenuState extends State<_MessageContextMenu>
|
||||
widget.onDeleteForAll!();
|
||||
},
|
||||
),
|
||||
if (widget.onComplain != null)
|
||||
_buildActionButton(
|
||||
icon: Icons.report_rounded,
|
||||
text: 'Пожаловаться',
|
||||
color: theme.colorScheme.error,
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
widget.onComplain!();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
173
lib/widgets/complaint_dialog.dart
Normal file
173
lib/widgets/complaint_dialog.dart
Normal file
@@ -0,0 +1,173 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gwid/models/complaint.dart';
|
||||
import 'package:gwid/api/api_service.dart';
|
||||
import 'dart:async';
|
||||
|
||||
class ComplaintDialog extends StatefulWidget {
|
||||
final String messageId;
|
||||
final int chatId;
|
||||
|
||||
const ComplaintDialog({
|
||||
super.key,
|
||||
required this.messageId,
|
||||
required this.chatId,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ComplaintDialog> createState() => _ComplaintDialogState();
|
||||
}
|
||||
|
||||
class _ComplaintDialogState extends State<ComplaintDialog> {
|
||||
ComplaintData? _complaintData;
|
||||
bool _isLoading = true;
|
||||
String? _error;
|
||||
StreamSubscription? _messageSubscription;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadComplaints();
|
||||
_listenForComplaintsData();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_messageSubscription?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _loadComplaints() {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
_error = null;
|
||||
});
|
||||
|
||||
ApiService.instance.getComplaints();
|
||||
}
|
||||
|
||||
void _listenForComplaintsData() {
|
||||
_messageSubscription = ApiService.instance.messages.listen((message) {
|
||||
if (message['type'] == 'complaints_data' && mounted) {
|
||||
setState(() {
|
||||
_complaintData = message['complaintData'] as ComplaintData?;
|
||||
_isLoading = false;
|
||||
_error = null;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _handleComplaintSelected(int typeId, int reasonId) {
|
||||
ApiService.instance.sendComplaint(
|
||||
widget.chatId,
|
||||
widget.messageId,
|
||||
typeId,
|
||||
reasonId,
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Жалоба отправлена'),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
duration: Duration(seconds: 2),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Жалоба на сообщение'),
|
||||
content: SizedBox(
|
||||
width: double.maxFinite,
|
||||
child: _isLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: _error != null
|
||||
? Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('Ошибка: $_error'),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: _loadComplaints,
|
||||
child: const Text('Повторить'),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: _complaintData == null
|
||||
? const Center(child: Text('Нет данных о жалобах'))
|
||||
: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: _getAllReasons().length,
|
||||
itemBuilder: (context, index) {
|
||||
final reasonData = _getAllReasons()[index];
|
||||
return ListTile(
|
||||
leading: Icon(
|
||||
reasonData['icon'] as IconData,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
title: Text(reasonData['title'] as String),
|
||||
onTap: () => _handleComplaintSelected(
|
||||
reasonData['typeId'] as int,
|
||||
reasonData['reasonId'] as int,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Отмена'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> _getAllReasons() {
|
||||
if (_complaintData == null) return [];
|
||||
|
||||
final uniqueReasons = <int, Map<String, dynamic>>{};
|
||||
for (final complaintType in _complaintData!.complainTypes) {
|
||||
for (final reason in complaintType.reasons) {
|
||||
if (!uniqueReasons.containsKey(reason.reasonId)) {
|
||||
String title = reason.reasonTitle;
|
||||
// Забавный прикол для оскорблений
|
||||
if (reason.reasonId == 11) {
|
||||
// Оскорбления
|
||||
title = 'Абзывательства матюки';
|
||||
}
|
||||
|
||||
uniqueReasons[reason.reasonId] = {
|
||||
'title': title,
|
||||
'typeId': complaintType.typeId,
|
||||
'reasonId': reason.reasonId,
|
||||
'icon': _getReasonIcon(reason.reasonId),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return uniqueReasons.values.toList();
|
||||
}
|
||||
|
||||
IconData _getReasonIcon(int reasonId) {
|
||||
switch (reasonId) {
|
||||
case 7: // Другое
|
||||
return Icons.more_horiz;
|
||||
case 8: // Мошенничество
|
||||
return Icons.warning;
|
||||
case 9: // Спам
|
||||
return Icons.campaign;
|
||||
case 10: // Шантаж
|
||||
return Icons.gavel;
|
||||
case 11: // Оскорбления
|
||||
return Icons.sentiment_very_dissatisfied;
|
||||
case 12: // Недостоверная информация
|
||||
return Icons.help_outline;
|
||||
default:
|
||||
return Icons.report_problem;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user