feat: tap simple toujours createur d'impact + ecran de plotting renomme Synthese
This commit is contained in:
@@ -1,85 +0,0 @@
|
||||
/// Bottom sheet de détails d'un impact : modification du score et suppression.
|
||||
///
|
||||
/// Partagée entre l'écran d'analyse (consultation du plotting) et l'éditeur
|
||||
/// d'impacts plein écran, qui opèrent sur le même AnalysisProvider.
|
||||
library;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../data/models/shot.dart';
|
||||
import '../analysis_provider.dart';
|
||||
|
||||
void showShotDetailsSheet(
|
||||
BuildContext context,
|
||||
AnalysisProvider provider,
|
||||
Shot shot,
|
||||
) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => Container(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'Impact #${provider.shots.indexOf(shot) + 1}',
|
||||
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
|
||||
),
|
||||
Text(
|
||||
'ID: ${shot.id}',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall
|
||||
?.copyWith(color: Colors.grey, fontSize: 10),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.score),
|
||||
title: const Text('Modifier le score'),
|
||||
trailing: DropdownButton<int>(
|
||||
value: shot.score.clamp(0, 10),
|
||||
items: List.generate(11, (index) => index)
|
||||
.map(
|
||||
(s) => DropdownMenuItem(
|
||||
value: s,
|
||||
child: Text(
|
||||
'$s',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (newScore) {
|
||||
if (newScore != null) {
|
||||
provider.updateShotScore(shot.id, newScore);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: () {
|
||||
provider.removeShot(shot.id);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
icon: const Icon(Icons.delete, color: Colors.red),
|
||||
label: const Text(
|
||||
'SUPPRIMER',
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -53,7 +53,10 @@ class TargetOverlay extends StatelessWidget {
|
||||
// Désormais :
|
||||
// - L'AJOUT d'impact est géré par le GestureDetector parent (analysis_screen).
|
||||
// - Seule la SÉLECTION d'un impact existant est gérée ici, via des petites
|
||||
// zones de tap localisées (deferToChild) placées sur chaque impact.
|
||||
// zones de tap localisées (deferToChild) placées sur chaque impact —
|
||||
// et UNIQUEMENT si [onShotTapped] est fourni. Sans callback, aucune zone
|
||||
// de tap n'est créée : un tap pile sur un impact traverse jusqu'au parent
|
||||
// au lieu d'être absorbé dans le vide.
|
||||
return IgnorePointer(
|
||||
ignoring: false,
|
||||
child: CustomPaint(
|
||||
@@ -73,6 +76,8 @@ class TargetOverlay extends StatelessWidget {
|
||||
),
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final onTapped = onShotTapped;
|
||||
if (onTapped == null) return const SizedBox.expand();
|
||||
return Stack(
|
||||
children: shots.map((shot) {
|
||||
final x = shot.x * constraints.maxWidth;
|
||||
@@ -89,7 +94,7 @@ class TargetOverlay extends StatelessWidget {
|
||||
// Le reste de la surface reste donc disponible pour le
|
||||
// pinch/pan de l'InteractiveViewer.
|
||||
behavior: HitTestBehavior.deferToChild,
|
||||
onTap: () => onShotTapped?.call(shot),
|
||||
onTap: () => onTapped(shot),
|
||||
child: Container(
|
||||
width: tapSize,
|
||||
height: tapSize,
|
||||
|
||||
Reference in New Issue
Block a user