// ignore_for_file: deprecated_member_use import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; import 'package:didvan/models/infography/infography_content.dart' as inf; import 'package:didvan/models/tag.dart'; import 'package:didvan/routes/routes.dart'; import 'package:didvan/utils/category_labels.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/skeleton_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:persian_number_utility/persian_number_utility.dart'; /// کارت اینفوگرافی — دقیقا کپی از PodcastListCard (تب پادکست در media page). /// تفاوت‌ها: /// * به‌جای آیکن clock + مدت‌زمان، آیکن puzzle + دسته‌ی موضوعی نمایش داده می‌شود. /// * onTap به‌جای navigation به صفحه‌ی پادکست، تصویر را در InteractiveViewer باز می‌کند. class InfographyItem extends StatelessWidget { final String image; final String title; final String category; /// کلید English از metadata.category (مثلا 'political'). اگر داده شود، /// به‌جای `category` ـ والد، با ترجمه‌ی فارسی نمایش داده می‌شود. final String? metaCategory; final List tag; final String createdAt; final int id; final bool marked; final bool isLastItem; /// UUID محتوا در content-service. اگر null/خالی باشه به جای navigation به /// صفحه‌ی detail، تصویر در InteractiveViewer باز می‌شه (سازگاری با آیتم‌های legacy). final String? keycloakId; /// لینک خارجی (اختیاری). به صفحه‌ی detail پاس داده می‌شه تا دکمه‌ی «مشاهده منبع» نشون داده شه. final String? link; // ignore: unused_field final bool liked; // ignore: unused_field final int likes; final void Function(int id, bool value, bool shouldUpdate) onMarkChanged; // ignore: unused_field final void Function(int id, bool value, bool shouldUpdate) onLikedChanged; const InfographyItem({ super.key, required this.onMarkChanged, required this.image, required this.category, required this.title, required this.tag, required this.createdAt, required this.id, required this.marked, required this.liked, required this.likes, required this.onLikedChanged, this.metaCategory, this.isLastItem = false, this.keycloakId, this.link, }); void _openDetail(BuildContext context) { Navigator.of(context).pushNamed( Routes.infographyDetails, arguments: { 'item': inf.Content( id: id, marked: marked, liked: liked, likes: likes, createdAt: createdAt, title: title, image: image, category: category, tags: tag, metaCategory: metaCategory ?? '', keycloakId: keycloakId, link: link, ), if (keycloakId != null && keycloakId!.isNotEmpty) 'contentUuid': keycloakId, 'onMarkChanged': (int id, bool value) => onMarkChanged(id, value, true), }, ); } String _displayCategory() { final m = metaCategory; if (m != null && m.isNotEmpty) { final t = CategoryLabels.label(m); if (t.isNotEmpty) return t; } return category; } String _formatDate(String dateStr) { try { final date = DateTime.parse(dateStr); return date.toPersianDateStr(); } catch (e) { return dateStr; } } @override Widget build(BuildContext context) { final textTheme = Theme.of(context).textTheme; return GestureDetector( onTap: () => _openDetail(context), child: Column( children: [ Container( height: 120, margin: const EdgeInsets.only( bottom: 8, left: 16, right: 16, ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), ), child: ClipRRect( borderRadius: BorderRadius.circular(20), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.all(6.0), child: AspectRatio( aspectRatio: 1.42, child: ClipRRect( borderRadius: BorderRadius.circular(16), child: SkeletonImage( imageUrl: image, width: double.infinity, height: double.infinity, borderRadius: BorderRadius.circular(16), ), ), ), ), Expanded( child: Padding( padding: const EdgeInsets.fromLTRB(12, 3, 12, 10), child: Container( color: DesignConfig.isDark ? Colors.transparent : Colors.white, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ DidvanText( title, style: textTheme.bodyMedium?.copyWith( fontWeight: FontWeight.w600, color: DesignConfig.isDark ? const Color.fromARGB(255, 206, 206, 206) : Colors.black87, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), const Spacer(), Row( children: [ SvgPicture.asset( 'lib/assets/icons/calendar.svg', color: Theme.of(context).colorScheme.caption, ), const SizedBox(width: 4), DidvanText( _formatDate(createdAt), style: textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.caption, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), const SizedBox(height: 7), Row( children: [ // به‌جای آیکن ساعت (مدت زمان پادکست)، آیکن // دسته‌بندی + نام فارسی دسته نمایش داده می‌شود. SvgPicture.asset( 'lib/assets/icons/element-2.svg', color: Theme.of(context).colorScheme.caption, width: 16, height: 16, ), const SizedBox(width: 4), Expanded( child: DidvanText( _displayCategory().toPersianDigit(), style: textTheme.bodySmall?.copyWith( color: Theme.of(context) .colorScheme .caption, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ], ), ], ), ), ), ), ], ), ), ), if (!isLastItem) Divider( color: Colors.grey[300], thickness: 2, indent: 16, endIndent: 16, ), ], ), ); } }