fix: reeduction temps prise photo et enleve confusion photo en cours de traitement
This commit is contained in:
@@ -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`
|
||||
// (12–48 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user