diff --git a/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/.ninja_log b/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/.ninja_log index e50df8c7..6dedaf62 100644 --- a/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/.ninja_log +++ b/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/.ninja_log @@ -82,3 +82,5 @@ 6 52 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/CMakeFiles/cmake.verify_globs 5250f1b80cb55465 18 2342 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/CMakeFiles/cmake.verify_globs 5250f1b80cb55465 4 41 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/CMakeFiles/cmake.verify_globs 5250f1b80cb55465 +4 46 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/CMakeFiles/cmake.verify_globs 5250f1b80cb55465 +2 34 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/CMakeFiles/cmake.verify_globs 5250f1b80cb55465 diff --git a/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/configure_fingerprint.bin b/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/configure_fingerprint.bin index 6c2e116c..340d35cd 100644 --- a/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/configure_fingerprint.bin +++ b/android/app/.cxx/RelWithDebInfo/3x5j4n2e/arm64-v8a/configure_fingerprint.bin @@ -2,41 +2,41 @@ C/C++ Structured Logg e cC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\additional_project_files.txtC A -?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  ïú£Ü�4Å, ½Ñªðò3d +?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  �¤Êì�4Å, ½Ñªðò3d b -`C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\android_gradle_build.json  ïú£Ü�4û" ÂѪðò3i +`C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\android_gradle_build.json  �¤Êì�4û" ÂѪðò3i g -eC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\android_gradle_build_mini.json  ïú£Ü�4ï  Òªðò3V +eC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\android_gradle_build_mini.json  �¤Êì�4ï  Òªðò3V T -RC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\build.ninja  ïú£Ü�4œÞ åͪðò3Z +RC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\build.ninja  �¤Êì�4œÞ åͪðò3Z X -VC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\build.ninja.txt  ïú£Ü�4_ +VC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\build.ninja.txt  �¤Êì�4_ ] -[C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\build_file_index.txt  ïú£Ü�4� ¨Òªðò3` +[C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\build_file_index.txt  �¤Êì�4� ¨Òªðò3` ^ -\C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\compile_commands.json  ïú£Ü�4‘Ø ãͪðò3d +\C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\compile_commands.json  �¤Êì�4‘Ø ãͪðò3d b -`C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\compile_commands.json.bin  ïú£Ü�4 Ê„ ãͪðò3j +`C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\compile_commands.json.bin  �¤Êì�4 Ê„ ãͪðò3j h -fC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\metadata_generation_command.txt  ïú£Ü�4 +fC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\metadata_generation_command.txt  �¤Êì�4 ¸ §Òªðò3] [ -YC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\prefab_config.json  ïú£Ü�4 € ¨Òªðò3b +YC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\prefab_config.json  �¤Êì�4 € ¨Òªðò3b ` -^C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\symbol_folder_index.txt  ïú£Ü�4  ] ¨Òªðò3{ +^C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\arm64-v8a\symbol_folder_index.txt  �¤Êì�4  ] ¨Òªðò3{ y -wC:\GitHub\Schnappix\node_modules\react-native-gesture-handler\android\build\generated\source\codegen\jni\CMakeLists.txt  ïú£Ü�4 ¾ Ü…§ðò3v +wC:\GitHub\Schnappix\node_modules\react-native-gesture-handler\android\build\generated\source\codegen\jni\CMakeLists.txt  �¤Êì�4 ¾ Ü…§ðò3v t -rC:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\generated\source\codegen\jni\CMakeLists.txt  ïú£Ü�4ö ùާðò3µ +rC:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\generated\source\codegen\jni\CMakeLists.txt  �¤Êì�4ö ùާðò3µ ² -¯C:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  ïú£Ü�4Y +¯C:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  �¤Êì�4Y W -UC:\GitHub\Schnappix\node_modules\react-native-svg\android\src\main\jni\CMakeLists.txt  ïú£Ü�4½ œ§ØÖç3u +UC:\GitHub\Schnappix\node_modules\react-native-svg\android\src\main\jni\CMakeLists.txt  �¤Êì�4½ œ§ØÖç3u s -qC:\GitHub\Schnappix\node_modules\react-native-view-shot\android\build\generated\source\codegen\jni\CMakeLists.txt  ïú£Ü�4ê ú„§ðò3t +qC:\GitHub\Schnappix\node_modules\react-native-view-shot\android\build\generated\source\codegen\jni\CMakeLists.txt  �¤Êì�4ê ú„§ðò3t r -pC:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\generated\source\codegen\jni\CMakeLists.txt  ïú£Ü�4ê è„§ðò3³ +pC:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\generated\source\codegen\jni\CMakeLists.txt  �¤Êì�4ê è„§ðò3³ ° -­C:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  ïú£Ü�4k +­C:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  �¤Êì�4k i -gC:\GitHub\Schnappix\node_modules\react-native\ReactAndroid\cmake-utils\default-app-setup\CMakeLists.txt  ïú£Ü�4ð ®¡ÈÑç3 \ No newline at end of file +gC:\GitHub\Schnappix\node_modules\react-native\ReactAndroid\cmake-utils\default-app-setup\CMakeLists.txt  �¤Êì�4ð ®¡ÈÑç3 \ No newline at end of file diff --git a/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/.ninja_log b/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/.ninja_log index 211b2720..722cdbec 100644 --- a/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/.ninja_log +++ b/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/.ninja_log @@ -82,3 +82,5 @@ 7 60 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/CMakeFiles/cmake.verify_globs 1eb2d1da6ebc2e74 3 49 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/CMakeFiles/cmake.verify_globs 1eb2d1da6ebc2e74 6 40 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/CMakeFiles/cmake.verify_globs 1eb2d1da6ebc2e74 +6 42 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/CMakeFiles/cmake.verify_globs 1eb2d1da6ebc2e74 +5 42 0 C:/GitHub/Schnappix/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/CMakeFiles/cmake.verify_globs 1eb2d1da6ebc2e74 diff --git a/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/configure_fingerprint.bin b/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/configure_fingerprint.bin index d134a4c9..61490a1d 100644 --- a/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/configure_fingerprint.bin +++ b/android/app/.cxx/RelWithDebInfo/3x5j4n2e/armeabi-v7a/configure_fingerprint.bin @@ -2,41 +2,41 @@ C/C++ Structured Logi g eC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\additional_project_files.txtC A -?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  „†¤Ü�4ý, ÷íðò3f +?com.android.build.gradle.internal.cxx.io.EncodedFileFingerPrint  ‰§Êì�4ý, ÷íðò3f d -bC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\android_gradle_build.json  „†¤Ü�4�# øÃ­ðò3k +bC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\android_gradle_build.json  ‰§Êì�4�# øÃ­ðò3k i -gC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\android_gradle_build_mini.json  „†¤Ü�4‘ ŸÄ­ðò3X +gC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\android_gradle_build_mini.json  ‰§Êì�4‘ ŸÄ­ðò3X V -TC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\build.ninja  „†¤Ü�4Áå âÀ­ðò3\ +TC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\build.ninja  ‰§Êì�4Áå âÀ­ðò3\ Z -XC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\build.ninja.txt  „†¤Ü�4a +XC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\build.ninja.txt  ‰§Êì�4a _ -]C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\build_file_index.txt  „†¤Ü�4�  Ä­ðò3b +]C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\build_file_index.txt  ‰§Êì�4�  Ä­ðò3b ` -^C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\compile_commands.json  „†¤Ü�4´à àÀ­ðò3f +^C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\compile_commands.json  ‰§Êì�4´à àÀ­ðò3f d -bC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\compile_commands.json.bin  „†¤Ü�4 ò„ àÀ­ðò3l +bC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\compile_commands.json.bin  ‰§Êì�4 ò„ àÀ­ðò3l j -hC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\metadata_generation_command.txt  „†¤Ü�4 +hC:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\metadata_generation_command.txt  ‰§Êì�4 Ä ŸÄ­ðò3_ ] -[C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\prefab_config.json  „†¤Ü�4 € ŸÄ­ðò3d +[C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\prefab_config.json  ‰§Êì�4 € ŸÄ­ðò3d b -`C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\symbol_folder_index.txt  „†¤Ü�4  _  Ä­ðò3{ +`C:\GitHub\Schnappix\android\app\.cxx\RelWithDebInfo\3x5j4n2e\armeabi-v7a\symbol_folder_index.txt  ‰§Êì�4  _  Ä­ðò3{ y -wC:\GitHub\Schnappix\node_modules\react-native-gesture-handler\android\build\generated\source\codegen\jni\CMakeLists.txt  „†¤Ü�4 ¾ Ü…§ðò3v +wC:\GitHub\Schnappix\node_modules\react-native-gesture-handler\android\build\generated\source\codegen\jni\CMakeLists.txt  ‰§Êì�4 ¾ Ü…§ðò3v t -rC:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\generated\source\codegen\jni\CMakeLists.txt  „†¤Ü�4ö ùާðò3µ +rC:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\generated\source\codegen\jni\CMakeLists.txt  ‰§Êì�4ö ùާðò3µ ² -¯C:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  „†¤Ü�4Y +¯C:\GitHub\Schnappix\node_modules\react-native-reanimated\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  ‰§Êì�4Y W -UC:\GitHub\Schnappix\node_modules\react-native-svg\android\src\main\jni\CMakeLists.txt  „†¤Ü�4½ œ§ØÖç3u +UC:\GitHub\Schnappix\node_modules\react-native-svg\android\src\main\jni\CMakeLists.txt  ‰§Êì�4½ œ§ØÖç3u s -qC:\GitHub\Schnappix\node_modules\react-native-view-shot\android\build\generated\source\codegen\jni\CMakeLists.txt  „†¤Ü�4ê ú„§ðò3t +qC:\GitHub\Schnappix\node_modules\react-native-view-shot\android\build\generated\source\codegen\jni\CMakeLists.txt  ‰§Êì�4ê ú„§ðò3t r -pC:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\generated\source\codegen\jni\CMakeLists.txt  „†¤Ü�4ê è„§ðò3³ +pC:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\generated\source\codegen\jni\CMakeLists.txt  ‰§Êì�4ê è„§ðò3³ ° -­C:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  „†¤Ü�4k +­C:\GitHub\Schnappix\node_modules\react-native-worklets\android\build\intermediates\prefab_package_configuration\release\prefabReleaseConfigurePackage\prefab_publication.json  ‰§Êì�4k i -gC:\GitHub\Schnappix\node_modules\react-native\ReactAndroid\cmake-utils\default-app-setup\CMakeLists.txt  „†¤Ü�4ð ®¡ÈÑç3 \ No newline at end of file +gC:\GitHub\Schnappix\node_modules\react-native\ReactAndroid\cmake-utils\default-app-setup\CMakeLists.txt  ‰§Êì�4ð ®¡ÈÑç3 \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 757d4e24..ffc89085 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -92,8 +92,8 @@ android { applicationId 'de.orfel.schnappix' minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 39 - versionName "23.01.39" + versionCode 40 + versionName "23.01.40" buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\"" } diff --git a/apks/Schnappix_v23.01.40.aab b/apks/Schnappix_v23.01.40.aab new file mode 100644 index 00000000..3c60048b Binary files /dev/null and b/apks/Schnappix_v23.01.40.aab differ diff --git a/apks/Schnappix_v23.01.40.apk b/apks/Schnappix_v23.01.40.apk new file mode 100644 index 00000000..75dcd9f9 --- /dev/null +++ b/apks/Schnappix_v23.01.40.apk @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cc77fe7bc4f3051a3fd7c6cf279dbea846a1cc71bd20c1118211c9775e0d7cf0 +size 116898195 diff --git a/app.json b/app.json index 6e564a6b..c4622945 100644 --- a/app.json +++ b/app.json @@ -3,7 +3,7 @@ "newArchEnabled": true, "name": "Schnappix", "slug": "Schnappix", - "version": "23.01.39", + "version": "23.01.40", "orientation": "landscape", "icon": "./Icon.png", "userInterfaceStyle": "dark", @@ -13,7 +13,7 @@ }, "android": { "package": "de.orfel.schnappix", - "versionCode": 39, + "versionCode": 40, "usesCleartextTraffic": true, "adaptiveIcon": { "backgroundColor": "#050510", diff --git a/modules/kiosk-mode/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/modules/kiosk-mode/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock index a4198150..b598c1d2 100644 Binary files a/modules/kiosk-mode/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock and b/modules/kiosk-mode/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/modules/kiosk-mode/android/.gradle/buildOutputCleanup/cache.properties b/modules/kiosk-mode/android/.gradle/buildOutputCleanup/cache.properties index 76e7d6b4..2e9c9105 100644 --- a/modules/kiosk-mode/android/.gradle/buildOutputCleanup/cache.properties +++ b/modules/kiosk-mode/android/.gradle/buildOutputCleanup/cache.properties @@ -1,2 +1,2 @@ -#Mon Aug 17 18:06:08 CEST 2026 -gradle.version=9.2.0 +#Thu Aug 20 07:04:03 CEST 2026 +gradle.version=8.9 diff --git a/modules/kiosk-mode/android/src/main/java/expo/modules/kioskmode/KioskModeModule.kt b/modules/kiosk-mode/android/src/main/java/expo/modules/kioskmode/KioskModeModule.kt index c1a45a77..6e99426d 100644 --- a/modules/kiosk-mode/android/src/main/java/expo/modules/kioskmode/KioskModeModule.kt +++ b/modules/kiosk-mode/android/src/main/java/expo/modules/kioskmode/KioskModeModule.kt @@ -59,5 +59,56 @@ class KioskModeModule : Module() { val dpm = activity.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager return@Function dpm.isDeviceOwnerApp(activity.packageName) } + + AsyncFunction("saveImageToAlbum") { localUri: String, albumName: String, fileName: String, promise: expo.modules.kotlin.Promise -> + val context = appContext.reactContext ?: run { + promise.reject("ERR_CONTEXT", "React Context is null", null) + return@AsyncFunction + } + + try { + val resolver = context.contentResolver + val values = android.content.ContentValues().apply { + put(android.provider.MediaStore.Images.Media.DISPLAY_NAME, fileName) + put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg") + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { + put(android.provider.MediaStore.Images.Media.RELATIVE_PATH, "Pictures/${albumName}") + put(android.provider.MediaStore.Images.Media.IS_PENDING, 1) + } + } + + val collection = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { + android.provider.MediaStore.Images.Media.getContentUri(android.provider.MediaStore.VOLUME_EXTERNAL_PRIMARY) + } else { + android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI + } + + val uri = resolver.insert(collection, values) + if (uri == null) { + promise.reject("ERR_INSERT", "Failed to create new MediaStore record", null) + return@AsyncFunction + } + + // Remove file:// prefix if present + val cleanLocalUri = localUri.replace("file://", "") + val localFile = java.io.File(cleanLocalUri) + + resolver.openOutputStream(uri)?.use { out -> + java.io.FileInputStream(localFile).use { input -> + input.copyTo(out) + } + } + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { + values.clear() + values.put(android.provider.MediaStore.Images.Media.IS_PENDING, 0) + resolver.update(uri, values, null, null) + } + + promise.resolve(uri.toString()) + } catch (e: Exception) { + promise.reject("ERR_SAVE", e.message, e) + } + } } } diff --git a/modules/kiosk-mode/index.ts b/modules/kiosk-mode/index.ts index 35a85ab4..18082d80 100644 --- a/modules/kiosk-mode/index.ts +++ b/modules/kiosk-mode/index.ts @@ -15,6 +15,7 @@ export interface KioskModeInterface { stopKiosk(): boolean; isKioskActive(): boolean; isDeviceOwner(): boolean; + saveImageToAlbum(localUri: string, albumName: string, fileName: string): Promise; } const KioskModeProxy: KioskModeInterface = { @@ -29,6 +30,9 @@ const KioskModeProxy: KioskModeInterface = { }, isDeviceOwner() { return KioskMode ? KioskMode.isDeviceOwner() : false; + }, + async saveImageToAlbum(localUri: string, albumName: string, fileName: string): Promise { + return KioskMode ? await KioskMode.saveImageToAlbum(localUri, albumName, fileName) : localUri; } }; diff --git a/package.json b/package.json index 7a1a366a..2c22ded9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "schnappix", - "version": "23.01.39", + "version": "23.01.40", "main": "index.ts", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.7.2", diff --git a/src/screens/CameraScreen.tsx b/src/screens/CameraScreen.tsx index c5752074..de722cdf 100644 --- a/src/screens/CameraScreen.tsx +++ b/src/screens/CameraScreen.tsx @@ -703,23 +703,26 @@ export default function CameraScreen({ {Platform.OS === 'android' ? ( <> - { - logger.log('USB Camera is fully ready.'); - }} - onCameraError={(event: any) => { - logger.error('USB Camera Error from Native:', event.nativeEvent); - }} - onCameraState={(event: any) => { - logger.log(`USB Camera State: ${JSON.stringify(event.nativeEvent)}`); - }} - /> - {!isUsbConnected && ( + {/* Only mount USB camera when active to ensure it resets properly after preview */} + {!isIdle && ( + { + logger.log('USB Camera is fully ready.'); + }} + onCameraError={(event: any) => { + logger.error('USB Camera Error from Native:', event.nativeEvent); + }} + onCameraState={(event: any) => { + logger.log(`USB Camera State: ${JSON.stringify(event.nativeEvent)}`); + }} + /> + )} + {!isUsbConnected && !isIdle && ( useFrontCamera ? ( True if permissions are granted. */ export async function requestStoragePermission(): Promise { - const { status, canAskAgain } = await getPermissionsAsync(true); - if (status === 'granted') { - return true; - } - - if (canAskAgain) { - const { status: newStatus } = await requestPermissionsAsync(true); - return newStatus === 'granted'; - } - - // On Android 13+, writeOnly permissions don't block MediaStore inserts + // We don't use expo-media-library anymore for saving, so we just assume we have permission + // Android 10+ MediaStore API with RELATIVE_PATH doesn't require READ/WRITE permissions to insert! return true; } @@ -38,11 +29,6 @@ function getFormattedDateTime(): string { */ export async function saveToGallery(localUri: string, type: 'Raw' | 'Collage', eventName: string): Promise { logger.log(`Starting saveToGallery for ${localUri}`); - const hasPermission = await requestStoragePermission(); - if (!hasPermission) { - logger.error('Storage permission not granted. Cannot save photo to gallery.'); - throw new Error('Storage permission not granted. Cannot save photo to gallery.'); - } // Clean event name for file system usage const safeEventName = eventName.replace(/[^a-zA-Z0-9_-]/g, '').trim() || 'Event'; @@ -51,47 +37,18 @@ export async function saveToGallery(localUri: string, type: 'Raw' | 'Collage', e // Format: EventName_YYYY-MM-DD_HH-mm-ss_Type.jpg const newFileName = `${safeEventName}_${timestamp}_${type}.${fileExtension}`; - const newLocalUri = `${FileSystem.cacheDirectory}${newFileName}`; - logger.log(`Types: createAsset=${typeof createAssetAsync}, getAlbum=${typeof getAlbumAsync}, createAlbum=${typeof createAlbumAsync}, addAssets=${typeof addAssetsToAlbumAsync}`); - - let asset; - try { - // 1. Create a media asset directly from the local uri - asset = await createAssetAsync(localUri); - } catch (e: any) { - logger.error(`Error in createAssetAsync: ${e.message}`, e); - throw e; - } - // Define album name const subFolder = type === 'Raw' ? 'Originale' : 'Collagen'; const ALBUM_NAME = `Schnappix - ${safeEventName} - ${subFolder}`; try { - // 2. Check if the album already exists - const album = await getAlbumAsync(ALBUM_NAME); - - if (!album) { - // 3. If it doesn't exist, create it with our asset - await createAlbumAsync(ALBUM_NAME, asset, true); - logger.log(`Created new album "${ALBUM_NAME}" and copied photo.`); - } else { - // 4. If it exists, add our asset to it - await addAssetsToAlbumAsync([asset], album, true); - logger.log(`Copied photo to existing album "${ALBUM_NAME}".`); - } - - return asset.uri; + const uri = await KioskMode.saveImageToAlbum(localUri, ALBUM_NAME, newFileName); + logger.log(`Successfully saved photo to album "${ALBUM_NAME}" directly via MediaStore: ${uri}`); + return uri; } catch (e: any) { - logger.warn(`Could not save asset to album ${ALBUM_NAME} (likely due to write-only permissions on Android 13+). Photo is still saved in main gallery: ${e?.message || e}`); - return asset.uri; - } finally { - // Cleanup our temp renamed file - try { - await FileSystem.deleteAsync(newLocalUri, { idempotent: true }); - } catch (e) { - // ignore - } + logger.error(`Error saving photo to MediaStore album ${ALBUM_NAME}: ${e?.message || e}`); + // Fallback: don't crash, return localUri just so the app continues + return localUri; } }