import 'package:flutter/material.dart'; import '../../core/contracts/script_widget.dart'; import '../theme/app_theme.dart'; import 'app_card.dart'; import 'metadata_chip.dart'; import 'smart_image.dart'; class ScriptVideoCard extends StatefulWidget { final ScriptVideoItem item; final double width; final VoidCallback? onTap; final Color? textColor; const ScriptVideoCard({ super.key, required this.item, required this.width, this.onTap, this.textColor, }); @override State createState() => _ScriptVideoCardState(); } class _ScriptVideoCardState extends State { bool _isHovered = false; String? get _imageUrl { final imageCandidates = [ widget.item.posterPath, widget.item.coverUrl, widget.item.detailPoster, ]; for (final imageCandidate in imageCandidates) { if (imageCandidate.trim().isNotEmpty) return imageCandidate; } return null; } String? get _subtitle { final subtitleParts = [ if (widget.item.releaseDate.trim().isNotEmpty) widget.item.releaseDate, if (widget.item.genreTitle.trim().isNotEmpty) widget.item.genreTitle, ]; return subtitleParts.isEmpty ? null : subtitleParts.join(' ยท '); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final tokens = context.appTokens; final rating = widget.item.rating; final title = widget.item.title.trim().isEmpty ? widget.item.id : widget.item.title; return SizedBox( width: widget.width, child: AppCard( filled: false, enableHover: false, radius: tokens.radiusCard, padding: EdgeInsets.zero, onTap: widget.onTap, onHoverChanged: (isHovered) { if (_isHovered == isHovered) return; setState(() => _isHovered = isHovered); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Stack( fit: StackFit.expand, children: [ AnimatedOpacity( opacity: _isHovered ? 0.84 : 1, duration: const Duration(milliseconds: 160), child: SmartImage( url: _imageUrl, fallbackIcon: Icons.movie_outlined, borderRadius: tokens.posterRadius, ), ), Positioned.fill( child: AnimatedOpacity( opacity: _isHovered && widget.onTap != null ? 1 : 0, duration: const Duration(milliseconds: 160), child: IgnorePointer( child: DecoratedBox( decoration: BoxDecoration( color: Colors.black.withValues(alpha: 0.30), borderRadius: BorderRadius.circular( tokens.posterRadius, ), ), child: const Center( child: Icon( Icons.play_arrow_rounded, size: 32, color: Colors.white, ), ), ), ), ), ), if (rating != null && rating > 0) Positioned( top: 7, right: 7, child: MetadataChip( icon: Icons.star_rounded, label: rating.toStringAsFixed(1), foreground: tokens.ratingColor, background: Colors.black.withValues(alpha: 0.68), ), ), ], ), ), const SizedBox(height: 8), Text( title, maxLines: 1, overflow: TextOverflow.ellipsis, style: theme.textTheme.bodySmall?.copyWith( fontWeight: FontWeight.w500, color: widget.textColor, ), ), if (_subtitle case final subtitle?) ...[ const SizedBox(height: 2), Text( subtitle, maxLines: 1, overflow: TextOverflow.ellipsis, style: theme.textTheme.bodySmall?.copyWith( color: widget.textColor?.withValues(alpha: 0.55) ?? tokens.mutedForeground, ), ), ], ], ), ), ); } }