268 lines
7.6 KiB
Dart
268 lines
7.6 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'package:uuid/uuid.dart';
|
|
|
|
import '../modelos/alarma_musical.dart';
|
|
import '../modelos/emisora.dart';
|
|
import 'servicio_programacion_alarmas.dart';
|
|
|
|
class ConfiguracionAlarmas {
|
|
const ConfiguracionAlarmas({
|
|
required this.alarmas,
|
|
required this.vacaciones,
|
|
required this.excepciones,
|
|
});
|
|
|
|
final List<AlarmaMusical> alarmas;
|
|
final List<RangoVacaciones> vacaciones;
|
|
final List<ExcepcionAlarma> excepciones;
|
|
}
|
|
|
|
class ServicioAlarmas {
|
|
ServicioAlarmas({
|
|
ServicioProgramacionAlarmas? programacion,
|
|
SharedPreferences? prefs,
|
|
DateTime Function()? reloj,
|
|
}) : _programacion = programacion ?? ServicioProgramacionAlarmas(),
|
|
_prefs = prefs,
|
|
_reloj = reloj ?? DateTime.now;
|
|
|
|
static const _keyConfig = 'alarmas_musicales_v1';
|
|
final ServicioProgramacionAlarmas _programacion;
|
|
final SharedPreferences? _prefs;
|
|
final DateTime Function() _reloj;
|
|
final _uuid = const Uuid();
|
|
|
|
Future<ConfiguracionAlarmas> cargar() async {
|
|
final prefs = await _resolverPrefs();
|
|
final raw = prefs.getString(_keyConfig);
|
|
if (raw == null || raw.trim().isEmpty) {
|
|
return const ConfiguracionAlarmas(
|
|
alarmas: [],
|
|
vacaciones: [],
|
|
excepciones: [],
|
|
);
|
|
}
|
|
try {
|
|
final data = jsonDecode(raw) as Map<String, dynamic>;
|
|
return ConfiguracionAlarmas(
|
|
alarmas:
|
|
(data['alarmas'] as List? ?? const [])
|
|
.whereType<Map>()
|
|
.map(
|
|
(e) => AlarmaMusical.fromJson(Map<String, dynamic>.from(e)),
|
|
)
|
|
.toList(),
|
|
vacaciones:
|
|
(data['vacaciones'] as List? ?? const [])
|
|
.whereType<Map>()
|
|
.map(
|
|
(e) => RangoVacaciones.fromJson(Map<String, dynamic>.from(e)),
|
|
)
|
|
.toList(),
|
|
excepciones:
|
|
(data['excepciones'] as List? ?? const [])
|
|
.whereType<Map>()
|
|
.map(
|
|
(e) => ExcepcionAlarma.fromJson(Map<String, dynamic>.from(e)),
|
|
)
|
|
.toList(),
|
|
);
|
|
} catch (_) {
|
|
return const ConfiguracionAlarmas(
|
|
alarmas: [],
|
|
vacaciones: [],
|
|
excepciones: [],
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<ConfiguracionAlarmas> guardarAlarma(
|
|
AlarmaMusical alarma, {
|
|
List<RangoVacaciones>? vacaciones,
|
|
List<ExcepcionAlarma>? excepciones,
|
|
}) async {
|
|
final config = await cargar();
|
|
final ahora = _reloj();
|
|
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,
|
|
);
|
|
|
|
if (index >= 0) {
|
|
alarmas[index] = normalizada;
|
|
} else {
|
|
alarmas.add(normalizada);
|
|
}
|
|
final nuevo = ConfiguracionAlarmas(
|
|
alarmas: alarmas,
|
|
vacaciones: vacaciones ?? config.vacaciones,
|
|
excepciones: excepciones ?? config.excepciones,
|
|
);
|
|
await _guardar(nuevo);
|
|
return nuevo;
|
|
}
|
|
|
|
Future<ConfiguracionAlarmas> eliminarAlarma(String id) async {
|
|
final config = await cargar();
|
|
final nuevo = ConfiguracionAlarmas(
|
|
alarmas: config.alarmas.where((a) => a.id != id).toList(),
|
|
vacaciones: config.vacaciones,
|
|
excepciones: config.excepciones.where((e) => e.alarmaId != id).toList(),
|
|
);
|
|
await _guardar(nuevo);
|
|
return nuevo;
|
|
}
|
|
|
|
Future<ConfiguracionAlarmas> guardarVacaciones(
|
|
List<RangoVacaciones> vacaciones,
|
|
) async {
|
|
final config = await cargar();
|
|
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,
|
|
vacaciones: normalizadas,
|
|
excepciones: config.excepciones,
|
|
);
|
|
await _guardar(nuevo);
|
|
return nuevo;
|
|
}
|
|
|
|
RangoVacaciones crearRangoVacaciones({
|
|
required DateTime inicio,
|
|
required DateTime fin,
|
|
String? nombre,
|
|
}) {
|
|
final rango = RangoVacaciones(
|
|
id: _uuid.v4(),
|
|
nombre: (nombre == null || nombre.trim().isEmpty)
|
|
? 'Vacaciones'
|
|
: nombre.trim(),
|
|
inicio: inicio,
|
|
fin: fin,
|
|
);
|
|
return rango.normalizado();
|
|
}
|
|
|
|
Future<ConfiguracionAlarmas> recalcularTodas() async {
|
|
final config = await cargar();
|
|
final alarmas =
|
|
config.alarmas
|
|
.map((a) => _recalcular(a, config.vacaciones, config.excepciones))
|
|
.toList();
|
|
final nuevo = ConfiguracionAlarmas(
|
|
alarmas: alarmas,
|
|
vacaciones: config.vacaciones,
|
|
excepciones: config.excepciones,
|
|
);
|
|
await _guardar(nuevo);
|
|
return nuevo;
|
|
}
|
|
|
|
Future<ConfiguracionAlarmas> saltarProxima(String alarmaId) async {
|
|
final config = await cargar();
|
|
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;
|
|
}
|
|
|
|
AlarmaMusical crearAlarma({
|
|
required String nombre,
|
|
required int hora,
|
|
required int minuto,
|
|
required TipoProgramacionAlarma tipoProgramacion,
|
|
required List<int> diasSemana,
|
|
DateTime? fechaUnica,
|
|
Emisora? emisora,
|
|
Emisora? emisoraFallback,
|
|
bool sonarEnVacaciones = true,
|
|
int snoozeMinutos = 5,
|
|
double volumen = 0.85,
|
|
SonidoInternoAlarma sonidoInterno = SonidoInternoAlarma.amanecer,
|
|
}) {
|
|
final ahora = _reloj();
|
|
return AlarmaMusical(
|
|
id: _uuid.v4(),
|
|
nombre: nombre,
|
|
hora: hora,
|
|
minuto: minuto,
|
|
tipoProgramacion: tipoProgramacion,
|
|
diasSemana: diasSemana,
|
|
fechaUnica: fechaUnica,
|
|
emisora: emisora,
|
|
emisoraFallback: emisoraFallback,
|
|
sonarEnVacaciones: sonarEnVacaciones,
|
|
snoozeMinutos: snoozeMinutos,
|
|
volumen: volumen,
|
|
sonidoInterno: sonidoInterno,
|
|
creadaEn: ahora,
|
|
actualizadaEn: ahora,
|
|
);
|
|
}
|
|
|
|
Future<void> _guardar(ConfiguracionAlarmas config) async {
|
|
final prefs = await _resolverPrefs();
|
|
await prefs.setString(
|
|
_keyConfig,
|
|
jsonEncode({
|
|
'alarmas': config.alarmas.map((a) => a.toJson()).toList(),
|
|
'vacaciones': config.vacaciones.map((v) => v.toJson()).toList(),
|
|
'excepciones': config.excepciones.map((e) => e.toJson()).toList(),
|
|
}),
|
|
);
|
|
}
|
|
|
|
AlarmaMusical _recalcular(
|
|
AlarmaMusical alarma,
|
|
List<RangoVacaciones> vacaciones,
|
|
List<ExcepcionAlarma> excepciones,
|
|
) {
|
|
final proxima = _programacion.calcularProxima(
|
|
alarma: alarma,
|
|
desde: _reloj(),
|
|
vacaciones: vacaciones,
|
|
excepciones: excepciones,
|
|
);
|
|
return alarma.copyWith(
|
|
proximaEjecucion: proxima,
|
|
limpiarProximaEjecucion: true,
|
|
);
|
|
}
|
|
|
|
Future<SharedPreferences> _resolverPrefs() async =>
|
|
_prefs ?? SharedPreferences.getInstance();
|
|
}
|