Design: Remplacement du point rouge par une mire vert fluo interne dans le viseur

This commit is contained in:
qguillaume
2026-05-25 02:59:46 +02:00
parent f149fe092b
commit a9ff826246
2 changed files with 104 additions and 93 deletions

View File

@@ -28,7 +28,7 @@ class CropScreen extends StatefulWidget {
class _CropScreenState extends State<CropScreen> {
final ImageCropService _cropService = ImageCropService();
// États de transformation
double _scale = 1.0;
double _baseScale = 1.0;
@@ -82,81 +82,83 @@ class _CropScreenState extends State<CropScreen> {
body: _isLoading
? const Center(child: CircularProgressIndicator(color: Color(0xFF1A73E8)))
: Column(
children: [
// Zone interactive de crop
Expanded(
child: Container(
margin: const EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.white10),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: _imageLoaded ? _buildInteractiveCrop() : const Center(child: CircularProgressIndicator()),
),
),
),
// Bouton d'aide / Modifier
Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// CORRECTION : Icône passée en vert fluo (0xFF00FF00)
const Icon(Icons.center_focus_strong, color: Color(0xFF00FF00), size: 20),
const SizedBox(width: 8),
Text(
'Alignez le centre de la cible sur la croix',
style: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 14, fontWeight: FontWeight.w500),
),
],
),
const SizedBox(height: 4),
Text(
'Zoomez pour plus de précision',
style: TextStyle(color: Colors.white.withOpacity(0.5), fontSize: 12),
),
],
),
),
// Boutons du bas
Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 30),
child: Row(
children: [
// Zone interactive de crop
Expanded(
child: Container(
margin: const EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.white10),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: _imageLoaded ? _buildInteractiveCrop() : const Center(child: CircularProgressIndicator()),
child: OutlinedButton(
onPressed: () => Navigator.pop(context),
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Colors.white24),
padding: const EdgeInsets.symmetric(vertical: 15),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: const Text('Retour', style: TextStyle(color: Colors.white)),
),
),
// Bouton d'aide / Modifier
Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.center_focus_strong, color: Colors.redAccent, size: 20),
const SizedBox(width: 8),
Text(
'Alignez le centre de la cible sur la croix',
style: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 14, fontWeight: FontWeight.w500),
),
],
),
const SizedBox(height: 4),
Text(
'Zoomez pour plus de précision',
style: TextStyle(color: Colors.white.withOpacity(0.5), fontSize: 12),
),
],
),
),
// Boutons du bas
Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 30),
child: Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () => Navigator.pop(context),
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Colors.white24),
padding: const EdgeInsets.symmetric(vertical: 15),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: const Text('Retour', style: TextStyle(color: Colors.white)),
),
),
const SizedBox(width: 16),
Expanded(
child: ElevatedButton(
onPressed: _onCropConfirm,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF1A73E8),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 15),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: const Text('Analyser', style: TextStyle(fontWeight: FontWeight.bold)),
),
),
],
const SizedBox(width: 16),
Expanded(
child: ElevatedButton(
onPressed: _onCropConfirm,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF1A73E8),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 15),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
// CORRECTION : Texte modifié pour correspondre au nouveau flux
child: const Text('Suivant', style: TextStyle(fontWeight: FontWeight.bold)),
),
),
],
),
),
],
),
);
}
@@ -164,7 +166,7 @@ class _CropScreenState extends State<CropScreen> {
return LayoutBuilder(
builder: (context, constraints) {
_viewportSize = Size(constraints.maxWidth, constraints.maxHeight);
// Le carré de crop occupe presque tout l'espace disponible
_cropSize = math.min(constraints.maxWidth, constraints.maxHeight) * 0.95;
@@ -207,7 +209,7 @@ class _CropScreenState extends State<CropScreen> {
void _initializeImagePosition() {
if (_imageSize == null) return;
final imageAspect = _imageSize!.width / _imageSize!.height;
final viewportAspect = _viewportSize.width / _viewportSize.height;
@@ -221,10 +223,10 @@ class _CropScreenState extends State<CropScreen> {
}
final minDisplayDim = math.min(displayWidth, displayHeight);
_scale = widget.initialScale ?? (_cropSize / minDisplayDim);
if (_scale < 1.0 && widget.initialScale == null) _scale = 1.0;
if (widget.initialOffset != null) {
_offset = widget.initialOffset!;
}
@@ -253,6 +255,10 @@ class _CropScreenState extends State<CropScreen> {
final targetCenterY = cropRect.y + cropRect.height / 2;
if (!mounted) return;
// Note : On laisse temporairement AnalysisScreen ici.
// Dès qu'on s'attaque au fichier de calibration, on modifiera cette ligne
// pour basculer directement sur le bon écran !
Navigator.pushReplacement(
context,
MaterialPageRoute(
@@ -277,7 +283,7 @@ class _CropScreenState extends State<CropScreen> {
CropRect _calculateCropRect() {
if (_imageSize == null) return const CropRect(x: 0, y: 0, width: 1, height: 1);
final imageAspect = _imageSize!.width / _imageSize!.height;
final viewportAspect = _viewportSize.width / _viewportSize.height;
@@ -292,13 +298,13 @@ class _CropScreenState extends State<CropScreen> {
final scaledWidth = displayWidth * _scale;
final scaledHeight = displayHeight * _scale;
final imageCenterX = _viewportSize.width / 2 + _offset.dx;
final imageCenterY = _viewportSize.height / 2 + _offset.dy;
final imageLeft = imageCenterX - scaledWidth / 2;
final imageTop = imageCenterY - scaledHeight / 2;
final cropLeft = (_viewportSize.width - _cropSize) / 2;
final cropTop = (_viewportSize.height - _cropSize) / 2;