feat(stations): add quality filters and list ordering
This commit is contained in:
@@ -47,6 +47,7 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
|
||||
final _controller = TextEditingController();
|
||||
String? _paisSeleccionado;
|
||||
String? _idiomaSeleccionado;
|
||||
int? _calidadMinima;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@@ -60,6 +61,7 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
|
||||
nombre: q.isNotEmpty ? q : null,
|
||||
pais: _paisSeleccionado,
|
||||
idioma: _idiomaSeleccionado,
|
||||
minBitrate: _calidadMinima,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -108,7 +110,6 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
|
||||
),
|
||||
),
|
||||
),
|
||||
_seccionCercanas(estado),
|
||||
_seccionFiltro(
|
||||
'Pais',
|
||||
_paises.map((p) => (p.$1, p.$2)).toList(),
|
||||
@@ -127,80 +128,20 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
|
||||
_buscar();
|
||||
},
|
||||
),
|
||||
_seccionFiltroInt(
|
||||
'Calidad m?nima',
|
||||
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 _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,
|
||||
@@ -247,6 +188,51 @@ class _PantallaBuscarState extends State<PantallaBuscar> {
|
||||
);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (estado.cargandoBusqueda) {
|
||||
return const SizedBox(
|
||||
|
||||
Reference in New Issue
Block a user