react-native-ensys-camera-x 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CustomCamera.podspec +20 -0
- package/LICENSE +20 -0
- package/README.md +833 -0
- package/android/build.gradle +135 -0
- package/android/consumer-rules.pro +47 -0
- package/android/src/main/AndroidManifest.xml +72 -0
- package/android/src/main/java/android/print/PdfPrint.java +51 -0
- package/android/src/main/java/com/customcamera/AnimatedImageViewManager.kt +199 -0
- package/android/src/main/java/com/customcamera/AudioPlayerView.kt +322 -0
- package/android/src/main/java/com/customcamera/AudioRecorder.kt +506 -0
- package/android/src/main/java/com/customcamera/BarcodeScannerActivity.kt +361 -0
- package/android/src/main/java/com/customcamera/BlurBackgroundView.kt +199 -0
- package/android/src/main/java/com/customcamera/CacheCleanupManager.kt +386 -0
- package/android/src/main/java/com/customcamera/CameraAspectRatioMode.kt +77 -0
- package/android/src/main/java/com/customcamera/CameraAsset.kt +211 -0
- package/android/src/main/java/com/customcamera/CameraTheme.kt +479 -0
- package/android/src/main/java/com/customcamera/CompressionCacheStore.kt +504 -0
- package/android/src/main/java/com/customcamera/CompressionFileNameUtils.kt +7 -0
- package/android/src/main/java/com/customcamera/CompressionProfile.kt +195 -0
- package/android/src/main/java/com/customcamera/CustomCameraActivity.kt +7291 -0
- package/android/src/main/java/com/customcamera/CustomCameraFileProvider.kt +9 -0
- package/android/src/main/java/com/customcamera/CustomCameraModule.kt +2479 -0
- package/android/src/main/java/com/customcamera/CustomCameraPackage.kt +53 -0
- package/android/src/main/java/com/customcamera/DisplayUtils.kt +9 -0
- package/android/src/main/java/com/customcamera/DocumentPreviewView.kt +846 -0
- package/android/src/main/java/com/customcamera/DrawingView.kt +214 -0
- package/android/src/main/java/com/customcamera/EmojiPickerData.kt +228 -0
- package/android/src/main/java/com/customcamera/FilterStripAdapter.kt +158 -0
- package/android/src/main/java/com/customcamera/GifSupport.kt +215 -0
- package/android/src/main/java/com/customcamera/GlobalAudioPlayer.kt +320 -0
- package/android/src/main/java/com/customcamera/ImageExporter.kt +1394 -0
- package/android/src/main/java/com/customcamera/ImageFormatSupport.kt +163 -0
- package/android/src/main/java/com/customcamera/Localization.kt +206 -0
- package/android/src/main/java/com/customcamera/MediaAdapters.kt +758 -0
- package/android/src/main/java/com/customcamera/MediaCacheManager.kt +782 -0
- package/android/src/main/java/com/customcamera/MediaExportFormats.kt +201 -0
- package/android/src/main/java/com/customcamera/MediaFileIo.kt +310 -0
- package/android/src/main/java/com/customcamera/MediaMetadataStore.kt +494 -0
- package/android/src/main/java/com/customcamera/MediaPreviewEditor.kt +14865 -0
- package/android/src/main/java/com/customcamera/MediaPublisher.kt +423 -0
- package/android/src/main/java/com/customcamera/MediaStorageWorkflow.kt +722 -0
- package/android/src/main/java/com/customcamera/MediaStoreRepository.kt +378 -0
- package/android/src/main/java/com/customcamera/MediaThumbnailView.kt +286 -0
- package/android/src/main/java/com/customcamera/MediaUtils.kt +37 -0
- package/android/src/main/java/com/customcamera/NativeVideoViewManager.kt +845 -0
- package/android/src/main/java/com/customcamera/OfficeDocumentConverter.kt +2791 -0
- package/android/src/main/java/com/customcamera/PendingCaptureCrops.kt +88 -0
- package/android/src/main/java/com/customcamera/PowerPointPreview.kt +4077 -0
- package/android/src/main/java/com/customcamera/RecentPickerStore.kt +74 -0
- package/android/src/main/java/com/customcamera/SecureFileEraser.kt +411 -0
- package/android/src/main/java/com/customcamera/SecureKeyModule.kt +88 -0
- package/android/src/main/java/com/customcamera/SecureMediaDeleter.kt +493 -0
- package/android/src/main/java/com/customcamera/StickerPickerData.kt +107 -0
- package/android/src/main/java/com/customcamera/SvgDrawable.kt +175 -0
- package/android/src/main/java/com/customcamera/SvgIconViewManager.kt +77 -0
- package/android/src/main/java/com/customcamera/TextEntryController.kt +553 -0
- package/android/src/main/java/com/customcamera/ThumbnailLoader.kt +455 -0
- package/android/src/main/java/com/customcamera/UploadService.kt +909 -0
- package/android/src/main/java/com/customcamera/VideoEditUtils.kt +210 -0
- package/android/src/main/java/com/customcamera/VideoRotationTranscoder.kt +1992 -0
- package/android/src/main/java/com/customcamera/gif/AnimatedGifEncoder.kt +473 -0
- package/android/src/main/java/com/customcamera/gif/GifDecoder.kt +690 -0
- package/android/src/main/java/com/customcamera/gif/GifFramesDrawable.kt +160 -0
- package/android/src/main/java/com/customcamera/gif/GifHttp.kt +112 -0
- package/android/src/main/java/com/customcamera/gif/GifImageLoader.kt +186 -0
- package/android/src/main/java/com/customcamera/gif/GifModels.kt +74 -0
- package/android/src/main/java/com/customcamera/gif/GifProvider.kt +49 -0
- package/android/src/main/java/com/customcamera/gif/GifProviders.kt +27 -0
- package/android/src/main/java/com/customcamera/gif/GifRepository.kt +124 -0
- package/android/src/main/java/com/customcamera/gif/GifSafety.kt +33 -0
- package/android/src/main/java/com/customcamera/gif/GiphyGifProvider.kt +146 -0
- package/android/src/main/java/com/customcamera/gif/LZWEncoder.kt +258 -0
- package/android/src/main/java/com/customcamera/gif/NeuQuant.kt +435 -0
- package/android/src/main/java/com/customcamera/gif/TenorGifProvider.kt +147 -0
- package/android/src/main/res/drawable/bg_brush_selected.xml +5 -0
- package/android/src/main/res/drawable/bg_color_swatch.xml +5 -0
- package/android/src/main/res/drawable/bg_editor_toolbar.xml +6 -0
- package/android/src/main/res/drawable/bg_icon_circle.xml +5 -0
- package/android/src/main/res/drawable/bg_icon_circle_light.xml +5 -0
- package/android/src/main/res/drawable/bg_mode_tab_active.xml +6 -0
- package/android/src/main/res/drawable/bg_pill.xml +6 -0
- package/android/src/main/res/drawable/bg_recording_dot.xml +6 -0
- package/android/src/main/res/drawable/bg_selection_badge.xml +8 -0
- package/android/src/main/res/drawable/bg_send_button.xml +5 -0
- package/android/src/main/res/drawable/bg_shutter_inner.xml +5 -0
- package/android/src/main/res/drawable/bg_shutter_recording.xml +6 -0
- package/android/src/main/res/drawable/bg_shutter_ring.xml +8 -0
- package/android/src/main/res/drawable/bg_shutter_video_idle.xml +5 -0
- package/android/src/main/res/drawable/bg_thumbnail.xml +9 -0
- package/android/src/main/res/drawable/ic_aspect_ratio.xml +17 -0
- package/android/src/main/res/drawable/ic_audio.xml +10 -0
- package/android/src/main/res/drawable/ic_back.xml +10 -0
- package/android/src/main/res/drawable/ic_brush_medium.xml +12 -0
- package/android/src/main/res/drawable/ic_brush_thick.xml +12 -0
- package/android/src/main/res/drawable/ic_brush_thin.xml +12 -0
- package/android/src/main/res/drawable/ic_check.xml +17 -0
- package/android/src/main/res/drawable/ic_chevron_down.xml +10 -0
- package/android/src/main/res/drawable/ic_chevron_up.xml +13 -0
- package/android/src/main/res/drawable/ic_clear_drawing.xml +10 -0
- package/android/src/main/res/drawable/ic_close.xml +10 -0
- package/android/src/main/res/drawable/ic_cover.xml +9 -0
- package/android/src/main/res/drawable/ic_crop.xml +10 -0
- package/android/src/main/res/drawable/ic_delete.xml +9 -0
- package/android/src/main/res/drawable/ic_document.xml +10 -0
- package/android/src/main/res/drawable/ic_done.xml +10 -0
- package/android/src/main/res/drawable/ic_download.xml +10 -0
- package/android/src/main/res/drawable/ic_emoji.xml +10 -0
- package/android/src/main/res/drawable/ic_filter.xml +10 -0
- package/android/src/main/res/drawable/ic_flash_auto.xml +7 -0
- package/android/src/main/res/drawable/ic_flash_off.xml +23 -0
- package/android/src/main/res/drawable/ic_flash_on.xml +16 -0
- package/android/src/main/res/drawable/ic_flip.xml +15 -0
- package/android/src/main/res/drawable/ic_gallery.xml +10 -0
- package/android/src/main/res/drawable/ic_gif.xml +24 -0
- package/android/src/main/res/drawable/ic_lock.xml +19 -0
- package/android/src/main/res/drawable/ic_lock_open.xml +22 -0
- package/android/src/main/res/drawable/ic_marker.xml +10 -0
- package/android/src/main/res/drawable/ic_more_vert.xml +18 -0
- package/android/src/main/res/drawable/ic_overlay_close.xml +19 -0
- package/android/src/main/res/drawable/ic_overlay_resize.xml +18 -0
- package/android/src/main/res/drawable/ic_pause.xml +10 -0
- package/android/src/main/res/drawable/ic_photo_mode.xml +10 -0
- package/android/src/main/res/drawable/ic_play.xml +10 -0
- package/android/src/main/res/drawable/ic_redo.xml +10 -0
- package/android/src/main/res/drawable/ic_rotate.xml +9 -0
- package/android/src/main/res/drawable/ic_send.xml +10 -0
- package/android/src/main/res/drawable/ic_share.xml +10 -0
- package/android/src/main/res/drawable/ic_stat_upload.xml +10 -0
- package/android/src/main/res/drawable/ic_sticker.xml +24 -0
- package/android/src/main/res/drawable/ic_text.xml +10 -0
- package/android/src/main/res/drawable/ic_text_align_center.xml +11 -0
- package/android/src/main/res/drawable/ic_text_align_left.xml +11 -0
- package/android/src/main/res/drawable/ic_text_align_right.xml +11 -0
- package/android/src/main/res/drawable/ic_text_bg.xml +11 -0
- package/android/src/main/res/drawable/ic_trim.xml +23 -0
- package/android/src/main/res/drawable/ic_undo.xml +10 -0
- package/android/src/main/res/drawable/ic_video_mode.xml +10 -0
- package/android/src/main/res/drawable/ic_video_note.xml +13 -0
- package/android/src/main/res/drawable/ic_volume_off.xml +9 -0
- package/android/src/main/res/drawable/ic_volume_on.xml +9 -0
- package/android/src/main/res/drawable/sticker_heart.xml +9 -0
- package/android/src/main/res/drawable/sticker_smile.xml +9 -0
- package/android/src/main/res/drawable/sticker_star.xml +9 -0
- package/android/src/main/res/drawable/sticker_thumbsup.xml +9 -0
- package/android/src/main/res/values/colors.xml +34 -0
- package/android/src/main/res/values/ids.xml +15 -0
- package/android/src/main/res/values/strings.xml +15 -0
- package/android/src/main/res/values/styles.xml +20 -0
- package/android/src/main/res/xml/file_paths.xml +34 -0
- package/ios/CustomCamera.h +5 -0
- package/ios/CustomCamera.mm +214 -0
- package/lib/module/AudioPlayerContext.js +233 -0
- package/lib/module/AudioPlayerContext.js.map +1 -0
- package/lib/module/CameraPreview.js +304 -0
- package/lib/module/CameraPreview.js.map +1 -0
- package/lib/module/NativeAnimatedImageView.js +41 -0
- package/lib/module/NativeAnimatedImageView.js.map +1 -0
- package/lib/module/NativeAudioPlayerView.js +33 -0
- package/lib/module/NativeAudioPlayerView.js.map +1 -0
- package/lib/module/NativeBlurView.js +35 -0
- package/lib/module/NativeBlurView.js.map +1 -0
- package/lib/module/NativeCustomCamera.js +128 -0
- package/lib/module/NativeCustomCamera.js.map +1 -0
- package/lib/module/NativeCustomCamera.web.js +143 -0
- package/lib/module/NativeCustomCamera.web.js.map +1 -0
- package/lib/module/NativeCustomVideoView.js +5 -0
- package/lib/module/NativeCustomVideoView.js.map +1 -0
- package/lib/module/NativeDocumentPreviewView.js +156 -0
- package/lib/module/NativeDocumentPreviewView.js.map +1 -0
- package/lib/module/NativeMediaThumbnailView.js +110 -0
- package/lib/module/NativeMediaThumbnailView.js.map +1 -0
- package/lib/module/NativeSvgIcon.js +32 -0
- package/lib/module/NativeSvgIcon.js.map +1 -0
- package/lib/module/ResponsivePreviewContainer.js +171 -0
- package/lib/module/ResponsivePreviewContainer.js.map +1 -0
- package/lib/module/accessibility.js +61 -0
- package/lib/module/accessibility.js.map +1 -0
- package/lib/module/config.js +352 -0
- package/lib/module/config.js.map +1 -0
- package/lib/module/cpuOptimization.js +296 -0
- package/lib/module/cpuOptimization.js.map +1 -0
- package/lib/module/db/DatabaseManager.js +191 -0
- package/lib/module/db/DatabaseManager.js.map +1 -0
- package/lib/module/db/MediaMapper.js +284 -0
- package/lib/module/db/MediaMapper.js.map +1 -0
- package/lib/module/db/MediaRepository.js +242 -0
- package/lib/module/db/MediaRepository.js.map +1 -0
- package/lib/module/db/index.js +41 -0
- package/lib/module/db/index.js.map +1 -0
- package/lib/module/db/migrations.js +180 -0
- package/lib/module/db/migrations.js.map +1 -0
- package/lib/module/db/react-native-sqlcipher.d.js +2 -0
- package/lib/module/db/react-native-sqlcipher.d.js.map +1 -0
- package/lib/module/db/secureKey.js +87 -0
- package/lib/module/db/secureKey.js.map +1 -0
- package/lib/module/db/types.js +57 -0
- package/lib/module/db/types.js.map +1 -0
- package/lib/module/db/useMediaDatabase.js +123 -0
- package/lib/module/db/useMediaDatabase.js.map +1 -0
- package/lib/module/defaultIcons.js +2259 -0
- package/lib/module/defaultIcons.js.map +1 -0
- package/lib/module/deviceCapabilities.js +408 -0
- package/lib/module/deviceCapabilities.js.map +1 -0
- package/lib/module/errors.js +267 -0
- package/lib/module/errors.js.map +1 -0
- package/lib/module/iconConfig.js +796 -0
- package/lib/module/iconConfig.js.map +1 -0
- package/lib/module/icons.js +514 -0
- package/lib/module/icons.js.map +1 -0
- package/lib/module/index.js +251 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/jest-globals.d.js +2 -0
- package/lib/module/jest-globals.d.js.map +1 -0
- package/lib/module/library/MediaLibrary.js +107 -0
- package/lib/module/library/MediaLibrary.js.map +1 -0
- package/lib/module/library/MediaLibraryScreen.js +2597 -0
- package/lib/module/library/MediaLibraryScreen.js.map +1 -0
- package/lib/module/library/components/AudioPreview.js +74 -0
- package/lib/module/library/components/AudioPreview.js.map +1 -0
- package/lib/module/library/components/DocumentPreview.js +331 -0
- package/lib/module/library/components/DocumentPreview.js.map +1 -0
- package/lib/module/library/components/ExpandableFab.js +343 -0
- package/lib/module/library/components/ExpandableFab.js.map +1 -0
- package/lib/module/library/components/FileTiles.js +251 -0
- package/lib/module/library/components/FileTiles.js.map +1 -0
- package/lib/module/library/components/ImagePreview.js +70 -0
- package/lib/module/library/components/ImagePreview.js.map +1 -0
- package/lib/module/library/components/MediaMetadataHeader.js +175 -0
- package/lib/module/library/components/MediaMetadataHeader.js.map +1 -0
- package/lib/module/library/components/RecordAudioScreen.js +816 -0
- package/lib/module/library/components/RecordAudioScreen.js.map +1 -0
- package/lib/module/library/components/VideoPreview.js +453 -0
- package/lib/module/library/components/VideoPreview.js.map +1 -0
- package/lib/module/library/components/ViewerCounter.js +55 -0
- package/lib/module/library/components/ViewerCounter.js.map +1 -0
- package/lib/module/library/compressionEstimate.js +507 -0
- package/lib/module/library/compressionEstimate.js.map +1 -0
- package/lib/module/library/fileMetadata.js +196 -0
- package/lib/module/library/fileMetadata.js.map +1 -0
- package/lib/module/library/index.js +42 -0
- package/lib/module/library/index.js.map +1 -0
- package/lib/module/library/libraryIconRegistry.js +69 -0
- package/lib/module/library/libraryIconRegistry.js.map +1 -0
- package/lib/module/library/libraryIcons.js +858 -0
- package/lib/module/library/libraryIcons.js.map +1 -0
- package/lib/module/library/localizedFormat.js +181 -0
- package/lib/module/library/localizedFormat.js.map +1 -0
- package/lib/module/library/palette.js +225 -0
- package/lib/module/library/palette.js.map +1 -0
- package/lib/module/library/responsive.js +53 -0
- package/lib/module/library/responsive.js.map +1 -0
- package/lib/module/locales.js +416 -0
- package/lib/module/locales.js.map +1 -0
- package/lib/module/localization.js +1064 -0
- package/lib/module/localization.js.map +1 -0
- package/lib/module/logger.js +20 -0
- package/lib/module/logger.js.map +1 -0
- package/lib/module/lowMemoryCache.js +206 -0
- package/lib/module/lowMemoryCache.js.map +1 -0
- package/lib/module/mediaHistory.js +33 -0
- package/lib/module/mediaHistory.js.map +1 -0
- package/lib/module/mediaStorageService.js +402 -0
- package/lib/module/mediaStorageService.js.map +1 -0
- package/lib/module/memory.js +79 -0
- package/lib/module/memory.js.map +1 -0
- package/lib/module/nativeActions.js +307 -0
- package/lib/module/nativeActions.js.map +1 -0
- package/lib/module/nativeComponentSupport.js +61 -0
- package/lib/module/nativeComponentSupport.js.map +1 -0
- package/lib/module/networkPerformance.js +24 -0
- package/lib/module/networkPerformance.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/performance.js +104 -0
- package/lib/module/performance.js.map +1 -0
- package/lib/module/performanceMonitor.js +155 -0
- package/lib/module/performanceMonitor.js.map +1 -0
- package/lib/module/permissions.js +370 -0
- package/lib/module/permissions.js.map +1 -0
- package/lib/module/rendering.js +40 -0
- package/lib/module/rendering.js.map +1 -0
- package/lib/module/security.js +18 -0
- package/lib/module/security.js.map +1 -0
- package/lib/module/state.js +266 -0
- package/lib/module/state.js.map +1 -0
- package/lib/module/storage.js +400 -0
- package/lib/module/storage.js.map +1 -0
- package/lib/module/theme.js +390 -0
- package/lib/module/theme.js.map +1 -0
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/utils.js +115 -0
- package/lib/module/utils.js.map +1 -0
- package/lib/module/validation.js +288 -0
- package/lib/module/validation.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/AudioPlayerContext.d.ts +27 -0
- package/lib/typescript/src/AudioPlayerContext.d.ts.map +1 -0
- package/lib/typescript/src/CameraPreview.d.ts +13 -0
- package/lib/typescript/src/CameraPreview.d.ts.map +1 -0
- package/lib/typescript/src/NativeAnimatedImageView.d.ts +33 -0
- package/lib/typescript/src/NativeAnimatedImageView.d.ts.map +1 -0
- package/lib/typescript/src/NativeAudioPlayerView.d.ts +12 -0
- package/lib/typescript/src/NativeAudioPlayerView.d.ts.map +1 -0
- package/lib/typescript/src/NativeBlurView.d.ts +12 -0
- package/lib/typescript/src/NativeBlurView.d.ts.map +1 -0
- package/lib/typescript/src/NativeCustomCamera.d.ts +167 -0
- package/lib/typescript/src/NativeCustomCamera.d.ts.map +1 -0
- package/lib/typescript/src/NativeCustomCamera.web.d.ts +47 -0
- package/lib/typescript/src/NativeCustomCamera.web.d.ts.map +1 -0
- package/lib/typescript/src/NativeCustomVideoView.d.ts +30 -0
- package/lib/typescript/src/NativeCustomVideoView.d.ts.map +1 -0
- package/lib/typescript/src/NativeDocumentPreviewView.d.ts +48 -0
- package/lib/typescript/src/NativeDocumentPreviewView.d.ts.map +1 -0
- package/lib/typescript/src/NativeMediaThumbnailView.d.ts +54 -0
- package/lib/typescript/src/NativeMediaThumbnailView.d.ts.map +1 -0
- package/lib/typescript/src/NativeSvgIcon.d.ts +25 -0
- package/lib/typescript/src/NativeSvgIcon.d.ts.map +1 -0
- package/lib/typescript/src/ResponsivePreviewContainer.d.ts +92 -0
- package/lib/typescript/src/ResponsivePreviewContainer.d.ts.map +1 -0
- package/lib/typescript/src/accessibility.d.ts +20 -0
- package/lib/typescript/src/accessibility.d.ts.map +1 -0
- package/lib/typescript/src/config.d.ts +145 -0
- package/lib/typescript/src/config.d.ts.map +1 -0
- package/lib/typescript/src/cpuOptimization.d.ts +63 -0
- package/lib/typescript/src/cpuOptimization.d.ts.map +1 -0
- package/lib/typescript/src/db/DatabaseManager.d.ts +48 -0
- package/lib/typescript/src/db/DatabaseManager.d.ts.map +1 -0
- package/lib/typescript/src/db/MediaMapper.d.ts +77 -0
- package/lib/typescript/src/db/MediaMapper.d.ts.map +1 -0
- package/lib/typescript/src/db/MediaRepository.d.ts +66 -0
- package/lib/typescript/src/db/MediaRepository.d.ts.map +1 -0
- package/lib/typescript/src/db/index.d.ts +23 -0
- package/lib/typescript/src/db/index.d.ts.map +1 -0
- package/lib/typescript/src/db/migrations.d.ts +31 -0
- package/lib/typescript/src/db/migrations.d.ts.map +1 -0
- package/lib/typescript/src/db/secureKey.d.ts +10 -0
- package/lib/typescript/src/db/secureKey.d.ts.map +1 -0
- package/lib/typescript/src/db/types.d.ts +115 -0
- package/lib/typescript/src/db/types.d.ts.map +1 -0
- package/lib/typescript/src/db/useMediaDatabase.d.ts +41 -0
- package/lib/typescript/src/db/useMediaDatabase.d.ts.map +1 -0
- package/lib/typescript/src/defaultIcons.d.ts +139 -0
- package/lib/typescript/src/defaultIcons.d.ts.map +1 -0
- package/lib/typescript/src/deviceCapabilities.d.ts +92 -0
- package/lib/typescript/src/deviceCapabilities.d.ts.map +1 -0
- package/lib/typescript/src/errors.d.ts +95 -0
- package/lib/typescript/src/errors.d.ts.map +1 -0
- package/lib/typescript/src/iconConfig.d.ts +176 -0
- package/lib/typescript/src/iconConfig.d.ts.map +1 -0
- package/lib/typescript/src/icons.d.ts +217 -0
- package/lib/typescript/src/icons.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +104 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/library/MediaLibrary.d.ts +57 -0
- package/lib/typescript/src/library/MediaLibrary.d.ts.map +1 -0
- package/lib/typescript/src/library/MediaLibraryScreen.d.ts +51 -0
- package/lib/typescript/src/library/MediaLibraryScreen.d.ts.map +1 -0
- package/lib/typescript/src/library/components/AudioPreview.d.ts +6 -0
- package/lib/typescript/src/library/components/AudioPreview.d.ts.map +1 -0
- package/lib/typescript/src/library/components/DocumentPreview.d.ts +10 -0
- package/lib/typescript/src/library/components/DocumentPreview.d.ts.map +1 -0
- package/lib/typescript/src/library/components/ExpandableFab.d.ts +39 -0
- package/lib/typescript/src/library/components/ExpandableFab.d.ts.map +1 -0
- package/lib/typescript/src/library/components/FileTiles.d.ts +8 -0
- package/lib/typescript/src/library/components/FileTiles.d.ts.map +1 -0
- package/lib/typescript/src/library/components/ImagePreview.d.ts +5 -0
- package/lib/typescript/src/library/components/ImagePreview.d.ts.map +1 -0
- package/lib/typescript/src/library/components/MediaMetadataHeader.d.ts +16 -0
- package/lib/typescript/src/library/components/MediaMetadataHeader.d.ts.map +1 -0
- package/lib/typescript/src/library/components/RecordAudioScreen.d.ts +8 -0
- package/lib/typescript/src/library/components/RecordAudioScreen.d.ts.map +1 -0
- package/lib/typescript/src/library/components/VideoPreview.d.ts +20 -0
- package/lib/typescript/src/library/components/VideoPreview.d.ts.map +1 -0
- package/lib/typescript/src/library/components/ViewerCounter.d.ts +13 -0
- package/lib/typescript/src/library/components/ViewerCounter.d.ts.map +1 -0
- package/lib/typescript/src/library/compressionEstimate.d.ts +313 -0
- package/lib/typescript/src/library/compressionEstimate.d.ts.map +1 -0
- package/lib/typescript/src/library/fileMetadata.d.ts +33 -0
- package/lib/typescript/src/library/fileMetadata.d.ts.map +1 -0
- package/lib/typescript/src/library/index.d.ts +40 -0
- package/lib/typescript/src/library/index.d.ts.map +1 -0
- package/lib/typescript/src/library/libraryIconRegistry.d.ts +35 -0
- package/lib/typescript/src/library/libraryIconRegistry.d.ts.map +1 -0
- package/lib/typescript/src/library/libraryIcons.d.ts +85 -0
- package/lib/typescript/src/library/libraryIcons.d.ts.map +1 -0
- package/lib/typescript/src/library/localizedFormat.d.ts +49 -0
- package/lib/typescript/src/library/localizedFormat.d.ts.map +1 -0
- package/lib/typescript/src/library/palette.d.ts +104 -0
- package/lib/typescript/src/library/palette.d.ts.map +1 -0
- package/lib/typescript/src/library/responsive.d.ts +15 -0
- package/lib/typescript/src/library/responsive.d.ts.map +1 -0
- package/lib/typescript/src/locales.d.ts +103 -0
- package/lib/typescript/src/locales.d.ts.map +1 -0
- package/lib/typescript/src/localization.d.ts +1051 -0
- package/lib/typescript/src/localization.d.ts.map +1 -0
- package/lib/typescript/src/logger.d.ts +4 -0
- package/lib/typescript/src/logger.d.ts.map +1 -0
- package/lib/typescript/src/lowMemoryCache.d.ts +64 -0
- package/lib/typescript/src/lowMemoryCache.d.ts.map +1 -0
- package/lib/typescript/src/mediaHistory.d.ts +3 -0
- package/lib/typescript/src/mediaHistory.d.ts.map +1 -0
- package/lib/typescript/src/mediaStorageService.d.ts +155 -0
- package/lib/typescript/src/mediaStorageService.d.ts.map +1 -0
- package/lib/typescript/src/memory.d.ts +21 -0
- package/lib/typescript/src/memory.d.ts.map +1 -0
- package/lib/typescript/src/nativeActions.d.ts +174 -0
- package/lib/typescript/src/nativeActions.d.ts.map +1 -0
- package/lib/typescript/src/nativeComponentSupport.d.ts +30 -0
- package/lib/typescript/src/nativeComponentSupport.d.ts.map +1 -0
- package/lib/typescript/src/networkPerformance.d.ts +12 -0
- package/lib/typescript/src/networkPerformance.d.ts.map +1 -0
- package/lib/typescript/src/performance.d.ts +32 -0
- package/lib/typescript/src/performance.d.ts.map +1 -0
- package/lib/typescript/src/performanceMonitor.d.ts +45 -0
- package/lib/typescript/src/performanceMonitor.d.ts.map +1 -0
- package/lib/typescript/src/permissions.d.ts +132 -0
- package/lib/typescript/src/permissions.d.ts.map +1 -0
- package/lib/typescript/src/rendering.d.ts +9 -0
- package/lib/typescript/src/rendering.d.ts.map +1 -0
- package/lib/typescript/src/security.d.ts +6 -0
- package/lib/typescript/src/security.d.ts.map +1 -0
- package/lib/typescript/src/state.d.ts +102 -0
- package/lib/typescript/src/state.d.ts.map +1 -0
- package/lib/typescript/src/storage.d.ts +117 -0
- package/lib/typescript/src/storage.d.ts.map +1 -0
- package/lib/typescript/src/theme.d.ts +15 -0
- package/lib/typescript/src/theme.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +802 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/lib/typescript/src/utils.d.ts +50 -0
- package/lib/typescript/src/utils.d.ts.map +1 -0
- package/lib/typescript/src/validation.d.ts +52 -0
- package/lib/typescript/src/validation.d.ts.map +1 -0
- package/package.json +204 -0
- package/react-native.config.js +17 -0
- package/src/AudioPlayerContext.tsx +220 -0
- package/src/CameraPreview.tsx +352 -0
- package/src/NativeAnimatedImageView.tsx +71 -0
- package/src/NativeAudioPlayerView.tsx +39 -0
- package/src/NativeBlurView.tsx +40 -0
- package/src/NativeCustomCamera.ts +305 -0
- package/src/NativeCustomCamera.web.ts +192 -0
- package/src/NativeCustomVideoView.ts +30 -0
- package/src/NativeDocumentPreviewView.tsx +196 -0
- package/src/NativeMediaThumbnailView.tsx +167 -0
- package/src/NativeSvgIcon.tsx +46 -0
- package/src/ResponsivePreviewContainer.tsx +227 -0
- package/src/accessibility.ts +80 -0
- package/src/config.ts +406 -0
- package/src/cpuOptimization.ts +365 -0
- package/src/db/DatabaseManager.ts +212 -0
- package/src/db/MediaMapper.ts +377 -0
- package/src/db/MediaRepository.ts +313 -0
- package/src/db/index.ts +73 -0
- package/src/db/migrations.ts +222 -0
- package/src/db/react-native-sqlcipher.d.ts +76 -0
- package/src/db/secureKey.ts +100 -0
- package/src/db/types.ts +123 -0
- package/src/db/useMediaDatabase.ts +191 -0
- package/src/defaultIcons.tsx +2390 -0
- package/src/deviceCapabilities.ts +438 -0
- package/src/errors.ts +350 -0
- package/src/iconConfig.tsx +962 -0
- package/src/icons.tsx +788 -0
- package/src/index.tsx +763 -0
- package/src/jest-globals.d.ts +9 -0
- package/src/library/MediaLibrary.tsx +141 -0
- package/src/library/MediaLibraryScreen.tsx +3003 -0
- package/src/library/components/AudioPreview.tsx +73 -0
- package/src/library/components/DocumentPreview.tsx +361 -0
- package/src/library/components/ExpandableFab.tsx +342 -0
- package/src/library/components/FileTiles.tsx +252 -0
- package/src/library/components/ImagePreview.tsx +72 -0
- package/src/library/components/MediaMetadataHeader.tsx +208 -0
- package/src/library/components/RecordAudioScreen.tsx +845 -0
- package/src/library/components/VideoPreview.tsx +478 -0
- package/src/library/components/ViewerCounter.tsx +71 -0
- package/src/library/compressionEstimate.ts +662 -0
- package/src/library/fileMetadata.ts +212 -0
- package/src/library/index.ts +66 -0
- package/src/library/libraryIconRegistry.tsx +86 -0
- package/src/library/libraryIcons.tsx +928 -0
- package/src/library/localizedFormat.ts +207 -0
- package/src/library/palette.ts +281 -0
- package/src/library/responsive.ts +49 -0
- package/src/locales.ts +381 -0
- package/src/localization.ts +1947 -0
- package/src/logger.ts +20 -0
- package/src/lowMemoryCache.ts +218 -0
- package/src/mediaHistory.ts +42 -0
- package/src/mediaStorageService.ts +546 -0
- package/src/memory.ts +102 -0
- package/src/nativeActions.ts +422 -0
- package/src/nativeComponentSupport.ts +60 -0
- package/src/networkPerformance.ts +30 -0
- package/src/performance.ts +137 -0
- package/src/performanceMonitor.ts +219 -0
- package/src/permissions.ts +403 -0
- package/src/rendering.ts +47 -0
- package/src/security.ts +19 -0
- package/src/state.ts +333 -0
- package/src/storage.ts +453 -0
- package/src/theme.tsx +467 -0
- package/src/types.ts +946 -0
- package/src/utils.ts +177 -0
- package/src/validation.ts +372 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
package com.customcamera
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.ContentResolver
|
|
5
|
+
import android.content.ContentValues
|
|
6
|
+
import android.net.Uri
|
|
7
|
+
import android.os.Build
|
|
8
|
+
import android.os.Environment
|
|
9
|
+
import android.provider.MediaStore
|
|
10
|
+
import android.util.Log
|
|
11
|
+
import kotlinx.coroutines.Dispatchers
|
|
12
|
+
import kotlinx.coroutines.withContext
|
|
13
|
+
import java.io.File
|
|
14
|
+
import java.io.FileInputStream
|
|
15
|
+
import java.io.IOException
|
|
16
|
+
import java.text.SimpleDateFormat
|
|
17
|
+
import java.util.Date
|
|
18
|
+
import java.util.Locale
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* MediaPublisher handles moving and copying media from cache to document/gallery directories.
|
|
22
|
+
* Manages file operations, URI generation, and metadata preservation.
|
|
23
|
+
*
|
|
24
|
+
* Supports:
|
|
25
|
+
* - Atomic move operations (cache -> documents)
|
|
26
|
+
* - Copy operations (cache -> documents, keeping original)
|
|
27
|
+
* - URI generation compatible with all Android versions
|
|
28
|
+
* - File hash computation for duplicate detection
|
|
29
|
+
* - Error handling and recovery
|
|
30
|
+
*/
|
|
31
|
+
class MediaPublisher private constructor(private val context: Context) {
|
|
32
|
+
|
|
33
|
+
companion object {
|
|
34
|
+
private const val TAG = "MediaPublisher"
|
|
35
|
+
|
|
36
|
+
@Volatile
|
|
37
|
+
private var instance: MediaPublisher? = null
|
|
38
|
+
|
|
39
|
+
fun getInstance(context: Context): MediaPublisher {
|
|
40
|
+
return instance ?: synchronized(this) {
|
|
41
|
+
instance ?: MediaPublisher(context.applicationContext).also { instance = it }
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private const val BUFFER_SIZE = MediaFileIo.COPY_BUFFER_BYTES
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Head-room kept free when sizing a publish. Filling a volume to the last byte is what makes
|
|
49
|
+
* the NEXT write (metadata, thumbnail, the following capture) the one that fails.
|
|
50
|
+
*/
|
|
51
|
+
private const val SPACE_MARGIN_BYTES = 32L * 1024L * 1024L
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private val contentResolver: ContentResolver = context.contentResolver
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Move media from cache to documents directory.
|
|
58
|
+
*
|
|
59
|
+
* @param knownHash the signature already recorded for this media, when the caller has one.
|
|
60
|
+
* Supplying it skips a full read of the file — see [computeFileHash].
|
|
61
|
+
*/
|
|
62
|
+
suspend fun moveToDocuments(
|
|
63
|
+
sourceFile: File,
|
|
64
|
+
fileName: String,
|
|
65
|
+
mediaType: String,
|
|
66
|
+
metadata: MediaStorageMetadata,
|
|
67
|
+
knownHash: String? = null
|
|
68
|
+
): PublishResult = withContext(Dispatchers.IO) {
|
|
69
|
+
try {
|
|
70
|
+
if (!sourceFile.exists()) {
|
|
71
|
+
return@withContext PublishResult(
|
|
72
|
+
success = false,
|
|
73
|
+
error = "Source file does not exist: ${sourceFile.absolutePath}"
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
val targetFile = getDocumentFile(fileName, mediaType)
|
|
78
|
+
val fileHash = knownHash?.takeIf { it.isNotEmpty() } ?: computeFileHash(sourceFile)
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
// A genuine move: renamed when cache and documents share a volume (no bytes read or
|
|
82
|
+
// written at all, whatever the clip's size), streamed and then unlinked when they do not.
|
|
83
|
+
// This used to be a full byte-for-byte copy followed by the caller deleting the source,
|
|
84
|
+
// which for a long recording meant re-writing hundreds of megabytes on the send path.
|
|
85
|
+
//
|
|
86
|
+
// relocate() checks free space itself, and ONLY on the path that actually writes bytes —
|
|
87
|
+
// a rename must stay possible on a device too full to hold a second copy.
|
|
88
|
+
when (MediaFileIo.relocate(sourceFile, targetFile, SPACE_MARGIN_BYTES)) {
|
|
89
|
+
MediaFileIo.Outcome.RENAMED, MediaFileIo.Outcome.COPIED -> Unit
|
|
90
|
+
MediaFileIo.Outcome.INSUFFICIENT_SPACE ->
|
|
91
|
+
return@withContext PublishResult(
|
|
92
|
+
success = false,
|
|
93
|
+
error = "Not enough storage space to save this media"
|
|
94
|
+
)
|
|
95
|
+
MediaFileIo.Outcome.FAILED ->
|
|
96
|
+
return@withContext PublishResult(
|
|
97
|
+
success = false,
|
|
98
|
+
error = "Failed to copy file to documents"
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Update metadata on target file
|
|
103
|
+
updateFileMetadata(targetFile, metadata)
|
|
104
|
+
|
|
105
|
+
// Generate URI for the target file
|
|
106
|
+
val targetUri = generateUri(targetFile, mediaType)
|
|
107
|
+
|
|
108
|
+
// Verify the target file exists and is readable
|
|
109
|
+
if (!targetFile.exists() || !targetFile.canRead()) {
|
|
110
|
+
targetFile.delete()
|
|
111
|
+
return@withContext PublishResult(
|
|
112
|
+
success = false,
|
|
113
|
+
error = "Target file not readable after copy"
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
Log.i(TAG, "Media moved successfully from ${sourceFile.absolutePath} to ${targetFile.absolutePath}")
|
|
118
|
+
|
|
119
|
+
PublishResult(
|
|
120
|
+
success = true,
|
|
121
|
+
targetUri = targetUri,
|
|
122
|
+
fileHash = fileHash,
|
|
123
|
+
targetPath = targetFile.absolutePath
|
|
124
|
+
)
|
|
125
|
+
} catch (e: IOException) {
|
|
126
|
+
Log.e(TAG, "IO error during move operation", e)
|
|
127
|
+
targetFile.delete() // Cleanup partial file
|
|
128
|
+
PublishResult(
|
|
129
|
+
success = false,
|
|
130
|
+
error = "IO error: ${e.message}"
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
} catch (e: Exception) {
|
|
134
|
+
Log.e(TAG, "Unexpected error in moveToDocuments", e)
|
|
135
|
+
PublishResult(
|
|
136
|
+
success = false,
|
|
137
|
+
error = "Unexpected error: ${e.message}"
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Copy media from cache to documents directory (keeping original)
|
|
144
|
+
*
|
|
145
|
+
* @param knownHash see [moveToDocuments].
|
|
146
|
+
*/
|
|
147
|
+
suspend fun copyToDocuments(
|
|
148
|
+
sourceFile: File,
|
|
149
|
+
fileName: String,
|
|
150
|
+
mediaType: String,
|
|
151
|
+
metadata: MediaStorageMetadata,
|
|
152
|
+
knownHash: String? = null
|
|
153
|
+
): PublishResult = withContext(Dispatchers.IO) {
|
|
154
|
+
try {
|
|
155
|
+
if (!sourceFile.exists()) {
|
|
156
|
+
return@withContext PublishResult(
|
|
157
|
+
success = false,
|
|
158
|
+
error = "Source file does not exist: ${sourceFile.absolutePath}"
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
val targetFile = getDocumentFile(fileName, mediaType)
|
|
163
|
+
val fileHash = knownHash?.takeIf { it.isNotEmpty() } ?: computeFileHash(sourceFile)
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
// Unlike moveToDocuments this ALWAYS writes a second copy, so duplicate()'s space check is
|
|
167
|
+
// unconditional. Running the volume dry here used to leave a truncated file behind that
|
|
168
|
+
// looked like a real published asset to everything downstream.
|
|
169
|
+
when (MediaFileIo.duplicate(sourceFile, targetFile, SPACE_MARGIN_BYTES)) {
|
|
170
|
+
MediaFileIo.Outcome.RENAMED, MediaFileIo.Outcome.COPIED -> Unit
|
|
171
|
+
MediaFileIo.Outcome.INSUFFICIENT_SPACE ->
|
|
172
|
+
return@withContext PublishResult(
|
|
173
|
+
success = false,
|
|
174
|
+
error = "Not enough storage space to save this media"
|
|
175
|
+
)
|
|
176
|
+
MediaFileIo.Outcome.FAILED ->
|
|
177
|
+
return@withContext PublishResult(
|
|
178
|
+
success = false,
|
|
179
|
+
error = "Failed to copy file to documents"
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Update metadata on target file
|
|
184
|
+
updateFileMetadata(targetFile, metadata)
|
|
185
|
+
|
|
186
|
+
// Generate URI for the target file
|
|
187
|
+
val targetUri = generateUri(targetFile, mediaType)
|
|
188
|
+
|
|
189
|
+
Log.i(TAG, "Media copied successfully from ${sourceFile.absolutePath} to ${targetFile.absolutePath}")
|
|
190
|
+
|
|
191
|
+
PublishResult(
|
|
192
|
+
success = true,
|
|
193
|
+
targetUri = targetUri,
|
|
194
|
+
fileHash = fileHash,
|
|
195
|
+
targetPath = targetFile.absolutePath
|
|
196
|
+
)
|
|
197
|
+
} catch (e: IOException) {
|
|
198
|
+
Log.e(TAG, "IO error during copy operation", e)
|
|
199
|
+
targetFile.delete() // Cleanup partial file
|
|
200
|
+
PublishResult(
|
|
201
|
+
success = false,
|
|
202
|
+
error = "IO error: ${e.message}"
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
} catch (e: Exception) {
|
|
206
|
+
Log.e(TAG, "Unexpected error in copyToDocuments", e)
|
|
207
|
+
PublishResult(
|
|
208
|
+
success = false,
|
|
209
|
+
error = "Unexpected error: ${e.message}"
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Move media to gallery (MediaStore)
|
|
216
|
+
*/
|
|
217
|
+
suspend fun moveToGallery(
|
|
218
|
+
sourceFile: File,
|
|
219
|
+
fileName: String,
|
|
220
|
+
mediaType: String,
|
|
221
|
+
metadata: MediaStorageMetadata
|
|
222
|
+
): PublishResult = withContext(Dispatchers.IO) {
|
|
223
|
+
try {
|
|
224
|
+
if (!sourceFile.exists()) {
|
|
225
|
+
return@withContext PublishResult(
|
|
226
|
+
success = false,
|
|
227
|
+
error = "Source file does not exist"
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
val fileHash = computeFileHash(sourceFile)
|
|
232
|
+
val contentUri = getMediaStoreUri(mediaType)
|
|
233
|
+
|
|
234
|
+
val contentValues = ContentValues().apply {
|
|
235
|
+
put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
|
|
236
|
+
put(MediaStore.MediaColumns.MIME_TYPE, getMimeType(mediaType, fileName))
|
|
237
|
+
put(MediaStore.MediaColumns.RELATIVE_PATH, getRelativePath(mediaType))
|
|
238
|
+
|
|
239
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
240
|
+
put(MediaStore.MediaColumns.DATE_TAKEN, metadata.dateTaken ?: System.currentTimeMillis())
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
val newUri = contentResolver.insert(contentUri, contentValues)
|
|
246
|
+
?: return@withContext PublishResult(
|
|
247
|
+
success = false,
|
|
248
|
+
error = "Failed to insert into MediaStore"
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
// Copy file content to MediaStore
|
|
252
|
+
val outputStream = contentResolver.openOutputStream(newUri)
|
|
253
|
+
?: return@withContext PublishResult(
|
|
254
|
+
success = false,
|
|
255
|
+
error = "Failed to open output stream"
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
val inputStream = FileInputStream(sourceFile)
|
|
259
|
+
inputStream.use { input ->
|
|
260
|
+
outputStream.use { output ->
|
|
261
|
+
input.copyTo(output, BUFFER_SIZE)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
Log.i(TAG, "Media moved to gallery successfully: $newUri")
|
|
266
|
+
|
|
267
|
+
PublishResult(
|
|
268
|
+
success = true,
|
|
269
|
+
targetUri = newUri.toString(),
|
|
270
|
+
fileHash = fileHash
|
|
271
|
+
)
|
|
272
|
+
} catch (e: IOException) {
|
|
273
|
+
Log.e(TAG, "IO error during MediaStore operation", e)
|
|
274
|
+
PublishResult(
|
|
275
|
+
success = false,
|
|
276
|
+
error = "IO error: ${e.message}"
|
|
277
|
+
)
|
|
278
|
+
}
|
|
279
|
+
} catch (e: Exception) {
|
|
280
|
+
Log.e(TAG, "Unexpected error in moveToGallery", e)
|
|
281
|
+
PublishResult(
|
|
282
|
+
success = false,
|
|
283
|
+
error = "Unexpected error: ${e.message}"
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Content signature for duplicate detection.
|
|
290
|
+
*
|
|
291
|
+
* Bounded for large files, so publishing a long recording no longer reads the whole clip just to
|
|
292
|
+
* produce a value that is only compared for equality — see [MediaFileIo.contentSignature].
|
|
293
|
+
* Callers that already hold the signature should pass it in rather than reach this at all.
|
|
294
|
+
*/
|
|
295
|
+
private fun computeFileHash(file: File): String = MediaFileIo.contentSignature(file)
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Update file metadata (timestamps, permissions)
|
|
299
|
+
*/
|
|
300
|
+
private fun updateFileMetadata(file: File, metadata: MediaStorageMetadata) {
|
|
301
|
+
try {
|
|
302
|
+
if (metadata.dateTaken != null) {
|
|
303
|
+
file.setLastModified(metadata.dateTaken)
|
|
304
|
+
}
|
|
305
|
+
} catch (e: Exception) {
|
|
306
|
+
Log.w(TAG, "Failed to update file metadata", e)
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* True when a published document with this name already occupies the target path.
|
|
312
|
+
*
|
|
313
|
+
* Callers use it to uniquify a name BEFORE publishing, so a publish can never silently overwrite
|
|
314
|
+
* an unrelated file. Cheap — one stat, no read of the media itself.
|
|
315
|
+
*/
|
|
316
|
+
fun documentFileExists(fileName: String, mediaType: String): Boolean =
|
|
317
|
+
runCatching { getDocumentFile(fileName, mediaType).exists() }.getOrDefault(false)
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Get document directory file
|
|
321
|
+
*/
|
|
322
|
+
private fun getDocumentFile(fileName: String, mediaType: String): File {
|
|
323
|
+
val baseDir = context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)
|
|
324
|
+
?: context.filesDir
|
|
325
|
+
|
|
326
|
+
val mediaDir = File(baseDir, "media_documents").apply { mkdirs() }
|
|
327
|
+
val typeDir = File(mediaDir, when (mediaType) {
|
|
328
|
+
"video" -> "videos"
|
|
329
|
+
"audio" -> "audio"
|
|
330
|
+
else -> "photos"
|
|
331
|
+
}).apply { mkdirs() }
|
|
332
|
+
|
|
333
|
+
return File(typeDir, fileName)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Generate unique file name with timestamp if needed
|
|
338
|
+
*/
|
|
339
|
+
private fun getUniqueFileName(baseFileName: String): String {
|
|
340
|
+
val file = File(baseFileName)
|
|
341
|
+
if (!file.exists()) return baseFileName
|
|
342
|
+
|
|
343
|
+
val name = file.nameWithoutExtension
|
|
344
|
+
val ext = file.extension
|
|
345
|
+
val parent = file.parentFile
|
|
346
|
+
|
|
347
|
+
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
|
|
348
|
+
val newName = "${name}_$timestamp.$ext"
|
|
349
|
+
|
|
350
|
+
return File(parent, newName).absolutePath
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Generate media-compatible URI
|
|
355
|
+
*/
|
|
356
|
+
private fun generateUri(file: File, mediaType: String): String {
|
|
357
|
+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
358
|
+
try {
|
|
359
|
+
androidx.core.content.FileProvider.getUriForFile(
|
|
360
|
+
context,
|
|
361
|
+
"${context.packageName}.camera.fileprovider",
|
|
362
|
+
file
|
|
363
|
+
).toString()
|
|
364
|
+
} catch (e: Exception) {
|
|
365
|
+
Log.w(TAG, "FileProvider failed, falling back to file:// URI", e)
|
|
366
|
+
Uri.fromFile(file).toString()
|
|
367
|
+
}
|
|
368
|
+
} else {
|
|
369
|
+
// For Android versions before N, we can use file:// URIs
|
|
370
|
+
Uri.fromFile(file).toString()
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Get MediaStore URI based on media type
|
|
376
|
+
*/
|
|
377
|
+
private fun getMediaStoreUri(mediaType: String): Uri {
|
|
378
|
+
return if (mediaType == "video") {
|
|
379
|
+
MediaStore.Video.Media.EXTERNAL_CONTENT_URI
|
|
380
|
+
} else {
|
|
381
|
+
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Get relative path for MediaStore
|
|
387
|
+
*/
|
|
388
|
+
private fun getRelativePath(mediaType: String): String {
|
|
389
|
+
return if (mediaType == "video") {
|
|
390
|
+
"${Environment.DIRECTORY_MOVIES}/CustomCamera/"
|
|
391
|
+
} else {
|
|
392
|
+
"${Environment.DIRECTORY_PICTURES}/CustomCamera/"
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Get MIME type for media.
|
|
398
|
+
*
|
|
399
|
+
* Derived from [fileName]'s extension so a non-JPEG image keeps its real type when it is
|
|
400
|
+
* inserted into MediaStore — declaring image/jpeg for a GIF makes the gallery store (and every
|
|
401
|
+
* app that later reads) a mislabelled file. Falls back to the per-type default when the name
|
|
402
|
+
* carries no recognised extension.
|
|
403
|
+
*/
|
|
404
|
+
private fun getMimeType(mediaType: String, fileName: String? = null): String {
|
|
405
|
+
if (mediaType == "video") {
|
|
406
|
+
// Container table for video lives in MediaExportFormats, so an exported .webm / .3gp is
|
|
407
|
+
// inserted into MediaStore as what it actually is instead of as video/mp4.
|
|
408
|
+
return MediaExportFormats.videoContainerFromFileName(fileName)?.mimeType ?: "video/mp4"
|
|
409
|
+
}
|
|
410
|
+
// Container table lives in ImageFormatSupport so publishing, caching and editor export can
|
|
411
|
+
// never disagree about what a given extension means — publishing a HEIF/AVIF as image/jpeg
|
|
412
|
+
// would make MediaStore describe bytes it does not have.
|
|
413
|
+
return ImageFormatSupport.fromFileName(fileName)?.mimeType ?: "image/jpeg"
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
data class PublishResult(
|
|
417
|
+
val success: Boolean,
|
|
418
|
+
val targetUri: String? = null,
|
|
419
|
+
val fileHash: String? = null,
|
|
420
|
+
val targetPath: String? = null,
|
|
421
|
+
val error: String? = null
|
|
422
|
+
)
|
|
423
|
+
}
|