feat(alarm): add musical alarm foundation
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
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 alarmas =
|
||||
config.alarmas
|
||||
.map((a) => _recalcular(a, vacaciones, config.excepciones))
|
||||
.toList();
|
||||
final nuevo = ConfiguracionAlarmas(
|
||||
alarmas: alarmas,
|
||||
vacaciones: 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,
|
||||
Emisora? emisora,
|
||||
}) {
|
||||
final ahora = _reloj();
|
||||
return AlarmaMusical(
|
||||
id: _uuid.v4(),
|
||||
nombre: nombre,
|
||||
hora: hora,
|
||||
minuto: minuto,
|
||||
tipoProgramacion: tipoProgramacion,
|
||||
diasSemana: diasSemana,
|
||||
emisora: emisora,
|
||||
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,
|
||||
) {
|
||||
return alarma.copyWith(
|
||||
proximaEjecucion: _programacion.calcularProxima(
|
||||
alarma: alarma,
|
||||
desde: _reloj(),
|
||||
vacaciones: vacaciones,
|
||||
excepciones: excepciones,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<SharedPreferences> _resolverPrefs() async =>
|
||||
_prefs ?? SharedPreferences.getInstance();
|
||||
}
|
||||
Reference in New Issue
Block a user