Some checks failed
Flutter CI/CD — PluriWave / Test + Build (pull_request) Has been cancelled
- Modelo Emisora: campos completos Radio Browser API (fromApi + fromMap) - ServicioRadio: cliente Radio Browser API (populares, tendencias, buscar por nombre/país/idioma/tag) - ServicioAudio: just_audio + audio_service wrapper (play/pause/stop/toggle, fade, background handler) - ServicioTimer: countdown con fade out gradual (15/30/60/90 min) - ServicioFavoritos: actualizado a v2 con campos codec/bitrate/votes/clickcount - EstadoRadio: ChangeNotifier global con Provider - PantallaInicio: grid emisoras populares, chips género, shimmer loading, pull-to-refresh - PantallaBuscar: SearchBar + filtros país/idioma, lista resultados - PantallaFavoritos: ReorderableListView + swipe-to-delete (Dismissible) - TarjetaEmisora: card + modo compacto ListTile, cached_network_image, shimmer fallback - MiniReproductor: barra inferior persistente con stream de estado - app.dart: MaterialApp + Provider + NavigationBar + timer dialog - main.dart: punto de entrada limpio - AndroidManifest.xml: permisos INTERNET + FOREGROUND_SERVICE + audio_service receivers
137 lines
3.4 KiB
Dart
137 lines
3.4 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
import '../modelos/emisora.dart';
|
|
import '../servicios/servicio_audio.dart';
|
|
import '../servicios/servicio_favoritos.dart';
|
|
import '../servicios/servicio_radio.dart';
|
|
import '../servicios/servicio_timer.dart';
|
|
|
|
/// Estado global de la app con ChangeNotifier (Provider).
|
|
///
|
|
/// Centraliza: reproductoor, favoritos, búsqueda, timer.
|
|
class EstadoRadio extends ChangeNotifier {
|
|
final ServicioAudio audio = ServicioAudio();
|
|
final ServicioFavoritos favoritos = ServicioFavoritos();
|
|
final ServicioRadio radio = ServicioRadio();
|
|
late final ServicioTimer timer;
|
|
|
|
List<Emisora> _populares = [];
|
|
List<Emisora> _tendencias = [];
|
|
List<Emisora> _resultadosBusqueda = [];
|
|
List<Emisora> _listafavoritos = [];
|
|
|
|
bool _cargandoPopulares = false;
|
|
bool _cargandoBusqueda = false;
|
|
String? _error;
|
|
|
|
EstadoRadio() {
|
|
timer = ServicioTimer(audio);
|
|
_init();
|
|
}
|
|
|
|
List<Emisora> get populares => _populares;
|
|
List<Emisora> get tendencias => _tendencias;
|
|
List<Emisora> get resultadosBusqueda => _resultadosBusqueda;
|
|
List<Emisora> get listaFavoritos => _listafavoritos;
|
|
bool get cargandoPopulares => _cargandoPopulares;
|
|
bool get cargandoBusqueda => _cargandoBusqueda;
|
|
String? get error => _error;
|
|
Emisora? get emisoraActual => audio.emisoraActual;
|
|
Stream<EstadoReproduccion> get estadoStream => audio.estadoStream;
|
|
|
|
Future<void> _init() async {
|
|
await Future.wait([
|
|
cargarPopulares(),
|
|
cargarFavoritos(),
|
|
]);
|
|
}
|
|
|
|
Future<void> cargarPopulares() async {
|
|
_cargandoPopulares = true;
|
|
_error = null;
|
|
notifyListeners();
|
|
try {
|
|
final results = await Future.wait([
|
|
radio.obtenerPopulares(limit: 30),
|
|
radio.obtenerTendencias(limit: 20),
|
|
]);
|
|
_populares = results[0];
|
|
_tendencias = results[1];
|
|
} catch (e) {
|
|
_error = 'Error al cargar emisoras: $e';
|
|
} finally {
|
|
_cargandoPopulares = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
Future<void> cargarFavoritos() async {
|
|
_listafavoritos = await favoritos.obtenerTodos();
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> buscar({
|
|
String? nombre,
|
|
String? pais,
|
|
String? idioma,
|
|
String? tag,
|
|
}) async {
|
|
_cargandoBusqueda = true;
|
|
_resultadosBusqueda = [];
|
|
notifyListeners();
|
|
try {
|
|
_resultadosBusqueda = await radio.buscar(
|
|
nombre: nombre,
|
|
pais: pais,
|
|
idioma: idioma,
|
|
tag: tag,
|
|
);
|
|
} catch (e) {
|
|
_error = 'Error en búsqueda: $e';
|
|
} finally {
|
|
_cargandoBusqueda = false;
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
Future<void> reproducir(Emisora emisora) async {
|
|
try {
|
|
await audio.reproducir(emisora);
|
|
radio.registrarClick(emisora.uuid); // fire & forget
|
|
notifyListeners();
|
|
} catch (e) {
|
|
_error = 'No se puede reproducir esta emisora';
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
Future<void> togglePlay() async {
|
|
await audio.togglePlay();
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<bool> toggleFavorito(Emisora emisora) async {
|
|
final esFav = await favoritos.toggleFavorito(emisora);
|
|
await cargarFavoritos();
|
|
return esFav;
|
|
}
|
|
|
|
Future<bool> esFavorito(String uuid) => favoritos.esFavorito(uuid);
|
|
|
|
void iniciarTimer(int minutos) {
|
|
timer.iniciar(minutos);
|
|
notifyListeners();
|
|
}
|
|
|
|
void cancelarTimer() {
|
|
timer.cancelar();
|
|
notifyListeners();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
audio.dispose();
|
|
timer.dispose();
|
|
super.dispose();
|
|
}
|
|
}
|