import 'package:flutter/material.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:geosector_app/core/data/models/passage_model.dart'; import 'package:geosector_app/core/data/models/sector_model.dart'; import 'package:geosector_app/core/constants/app_keys.dart'; import 'package:geosector_app/core/theme/app_theme.dart'; class SectorDistributionCard extends StatelessWidget { final String title; final double? height; final EdgeInsetsGeometry? padding; const SectorDistributionCard({ super.key, this.title = 'Répartition par secteur', this.height, this.padding, }); @override Widget build(BuildContext context) { return Container( height: height, padding: padding ?? const EdgeInsets.all(AppTheme.spacingM), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(AppTheme.borderRadiusMedium), boxShadow: AppTheme.cardShadow, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), const SizedBox(height: AppTheme.spacingM), Expanded( child: _buildAutoRefreshContent(), ), ], ), ); } Widget _buildAutoRefreshContent() { // Écouter les changements des deux boîtes return ValueListenableBuilder( valueListenable: Hive.box(AppKeys.sectorsBoxName).listenable(), builder: (context, Box sectorsBox, child) { return ValueListenableBuilder( valueListenable: Hive.box(AppKeys.passagesBoxName).listenable(), builder: (context, Box passagesBox, child) { return _buildContent(sectorsBox, passagesBox); }, ); }, ); } Widget _buildContent( Box sectorsBox, Box passagesBox) { try { // Calculer les statistiques final sectorStats = _calculateSectorStats(sectorsBox, passagesBox); if (sectorStats.isEmpty) { return const Center( child: Text('Aucune donnée de secteur disponible'), ); } return ListView.builder( itemCount: sectorStats.length, itemBuilder: (context, index) { final sector = sectorStats[index]; return _buildSectorItem( sector['name'], sector['count'], Color(sector['color']), sectorStats, ); }, ); } catch (e) { debugPrint('Erreur lors du calcul des statistiques: $e'); return Center( child: Text('Erreur: ${e.toString()}'), ); } } List> _calculateSectorStats( Box sectorsBox, Box passagesBox, ) { // Récupérer tous les secteurs et passages final List sectors = sectorsBox.values.toList(); final List passages = passagesBox.values.toList(); // Compter les passages par secteur (en excluant ceux où fkType==2) final Map sectorCounts = {}; for (final passage in passages) { // Exclure les passages où fkType==2 et ceux sans secteur if (passage.fkType != 2 && passage.fkSector != null) { sectorCounts[passage.fkSector!] = (sectorCounts[passage.fkSector!] ?? 0) + 1; } } // Préparer les données pour l'affichage List> stats = []; for (final sector in sectors) { final count = sectorCounts[sector.id] ?? 0; if (count > 0) { stats.add({ 'name': sector.libelle, 'count': count, 'color': sector.color.isEmpty ? 0xFF4B77BE : int.tryParse(sector.color.replaceAll('#', '0xFF')) ?? 0xFF4B77BE, }); } } // Trier par nombre de passages (décroissant) stats.sort((a, b) => (b['count'] as int).compareTo(a['count'] as int)); return stats; } Widget _buildSectorItem( String name, int count, Color color, List> allStats, ) { final totalCount = allStats.fold(0, (sum, item) => sum + (item['count'] as int)); final percentage = totalCount > 0 ? (count / totalCount) * 100 : 0; return Padding( padding: const EdgeInsets.only(bottom: AppTheme.spacingS), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( name, style: const TextStyle(fontSize: 14), overflow: TextOverflow.ellipsis, ), ), Text( '$count (${percentage.toInt()}%)', style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 14, ), ), ], ), const SizedBox(height: 4), LinearProgressIndicator( value: percentage / 100, backgroundColor: Colors.grey[200], valueColor: AlwaysStoppedAnimation(color), minHeight: 8, borderRadius: BorderRadius.circular(4), ), ], ), ); } }