feat(alarm): complete musical alarm flows
This commit is contained in:
@@ -122,13 +122,49 @@ class ServicioAlarmas {
|
||||
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, vacaciones, config.excepciones))
|
||||
.map((a) => _recalcular(a, normalizadas, config.excepciones))
|
||||
.toList();
|
||||
final nuevo = ConfiguracionAlarmas(
|
||||
alarmas: alarmas,
|
||||
vacaciones: vacaciones,
|
||||
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);
|
||||
@@ -169,7 +205,13 @@ class ServicioAlarmas {
|
||||
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(
|
||||
@@ -179,7 +221,13 @@ class ServicioAlarmas {
|
||||
minuto: minuto,
|
||||
tipoProgramacion: tipoProgramacion,
|
||||
diasSemana: diasSemana,
|
||||
fechaUnica: fechaUnica,
|
||||
emisora: emisora,
|
||||
emisoraFallback: emisoraFallback,
|
||||
sonarEnVacaciones: sonarEnVacaciones,
|
||||
snoozeMinutos: snoozeMinutos,
|
||||
volumen: volumen,
|
||||
sonidoInterno: sonidoInterno,
|
||||
creadaEn: ahora,
|
||||
actualizadaEn: ahora,
|
||||
);
|
||||
|
||||
@@ -1,7 +1,29 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../modelos/alarma_musical.dart';
|
||||
|
||||
class EventoAlarmaAndroid {
|
||||
const EventoAlarmaAndroid({
|
||||
required this.alarmaId,
|
||||
required this.titulo,
|
||||
required this.accion,
|
||||
});
|
||||
|
||||
final String alarmaId;
|
||||
final String titulo;
|
||||
final String accion;
|
||||
|
||||
factory EventoAlarmaAndroid.fromMap(Map<Object?, Object?> map) {
|
||||
return EventoAlarmaAndroid(
|
||||
alarmaId: map['alarmId'] as String? ?? '',
|
||||
titulo: map['alarmTitle'] as String? ?? 'PluriWave',
|
||||
accion: map['alarmAction'] as String? ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DiagnosticoAlarmasAndroid {
|
||||
const DiagnosticoAlarmasAndroid({
|
||||
required this.puedeProgramarExactas,
|
||||
@@ -28,9 +50,16 @@ class DiagnosticoAlarmasAndroid {
|
||||
class ServicioAlarmasAndroid {
|
||||
ServicioAlarmasAndroid({
|
||||
MethodChannel channel = const MethodChannel('pluriwave/alarm_scheduler'),
|
||||
}) : _channel = channel;
|
||||
}) : _channel = channel {
|
||||
_instalarHandler(_channel);
|
||||
}
|
||||
|
||||
final MethodChannel _channel;
|
||||
static final _eventosController =
|
||||
StreamController<EventoAlarmaAndroid>.broadcast();
|
||||
static bool _handlerInstalado = false;
|
||||
|
||||
Stream<EventoAlarmaAndroid> get eventosAlarma => _eventosController.stream;
|
||||
|
||||
Future<void> programar(AlarmaMusical alarma) async {
|
||||
final proxima = alarma.proximaEjecucion;
|
||||
@@ -56,4 +85,28 @@ class ServicioAlarmasAndroid {
|
||||
);
|
||||
return DiagnosticoAlarmasAndroid.fromMap(raw ?? const {});
|
||||
}
|
||||
|
||||
Future<EventoAlarmaAndroid?> obtenerEventoInicial() async {
|
||||
final raw = await _channel.invokeMethod<Map<Object?, Object?>>(
|
||||
'getInitialAlarmIntent',
|
||||
);
|
||||
if (raw == null || raw.isEmpty) return null;
|
||||
final evento = EventoAlarmaAndroid.fromMap(raw);
|
||||
return evento.alarmaId.isEmpty ? null : evento;
|
||||
}
|
||||
|
||||
static void _instalarHandler(MethodChannel channel) {
|
||||
if (_handlerInstalado) return;
|
||||
_handlerInstalado = true;
|
||||
channel.setMethodCallHandler((call) async {
|
||||
if (call.method != 'alarmFired') return;
|
||||
final args = call.arguments;
|
||||
if (args is Map) {
|
||||
final evento = EventoAlarmaAndroid.fromMap(args);
|
||||
if (evento.alarmaId.isNotEmpty) {
|
||||
_eventosController.add(evento);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,19 +9,29 @@ class ServicioProgramacionAlarmas {
|
||||
}) {
|
||||
if (!alarma.activa) return null;
|
||||
|
||||
final diaBase =
|
||||
alarma.tipoProgramacion == TipoProgramacionAlarma.unica &&
|
||||
alarma.fechaUnica != null
|
||||
? alarma.fechaUnica!
|
||||
: desde;
|
||||
final inicio = DateTime(
|
||||
desde.year,
|
||||
desde.month,
|
||||
desde.day,
|
||||
diaBase.year,
|
||||
diaBase.month,
|
||||
diaBase.day,
|
||||
alarma.hora,
|
||||
alarma.minuto,
|
||||
);
|
||||
final primerCandidato =
|
||||
inicio.isAfter(desde) ? inicio : inicio.add(const Duration(days: 1));
|
||||
alarma.tipoProgramacion == TipoProgramacionAlarma.unica
|
||||
? inicio
|
||||
: inicio.isAfter(desde)
|
||||
? inicio
|
||||
: inicio.add(const Duration(days: 1));
|
||||
|
||||
return switch (alarma.tipoProgramacion) {
|
||||
TipoProgramacionAlarma.unica =>
|
||||
_esValida(alarma, primerCandidato, vacaciones, excepciones)
|
||||
primerCandidato.isAfter(desde) &&
|
||||
_esValida(alarma, primerCandidato, vacaciones, excepciones)
|
||||
? primerCandidato
|
||||
: null,
|
||||
TipoProgramacionAlarma.diaria => _buscarDiaria(
|
||||
|
||||
Reference in New Issue
Block a user