Files
impact/lib/features/analysis/widgets/score_card.dart
2026-01-18 13:38:09 +01:00

168 lines
4.8 KiB
Dart

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]!;
}
}