149 lines
4.9 KiB
Dart
149 lines
4.9 KiB
Dart
// Author: fruit.com.cn
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../../../core/data/models/comment.dart';
|
|
import '../../../core/data/services/comment_controller.dart';
|
|
import '../../../core/theme/app_colors.dart';
|
|
import '../../../l10n/app_localizations.dart';
|
|
|
|
const String _deleteAction = 'delete';
|
|
const String _reportAction = 'report';
|
|
|
|
/// 评论条目的交互回调集合。
|
|
class CommentInteractionHandlers {
|
|
const CommentInteractionHandlers({
|
|
required this.onReply,
|
|
required this.onLike,
|
|
required this.onDelete,
|
|
required this.onReport,
|
|
});
|
|
|
|
final ValueChanged<DramaComment> onReply;
|
|
final Future<void> Function(DramaComment) onLike;
|
|
final Future<void> Function(DramaComment) onDelete;
|
|
final Future<void> Function(DramaComment) onReport;
|
|
}
|
|
|
|
/// 单条评论或回复的展示与操作行。
|
|
class CommentTile extends StatelessWidget {
|
|
const CommentTile({
|
|
super.key,
|
|
required this.comment,
|
|
required this.controller,
|
|
required this.handlers,
|
|
this.isReply = false,
|
|
});
|
|
|
|
final DramaComment comment;
|
|
final CommentController controller;
|
|
final CommentInteractionHandlers handlers;
|
|
final bool isReply;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l10n = AppLocalizations.of(context)!;
|
|
final name = comment.nickname.isEmpty ? l10n.anonymousUser : comment.nickname;
|
|
return Padding(
|
|
key: Key('comment-item-${comment.id}'),
|
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
CircleAvatar(
|
|
radius: isReply ? 12 : 16,
|
|
backgroundColor: AppColors.blue.withValues(alpha: 0.2),
|
|
child: Icon(
|
|
Icons.person_rounded,
|
|
size: isReply ? 14 : 18,
|
|
color: AppColors.blueSoft,
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
name,
|
|
style: const TextStyle(
|
|
color: AppColors.muted,
|
|
fontSize: 12,
|
|
),
|
|
),
|
|
),
|
|
PopupMenuButton<String>(
|
|
key: Key('comment-menu-${comment.id}'),
|
|
tooltip: l10n.more,
|
|
onSelected: (value) {
|
|
if (value == _deleteAction) {
|
|
handlers.onDelete(comment);
|
|
} else if (value == _reportAction) {
|
|
handlers.onReport(comment);
|
|
}
|
|
},
|
|
itemBuilder: (_) => [
|
|
if (comment.mine)
|
|
PopupMenuItem(
|
|
value: _deleteAction,
|
|
child: Text(l10n.deleteComment),
|
|
),
|
|
PopupMenuItem(
|
|
value: _reportAction,
|
|
child: Text(l10n.reportComment),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
Text(
|
|
comment.content,
|
|
style: const TextStyle(color: Colors.white, fontSize: 14),
|
|
),
|
|
if (comment.isPending)
|
|
Padding(
|
|
padding: const EdgeInsets.only(top: 4),
|
|
child: Text(
|
|
l10n.underReview,
|
|
key: Key('comment-pending-${comment.id}'),
|
|
style: const TextStyle(
|
|
color: AppColors.blueSoft,
|
|
fontSize: 11,
|
|
),
|
|
),
|
|
),
|
|
Row(
|
|
children: [
|
|
TextButton.icon(
|
|
key: Key('comment-like-${comment.id}'),
|
|
onPressed: controller.likingComment(comment.id)
|
|
? null
|
|
: () => handlers.onLike(comment),
|
|
icon: Icon(
|
|
comment.liked
|
|
? Icons.favorite_rounded
|
|
: Icons.favorite_border_rounded,
|
|
size: 16,
|
|
),
|
|
label: Text('${comment.likeCount}'),
|
|
),
|
|
if (!isReply)
|
|
TextButton(
|
|
key: Key('comment-reply-${comment.id}'),
|
|
onPressed: () => handlers.onReply(comment),
|
|
child: Text(l10n.reply),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|