import 'package:flutter/material.dart'; import '../models/video_item.dart'; class VideoResultCard extends StatelessWidget { const VideoResultCard({ super.key, required this.video, required this.onTap, this.trailing, }); final VideoItem video; final VoidCallback onTap; final Widget? trailing; @override Widget build(BuildContext context) { final isWide = MediaQuery.sizeOf(context).width >= 700; return Material( color: Colors.transparent, child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(14), child: Padding( padding: EdgeInsets.all(8), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(child: isWide ? _buildWide(context) : _buildCompact(context)), if (trailing != null) trailing!, ], ), ), ), ); } Widget _buildWide(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 300, child: _Thumbnail(video: video), ), SizedBox(width: 18), Expanded( child: Padding( padding: EdgeInsets.only(top: 4, right: 12), child: _VideoText(video: video), ), ), ], ); } Widget _buildCompact(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _Thumbnail(video: video), SizedBox(height: 10), Padding( padding: EdgeInsets.symmetric(horizontal: 2), child: _VideoText(video: video), ), ], ); } } class _Thumbnail extends StatelessWidget { const _Thumbnail({required this.video}); final VideoItem video; @override Widget build(BuildContext context) { return AspectRatio( aspectRatio: 16 / 9, child: ClipRRect( borderRadius: BorderRadius.circular(12), child: Stack( fit: StackFit.expand, children: [ ColoredBox( color: Theme.of(context).colorScheme.surfaceContainerHigh, child: Image.network( video.thumbnailUrl, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { return Center( child: Icon( Icons.broken_image_outlined, size: 42, color: Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.62), ), ); }, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) { return child; } return Center( child: CircularProgressIndicator(strokeWidth: 2), ); }, ), ), if (video.durationLabel.isNotEmpty) Positioned( right: 7, bottom: 7, child: DecoratedBox( decoration: BoxDecoration( color: Colors.black87, borderRadius: BorderRadius.circular(5), ), child: Padding( padding: EdgeInsets.symmetric( horizontal: 6, vertical: 3, ), child: Text( video.durationLabel, style: TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w600, ), ), ), ), ), ], ), ), ); } } class _VideoText extends StatelessWidget { const _VideoText({required this.video}); final VideoItem video; @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( video.title, maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 16, height: 1.25, fontWeight: FontWeight.w600, ), ), SizedBox(height: 7), Row( children: [ Icon( Icons.account_circle_outlined, size: 18, color: Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.86), ), SizedBox(width: 6), Expanded( child: Text( video.author, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.86), fontSize: 14, ), ), ), ], ), if (video.viewCount != null || video.likeCount != null) ...[ SizedBox(height: 6), Text( [ if (video.viewCount != null) '${_compact(video.viewCount!)} vues', if (video.likeCount != null) '${_compact(video.likeCount!)} likes', ].join(' • '), maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: Color(0x73FFFFFF), fontSize: 12, ), ), ], if (video.description.trim().isNotEmpty) ...[ SizedBox(height: 6), Text( video.description .replaceAll(RegExp(r'\s+'), ' ') .trim(), maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle( color: Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.62), fontSize: 12, height: 1.3, ), ), ], ], ); } String _compact(int value) { if (value >= 1000000000) { return '${(value / 1000000000).toStringAsFixed(value >= 10000000000 ? 0 : 1)} Md'; } if (value >= 1000000) { return '${(value / 1000000).toStringAsFixed(value >= 10000000 ? 0 : 1)} M'; } if (value >= 1000) { return '${(value / 1000).toStringAsFixed(value >= 10000 ? 0 : 1)} k'; } return '$value'; } }