From fc7b2c77692a0b752f778d1f1779bf9fee567ad1 Mon Sep 17 00:00:00 2001 From: orfelorfel23 Date: Thu, 11 Jun 2026 15:25:22 +0200 Subject: [PATCH] feat: dynamic collage layout based on photo selection count --- src/screens/AdminScreen.tsx | 3 +- src/screens/CameraScreen.tsx | 4 +- src/screens/PreviewScreen.tsx | 188 ++++++++++++---------------------- 3 files changed, 68 insertions(+), 127 deletions(-) diff --git a/src/screens/AdminScreen.tsx b/src/screens/AdminScreen.tsx index 8d9068d8..e8e7a953 100644 --- a/src/screens/AdminScreen.tsx +++ b/src/screens/AdminScreen.tsx @@ -29,7 +29,7 @@ import { import { THEME } from '../styles/theme'; import { logger } from '../services/logger'; import KioskMode from '../../modules/kiosk-mode'; -import { AppSettings, saveSettings } from '../services/settings'; +import { AppSettings, loadSettings, saveSettings, APP_VERSION } from '../services/settings'; import { FRAMES } from '../data/frames'; interface AdminScreenProps { @@ -229,6 +229,7 @@ export default function AdminScreen({ currentSettings, onSave, onClose }: AdminS } const updated: AppSettings = { + appVersion: APP_VERSION, countdownDuration: duration, printerIp: ipTrimmed, adminPassword: password.trim(), diff --git a/src/screens/CameraScreen.tsx b/src/screens/CameraScreen.tsx index 34768a2a..e5278f87 100644 --- a/src/screens/CameraScreen.tsx +++ b/src/screens/CameraScreen.tsx @@ -108,7 +108,7 @@ export default function CameraScreen({ const scale = useSharedValue(1); useEffect(() => { - if (countdown !== '') { + if (countdown !== null) { scale.value = 0.5; scale.value = withSpring(1.25, { damping: 10, stiffness: 120 }, () => { scale.value = withTiming(1.0, { duration: 150 }); @@ -147,7 +147,7 @@ export default function CameraScreen({ PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE, ]); - logger.log('Android Permissions:', JSON.stringify(granted)); + logger.log('Android Permissions: ' + JSON.stringify(granted)); } catch (err) { console.warn('Failed to request Android permissions', err); } diff --git a/src/screens/PreviewScreen.tsx b/src/screens/PreviewScreen.tsx index a3e30447..d90c64fa 100644 --- a/src/screens/PreviewScreen.tsx +++ b/src/screens/PreviewScreen.tsx @@ -60,39 +60,43 @@ export default function PreviewScreen({ const [isCapturing, setIsCapturing] = useState(false); const [statusMessage, setStatusMessage] = useState(''); - const getRequiredPhotoCount = (l: CollageLayout) => { - if (l === 'single') return 1; - if (l === 'duo') return 2; - if (l === 'strip') return 3; - if (l === 'grid') return 4; - return 1; - }; - const [activeUris, setActiveUris] = useState([]); + // Initialize activeUris with all available photos up to 4 when first loaded useEffect(() => { - const req = getRequiredPhotoCount(layout); - setActiveUris(prev => { - if (prev.length === req) return prev; - if (prev.length > req) return prev.slice(prev.length - req); - const available = photoUris.filter(u => !prev.includes(u)); - const needed = req - prev.length; - const toAdd = available.slice(-needed); - return [...prev, ...toAdd]; - }); - }, [layout, photoUris]); + setActiveUris(photoUris.slice(-4)); + const count = Math.min(photoUris.length, 4); + if (count === 1) setLayout('single'); + else if (count === 2) setLayout('duo'); + else if (count === 3) setLayout('strip'); + else if (count === 4) setLayout('grid'); + }, [photoUris]); const togglePhoto = (uri: string) => { logger.log(`Action: Toggled photo ${uri}`); setActiveUris(prev => { - const req = getRequiredPhotoCount(layout); - if (prev.includes(uri)) { - return prev; // Already selected, do nothing + const isSelected = prev.includes(uri); + let nextUris: string[]; + + if (isSelected) { + if (prev.length <= 1) return prev; // Don't allow 0 photos + nextUris = prev.filter(u => u !== uri); + } else { + if (prev.length >= 4) { + nextUris = [...prev.slice(1), uri]; // Keep max 4, replace oldest + } else { + nextUris = [...prev, uri]; + } } - if (prev.length >= req) { - return [...prev.slice(1), uri]; // FIFO: remove oldest, add new - } - return [...prev, uri]; + + // Automatically update layout based on selection count + const count = nextUris.length; + if (count === 1) setLayout('single'); + else if (count === 2) setLayout('duo'); + else if (count === 3) setLayout('strip'); + else if (count === 4) setLayout('grid'); + + return nextUris; }); }; @@ -552,77 +556,36 @@ export default function PreviewScreen({ {/* Right panel: Controls */} - WÄHLE DEINEN STIL + DEIN FOTO - {/* Layout Selection */} - - { logger.log('Action: Selected layout single'); setLayout('single'); }} - > - Einzelbild - - - { logger.log('Action: Selected layout duo'); setLayout('duo'); }} - > - Duo (2) - - - { logger.log('Action: Selected layout strip'); setLayout('strip'); }} - > - Streifen (3) - - - { logger.log('Action: Selected layout grid'); setLayout('grid'); }} - > - Raster (4) - - - {/* Thumbnail Reel for Photo Selection */} - {photoUris.length > 1 && layout !== 'single' && ( - - - {photoUris.map((uri, idx) => { - const isActive = activeUris.includes(uri); - return ( - togglePhoto(uri)} - activeOpacity={0.7} - > - - {isActive && ( - - - - )} - - ); - })} - + {photoUris.length > 1 && ( + + + Tippe auf bis zu 4 Bilder für eine Collage: + + + + {photoUris.map((uri, idx) => { + const isActive = activeUris.includes(uri); + return ( + togglePhoto(uri)} + activeOpacity={0.7} + > + + {isActive && ( + + + + )} + + ); + })} + + )} @@ -776,37 +739,14 @@ const styles = StyleSheet.create({ textShadowOffset: { width: 0, height: 0 }, textShadowRadius: 12, }, - layoutSelector: { - flexDirection: 'row', - justifyContent: 'space-between', - marginBottom: THEME.spacing.md, - }, - layoutBtn: { - flex: 1, - paddingVertical: THEME.spacing.sm, - backgroundColor: THEME.colors.surfaceSecondary, - borderWidth: 1, - borderColor: THEME.colors.border, - borderRadius: THEME.borderRadius.sm, - alignItems: 'center', - marginHorizontal: 3, - }, - layoutBtnActive: { - backgroundColor: THEME.colors.accent, - borderColor: THEME.colors.accent, - shadowColor: THEME.colors.accent, - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.5, - shadowRadius: 8, - elevation: 4, - }, - layoutBtnDisabled: { - opacity: 0.3, - }, - layoutBtnText: { - color: THEME.colors.text, + thumbnailInstruction: { + color: THEME.colors.textMuted, fontSize: 12, - fontWeight: 'bold', + marginBottom: THEME.spacing.xs, + textAlign: 'center', + }, + thumbnailReelContainer: { + marginBottom: THEME.spacing.md, }, thumbnailReel: { marginBottom: THEME.spacing.md,