Commit Graph
5 Commits
Author SHA1 Message Date
FreeTLab 66a19525bd fix(alarm): defer the Dart fade-in until the native handoff confirms
Build & Deploy PluriWave / Análisis de código (push) Successful in 37s
Build & Deploy PluriWave / Build APK + AAB release (push) Successful in 1m50s
The native service and the Flutter player each ran their own 5%-to-
target fade-in, and both could drive audible volume at the handoff,
producing a jump or ramp reset. The Dart ramp now starts exactly once
from the handoff-confirmation path: the player still pre-starts at 5%,
and _confirmarAudioFlutterListo() starts the ramp in a finally block
so it runs whether the native confirmation succeeds or fails — the
alarm can never stay stuck at 5% if the native side is already gone.

Work unit 3/3 of alarm-volume-ramp-restore (fade-in dedup).
2026-07-11 09:57:06 +02:00
FreeTLab acd903d9a8 feat(alarm): make the ring immune to device media volume
Build & Deploy PluriWave / Análisis de código (push) Successful in 41s
Build & Deploy PluriWave / Build APK + AAB release (push) Successful in 2m39s
The alarm's steady-state audio runs on the Flutter media-stream
player after the native handoff, so device volume 0 silenced it
entirely. The ring now forces STREAM_MUSIC to an audible reference:
Dart requests the override before pre-starting alarm audio (fallback
WAV included), Kotlin captures the current volume once and restores
it idempotently on every exit path (dismiss, snooze, dispose), with
a native best-effort backstop in service teardown.

The backstop is handoff-aware via PluriWaveAlarmService.flutterOwnsRing:
confirmFlutterAudio marks the handoff before triggering the native
stop, so the backstop cannot restore the volume mid-ring right as the
Flutter player takes over (that would re-silence the alarm at volume
0). The flag resets at every ring start; Flutter process death after
handoff remains a documented best-effort gap.

The alarm's perceived loudness keeps ramping 5% to the configured
volume through the player as before; normal radio playback and call
ducking never touch the override.

Work unit 2/3 of alarm-volume-ramp-restore (ring volume override).
2026-07-11 09:15:37 +02:00
FreeTLab 6acbd7ca93 fix(alarm): handle snooze reschedule failures instead of silently dropping them
Build & Deploy PluriWave / Análisis de código (push) Successful in 47s
Build & Deploy PluriWave / Build APK + AAB release (push) Successful in 2m1s
posponerAlarma() and posponerProximaDesdePreaviso() called the native
scheduler with no error handling, unlike guardarAlarma(). When the
native call failed (e.g. revoked exact-alarm permission), the
exception escaped before notifyListeners() ran, leaving the alarm
list stuck on stale data with no real alarm scheduled and no snooze
countdown notification.

Both methods now mirror guardarAlarma()'s pattern: permission
pre-check, try/catch into _error, and an unconditional
notifyListeners() so the UI always reflects the outcome. Failures
surface via SnackBar in the ringing screen and in app.dart's
postpone-next handler.
2026-07-01 00:22:58 +02:00
FreeTLab 079e19f0ee feat(audio): audio session integration and runtime robustness
- 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
2026-06-11 16:25:09 +02:00
FreeTLab f3e9487215 feat(alarms): native reliability fixes and end-to-end snooze
- Use mediaPlayback|systemExempted FGS type with FOREGROUND_SERVICE_SYSTEM_EXEMPTED so alarms fire on Android 14+ (FOREGROUND_SERVICE_ALARM does not exist in the SDK)
- Deduplicate fire notifications: the foreground service FSI notification is the single owner; receiver path removed
- Notification channel v2 with alarm sound URI and USAGE_ALARM attributes, one-time guarded migration from legacy channels
- Pass fallback station through the MethodChannel (NativeAlarmSpec schemaVersion 3) with a three-stage audio chain: primary -> fallback station -> bundled WAV
- Native fade-in volume ramp honoring fadeInSegundos when the app is killed
- Request battery-optimization exemption once, tracked with a persisted asked-once flag
- Fix snooze end-to-end: native ACTION_SNOOZE now reports back to Flutter (snoozed event + cold-start sync), snooze anchor unified to occurrence+minutes on both sides, periodic recalc no longer erases an active snooze
- Add snooze buttons (3/5/10/custom) to the ringing screen with shared audio teardown
- Redesign ringing screen on PluriWaveScaffold with reduced-motion-aware entry animation (new PluriAnimate helper)
- Alarm editor: live next-trigger preview, searchable station pickers (primary and fallback), configurable snooze duration, volume floor down to 0
- New alarm strings localized across all 13 locales
- New unit/widget tests for the snooze flow, alarm bridge payloads, ringing screen and editor (77 tests green)
- SDD artifacts for the app-quality-and-native-alarms change (explore, proposal, spec, design, tasks, apply progress)
2026-06-11 15:33:30 +02:00