160 lines
4.9 KiB
Dart
160 lines
4.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:intl/intl.dart';
|
|
import '../models/collaboration.dart';
|
|
import '../core/theme/app_theme.dart';
|
|
|
|
class CommentThread extends StatelessWidget {
|
|
final List<Comment> comments;
|
|
final String currentUserId;
|
|
final Future<bool> Function(String body, {String? parentId}) onAddComment;
|
|
|
|
const CommentThread({
|
|
super.key,
|
|
required this.comments,
|
|
required this.currentUserId,
|
|
required this.onAddComment,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final topLevel = comments.where((c) => c.parentId == null).toList();
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
...topLevel.map((comment) => _CommentCard(
|
|
comment: comment,
|
|
currentUserId: currentUserId,
|
|
onReply: (parentId, body) => onAddComment(body, parentId: parentId),
|
|
)),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _CommentCard extends StatelessWidget {
|
|
final Comment comment;
|
|
final String currentUserId;
|
|
final Future<bool> Function(String parentId, String body) onReply;
|
|
|
|
const _CommentCard({
|
|
required this.comment,
|
|
required this.currentUserId,
|
|
required this.onReply,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Padding(
|
|
padding: const EdgeInsets.only(bottom: 12),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: VoIdeaColors.surface,
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
CircleAvatar(
|
|
radius: 14,
|
|
backgroundColor: VoIdeaColors.primary.withOpacity(0.1),
|
|
child: Text(
|
|
comment.userName.isNotEmpty
|
|
? comment.userName[0].toUpperCase()
|
|
: '?',
|
|
style: const TextStyle(
|
|
color: VoIdeaColors.primary,
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
comment.userName,
|
|
style: const TextStyle(fontWeight: FontWeight.w500),
|
|
),
|
|
const Spacer(),
|
|
Text(
|
|
DateFormat('d MMM').format(comment.createdAt),
|
|
style: TextStyle(
|
|
color: VoIdeaColors.muted,
|
|
fontSize: 12,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(comment.body),
|
|
if (comment.userId != currentUserId)
|
|
Padding(
|
|
padding: const EdgeInsets.only(top: 8),
|
|
child: GestureDetector(
|
|
onTap: () => _showReplyDialog(context),
|
|
child: Text(
|
|
'Ответить',
|
|
style: TextStyle(
|
|
color: VoIdeaColors.primary,
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
if (comment.replies.isNotEmpty)
|
|
Padding(
|
|
padding: const EdgeInsets.only(left: 24, top: 8),
|
|
child: Column(
|
|
children: comment.replies.map((reply) => _CommentCard(
|
|
comment: reply,
|
|
currentUserId: currentUserId,
|
|
onReply: onReply,
|
|
)).toList(),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
void _showReplyDialog(BuildContext context) {
|
|
final controller = TextEditingController();
|
|
showDialog(
|
|
context: context,
|
|
builder: (ctx) => AlertDialog(
|
|
title: const Text('Ответить'),
|
|
content: TextField(
|
|
controller: controller,
|
|
maxLines: 3,
|
|
decoration: const InputDecoration(
|
|
hintText: 'Напишите ответ...',
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(ctx),
|
|
child: const Text('Отмена'),
|
|
),
|
|
ElevatedButton(
|
|
onPressed: () {
|
|
if (controller.text.isNotEmpty) {
|
|
onReply(comment.id, controller.text);
|
|
Navigator.pop(ctx);
|
|
}
|
|
},
|
|
child: const Text('Отправить'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|