fix(alarm): recalculate every alarm on each mutation, not just the touched one
guardarAlarma only recomputed proximaEjecucion for the alarm being saved; every other alarm kept whatever snapshot the last periodic recalculation left, which can be stale or already past-due. Since EstadoAlarmas.proximaAlarma just sorts by proximaProgramable, a stale sibling could wrongly outrank a freshly activated/created/edited alarm in the "Próxima alarma" panel until the next 1-minute tick. Extended the same full-list recalculation guardarVacaciones already did to guardarAlarma, eliminarAlarma, completarEjecucion, sincronizarEjecucionesNativas, saltarProxima and posponerEjecucionHasta, via a shared _recalcularLista helper.
This commit is contained in:
@@ -116,23 +116,32 @@ class ServicioAlarmas {
|
||||
}) => _enCola(() async {
|
||||
final config = await _configActual();
|
||||
final ahora = _reloj();
|
||||
final vacacionesActuales = vacaciones ?? config.vacaciones;
|
||||
final excepcionesActuales = excepciones ?? config.excepciones;
|
||||
final alarmas = List<AlarmaMusical>.from(config.alarmas);
|
||||
final index = alarmas.indexWhere((a) => a.id == alarma.id);
|
||||
final normalizada = _recalcular(
|
||||
alarma.copyWith(creadaEn: alarma.creadaEn ?? ahora, actualizadaEn: ahora),
|
||||
vacaciones ?? config.vacaciones,
|
||||
excepciones ?? config.excepciones,
|
||||
final actualizada = alarma.copyWith(
|
||||
creadaEn: alarma.creadaEn ?? ahora,
|
||||
actualizadaEn: ahora,
|
||||
);
|
||||
|
||||
if (index >= 0) {
|
||||
alarmas[index] = normalizada;
|
||||
alarmas[index] = actualizada;
|
||||
} else {
|
||||
alarmas.add(normalizada);
|
||||
alarmas.add(actualizada);
|
||||
}
|
||||
// Recalculate every alarm, not just the one just saved: siblings can
|
||||
// hold a proximaEjecucion snapshot from the last periodic tick that is
|
||||
// stale (even past-due), which would otherwise outrank a freshly
|
||||
// created/activated/edited alarm when EstadoAlarmas.proximaAlarma sorts
|
||||
// by proximaProgramable.
|
||||
final nuevo = ConfiguracionAlarmas(
|
||||
alarmas: alarmas,
|
||||
vacaciones: vacaciones ?? config.vacaciones,
|
||||
excepciones: excepciones ?? config.excepciones,
|
||||
alarmas: _recalcularLista(
|
||||
alarmas,
|
||||
vacacionesActuales,
|
||||
excepcionesActuales,
|
||||
),
|
||||
vacaciones: vacacionesActuales,
|
||||
excepciones: excepcionesActuales,
|
||||
);
|
||||
await _guardar(nuevo);
|
||||
return nuevo;
|
||||
@@ -140,10 +149,13 @@ class ServicioAlarmas {
|
||||
|
||||
Future<ConfiguracionAlarmas> eliminarAlarma(String id) => _enCola(() async {
|
||||
final config = await _configActual();
|
||||
final restantes = config.alarmas.where((a) => a.id != id).toList();
|
||||
final excepciones =
|
||||
config.excepciones.where((e) => e.alarmaId != id).toList();
|
||||
final nuevo = ConfiguracionAlarmas(
|
||||
alarmas: config.alarmas.where((a) => a.id != id).toList(),
|
||||
alarmas: _recalcularLista(restantes, config.vacaciones, excepciones),
|
||||
vacaciones: config.vacaciones,
|
||||
excepciones: config.excepciones.where((e) => e.alarmaId != id).toList(),
|
||||
excepciones: excepciones,
|
||||
);
|
||||
await _guardar(nuevo);
|
||||
return nuevo;
|
||||
@@ -156,12 +168,12 @@ class ServicioAlarmas {
|
||||
final normalizadas =
|
||||
vacaciones.map((v) => v.normalizado()).toList()
|
||||
..sort((a, b) => a.inicioDia.compareTo(b.inicioDia));
|
||||
final alarmas =
|
||||
config.alarmas
|
||||
.map((a) => _recalcular(a, normalizadas, config.excepciones))
|
||||
.toList();
|
||||
final nuevo = ConfiguracionAlarmas(
|
||||
alarmas: alarmas,
|
||||
alarmas: _recalcularLista(
|
||||
config.alarmas,
|
||||
normalizadas,
|
||||
config.excepciones,
|
||||
),
|
||||
vacaciones: normalizadas,
|
||||
excepciones: config.excepciones,
|
||||
);
|
||||
@@ -188,10 +200,11 @@ class ServicioAlarmas {
|
||||
|
||||
Future<ConfiguracionAlarmas> recalcularTodas() => _enCola(() async {
|
||||
final config = await _configActual();
|
||||
final alarmas =
|
||||
config.alarmas
|
||||
.map((a) => _recalcular(a, config.vacaciones, config.excepciones))
|
||||
.toList();
|
||||
final alarmas = _recalcularLista(
|
||||
config.alarmas,
|
||||
config.vacaciones,
|
||||
config.excepciones,
|
||||
);
|
||||
final nuevo = ConfiguracionAlarmas(
|
||||
alarmas: alarmas,
|
||||
vacaciones: config.vacaciones,
|
||||
@@ -258,7 +271,7 @@ class ServicioAlarmas {
|
||||
|
||||
if (!huboCambios) return config;
|
||||
final nuevo = ConfiguracionAlarmas(
|
||||
alarmas: alarmas,
|
||||
alarmas: _recalcularLista(alarmas, config.vacaciones, config.excepciones),
|
||||
vacaciones: config.vacaciones,
|
||||
excepciones: config.excepciones,
|
||||
);
|
||||
@@ -266,38 +279,26 @@ class ServicioAlarmas {
|
||||
return nuevo;
|
||||
}
|
||||
|
||||
Future<ConfiguracionAlarmas> saltarProxima(String alarmaId) =>
|
||||
_enCola(() async {
|
||||
final config = await _configActual();
|
||||
final alarma = config.alarmas.firstWhere((a) => a.id == alarmaId);
|
||||
final proxima = alarma.proximaEjecucion;
|
||||
if (proxima == null) return config;
|
||||
Future<ConfiguracionAlarmas> saltarProxima(
|
||||
String alarmaId,
|
||||
) => _enCola(() async {
|
||||
final config = await _configActual();
|
||||
final alarma = config.alarmas.firstWhere((a) => a.id == alarmaId);
|
||||
final proxima = alarma.proximaEjecucion;
|
||||
if (proxima == null) return config;
|
||||
|
||||
final excepciones = [
|
||||
...config.excepciones,
|
||||
ExcepcionAlarma(
|
||||
alarmaId: alarmaId,
|
||||
ejecucion: proxima,
|
||||
tipo: 'skipNext',
|
||||
),
|
||||
];
|
||||
final alarmas =
|
||||
config.alarmas
|
||||
.map(
|
||||
(a) =>
|
||||
a.id == alarmaId
|
||||
? _recalcular(a, config.vacaciones, excepciones)
|
||||
: a,
|
||||
)
|
||||
.toList();
|
||||
final nuevo = ConfiguracionAlarmas(
|
||||
alarmas: alarmas,
|
||||
vacaciones: config.vacaciones,
|
||||
excepciones: excepciones,
|
||||
);
|
||||
await _guardar(nuevo);
|
||||
return nuevo;
|
||||
});
|
||||
final excepciones = [
|
||||
...config.excepciones,
|
||||
ExcepcionAlarma(alarmaId: alarmaId, ejecucion: proxima, tipo: 'skipNext'),
|
||||
];
|
||||
final nuevo = ConfiguracionAlarmas(
|
||||
alarmas: _recalcularLista(config.alarmas, config.vacaciones, excepciones),
|
||||
vacaciones: config.vacaciones,
|
||||
excepciones: excepciones,
|
||||
);
|
||||
await _guardar(nuevo);
|
||||
return nuevo;
|
||||
});
|
||||
|
||||
Future<ConfiguracionAlarmas> posponerEjecucion(
|
||||
String alarmaId,
|
||||
@@ -340,7 +341,7 @@ class ServicioAlarmas {
|
||||
)
|
||||
.toList();
|
||||
final nuevo = ConfiguracionAlarmas(
|
||||
alarmas: alarmas,
|
||||
alarmas: _recalcularLista(alarmas, config.vacaciones, config.excepciones),
|
||||
vacaciones: config.vacaciones,
|
||||
excepciones: config.excepciones,
|
||||
);
|
||||
@@ -376,7 +377,7 @@ class ServicioAlarmas {
|
||||
);
|
||||
}).toList();
|
||||
final nuevo = ConfiguracionAlarmas(
|
||||
alarmas: alarmas,
|
||||
alarmas: _recalcularLista(alarmas, config.vacaciones, config.excepciones),
|
||||
vacaciones: config.vacaciones,
|
||||
excepciones: config.excepciones,
|
||||
);
|
||||
@@ -459,6 +460,18 @@ class ServicioAlarmas {
|
||||
);
|
||||
}
|
||||
|
||||
// Every mutation that can shift "which alarm fires next" (create, edit,
|
||||
// activate/deactivate, delete, fire, snooze, skip) recalculates the whole
|
||||
// list, not just the alarm it touched directly. Siblings otherwise keep a
|
||||
// proximaEjecucion snapshot from the last periodic tick, which can be
|
||||
// stale (or already past-due) and wrongly outrank a freshly updated alarm
|
||||
// wherever proximaProgramable values are compared (EstadoAlarmas.proximaAlarma).
|
||||
List<AlarmaMusical> _recalcularLista(
|
||||
List<AlarmaMusical> alarmas,
|
||||
List<RangoVacaciones> vacaciones,
|
||||
List<ExcepcionAlarma> excepciones,
|
||||
) => alarmas.map((a) => _recalcular(a, vacaciones, excepciones)).toList();
|
||||
|
||||
Future<SharedPreferences> _resolverPrefs() async =>
|
||||
_prefs ?? SharedPreferences.getInstance();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user