refactor: reglages de calibration au-dessus de la photo + boutons de taille fonctionnels

This commit is contained in:
qlionbleusam
2026-08-04 15:57:10 +02:00
parent 6130e63cfb
commit a4dc26fda8
3 changed files with 258 additions and 201 deletions
+126 -15
View File
@@ -110,6 +110,9 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
bool _isCalibrating = true;
bool _isAtBottom = false;
// Affichage du réglage manuel de l'espacement des anneaux.
bool _showSpacing = false;
final ScrollController _scrollController = ScrollController();
final GlobalKey _imageKey = GlobalKey();
@@ -143,7 +146,12 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
/// La cible du mode Plotting est désormais un élément fixe (aucun zoom à
/// réinitialiser) : on se contente donc de rebasculer l'état.
void _enterCalibration() {
setState(() => _isCalibrating = true);
setState(() {
_isCalibrating = true;
// La calibration est reconstruite à neuf (espacement manuel désactivé) :
// on aligne l'état du panneau pour ne pas afficher un mode inactif.
_showSpacing = false;
});
}
/// Ouvre l'éditeur d'impacts (plein écran) en PARTAGEANT le provider courant.
@@ -182,6 +190,113 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
return widget.originalImagePath ?? provider.imagePath!;
}
/// Panneau de réglages de la calibration (taille + espacement).
///
/// Rendu AU-DESSUS de l'image (et non plus en surimpression) pour ne pas
/// masquer la cible. Les valeurs affichées viennent du provider ; les
/// modifications sont poussées dans l'état de [TargetCalibration] via sa clé.
Widget _buildCalibrationSettings(AnalysisProvider provider) {
final radius = provider.targetRadius.clamp(
TargetCalibrationState.minRadius,
TargetCalibrationState.maxRadius,
);
final spacing =
(provider.targetRadius > 0
? provider.targetInnerRadius / provider.targetRadius
: 0.1)
.clamp(
TargetCalibrationState.minSpacing,
TargetCalibrationState.maxSpacing,
);
return Padding(
padding: const EdgeInsets.fromLTRB(12, 0, 12, 4),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 36,
child: Row(
children: [
const Text(
'Taille',
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
),
const SizedBox(width: 4),
const Icon(Icons.zoom_out, size: 16),
Expanded(
child: Slider(
value: radius,
min: TargetCalibrationState.minRadius,
max: TargetCalibrationState.maxRadius,
activeColor: AppTheme.primaryColor,
onChanged: (value) =>
_calibrationKey.currentState?.setRadius(value),
),
),
const Icon(Icons.zoom_in, size: 16),
],
),
),
SizedBox(
height: 32,
child: Row(
children: [
const Expanded(
child: Text(
'Options d\'espacement avancées',
style: TextStyle(fontSize: 11, fontWeight: FontWeight.w500),
),
),
Switch(
value: _showSpacing,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
onChanged: (value) {
setState(() => _showSpacing = value);
_calibrationKey.currentState?.setSpacingMode(value);
},
),
],
),
),
if (_showSpacing)
SizedBox(
height: 36,
child: Row(
children: [
const Text(
'Espacement',
style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
),
const SizedBox(width: 4),
const Icon(Icons.compress, size: 16),
Expanded(
child: Slider(
value: spacing,
min: TargetCalibrationState.minSpacing,
max: TargetCalibrationState.maxSpacing,
activeColor: Colors.orange,
onChanged: (value) =>
_calibrationKey.currentState?.setSpacingRatio(value),
),
),
const Icon(Icons.expand, size: 16),
IconButton(
icon: const Icon(Icons.refresh, size: 20),
tooltip: 'Réinitialiser l\'espacement',
constraints: const BoxConstraints(),
padding: const EdgeInsets.symmetric(horizontal: 8),
onPressed: () =>
_calibrationKey.currentState?.resetSpacing(),
),
],
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
final provider = context.watch<AnalysisProvider>();
@@ -230,21 +345,17 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
controller: _scrollController,
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(AppConstants.defaultPadding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (provider.state == AnalysisState.loading)
const Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: CircularProgressIndicator(),
),
),
],
// Plus de bloc vide au-dessus de l'image : l'indicateur n'occupe
// de la place que pendant le chargement.
if (provider.state == AnalysisState.loading)
const Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Center(child: CircularProgressIndicator()),
),
),
// Réglages de calibration : au-dessus de la photo pour ne rien
// masquer de la cible.
if (_isCalibrating) _buildCalibrationSettings(provider),
AspectRatio(
aspectRatio: provider.imageAspectRatio,