diff --git a/App.tsx b/App.tsx index cd0bb9bf..a3037ee4 100644 --- a/App.tsx +++ b/App.tsx @@ -157,6 +157,7 @@ export default function App() { onBurstComplete={handleBurstComplete} onCancel={handleReset} isIdle={currentScreen !== 'camera'} + isObscured={currentScreen === 'preview' || currentScreen === 'admin'} onStartBooth={handleStartBooth} onNavigateToAdmin={handleOpenAdmin} adminPassword={settings.adminPassword} diff --git a/package-lock.json b/package-lock.json index 6bbc5b8b..5a568788 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@react-native-masked-view/masked-view": "0.3.2", "buffer": "^6.0.3", "expo": "~54.0.0", + "expo-application": "~7.0.8", "expo-build-properties": "~1.0.10", "expo-camera": "~17.0.10", "expo-file-system": "~19.0.23", @@ -4617,6 +4618,15 @@ } } }, + "node_modules/expo-application": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-7.0.8.tgz", + "integrity": "sha512-qFGyxk7VJbrNOQWBbE09XUuGuvkOgFS9QfToaK2FdagM2aQ+x3CvGV2DuVgl/l4ZxPgIf3b/MNh9xHpwSwn74Q==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, "node_modules/expo-asset": { "version": "12.0.13", "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-12.0.13.tgz", diff --git a/package.json b/package.json index 09ee86e1..e6d400a6 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "@react-native-masked-view/masked-view": "0.3.2", "buffer": "^6.0.3", "expo": "~54.0.0", + "expo-application": "~7.0.8", "expo-build-properties": "~1.0.10", "expo-camera": "~17.0.10", "expo-file-system": "~19.0.23", diff --git a/src/components/DraggableSticker.tsx b/src/components/DraggableSticker.tsx index 9f9cbfbd..ffdaa7a5 100644 --- a/src/components/DraggableSticker.tsx +++ b/src/components/DraggableSticker.tsx @@ -121,13 +121,6 @@ export default function DraggableSticker({ ], })); - const deleteBtnStyle = useAnimatedStyle(() => ({ - transform: [ - { scale: 1 / scale.value }, - { rotate: `${-rotation.value}rad` }, // keep it upright - ], - })); - const isText = sticker.type === 'text'; return ( @@ -140,17 +133,6 @@ export default function DraggableSticker({ ) : ( {sticker.content} )} - {isSelected && ( - - onDelete(sticker.id)} - hitSlop={{ top: 20, bottom: 20, left: 20, right: 20 }} - > - × - - - )} ); diff --git a/src/screens/AdminScreen.tsx b/src/screens/AdminScreen.tsx index e8e7a953..2607ad84 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, loadSettings, saveSettings, APP_VERSION } from '../services/settings'; +import { AppSettings, loadSettings, saveSettings } from '../services/settings'; import { FRAMES } from '../data/frames'; interface AdminScreenProps { @@ -229,7 +229,7 @@ export default function AdminScreen({ currentSettings, onSave, onClose }: AdminS } const updated: AppSettings = { - appVersion: APP_VERSION, + appLastUpdate: currentSettings.appLastUpdate, countdownDuration: duration, printerIp: ipTrimmed, adminPassword: password.trim(), diff --git a/src/screens/CameraScreen.tsx b/src/screens/CameraScreen.tsx index e5278f87..63594cda 100644 --- a/src/screens/CameraScreen.tsx +++ b/src/screens/CameraScreen.tsx @@ -56,6 +56,7 @@ interface CameraScreenProps { selectedFrameId: string | null; footerText: string; useFrontCamera: boolean; + isObscured: boolean; } export default function CameraScreen({ @@ -74,6 +75,7 @@ export default function CameraScreen({ selectedFrameId, footerText, useFrontCamera, + isObscured, }: CameraScreenProps) { const [permission, requestPermission] = useCameraPermissions(); const [isUsbConnected, setIsUsbConnected] = useState(false); @@ -653,10 +655,10 @@ export default function CameraScreen({ {/* Camera Preview Background */} - {Platform.OS === 'android' && !useFrontCamera ? ( + {!isObscured && isUsbConnected && !useFrontCamera ? ( ) : ( - SCHNAPPIX FOTOBOX + {eventText} {new Date().toLocaleDateString('de-DE')} @@ -454,7 +455,7 @@ export default function PreviewScreen({ ))} - SCHNAPPIX FOTOBOX + {eventText} ); @@ -475,7 +476,7 @@ export default function PreviewScreen({ ))} - SCHNAPPIX FOTOBOX + {eventText} ); @@ -554,9 +555,20 @@ export default function PreviewScreen({ )} + {/* Global Trash Can for Stickers */} + {selectedStickerId !== null && ( + handleStickerDelete(selectedStickerId)} + activeOpacity={0.7} + > + + + )} + {/* Right panel: Controls */} - DEIN FOTO + {eventText} {/* Thumbnail Reel for Photo Selection */} {photoUris.length > 1 && ( @@ -568,6 +580,7 @@ export default function PreviewScreen({ {photoUris.map((uri, idx) => { const isActive = activeUris.includes(uri); + const indexInSelection = activeUris.indexOf(uri) + 1; return ( {isActive && ( - + {indexInSelection} )} @@ -739,6 +752,23 @@ const styles = StyleSheet.create({ textShadowOffset: { width: 0, height: 0 }, textShadowRadius: 12, }, + globalTrashButton: { + position: 'absolute', + top: 40, + alignSelf: 'center', + width: 60, + height: 60, + borderRadius: 30, + backgroundColor: THEME.colors.error, + justifyContent: 'center', + alignItems: 'center', + zIndex: 9999, + shadowColor: '#000', + shadowOffset: { width: 0, height: 4 }, + shadowOpacity: 0.5, + shadowRadius: 6, + elevation: 8, + }, thumbnailInstruction: { color: THEME.colors.textMuted, fontSize: 12, diff --git a/src/services/settings.ts b/src/services/settings.ts index 6b085ebd..3de830e5 100644 --- a/src/services/settings.ts +++ b/src/services/settings.ts @@ -2,10 +2,10 @@ import { File, Paths } from 'expo-file-system'; import * as FileSystem from 'expo-file-system/legacy'; import { FRAMES } from '../data/frames'; -export const APP_VERSION = 2; // Increment this whenever you want settings to reset on update +import * as Application from 'expo-application'; export interface AppSettings { - appVersion: number; + appLastUpdate: number | null; countdownDuration: number; // in seconds printerIp: string; adminPassword: string; @@ -33,7 +33,7 @@ export interface AppSettings { const settingsFile = new File(Paths.document, 'settings.json'); const DEFAULT_SETTINGS: AppSettings = { - appVersion: APP_VERSION, + appLastUpdate: null, countdownDuration: 3, printerIp: '192.168.1.100', adminPassword: '1234', @@ -56,21 +56,35 @@ const DEFAULT_SETTINGS: AppSettings = { * Load settings from persistent storage. */ export async function loadSettings(): Promise { + let currentUpdateTime: number | null = null; + try { + const updateTime = await Application.getLastUpdateTimeAsync(); + currentUpdateTime = updateTime ? updateTime.getTime() : null; + } catch (e) { + console.warn('Could not get app update time:', e); + } + try { const content = await settingsFile.text(); const parsed = JSON.parse(content); - // Reset to defaults if the app version has changed (app updated) - if (parsed.appVersion !== APP_VERSION) { - console.log(`Settings version mismatch (old: ${parsed.appVersion}, new: ${APP_VERSION}). Resetting to default.`); - return DEFAULT_SETTINGS; + // Reset to defaults if the app installation/update time has changed + // Allow a small drift margin (e.g. 5 seconds) just in case + if (parsed.appLastUpdate && currentUpdateTime) { + if (Math.abs(parsed.appLastUpdate - currentUpdateTime) > 5000) { + console.log(`App update detected. Resetting settings to default.`); + const defaults = { ...DEFAULT_SETTINGS, appLastUpdate: currentUpdateTime }; + // Instantly save the new default settings to disk so they persist! + await saveSettings(defaults); + return defaults; + } } - return { ...DEFAULT_SETTINGS, ...parsed }; + return { ...DEFAULT_SETTINGS, ...parsed, appLastUpdate: currentUpdateTime }; } catch (e) { console.error('Failed to load settings, using defaults:', e); } - return DEFAULT_SETTINGS; + return { ...DEFAULT_SETTINGS, appLastUpdate: currentUpdateTime }; } /**