import 'dart:async'; import 'package:pluriwave/modelos/emisora.dart'; import 'package:pluriwave/modelos/preset_ecualizador.dart'; import 'package:pluriwave/servicios/servicio_audio.dart'; import 'package:pluriwave/servicios/servicio_ecualizador.dart'; import 'package:pluriwave/servicios/servicio_favoritos.dart'; import 'package:pluriwave/servicios/servicio_radio.dart'; class FakeServicioAudio extends ServicioAudio { FakeServicioAudio({this.ecualizadorActivo = true}) { _estadoController.add(EstadoReproduccion.detenido); } final bool ecualizadorActivo; final _estadoController = StreamController.broadcast(); final List presetsAplicados = []; final List emisorasReproducidas = []; Emisora? _emisoraActual; EstadoReproduccion _estadoActual = EstadoReproduccion.detenido; @override Emisora? get emisoraActual => _emisoraActual; @override bool get ecualizadorDisponible => ecualizadorActivo; @override Stream get estadoStream => _estadoController.stream; @override bool get estaSonando => _estadoActual == EstadoReproduccion.reproduciendo; @override Future reproducir(Emisora emisora) async { _emisoraActual = emisora; emisorasReproducidas.add(emisora); emitirEstado(EstadoReproduccion.reproduciendo); } @override Future detener() async { _emisoraActual = null; emitirEstado(EstadoReproduccion.detenido); } void emitirEstado(EstadoReproduccion estado) { _estadoActual = estado; _estadoController.add(estado); } @override Future aplicarPreset(PresetEcualizador preset) async { presetsAplicados.add(preset); } @override Future setBanda(int index, double db) async {} @override Future dispose() async { await _estadoController.close(); } } class FakeServicioFavoritos extends ServicioFavoritos { final List _favoritos = []; int toggleCalls = 0; @override Future> obtenerTodos() async => _favoritos.map((e) => e.copyWith()).toList(); @override Future agregar(Emisora emisora) async { _favoritos.removeWhere((e) => e.uuid == emisora.uuid); _favoritos.add(emisora.copyWith(orden: _favoritos.length)); } @override Future eliminar(String uuid) async { _favoritos.removeWhere((e) => e.uuid == uuid); for (var i = 0; i < _favoritos.length; i++) { _favoritos[i] = _favoritos[i].copyWith(orden: i); } } @override Future esFavorito(String uuid) async => _favoritos.any((e) => e.uuid == uuid); @override Future toggleFavorito(Emisora emisora) async { toggleCalls += 1; if (_favoritos.any((e) => e.uuid == emisora.uuid)) { await eliminar(emisora.uuid); return false; } await agregar(emisora); return true; } @override Future reordenar(String uuid, int nuevoOrden) async { final oldIndex = _favoritos.indexWhere((e) => e.uuid == uuid); if (oldIndex == -1 || _favoritos.isEmpty) return; final targetIndex = nuevoOrden.clamp(0, _favoritos.length - 1); final moved = _favoritos.removeAt(oldIndex); _favoritos.insert(targetIndex, moved); for (var i = 0; i < _favoritos.length; i++) { _favoritos[i] = _favoritos[i].copyWith(orden: i); } } } class FakeServicioRadio extends ServicioRadio { FakeServicioRadio({ List? populares, List? tendencias, List? busqueda, List>? popularesPorLlamada, List>? tendenciasPorLlamada, List? erroresPopularesPorLlamada, List? erroresTendenciasPorLlamada, }) : _populares = populares ?? [], _tendencias = tendencias ?? [], _busqueda = busqueda ?? [], _popularesPorLlamada = popularesPorLlamada ?? const [], _tendenciasPorLlamada = tendenciasPorLlamada ?? const [], _erroresPopularesPorLlamada = erroresPopularesPorLlamada ?? const [], _erroresTendenciasPorLlamada = erroresTendenciasPorLlamada ?? const []; final List _populares; final List _tendencias; final List _busqueda; final List> _popularesPorLlamada; final List> _tendenciasPorLlamada; final List _erroresPopularesPorLlamada; final List _erroresTendenciasPorLlamada; int obtenerPopularesCalls = 0; int obtenerTendenciasCalls = 0; int registrarClickCalls = 0; String? ultimoUuidClick; Exception _normalizarError(Object error) => error is Exception ? error : Exception(error.toString()); @override Future> obtenerPopulares({int limit = 30, int offset = 0}) async { final llamada = obtenerPopularesCalls++; if (llamada < _erroresPopularesPorLlamada.length) { throw _normalizarError(_erroresPopularesPorLlamada[llamada]); } final data = llamada < _popularesPorLlamada.length ? _popularesPorLlamada[llamada] : _populares; return data.take(limit).toList(); } @override Future> obtenerTendencias({int limit = 20}) async { final llamada = obtenerTendenciasCalls++; if (llamada < _erroresTendenciasPorLlamada.length) { throw _normalizarError(_erroresTendenciasPorLlamada[llamada]); } final data = llamada < _tendenciasPorLlamada.length ? _tendenciasPorLlamada[llamada] : _tendencias; return data.take(limit).toList(); } @override Future> buscar({ String? nombre, String? pais, String? idioma, String? tag, int limit = 30, int offset = 0, }) async { return _busqueda.skip(offset).take(limit).toList(); } @override Future registrarClick(String uuid) async { registrarClickCalls += 1; ultimoUuidClick = uuid; } } class FakeServicioEcualizador extends ServicioEcualizador { FakeServicioEcualizador({ PresetEcualizador? principal, Map? porEmisora, }) : _config = ConfiguracionEcualizador( principal: principal ?? PresetEcualizador.flat, porEmisora: porEmisora ?? {}, ); ConfiguracionEcualizador _config; @override Future cargar() async => _config; @override Future guardarPrincipal(PresetEcualizador preset) async { _config = ConfiguracionEcualizador( principal: preset, porEmisora: _config.porEmisora, ); } @override Future guardarPorEmisora(String uuid, PresetEcualizador preset) async { final mapa = Map.from(_config.porEmisora); mapa[uuid] = preset; _config = ConfiguracionEcualizador( principal: _config.principal, porEmisora: mapa, ); } @override Future eliminarPorEmisora(String uuid) async { final mapa = Map.from(_config.porEmisora); mapa.remove(uuid); _config = ConfiguracionEcualizador( principal: _config.principal, porEmisora: mapa, ); } } Emisora emisoraDemo({ required String uuid, required String nombre, String url = 'https://stream.demo/radio', }) { return Emisora(uuid: uuid, nombre: nombre, url: url); }