import 'package:flutter/material.dart'; import 'package:patbond_flutter/core/theme/app_theme.dart'; import 'package:patbond_flutter/core/widgets/like_button.dart'; import 'package:patbond_flutter/core/widgets/pet_avatar.dart'; import 'package:patbond_flutter/core/widgets/post_media_grid.dart'; import 'package:patbond_flutter/features/community/community_display.dart'; import 'package:patbond_flutter/features/community/community_models.dart'; import 'package:patbond_flutter/widgets/common.dart'; /// 帖子卡三形态(05 号规范 §2.1/§3.1):home 私有 `_PostCard` 的升级 /// 迁移,按媒体形态分支—— /// /// | 形态 | 媒体区 | /// | --- | --- | /// | 单图(mediaCount ≤ 1 且有封面) | 通栏出血 4:3 | /// | 多图(mediaCount > 1) | [PostMediaGrid] 折叠封面(FeedCard 契约只带封面 + 计数),水平 padding 14 | /// | 纯文字(无封面) | 无媒体区,正文放宽 ≤6 行、15/1.6 | /// /// 头部行:作者头像 32 + 名字 14/w700 + 时间 12 `inkSoft`;求助帖 /// 元信息尾追加 `TagPill(accent)`。降级作者([AuthorSummary.isDegraded]) /// 渲染占位头像 + 「宠友」。操作行:[LikeButton](点赞 / 收藏)+ 评论 /// 计数 + 分享,各钮触控 44;互动回调传 null 即纯展示(T3-14 形态, /// ToggleSync 接线属 T3-15/16)。 class PostCard extends StatelessWidget { const PostCard({ required this.card, super.key, this.onTap, this.onLikeTap, this.onCommentTap, this.onBookmarkTap, this.onShareTap, this.now, }); final FeedCard card; /// 整卡点按(帖子详情入口)。 final VoidCallback? onTap; final VoidCallback? onLikeTap; final VoidCallback? onCommentTap; final VoidCallback? onBookmarkTap; final VoidCallback? onShareTap; /// 相对时间的参考时钟(测试注入;缺省取当前时间)。 final DateTime? now; bool get _isTextOnly => card.coverImage == null; @override Widget build(BuildContext context) { return Card( clipBehavior: Clip.antiAlias, child: InkWell( onTap: onTap, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _header(context), if (card.coverImage != null) card.mediaCount > 1 ? Padding( padding: const EdgeInsets.symmetric(horizontal: 14), child: PostMediaGrid( urls: [card.coverImage!.url], totalCount: card.mediaCount, ), ) : AspectRatio( aspectRatio: 4 / 3, child: RemoteImage(url: card.coverImage!.url), ), _body(context), _actionRow(), ], ), ), ); } Widget _header(BuildContext context) { return Padding( padding: const EdgeInsets.all(14), child: Row( children: [ PetAvatar(size: PetAvatarSize.sm, url: card.author.avatarUrl), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( authorDisplayName(card.author), maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w700, ), ), const SizedBox(height: 2), Row( children: [ Text( feedRelativeTime(card.publishedAt, now: now), style: const TextStyle( color: AppColors.inkSoft, fontSize: 12, ), ), if (card.category == PostCategory.help) ...[ const SizedBox(width: 6), const TagPill('求助', color: AppColors.accent), ], ], ), ], ), ), ], ), ); } Widget _body(BuildContext context) { return Padding( padding: const EdgeInsets.fromLTRB(14, 12, 14, 0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (card.title != null) ...[ Text( card.title!, maxLines: 1, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 6), ], Text( card.contentPreview, // 纯文字帖放宽至 6 行并升字号补偿视觉重量(§2.1)。 maxLines: _isTextOnly ? 6 : 2, overflow: TextOverflow.ellipsis, style: _isTextOnly ? const TextStyle( color: AppColors.ink, fontSize: 15, height: 1.6, ) : Theme.of(context).textTheme.bodyMedium, ), ], ), ); } Widget _actionRow() { return Padding( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 2), child: Row( children: [ LikeButton( variant: LikeButtonVariant.like, active: card.likedByMe, count: card.likeCount, onPressed: onLikeTap, semanticLabel: '点赞', ), const SizedBox(width: 4), _CommentCount(count: card.commentCount, onPressed: onCommentTap), const SizedBox(width: 4), LikeButton( variant: LikeButtonVariant.bookmark, active: card.bookmarkedByMe, count: card.bookmarkCount, onPressed: onBookmarkTap, semanticLabel: '收藏', ), const Spacer(), InkWell( onTap: onShareTap, borderRadius: BorderRadius.circular(AppRadius.pill), child: const SizedBox( width: 44, height: 44, child: Icon( Icons.ios_share_outlined, size: 20, color: AppColors.inkSoft, ), ), ), ], ), ); } } /// 评论计数钮(与 LikeButton 同视觉规格,无激活态)。 class _CommentCount extends StatelessWidget { const _CommentCount({required this.count, this.onPressed}); final int count; final VoidCallback? onPressed; @override Widget build(BuildContext context) { return InkWell( onTap: onPressed, borderRadius: BorderRadius.circular(AppRadius.pill), child: ConstrainedBox( constraints: const BoxConstraints(minWidth: 44, minHeight: 44), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.chat_bubble_outline, size: 20, color: AppColors.inkSoft, ), const SizedBox(width: 4), Text( '$count', style: const TextStyle( color: AppColors.inkSoft, fontSize: 13, fontWeight: FontWeight.w600, ), ), ], ), ), ), ); } }