import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:provider/provider.dart'; import '../estado/estado_radio.dart'; import '../l10n/gen/app_localizations.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 = [ ('countrySpain', 'ES'), ('countryUsa', 'US'), ('countryMexico', 'MX'), ('countryArgentina', 'AR'), ('countryUk', 'GB'), ('countryFrance', 'FR'), ('countryGermany', 'DE'), ('countryItaly', 'IT'), ('countryBrazil', 'BR'), ('countryJapan', 'JP'), ]; const _idiomas = [ ('spanish', 'languageNameSpanish'), ('english', 'languageNameEnglish'), ('french', 'languageNameFrench'), ('german', 'languageNameGerman'), ('portuguese', 'languageNamePortuguese'), ('italian', 'languageNameItalian'), ('japanese', 'languageNameJapanese'), ('arabic', 'languageNameArabic'), ('russian', 'languageNameRussian'), ]; class PantallaBuscar extends StatefulWidget { const PantallaBuscar({super.key}); @override State createState() => _PantallaBuscarState(); } class _PantallaBuscarState extends State { final _controller = TextEditingController(); String? _paisSeleccionado; String? _idiomaSeleccionado; int? _calidadMinima; @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, minBitrate: _calidadMinima, ); } @override Widget build(BuildContext context) { final estado = context.watch(); final theme = Theme.of(context); final l10n = AppLocalizations.of(context); return ListView( padding: PluriLayout.pageListPadding, children: [ PluriScreenHeader( title: l10n.searchScreenTitle, subtitle: l10n.searchScreenSubtitle, glyph: PluriIconGlyph.search, trailing: PluriStatusPill( icon: Icons.tune_rounded, label: l10n.searchFiltersLabel, ), ), 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: l10n.searchHint, 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(() {}), ), ), ), _seccionFiltro( l10n.searchCountryFilterLabel, _paises.map((p) => (_countryLabel(l10n, p.$1), p.$2)).toList(), _paisSeleccionado, (v) { setState(() => _paisSeleccionado = v); _buscar(); }, ), _seccionFiltro( l10n.searchLanguageFilterLabel, _idiomas.map((i) => (_languageLabel(l10n, i.$2), i.$1)).toList(), _idiomaSeleccionado, (v) { setState(() => _idiomaSeleccionado = v); _buscar(); }, ), _seccionFiltroInt( l10n.searchMinQualityFilterLabel, const [('64 kbps', 64), ('96 kbps', 96), ('128 kbps', 128), ('192 kbps', 192), ('320 kbps', 320)], _calidadMinima, (v) { setState(() => _calidadMinima = v); _buscar(); }, ), _resultados(estado, theme), ], ); } 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 _seccionFiltroInt( String titulo, List<(String, int)> opciones, int? seleccionado, void Function(int?) 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) { final l10n = AppLocalizations.of(context); 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 ? l10n.searchEmptyTitle : l10n.searchNoResultsTitle, subtitle: sinFiltros ? l10n.searchEmptySubtitle : l10n.searchNoResultsSubtitle, ), ); } 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); }, ); } String _countryLabel(AppLocalizations l10n, String key) => switch (key) { 'countrySpain' => l10n.countrySpain, 'countryUsa' => l10n.countryUsa, 'countryMexico' => l10n.countryMexico, 'countryArgentina' => l10n.countryArgentina, 'countryUk' => l10n.countryUk, 'countryFrance' => l10n.countryFrance, 'countryGermany' => l10n.countryGermany, 'countryItaly' => l10n.countryItaly, 'countryBrazil' => l10n.countryBrazil, 'countryJapan' => l10n.countryJapan, _ => key, }; String _languageLabel(AppLocalizations l10n, String key) => switch (key) { 'languageNameSpanish' => l10n.languageNameSpanish, 'languageNameEnglish' => l10n.languageNameEnglish, 'languageNameFrench' => l10n.languageNameFrench, 'languageNameGerman' => l10n.languageNameGerman, 'languageNamePortuguese' => l10n.languageNamePortuguese, 'languageNameItalian' => l10n.languageNameItalian, 'languageNameJapanese' => l10n.languageNameJapanese, 'languageNameArabic' => l10n.languageNameArabic, 'languageNameRussian' => l10n.languageNameRussian, _ => key, }; }