Tres fallos reportados en uso real, con sus causas raiz verificadas en codigo.
1. Ecualizador: el estado no tenia dueño unico
El handler arrancaba con `_ecualizadorActivo = true` a fuego. El valor
persistido solo llegaba por EstadoEcualizador.cargarPersistido(), alcanzable
unicamente desde el arbol de widgets, que un arranque headless de Android Auto
nunca construye. Resultado: el coche reproducia con el EQ forzado a ON mientras
disco e interfaz decian OFF.
Ahora registrarHandler siembra el flag desde disco en todos los motores y
setEcualizadorActivo persiste por su cuenta, asi que un toggle desde el coche o
la notificacion sobrevive sin EstadoEcualizador. _resincronizarConHandler pasa
a ser adopcion pura de interfaz.
Ademas mapearGananciaNativa enviaba 0 dB al punto MEDIO del rango nativo. Con
un getBandLevelRange() asimetrico, un preset plano metia varios dB de boost
real: la causa del "suena muy alto con el boton apagado". Reescrito para
escalar cada lado contra su propio extremo, de modo que 0 dB es siempre 0.
El dispatch de customAction no tenia ningun test. Se extrae decidirToggleEq y
se cubre contra el handler real. El efecto nativo se re-asierta al reactivarse
el reproductor, porque AudioEffect.setEnabled de just_audio es un no-op
mientras la plataforma esta desacoplada.
2. Musica Local no aparecia en el arbol de Android Auto
hayCarpetaConfigurada() consultaba MethodChannel('pluriwave/file_actions'),
registrado solo en MainActivity.configureFlutterEngine. Sin Activity no hay
handler, invokeMethod lanza MissingPluginException y el catch la confundia con
"permiso revocado", omitiendo el nodo. No dependia del entitlement.
La logica SAF sale a packages/pluriwave_file_actions, un paquete plugin local.
El motor headless que crea audio_service ejecuta GeneratedPluginRegistrant en
su constructor, asi que el canal queda registrado en ambos motores. Repuntar el
manifest a una subclase de AudioService no era viable: AudioServicePlugin
enlaza por ComponentName explicito y la app perderia el audio.
EstadoCarpetaLocal de tres valores separa "sin carpeta" de "canal no
disponible"; la raiz decide por la URI persistida y el subarbol muestra un item
explicativo en vez de una carpeta vacia. La invalidacion del arbol cacheado se
dispara al reanudar con el coche ya suscrito; el guardia anterior miraba
View.maybeOf, que bajo runApp siempre existe, por lo que se gastaba en el
arranque headless y no volvia a dispararse.
3. El paywall bloqueaba las compras
restorePurchases() de in_app_purchase_android emite siempre, y con lista vacia
si no hay nada que restaurar. El `if (compras.isEmpty) return;` se la tragaba,
noEncontrada nunca se emitia y la rama que limpia _compraEnCurso estaba muerta
en produccion. Como comprar y restaurar comparten ese flag, un usuario sin
compras que pulsaba restaurar se quedaba sin poder comprar.
Suite completa: 1366 pasan, 2 omitidos. 17 tests nuevos, todos nacidos rojos y
verificados por mutacion. flutter analyze mantiene los 5 avisos preexistentes.
111 lines
3.1 KiB
YAML
111 lines
3.1 KiB
YAML
name: pluriwave
|
|
description: "Radio mundial con ecualizador, reconocimiento de canciones y UI premium"
|
|
publish_to: 'none'
|
|
version: 1.3.3+158
|
|
|
|
environment:
|
|
sdk: ^3.7.0
|
|
|
|
dependencies:
|
|
flutter:
|
|
sdk: flutter
|
|
flutter_localizations:
|
|
sdk: flutter
|
|
intl: ^0.20.2
|
|
|
|
# Audio
|
|
just_audio: ^0.9.42
|
|
audio_service: ^0.18.15
|
|
audio_session: ^0.1.21
|
|
# Ya transitiva vía audio_service; directa para poder emitir
|
|
# notifyChildrenChanged (subscribeToChildren con BehaviorSubject).
|
|
rxdart: ^0.28.0
|
|
|
|
# UI
|
|
cupertino_icons: ^1.0.8
|
|
google_fonts: ^6.2.1
|
|
flutter_animate: ^4.5.2
|
|
cached_network_image: ^3.4.1
|
|
shimmer: ^3.0.0
|
|
|
|
# State
|
|
provider: ^6.1.2
|
|
|
|
# Storage
|
|
sqflite: ^2.4.1
|
|
path_provider: ^2.1.5
|
|
shared_preferences: ^2.3.4
|
|
|
|
# Network
|
|
http: ^1.2.2
|
|
|
|
# Utils
|
|
path: ^1.9.1
|
|
share_plus: ^10.1.3
|
|
file_picker: ^8.1.7
|
|
uuid: ^4.5.1
|
|
url_launcher: ^6.3.1
|
|
geolocator: ^13.0.4
|
|
geocoding: ^3.0.0
|
|
package_info_plus: ^8.3.1
|
|
|
|
# Ads — TODO: swap Google test ad unit IDs (servicio_anuncios.dart) for
|
|
# real AdMob unit IDs once provisioned (iap-freemium-unlock, Open Question).
|
|
google_mobile_ads: ^5.3.0
|
|
|
|
# In-app purchase
|
|
in_app_purchase: ^3.2.0
|
|
|
|
# Canal nativo SAF (`pluriwave/file_actions`) empaquetado como plugin para
|
|
# que GeneratedPluginRegistrant lo instale TAMBIEN en el FlutterEngine
|
|
# headless que audio_service crea al arrancar desde Android Auto. Sin esto
|
|
# el canal solo existia en el engine de MainActivity y "Musica Local"
|
|
# desaparecia del arbol del coche. No expone API Dart: los llamantes siguen
|
|
# usando MethodChannel('pluriwave/file_actions').
|
|
pluriwave_file_actions:
|
|
path: packages/pluriwave_file_actions
|
|
|
|
# Song recognition (activar con AudD key)
|
|
# permission_handler: ^11.3.1
|
|
|
|
dev_dependencies:
|
|
flutter_test:
|
|
sdk: flutter
|
|
flutter_lints: ^5.0.0
|
|
sqflite_common_ffi: ^2.3.7+1
|
|
|
|
flutter:
|
|
generate: true
|
|
uses-material-design: true
|
|
|
|
assets:
|
|
- assets/images/
|
|
- assets/icons/
|
|
- assets/icons/alarmas/
|
|
- assets/audio/
|
|
- assets/mockups/
|
|
- assets/generated/
|
|
# Flutter NO recurse: declarar 'assets/content/' incluye solo los
|
|
# ficheros sueltos de esa carpeta, nunca los de sus subcarpetas. Todo
|
|
# el contenido vive en subcarpetas, asi que NADA de esto viajaba en el
|
|
# APK -- verificado abriendo el binario instalado: cero entradas de
|
|
# assets/content. El onboarding reventaba en cada arranque con
|
|
# 'Unable to load asset: assets/content/onboarding/en.md' aunque el
|
|
# fichero existe en disco. Mismo fallo de familia que los drawables
|
|
# resueltos por nombre: referencia sin validacion en compilacion.
|
|
- assets/content/
|
|
- assets/content/onboarding/
|
|
- assets/content/updates/ar/
|
|
- assets/content/updates/bn/
|
|
- assets/content/updates/de/
|
|
- assets/content/updates/en/
|
|
- assets/content/updates/es/
|
|
- assets/content/updates/fr/
|
|
- assets/content/updates/hi/
|
|
- assets/content/updates/id/
|
|
- assets/content/updates/it/
|
|
- assets/content/updates/ja/
|
|
- assets/content/updates/pt/
|
|
- assets/content/updates/ru/
|
|
- assets/content/updates/zh/
|