feat: tap simple toujours createur d'impact + ecran de plotting renomme Synthese
This commit is contained in:
@@ -7,8 +7,11 @@
|
||||
/// scroll vertical ou une transformation parente.
|
||||
///
|
||||
/// Interactions :
|
||||
/// - Tap sur zone vide -> ajoute un impact
|
||||
/// - Tap sur un impact -> ouvre l'édition (score / suppression)
|
||||
/// - Tap -> ajoute TOUJOURS un impact, même juste à côté
|
||||
/// (ou par-dessus) un impact existant. Aucun tap
|
||||
/// n'ouvre d'édition de score : on peut donc
|
||||
/// placer un impact au pouce près sans être
|
||||
/// interrompu par une popup.
|
||||
/// - Appui long + glisser -> déplace l'impact
|
||||
///
|
||||
/// L'état des impacts est partagé avec l'écran d'analyse via le MÊME
|
||||
@@ -24,7 +27,6 @@ import '../../core/theme/app_theme.dart';
|
||||
import '../../data/models/shot.dart';
|
||||
import 'analysis_provider.dart';
|
||||
import 'widgets/target_overlay.dart';
|
||||
import 'widgets/shot_details_sheet.dart';
|
||||
|
||||
class ImpactEditorScreen extends StatefulWidget {
|
||||
const ImpactEditorScreen({super.key});
|
||||
@@ -73,8 +75,11 @@ class _ImpactEditorScreenState extends State<ImpactEditorScreen> {
|
||||
}
|
||||
|
||||
/// Renvoie l'impact le plus proche de [rel] dans la tolérance, sinon null.
|
||||
///
|
||||
/// Utilisé uniquement par l'appui long (déplacement) : le tap simple, lui,
|
||||
/// ajoute toujours un impact sans chercher à en sélectionner un.
|
||||
Shot? _hitTestShot(AnalysisProvider provider, Offset rel,
|
||||
{double tolerance = 0.04}) {
|
||||
{double tolerance = 0.06}) {
|
||||
Shot? closest;
|
||||
double minDistance = double.infinity;
|
||||
for (final shot in provider.shots) {
|
||||
@@ -100,7 +105,7 @@ class _ImpactEditorScreenState extends State<ImpactEditorScreen> {
|
||||
title: Text('Placement des impacts (${provider.shotCount})'),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
tooltip: 'Retour au plotting',
|
||||
tooltip: 'Retour à la synthèse',
|
||||
onPressed: () => Navigator.pop(context, false),
|
||||
),
|
||||
),
|
||||
@@ -134,7 +139,7 @@ class _ImpactEditorScreenState extends State<ImpactEditorScreen> {
|
||||
color: Colors.white10,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: const Text(
|
||||
'Tap : ajouter • Tap sur impact : éditer • Appui long : déplacer • Pincer : zoomer',
|
||||
'Tap : ajouter un impact • Appui long : déplacer • Pincer : zoomer',
|
||||
style: TextStyle(color: Colors.white70, fontSize: 12),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -151,24 +156,20 @@ class _ImpactEditorScreenState extends State<ImpactEditorScreen> {
|
||||
child: Center(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
// TAP : éditer si on touche un impact, sinon ajouter.
|
||||
// TAP : ajoute un impact, sans exception. Même collé à un
|
||||
// impact existant, le tap crée le nouvel impact au lieu
|
||||
// d'ouvrir l'édition du score.
|
||||
onTapUp: (details) {
|
||||
if (_movingShotId != null) return;
|
||||
final rel = _toImageRelative(details.globalPosition);
|
||||
if (rel == null) return;
|
||||
|
||||
final hit = _hitTestShot(provider, rel);
|
||||
if (hit != null) {
|
||||
showShotDetailsSheet(context, provider, hit);
|
||||
} else {
|
||||
provider.addShot(rel.dx, rel.dy);
|
||||
}
|
||||
provider.addShot(rel.dx, rel.dy);
|
||||
},
|
||||
// APPUI LONG : on saisit l'impact le plus proche pour le déplacer.
|
||||
onLongPressStart: (details) {
|
||||
final rel = _toImageRelative(details.globalPosition);
|
||||
if (rel == null) return;
|
||||
final hit = _hitTestShot(provider, rel, tolerance: 0.06);
|
||||
final hit = _hitTestShot(provider, rel);
|
||||
if (hit != null) {
|
||||
setState(() => _movingShotId = hit.id);
|
||||
}
|
||||
@@ -204,10 +205,10 @@ class _ImpactEditorScreenState extends State<ImpactEditorScreen> {
|
||||
shots: provider.shots,
|
||||
showRings: true,
|
||||
zoomScale: _currentZoomScale,
|
||||
// L'ajout et la sélection sont gérés par le
|
||||
// GestureDetector parent ci-dessus.
|
||||
onShotTapped: (shot) =>
|
||||
showShotDetailsSheet(context, provider, shot),
|
||||
// Aucun onShotTapped : les impacts ne captent plus le
|
||||
// toucher, tout va au GestureDetector parent qui
|
||||
// ajoute un impact (y compris pile sur un impact
|
||||
// existant).
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user