Compare commits

...
6 Commits
19 changed files with 140 additions and 139 deletions
+19 -20
View File
@@ -5,6 +5,7 @@ import CameraScreen from './src/screens/CameraScreen';
import PreviewScreen from './src/screens/PreviewScreen'; import PreviewScreen from './src/screens/PreviewScreen';
import AdminScreen from './src/screens/AdminScreen'; import AdminScreen from './src/screens/AdminScreen';
import { loadSettings, saveSettings, AppSettings } from './src/services/settings'; import { loadSettings, saveSettings, AppSettings } from './src/services/settings';
import { StickerData } from './src/components/DraggableSticker';
import { logger, setLogsEnabled } from './src/services/logger'; import { logger, setLogsEnabled } from './src/services/logger';
import * as FileSystem from 'expo-file-system/legacy'; import * as FileSystem from 'expo-file-system/legacy';
@@ -30,6 +31,10 @@ export default function App() {
const [showEventModal, setShowEventModal] = useState(false); const [showEventModal, setShowEventModal] = useState(false);
const [tempEventName, setTempEventName] = useState(''); const [tempEventName, setTempEventName] = useState('');
// Persist edits across camera switches for collages
const [stickers, setStickers] = useState<StickerData[]>([]);
const [selectedFrameId, setSelectedFrameId] = useState<string | null>(null);
// 1. Load configuration settings on app start // 1. Load configuration settings on app start
useEffect(() => { useEffect(() => {
async function initApp() { async function initApp() {
@@ -45,6 +50,10 @@ export default function App() {
console.warn('Failed to auto-start Kiosk mode:', e); console.warn('Failed to auto-start Kiosk mode:', e);
} }
} }
if (savedSettings.frameMode === 'always') {
setSelectedFrameId(savedSettings.selectedFrameId);
}
} }
initApp(); initApp();
}, []); }, []);
@@ -67,6 +76,8 @@ export default function App() {
} }
setPhotoUris([]); setPhotoUris([]);
setCaptureHistory([]); setCaptureHistory([]);
setStickers([]);
setSelectedFrameId(settings?.frameMode === 'always' ? settings.selectedFrameId : null);
setCurrentScreen('camera'); setCurrentScreen('camera');
}; };
@@ -81,6 +92,8 @@ export default function App() {
// Resume start // Resume start
setPhotoUris([]); setPhotoUris([]);
setCaptureHistory([]); setCaptureHistory([]);
setStickers([]);
setSelectedFrameId(updated.frameMode === 'always' ? updated.selectedFrameId : null);
setCurrentScreen('camera'); setCurrentScreen('camera');
}; };
@@ -110,26 +123,7 @@ export default function App() {
setCurrentScreen('preview'); setCurrentScreen('preview');
}; };
const handleRetakeLast = async () => {
// Remove photos from the last capture event
const lastCaptureCount = captureHistory.length > 0 ? captureHistory[captureHistory.length - 1] : 1;
const updatedUris = [...photoUris];
const removedUris = updatedUris.splice(-lastCaptureCount, lastCaptureCount);
setPhotoUris(updatedUris);
setCaptureHistory((prev) => prev.slice(0, -1));
// Clean up temp files
for (const uri of removedUris) {
try {
await FileSystem.deleteAsync(uri, { idempotent: true });
} catch (e) {
console.warn('Failed to delete temp file:', e);
}
}
// Always let user retake
setCurrentScreen('camera');
};
const handleAddAnother = () => { const handleAddAnother = () => {
setCurrentScreen('camera'); setCurrentScreen('camera');
@@ -146,6 +140,8 @@ export default function App() {
} }
setPhotoUris([]); setPhotoUris([]);
setCaptureHistory([]); setCaptureHistory([]);
setStickers([]);
setSelectedFrameId(settings?.frameMode === 'always' ? settings.selectedFrameId : null);
setCurrentScreen('home'); // Go to home when cancelled setCurrentScreen('home'); // Go to home when cancelled
}; };
@@ -199,7 +195,6 @@ export default function App() {
<PreviewScreen <PreviewScreen
photoUris={photoUris} photoUris={photoUris}
printerIp={settings.printerIp} printerIp={settings.printerIp}
onRetakeLast={handleRetakeLast}
onAddAnother={handleAddAnother} onAddAnother={handleAddAnother}
onReset={handleReset} onReset={handleReset}
frameMode={settings.frameMode} frameMode={settings.frameMode}
@@ -208,6 +203,10 @@ export default function App() {
dateOverlay={settings.dateOverlay} dateOverlay={settings.dateOverlay}
dateOverlayTransform={settings.dateOverlayTransform} dateOverlayTransform={settings.dateOverlayTransform}
eventText={settings.eventText} eventText={settings.eventText}
stickers={stickers}
setStickers={setStickers}
selectedFrameId={selectedFrameId}
setSelectedFrameId={setSelectedFrameId}
/> />
</View> </View>
)} )}
@@ -45,3 +45,4 @@
42514 42649 8048871219047361 C:/GitHub/Schnappix/android/app/build/intermediates/cxx/RelWithDebInfo/3x5j4n2e/obj/arm64-v8a/libappmodules.so 22f7dfe7517aece 42514 42649 8048871219047361 C:/GitHub/Schnappix/android/app/build/intermediates/cxx/RelWithDebInfo/3x5j4n2e/obj/arm64-v8a/libappmodules.so 22f7dfe7517aece
20 71 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/CMakeFiles/cmake.verify_globs 5250f1b80cb55465 20 71 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/CMakeFiles/cmake.verify_globs 5250f1b80cb55465
2 24 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/CMakeFiles/cmake.verify_globs 5250f1b80cb55465 2 24 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/CMakeFiles/cmake.verify_globs 5250f1b80cb55465
6 63 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/CMakeFiles/cmake.verify_globs 5250f1b80cb55465
@@ -2,41 +2,41 @@ C/C++ Structured Logg
e e
cC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\additional_project_files.txtC cC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\additional_project_files.txtC
A A
?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  Îïìòò3Å, ½Ñªðò3d ?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  ¶…—Åô3Å, ½Ñªðò3d
b b
`C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\android_gradle_build.json  Îïìòò3û" ÂѪðò3i `C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\android_gradle_build.json  ¶…—Åô3û" ÂѪðò3i
g g
eC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\android_gradle_build_mini.json  Îïìòò3ï  Òªðò3V eC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\android_gradle_build_mini.json  ¶…—Åô3ï  Òªðò3V
T T
RC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\build.ninja  Îïìòò3œÞ åͪðò3Z RC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\build.ninja  ¶…—Åô3œÞ åͪðò3Z
X X
VC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\build.ninja.txt  Îïìòò3_ VC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\build.ninja.txt  ¶…—Åô3_
] ]
[C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\build_file_index.txt  Îïìòò3 ¨Òªðò3` [C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\build_file_index.txt  ¶…—Åô3 ¨Òªðò3`
^ ^
\C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\compile_commands.json  Îïìòò3‘Ø ãͪðò3d \C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\compile_commands.json  ¶…—Åô3‘Ø ãͪðò3d
b b
`C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\compile_commands.json.bin  Îïìòò3 Ê„ ãͪðò3j `C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\compile_commands.json.bin  ¶…—Åô3 Ê„ ãͪðò3j
h h
fC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\metadata_generation_command.txt  Îïìòò3 fC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\metadata_generation_command.txt  ¶…—Åô3
¸ §Òªðò3] ¸ §Òªðò3]
[ [
YC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\prefab_config.json  Îïìòò3  ¨Òªðò3b YC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\prefab_config.json  ¶…—Åô3  ¨Òªðò3b
` `
^C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\symbol_folder_index.txt  Îïìòò3 ^C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\symbol_folder_index.txt  ¶…—Åô3
 ] ¨Òªðò3{  ] ¨Òªðò3{
y y
wC:\GitHub\Schnappix\node_modules\react-native-gesture-handler\android\build\generated\source\codegen\jni\CMakeLists.txt  ¶…—Åô3 wC:\GitHub\Schnappix\node_modules\react-native-gesture-handler\android\build\generated\source\codegen\jni\CMakeLists.txt  ¶…—Åô3
¾ Ü…§ðò3v ¾ Ü…§ðò3v
t t
rC:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\generated\source\codegen\jni\CMakeLists.txt  Îïìòò3ö ùާðò3µ rC:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\generated\source\codegen\jni\CMakeLists.txt  ¶…—Åô3ö ùާðò3µ
² ²
¯C:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  Îïìòò3Y ¯C:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  ¶…—Åô3Y
W W
UC:\GitHub\Schnappix\node_modules\react-native-svg\android\src\main\jni\CMakeLists.txt  Îïìòò3½ œ§ØÖç3u UC:\GitHub\Schnappix\node_modules\react-native-svg\android\src\main\jni\CMakeLists.txt  ¶…—Åô3½ œ§ØÖç3u
s s
qC:\GitHub\Schnappix\node_modules\react-native-view-shot\android\build\generated\source\codegen\jni\CMakeLists.txt  Îïìòò3ê ú„§ðò3t qC:\GitHub\Schnappix\node_modules\react-native-view-shot\android\build\generated\source\codegen\jni\CMakeLists.txt  ¶…—Åô3ê ú„§ðò3t
r r
pC:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\generated\source\codegen\jni\CMakeLists.txt  Îïìòò3ê è„§ðò3³ pC:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\generated\source\codegen\jni\CMakeLists.txt  ¶…—Åô3ê è„§ðò3³
° °
­C:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  Îïìòò3k ­C:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  ¶…—Åô3k
@@ -45,3 +45,4 @@
20839 20978 8048871470843232 C:/GitHub/Schnappix/android/app/build/intermediates/cxx/RelWithDebInfo/3x5j4n2e/obj/armeabi-v7a/libappmodules.so 7a2dfc40ee7e94c1 20839 20978 8048871470843232 C:/GitHub/Schnappix/android/app/build/intermediates/cxx/RelWithDebInfo/3x5j4n2e/obj/armeabi-v7a/libappmodules.so 7a2dfc40ee7e94c1
2 33 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/CMakeFiles/cmake.verify_globs 1eb2d1da6ebc2e74 2 33 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/CMakeFiles/cmake.verify_globs 1eb2d1da6ebc2e74
2 27 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/CMakeFiles/cmake.verify_globs 1eb2d1da6ebc2e74 2 27 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/CMakeFiles/cmake.verify_globs 1eb2d1da6ebc2e74
3 46 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/CMakeFiles/cmake.verify_globs 1eb2d1da6ebc2e74
@@ -2,41 +2,41 @@ C/C++ Structured Logi
g g
eC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\additional_project_files.txtC eC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\additional_project_files.txtC
A A
?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  Ýðìòò3ý, ÷íðò3f ?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  Õ‡—Åô3ý, ÷íðò3f
d d
bC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\android_gradle_build.json  Ýðìòò3# øÃ­ðò3k bC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\android_gradle_build.json  Õ‡—Åô3# øÃ­ðò3k
i i
gC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\android_gradle_build_mini.json  Ýðìòò3 ŸÄ­ðò3X gC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\android_gradle_build_mini.json  Õ‡—Åô3 ŸÄ­ðò3X
V V
TC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\build.ninja  Ýðìòò3Áå âÀ­ðò3\ TC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\build.ninja  Õ‡—Åô3Áå âÀ­ðò3\
Z Z
XC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\build.ninja.txt  Ýðìòò3a XC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\build.ninja.txt  Õ‡—Åô3a
_ _
]C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\build_file_index.txt  Ýðìòò3  Ä­ðò3b ]C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\build_file_index.txt  Õ‡—Åô3  Ä­ðò3b
` `
^C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\compile_commands.json  Ýðìòò3´à àÀ­ðò3f ^C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\compile_commands.json  Õ‡—Åô3´à àÀ­ðò3f
d d
bC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\compile_commands.json.bin  Ýðìòò3 ò„ àÀ­ðò3l bC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\compile_commands.json.bin  Õ‡—Åô3 ò„ àÀ­ðò3l
j j
hC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\metadata_generation_command.txt  Ýðìòò3 hC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\metadata_generation_command.txt  Õ‡—Åô3
Ä ŸÄ­ðò3_ Ä ŸÄ­ðò3_
] ]
[C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\prefab_config.json  Ýðìòò3  ŸÄ­ðò3d [C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\prefab_config.json  Õ‡—Åô3  ŸÄ­ðò3d
b b
`C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\symbol_folder_index.txt  Ýðìòò3 `C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\symbol_folder_index.txt  Õ‡—Åô3
 _  Ä­ðò3{  _  Ä­ðò3{
y y
wC:\GitHub\Schnappix\node_modules\react-native-gesture-handler\android\build\generated\source\codegen\jni\CMakeLists.txt  Õ‡—Åô3 wC:\GitHub\Schnappix\node_modules\react-native-gesture-handler\android\build\generated\source\codegen\jni\CMakeLists.txt  Õ‡—Åô3
¾ Ü…§ðò3v ¾ Ü…§ðò3v
t t
rC:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\generated\source\codegen\jni\CMakeLists.txt  Ýðìòò3ö ùާðò3µ rC:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\generated\source\codegen\jni\CMakeLists.txt  Õ‡—Åô3ö ùާðò3µ
² ²
¯C:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  Ýðìòò3Y ¯C:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  Õ‡—Åô3Y
W W
UC:\GitHub\Schnappix\node_modules\react-native-svg\android\src\main\jni\CMakeLists.txt  Ýðìòò3½ œ§ØÖç3u UC:\GitHub\Schnappix\node_modules\react-native-svg\android\src\main\jni\CMakeLists.txt  Õ‡—Åô3½ œ§ØÖç3u
s s
qC:\GitHub\Schnappix\node_modules\react-native-view-shot\android\build\generated\source\codegen\jni\CMakeLists.txt  Ýðìòò3ê ú„§ðò3t qC:\GitHub\Schnappix\node_modules\react-native-view-shot\android\build\generated\source\codegen\jni\CMakeLists.txt  Õ‡—Åô3ê ú„§ðò3t
r r
pC:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\generated\source\codegen\jni\CMakeLists.txt  Ýðìòò3ê è„§ðò3³ pC:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\generated\source\codegen\jni\CMakeLists.txt  Õ‡—Åô3ê è„§ðò3³
° °
­C:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  Ýðìòò3k ­C:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  Õ‡—Åô3k
+2 -2
View File
@@ -92,8 +92,8 @@ android {
applicationId 'de.orfel.schnappix' applicationId 'de.orfel.schnappix'
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 16 versionCode 17
versionName "23.01.16" versionName "23.01.17"
buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\"" buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
} }
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -3,7 +3,7 @@
"newArchEnabled": true, "newArchEnabled": true,
"name": "Schnappix", "name": "Schnappix",
"slug": "Schnappix", "slug": "Schnappix",
"version": "23.01.16", "version": "23.01.17",
"orientation": "landscape", "orientation": "landscape",
"icon": "./Icon.png", "icon": "./Icon.png",
"userInterfaceStyle": "dark", "userInterfaceStyle": "dark",
@@ -13,7 +13,7 @@
}, },
"android": { "android": {
"package": "de.orfel.schnappix", "package": "de.orfel.schnappix",
"versionCode": 16, "versionCode": 17,
"adaptiveIcon": { "adaptiveIcon": {
"backgroundColor": "#050510", "backgroundColor": "#050510",
"foregroundImage": "./Icon-padded.png" "foregroundImage": "./Icon-padded.png"
@@ -1,2 +1,2 @@
#Mon May 25 16:29:05 CEST 2026 #Fri Jul 10 19:48:13 CEST 2026
gradle.version=8.9 gradle.version=9.2.0
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "schnappix", "name": "schnappix",
"version": "23.01.16", "version": "23.01.17",
"main": "index.ts", "main": "index.ts",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.7.2", "@fortawesome/fontawesome-svg-core": "^6.7.2",
+8 -10
View File
@@ -213,12 +213,10 @@ export default function AdminScreen({ currentSettings, onSave, onClose }: AdminS
const ipTrimmed = printerIp.trim(); const ipTrimmed = printerIp.trim();
const ipRegex = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/; const ipRegex = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/;
if (!ipTrimmed) {
Alert.alert('Ungültige Eingabe', 'Die Drucker-IP-Adresse darf nicht leer sein.'); // IP may be empty to enable digital-only mode
return; if (ipTrimmed !== '' && !ipRegex.test(ipTrimmed)) {
} Alert.alert('Ungültige Eingabe', 'Bitte gib eine gültige IP-Adresse ein oder lass das Feld leer (für rein digitalen Modus).');
if (!ipRegex.test(ipTrimmed)) {
Alert.alert('Ungültige Eingabe', 'Bitte gib eine gültige IP-Adresse ein (z.B. 192.168.1.100).');
return; return;
} }
@@ -356,7 +354,7 @@ export default function AdminScreen({ currentSettings, onSave, onClose }: AdminS
/> />
</View> </View>
<View style={styles.inputGroup}> <View style={styles.inputGroup}>
<Text style={styles.label}>Subtext (Footer)</Text> <Text style={styles.label}>Fußtext</Text>
<TextInput <TextInput
style={styles.input} style={styles.input}
placeholder="Display tippen! • Lächeln! • Foto schnappen!" placeholder="Display tippen! • Lächeln! • Foto schnappen!"
@@ -579,7 +577,7 @@ export default function AdminScreen({ currentSettings, onSave, onClose }: AdminS
placeholderTextColor={THEME.colors.textMuted} placeholderTextColor={THEME.colors.textMuted}
value={printerIp} value={printerIp}
onChangeText={setPrinterIp} onChangeText={setPrinterIp}
keyboardType="numeric" keyboardType="numbers-and-punctuation"
/> />
</View> </View>
<View style={styles.inputGroup}> <View style={styles.inputGroup}>
@@ -596,7 +594,7 @@ export default function AdminScreen({ currentSettings, onSave, onClose }: AdminS
/> />
</View> </View>
<View style={styles.toggleRow}> <View style={styles.toggleRow}>
<Text style={styles.toggleLabel}>Tablet-Frontkamera als Fallback erzwingen</Text> <Text style={styles.toggleLabel}>Frontkamera nutzen (Deaktiviert externe Kamera)</Text>
<Switch <Switch
value={useFrontCamera} value={useFrontCamera}
onValueChange={setUseFrontCamera} onValueChange={setUseFrontCamera}
@@ -605,7 +603,7 @@ export default function AdminScreen({ currentSettings, onSave, onClose }: AdminS
/> />
</View> </View>
<View style={styles.toggleRow}> <View style={styles.toggleRow}>
<Text style={styles.toggleLabel}>App-Protokollierung (Logs) aktivieren</Text> <Text style={styles.toggleLabel}>Logs aktivieren</Text>
<Switch <Switch
value={enableLogs} value={enableLogs}
onValueChange={setEnableLogs} onValueChange={setEnableLogs}
+2 -2
View File
@@ -348,7 +348,7 @@ export default function CameraScreen({
}); });
capturedUri = photo.uri; capturedUri = photo.uri;
} else { } else {
throw new Error('Kamera-Referenz ist nicht verfügbar. Bitte stelle sicher, dass die externe Kamera verbunden ist, oder aktiviere den Front-Kamera-Fallback in den Admin-Einstellungen.'); throw new Error('Externe Kamera nicht gefunden. Bitte stelle sicher, dass die externe Kamera richtig verbunden ist oder aktiviere die Front-Kamera in den Admin-Einstellungen (oben rechts).');
} }
} }
@@ -562,7 +562,7 @@ export default function CameraScreen({
<Text style={styles.modalTitle}>Admin-Zugang</Text> <Text style={styles.modalTitle}>Admin-Zugang</Text>
<Text style={styles.modalSub}>Passwort eingeben, um Einstellungen zu öffnen</Text> <Text style={styles.modalSub}>Passwort eingeben, um Einstellungen zu öffnen</Text>
<Text style={[styles.modalSub, { color: THEME.colors.error, marginTop: 10, fontSize: 14, fontStyle: 'italic' }]}> <Text style={[styles.modalSub, { color: THEME.colors.error, marginTop: 10, fontSize: 14, fontStyle: 'italic' }]}>
Tipp: Standardcode ist 1234. Bitte ändern! Ein Zurücksetzen ist nur durch Neuinstallation der App möglich. Standardcode: 1234. Bitte in den Einstellungen ändern! Ein Zurücksetzen ist nur durch Neuinstallation der App möglich.
</Text> </Text>
<TextInput <TextInput
+22 -24
View File
@@ -27,7 +27,6 @@ import { FRAMES } from '../data/frames';
interface PreviewScreenProps { interface PreviewScreenProps {
photoUris: string[]; photoUris: string[];
printerIp: string; printerIp: string;
onRetakeLast: () => void;
onAddAnother: () => void; onAddAnother: () => void;
onReset: () => void; onReset: () => void;
// Frame settings // Frame settings
@@ -39,6 +38,11 @@ interface PreviewScreenProps {
dateOverlayTransform: { x: number; y: number; rotation: number; scale: number }; dateOverlayTransform: { x: number; y: number; rotation: number; scale: number };
// Event text // Event text
eventText: string; eventText: string;
// Hoisted state
stickers: StickerData[];
setStickers: React.Dispatch<React.SetStateAction<StickerData[]>>;
selectedFrameId: string | null;
setSelectedFrameId: React.Dispatch<React.SetStateAction<string | null>>;
} }
type CollageLayout = 'single' | 'strip' | 'grid' | 'duo'; type CollageLayout = 'single' | 'strip' | 'grid' | 'duo';
@@ -46,7 +50,6 @@ type CollageLayout = 'single' | 'strip' | 'grid' | 'duo';
export default function PreviewScreen({ export default function PreviewScreen({
photoUris, photoUris,
printerIp, printerIp,
onRetakeLast,
onAddAnother, onAddAnother,
onReset, onReset,
frameMode, frameMode,
@@ -55,6 +58,10 @@ export default function PreviewScreen({
dateOverlay, dateOverlay,
dateOverlayTransform, dateOverlayTransform,
eventText, eventText,
stickers,
setStickers,
selectedFrameId,
setSelectedFrameId,
}: PreviewScreenProps) { }: PreviewScreenProps) {
const [layout, setLayout] = useState<CollageLayout>('single'); const [layout, setLayout] = useState<CollageLayout>('single');
const [isProcessing, setIsProcessing] = useState<boolean>(false); const [isProcessing, setIsProcessing] = useState<boolean>(false);
@@ -107,8 +114,6 @@ export default function PreviewScreen({
// Sticker state
const [stickers, setStickers] = useState<StickerData[]>([]);
const [selectedStickerId, setSelectedStickerId] = useState<string | null>(null); const [selectedStickerId, setSelectedStickerId] = useState<string | null>(null);
const mountedRef = useRef(true); const mountedRef = useRef(true);
@@ -147,10 +152,6 @@ export default function PreviewScreen({
}; };
}, [onReset]); }, [onReset]);
// Frame state
const [selectedFrameId, setSelectedFrameId] = useState<string | null>(
frameMode === 'always' ? initialFrameId : null
);
const viewShotRef = useRef<any>(null); const viewShotRef = useRef<any>(null);
@@ -372,26 +373,26 @@ export default function PreviewScreen({
}; };
}, [resetIdleTimer]); }, [resetIdleTimer]);
const handleRetakeClick = async () => { const handleAddAnotherClick = async () => {
logger.log('Action: Clicked Retake button'); logger.log('Action: Clicked Add Another button');
if (idleTimerRef.current) clearTimeout(idleTimerRef.current); if (idleTimerRef.current) clearTimeout(idleTimerRef.current);
if (!mountedRef.current) return; if (!mountedRef.current) return;
if (isProcessing) return; if (isProcessing) return;
if (stickers.length > 0 || layout !== 'single' || activeFrame || dateOverlay !== 'off') {
// Auto-save the intermediate collage before adding another photo
setIsProcessing(true); setIsProcessing(true);
try { try {
const capturedUri = await captureComposite(currentPhoto); const capturedUri = await captureComposite(currentPhoto);
if (!mountedRef.current) return; if (!mountedRef.current) return;
setStatusMessage('Wird vor dem Wiederholen gespeichert...'); setStatusMessage('Wird zwischengespeichert...');
await saveToGallery(capturedUri, 'Collage', eventText); await saveToGallery(capturedUri, 'Collage', eventText);
if (!mountedRef.current) return;
} catch (e) { } catch (e) {
if (!mountedRef.current) return; if (!mountedRef.current) return;
console.error('Failed to auto-save before retake:', e); console.error('Failed to auto-save before adding another:', e);
} }
setIsProcessing(false); setIsProcessing(false);
}
onRetakeLast(); onAddAnother();
}; };
// ── Render the collage ── // ── Render the collage ──
@@ -635,6 +636,7 @@ export default function PreviewScreen({
{/* Action Buttons */} {/* Action Buttons */}
<View style={styles.actions}> <View style={styles.actions}>
{!!printerIp?.trim() && (
<TouchableOpacity style={[styles.actionBtn, styles.printBtn, isProcessing && styles.btnDisabled, isSmallDevice && { marginBottom: THEME.spacing.sm }]} onPress={handlePrint} activeOpacity={0.8} disabled={isProcessing}> <TouchableOpacity style={[styles.actionBtn, styles.printBtn, isProcessing && styles.btnDisabled, isSmallDevice && { marginBottom: THEME.spacing.sm }]} onPress={handlePrint} activeOpacity={0.8} disabled={isProcessing}>
<LinearGradient <LinearGradient
colors={THEME.gradient.primary} colors={THEME.gradient.primary}
@@ -646,23 +648,19 @@ export default function PreviewScreen({
<Text style={styles.actionBtnText}>JETZT DRUCKEN</Text> <Text style={styles.actionBtnText}>JETZT DRUCKEN</Text>
</LinearGradient> </LinearGradient>
</TouchableOpacity> </TouchableOpacity>
)}
{photoUris.length < 4 && ( {photoUris.length < 4 && (
<TouchableOpacity style={[styles.actionBtn, styles.addBtn, isProcessing && styles.btnDisabled, isSmallDevice && { paddingVertical: THEME.spacing.sm, marginBottom: THEME.spacing.sm }]} onPress={onAddAnother} disabled={isProcessing}> <TouchableOpacity style={[styles.actionBtn, styles.addBtn, isProcessing && styles.btnDisabled, isSmallDevice && { paddingVertical: THEME.spacing.sm, marginBottom: THEME.spacing.sm }]} onPress={handleAddAnotherClick} disabled={isProcessing}>
<FontAwesomeIcon icon={faPlus} size={16} color={THEME.colors.text} style={{ marginRight: 8 }} /> <FontAwesomeIcon icon={faPlus} size={16} color={THEME.colors.text} style={{ marginRight: 8 }} />
<Text style={styles.actionBtnText}>Weiteres Foto aufnehmen</Text> <Text style={styles.actionBtnText}>Foto zur Collage hinzufügen</Text>
</TouchableOpacity> </TouchableOpacity>
)} )}
<View style={styles.rowActions}> <View style={styles.rowActions}>
<TouchableOpacity style={[styles.smallBtn, styles.retakeBtn, isProcessing && styles.btnDisabled]} onPress={handleRetakeClick} disabled={isProcessing}> <TouchableOpacity style={[styles.smallBtn, styles.resetBtn, isProcessing && styles.btnDisabled, { width: '100%' }]} onPress={handleExit} disabled={isProcessing}>
<FontAwesomeIcon icon={faRotateLeft} size={14} color={THEME.colors.error} style={{ marginRight: 6 }} />
<Text style={[styles.smallBtnText, { color: THEME.colors.error }]}>Wiederholen</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.smallBtn, styles.resetBtn, isProcessing && styles.btnDisabled]} onPress={handleExit} disabled={isProcessing}>
<FontAwesomeIcon icon={faRightFromBracket} size={14} color={THEME.colors.textMuted} style={{ marginRight: 6 }} /> <FontAwesomeIcon icon={faRightFromBracket} size={14} color={THEME.colors.textMuted} style={{ marginRight: 6 }} />
<Text style={styles.smallBtnText}>Beenden</Text> <Text style={styles.smallBtnText}>Beenden</Text>
</TouchableOpacity> </TouchableOpacity>
+3 -2
View File
@@ -18,8 +18,9 @@ export interface PrintOptions {
export async function printImageLocal(imageUri: string, options: PrintOptions): Promise<void> { export async function printImageLocal(imageUri: string, options: PrintOptions): Promise<void> {
const { ipAddress, jobName = 'Schnappix Photo', username = 'Schnappix Kiosk' } = options; const { ipAddress, jobName = 'Schnappix Photo', username = 'Schnappix Kiosk' } = options;
if (!ipAddress) { if (!ipAddress || ipAddress.trim() === '') {
throw new Error('Drucker-IP-Adresse ist erforderlich.'); console.log('Drucken übersprungen: Keine Drucker-IP-Adresse hinterlegt (Digitaler Modus).');
return;
} }
// 1. Read the image file from local storage as Base64 and convert to binary Buffer // 1. Read the image file from local storage as Base64 and convert to binary Buffer
+1 -1
View File
@@ -48,7 +48,7 @@ const DEFAULT_SETTINGS: AppSettings = {
burstIntervalSec: 5, burstIntervalSec: 5,
welcomeText: 'Zeit für ein Erinnerungsfoto!', welcomeText: 'Zeit für ein Erinnerungsfoto!',
footerText: 'Display tippen! • Lächeln! • Foto schnappen!', footerText: 'Display tippen! • Lächeln! • Foto schnappen!',
useFrontCamera: false, useFrontCamera: true,
enableLogs: true, enableLogs: true,
}; };