premier app version beta
This commit is contained in:
246
lib/features/history/session_detail_screen.dart
Normal file
246
lib/features/history/session_detail_screen.dart
Normal file
@@ -0,0 +1,246 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../core/constants/app_constants.dart';
|
||||
import '../../core/theme/app_theme.dart';
|
||||
import '../../data/models/session.dart';
|
||||
import '../../data/repositories/session_repository.dart';
|
||||
import '../../services/score_calculator_service.dart';
|
||||
import '../../services/grouping_analyzer_service.dart';
|
||||
import '../analysis/widgets/target_overlay.dart';
|
||||
import '../analysis/widgets/score_card.dart';
|
||||
import '../analysis/widgets/grouping_stats.dart';
|
||||
import '../statistics/statistics_screen.dart';
|
||||
|
||||
class SessionDetailScreen extends StatelessWidget {
|
||||
final Session session;
|
||||
|
||||
const SessionDetailScreen({
|
||||
super.key,
|
||||
required this.session,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scoreCalculator = context.read<ScoreCalculatorService>();
|
||||
final groupingAnalyzer = context.read<GroupingAnalyzerService>();
|
||||
|
||||
final scoreResult = scoreCalculator.calculateScores(
|
||||
shots: session.shots,
|
||||
targetType: session.targetType,
|
||||
targetCenterX: session.targetCenterX ?? 0.5,
|
||||
targetCenterY: session.targetCenterY ?? 0.5,
|
||||
targetRadius: session.targetRadius ?? 0.4,
|
||||
);
|
||||
|
||||
final groupingResult = groupingAnalyzer.analyzeGrouping(session.shots);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
DateFormat('dd/MM/yyyy HH:mm').format(session.createdAt),
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.analytics),
|
||||
onPressed: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => StatisticsScreen(singleSession: session),
|
||||
),
|
||||
),
|
||||
tooltip: 'Statistiques',
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
onPressed: () => _confirmDelete(context),
|
||||
tooltip: 'Supprimer',
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Target image with overlay
|
||||
AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
if (File(session.imagePath).existsSync())
|
||||
Image.file(
|
||||
File(session.imagePath),
|
||||
fit: BoxFit.contain,
|
||||
)
|
||||
else
|
||||
Container(
|
||||
color: Colors.grey[200],
|
||||
child: const Center(
|
||||
child: Icon(Icons.image_not_supported, size: 64),
|
||||
),
|
||||
),
|
||||
TargetOverlay(
|
||||
shots: session.shots,
|
||||
targetCenterX: session.targetCenterX ?? 0.5,
|
||||
targetCenterY: session.targetCenterY ?? 0.5,
|
||||
targetRadius: session.targetRadius ?? 0.4,
|
||||
targetType: session.targetType,
|
||||
groupingCenterX: session.groupingCenterX,
|
||||
groupingCenterY: session.groupingCenterY,
|
||||
groupingDiameter: session.groupingDiameter,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(AppConstants.defaultPadding),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Session info
|
||||
_buildSessionInfo(context),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Score card
|
||||
ScoreCard(
|
||||
totalScore: session.totalScore,
|
||||
shotCount: session.shotCount,
|
||||
scoreResult: scoreResult,
|
||||
targetType: session.targetType,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Grouping stats
|
||||
if (session.shotCount > 1)
|
||||
GroupingStats(
|
||||
groupingResult: groupingResult,
|
||||
targetCenterX: session.targetCenterX ?? 0.5,
|
||||
targetCenterY: session.targetCenterY ?? 0.5,
|
||||
),
|
||||
|
||||
// Notes
|
||||
if (session.notes != null && session.notes!.isNotEmpty) ...[
|
||||
const SizedBox(height: 12),
|
||||
_buildNotesCard(context),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSessionInfo(BuildContext context) {
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(AppConstants.defaultPadding),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
session.targetType == session.targetType
|
||||
? Icons.track_changes
|
||||
: Icons.person,
|
||||
color: AppTheme.primaryColor,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
session.targetType.displayName,
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
DateFormat('EEEE dd MMMM yyyy, HH:mm', 'fr_FR')
|
||||
.format(session.createdAt),
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildNotesCard(BuildContext context) {
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(AppConstants.defaultPadding),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.notes, color: AppTheme.primaryColor),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Notes',
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(),
|
||||
Text(session.notes!),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _confirmDelete(BuildContext context) async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Supprimer'),
|
||||
content: const Text('Voulez-vous vraiment supprimer cette session?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, false),
|
||||
child: const Text('Annuler'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
child: const Text(
|
||||
'Supprimer',
|
||||
style: TextStyle(color: AppTheme.errorColor),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
if (confirmed == true && context.mounted) {
|
||||
try {
|
||||
final repository = context.read<SessionRepository>();
|
||||
await repository.deleteSession(session.id);
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Session supprimee')),
|
||||
);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Erreur: $e'),
|
||||
backgroundColor: AppTheme.errorColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user