import 'dart:async'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'estado/estado_radio.dart'; import 'pantallas/pantalla_inicio.dart'; import 'pantallas/pantalla_buscar.dart'; import 'pantallas/pantalla_favoritos.dart'; import 'pantallas/pantalla_ajustes.dart'; import 'tema/pluriwave_theme.dart'; import 'widgets/pluri_icon.dart'; import 'package:pluriwave/widgets/mini_reproductor.dart'; class PluriWaveApp extends StatelessWidget { const PluriWaveApp({super.key}); @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (_) => EstadoRadio(), child: MaterialApp( title: 'PluriWave', debugShowCheckedModeBanner: false, theme: PluriWaveTheme.dark(), darkTheme: PluriWaveTheme.dark(), themeMode: ThemeMode.dark, home: const _PaginaPrincipal(), ), ); } } class _PaginaPrincipal extends StatefulWidget { const _PaginaPrincipal(); @override State<_PaginaPrincipal> createState() => _PaginaPrincipalState(); } class _PaginaPrincipalState extends State<_PaginaPrincipal> { int _indice = 0; StreamSubscription? _errorSubscription; EstadoRadio? _estadoSuscrito; static const _paginas = [ PantallaInicio(), PantallaBuscar(), PantallaFavoritos(), PantallaAjustes(), ]; static const _destinos = [ NavigationDestination( icon: PluriIcon(glyph: PluriIconGlyph.home), selectedIcon: PluriIcon( glyph: PluriIconGlyph.home, variant: PluriIconVariant.activeGlow, ), label: 'Inicio', ), NavigationDestination( icon: PluriIcon(glyph: PluriIconGlyph.search), selectedIcon: PluriIcon( glyph: PluriIconGlyph.search, variant: PluriIconVariant.activeGlow, ), label: 'Buscar', ), NavigationDestination( icon: PluriIcon(glyph: PluriIconGlyph.favorites), selectedIcon: PluriIcon( glyph: PluriIconGlyph.favorites, variant: PluriIconVariant.activeGlow, ), label: 'Favoritos', ), NavigationDestination( icon: PluriIcon(glyph: PluriIconGlyph.settings), selectedIcon: PluriIcon( glyph: PluriIconGlyph.settings, variant: PluriIconVariant.activeGlow, ), label: 'Ajustes', ), ]; @override void didChangeDependencies() { super.didChangeDependencies(); final estado = context.read(); if (identical(_estadoSuscrito, estado) && _errorSubscription != null) { return; } _errorSubscription?.cancel(); _estadoSuscrito = estado; _errorSubscription = estado.errorStream.listen((msg) { if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(msg), duration: const Duration(seconds: 3), action: SnackBarAction(label: 'OK', onPressed: () {}), ), ); }); } @override void dispose() { _errorSubscription?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: _indice == 3 ? null // PantallaAjustes tiene su propio AppBar : AppBar( title: const Text('PluriWave'), actions: [ IconButton( icon: const Icon(Icons.bedtime_outlined), tooltip: 'Timer de sueño', onPressed: () => _mostrarTimerDialog(context), ), ], ), body: _paginas[_indice], bottomNavigationBar: Column( mainAxisSize: MainAxisSize.min, children: [ const MiniReproductor(), NavigationBar( selectedIndex: _indice, onDestinationSelected: (i) => setState(() => _indice = i), destinations: _destinos, ), ], ), ); } void _mostrarTimerDialog(BuildContext context) { final estado = context.read(); showModalBottomSheet( context: context, builder: (ctx) => SafeArea( child: Padding( padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Timer de sueño', style: Theme.of(ctx).textTheme.titleLarge, ), const SizedBox(height: 16), if (estado.timer.activo) StreamBuilder( stream: estado.timer.tiempoRestanteStream, builder: (ctx, snap) { final t = snap.data ?? Duration.zero; final h = t.inHours; final m = t.inMinutes .remainder(60) .toString() .padLeft(2, '0'); final s = t.inSeconds .remainder(60) .toString() .padLeft(2, '0'); return Column( children: [ Text( '${h > 0 ? "${h}h " : ""}${m}m ${s}s', style: Theme.of(ctx).textTheme.headlineMedium, ), const SizedBox(height: 8), FilledButton.tonal( onPressed: () { estado.cancelarTimer(); Navigator.pop(ctx); }, child: const Text('Cancelar timer'), ), ], ); }, ) else Wrap( spacing: 8, children: [3, 5, 10, 15, 30, 60, 90, 120, 180] .map( (min) => ActionChip( label: Text('$min min'), onPressed: () { estado.iniciarTimer(min); Navigator.pop(ctx); }, ), ) .toList(), ), ], ), ), ), ); } }