Files
impact/lib/features/home/home_screen.dart
2026-05-08 08:34:16 +02:00

327 lines
9.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../core/constants/app_constants.dart';
import '../../core/theme/app_theme.dart';
import '../../data/repositories/session_repository.dart';
import '../capture/capture_screen.dart';
import '../history/history_screen.dart';
import '../statistics/statistics_screen.dart';
import 'package:fl_chart/fl_chart.dart';
import '../../data/models/session.dart';
import '../settings/settings_screen.dart';
import 'widgets/stats_card.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
Map<String, dynamic>? _stats;
List<Session> _recentSessions = [];
bool _isLoading = true;
@override
void initState() {
super.initState();
_loadStats();
}
Future<void> _loadStats() async {
final repository = context.read<SessionRepository>();
final stats = await repository.getStatistics();
final sessions = await repository.getAllSessions();
if (mounted) {
setState(() {
_stats = stats;
_recentSessions = sessions;
_isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// --- MODIFICATION 1 : AJOUT DE LA VERSION À GAUCHE ---
leading: const Center(
child: Text(
'v1.0.2',
style: TextStyle(fontSize: 12, color: Colors.white70),
),
),
title: const Text('Bully'),
actions: [
IconButton(
icon: const Icon(Icons.analytics),
onPressed: () => _navigateToStatistics(context),
tooltip: 'Statistiques',
),
IconButton(
icon: const Icon(Icons.history),
onPressed: () => _navigateToHistory(context),
tooltip: 'Historique',
),
IconButton(
icon: const Icon(Icons.settings),
onPressed: () => _navigateToSettings(context),
tooltip: 'Paramètres',
),
],
),
body: RefreshIndicator(
onRefresh: _loadStats,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.all(AppConstants.defaultPadding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// App logo/header
_buildHeader(),
const SizedBox(height: AppConstants.largePadding),
// Main action button
_buildMainActionButton(context),
const SizedBox(height: AppConstants.largePadding),
// Statistics section
if (_isLoading)
const Center(child: CircularProgressIndicator())
else if (_stats != null)
_buildStatsSection(),
],
),
),
),
);
}
Widget _buildHeader() {
return Column(
children: [
Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: AppTheme.primaryColor.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.track_changes,
size: 64,
color: AppTheme.primaryColor,
),
),
const SizedBox(height: 16),
Text(
'Analyse de Cibles',
style: Theme.of(
context,
).textTheme.headlineMedium?.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
'Scannez vos cibles et analysez vos performances',
style: Theme.of(
context,
).textTheme.bodyLarge?.copyWith(color: AppTheme.textSecondary),
textAlign: TextAlign.center,
),
],
);
}
Widget _buildMainActionButton(BuildContext context) {
return ElevatedButton.icon(
onPressed: () => _navigateToCapture(context),
style: ElevatedButton.styleFrom(
backgroundColor: AppTheme.primaryColor,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 20),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppConstants.borderRadius),
),
),
icon: const Icon(Icons.add_a_photo, size: 28),
label: const Text(
'Nouvelle Analyse',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
);
}
Widget _buildStatsSection() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Statistiques',
style: Theme.of(
context,
).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
// Première ligne de vignettes (Sessions et Tirs)
Row(
children: [
Expanded(
child: InkWell(
onTap: () => _navigateToStatistics(context),
borderRadius: BorderRadius.circular(AppConstants.borderRadius),
child: StatsCard(
icon: Icons.assessment,
title: 'Sessions',
value: '${_stats!['totalSessions']}',
color: AppTheme.primaryColor,
),
),
),
const SizedBox(width: 12),
Expanded(
child: StatsCard(
icon: Icons.gps_fixed,
title: 'Tirs',
value: '${_stats!['totalShots']}',
color: AppTheme.secondaryColor,
),
),
],
),
// --- MODIFICATION 2 : GRAPHIQUE RÉEL (Restauré) ---
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Container(
height: 150,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(AppConstants.borderRadius),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: _recentSessions.length < 2
? const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.show_chart, size: 40, color: Colors.grey),
Text(
'Pas assez de données',
style: TextStyle(color: Colors.grey, fontSize: 12),
),
],
),
)
: _buildHomeTrendChart(),
),
),
// Deuxième ligne de vignettes (Historique et Meilleur)
Row(
children: [
Expanded(
child: InkWell(
onTap: () => _navigateToHistory(context),
borderRadius: BorderRadius.circular(AppConstants.borderRadius),
child: StatsCard(
icon: Icons.trending_up,
title: 'Historique',
value: (_stats!['averageScore'] as double).toStringAsFixed(1),
color: AppTheme.warningColor,
),
),
),
const SizedBox(width: 12),
Expanded(
child: StatsCard(
icon: Icons.emoji_events,
title: 'Meilleur',
value: '${_stats!['bestScore']}',
color: AppTheme.successColor,
),
),
],
),
],
);
}
// --- MÉTHODES DE NAVIGATION ---
void _navigateToCapture(BuildContext context) async {
await Navigator.push(
context,
MaterialPageRoute(builder: (_) => const CaptureScreen()),
);
_loadStats();
}
void _navigateToHistory(BuildContext context) async {
await Navigator.push(
context,
MaterialPageRoute(builder: (_) => const HistoryScreen()),
);
_loadStats();
}
void _navigateToStatistics(BuildContext context) async {
await Navigator.push(
context,
MaterialPageRoute(builder: (_) => const StatisticsScreen()),
);
_loadStats();
}
// --- WIDGET DU GRAPHIQUE D'ACCUEIL ---
Widget _buildHomeTrendChart() {
// Trier par date et prendre les 7 dernières
final sorted = List<Session>.from(_recentSessions)
..sort((a, b) => a.createdAt.compareTo(b.createdAt));
final display =
sorted.length > 7 ? sorted.sublist(sorted.length - 7) : sorted;
return LineChart(
LineChartData(
gridData: const FlGridData(show: false),
titlesData: const FlTitlesData(show: false),
borderData: FlBorderData(show: false),
lineBarsData: [
LineChartBarData(
spots: display.asMap().entries.map((e) {
return FlSpot(e.key.toDouble(), e.value.totalScore.toDouble());
}).toList(),
isCurved: true,
color: AppTheme.primaryColor,
barWidth: 4,
isStrokeCapRound: true,
dotData: const FlDotData(show: false),
belowBarData: BarAreaData(
show: true,
color: AppTheme.primaryColor.withOpacity(0.1),
),
),
],
),
);
}
void _navigateToSettings(BuildContext context) {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const SettingsScreen()),
);
}
}