/// Carte d'affichage des scores. /// /// Affiche le score total, le nombre d'impacts, la moyenne et le pourcentage. /// Inclut la distribution des scores par valeur (1-10 pour cibles concentriques). library; import 'package:flutter/material.dart'; import '../../../core/constants/app_constants.dart'; import '../../../core/theme/app_theme.dart'; import '../../../data/models/target_type.dart'; import '../../../services/score_calculator_service.dart'; class ScoreCard extends StatelessWidget { final int totalScore; final int shotCount; final ScoreResult? scoreResult; final TargetType targetType; const ScoreCard({ super.key, required this.totalScore, required this.shotCount, this.scoreResult, required this.targetType, }); @override Widget build(BuildContext context) { final maxScore = targetType == TargetType.concentric ? 10 : 5; return Card( child: Padding( padding: const EdgeInsets.all(AppConstants.defaultPadding), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.scoreboard, color: AppTheme.primaryColor), const SizedBox(width: 8), Text( 'Score', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), ], ), const Divider(), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _buildScoreStat( context, 'Total', '$totalScore', subtitle: '/ ${shotCount * maxScore}', ), _buildScoreStat( context, 'Impacts', '$shotCount', ), _buildScoreStat( context, 'Moyenne', shotCount > 0 ? (totalScore / shotCount).toStringAsFixed(1) : '-', ), if (scoreResult != null) _buildScoreStat( context, 'Pourcentage', '${scoreResult!.percentage.toStringAsFixed(0)}%', ), ], ), if (scoreResult != null && scoreResult!.scoreDistribution.isNotEmpty) ...[ const SizedBox(height: 12), const Divider(), const SizedBox(height: 8), Text( 'Distribution des scores', style: Theme.of(context).textTheme.bodySmall?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), _buildScoreDistribution(context), ], ], ), ), ); } Widget _buildScoreStat( BuildContext context, String label, String value, { String? subtitle, }) { return Column( children: [ Text( value, style: Theme.of(context).textTheme.headlineSmall?.copyWith( fontWeight: FontWeight.bold, color: AppTheme.primaryColor, ), ), if (subtitle != null) Text( subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Colors.grey, ), ), Text( label, style: Theme.of(context).textTheme.bodySmall, ), ], ); } Widget _buildScoreDistribution(BuildContext context) { final maxScoreValue = targetType == TargetType.concentric ? 10 : 5; final distribution = scoreResult!.scoreDistribution; return Wrap( spacing: 8, runSpacing: 4, children: List.generate(maxScoreValue + 1, (index) { final score = maxScoreValue - index; final count = distribution[score] ?? 0; if (count == 0) return const SizedBox.shrink(); return Chip( label: Text( 'x$count', style: const TextStyle(fontSize: 12), ), avatar: CircleAvatar( radius: 12, backgroundColor: _getScoreColor(score, maxScoreValue), child: Text( '$score', style: const TextStyle( fontSize: 10, color: Colors.white, fontWeight: FontWeight.bold, ), ), ), visualDensity: VisualDensity.compact, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ); }), ); } Color _getScoreColor(int score, int maxScore) { if (score == maxScore) return Colors.amber; if (score >= maxScore * 0.8) return Colors.orange; if (score >= maxScore * 0.6) return Colors.blue; if (score >= maxScore * 0.4) return Colors.green; if (score >= maxScore * 0.2) return Colors.grey; return Colors.grey[400]!; } }