# Alarm Snooze Reschedule Specification ## Purpose Snoozing an alarm (from the ringing screen or from a pre-notice) MUST reliably re-arm the native Android alarm, refresh the in-app UI, and inform the user when scheduling fails. This spec covers `EstadoAlarmas.posponerAlarma()`, `EstadoAlarmas.posponerProximaDesdePreaviso()`, and the user-facing failure feedback in `_posponer()`. ## Requirements ### Requirement: Permission Pre-Check Before Snooze Scheduling The system MUST call `_solicitarPermisosNecesariosParaAlarma()` before invoking `android.programar()` in both `posponerAlarma()` and `posponerProximaDesdePreaviso()`, mirroring `guardarAlarma()`. #### Scenario: Exact-alarm permission was revoked since the alarm was created - GIVEN the exact-alarm permission was previously granted but has since been revoked (OEM battery manager or Android 14 auto-revoke) - WHEN the user snoozes the ringing alarm - THEN the system re-requests the exact-alarm permission before calling `android.programar()` #### Scenario: Permission already granted - GIVEN the exact-alarm permission is currently granted - WHEN the user snoozes the alarm - THEN the permission pre-check is a no-op and scheduling proceeds immediately ### Requirement: Native Scheduling Failure Must Not Corrupt UI State `posponerAlarma()` and `posponerProximaDesdePreaviso()` MUST wrap the call to `android.programar()` in try/catch and MUST call `notifyListeners()` regardless of whether scheduling succeeds or fails. #### Scenario: Native scheduling succeeds (happy path) - GIVEN the user snoozes an alarm from the ringing screen - WHEN `android.programar()` completes successfully - THEN the in-memory alarm state reflects the new `snoozeHasta` - AND `notifyListeners()` is called - AND the "next alarm" panel updates to show the snoozed time - AND a per-minute countdown notification appears - AND the native alarm re-fires at the snoozed time #### Scenario: Native scheduling throws (failure path) - GIVEN the user snoozes an alarm from the ringing screen - WHEN `android.programar()` throws (e.g. `StateError` from a failed `scheduleAlarm` platform call) - THEN the exception is caught inside `posponerAlarma()` (or `posponerProximaDesdePreaviso()`) - AND `notifyListeners()` is still called - AND no real alarm is left silently un-scheduled without the UI knowing - AND the failure is recorded (e.g. into an error field) instead of propagating uncaught #### Scenario: Pre-notice snooze failure (variant path) - GIVEN the user snoozes from a pre-notice (not the ringing screen) - WHEN `android.programar()` throws inside `posponerProximaDesdePreaviso()` - THEN the same catch + `notifyListeners()` guarantee applies as in `posponerAlarma()` ### Requirement: User-Facing Failure Feedback `_posponer()` in `pantalla_alarma_sonando.dart` MUST surface a scheduling failure to the user (e.g. via SnackBar) instead of only `debugPrint`. #### Scenario: Snooze fails and ringing screen dismisses - GIVEN `posponerAlarma()` reports a failure (via thrown/caught error or returned failure state) - WHEN `_posponer()` handles the result - THEN the ringing screen still dismisses (existing dismiss-by-design behavior is preserved) - AND the user sees an explicit failure message (e.g. SnackBar) before or immediately after dismissal - AND no failure is silently swallowed with only a debug log #### Scenario: Snooze succeeds - GIVEN `posponerAlarma()` completes successfully - WHEN `_posponer()` handles the result - THEN the ringing screen dismisses - AND no failure message is shown