// Author: fruit.com.cn import 'package:flutter/material.dart'; import '../../../core/data/models/comment.dart'; import '../../../core/formatting/relative_date_time.dart'; import '../../../core/theme/app_colors.dart'; import '../../../core/theme/app_dimens.dart'; import '../../../core/widgets/remote_image.dart'; import '../../../l10n/app_localizations.dart'; /// 评论条目的交互回调集合。 class CommentInteractionHandlers { const CommentInteractionHandlers({required this.onReply}); final ValueChanged onReply; } /// 单条评论或回复的展示与操作行。 class CommentTile extends StatelessWidget { const CommentTile({ super.key, required this.comment, required this.handlers, this.isReply = false, }); final DramaComment comment; 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.only(top: 10, bottom: 12), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ _avatar(), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( name, style: const TextStyle( color: AppColors.muted, fontSize: 12, fontWeight: FontWeight.w400, ), ), const SizedBox(height: 2), Text( comment.content, style: const TextStyle( color: AppColors.cream, fontSize: 16, height: 1.4, ), ), 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: AppDimens.caption, ), ), ), if (comment.createdAt != null || !isReply) Padding( padding: const EdgeInsets.only(top: 4), child: _metadata(context, l10n), ), ], ), ), ], ), ); } Widget _avatar() { final size = isReply ? 28.0 : 40.0; if (comment.avatarUrl.isEmpty) { return CircleAvatar( radius: size / 2, backgroundColor: AppColors.raised, child: Icon( Icons.person_rounded, size: isReply ? 16 : 22, color: AppColors.cream, ), ); } return ClipOval( child: SizedBox( width: size, height: size, child: RemoteImage(comment.avatarUrl, fit: BoxFit.cover), ), ); } Widget _metadata(BuildContext context, AppLocalizations l10n) { final createdAt = comment.createdAt; return Row( children: [ if (createdAt != null) Text( formatRelativeDateTime(createdAt, l10n), style: const TextStyle(color: AppColors.subtle, fontSize: 12), ), if (createdAt != null && !isReply) ...[ const SizedBox(width: 8), const Text( '·', style: TextStyle(color: AppColors.muted, fontSize: 12), ), const SizedBox(width: 8), ], if (!isReply) TextButton( key: Key('comment-reply-${comment.id}'), style: TextButton.styleFrom( foregroundColor: AppColors.muted, padding: EdgeInsets.zero, minimumSize: const Size(0, 24), tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), onPressed: () => handlers.onReply(comment), child: Text( l10n.reply, style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w400), ), ), ], ); } }