Files
worker/lib/features/news/presentation/widgets/related_article_card.dart
Phuoc Nguyen 19d9a3dc2d update loaing
2025-12-02 18:09:20 +07:00

120 lines
3.8 KiB
Dart

/// Related Article Card Widget
///
/// Compact horizontal card for displaying related articles.
/// Used in the news detail page to show similar content.
library;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:worker/core/widgets/loading_indicator.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:worker/core/constants/ui_constants.dart';
import 'package:worker/features/news/domain/entities/news_article.dart';
/// Related Article Card
///
/// Features:
/// - Horizontal layout
/// - 60x60 thumbnail
/// - Title (max 2 lines)
/// - Metadata: date and view count
/// - OnTap handler for navigation
class RelatedArticleCard extends StatelessWidget {
/// Article to display
final NewsArticle article;
/// Callback when card is tapped
final VoidCallback? onTap;
/// Constructor
const RelatedArticleCard({super.key, required this.article, this.onTap});
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return GestureDetector(
onTap: onTap,
child: Container(
margin: const EdgeInsets.only(bottom: AppSpacing.md),
padding: const EdgeInsets.all(AppSpacing.md),
decoration: BoxDecoration(
color: colorScheme.surface,
borderRadius: BorderRadius.circular(AppRadius.lg),
border: Border.all(color: colorScheme.outlineVariant),
),
child: Row(
children: [
// Thumbnail (60x60)
ClipRRect(
borderRadius: BorderRadius.circular(AppRadius.md),
child: CachedNetworkImage(
imageUrl: article.imageUrl,
width: 60,
height: 60,
fit: BoxFit.cover,
placeholder: (context, url) => Container(
width: 60,
height: 60,
color: colorScheme.surfaceContainerHighest,
child: const Center(
child: SizedBox(
width: 16,
height: 16,
child: CustomLoadingIndicator(color: colorScheme.primary, size: 20),
),
),
),
errorWidget: (context, url, error) => Container(
width: 60,
height: 60,
color: colorScheme.surfaceContainerHighest,
child: FaIcon(
FontAwesomeIcons.image,
size: 20,
color: colorScheme.onSurfaceVariant,
),
),
),
),
const SizedBox(width: AppSpacing.md),
// Content
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Title (max 2 lines)
Text(
article.title,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: colorScheme.onSurface,
height: 1.3,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 6),
// Metadata
Text(
'${article.formattedDate}${article.formattedViewCount} lượt xem',
style: TextStyle(
fontSize: 12,
color: colorScheme.onSurfaceVariant,
),
),
],
),
),
],
),
),
);
}
}