import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:shimmer/shimmer.dart'; import '../estado/estado_radio.dart'; import '../modelos/emisora.dart'; /// Tarjeta compacta para mostrar una emisora en listas y grids. /// Incluye botón de favorito visible en ambos modos. class TarjetaEmisora extends StatefulWidget { final Emisora emisora; final VoidCallback? onTap; final bool esCompacta; const TarjetaEmisora({ super.key, required this.emisora, this.onTap, this.esCompacta = false, }); @override State createState() => _TarjetaEmisoraState(); } class _TarjetaEmisoraState extends State { bool _esFavorito = false; bool _toggling = false; @override void initState() { super.initState(); _checkFavorito(); } Future _checkFavorito() async { final fav = await context.read().esFavorito(widget.emisora.uuid); if (mounted) setState(() => _esFavorito = fav); } Future _toggle() async { if (_toggling) return; _toggling = true; final estado = context.read(); final esFav = await estado.toggleFavorito(widget.emisora); if (mounted) setState(() => _esFavorito = esFav); _toggling = false; if (mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text(esFav ? '${widget.emisora.nombre} añadida a favoritos' : '${widget.emisora.nombre} eliminada de favoritos'), duration: const Duration(seconds: 2), )); } } @override Widget build(BuildContext context) { final theme = Theme.of(context); return Card( clipBehavior: Clip.antiAlias, child: InkWell( onTap: widget.onTap, child: widget.esCompacta ? _buildCompacta(theme) : _buildCompleta(theme), ), ); } Widget _buildCompleta(ThemeData theme) { return Stack( children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ AspectRatio( aspectRatio: 1, child: _logo(theme, 60), ), Padding( padding: const EdgeInsets.fromLTRB(8, 8, 8, 4), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.emisora.nombre, style: theme.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.bold), maxLines: 2, overflow: TextOverflow.ellipsis, ), if (widget.emisora.pais != null) Text( widget.emisora.pais!, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ), ], ), // Botón favorito superpuesto (esquina superior derecha) Positioned( top: 4, right: 4, child: _botonFavorito(theme, mini: true), ), ], ); } Widget _buildCompacta(ThemeData theme) { return ListTile( leading: SizedBox(width: 48, height: 48, child: _logo(theme, 24)), title: Text( widget.emisora.nombre, maxLines: 1, overflow: TextOverflow.ellipsis, ), subtitle: Text( [widget.emisora.pais, widget.emisora.idioma] .where((s) => s != null && s.isNotEmpty) .join(' · '), maxLines: 1, overflow: TextOverflow.ellipsis, ), trailing: _botonFavorito(theme, mini: false), ); } Widget _botonFavorito(ThemeData theme, {required bool mini}) { return Material( color: mini ? theme.colorScheme.surface.withValues(alpha: 0.8) : Colors.transparent, shape: const CircleBorder(), child: InkWell( customBorder: const CircleBorder(), onTap: _toggle, child: Padding( padding: EdgeInsets.all(mini ? 6 : 4), child: Icon( _esFavorito ? Icons.favorite_rounded : Icons.favorite_outline_rounded, color: _esFavorito ? theme.colorScheme.error : theme.colorScheme.onSurfaceVariant, size: mini ? 18 : 22, ), ), ), ); } Widget _logo(ThemeData theme, double iconSize) { if (widget.emisora.favicon != null && widget.emisora.favicon!.isNotEmpty) { return CachedNetworkImage( imageUrl: widget.emisora.favicon!, fit: BoxFit.cover, placeholder: (_, __) => _shimmer(theme), errorWidget: (_, __, ___) => _iconoFallback(theme, iconSize), ); } return _iconoFallback(theme, iconSize); } Widget _shimmer(ThemeData theme) { return Shimmer.fromColors( baseColor: theme.colorScheme.surfaceContainerHighest, highlightColor: theme.colorScheme.surface, child: Container(color: theme.colorScheme.surfaceContainerHighest), ); } Widget _iconoFallback(ThemeData theme, double size) { return Container( color: theme.colorScheme.primaryContainer, child: Icon(Icons.radio, size: size, color: theme.colorScheme.onPrimaryContainer), ); } } /// Placeholder shimmer para listas en carga. class TarjetaEmisoraShimmer extends StatelessWidget { const TarjetaEmisoraShimmer({super.key}); @override Widget build(BuildContext context) { final theme = Theme.of(context); return Shimmer.fromColors( baseColor: theme.colorScheme.surfaceContainerHighest, highlightColor: theme.colorScheme.surface, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ AspectRatio( aspectRatio: 1, child: Container(color: theme.colorScheme.surfaceContainerHighest), ), const SizedBox(height: 8), Container(height: 14, color: theme.colorScheme.surfaceContainerHighest), const SizedBox(height: 4), Container(height: 12, width: 60, color: theme.colorScheme.surfaceContainerHighest), ], ), ); } }