import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:provider/provider.dart'; import 'package:shimmer/shimmer.dart' as shimmer; import '../estado/estado_radio.dart'; import '../tema/pluriwave_theme.dart'; import '../widgets/pluri_glass_surface.dart'; import '../widgets/pluri_icon.dart'; import '../widgets/pluri_premium_widgets.dart'; import 'package:pluriwave/widgets/tarjeta_emisora.dart'; import 'reproducir_minimizado.dart'; /// Pantalla principal: emisoras populares y por género. class PantallaInicio extends StatefulWidget { const PantallaInicio({super.key}); @override State createState() => _PantallaInicioState(); } class _PantallaInicioState extends State { static const _generos = [ 'pop', 'rock', 'jazz', 'classical', 'electronic', 'news', 'talk', 'hip-hop', 'country', 'metal', 'reggae', 'latin', ]; String? _generoSeleccionado; @override Widget build(BuildContext context) { final estado = context.watch(); final theme = Theme.of(context); final t = context.pluriTokens; return RefreshIndicator( onRefresh: estado.cargarPopulares, child: CustomScrollView( slivers: [ SliverToBoxAdapter(child: _heroHeader(context, estado)), SliverToBoxAdapter(child: _seccionCercanas(estado, theme)), SliverToBoxAdapter(child: _seccionTendencias(estado, theme)), SliverToBoxAdapter(child: _chipGeneros(context, theme)), if (estado.error != null) SliverToBoxAdapter(child: _errorBanner(estado, theme)), SliverPadding( padding: EdgeInsets.fromLTRB(t.spacingMd, 0, t.spacingMd, 124), sliver: _gridEmisoras(estado), ), ], ), ); } Widget _heroHeader(BuildContext context, EstadoRadio estado) { return PluriScreenHeader( title: 'PluriWave', subtitle: 'Radio global en vivo con senales limpias, favoritos inteligentes y una experiencia visual de concurso.', glyph: PluriIconGlyph.home, primaryActionLabel: 'Explorar emisoras', onPrimaryAction: estado.cargarPopulares, trailing: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ PluriStatusPill( icon: Icons.public_rounded, label: '${estado.emisorasInicio.length} radios', accent: Theme.of(context).colorScheme.secondary, ), const SizedBox(height: 8), const PluriStatusPill( icon: Icons.hd_rounded, label: 'Calidad HD', ), ], ), ); } Widget _seccionCercanas(EstadoRadio estado, ThemeData theme) { final pais = estado.paisCercanoDetectado; return Padding( padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), child: PluriGlassSurface( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( pais == null ? 'Cerca de vos' : 'Cerca de vos ? $pais', style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w900, ), ), ), TextButton.icon( onPressed: estado.cargandoCercanas ? null : estado.cargarEmisorasCercanas, icon: estado.cargandoCercanas ? const SizedBox( width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2), ) : const Icon(Icons.my_location_rounded, size: 18), label: const Text('Detectar'), ), ], ), if (estado.errorCercanas != null) Text( estado.errorCercanas!, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.error, ), ), if (estado.emisorasCercanas.isNotEmpty) ...[ const SizedBox(height: 8), SizedBox( height: 76, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: estado.emisorasCercanas.length, separatorBuilder: (_, __) => const SizedBox(width: 8), itemBuilder: (context, i) { final emisora = estado.emisorasCercanas[i]; return SizedBox( width: 260, child: TarjetaEmisora( emisora: emisora, esCompacta: true, onTap: () => reproducirMinimizado(context, emisora), ), ); }, ), ), ], ], ), ), ); } Widget _seccionTendencias(EstadoRadio estado, ThemeData theme) { return Padding( padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), child: PluriGlassSurface( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Radar en directo', style: theme.textTheme.titleMedium), const SizedBox(height: 8), SizedBox( height: 56, child: estado.cargandoPopulares ? ListView.separated( scrollDirection: Axis.horizontal, itemCount: 5, separatorBuilder: (_, __) => const SizedBox(width: 8), itemBuilder: (_, __) => _ChipShimmer(theme: theme), ) : ListView.separated( scrollDirection: Axis.horizontal, itemCount: estado.tendencias.length, separatorBuilder: (_, __) => const SizedBox(width: 8), itemBuilder: (context, i) { final e = estado.tendencias[i]; return ActionChip( avatar: const Icon( Icons.graphic_eq_rounded, size: 18, ), label: Text(e.nombre, maxLines: 1), onPressed: () => reproducirMinimizado(context, e), ).animate().fadeIn(delay: (i * 50).ms); }, ), ), ], ), ), ); } Widget _chipGeneros(BuildContext context, ThemeData theme) { return Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 8), child: PluriGlassSurface( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Géneros', style: theme.textTheme.titleMedium), const SizedBox(height: 8), Wrap( spacing: 8, runSpacing: 4, children: _generos.map((g) { final seleccionado = _generoSeleccionado == g; return FilterChip( label: Text(g), selected: seleccionado, onSelected: (_) { setState(() { _generoSeleccionado = seleccionado ? null : g; }); if (!seleccionado) { context.read().buscar(tag: g); } else { context.read().cargarPopulares(); } }, ); }).toList(), ), ], ), ), ); } Widget _errorBanner(EstadoRadio estado, ThemeData theme) { return Padding( padding: const EdgeInsets.all(16), child: PluriGlassSurface( padding: const EdgeInsets.all(12), child: Row( children: [ Icon(Icons.wifi_off, color: theme.colorScheme.error), const SizedBox(width: 8), Expanded(child: Text(estado.error!)), TextButton( onPressed: estado.cargarPopulares, child: const Text('Reintentar'), ), ], ), ), ); } Widget _gridEmisoras(EstadoRadio estado) { final emisoras = _generoSeleccionado != null ? estado.resultadosBusqueda : estado.emisorasInicio; final cargando = estado.cargandoPopulares || (_generoSeleccionado != null && estado.cargandoBusqueda); if (cargando) { return SliverGrid( delegate: SliverChildBuilderDelegate( (_, __) => const TarjetaEmisoraShimmer(), childCount: 12, ), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 0.78, crossAxisSpacing: 12, mainAxisSpacing: 12, ), ); } if (emisoras.isEmpty) { return const SliverFillRemaining( child: PluriEmptyState( glyph: PluriIconGlyph.home, title: 'No hay emisoras disponibles', subtitle: 'Proba refrescar o elegir otro g?nero para volver a capturar se?al.', ), ); } return SliverGrid( delegate: SliverChildBuilderDelegate( (context, i) => TarjetaEmisora( emisora: emisoras[i], onTap: () => reproducirMinimizado(context, emisoras[i]), ).animate().fadeIn(delay: (i * 30).ms).slideY(begin: 0.1), childCount: emisoras.length, ), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 0.78, crossAxisSpacing: 12, mainAxisSpacing: 12, ), ); } } class _ChipShimmer extends StatelessWidget { final ThemeData theme; const _ChipShimmer({required this.theme}); @override Widget build(BuildContext context) { return shimmer.Shimmer.fromColors( baseColor: theme.colorScheme.surfaceContainerHighest, highlightColor: theme.colorScheme.surface, child: Container( width: 120, height: 56, decoration: BoxDecoration( color: theme.colorScheme.surfaceContainerHighest, borderRadius: BorderRadius.circular(20), ), ), ); } }