fix(alarmas): reload and re-sync alarms after backup import

Importing a backup wrote the alarm/vacation/exception block straight to
SharedPreferences but never told EstadoAlarmas about it, so the UI kept
showing the pre-import alarms, a later edit could persist that stale
state back over the imported one, and imported alarms were never
(re)scheduled with the Android native layer. The backup screen now
calls EstadoAlarmas.cargarPersistidasSinRecalcular() followed by
refrescarProgramacion() after a successful import, extracted into a
directly-testable aplicarImportacionConfig() function.
This commit is contained in:
2026-08-28 22:47:38 +02:00
parent fdddd95199
commit e57f7bb17b
3 changed files with 325 additions and 2 deletions
+6 -1
View File
@@ -945,7 +945,12 @@ class EstadoRadio extends ChangeNotifier {
final alarmasData = data['alarmas'];
if (alarmasData is Map<String, dynamic>) {
// Escribimos el bloque JSON tal como estaba en el dispositivo origen.
// ServicioAlarmas lo leerá con su propio fromJson al siguiente acceso.
// EstadoAlarmas es un ChangeNotifier independiente y de larga vida
// que ya cargó sus alarmas en memoria: NO relee este storage por sí
// solo. El llamador (pantalla_ajustes_backup.dart) es responsable de
// invocar `EstadoAlarmas.cargarPersistidasSinRecalcular()` seguido
// de `refrescarProgramacion()` tras un import exitoso; EstadoRadio
// se mantiene deliberadamente sin depender de EstadoAlarmas.
await prefs.setString(_keyAlarmasConfig, jsonEncode(alarmasData));
}
}
@@ -6,12 +6,45 @@ import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:share_plus/share_plus.dart' show Share, XFile;
import '../../estado/estado_alarmas.dart';
import '../../estado/estado_radio.dart';
import '../../l10n/gen/app_localizations.dart';
import '../../widgets/pluri_glass_surface.dart';
import '../../widgets/pluri_layout.dart';
import '../../widgets/pluri_push_scaffold.dart';
/// Applies a successfully-parsed backup to BOTH independent notifiers that
/// own pieces of it (fix/import-alarmas-y-paywall).
///
/// `EstadoRadio.importarConfig` writes the raw alarm/vacation/exception JSON
/// block straight to SharedPreferences, but `EstadoAlarmas` is a separate
/// long-lived `ChangeNotifier` that loaded its alarms into memory at
/// construction and never re-reads storage on its own — `EstadoRadio` stays
/// deliberately free of a dependency on it. Without the two calls below the
/// imported block is invisible to the running app: the UI keeps showing the
/// pre-import alarms, a later edit would persist that stale in-memory list
/// OVER the imported one, and the imported alarms would never be
/// (re)scheduled with the Android native layer even after a restart.
///
/// Extracted as a top-level function (rather than inlined in `_importar`)
/// so this exact production sequence — not a reimplementation of it — is
/// directly unit-testable without depending on the `file_picker` platform
/// channel or the confirmation dialog.
Future<void> aplicarImportacionConfig(
EstadoRadio estado,
EstadoAlarmas alarmas,
Map<String, dynamic> json,
) async {
await estado.importarConfig(json);
// Re-reads from storage — clears ServicioAlarmas' in-memory cache so the
// just-imported alarms/vacations/exceptions (same JSON block, same
// notifier) replace the stale ones.
await alarmas.cargarPersistidasSinRecalcular();
// Recomputes next-run times against the (now fresh) imported data and
// re-syncs every alarm with the Android native scheduler.
await alarmas.refrescarProgramacion();
}
/// APLICACIÓN group · "Copia de seguridad" (design ADR-3). Body moved
/// verbatim from the former `_SeccionBackup` in `pantalla_ajustes.dart` —
/// only the panel header's icon and title were removed (the pushed screen's
@@ -102,8 +135,9 @@ class _CuerpoBackup extends StatelessWidget {
if (confirmar != true) return;
if (context.mounted) {
final estado = context.read<EstadoRadio>();
final alarmas = context.read<EstadoAlarmas>();
final messenger = ScaffoldMessenger.of(context);
await estado.importarConfig(json);
await aplicarImportacionConfig(estado, alarmas, json);
messenger.showSnackBar(
SnackBar(content: Text(l10n.backupImportSuccess)),
);