FreeTLab f2f706b342 fix(auto): restore the equalizer toggle and list the user's own presets
Two Android Auto regressions reported from the car.

1. The on/off equalizer action disappeared from the playback screen.

That was self-inflicted: commit cacd3ec removed it on the theory that a
custom action in `controls` aborts `AudioService.setState` and kills the
media notification. Reading the plugin source refutes it. setState
(AudioService.java:513-520) SPLITS the list -- a control carrying a
customAction goes to `customActions` (PlaybackStateCompat, i.e. the car),
everything else becomes a NotificationCompat.Action in `nativeActions`
(the phone notification). The two never mix. And the throw the theory
depended on cannot happen here: ic_auto_eq_on/ic_auto_eq_off both exist
under res/drawable, and the labels are non-empty in all 13 locales.

The notification outage was already fixed by abc6b47 (transient idle on
a source change, which setState turns into a full stop() at :557).

The action is back, with both state-aware icons. The real invariant --
a custom action's icon must resolve and its label must be non-empty --
is now a test that reads res/drawable and fails on a missing file,
instead of a comment claiming custom actions are forbidden outright.

2. The Ecualizador folder never listed the user's saved presets.

itemsEcualizadorAuto iterated PresetEcualizador.presets, so only the six
factory presets appeared -- the user's own were unreachable from the
car, the surface where a preset picker matters most. They now arrive
through a registered read function (same seam as stations and local
music, re-read per browse so a preset saved on the phone shows up
without an app restart).

presetsEcualizadorAuto is the single source of truth for the ordered
universe, used to BUILD the items and to RESOLVE a tap, so the folder
cannot show an item that resolution then refuses -- which is what the
factory-only default in seleccionarPresetEqPorMediaId would have caused.
A custom preset whose name collides with a factory one is dropped: the
media id is the raw name, so it could only ever resolve to the factory
entry, and an item that applies a preset other than the one it names is
worse than an absent one.

Tests: 1108 -> 1120.
2026-08-03 21:32:09 +02:00

PluriWave

Radio mundial con ecualizador personalizable, reconocimiento de canciones y UI premium.

Features

  • +53.000 emisoras de 238 países (Radio Browser API)
  • Ecualizador por emisora — guarda tu preset favorito para cada radio
  • Reconocimiento de canciones — "¿Qué suena?" sin salir de la app
  • Timer de auto-apagado — perfecto para dormir
  • Reproducción en segundo plano — sigue sonando con la pantalla apagada
  • Favoritos — acceso rápido a emisoras preferidas
  • Compartir — envía emisoras a tus amigos
  • UI premium — Material You, visualizador de audio, animaciones fluidas

Monetización

  • 14 días PRO gratis al instalar
  • Free: radio + favoritos + timer + background (con ads)
  • PRO €2.99/año: sin ads + ecualizador + reconocimiento ilimitado

Stack

  • Frontend: Flutter (Android + iOS)
  • Radio API: Radio Browser (gratis, +53K emisoras)
  • Audio: just_audio + audio_service
  • Ecualizador: just_audio equalizer (Android nativo)
  • Reconocimiento: AudD API (1000 req/mes free)
  • Ads: Google AdMob
  • Compras: in_app_purchase

CI/CD

Workflow Gitea Actions en .gitea/workflows/ci.yml, runner macmini-flutter.

Jobs: flutter pub getflutter testbuild apk --releasebuild appbundle --release

Artifacts: APK y AAB guardados en Gitea con nombre pluriwave-apk-<sha> / pluriwave-aab-<sha>.

Notificaciones: Telegram al completar (éxito / fallo ).

Secrets necesarios en el repo:

Secret Uso
TELEGRAM_BOT_TOKEN Notificaciones CI
TELEGRAM_CHAT_ID Canal de destino

Signing: build de release usa clave debug (válido para CI interno). Para Play Store se requiere keystore como secret adicional.

Desarrollador

FreeTimeLab — freetimelab.es

Licencia

MIT

S
Description
PluriWave — Radio mundial con ecualizador, reconocimiento de canciones y UI premium
Readme
49 MiB
Languages
Dart 86%
HTML 7.1%
Kotlin 5.1%
JavaScript 1.6%
Swift 0.1%