import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:provider/provider.dart'; import '../estado/estado_radio.dart'; import '../widgets/pluri_glass_surface.dart'; import '../widgets/pluri_icon.dart'; import '../widgets/pluri_layout.dart'; import '../widgets/pluri_premium_widgets.dart'; import 'package:pluriwave/widgets/tarjeta_emisora.dart'; import 'reproducir_minimizado.dart'; const _paises = [ ('Espana', 'ES'), ('USA', 'US'), ('Mexico', 'MX'), ('Argentina', 'AR'), ('UK', 'GB'), ('Francia', 'FR'), ('Alemania', 'DE'), ('Italia', 'IT'), ('Brasil', 'BR'), ('Japon', 'JP'), ]; const _idiomas = [ 'spanish', 'english', 'french', 'german', 'portuguese', 'italian', 'japanese', 'arabic', 'russian', ]; class PantallaBuscar extends StatefulWidget { const PantallaBuscar({super.key}); @override State createState() => _PantallaBuscarState(); } class _PantallaBuscarState extends State { final _controller = TextEditingController(); String? _paisSeleccionado; String? _idiomaSeleccionado; @override void dispose() { _controller.dispose(); super.dispose(); } void _buscar() { final q = _controller.text.trim(); context.read().buscar( nombre: q.isNotEmpty ? q : null, pais: _paisSeleccionado, idioma: _idiomaSeleccionado, ); } @override Widget build(BuildContext context) { final estado = context.watch(); final theme = Theme.of(context); return ListView( padding: PluriLayout.pageListPadding, children: [ PluriScreenHeader( title: 'Buscar senal', subtitle: 'Encontra radios por nombre, pais o idioma con filtros rapidos y alto contraste.', glyph: PluriIconGlyph.search, trailing: const PluriStatusPill( icon: Icons.tune_rounded, label: 'Filtros', ), ), Padding( padding: const EdgeInsets.fromLTRB(PluriLayout.horizontal, 10, PluriLayout.horizontal, 0), child: PluriGlassSurface( padding: const EdgeInsets.all(10), borderRadius: BorderRadius.circular(999), child: SearchBar( controller: _controller, hintText: 'Radio Horizonte, jazz, noticias...', leading: const PluriIcon( glyph: PluriIconGlyph.search, variant: PluriIconVariant.filled, ), trailing: [ if (_controller.text.isNotEmpty) IconButton( icon: const Icon(Icons.clear), onPressed: () { _controller.clear(); setState(() {}); _buscar(); }, ), ], onSubmitted: (_) => _buscar(), onChanged: (_) => setState(() {}), ), ), ), _seccionCercanas(estado), _seccionFiltro( 'Pais', _paises.map((p) => (p.$1, p.$2)).toList(), _paisSeleccionado, (v) { setState(() => _paisSeleccionado = v); _buscar(); }, ), _seccionFiltro( 'Idioma', _idiomas.map((i) => (i, i)).toList(), _idiomaSeleccionado, (v) { setState(() => _idiomaSeleccionado = v); _buscar(); }, ), _resultados(estado, theme), ], ); } Widget _seccionCercanas(EstadoRadio estado) { final theme = Theme.of(context); final pais = estado.paisCercanoDetectado; return Padding( padding: const EdgeInsets.fromLTRB(PluriLayout.horizontal, 8, PluriLayout.horizontal, 0), child: PluriGlassSurface( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( pais == null ? 'Emisoras cercanas' : 'Emisoras cercanas - $pais', style: theme.textTheme.labelLarge?.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('Buscar cerca'), ), ], ), 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 _seccionFiltro( String titulo, List<(String, String)> opciones, String? seleccionado, void Function(String?) onChanged, ) { final theme = Theme.of(context); return Padding( padding: const EdgeInsets.fromLTRB(PluriLayout.horizontal, 8, PluriLayout.horizontal, 0), child: PluriGlassSurface( padding: const EdgeInsets.all(10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( titulo, style: theme.textTheme.labelLarge?.copyWith( fontWeight: FontWeight.w900, ), ), const SizedBox(height: 6), SizedBox( height: 40, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: opciones.length, separatorBuilder: (_, __) => const SizedBox(width: 8), itemBuilder: (_, i) { final (label, value) = opciones[i]; final sel = seleccionado == value; return FilterChip( label: Text(label), selected: sel, visualDensity: VisualDensity.compact, onSelected: (_) => onChanged(sel ? null : value), ); }, ), ), ], ), ), ); } Widget _resultados(EstadoRadio estado, ThemeData theme) { if (estado.cargandoBusqueda) { return const SizedBox( height: 220, child: Center(child: CircularProgressIndicator()), ); } final resultados = estado.resultadosBusqueda; if (resultados.isEmpty) { final sinFiltros = _controller.text.isEmpty && _paisSeleccionado == null && _idiomaSeleccionado == null; return SizedBox( height: 260, child: PluriEmptyState( glyph: PluriIconGlyph.search, title: sinFiltros ? 'Busca una emisora' : 'Sin resultados', subtitle: sinFiltros ? 'Usa la barra superior o los chips para descubrir senales de todo el mundo.' : 'Proba quitar filtros o escribir otro nombre para encontrar una senal activa.', ), ); } final total = resultados.length + (estado.hayMasBusqueda ? 1 : 0); return ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.all(PluriLayout.horizontal), itemCount: total, separatorBuilder: (_, __) => const SizedBox(height: 10), itemBuilder: (context, i) { if (i >= resultados.length) { if (!estado.cargandoMasBusqueda) { Future.microtask(estado.cargarMasBusqueda); } return const Padding( padding: EdgeInsets.all(18), child: Center(child: CircularProgressIndicator()), ); } if (i >= resultados.length - 5 && estado.hayMasBusqueda) { Future.microtask(estado.cargarMasBusqueda); } return TarjetaEmisora( emisora: resultados[i], esCompacta: true, onTap: () => reproducirMinimizado(context, resultados[i]), ).animate().fadeIn(delay: (i.clamp(0, 12) * 20).ms).slideY(begin: 0.08); }, ); } }