Grapevine_Disease_Detection/VinEye/src/hooks/useDetection.ts
Yanis a3cd906a6d fix(scanner): yield to scheduler before runSync + min skeleton + gallery placeholder
- useDetection.analyze() now awaits a requestAnimationFrame before
  calling runInference. Without it React commits isAnalyzing=true and
  immediately hits the synchronous TFLite runSync that blocks the JS
  thread for 500-1500ms — the analyzing skeleton overlay appears AFTER
  the inference, defeating its purpose.
- Same hook enforces a minimum 600ms total before resolving so a
  cached/fast inference doesn't show a skeleton flicker that reads as
  a glitch.
- ScannerScreen.handleCapture is split: capture stays inline,
  processImage(uri) is now its own async function. Cleaner control
  flow when a take succeeds but analysis is delegated.
- The previously dead "image gallery" icon next to the shutter is now
  a real TouchableOpacity that fires a "coming soon" toast (we'll wire
  it to expo-image-picker once we add the lib + native rebuild).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 14:03:12 +02:00

46 lines
1.5 KiB
TypeScript

import { useState, useCallback } from 'react';
import { runInference } from '@/services/tflite/model';
import type { Detection } from '@/types/detection';
export function useDetection() {
const [isAnalyzing, setIsAnalyzing] = useState(false);
const [lastDetection, setLastDetection] = useState<Detection | null>(null);
const [error, setError] = useState<string | null>(null);
const analyze = useCallback(async (imageUri?: string): Promise<Detection | null> => {
setIsAnalyzing(true);
setError(null);
// Yield au scheduler pour que React commit le render `isAnalyzing=true`
// (le skeleton overlay) AVANT que runSync() ne bloque le JS thread ~500-1500ms.
await new Promise<void>((resolve) =>
requestAnimationFrame(() => resolve()),
);
const startedAt = Date.now();
try {
const detection = await runInference(imageUri);
// UX : maintenir le skeleton visible au moins 600ms pour éviter un flash
// perçu comme un bug ("rien ne se passe") quand l'inférence est très rapide.
const elapsed = Date.now() - startedAt;
if (elapsed < 600) {
await new Promise((r) => setTimeout(r, 600 - elapsed));
}
setLastDetection(detection);
return detection;
} catch (err) {
setError("Erreur lors de l'analyse. Veuillez reessayer.");
return null;
} finally {
setIsAnalyzing(false);
}
}, []);
const reset = useCallback(() => {
setLastDetection(null);
setError(null);
}, []);
return { analyze, isAnalyzing, lastDetection, error, reset };
}