import 'dart:async'; import 'package:flutter/material.dart'; import 'package:just_audio/just_audio.dart'; import 'package:provider/provider.dart'; import '../estado/estado_alarmas.dart'; import '../estado/estado_radio.dart'; import '../modelos/alarma_musical.dart'; import '../servicios/servicio_audio.dart'; import '../widgets/pluri_glass_surface.dart'; class PantallaAlarmaSonando extends StatefulWidget { const PantallaAlarmaSonando({ super.key, required this.alarma, this.audioPrearrancado = false, }); final AlarmaMusical alarma; final bool audioPrearrancado; @override State createState() => _PantallaAlarmaSonandoState(); } class _PantallaAlarmaSonandoState extends State { final AudioPlayer _fallbackPlayer = AudioPlayer(); StreamSubscription? _estadoSub; Timer? _fallbackTimer; bool _fallbackActivo = false; bool _radioIntentada = false; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) => _iniciarAlarma()); } Future _iniciarAlarma() async { final radio = context.read(); await _fallbackPlayer.setVolume(widget.alarma.volumen.clamp(0.0, 1.0)); await _fallbackPlayer.setLoopMode(LoopMode.one); final emisora = widget.alarma.emisora; if (emisora == null) { await _iniciarFallback(); return; } _radioIntentada = true; await radio.audio.setVolumen(widget.alarma.volumen.clamp(0.0, 1.0)); if (!widget.audioPrearrancado) { unawaited(radio.reproducir(emisora)); } _estadoSub = radio.estadoStream.listen((estado) { if (estado == EstadoReproduccion.reproduciendo && mounted) { _fallbackTimer?.cancel(); } if (estado == EstadoReproduccion.error && mounted) { _iniciarFallback(); } }); _fallbackTimer = Timer(const Duration(seconds: 12), () { if (mounted) _iniciarFallback(); }); if (widget.audioPrearrancado && radio.audio.estaSonando) { _fallbackTimer?.cancel(); } } Future _iniciarFallback() async { if (_fallbackActivo) return; _fallbackActivo = true; await _fallbackPlayer.setAsset(_assetFallback(widget.alarma.sonidoInterno)); await _fallbackPlayer.play(); if (mounted) setState(() {}); } Future _detener() async { final radio = context.read(); final alarmas = context.read(); final navigator = Navigator.of(context); _fallbackTimer?.cancel(); await _estadoSub?.cancel(); await _fallbackPlayer.stop(); await radio.audio.pausar(); await alarmas.finalizarEjecucion(widget.alarma.id); if (mounted) navigator.pop(); } Future _posponer(int minutos) async { final radio = context.read(); final alarmas = context.read(); final navigator = Navigator.of(context); _fallbackTimer?.cancel(); await _estadoSub?.cancel(); await _fallbackPlayer.stop(); await radio.audio.pausar(); await alarmas.posponerAlarma(widget.alarma, minutos); if (mounted) navigator.pop(); } @override void dispose() { _fallbackTimer?.cancel(); _estadoSub?.cancel(); _fallbackPlayer.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final alarma = widget.alarma; return Scaffold( backgroundColor: const Color(0xFF061722), body: SafeArea( child: Padding( padding: const EdgeInsets.all(20), child: Center( child: PluriGlassSurface( borderRadius: BorderRadius.circular(32), padding: const EdgeInsets.all(24), glowColor: const Color(0xFFFFB86B).withValues(alpha: 0.35), child: Column( mainAxisSize: MainAxisSize.min, children: [ Image.asset( 'assets/icons/alarmas/alarm_music.png', width: 128, height: 128, ), const SizedBox(height: 16), Text( _hora(alarma), style: Theme.of(context).textTheme.displayMedium?.copyWith( fontWeight: FontWeight.w900, letterSpacing: -2, ), ), const SizedBox(height: 8), Text( alarma.nombre, textAlign: TextAlign.center, style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 8), Text( _fallbackActivo ? 'Sonando con audio seguro interno.' : _radioIntentada ? 'Intentando reproducir tu emisora con máxima calidad disponible.' : 'Preparando audio seguro interno.', textAlign: TextAlign.center, ), const SizedBox(height: 22), FilledButton.icon( onPressed: _detener, icon: const Icon(Icons.stop_rounded), label: const Text('Detener alarma'), ), const SizedBox(height: 12), Wrap( spacing: 8, children: [ for (final min in const [3, 5, 10]) ActionChip( avatar: const Icon(Icons.snooze_rounded, size: 18), label: Text('Posponer $min min'), onPressed: () => _posponer(min), ), ], ), ], ), ), ), ), ), ); } } String _assetFallback(SonidoInternoAlarma sonido) => switch (sonido) { SonidoInternoAlarma.amanecer => 'assets/audio/alarm_amanecer.wav', SonidoInternoAlarma.campanaSuave => 'assets/audio/alarm_campana_suave.wav', SonidoInternoAlarma.pulsoDigital => 'assets/audio/alarm_pulso_digital.wav', }; String _hora(AlarmaMusical alarma) => '${alarma.hora.toString().padLeft(2, '0')}:${alarma.minuto.toString().padLeft(2, '0')}';