From d38115528e3507b4f080c0f6c8f70aa50b266941 Mon Sep 17 00:00:00 2001 From: orfelorfel23 Date: Sun, 31 May 2026 23:47:25 +0200 Subject: [PATCH] Fix 5 hidden edge cases: IPP decode, settings race, PreviewScreen state sync, burst timeout leak, and logger spam --- src/components/DraggableSticker.tsx | 10 ++++------ src/screens/CameraScreen.tsx | 23 +++++++++++++++++++++-- src/screens/PreviewScreen.tsx | 15 +++++++-------- src/services/printer.ts | 5 +++-- src/services/settings.ts | 8 +++----- 5 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/components/DraggableSticker.tsx b/src/components/DraggableSticker.tsx index 2d638ccd..7ad8f7f2 100644 --- a/src/components/DraggableSticker.tsx +++ b/src/components/DraggableSticker.tsx @@ -148,11 +148,10 @@ export default function DraggableSticker({ } const styles = StyleSheet.create({ - stickerWrapper: { + stickerContainer: { position: 'absolute', alignItems: 'center', justifyContent: 'center', - zIndex: 100, }, emojiText: { fontSize: 48, @@ -179,13 +178,12 @@ const styles = StyleSheet.create({ position: 'absolute', top: -10, right: -10, - width: 22, - height: 22, - borderRadius: 11, + width: 24, + height: 24, + borderRadius: 12, backgroundColor: THEME.colors.error, alignItems: 'center', justifyContent: 'center', - zIndex: 200, }, deleteBtnText: { color: '#fff', diff --git a/src/screens/CameraScreen.tsx b/src/screens/CameraScreen.tsx index 5c21dcee..778c40f4 100644 --- a/src/screens/CameraScreen.tsx +++ b/src/screens/CameraScreen.tsx @@ -96,6 +96,7 @@ export default function CameraScreen({ const expoCameraRef = useRef(null); const burstTimerRef = useRef(null); const countdownTimerRef = useRef(null); + const completionTimerRef = useRef(null); const isCancelledRef = useRef(false); // Reanimated countdown pulse animation @@ -162,6 +163,7 @@ export default function CameraScreen({ return () => { if (burstTimerRef.current) clearTimeout(burstTimerRef.current); if (countdownTimerRef.current) clearTimeout(countdownTimerRef.current); + if (completionTimerRef.current) clearTimeout(completionTimerRef.current); }; }, []); @@ -207,6 +209,7 @@ export default function CameraScreen({ isCancelledRef.current = true; if (burstTimerRef.current) clearTimeout(burstTimerRef.current); if (countdownTimerRef.current) clearTimeout(countdownTimerRef.current); + if (completionTimerRef.current) clearTimeout(completionTimerRef.current); // Clean up any temp files from a partially completed burst for (const uri of burstUris) { @@ -362,12 +365,12 @@ export default function CameraScreen({ setBurstIndex(0); setBurstUris([]); // Short delay prevents Android expo-camera crash on immediate unmount - setTimeout(() => { + completionTimerRef.current = setTimeout(() => { onBurstComplete(newUris); }, 400); } else { // Single shot mode - setTimeout(() => { + completionTimerRef.current = setTimeout(() => { onPhotoCaptured(capturedUri); }, 400); } @@ -443,6 +446,22 @@ export default function CameraScreen({ > {welcomeText} + + {/* White Outline Layers */} + {[ + { t: -2, l: -2 }, { t: -2, l: 0 }, { t: -2, l: 2 }, + { t: 0, l: -2 }, { t: 0, l: 2 }, + { t: 2, l: -2 }, { t: 2, l: 0 }, { t: 2, l: 2 } + ].map((pos, index) => ( + + {welcomeText} + + ))} {/* Gradient Text Layer over the shadow layer */} (false); const [statusMessage, setStatusMessage] = useState(''); - React.useEffect(() => { - logger.log('PreviewScreen: render function executed'); - }); + // Sticker state const [stickers, setStickers] = useState([]); @@ -224,11 +222,10 @@ export default function PreviewScreen({ if (!mountedRef.current) return; if (isProcessing) return; setIsProcessing(true); - setStatusMessage('Dein Foto wird vorbereitet...'); try { - setStatusMessage('Bild wird generiert...'); const printUri = await captureComposite(currentPhoto); if (!mountedRef.current) return; + setStatusMessage('Dein Foto wird vorbereitet...'); setStatusMessage('Druckauftrag wird an Drucker gesendet...'); await printImageLocal(printUri, { @@ -259,10 +256,10 @@ export default function PreviewScreen({ if (!mountedRef.current) return; if (isProcessing) return; setIsProcessing(true); - setStatusMessage('Bild wird generiert...'); try { const saveUri = await captureComposite(currentPhoto); if (!mountedRef.current) return; + setStatusMessage('Bild wird generiert...'); setStatusMessage('Wird in Galerie gespeichert...'); await saveToGallery(saveUri); @@ -293,10 +290,10 @@ export default function PreviewScreen({ } setIsProcessing(true); - setStatusMessage('Wird gespeichert...'); try { const capturedUri = await captureComposite(state.currentPhoto); if (!mountedRef.current) return; + setStatusMessage('Wird gespeichert...'); await saveToGallery(capturedUri); if (!mountedRef.current) return; setStatusMessage('Erfolgreich gespeichert!'); @@ -333,10 +330,10 @@ export default function PreviewScreen({ if (isProcessing) return; if (stickers.length > 0 || layout !== 'single' || activeFrame || dateOverlay !== 'off') { setIsProcessing(true); - setStatusMessage('Wird vor dem Wiederholen gespeichert...'); try { const capturedUri = await captureComposite(currentPhoto); if (!mountedRef.current) return; + setStatusMessage('Wird vor dem Wiederholen gespeichert...'); await saveToGallery(capturedUri); if (!mountedRef.current) return; } catch (e) { @@ -659,6 +656,8 @@ const styles = StyleSheet.create({ height: 320, justifyContent: 'center', alignItems: 'center', + overflow: 'hidden', + backgroundColor: THEME.colors.background, }, controlPanel: { flex: 0.8, diff --git a/src/services/printer.ts b/src/services/printer.ts index 62cad4b3..1473a82f 100644 --- a/src/services/printer.ts +++ b/src/services/printer.ts @@ -91,8 +91,9 @@ export async function printImageLocal(imageUri: string, options: PrintOptions): } console.log('Silent print job accepted successfully!'); } catch (e: any) { - // If decoding fails, we still assume success since the network request completed successfully - console.warn('Failed to parse IPP response, but network request succeeded:', e.message); + // If decoding fails, it's a print error. Let it trigger a retry. + console.warn('Failed to parse IPP response. The printer may be incompatible or returning malformed data:', e.message); + throw e; } return; // Success, exit retry loop diff --git a/src/services/settings.ts b/src/services/settings.ts index ba8fc3da..f1951e34 100644 --- a/src/services/settings.ts +++ b/src/services/settings.ts @@ -46,11 +46,9 @@ const DEFAULT_SETTINGS: AppSettings = { */ export async function loadSettings(): Promise { try { - if (settingsFile.exists) { - const content = await settingsFile.text(); - const parsed = JSON.parse(content); - return { ...DEFAULT_SETTINGS, ...parsed }; - } + const content = await settingsFile.text(); + const parsed = JSON.parse(content); + return { ...DEFAULT_SETTINGS, ...parsed }; } catch (e) { console.error('Failed to load settings, using defaults:', e); }