diff --git a/src/screens/CameraScreen.tsx b/src/screens/CameraScreen.tsx index 7f908a87..e2cc9504 100644 --- a/src/screens/CameraScreen.tsx +++ b/src/screens/CameraScreen.tsx @@ -92,6 +92,7 @@ export default function CameraScreen({ const usbCameraRef = useRef(null); const expoCameraRef = useRef(null); const burstTimerRef = useRef(null); + const isCancelledRef = useRef(false); // Reanimated countdown pulse animation const scale = useSharedValue(1); @@ -195,6 +196,7 @@ export default function CameraScreen({ // Cancel capture process const handleLocalCancel = async () => { + isCancelledRef.current = true; if (burstTimerRef.current) clearTimeout(burstTimerRef.current); // Clean up any temp files from a partially completed burst @@ -208,6 +210,8 @@ export default function CameraScreen({ setCountdown(countdownDuration); setIsCapturing(false); + setIsBurstWaiting(false); + setHasStarted(false); setBurstIndex(0); setBurstUris([]); setShowBurstIndicator(''); @@ -229,6 +233,7 @@ export default function CameraScreen({ }, [countdownDuration, isIdle]); const startCountdown = () => { + isCancelledRef.current = false; let timer: any; let count = countdownDuration; @@ -281,7 +286,7 @@ export default function CameraScreen({ if (expoCameraRef.current) { const photo = await expoCameraRef.current.takePictureAsync({ quality: 0.7, // Lower quality slightly to reduce file size - skipProcessing: false, // Ensure correct orientation + skipProcessing: Platform.OS === 'android', // Prevent memory crash on Android }); capturedUri = photo.uri; } else { @@ -289,6 +294,12 @@ export default function CameraScreen({ } } + // If user cancelled while the camera promise was processing, abort before side-effects + if (isCancelledRef.current) { + console.log('Capture cancelled by user during processing.'); + return; + } + // Instead of manipulating the image and risking an OOM or BitmapFactory crash, // we directly use the captured photo and rely on React Native's Image component // to safely downsample it during rendering via resizeMethod="resize". diff --git a/src/screens/PreviewScreen.tsx b/src/screens/PreviewScreen.tsx index c5be4bcb..c6553161 100644 --- a/src/screens/PreviewScreen.tsx +++ b/src/screens/PreviewScreen.tsx @@ -204,6 +204,7 @@ export default function PreviewScreen({ // Triggers the view capture and the print job const handlePrint = async () => { + if (isProcessing) return; setIsProcessing(true); setStatusMessage('Dein Foto wird vorbereitet...'); try { @@ -233,6 +234,7 @@ export default function PreviewScreen({ // Saves to gallery without printing const handleSaveOnly = async () => { + if (isProcessing) return; setIsProcessing(true); setStatusMessage('Bild wird generiert...'); try { @@ -255,6 +257,7 @@ export default function PreviewScreen({ // Auto-save and exit const handleExit = useCallback(async () => { + if (isProcessing) return; const state = stateRef.current; if (state.stickers.length === 0 && state.layout === 'single' && !state.activeFrame && state.dateOverlay === 'off') { state.onReset(); @@ -294,6 +297,7 @@ export default function PreviewScreen({ }, [resetIdleTimer]); const handleRetakeClick = async () => { + if (isProcessing) return; if (stickers.length > 0 || layout !== 'single' || activeFrame || dateOverlay !== 'off') { setIsProcessing(true); setStatusMessage('Wird vor dem Wiederholen gespeichert...'); @@ -523,7 +527,7 @@ export default function PreviewScreen({ {/* Action Buttons */} - + - + Nur auf Tablet speichern {photoUris.length < 4 && ( - + Weiteres Foto aufnehmen )} - + Wiederholen - + Beenden @@ -747,6 +751,9 @@ const styles = StyleSheet.create({ fontSize: 14, fontWeight: '600', }, + btnDisabled: { + opacity: 0.5, + }, // ── Photo Canvases ── singleCanvas: { width: 480,