feat(radio): add nearby discovery and paged search
This commit is contained in:
+113
-13
@@ -3,6 +3,8 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:geocoding/geocoding.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import '../modelos/emisora.dart';
|
||||
@@ -51,6 +53,7 @@ class EstadoRadio extends ChangeNotifier {
|
||||
List<Emisora> _populares = [];
|
||||
List<Emisora> _tendencias = [];
|
||||
List<Emisora> _resultadosBusqueda = [];
|
||||
List<Emisora> _emisorasCercanas = [];
|
||||
List<Emisora> _listaFavoritos = [];
|
||||
List<Emisora> _emisorasCustom = [];
|
||||
|
||||
@@ -61,16 +64,31 @@ class EstadoRadio extends ChangeNotifier {
|
||||
|
||||
bool _cargandoPopulares = false;
|
||||
bool _cargandoBusqueda = false;
|
||||
EstadoReproduccion _estadoReproduccion = EstadoReproduccion.detenido;
|
||||
bool _cargandoMasBusqueda = false;
|
||||
bool _hayMasBusqueda = true;
|
||||
bool _cargandoCercanas = false;
|
||||
String? _paisCercanoDetectado;
|
||||
String? _errorCercanas;
|
||||
int _offsetBusqueda = 0;
|
||||
String? _ultimoNombreBusqueda;
|
||||
String? _ultimoPaisBusqueda;
|
||||
String? _ultimoIdiomaBusqueda;
|
||||
String? _ultimoTagBusqueda;
|
||||
String? _errorCarga;
|
||||
|
||||
List<Emisora> get populares => _populares;
|
||||
List<Emisora> get tendencias => _tendencias;
|
||||
List<Emisora> get resultadosBusqueda => _resultadosBusqueda;
|
||||
List<Emisora> get emisorasCercanas => _emisorasCercanas;
|
||||
List<Emisora> get listaFavoritos => _listaFavoritos;
|
||||
List<Emisora> get emisorasCustom => _emisorasCustom;
|
||||
bool get cargandoPopulares => _cargandoPopulares;
|
||||
bool get cargandoBusqueda => _cargandoBusqueda;
|
||||
bool get cargandoMasBusqueda => _cargandoMasBusqueda;
|
||||
bool get hayMasBusqueda => _hayMasBusqueda;
|
||||
bool get cargandoCercanas => _cargandoCercanas;
|
||||
String? get paisCercanoDetectado => _paisCercanoDetectado;
|
||||
String? get errorCercanas => _errorCercanas;
|
||||
String? get error => _errorCarga;
|
||||
Emisora? get emisoraActual => audio.emisoraActual;
|
||||
Stream<EstadoReproduccion> get estadoStream => audio.estadoStream;
|
||||
@@ -119,7 +137,6 @@ class EstadoRadio extends ChangeNotifier {
|
||||
/// Escucha el stream de estado del audio y gestiona errores de reproducción.
|
||||
void _escucharErroresReproduccion() {
|
||||
_suscripcionEstadoAudio = audio.estadoStream.listen((estado) {
|
||||
_estadoReproduccion = estado;
|
||||
if (estado == EstadoReproduccion.error && timer.activo) {
|
||||
unawaited(timer.cancelar());
|
||||
}
|
||||
@@ -167,42 +184,125 @@ class EstadoRadio extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
static const int _tamanoPaginaBusqueda = 30;
|
||||
static const int _maxResultadosBusquedaEnMemoria = 180;
|
||||
|
||||
Future<void> buscar({
|
||||
String? nombre,
|
||||
String? pais,
|
||||
String? idioma,
|
||||
String? tag,
|
||||
}) async {
|
||||
_ultimoNombreBusqueda = nombre;
|
||||
_ultimoPaisBusqueda = pais;
|
||||
_ultimoIdiomaBusqueda = idioma;
|
||||
_ultimoTagBusqueda = tag;
|
||||
_offsetBusqueda = 0;
|
||||
_hayMasBusqueda = true;
|
||||
_cargandoBusqueda = true;
|
||||
_resultadosBusqueda = [];
|
||||
notifyListeners();
|
||||
try {
|
||||
_resultadosBusqueda = await radio.buscar(
|
||||
final pagina = await radio.buscar(
|
||||
nombre: nombre,
|
||||
pais: pais,
|
||||
idioma: idioma,
|
||||
tag: tag,
|
||||
limit: _tamanoPaginaBusqueda,
|
||||
offset: _offsetBusqueda,
|
||||
);
|
||||
_resultadosBusqueda = pagina;
|
||||
_offsetBusqueda = pagina.length;
|
||||
_hayMasBusqueda = pagina.length == _tamanoPaginaBusqueda;
|
||||
} catch (_) {
|
||||
_errorController.add('Error en la búsqueda. Comprueba tu conexión.');
|
||||
_errorController.add('Error en la busqueda. Comprueba tu conexion.');
|
||||
} finally {
|
||||
_cargandoBusqueda = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> reproducir(Emisora emisora) async {
|
||||
final actual = audio.emisoraActual;
|
||||
final mismaEmisoraActiva = actual?.uuid == emisora.uuid;
|
||||
final yaEstaConectandoOSonando =
|
||||
_estadoReproduccion == EstadoReproduccion.cargando ||
|
||||
_estadoReproduccion == EstadoReproduccion.reproduciendo ||
|
||||
audio.estaSonando;
|
||||
if (mismaEmisoraActiva && yaEstaConectandoOSonando) {
|
||||
Future<void> cargarMasBusqueda() async {
|
||||
if (_cargandoBusqueda || _cargandoMasBusqueda || !_hayMasBusqueda) return;
|
||||
_cargandoMasBusqueda = true;
|
||||
notifyListeners();
|
||||
try {
|
||||
final pagina = await radio.buscar(
|
||||
nombre: _ultimoNombreBusqueda,
|
||||
pais: _ultimoPaisBusqueda,
|
||||
idioma: _ultimoIdiomaBusqueda,
|
||||
tag: _ultimoTagBusqueda,
|
||||
limit: _tamanoPaginaBusqueda,
|
||||
offset: _offsetBusqueda,
|
||||
);
|
||||
final porUuid = <String, Emisora>{
|
||||
for (final emisora in _resultadosBusqueda) emisora.uuid: emisora,
|
||||
};
|
||||
for (final emisora in pagina) {
|
||||
porUuid[emisora.uuid] = emisora;
|
||||
}
|
||||
var nuevaLista = porUuid.values.toList();
|
||||
if (nuevaLista.length > _maxResultadosBusquedaEnMemoria) {
|
||||
nuevaLista = nuevaLista.sublist(
|
||||
nuevaLista.length - _maxResultadosBusquedaEnMemoria,
|
||||
);
|
||||
}
|
||||
_resultadosBusqueda = nuevaLista;
|
||||
_offsetBusqueda += pagina.length;
|
||||
_hayMasBusqueda = pagina.length == _tamanoPaginaBusqueda;
|
||||
} catch (_) {
|
||||
_errorController.add('No se pudieron cargar mas emisoras.');
|
||||
} finally {
|
||||
_cargandoMasBusqueda = false;
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> cargarEmisorasCercanas() async {
|
||||
_cargandoCercanas = true;
|
||||
_errorCercanas = null;
|
||||
notifyListeners();
|
||||
try {
|
||||
var pais = PlatformDispatcher.instance.locale.countryCode;
|
||||
final servicioActivo = await Geolocator.isLocationServiceEnabled();
|
||||
if (servicioActivo) {
|
||||
var permiso = await Geolocator.checkPermission();
|
||||
if (permiso == LocationPermission.denied) {
|
||||
permiso = await Geolocator.requestPermission();
|
||||
}
|
||||
if (permiso == LocationPermission.always ||
|
||||
permiso == LocationPermission.whileInUse) {
|
||||
final posicion = await Geolocator.getCurrentPosition(
|
||||
locationSettings: const LocationSettings(
|
||||
accuracy: LocationAccuracy.low,
|
||||
timeLimit: Duration(seconds: 8),
|
||||
),
|
||||
);
|
||||
final marcas = await placemarkFromCoordinates(
|
||||
posicion.latitude,
|
||||
posicion.longitude,
|
||||
);
|
||||
if (marcas.isNotEmpty) {
|
||||
pais = marcas.first.isoCountryCode ?? pais;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pais == null || pais.isEmpty) {
|
||||
throw Exception('No se pudo detectar tu region');
|
||||
}
|
||||
_paisCercanoDetectado = pais;
|
||||
_emisorasCercanas = await radio.buscar(pais: pais, limit: 30);
|
||||
} catch (_) {
|
||||
_errorCercanas = 'No pudimos detectar emisoras cercanas. Usa filtros por pais.';
|
||||
_emisorasCercanas = [];
|
||||
} finally {
|
||||
_cargandoCercanas = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> reproducir(Emisora emisora) async {
|
||||
try {
|
||||
notifyListeners();
|
||||
await audio.reproducir(emisora);
|
||||
|
||||
Reference in New Issue
Block a user