import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../main.dart' show DrawerMenuButton; import '../providers/app_settings_provider.dart'; import '../services/nymea_service.dart'; import '../theme/etm_tokens.dart'; import '../features/dashboard/widgets/energy_flow_card.dart'; import '../features/dashboard/widgets/kpi_row.dart'; import '../features/dashboard/widgets/heos_decision_card.dart'; import '../features/dashboard/widgets/day_plan_card.dart'; class DashboardScreen extends StatefulWidget { const DashboardScreen({super.key}); @override State createState() => _DashboardScreenState(); } class _DashboardScreenState extends State { // Plus d'auto-simulation ici : le gate de routage (Étape 6) garantit qu'on // n'atteint le dashboard qu'avec une session active (box réelle ou démo). // La démo est un choix explicite depuis l'écran Installations. @override Widget build(BuildContext context) { return Consumer( builder: (context, service, _) { final data = service.energyData; return Scaffold( backgroundColor: EtmTokens.bgOf(context), body: RefreshIndicator( onRefresh: () async => service.startSimulation(), color: EtmTokens.ecoOf(context), child: CustomScrollView( slivers: [ _DashTopBar(service: service), SliverPadding( padding: const EdgeInsets.fromLTRB(14, 0, 14, 32), sliver: SliverList( delegate: SliverChildListDelegate([ const SizedBox(height: 14), EnergyFlowCard(data: data), const SizedBox(height: 14), KpiRow(data: data), const SizedBox(height: 14), const HeosDecisionCard(), const SizedBox(height: 14), const DayPlanCard(), const SizedBox(height: 8), ]), ), ), ], ), ), ); }, ); } } // ── TopBar ──────────────────────────────────────────────────────────────────── class _DashTopBar extends StatelessWidget { final NymeaService service; const _DashTopBar({required this.service}); @override Widget build(BuildContext context) { return SliverAppBar( floating: true, snap: true, backgroundColor: EtmTokens.bgOf(context), surfaceTintColor: Colors.transparent, elevation: 0, leading: const DrawerMenuButton(), leadingWidth: 64, title: Text( 'ETM PowerSync', style: EtmTokens.sans( size: 18, weight: FontWeight.w700, color: EtmTokens.inkOf(context), ), ), actions: [ const _ThemeToggle(), const SizedBox(width: 4), IconButton( icon: Icon( service.connected ? Icons.wifi_rounded : Icons.wifi_off_rounded, color: service.connected ? EtmTokens.ecoOf(context) : EtmTokens.danger, size: 20, ), onPressed: () => _showConnectionDialog(context, service), ), const SizedBox(width: 4), ], ); } void _showConnectionDialog(BuildContext context, NymeaService service) { showDialog( context: context, builder: (_) => AlertDialog( title: Text('Connexion nymea', style: EtmTokens.sans(size: 18, weight: FontWeight.w600, color: EtmTokens.inkOf(context))), content: Text( service.connected ? 'Connecté à ${service.host}' : service.isSimulation ? 'Mode simulation actif' : 'Non connecté', style: EtmTokens.sans(size: 14, color: EtmTokens.mutedOf(context)), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('OK', style: EtmTokens.sans(color: EtmTokens.ecoOf(context))), ), ], ), ); } } // ── Theme toggle ────────────────────────────────────────────────────────────── class _ThemeToggle extends StatelessWidget { const _ThemeToggle(); @override Widget build(BuildContext context) { final settings = context.watch(); final isDark = settings.themeMode == ThemeMode.dark; return GestureDetector( onTap: () => settings.setThemeMode( isDark ? ThemeMode.light : ThemeMode.dark, ), child: Container( width: 50, height: 28, margin: const EdgeInsets.symmetric(vertical: 8), decoration: BoxDecoration( color: isDark ? EtmTokens.brand.withValues(alpha: 0.2) : EtmTokens.bg2Of(context), borderRadius: BorderRadius.circular(14), border: Border.all( color: EtmTokens.lineOf(context), width: 1, ), ), child: Stack( children: [ AnimatedPositioned( duration: const Duration(milliseconds: 280), curve: Curves.easeOutBack, left: isDark ? 24 : 2, top: 2, child: Container( width: 22, height: 22, decoration: BoxDecoration( color: isDark ? EtmTokens.brand : Colors.white, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.12), blurRadius: 4, ), ], ), child: Icon( isDark ? Icons.dark_mode_rounded : Icons.light_mode_rounded, size: 13, color: isDark ? Colors.white : EtmTokens.amber, ), ), ), ], ), ), ); } }