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
package/src/db/index.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encrypted media database — public API.
|
|
3
|
+
*
|
|
4
|
+
* A modular SQLCipher persistence layer for the camera plugin:
|
|
5
|
+
* - `DatabaseManager` centralized encrypted connection + primitives
|
|
6
|
+
* - `migrations` schema versioning (PRAGMA user_version)
|
|
7
|
+
* - `MediaRepository` typed CRUD/service layer
|
|
8
|
+
* - `MediaMapper` CameraAsset ⇆ MediaRecord translation
|
|
9
|
+
* - `useMediaDatabase` React hook bridging UI and the store
|
|
10
|
+
* - `secureKey` Keystore-backed encryption-key provisioning
|
|
11
|
+
*
|
|
12
|
+
* Consumers should generally use `useMediaDatabase` (UI) or `getMediaRepository`
|
|
13
|
+
* (imperative), and call `initializeMediaDatabase()` once at startup.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// Models & types
|
|
17
|
+
export type {
|
|
18
|
+
MediaRecord,
|
|
19
|
+
MediaRecordInput,
|
|
20
|
+
MediaType,
|
|
21
|
+
MediaSource,
|
|
22
|
+
MediaFilter,
|
|
23
|
+
MediaCounts,
|
|
24
|
+
MediaQueryOptions,
|
|
25
|
+
} from './types';
|
|
26
|
+
export { MEDIA_TABLE, MediaColumns } from './types';
|
|
27
|
+
|
|
28
|
+
// Centralized manager
|
|
29
|
+
export {
|
|
30
|
+
DatabaseManager,
|
|
31
|
+
getDatabaseManager,
|
|
32
|
+
initializeMediaDatabase,
|
|
33
|
+
type BatchStatement,
|
|
34
|
+
} from './DatabaseManager';
|
|
35
|
+
|
|
36
|
+
// Schema versioning & migrations
|
|
37
|
+
export {
|
|
38
|
+
MIGRATIONS,
|
|
39
|
+
LATEST_SCHEMA_VERSION,
|
|
40
|
+
runMigrations,
|
|
41
|
+
type Migration,
|
|
42
|
+
type MigrationExecutor,
|
|
43
|
+
} from './migrations';
|
|
44
|
+
|
|
45
|
+
// Repository / service layer
|
|
46
|
+
export { MediaRepository, getMediaRepository } from './MediaRepository';
|
|
47
|
+
|
|
48
|
+
// Mapping helpers
|
|
49
|
+
export {
|
|
50
|
+
assetToRecordInput,
|
|
51
|
+
recordToAsset,
|
|
52
|
+
rowToRecord,
|
|
53
|
+
assetTypeToMediaType,
|
|
54
|
+
mediaTypeToAssetType,
|
|
55
|
+
normalizeSource,
|
|
56
|
+
extensionForMimeType,
|
|
57
|
+
// Documents-path & source resolution (persistence contract)
|
|
58
|
+
resolveDocumentsPath,
|
|
59
|
+
isPublishedToDocuments,
|
|
60
|
+
detectSource,
|
|
61
|
+
} from './MediaMapper';
|
|
62
|
+
|
|
63
|
+
// Encryption key provisioning
|
|
64
|
+
export {
|
|
65
|
+
getDatabaseKey,
|
|
66
|
+
isHardwareBackedKeyAvailable,
|
|
67
|
+
} from './secureKey';
|
|
68
|
+
|
|
69
|
+
// React hook
|
|
70
|
+
export {
|
|
71
|
+
useMediaDatabase,
|
|
72
|
+
type UseMediaDatabaseResult,
|
|
73
|
+
} from './useMediaDatabase';
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema versioning & migrations for the encrypted media database.
|
|
3
|
+
*
|
|
4
|
+
* Versioning uses SQLite's built-in `PRAGMA user_version`. On every open,
|
|
5
|
+
* `runMigrations` reads the current version and applies — inside a single
|
|
6
|
+
* transaction — every migration whose target version is greater than it, in
|
|
7
|
+
* ascending order. Adding a new schema change is a matter of appending one more
|
|
8
|
+
* entry to `MIGRATIONS`; never edit or reorder existing entries.
|
|
9
|
+
*/
|
|
10
|
+
import { MEDIA_TABLE, MediaColumns } from './types';
|
|
11
|
+
|
|
12
|
+
/** A single forward migration step. */
|
|
13
|
+
export interface Migration {
|
|
14
|
+
/** Target `user_version` this migration upgrades the database to. */
|
|
15
|
+
version: number;
|
|
16
|
+
/** Human-readable description (documentation only). */
|
|
17
|
+
description: string;
|
|
18
|
+
/** Ordered SQL statements executed to reach `version`. */
|
|
19
|
+
statements: string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Ordered list of migrations. `LATEST_SCHEMA_VERSION` is derived from the last
|
|
24
|
+
* entry, so bumping the schema only requires appending a new `Migration`.
|
|
25
|
+
*/
|
|
26
|
+
export const MIGRATIONS: Migration[] = [
|
|
27
|
+
{
|
|
28
|
+
version: 1,
|
|
29
|
+
description: 'Initial media table with type/source indexes',
|
|
30
|
+
statements: [
|
|
31
|
+
`CREATE TABLE IF NOT EXISTS ${MEDIA_TABLE} (
|
|
32
|
+
${MediaColumns.id} TEXT PRIMARY KEY NOT NULL,
|
|
33
|
+
${MediaColumns.mediaType} TEXT NOT NULL CHECK (${MediaColumns.mediaType} IN ('image','video')),
|
|
34
|
+
${MediaColumns.source} TEXT NOT NULL CHECK (${MediaColumns.source} IN ('camera','gallery')),
|
|
35
|
+
${MediaColumns.filePath} TEXT NOT NULL,
|
|
36
|
+
${MediaColumns.fileName} TEXT NOT NULL,
|
|
37
|
+
${MediaColumns.fileSize} INTEGER,
|
|
38
|
+
${MediaColumns.width} INTEGER,
|
|
39
|
+
${MediaColumns.height} INTEGER,
|
|
40
|
+
${MediaColumns.duration} INTEGER,
|
|
41
|
+
${MediaColumns.mimeType} TEXT,
|
|
42
|
+
${MediaColumns.createdAt} INTEGER NOT NULL,
|
|
43
|
+
${MediaColumns.updatedAt} INTEGER NOT NULL
|
|
44
|
+
);`,
|
|
45
|
+
`CREATE INDEX IF NOT EXISTS idx_media_type
|
|
46
|
+
ON ${MEDIA_TABLE} (${MediaColumns.mediaType});`,
|
|
47
|
+
`CREATE INDEX IF NOT EXISTS idx_media_created_at
|
|
48
|
+
ON ${MEDIA_TABLE} (${MediaColumns.createdAt} DESC);`,
|
|
49
|
+
// Non-unique: speeds up delete-by-path without rejecting a re-selected
|
|
50
|
+
// file that arrives under a new id (dedup is keyed on the primary id).
|
|
51
|
+
`CREATE INDEX IF NOT EXISTS idx_media_file_path
|
|
52
|
+
ON ${MEDIA_TABLE} (${MediaColumns.filePath});`,
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
version: 2,
|
|
57
|
+
description:
|
|
58
|
+
'Composite (media_type, created_at DESC) index for the filtered+ordered list query',
|
|
59
|
+
statements: [
|
|
60
|
+
// The Photos/Videos filters run `WHERE media_type = ? ORDER BY created_at DESC`
|
|
61
|
+
// (see MediaRepository.getAll). The single-column idx_media_type filters but then
|
|
62
|
+
// forces a sort of the matching rows on every query; the single-column
|
|
63
|
+
// idx_media_created_at orders but can't also filter. A composite index lets SQLite
|
|
64
|
+
// satisfy BOTH the equality filter and the ordering from one index — no separate
|
|
65
|
+
// sort step — which keeps the filtered list fast as the library grows into the
|
|
66
|
+
// thousands. Purely additive (CREATE INDEX IF NOT EXISTS): no data change, and the
|
|
67
|
+
// unfiltered "All" query keeps using idx_media_created_at.
|
|
68
|
+
`CREATE INDEX IF NOT EXISTS idx_media_type_created_at
|
|
69
|
+
ON ${MEDIA_TABLE} (${MediaColumns.mediaType}, ${MediaColumns.createdAt} DESC);`,
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
version: 3,
|
|
74
|
+
description:
|
|
75
|
+
'Widen media_type to include document + audio, and reclassify legacy rows by MIME/extension',
|
|
76
|
+
// SQLite cannot ALTER a CHECK constraint in place, so the table is rebuilt.
|
|
77
|
+
// The copy step reclassifies rows the old two-kind schema was forced to store
|
|
78
|
+
// as `image`: a picked PDF/track kept its real MIME (e.g. application/pdf,
|
|
79
|
+
// audio/mpeg) even though media_type was clamped to 'image', so we recover the
|
|
80
|
+
// correct kind here from mime_type (then the file extension as a fallback).
|
|
81
|
+
statements: [
|
|
82
|
+
// 1. Park the current table out of the way (its indexes move with it).
|
|
83
|
+
`ALTER TABLE ${MEDIA_TABLE} RENAME TO ${MEDIA_TABLE}_legacy_v2;`,
|
|
84
|
+
// 2. Recreate the table with the widened media_type CHECK constraint.
|
|
85
|
+
`CREATE TABLE ${MEDIA_TABLE} (
|
|
86
|
+
${MediaColumns.id} TEXT PRIMARY KEY NOT NULL,
|
|
87
|
+
${MediaColumns.mediaType} TEXT NOT NULL CHECK (${MediaColumns.mediaType} IN ('image','video','document','audio')),
|
|
88
|
+
${MediaColumns.source} TEXT NOT NULL CHECK (${MediaColumns.source} IN ('camera','gallery')),
|
|
89
|
+
${MediaColumns.filePath} TEXT NOT NULL,
|
|
90
|
+
${MediaColumns.fileName} TEXT NOT NULL,
|
|
91
|
+
${MediaColumns.fileSize} INTEGER,
|
|
92
|
+
${MediaColumns.width} INTEGER,
|
|
93
|
+
${MediaColumns.height} INTEGER,
|
|
94
|
+
${MediaColumns.duration} INTEGER,
|
|
95
|
+
${MediaColumns.mimeType} TEXT,
|
|
96
|
+
${MediaColumns.createdAt} INTEGER NOT NULL,
|
|
97
|
+
${MediaColumns.updatedAt} INTEGER NOT NULL
|
|
98
|
+
);`,
|
|
99
|
+
// 3. Copy rows over, reclassifying media_type from mime_type / file extension.
|
|
100
|
+
`INSERT INTO ${MEDIA_TABLE} (
|
|
101
|
+
${MediaColumns.id}, ${MediaColumns.mediaType}, ${MediaColumns.source},
|
|
102
|
+
${MediaColumns.filePath}, ${MediaColumns.fileName}, ${MediaColumns.fileSize},
|
|
103
|
+
${MediaColumns.width}, ${MediaColumns.height}, ${MediaColumns.duration},
|
|
104
|
+
${MediaColumns.mimeType}, ${MediaColumns.createdAt}, ${MediaColumns.updatedAt}
|
|
105
|
+
)
|
|
106
|
+
SELECT
|
|
107
|
+
${MediaColumns.id},
|
|
108
|
+
CASE
|
|
109
|
+
WHEN ${MediaColumns.mediaType} = 'video' THEN 'video'
|
|
110
|
+
WHEN ${MediaColumns.mimeType} LIKE 'video/%' THEN 'video'
|
|
111
|
+
WHEN ${MediaColumns.mimeType} LIKE 'audio/%' THEN 'audio'
|
|
112
|
+
WHEN ${MediaColumns.mimeType} LIKE 'image/%' THEN 'image'
|
|
113
|
+
WHEN ${MediaColumns.mimeType} = 'application/pdf'
|
|
114
|
+
OR ${MediaColumns.mimeType} LIKE 'application/vnd.%'
|
|
115
|
+
OR ${MediaColumns.mimeType} LIKE 'application/msword%'
|
|
116
|
+
OR ${MediaColumns.mimeType} LIKE 'application/rtf%'
|
|
117
|
+
OR ${MediaColumns.mimeType} = 'application/epub+zip'
|
|
118
|
+
OR ${MediaColumns.mimeType} LIKE 'text/%' THEN 'document'
|
|
119
|
+
WHEN lower(${MediaColumns.fileName}) LIKE '%.mp4'
|
|
120
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.mov'
|
|
121
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.mkv'
|
|
122
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.webm'
|
|
123
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.3gp'
|
|
124
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.m4v' THEN 'video'
|
|
125
|
+
WHEN lower(${MediaColumns.fileName}) LIKE '%.mp3'
|
|
126
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.wav'
|
|
127
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.aac'
|
|
128
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.m4a'
|
|
129
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.ogg'
|
|
130
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.flac'
|
|
131
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.opus'
|
|
132
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.amr' THEN 'audio'
|
|
133
|
+
WHEN lower(${MediaColumns.fileName}) LIKE '%.pdf'
|
|
134
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.doc'
|
|
135
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.docx'
|
|
136
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.xls'
|
|
137
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.xlsx'
|
|
138
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.ppt'
|
|
139
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.pptx'
|
|
140
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.txt'
|
|
141
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.csv'
|
|
142
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.rtf'
|
|
143
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.odt'
|
|
144
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.ods'
|
|
145
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.odp'
|
|
146
|
+
OR lower(${MediaColumns.fileName}) LIKE '%.epub' THEN 'document'
|
|
147
|
+
ELSE 'image'
|
|
148
|
+
END,
|
|
149
|
+
${MediaColumns.source}, ${MediaColumns.filePath}, ${MediaColumns.fileName},
|
|
150
|
+
${MediaColumns.fileSize}, ${MediaColumns.width}, ${MediaColumns.height},
|
|
151
|
+
${MediaColumns.duration}, ${MediaColumns.mimeType}, ${MediaColumns.createdAt},
|
|
152
|
+
${MediaColumns.updatedAt}
|
|
153
|
+
FROM ${MEDIA_TABLE}_legacy_v2;`,
|
|
154
|
+
// 4. Drop the legacy table (this also drops its now-orphaned indexes,
|
|
155
|
+
// freeing the index names for recreation below).
|
|
156
|
+
`DROP TABLE ${MEDIA_TABLE}_legacy_v2;`,
|
|
157
|
+
// 5. Recreate every index on the rebuilt table.
|
|
158
|
+
`CREATE INDEX IF NOT EXISTS idx_media_type
|
|
159
|
+
ON ${MEDIA_TABLE} (${MediaColumns.mediaType});`,
|
|
160
|
+
`CREATE INDEX IF NOT EXISTS idx_media_created_at
|
|
161
|
+
ON ${MEDIA_TABLE} (${MediaColumns.createdAt} DESC);`,
|
|
162
|
+
`CREATE INDEX IF NOT EXISTS idx_media_file_path
|
|
163
|
+
ON ${MEDIA_TABLE} (${MediaColumns.filePath});`,
|
|
164
|
+
`CREATE INDEX IF NOT EXISTS idx_media_type_created_at
|
|
165
|
+
ON ${MEDIA_TABLE} (${MediaColumns.mediaType}, ${MediaColumns.createdAt} DESC);`,
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
version: 4,
|
|
170
|
+
description:
|
|
171
|
+
'Add size_is_display_estimate flag: true when file_size is a compressed video’s proportional display figure, not the exact bytes on disk',
|
|
172
|
+
// Purely additive. Existing rows get NULL (read back as false), so nothing
|
|
173
|
+
// that was stored before this column re-stats differently. Only compressed
|
|
174
|
+
// videos published from the editor set it to 1 (see CameraAsset.sizeIsDisplayEstimate).
|
|
175
|
+
statements: [
|
|
176
|
+
`ALTER TABLE ${MEDIA_TABLE} ADD COLUMN ${MediaColumns.sizeIsDisplayEstimate} INTEGER;`,
|
|
177
|
+
],
|
|
178
|
+
},
|
|
179
|
+
];
|
|
180
|
+
|
|
181
|
+
/** The schema version the app expects after all migrations are applied. */
|
|
182
|
+
export const LATEST_SCHEMA_VERSION =
|
|
183
|
+
MIGRATIONS.length > 0 ? MIGRATIONS[MIGRATIONS.length - 1]!.version : 0;
|
|
184
|
+
|
|
185
|
+
/** Minimal executor contract so migrations don't depend on the concrete manager. */
|
|
186
|
+
export interface MigrationExecutor {
|
|
187
|
+
/** Reads the current `PRAGMA user_version`. */
|
|
188
|
+
getVersion(): Promise<number>;
|
|
189
|
+
/** Runs the given statements atomically in a single transaction. */
|
|
190
|
+
runBatch(statements: string[]): Promise<void>;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Applies all pending migrations. Safe to call on every launch — a fully
|
|
195
|
+
* up-to-date database performs only a cheap version read and returns.
|
|
196
|
+
*
|
|
197
|
+
* @returns the schema version after migration.
|
|
198
|
+
*/
|
|
199
|
+
export async function runMigrations(
|
|
200
|
+
executor: MigrationExecutor
|
|
201
|
+
): Promise<number> {
|
|
202
|
+
const currentVersion = await executor.getVersion();
|
|
203
|
+
|
|
204
|
+
if (currentVersion >= LATEST_SCHEMA_VERSION) {
|
|
205
|
+
return currentVersion;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const pending = MIGRATIONS.filter((m) => m.version > currentVersion).sort(
|
|
209
|
+
(a, b) => a.version - b.version
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
for (const migration of pending) {
|
|
213
|
+
// Each migration is atomic: the DDL statements and the version bump land in
|
|
214
|
+
// one transaction, or the whole step rolls back and the next launch retries.
|
|
215
|
+
await executor.runBatch([
|
|
216
|
+
...migration.statements,
|
|
217
|
+
`PRAGMA user_version = ${Math.floor(migration.version)};`,
|
|
218
|
+
]);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return LATEST_SCHEMA_VERSION;
|
|
222
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient type declaration for `react-native-sqlcipher`.
|
|
3
|
+
*
|
|
4
|
+
* `react-native-sqlcipher` is a SQLCipher-backed fork of
|
|
5
|
+
* `react-native-sqlite-storage` and ships without TypeScript types. This
|
|
6
|
+
* declaration types only the subset of the WebSQL-style API that the database
|
|
7
|
+
* layer in `src/db` actually consumes, so the project typechecks whether or not
|
|
8
|
+
* the native package has been installed yet.
|
|
9
|
+
*
|
|
10
|
+
* The runtime API is loaded lazily (see `DatabaseManager`), so a missing package
|
|
11
|
+
* is a graceful runtime fallback rather than a build error.
|
|
12
|
+
*/
|
|
13
|
+
declare module 'react-native-sqlcipher' {
|
|
14
|
+
export interface ResultSetRowList {
|
|
15
|
+
length: number;
|
|
16
|
+
item(index: number): any;
|
|
17
|
+
raw(): any[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ResultSet {
|
|
21
|
+
insertId?: number;
|
|
22
|
+
rowsAffected: number;
|
|
23
|
+
rows: ResultSetRowList;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface Transaction {
|
|
27
|
+
executeSql(
|
|
28
|
+
sqlStatement: string,
|
|
29
|
+
args?: any[]
|
|
30
|
+
): Promise<[Transaction, ResultSet]>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface SQLiteDatabase {
|
|
34
|
+
transaction(scope: (tx: Transaction) => void): Promise<Transaction>;
|
|
35
|
+
readTransaction(scope: (tx: Transaction) => void): Promise<Transaction>;
|
|
36
|
+
executeSql(
|
|
37
|
+
sqlStatement: string,
|
|
38
|
+
args?: any[]
|
|
39
|
+
): Promise<[ResultSet]>;
|
|
40
|
+
close(): Promise<void>;
|
|
41
|
+
attach?(...args: any[]): Promise<any>;
|
|
42
|
+
dbName?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface OpenDatabaseParams {
|
|
46
|
+
/** Database file name, e.g. `media_secure.db`. */
|
|
47
|
+
name: string;
|
|
48
|
+
/** SQLCipher passphrase used to encrypt/decrypt the database. */
|
|
49
|
+
key?: string;
|
|
50
|
+
/** Storage location. `default` = app's internal Documents/Databases dir. */
|
|
51
|
+
location?: 'default' | 'Library' | 'Documents';
|
|
52
|
+
createFromLocation?: number | string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface SQLiteStatic {
|
|
56
|
+
/** Enable promise-based API (must be called before openDatabase). */
|
|
57
|
+
enablePromise(enabled: boolean): void;
|
|
58
|
+
/** Enable/disable verbose native logging. */
|
|
59
|
+
DEBUG(enabled: boolean): void;
|
|
60
|
+
openDatabase(
|
|
61
|
+
params: OpenDatabaseParams
|
|
62
|
+
): Promise<SQLiteDatabase>;
|
|
63
|
+
openDatabase(
|
|
64
|
+
params: OpenDatabaseParams,
|
|
65
|
+
success?: (db: SQLiteDatabase) => void,
|
|
66
|
+
error?: (err: any) => void
|
|
67
|
+
): SQLiteDatabase;
|
|
68
|
+
deleteDatabase(params: {
|
|
69
|
+
name: string;
|
|
70
|
+
location?: string;
|
|
71
|
+
}): Promise<void>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const SQLite: SQLiteStatic;
|
|
75
|
+
export default SQLite;
|
|
76
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encryption-key provisioning for the SQLCipher database.
|
|
3
|
+
*
|
|
4
|
+
* Strategy (most secure first):
|
|
5
|
+
* 1. Native `SecureKeyModule` (Android) — generates a cryptographically random
|
|
6
|
+
* 256-bit key on first launch and persists it in `EncryptedSharedPreferences`,
|
|
7
|
+
* which is sealed by a master key held in the Android Keystore. The raw key
|
|
8
|
+
* material therefore never lives in the JS bundle or in plaintext on disk.
|
|
9
|
+
* 2. Fallback — a locally derived key used only when the native module is
|
|
10
|
+
* unavailable (web, iOS without the native helper, or an older build). This
|
|
11
|
+
* keeps the app functional but is NOT hardware-backed; see the warning below.
|
|
12
|
+
*
|
|
13
|
+
* The resolved key is cached in-memory for the process lifetime so the native
|
|
14
|
+
* bridge is hit at most once.
|
|
15
|
+
*/
|
|
16
|
+
import { NativeModules, Platform } from 'react-native';
|
|
17
|
+
|
|
18
|
+
/** Shape of the optional native key module. */
|
|
19
|
+
interface SecureKeyNativeModule {
|
|
20
|
+
getOrCreateDatabaseKey(): Promise<string>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const nativeKeyModule: SecureKeyNativeModule | undefined = (
|
|
24
|
+
NativeModules as Record<string, SecureKeyNativeModule | undefined>
|
|
25
|
+
).SecureKeyModule;
|
|
26
|
+
|
|
27
|
+
let cachedKey: string | null = null;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Deterministic fallback key. Used ONLY when no native Keystore-backed module is
|
|
31
|
+
* present. It is intentionally derived (not a bare literal) but, because it is
|
|
32
|
+
* reconstructable from the bundle, it does not provide hardware-backed secrecy.
|
|
33
|
+
* On Android the native module supersedes this path.
|
|
34
|
+
*/
|
|
35
|
+
function deriveFallbackKey(): string {
|
|
36
|
+
// A stable, app-scoped seed combined into a 64-hex-char (256-bit) string.
|
|
37
|
+
const seed = `rncc.media.${Platform.OS}.v1.9f3ac21e-secure-media-store`;
|
|
38
|
+
let h1 = 0x811c9dc5;
|
|
39
|
+
let h2 = 0xc2b2ae35;
|
|
40
|
+
for (let i = 0; i < seed.length; i++) {
|
|
41
|
+
const c = seed.charCodeAt(i);
|
|
42
|
+
h1 = Math.imul(h1 ^ c, 0x01000193) >>> 0;
|
|
43
|
+
h2 = Math.imul(h2 ^ c, 0x85ebca77) >>> 0;
|
|
44
|
+
}
|
|
45
|
+
// Expand the two 32-bit hashes into 64 hex chars deterministically.
|
|
46
|
+
let out = '';
|
|
47
|
+
let a = h1 >>> 0;
|
|
48
|
+
let b = h2 >>> 0;
|
|
49
|
+
for (let i = 0; i < 8; i++) {
|
|
50
|
+
a = (Math.imul(a, 0x9e3779b1) + 0x7f4a7c15) >>> 0;
|
|
51
|
+
b = (Math.imul(b, 0x85ebca6b) + 0xc2b2ae35) >>> 0;
|
|
52
|
+
out += a.toString(16).padStart(8, '0');
|
|
53
|
+
out += b.toString(16).padStart(8, '0');
|
|
54
|
+
}
|
|
55
|
+
return out.slice(0, 64);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Resolve the SQLCipher passphrase, preferring the hardware-backed native key.
|
|
60
|
+
* The result is memoized for the lifetime of the JS runtime.
|
|
61
|
+
*/
|
|
62
|
+
export async function getDatabaseKey(): Promise<string> {
|
|
63
|
+
if (cachedKey) return cachedKey;
|
|
64
|
+
|
|
65
|
+
if (nativeKeyModule?.getOrCreateDatabaseKey) {
|
|
66
|
+
try {
|
|
67
|
+
const key = await nativeKeyModule.getOrCreateDatabaseKey();
|
|
68
|
+
if (key && key.length >= 16) {
|
|
69
|
+
cachedKey = key;
|
|
70
|
+
return cachedKey;
|
|
71
|
+
}
|
|
72
|
+
console.warn(
|
|
73
|
+
'[SecureKey] Native module returned an unusable key; using fallback.'
|
|
74
|
+
);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.warn(
|
|
77
|
+
'[SecureKey] Native key retrieval failed; using fallback.',
|
|
78
|
+
error
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
} else if (Platform.OS === 'android') {
|
|
82
|
+
console.warn(
|
|
83
|
+
'[SecureKey] SecureKeyModule not linked. Rebuild the Android app to enable ' +
|
|
84
|
+
'Keystore-backed encryption; using derived fallback key for now.'
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
cachedKey = deriveFallbackKey();
|
|
89
|
+
return cachedKey;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** True when the hardware-backed native key module is available. */
|
|
93
|
+
export function isHardwareBackedKeyAvailable(): boolean {
|
|
94
|
+
return Boolean(nativeKeyModule?.getOrCreateDatabaseKey);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Test/hot-reload helper: clears the in-memory key cache. */
|
|
98
|
+
export function __resetDatabaseKeyCache(): void {
|
|
99
|
+
cachedKey = null;
|
|
100
|
+
}
|
package/src/db/types.ts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strongly-typed media models for the encrypted SQLCipher database.
|
|
3
|
+
*
|
|
4
|
+
* These types describe the *persistence* shape of a media item — the exact
|
|
5
|
+
* columns stored in the `media` table — independently of the UI-facing
|
|
6
|
+
* `CameraAsset` type. Mapping between the two lives in `MediaMapper.ts`, keeping
|
|
7
|
+
* a clean separation between the database schema and the rest of the app.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Persisted media kind. Photos are normalized to `image`; documents and audio
|
|
12
|
+
* are first-class kinds so a picked PDF/track is never mis-stored as an image.
|
|
13
|
+
*/
|
|
14
|
+
export type MediaType = 'image' | 'video' | 'document' | 'audio';
|
|
15
|
+
|
|
16
|
+
/** Where a media item originated. */
|
|
17
|
+
export type MediaSource = 'camera' | 'gallery';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A single row of the `media` table — the canonical, strongly-typed record.
|
|
21
|
+
*
|
|
22
|
+
* `null` is used (never `undefined`) for absent optional columns so the shape
|
|
23
|
+
* maps 1:1 onto SQL rows.
|
|
24
|
+
*/
|
|
25
|
+
export interface MediaRecord {
|
|
26
|
+
/** Unique identifier (primary key). */
|
|
27
|
+
id: string;
|
|
28
|
+
/** `image` or `video`. */
|
|
29
|
+
mediaType: MediaType;
|
|
30
|
+
/** `camera` or `gallery`. */
|
|
31
|
+
source: MediaSource;
|
|
32
|
+
/** Absolute file path or content URI. */
|
|
33
|
+
filePath: string;
|
|
34
|
+
/** Display file name, e.g. `photo_1699999999999.jpg`. */
|
|
35
|
+
fileName: string;
|
|
36
|
+
/** File size in bytes, or null if unknown. */
|
|
37
|
+
fileSize: number | null;
|
|
38
|
+
/** Pixel width, or null if unknown. */
|
|
39
|
+
width: number | null;
|
|
40
|
+
/** Pixel height, or null if unknown. */
|
|
41
|
+
height: number | null;
|
|
42
|
+
/** Duration in milliseconds (videos only), or null. */
|
|
43
|
+
duration: number | null;
|
|
44
|
+
/** MIME type such as `image/jpeg` or `video/mp4`, or null. */
|
|
45
|
+
mimeType: string | null;
|
|
46
|
+
/** Creation timestamp (epoch ms). */
|
|
47
|
+
createdAt: number;
|
|
48
|
+
/** Last-updated timestamp (epoch ms). */
|
|
49
|
+
updatedAt: number;
|
|
50
|
+
/**
|
|
51
|
+
* True when {@link fileSize} is a DISPLAY convention (a compressed video's
|
|
52
|
+
* proportional figure) rather than the exact bytes on disk. Read back onto
|
|
53
|
+
* `CameraAsset.sizeIsDisplayEstimate` so the preview / Info panel keeps the
|
|
54
|
+
* quoted size instead of re-statting the file. Absent (legacy) rows read false.
|
|
55
|
+
*/
|
|
56
|
+
sizeIsDisplayEstimate: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Fields required to insert a new media record. Timestamps are optional on
|
|
61
|
+
* input — the repository fills `createdAt`/`updatedAt` when omitted.
|
|
62
|
+
*/
|
|
63
|
+
export interface MediaRecordInput {
|
|
64
|
+
id: string;
|
|
65
|
+
mediaType: MediaType;
|
|
66
|
+
source: MediaSource;
|
|
67
|
+
filePath: string;
|
|
68
|
+
fileName: string;
|
|
69
|
+
fileSize?: number | null;
|
|
70
|
+
width?: number | null;
|
|
71
|
+
height?: number | null;
|
|
72
|
+
duration?: number | null;
|
|
73
|
+
mimeType?: string | null;
|
|
74
|
+
createdAt?: number;
|
|
75
|
+
updatedAt?: number;
|
|
76
|
+
/** See {@link MediaRecord.sizeIsDisplayEstimate}. Stored as INTEGER 1/0. */
|
|
77
|
+
sizeIsDisplayEstimate?: boolean | null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Filter used when querying the media list. */
|
|
81
|
+
export type MediaFilter = 'all' | 'image' | 'video' | 'document' | 'audio';
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Aggregate counts computed directly from the database via `COUNT(*)`.
|
|
85
|
+
* Backs the filter-card counters (All / Photos / Videos / Documents / Audio).
|
|
86
|
+
*/
|
|
87
|
+
export interface MediaCounts {
|
|
88
|
+
all: number;
|
|
89
|
+
image: number;
|
|
90
|
+
video: number;
|
|
91
|
+
document: number;
|
|
92
|
+
audio: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Options for ordered/paged queries against the media table. */
|
|
96
|
+
export interface MediaQueryOptions {
|
|
97
|
+
filter?: MediaFilter;
|
|
98
|
+
/** Column to order by. Defaults to `createdAt`. */
|
|
99
|
+
orderBy?: 'createdAt' | 'updatedAt' | 'fileName';
|
|
100
|
+
/** Sort direction. Defaults to `DESC` (newest first). */
|
|
101
|
+
direction?: 'ASC' | 'DESC';
|
|
102
|
+
limit?: number;
|
|
103
|
+
offset?: number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Table + column name constants — single source of truth for SQL strings. */
|
|
107
|
+
export const MEDIA_TABLE = 'media';
|
|
108
|
+
|
|
109
|
+
export const MediaColumns = {
|
|
110
|
+
id: 'id',
|
|
111
|
+
mediaType: 'media_type',
|
|
112
|
+
source: 'source',
|
|
113
|
+
filePath: 'file_path',
|
|
114
|
+
fileName: 'file_name',
|
|
115
|
+
fileSize: 'file_size',
|
|
116
|
+
width: 'width',
|
|
117
|
+
height: 'height',
|
|
118
|
+
duration: 'duration',
|
|
119
|
+
mimeType: 'mime_type',
|
|
120
|
+
createdAt: 'created_at',
|
|
121
|
+
updatedAt: 'updated_at',
|
|
122
|
+
sizeIsDisplayEstimate: 'size_is_display_estimate',
|
|
123
|
+
} as const;
|