Files
FreeTLab bccc5c48b8
Build & Deploy PluriWave / Análisis de código (push) Successful in 38s
Build & Deploy PluriWave / Build APK + AAB release (push) Successful in 2m30s
docs(openspec): add SDD artifact trail for recent alarm and EQ changes
Persist the exploration, proposal, spec, design, tasks, and
verify/archive reports produced during the multi-device EQ,
alarm-countdown, and notification-visual-polish SDD cycles.
2026-07-04 12:42:11 +02:00

6.6 KiB
Raw Permalink Blame History

Tasks: Alarm Live Countdown

Review Workload Forecast

Field Value
Estimated changed lines ~175200 (additions + deletions)
400-line budget risk Low
Chained PRs recommended No
Suggested split Single PR
Delivery strategy ask-on-risk
Chain strategy pending

Decision needed before apply: No Chained PRs recommended: No Chain strategy: pending 400-line budget risk: Low

Suggested Work Units

Unit Goal Likely PR Notes
1 All changes (l10n + MethodChannel + Kotlin receiver + snooze guard) PR 1 Two logically isolated features; same PR acceptable given low line count

Phase 1: Foundation — ARB Keys and Contracts

  • 1.1 Add preNoticeCountdown key (value: "Starts in {minutes} min") to lib/l10n/app_en.arb as the canonical English source key.
  • 1.2 [RED] Write a Dart unit test asserting AppLocalizations.of(ctx).preNoticeCountdown(minutes: 30) returns the expected English string; confirm it fails (key missing).
  • 1.3 Add preNoticeCountdown key to all 12 remaining lib/l10n/app_*.arb files (es, fr, de, pt, it, ja, ko, zh, ar, ru, nl, pl) using locale-appropriate translation following the durationMinutesOnly sentence pattern. Each value must contain the {minutes} placeholder.
  • 1.4 [GREEN] Run flutter gen-l10n; confirm test 1.2 now passes.
  • 1.5 [REFACTOR] Verify ARB placeholder annotations ("@preNoticeCountdown" with placeholders.minutes.type: "int") are present in app_en.arb per ARB spec convention.

Phase 2: Flutter Side — MethodChannel Argument

  • 2.1 [RED] Write a unit/widget test for ServicioAlarmasAndroid.programar() asserting the MethodChannel call includes a preNoticeTemplate key whose value contains {minutes}.
  • 2.2 In lib/servicios/servicio_alarmas_android.dart, compute preNoticeTemplate from l10n.preNoticeCountdown(minutes: '{minutes}') (passing the literal placeholder string) and add it to the scheduleAlarm MethodChannel arguments map.
  • 2.3 [GREEN] Confirm test 2.1 passes.
  • 2.4 [REFACTOR] Ensure the preNoticeTemplate argument is added adjacent to the existing title localization call; no dead code left over.

Phase 3: Kotlin — AlarmScheduler and NativeAlarmSpec

  • 3.1 [RED] Write a Kotlin unit test asserting AlarmScheduler.scheduleAlarm() with a preNoticeTemplate string stores it in the resulting NativeAlarmSpec and embeds it into the PendingIntent extras under key "preNoticeTemplate".
  • 3.2 Add preNoticeTemplate: String? = null field to NativeAlarmSpec data class in android/.../AlarmScheduler.kt (nullable for backward compat; schema stays v3).
  • 3.3 Update MainActivity.kt to read preNoticeTemplate from the MethodChannel arguments map and pass it to AlarmScheduler.scheduleAlarm().
  • 3.4 In AlarmScheduler.scheduleAlarm(), accept preNoticeTemplate param and embed it into the pre-notice Intent extras as EXTRA_PRE_NOTICE_TEMPLATE = "preNoticeTemplate".
  • 3.5 [GREEN] Confirm test 3.1 passes.
  • 3.6 [REFACTOR] Confirm EXTRA_PRE_NOTICE_TEMPLATE constant is declared once (in AlarmScheduler or a shared constants file) and not duplicated between scheduler and receiver.

Phase 4: Kotlin — BroadcastReceiver Countdown Computation

  • 4.1 [RED] Write a Kotlin unit test for PluriWaveAlarmReceiver.showPreNoticeNotification() covering: (a) normal case returns template with computed minutes, (b) clamped to 1 when triggerAtMillis <= currentTimeMillis, (c) null template falls back to English default text.
  • 4.2 In android/.../PluriWaveAlarmReceiver.kt, read EXTRA_PRE_NOTICE_TEMPLATE from the intent extras. Compute remaining = max(1L, (triggerAtMillis - System.currentTimeMillis()) / 60_000). Replace {minutes} placeholder in the template and pass result to NotificationCompat.Builder.setContentText().
  • 4.3 Add null-safety fallback: if preNoticeTemplate is null or blank, use "Starts in $remaining min" as the default English string.
  • 4.4 Remove the existing hardcoded Spanish "Empieza en 30 minutos" string from the receiver.
  • 4.5 [GREEN] Confirm all test cases in 4.1 pass.
  • 4.6 [REFACTOR] Extract the minutes-computation expression into a private function computeRemainingMinutes(triggerAtMillis: Long): Long for readability and testability.

Phase 5: Dart — Snooze Dismiss Guard

  • 5.1 [RED] Write a widget test for PantallaAlarmaSonando._posponer() in lib/pantallas/pantalla_alarma_sonando.dart asserting: (a) when Navigator.canPop() is true, Navigator.pop() is called and SystemNavigator.pop() is NOT called; (b) when canPop() is false, SystemNavigator.pop() is called instead.
  • 5.2 In lib/pantallas/pantalla_alarma_sonando.dart, replace the bare Navigator.of(context).pop() in _posponer() with if (Navigator.of(context).canPop()) { Navigator.of(context).pop(); } else { SystemNavigator.pop(); }. Apply the same guard to _detener() if it also calls pop() without a guard.
  • 5.3 Verify that _liberarAudioLocal(), radio.audio.pausar(), and alarmas.posponerAlarma() all execute BEFORE the navigation action (ordering unchanged).
  • 5.4 [GREEN] Confirm tests from 5.1 pass.
  • 5.5 [REFACTOR] Extract the guard into a private helper _dismissScreen() called from both _posponer() and _detener() to eliminate duplication.

Phase 6: Integration Verification

  • 6.1 Extend existing scheduleAlarm integration test (MethodChannel round-trip) to assert preNoticeTemplate survives the Flutter → Kotlin boundary correctly.
  • 6.2 Confirm notificationIdForAlarm(alarmId) is used in showPreNoticeNotification() (notification ID stability — re-posting same ID updates in place). No change needed if already correct; add assertion to test if not.
  • 6.3 Run full test suite (flutter test + Kotlin ./gradlew test); all pre-existing tests must remain green.
  • 6.4 Manual smoke test: schedule an alarm ~2 min out; verify pre-notice notification shows correct locale and computed minutes; tap Snooze from a fresh app launch; confirm screen dismisses cleanly.

Phase 7: Cleanup

  • 7.1 Confirm no hardcoded Spanish strings remain in PluriWaveAlarmReceiver.kt notification path (rg "Empieza" android/).
  • 7.2 Confirm preNoticeTemplate is the only new MethodChannel key added; no dead args left in scheduleAlarm map.
  • 7.3 Update inline code comments in AlarmScheduler.kt and PluriWaveAlarmReceiver.kt to document the template-at-schedule-time, replace-at-fire-time pattern.