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 };
}
/**