From a48dd6ddf97f2c422b776473daa01818c4058188 Mon Sep 17 00:00:00 2001 From: freetlab Date: Fri, 22 May 2026 18:41:57 +0200 Subject: [PATCH] fix(alarms): refresh next execution reliably --- .../freetimelab/pluriwave/AlarmScheduler.kt | 12 +++++++++- lib/estado/estado_alarmas.dart | 3 +++ lib/modelos/alarma_musical.dart | 6 ++++- lib/servicios/servicio_alarmas.dart | 14 ++++++----- .../servicio_programacion_alarmas_test.dart | 23 +++++++++++++++++++ 5 files changed, 50 insertions(+), 8 deletions(-) diff --git a/android/app/src/main/kotlin/es/freetimelab/pluriwave/AlarmScheduler.kt b/android/app/src/main/kotlin/es/freetimelab/pluriwave/AlarmScheduler.kt index 9650171..402f15d 100644 --- a/android/app/src/main/kotlin/es/freetimelab/pluriwave/AlarmScheduler.kt +++ b/android/app/src/main/kotlin/es/freetimelab/pluriwave/AlarmScheduler.kt @@ -47,7 +47,8 @@ class AlarmScheduler(private val context: Context) { ) Log.d(tag, "alarm.schedule setAlarmClock OK id=$id") - if (preNoticeAtMillis > System.currentTimeMillis()) { + val now = System.currentTimeMillis() + if (preNoticeAtMillis > now) { try { alarmManager.setExactAndAllowWhileIdle( AlarmManager.RTC_WAKEUP, @@ -68,6 +69,15 @@ class AlarmScheduler(private val context: Context) { // The main alarm is already scheduled with setAlarmClock. Log.w(tag, "alarm.schedule preNotice SecurityException id=$id") } + } else if (triggerAtMillis > now) { + context.sendBroadcast( + Intent(context, PluriWaveAlarmReceiver::class.java).apply { + action = PluriWaveAlarmReceiver.ACTION_PRE_NOTICE + putExtra(PluriWaveAlarmReceiver.EXTRA_ALARM_ID, id) + putExtra(PluriWaveAlarmReceiver.EXTRA_ALARM_TITLE, title) + } + ) + Log.d(tag, "alarm.schedule preNotice immediate id=$id") } else { Log.d(tag, "alarm.schedule preNotice skipped id=$id") } diff --git a/lib/estado/estado_alarmas.dart b/lib/estado/estado_alarmas.dart index 01e9429..b6e93fb 100644 --- a/lib/estado/estado_alarmas.dart +++ b/lib/estado/estado_alarmas.dart @@ -88,6 +88,9 @@ class EstadoAlarmas extends ChangeNotifier { debugPrint('[PluriWave][alarmas] refrescar programacion'); final config = await servicio.recalcularTodas(); _aplicar(config); + debugPrint( + '[PluriWave][alarmas] proxima tras refrescar=${proximaAlarma?.id} ${proximaAlarma?.proximaEjecucion?.toIso8601String()}', + ); await _sincronizarTodas(); notifyListeners(); } diff --git a/lib/modelos/alarma_musical.dart b/lib/modelos/alarma_musical.dart index bc8faca..facf063 100644 --- a/lib/modelos/alarma_musical.dart +++ b/lib/modelos/alarma_musical.dart @@ -60,6 +60,7 @@ class AlarmaMusical { double? volumen, SonidoInternoAlarma? sonidoInterno, DateTime? proximaEjecucion, + bool limpiarProximaEjecucion = false, DateTime? creadaEn, DateTime? actualizadaEn, }) { @@ -78,7 +79,10 @@ class AlarmaMusical { snoozeMinutos: snoozeMinutos ?? this.snoozeMinutos, volumen: volumen ?? this.volumen, sonidoInterno: sonidoInterno ?? this.sonidoInterno, - proximaEjecucion: proximaEjecucion ?? this.proximaEjecucion, + proximaEjecucion: + limpiarProximaEjecucion + ? proximaEjecucion + : proximaEjecucion ?? this.proximaEjecucion, creadaEn: creadaEn ?? this.creadaEn, actualizadaEn: actualizadaEn ?? this.actualizadaEn, ); diff --git a/lib/servicios/servicio_alarmas.dart b/lib/servicios/servicio_alarmas.dart index b412511..814b982 100644 --- a/lib/servicios/servicio_alarmas.dart +++ b/lib/servicios/servicio_alarmas.dart @@ -250,13 +250,15 @@ class ServicioAlarmas { List vacaciones, List excepciones, ) { + final proxima = _programacion.calcularProxima( + alarma: alarma, + desde: _reloj(), + vacaciones: vacaciones, + excepciones: excepciones, + ); return alarma.copyWith( - proximaEjecucion: _programacion.calcularProxima( - alarma: alarma, - desde: _reloj(), - vacaciones: vacaciones, - excepciones: excepciones, - ), + proximaEjecucion: proxima, + limpiarProximaEjecucion: true, ); } diff --git a/test/servicios/servicio_programacion_alarmas_test.dart b/test/servicios/servicio_programacion_alarmas_test.dart index fbe8253..6cdac8b 100644 --- a/test/servicios/servicio_programacion_alarmas_test.dart +++ b/test/servicios/servicio_programacion_alarmas_test.dart @@ -1,6 +1,8 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:pluriwave/modelos/alarma_musical.dart'; +import 'package:pluriwave/servicios/servicio_alarmas.dart'; import 'package:pluriwave/servicios/servicio_programacion_alarmas.dart'; +import 'package:shared_preferences/shared_preferences.dart'; void main() { group('ServicioProgramacionAlarmas', () { @@ -83,5 +85,26 @@ void main() { DateTime(2026, 5, 21, 7, 5), ); }); + + test('servicio limpia proxima ejecucion obsoleta al recalcular unica vencida', () async { + SharedPreferences.setMockInitialValues({}); + final servicioAlarmas = ServicioAlarmas( + reloj: () => DateTime(2026, 5, 22, 10), + ); + final alarma = AlarmaMusical( + id: 'a4', + nombre: 'Unica vencida', + hora: 9, + minuto: 0, + tipoProgramacion: TipoProgramacionAlarma.unica, + diasSemana: const [], + fechaUnica: DateTime(2026, 5, 22), + proximaEjecucion: DateTime(2026, 5, 22, 9), + ); + + final guardada = await servicioAlarmas.guardarAlarma(alarma); + + expect(guardada.alarmas.single.proximaEjecucion, isNull); + }); }); }