From f2b359e5158b6573691e2d6588e2786574b04023 Mon Sep 17 00:00:00 2001 From: javier Date: Wed, 29 Jul 2026 09:39:12 +0200 Subject: [PATCH] Final fixes for photo overlay position and rotation --- src/photo/FooterOverlay.tsx | 23 +++++--- src/screens/CameraScreen.tsx | 101 ++++++++++++++++------------------- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/photo/FooterOverlay.tsx b/src/photo/FooterOverlay.tsx index 01e9268..47fefaa 100644 --- a/src/photo/FooterOverlay.tsx +++ b/src/photo/FooterOverlay.tsx @@ -11,20 +11,21 @@ interface Props { config: FooterConfig; meta: StampMeta; imageWidth: number; + rotation?: number; // Rotación extra para la preview de cámara } -export function FooterOverlay({ config, meta, imageWidth }: Props) { +export function FooterOverlay({ config, meta, imageWidth, rotation = 0 }: Props) { if (!config.enabled) return null; const enabled = config.fields.filter((f) => f.enabled); if (enabled.length === 0 && !config.logoUri) return null; - const fontSize = Math.max(10, Math.round(imageWidth * 0.018)); - const logoDim = Math.max(40, Math.round(imageWidth * 0.08)); - const pad = Math.max(8, Math.round(imageWidth * 0.015)); + const fontSize = Math.max(10, Math.round(imageWidth * 0.022)); + const logoDim = Math.max(40, Math.round(imageWidth * 0.10)); + const pad = Math.max(8, Math.round(imageWidth * 0.02)); const lineH = Math.round(fontSize * 1.3); - // Determinar posición + // Determinar posición física const posStyle: ViewStyle = {}; if (config.overlayPosition.includes('top')) posStyle.top = 20; else posStyle.bottom = 20; @@ -32,6 +33,11 @@ export function FooterOverlay({ config, meta, imageWidth }: Props) { if (config.overlayPosition.includes('left')) posStyle.left = 20; else posStyle.right = 20; + // Aplicar rotación si se indica (para la cámara) + if (rotation !== 0) { + posStyle.transform = [{ rotate: `${rotation}deg` }]; + } + return ( {/* Logo */} @@ -39,7 +45,7 @@ export function FooterOverlay({ config, meta, imageWidth }: Props) { @@ -75,8 +81,9 @@ const styles = StyleSheet.create({ position: 'absolute', backgroundColor: 'rgba(0,0,0,0.65)', borderRadius: 8, - maxWidth: '50%', // Para no ocupar toda la pantalla + maxWidth: '70%', // Un poco más ancho para evitar cortes agresivos alignItems: 'flex-start', + zIndex: 1000, }, logoWrap: { backgroundColor: '#fff', @@ -84,7 +91,7 @@ const styles = StyleSheet.create({ justifyContent: 'center', alignItems: 'center', }, - logoImg: { width: '80%', height: '80%' }, + logoImg: { width: '85%', height: '85%' }, textBlock: { width: '100%' }, line: { color: '#fff' }, bold: { fontWeight: '700' }, diff --git a/src/screens/CameraScreen.tsx b/src/screens/CameraScreen.tsx index 61a2649..57187db 100644 --- a/src/screens/CameraScreen.tsx +++ b/src/screens/CameraScreen.tsx @@ -38,6 +38,8 @@ export function CameraScreen({ route, navigation }: Props) { }; const handleOrientation = (o: ScreenOrientation.Orientation) => { + // Nota: LANDSCAPE_LEFT es rotar el móvil a la derecha (home button a la derecha) + // Queremos contrarrestar el giro para que el sello esté derecho. if (o === ScreenOrientation.Orientation.LANDSCAPE_LEFT) setRotation(90); else if (o === ScreenOrientation.Orientation.LANDSCAPE_RIGHT) setRotation(-90); else if (o === ScreenOrientation.Orientation.PORTRAIT_UPSIDE_DOWN) setRotation(180); @@ -128,80 +130,71 @@ export function CameraScreen({ route, navigation }: Props) { - - {/* Header */} - - navigation.goBack()} style={styles.closeBtn}> - - - + /> - {/* Footer Preview con rotación */} - {config && meta && ( - - winH ? winH : winW} - /> - - )} - - {/* Controls */} - - void capture()} - disabled={taking} - > - - - + {/* Capa de UI sobre la cámara */} + + {/* Header con botón cerrar */} + + navigation.goBack()} style={styles.closeBtn}> + + - + + {/* Preview del sello (posicionado en su esquina con rotación) */} + {config && meta && ( + + + + )} + + {/* Botón de disparo abajo al centro */} + + void capture()} + disabled={taking} + > + + + + ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#000' }, - camera: { flex: 1 }, - overlay: { flex: 1, justifyContent: 'space-between' }, + overlay: { flex: 1, justifyContent: 'space-between', zIndex: 10 }, + fullOverlay: { + ...StyleSheet.absoluteFillObject, + // No centramos aquí, dejamos que FooterOverlay use sus offsets top/bottom/left/right + }, center: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#000' }, message: { color: '#fff', textAlign: 'center', marginBottom: 20 }, btn: { backgroundColor: COLORS.primary, padding: 12, borderRadius: 8 }, btnText: { color: '#fff', fontWeight: 'bold' }, header: { padding: 20, paddingTop: 50 }, - closeBtn: { width: 40, height: 40, justifyContent: 'center', alignItems: 'center' }, + closeBtn: { width: 40, height: 40, justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0,0,0,0.3)', borderRadius: 20 }, closeTxt: { color: '#fff', fontSize: 24 }, - footerWrapper: { - position: 'absolute', - // Ocupamos toda la pantalla para que el transform rote sobre el centro - // pero el FooterOverlay se posicionará internamente en su esquina. - top: 0, - left: 0, - right: 0, - bottom: 0, - justifyContent: 'center', - alignItems: 'center', - pointerEvents: 'none', - }, - controls: { + footerControls: { paddingBottom: 40, alignItems: 'center', + width: '100%', }, captureBtn: { - width: 70, - height: 70, - borderRadius: 35, - borderWidth: 4, + width: 76, + height: 70, // Un poco ovalado para que se note + borderRadius: 38, + borderWidth: 5, borderColor: '#fff', justifyContent: 'center', alignItems: 'center',