Phase 1: pick a device folder via SAF (persisted grant, no new
permission), browse its nested subfolders/tracks as a 5th Android
Auto root folder (hidden until configured), and play tracks through
the existing pipeline (EQ, art rotation, cold-start-safe source).
No metadata/sort/filter/shuffle yet -- filename is the title, generic
rotating art is the placeholder; deferred to a follow-up phase.
Adds a new pluriwave/file_actions native method (listAudioChildren)
and an onActivityResult override in MainActivity for the SAF folder
picker -- both static-review-only, no Android build available here.
Expose PluriWave to Android Auto (projected) as a media app:
- Declare car media support (automotive_app_desc.xml + manifest meta-data)
so Android Auto discovers the existing MediaBrowserService.
- New navegacion_auto.dart: ConstructorArbolAuto builds the browse tree
(Favoritos / Todas las emisoras / Mis emisoras, 50-item cap, stable
emisora:<id> media ids), reproducirPorMediaId routes a car tap to the
existing playMediaItem pipeline, FuenteEmisorasAutoLocal serves the tree
cold-start-safe (local favorites/custom stations before Flutter UI runs).
- PluriWaveAudioHandler overrides getChildren/getMediaItem/playFromMediaId
as thin delegations; playback pipeline untouched.
- EstadoRadio pushes live station snapshots to the browse source and
reconciles the selected station when playback starts from the car.
- Every playable item ships title + artUri; stations without logo fall
back to a bundled default art (android.resource://).
Tests: 52/52 green (10 new navegacion_auto, 2 new estado_radio, plus
audio safety-net suites). Handler overrides and native XML are
static-review-only (no Android build env). Size exception approved for a
single reviewable commit.
Replace generic system icons (info bubble, stock alarm clock) with a
custom equalizer-bars vector drawable across all 4 notification
builders: pre-notice, snooze countdown, ringing alarm, and the audio
player. Apply the app's cyan brand color to the 3 alarm notifications
that previously had none. Audio notification now explicitly declares
its icon instead of falling back to the full-color launcher icon,
which Android was auto-silhouetting into an illegible status-bar
blob.
- Replace all hardcoded Color literals outside lib/tema with theme tokens (new static brand palette in PluriWaveTokens); media notification uses the brand color instead of the Material default purple
- Favorite button on station cards grows to a 48dp target and becomes an independent semantics node for screen readers (Semantics container fix)
- All flutter_animate call sites route through the PluriAnimate reduced-motion gate (zero direct .animate() left)
- Locale-aware short dates via intl DateFormat (new lib/l10n/formato_fechas.dart) replacing the hardcoded DD/MM/YYYY; proper plural messages for the favorites counter; example stream URL as a localized key - all 13 locales
- Rounded shimmer placeholders matching card radii; shimmer loading state in search instead of a bare spinner; rounded icon variants unified in settings; bottom-sheet conventions on the custom station form
- Fix latent debug crash: vacation editor read AppLocalizations in initState
- 11 new tests (121 total green), flutter analyze clean
- Integrate audio_session (new servicio_audio_session.dart): incoming calls pause the radio and resume on end, headphone unplug pauses without auto-resume, permanent focus loss never auto-resumes, duck lowers volume
- Add play-intent flag to ServicioAudio so interruption handling and future reconnect logic can distinguish user pause from system-driven stops
- Eliminate read-modify-write race in ServicioAlarmas with an in-memory cache and single-writer queue across all mutations; recalcularTodas persists only when state actually changed
- Convert ServicioAlarmasAndroid static StreamController/handler to injectable instance fields, restoring test isolation
- Inject a single cached SharedPreferences from main.dart across services and state (removes 23 inline getInstance() calls)
- Move configurarLocalizaciones out of MiniReproductor.build() (was running on every rebuild during playback)
- Bound the alarm fire-dedup set (cap 200 entries, 24h pruning)
- 12 new tests (89 total green), flutter analyze clean
- ServicioAudio: delega a PluriWaveAudioHandler (audio_service) para
mantener audio vivo en background. AudioService.init() en main.dart.
onTaskRemoved() libera player. mediaItem con nombre/artista/artwork.
- ServicioRadio: lastcheckok=1 en todas las peticiones — solo emisoras
verificadas como funcionales por Radio Browser API.
- EstadoRadio: errorStream (broadcast) para errores de reproducción y
búsqueda. App.dart suscribe y muestra SnackBar flotante 3s.
Los errores de carga de lista siguen como banner inline.
- Icono: generado con SDXL (morado, ondas radio blancas, Material You).
5 densidades Android (48-192px), ic_launcher_round añadido.
- Flutter create con org es.freetimelab
- pubspec.yaml con dependencias core (just_audio, audio_service, provider, sqflite)
- README con features y stack
- Assets preparados