fix: reeduction temps prise photo et enleve confusion photo en cours de traitement

This commit is contained in:
qguillaume
2026-06-12 11:17:16 +02:00
parent 4e26431be5
commit 5d2e612b9c

View File

@@ -47,6 +47,11 @@ class _CaptureScreenState extends State<CaptureScreen>
String? _selectedImagePath;
bool _isLoading = false;
bool _isCapturing = false; // garde anti-double-capture pendant le traitement
// Chemin de la photo tout juste capturée, affichée FIGÉE pendant le
// traitement (downscale). Tant qu'il est null, la capture physique est
// encore en cours → l'utilisateur doit rester immobile. Une fois rempli,
// la photo est prise et l'utilisateur peut bouger.
String? _capturedPreviewPath;
// Caméra live
CameraController? _cameraController;
@@ -190,9 +195,15 @@ class _CaptureScreenState extends State<CaptureScreen>
_cameras = await availableCameras();
if (_cameras != null && _cameras!.isNotEmpty) {
// PERF : on capture en `veryHigh` (2160p) et non en `max`. Le pipeline
// redimensionne ensuite tout à 1080 px max → la résolution `max`
// (1248 MP) ne servait à rien et rallongeait fortement le décodage
// post-capture (« délai de quelques secondes »). `veryHigh` reste très
// au-dessus du 1080 px final : aucune perte de qualité, mais décodage
// bien plus rapide.
_cameraController = CameraController(
_cameras![0],
ResolutionPreset.max,
ResolutionPreset.veryHigh,
enableAudio: false,
imageFormatGroup: ImageFormatGroup.jpeg,
);
@@ -614,11 +625,32 @@ class _CaptureScreenState extends State<CaptureScreen>
// 6. Overlay bloquant pendant la capture/traitement : empêche de
// bouger l'UI ou de relancer une capture tant que la photo n'est pas
// chargée (absorbe tous les gestes + voile + indicateur).
// chargée (absorbe tous les gestes). Deux phases distinctes pour
// lever la confusion « puis-je bouger ? » :
// • _capturedPreviewPath == null → capture physique en cours :
// voile sur l'aperçu vivant + « Ne bougez pas ».
// • _capturedPreviewPath != null → photo prise, traitement en
// cours : on affiche l'image FIGÉE (le flux vivant disparaît)
// + « Photo prise ✓ — vous pouvez bouger ».
if (_isCapturing)
Positioned.fill(
child: AbsorbPointer(
child: Container(
child: _capturedPreviewPath == null
? _buildCapturingOverlay()
: _buildProcessingOverlay(_capturedPreviewPath!),
),
),
],
),
);
}
// ─────────────────────────────────────────────────────────────────────────
// Overlay PHASE 1 : capture physique en cours → l'utilisateur doit rester
// immobile. Voile semi-transparent par-dessus l'aperçu vivant.
// ─────────────────────────────────────────────────────────────────────────
Widget _buildCapturingOverlay() {
return Container(
color: Colors.black.withValues(alpha: 0.45),
child: const Center(
child: Column(
@@ -627,21 +659,75 @@ class _CaptureScreenState extends State<CaptureScreen>
CircularProgressIndicator(color: Colors.white),
SizedBox(height: 16),
Text(
'Photo en cours',
'NE BOUGEZ PAS — CAPTURE',
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w600,
fontWeight: FontWeight.w700,
letterSpacing: 1.2,
),
),
],
),
),
);
}
// ─────────────────────────────────────────────────────────────────────────
// Overlay PHASE 2 : photo capturée, traitement en cours. On affiche l'image
// FIGÉE (l'aperçu vivant disparaît, plus d'ambiguïté) et on indique
// clairement que l'utilisateur peut maintenant bouger.
// ─────────────────────────────────────────────────────────────────────────
Widget _buildProcessingOverlay(String imagePath) {
return Stack(
fit: StackFit.expand,
children: [
// Image figée de la photo prise → recouvre totalement le flux caméra
Image.file(File(imagePath), fit: BoxFit.cover),
Container(
color: Colors.black.withValues(alpha: 0.55),
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.check_circle,
color: Color(0xFF00FF00),
size: 52,
),
const SizedBox(height: 14),
const Text(
'PHOTO PRISE',
style: TextStyle(
color: Color(0xFF00FF00),
fontSize: 16,
fontWeight: FontWeight.w700,
letterSpacing: 1.2,
),
),
const SizedBox(height: 20),
const SizedBox(
width: 22,
height: 22,
child: CircularProgressIndicator(
color: Colors.white,
strokeWidth: 2.5,
),
),
const SizedBox(height: 14),
Text(
'Traitement… vous pouvez bouger',
style: TextStyle(
color: Colors.white.withValues(alpha: 0.85),
fontSize: 13,
fontWeight: FontWeight.w500,
),
),
],
),
),
),
),
),
],
),
);
}
@@ -761,6 +847,7 @@ class _CaptureScreenState extends State<CaptureScreen>
setState(() {
_isCapturing = true;
_isLoading = true;
_capturedPreviewPath = null; // phase « capture en cours »
});
try {
// On stoppe le flux d'analyse (obligatoire avant takePicture) puis on
@@ -772,6 +859,14 @@ class _CaptureScreenState extends State<CaptureScreen>
final XFile photo = await _cameraController!.takePicture();
// La photo est PHYSIQUEMENT capturée : on gèle l'aperçu en affichant
// l'image prise (le flux caméra « vivant » disparaît) et on bascule le
// message sur « vous pouvez bouger ». Tout ce qui suit n'est que du
// traitement et n'exige plus l'immobilité de l'utilisateur.
if (mounted) {
setState(() => _capturedPreviewPath = photo.path);
}
// Pas de redressement perspective automatique ici : il déformait l'image
// (écrasement en carré + rotation de l'axe de l'ellipse) et gelait le
// thread UI. Le recentrage ET la rotation se font manuellement à l'écran
@@ -801,6 +896,7 @@ class _CaptureScreenState extends State<CaptureScreen>
setState(() {
_isLoading = false;
_isCapturing = false;
_capturedPreviewPath = null;
});
}
}