import 'package:flutter/material.dart'; import '../../../../common/theme/theme.dart'; import '../../../../sample/community_sample_data.dart'; import '../community_ui.dart'; /// Kartu postingan. [expanded] menampilkan teks penuh (halaman detail). class CommunityPostCard extends StatefulWidget { const CommunityPostCard({ super.key, required this.post, this.onTap, this.onGroupTap, this.expanded = false, }); final CommunityPost post; final VoidCallback? onTap; final VoidCallback? onGroupTap; final bool expanded; @override State createState() => _CommunityPostCardState(); } class _CommunityPostCardState extends State { late bool _isLiked = widget.post.isLiked; late int _likeCount = widget.post.likeCount; bool _isSaved = false; void _toggleLike() { setState(() { _isLiked = !_isLiked; _likeCount += _isLiked ? 1 : -1; }); } @override Widget build(BuildContext context) { final post = widget.post; return Container( margin: const EdgeInsets.fromLTRB(16, 0, 16, 14), decoration: communityCardDecoration(), child: Material( type: MaterialType.transparency, child: InkWell( borderRadius: BorderRadius.circular(20), onTap: widget.onTap, child: Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildHeader(post), const SizedBox(height: 12), Text( post.content, maxLines: widget.expanded ? null : 4, overflow: widget.expanded ? null : TextOverflow.ellipsis, style: AppStyle.md.copyWith( height: 1.5, fontWeight: FontWeight.w500, ), ), if (post.image != null) ...[ const SizedBox(height: 12), ClipRRect( borderRadius: BorderRadius.circular(16), child: AspectRatio( aspectRatio: 16 / 10, child: Image.asset(post.image!, fit: BoxFit.cover), ), ), ], if (post.merchantName != null) ...[ const SizedBox(height: 10), _MerchantTag(name: post.merchantName!), ], const SizedBox(height: 6), _buildActions(post), ], ), ), ), ), ); } Widget _buildHeader(CommunityPost post) { return Row( children: [ CommunityAvatar(member: post.author, size: 42), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Flexible( child: Text( post.author.name, maxLines: 1, overflow: TextOverflow.ellipsis, style: AppStyle.md.copyWith(fontWeight: FontWeight.w700), ), ), if (post.author.badge != null) ...[ const SizedBox(width: 6), _AuthorBadge(label: post.author.badge!), ], ], ), const SizedBox(height: 2), GestureDetector( onTap: widget.onGroupTap, child: Text.rich( TextSpan( children: [ TextSpan( text: '${post.group.emoji} ${post.group.name}', style: const TextStyle( color: AppColor.textPrimary, fontWeight: FontWeight.w600, ), ), TextSpan(text: ' ยท ${formatTimeAgo(post.createdAt)}'), ], ), maxLines: 1, overflow: TextOverflow.ellipsis, style: AppStyle.xs.copyWith(color: CommunityColor.muted), ), ), ], ), ), IconButton( onPressed: () {}, visualDensity: VisualDensity.compact, icon: const Icon( Icons.more_horiz_rounded, color: CommunityColor.muted, ), ), ], ); } Widget _buildActions(CommunityPost post) { return Row( children: [ _ActionButton( icon: _isLiked ? Icons.favorite_rounded : Icons.favorite_border_rounded, label: formatCompact(_likeCount), color: _isLiked ? AppColor.primary : CommunityColor.muted, onTap: _toggleLike, ), _ActionButton( icon: Icons.chat_bubble_outline_rounded, label: formatCompact(post.commentCount), color: CommunityColor.muted, onTap: widget.onTap, ), _ActionButton( icon: Icons.ios_share_rounded, label: 'Bagikan', color: CommunityColor.muted, onTap: () {}, ), const Spacer(), IconButton( onPressed: () => setState(() => _isSaved = !_isSaved), visualDensity: VisualDensity.compact, icon: Icon( _isSaved ? Icons.bookmark_rounded : Icons.bookmark_border_rounded, size: 22, color: _isSaved ? AppColor.primary : CommunityColor.muted, ), ), ], ); } } class _AuthorBadge extends StatelessWidget { const _AuthorBadge({required this.label}); final String label; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: CommunityColor.blush, borderRadius: BorderRadius.circular(999), ), child: Text( label, style: AppStyle.xs.copyWith( fontSize: 10, color: AppColor.primary, fontWeight: FontWeight.w700, ), ), ); } } class _MerchantTag extends StatelessWidget { const _MerchantTag({required this.name}); final String name; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( color: CommunityColor.background, borderRadius: BorderRadius.circular(999), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.storefront_rounded, size: 14, color: AppColor.primary, ), const SizedBox(width: 6), Text(name, style: AppStyle.xs.copyWith(fontWeight: FontWeight.w700)), ], ), ); } } class _ActionButton extends StatelessWidget { const _ActionButton({ required this.icon, required this.label, required this.color, this.onTap, }); final IconData icon; final String label; final Color color; final VoidCallback? onTap; @override Widget build(BuildContext context) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(999), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8), child: Row( children: [ AnimatedSwitcher( duration: const Duration(milliseconds: 200), transitionBuilder: (child, animation) => ScaleTransition(scale: animation, child: child), child: Icon(icon, key: ValueKey(icon), size: 20, color: color), ), const SizedBox(width: 6), Text( label, style: AppStyle.sm.copyWith( color: color, fontWeight: FontWeight.w600, ), ), ], ), ), ); } }