feat(alarm): add musical alarm foundation
Build & Deploy Pluriwave / Análisis de código (push) Successful in 14s
Build & Deploy Pluriwave / Build APK + AAB release (push) Successful in 2m45s

This commit is contained in:
2026-05-21 23:46:52 +02:00
parent 8c2cba093c
commit fb808ebb60
30 changed files with 1437 additions and 43 deletions
@@ -0,0 +1,37 @@
# Design: alarm-clock-module
## Architecture
- Flutter owns alarm domain data, UX, recurrence calculation, and persistence.
- Android owns exact wakeup delivery through AlarmManager/setAlarmClock and notification actions.
- Communication uses a MethodChannel, tentatively `pluriwave/alarm_scheduler`.
- Existing `ServicioTimer` remains unchanged; a new `ServicioAlarmas` manages alarms.
## Data model
- `AlarmaMusical`: id, name, enabled, hour, minute, scheduleType, weekdays, stationUuid/url snapshot, fallbackStation snapshot, bundledSoundId, volume, snoozeMinutes, soundOnVacation, nextOccurrenceAt.
- `RangoVacaciones`: id, name, startDate, endDate, enabled.
- `ExcepcionAlarma`: alarmId, occurrenceAt, type (`skipNext`, `snooze`, `vacation`).
- `EjecucionAlarma`: scheduledAt, firedAt, status, fallbackUsed, failureReason.
## Persistence
Use JSON files or SharedPreferences for MVP to avoid risky DB migrations. If alarm history grows, migrate to sqflite later.
## Android native components
- `PluriWaveAlarmReceiver`: receives exact alarm and pre-alarm actions.
- `PluriWaveAlarmScheduler`: schedules/cancels next alarm and pre-notification.
- `PluriWaveAlarmActivity` or full-screen notification target for the ringing UI.
- Notification channels:
- `alarm_pre_notice`: silent, low/default importance, no sound.
- `alarm_ringing`: high importance for active alarms.
## Audio strategy
MVP: when the alarm fires, bring the Flutter app/alarm screen forward and use existing audio_service to play station/fallback. If Flutter/audio startup fails, Android should be able to play a bundled raw sound as last fallback.
## Reliability diagnostics
Expose statuses for:
- exact alarm permission (`canScheduleExactAlarms`).
- notification permission.
- battery optimization warning.
- DND policy access for optional override.
## Key decision
Use `setAlarmClock` for actual alarm occurrences because Android treats these as critical and visible user alarms. Use a separate exact/inexact notification alarm for the 30-minute silent pre-notice depending on permission and platform behavior.
@@ -0,0 +1,32 @@
# Proposal: alarm-clock-module
## Intent
Build an Android-first musical alarm system for PluriWave that can wake the user with radio/music while keeping reliable fallbacks and clear Android permission diagnostics.
## Scope
- Add a new alarm domain separate from the existing sleep timer.
- Support one-shot and recurrent alarms by weekday.
- Support snooze options: 3, 5, and 10 minutes.
- Support a silent pre-alarm notification 30 minutes before the next occurrence, with an action to skip only that next execution.
- Support vacation ranges and per-alarm `soundOnVacation` behavior. Default: true.
- Support audio fallback chain: selected station, optional fallback station, bundled internal alarm sounds.
- Add Android native scheduling using AlarmManager/setAlarmClock via MethodChannel.
- Add Flutter UI for listing, editing, enabling/disabling, vacation ranges, and reliability diagnostics.
## Out of Scope for MVP
- Cloud sync.
- iOS reliable alarm parity.
- Complex alarm-dismiss challenges.
- Multiple fallback station chains beyond one optional fallback station.
- Full background radio streaming implementation independent from existing audio_service if not needed for MVP.
## Rollback Plan
- Alarm functionality is isolated behind new services/models/screens and Android receivers.
- Existing radio playback, timer, favorites, EQ, and recording flows should remain untouched except for navigation entry points.
- If native scheduling causes issues, remove Android manifest receiver/service entries and hide the alarms entry point.
## Risks
- Android exact alarms require special permissions on Android 12+ and can be denied by default on Android 14+.
- OEM battery managers may still interfere; app must expose diagnostics and guidance.
- DND bypass requires Notification Policy Access and cannot be silently forced.
- Playing a radio stream at alarm time depends on network; bundled sounds must always be present.
@@ -0,0 +1,62 @@
# Spec: alarm-clock-module
## Requirement: Alarm scheduling
The app MUST support creating enabled/disabled alarms with a local time, one-shot or recurring schedule, and next occurrence calculation.
### Scenario: one-shot alarm fires once
Given an enabled one-shot alarm for a future date/time
When its scheduled occurrence fires
Then the app MUST start the alarm flow
And the alarm MUST be disabled or marked completed after that occurrence unless snoozed.
### Scenario: weekday recurring alarm
Given an enabled recurring alarm with selected weekdays
When the next matching weekday/time arrives
Then the app MUST start the alarm flow
And MUST schedule the following matching occurrence.
## Requirement: Snooze
The app MUST offer snooze durations of 3, 5, and 10 minutes when an alarm is ringing.
### Scenario: snooze selected
Given an alarm is ringing
When the user selects snooze 5 minutes
Then the app MUST stop current alarm playback
And MUST schedule a one-off snooze occurrence 5 minutes later.
## Requirement: Pre-alarm notification
The app MUST schedule a silent notification 30 minutes before each next alarm occurrence when notification permission is available.
### Scenario: skip next occurrence from notification
Given a pre-alarm notification is visible
When the user taps skip next occurrence
Then the app MUST record a skip for that alarm occurrence
And MUST not fire that specific occurrence
And MUST preserve future recurring occurrences.
## Requirement: Vacation ranges
The app MUST support global vacation ranges with start/end dates and per-alarm `soundOnVacation` flag defaulting to true.
### Scenario: alarm disabled for vacation date
Given today is inside an enabled vacation range
And an alarm has `soundOnVacation=false`
When calculating next occurrence
Then the app MUST skip occurrences inside that vacation range.
## Requirement: Audio fallback
The app MUST never depend solely on an internet radio stream to ring.
### Scenario: selected station fails
Given an alarm starts with a selected radio station
When the stream fails or does not become ready before timeout
Then the app MUST try a fallback station if configured
And otherwise MUST play a bundled internal alarm sound.
## Requirement: Android reliability
The app MUST use native Android scheduling for alarm occurrences and expose permission/diagnostic status.
### Scenario: exact alarm permission missing
Given Android denies exact alarm scheduling
When the user views alarm diagnostics
Then the app MUST show that exact alarm permission is missing
And MUST provide guidance to enable it.
@@ -0,0 +1,6 @@
change: alarm-clock-module
status: planned
artifact_store: hybrid
created: 2026-05-21
updated: 2026-05-21
phase: tasks-ready
@@ -0,0 +1,31 @@
# Tasks: alarm-clock-module
## Phase 1: domain and tests
- [ ] Add alarm domain models: alarm, vacation range, skip/exception, execution status.
- [ ] Add recurrence calculator with tests for one-shot, weekdays, vacations, skip-next, snooze.
- [ ] Add alarm persistence service with tests.
## Phase 2: Android scheduling bridge
- [ ] Add MethodChannel scheduler interface in Flutter.
- [ ] Add Kotlin scheduler using AlarmManager/setAlarmClock.
- [ ] Add BroadcastReceiver for alarm firing and pre-alarm actions.
- [ ] Add manifest permissions and receiver declarations.
- [ ] Add diagnostics method for exact alarm permission.
## Phase 3: app state and UI
- [ ] Add `EstadoAlarmas` or integrate alarm slice without bloating `EstadoRadio`.
- [ ] Add alarms tab/entry point.
- [ ] Add alarm list, editor, vacation ranges UI, and diagnostics panel.
- [ ] Add ringing screen with stop/snooze 3/5/10.
## Phase 4: audio fallback
- [ ] Add bundled internal alarm sounds under assets.
- [ ] Implement fallback sequence with timeouts.
- [ ] Add optional fallback station selection.
- [ ] Add volume/fade-in behavior.
## Phase 5: verification
- [ ] Run `dart format`.
- [ ] Run `flutter analyze --no-fatal-infos`.
- [ ] Run targeted tests if local runner does not hang.
- [ ] Document Android limitations and permission flow.