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,478 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VideoPreview — in-app video preview for a video asset in the full-screen viewer.
|
|
3
|
+
*
|
|
4
|
+
* Provides a polished, native-feel player on top of the native aspect-fit video surface
|
|
5
|
+
* (NativeVideoViewManager owns rotation-correct, contain scaling — the frame is never
|
|
6
|
+
* stretched, zoomed, or cropped for any resolution / orientation):
|
|
7
|
+
* - a lighter, centred play / pause control,
|
|
8
|
+
* - ±10s skip-back / skip-forward controls,
|
|
9
|
+
* - a draggable seek bar with current-time and total-duration readouts.
|
|
10
|
+
*
|
|
11
|
+
* All player state (play, pause, seek, forward, backward, replay, end-of-video) is kept in
|
|
12
|
+
* sync with the native player through onPlaybackProgress / onPlaybackEnded and the `seekTo`
|
|
13
|
+
* view command.
|
|
14
|
+
*/
|
|
15
|
+
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
16
|
+
import {
|
|
17
|
+
View,
|
|
18
|
+
TouchableOpacity,
|
|
19
|
+
StyleSheet,
|
|
20
|
+
Animated,
|
|
21
|
+
PanResponder,
|
|
22
|
+
UIManager,
|
|
23
|
+
findNodeHandle,
|
|
24
|
+
Text,
|
|
25
|
+
Platform,
|
|
26
|
+
type GestureResponderEvent,
|
|
27
|
+
} from 'react-native';
|
|
28
|
+
import type { CameraAsset } from '../../types';
|
|
29
|
+
import { NativeCustomVideoView } from '../../NativeCustomVideoView';
|
|
30
|
+
import { RenderIcon } from '../../icons';
|
|
31
|
+
import { useCameraLocalization } from '../../localization';
|
|
32
|
+
|
|
33
|
+
import { useLibraryPalette, type LibraryPalette } from '../palette';
|
|
34
|
+
import { localizeDigits } from '../localizedFormat';
|
|
35
|
+
|
|
36
|
+
/** How far a single skip-back / skip-forward tap moves the playhead. */
|
|
37
|
+
const SEEK_STEP_MS = 10000;
|
|
38
|
+
const SEEK_STEP_LABEL = '10';
|
|
39
|
+
// While the finger is dragging the scrubber the thumb tracks it every frame, but native seeks
|
|
40
|
+
// are throttled to this cadence so a fast drag can't flood MediaPlayer with seek requests.
|
|
41
|
+
// A final, precise seek always fires on release, so the end position is exact.
|
|
42
|
+
const NATIVE_SEEK_MIN_INTERVAL_MS = 50;
|
|
43
|
+
// Treat the last 100ms as "ended" so a replay tap is offered even if progress stops a frame short.
|
|
44
|
+
const END_EPSILON_MS = 100;
|
|
45
|
+
|
|
46
|
+
const clamp = (value: number, min: number, max: number): number =>
|
|
47
|
+
Math.min(Math.max(value, min), max);
|
|
48
|
+
|
|
49
|
+
const formatTime = (ms: number, locale?: string): string => {
|
|
50
|
+
if (!Number.isFinite(ms) || ms < 0) return localizeDigits('0:00', locale);
|
|
51
|
+
const totalSeconds = Math.floor(ms / 1000);
|
|
52
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
53
|
+
const seconds = totalSeconds % 60;
|
|
54
|
+
return localizeDigits(`${minutes}:${String(seconds).padStart(2, '0')}`, locale);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export interface VideoPreviewProps {
|
|
58
|
+
asset: CameraAsset;
|
|
59
|
+
paused: boolean;
|
|
60
|
+
onTogglePause: () => void;
|
|
61
|
+
onPlaybackEnded?: () => void;
|
|
62
|
+
active: boolean;
|
|
63
|
+
controlsVisible: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Fired ONLY when the video playback area itself is tapped. The host toggles the three transport
|
|
66
|
+
* controls: a tap reveals them, and a tap while they are showing hides them again. There is no
|
|
67
|
+
* auto-hide timer — once shown the controls stay until the video is tapped again. Deliberately
|
|
68
|
+
* scoped to the video surface: the X/close, counter, Share/Delete/Info and surrounding chrome are
|
|
69
|
+
* OUTSIDE this handler and never affect (or trigger) control visibility.
|
|
70
|
+
*/
|
|
71
|
+
onVideoAreaPress: () => void;
|
|
72
|
+
onControlInteraction: () => void;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const VideoPreview = ({
|
|
76
|
+
asset,
|
|
77
|
+
paused,
|
|
78
|
+
onTogglePause,
|
|
79
|
+
onPlaybackEnded,
|
|
80
|
+
active,
|
|
81
|
+
controlsVisible,
|
|
82
|
+
onVideoAreaPress,
|
|
83
|
+
onControlInteraction,
|
|
84
|
+
}: VideoPreviewProps) => {
|
|
85
|
+
const { t, locale } = useCameraLocalization();
|
|
86
|
+
const palette = useLibraryPalette();
|
|
87
|
+
const styles = useMemo(() => makeStyles(palette), [palette]);
|
|
88
|
+
const seekLabel = localizeDigits(SEEK_STEP_LABEL, locale);
|
|
89
|
+
const previewUri = asset.documentUri || asset.uri;
|
|
90
|
+
const nativeRef = useRef<null | { focus?: () => void }>(null);
|
|
91
|
+
|
|
92
|
+
const [currentTimeMs, setCurrentTimeMs] = useState(0);
|
|
93
|
+
const [durationMs, setDurationMs] = useState(0);
|
|
94
|
+
|
|
95
|
+
// Measured width of the scrubber track, used to turn a touch X into a 0..1 ratio.
|
|
96
|
+
const trackWidthRef = useRef(0);
|
|
97
|
+
// True while the finger is down on the scrubber: native progress events are ignored for the
|
|
98
|
+
// playhead so the thumb tracks the finger instead of being yanked back by the player's
|
|
99
|
+
// reported position (which lags a drag by up to one 200ms progress tick).
|
|
100
|
+
const isScrubbingRef = useRef(false);
|
|
101
|
+
// Latest scrub ratio, kept in a ref for the terminate handler (which has no event X).
|
|
102
|
+
const scrubValueRef = useRef(0);
|
|
103
|
+
// Timestamp of the last native seek dispatched mid-drag (throttling — see the constant above).
|
|
104
|
+
const lastNativeSeekRef = useRef(0);
|
|
105
|
+
// The one source of truth for the fill + thumb visual position. Driving it with `setValue`
|
|
106
|
+
// moves the connected Animated.Views directly (no React reconciliation), so the thumb tracks
|
|
107
|
+
// the finger every frame instead of dropping frames on per-move `setState` re-renders.
|
|
108
|
+
const scrubAnimationRef = useRef(new Animated.Value(0)).current;
|
|
109
|
+
|
|
110
|
+
const syncSeekFromNative = useCallback((nextCurrent: number, nextDuration: number) => {
|
|
111
|
+
const safeDuration = Number.isFinite(nextDuration) ? Math.max(0, nextDuration) : 0;
|
|
112
|
+
const safeCurrent = Number.isFinite(nextCurrent) ? Math.max(0, nextCurrent) : 0;
|
|
113
|
+
const boundedCurrent = safeDuration > 0 ? Math.min(safeCurrent, safeDuration) : 0;
|
|
114
|
+
const ratio = safeDuration > 0 ? boundedCurrent / safeDuration : 0;
|
|
115
|
+
setDurationMs(safeDuration);
|
|
116
|
+
setCurrentTimeMs(boundedCurrent);
|
|
117
|
+
scrubValueRef.current = ratio;
|
|
118
|
+
scrubAnimationRef.setValue(ratio);
|
|
119
|
+
}, []);
|
|
120
|
+
|
|
121
|
+
// Low-level: send the seek command to the native player only (no optimistic UI update). The
|
|
122
|
+
// native side clamps to the real duration and uses SEEK_CLOSEST, and every call is guarded, so
|
|
123
|
+
// rapid repeated seeks (a fast drag) can neither crash nor reset the clip.
|
|
124
|
+
const dispatchNativeSeek = useCallback((targetMs: number) => {
|
|
125
|
+
const handle = findNodeHandle(nativeRef.current as any);
|
|
126
|
+
if (handle === null || handle === undefined) return;
|
|
127
|
+
const safeMs = Number.isFinite(targetMs) ? Math.max(0, Math.round(targetMs)) : 0;
|
|
128
|
+
const manager = (UIManager as any).NativeCustomVideoView;
|
|
129
|
+
const commandId = manager?.Commands?.seekTo ?? 1;
|
|
130
|
+
if (Platform.OS === 'android') {
|
|
131
|
+
UIManager.dispatchViewManagerCommand(handle, commandId, [safeMs]);
|
|
132
|
+
}
|
|
133
|
+
}, []);
|
|
134
|
+
|
|
135
|
+
// Seek to an absolute position and immediately reflect it in the UI (skip buttons + replay).
|
|
136
|
+
const seekTo = useCallback(
|
|
137
|
+
(targetMs: number) => {
|
|
138
|
+
const bounded = durationMs > 0 ? clamp(targetMs, 0, durationMs) : Math.max(0, targetMs);
|
|
139
|
+
dispatchNativeSeek(bounded);
|
|
140
|
+
const ratio = durationMs > 0 ? bounded / durationMs : 0;
|
|
141
|
+
setCurrentTimeMs(bounded);
|
|
142
|
+
scrubValueRef.current = ratio;
|
|
143
|
+
// Move the thumb immediately (skip / replay) rather than waiting for the next progress tick.
|
|
144
|
+
scrubAnimationRef.setValue(ratio);
|
|
145
|
+
},
|
|
146
|
+
[durationMs, dispatchNativeSeek]
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const handleSeekDelta = useCallback(
|
|
150
|
+
(deltaMs: number) => {
|
|
151
|
+
const base = durationMs > 0 ? currentTimeMs : 0;
|
|
152
|
+
seekTo(base + deltaMs);
|
|
153
|
+
},
|
|
154
|
+
[currentTimeMs, durationMs, seekTo]
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const handlePrimaryAction = useCallback(() => {
|
|
158
|
+
const ended = durationMs > 0 && currentTimeMs >= durationMs - END_EPSILON_MS;
|
|
159
|
+
if (ended) {
|
|
160
|
+
// Replay from the start; if we were paused at the end, resume playing too.
|
|
161
|
+
seekTo(0);
|
|
162
|
+
if (paused) onTogglePause();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
onTogglePause();
|
|
166
|
+
}, [currentTimeMs, durationMs, onTogglePause, paused, seekTo]);
|
|
167
|
+
|
|
168
|
+
// Drag/tap the scrubber. The thumb + fill are moved every frame through the Animated.Value
|
|
169
|
+
// (a direct native update — no React re-render), while the time-label `setState` and the native
|
|
170
|
+
// seek are throttled together so a fast drag neither janks on reconciliation nor floods
|
|
171
|
+
// MediaPlayer. A final, precise update always fires on release (`commit`).
|
|
172
|
+
const scrubTo = useCallback(
|
|
173
|
+
(ratio: number, commit: boolean) => {
|
|
174
|
+
const clampedRatio = clamp(ratio, 0, 1);
|
|
175
|
+
const target = durationMs > 0 ? clampedRatio * durationMs : 0;
|
|
176
|
+
scrubValueRef.current = clampedRatio;
|
|
177
|
+
scrubAnimationRef.setValue(clampedRatio);
|
|
178
|
+
const now = Date.now();
|
|
179
|
+
if (commit) {
|
|
180
|
+
lastNativeSeekRef.current = now;
|
|
181
|
+
setCurrentTimeMs(target);
|
|
182
|
+
dispatchNativeSeek(target);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (now - lastNativeSeekRef.current >= NATIVE_SEEK_MIN_INTERVAL_MS) {
|
|
186
|
+
lastNativeSeekRef.current = now;
|
|
187
|
+
setCurrentTimeMs(target);
|
|
188
|
+
dispatchNativeSeek(target);
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
[durationMs, dispatchNativeSeek]
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const panResponder = useMemo(
|
|
195
|
+
() =>
|
|
196
|
+
PanResponder.create({
|
|
197
|
+
onStartShouldSetPanResponder: () => true,
|
|
198
|
+
onMoveShouldSetPanResponder: () => true,
|
|
199
|
+
// Win the gesture over the enclosing horizontal pager so a sideways drag on the bar
|
|
200
|
+
// scrubs the video instead of paging to the next slide.
|
|
201
|
+
onMoveShouldSetPanResponderCapture: () => true,
|
|
202
|
+
onPanResponderTerminationRequest: () => false,
|
|
203
|
+
onPanResponderGrant: (evt: GestureResponderEvent) => {
|
|
204
|
+
onControlInteraction();
|
|
205
|
+
isScrubbingRef.current = true;
|
|
206
|
+
const width = trackWidthRef.current;
|
|
207
|
+
if (width > 0) scrubTo(evt.nativeEvent.locationX / width, false);
|
|
208
|
+
},
|
|
209
|
+
onPanResponderMove: (evt: GestureResponderEvent) => {
|
|
210
|
+
const width = trackWidthRef.current;
|
|
211
|
+
if (width > 0) scrubTo(evt.nativeEvent.locationX / width, false);
|
|
212
|
+
},
|
|
213
|
+
onPanResponderRelease: (evt: GestureResponderEvent) => {
|
|
214
|
+
const width = trackWidthRef.current;
|
|
215
|
+
const ratio = width > 0 ? evt.nativeEvent.locationX / width : scrubValueRef.current;
|
|
216
|
+
scrubTo(ratio, true);
|
|
217
|
+
isScrubbingRef.current = false;
|
|
218
|
+
// Keep the controls visible after the drag finishes (they no longer auto-hide).
|
|
219
|
+
onControlInteraction();
|
|
220
|
+
},
|
|
221
|
+
onPanResponderTerminate: () => {
|
|
222
|
+
scrubTo(scrubValueRef.current, true);
|
|
223
|
+
isScrubbingRef.current = false;
|
|
224
|
+
},
|
|
225
|
+
}),
|
|
226
|
+
[scrubTo, onControlInteraction]
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
return (
|
|
230
|
+
<View style={styles.wrap}>
|
|
231
|
+
<View style={styles.videoWrapper}>
|
|
232
|
+
<NativeCustomVideoView
|
|
233
|
+
ref={nativeRef as any}
|
|
234
|
+
src={previewUri}
|
|
235
|
+
style={styles.video}
|
|
236
|
+
active={active}
|
|
237
|
+
paused={paused}
|
|
238
|
+
onPlaybackProgress={(event) => {
|
|
239
|
+
const { currentTimeMs: nextCurrent, durationMs: nextDuration } = event.nativeEvent;
|
|
240
|
+
if (isScrubbingRef.current) {
|
|
241
|
+
// Keep the duration fresh, but don't fight the finger over the playhead.
|
|
242
|
+
const safeDuration = Number.isFinite(nextDuration) ? Math.max(0, nextDuration) : 0;
|
|
243
|
+
setDurationMs(safeDuration);
|
|
244
|
+
} else {
|
|
245
|
+
syncSeekFromNative(nextCurrent, nextDuration);
|
|
246
|
+
}
|
|
247
|
+
}}
|
|
248
|
+
onPlaybackEnded={(event) => {
|
|
249
|
+
const endedDuration = event.nativeEvent.durationMs;
|
|
250
|
+
syncSeekFromNative(endedDuration, endedDuration);
|
|
251
|
+
onPlaybackEnded?.();
|
|
252
|
+
}}
|
|
253
|
+
/>
|
|
254
|
+
|
|
255
|
+
{/* Dedicated video-area press handler. It fills ONLY the video surface (inside
|
|
256
|
+
videoWrapper) and sits UNDER the transport controls / scrubber, so tapping the video
|
|
257
|
+
toggles the controls (show, then hide on the next tap), while taps on the buttons or the
|
|
258
|
+
scrubber are handled by those (on top) and never reach here. Chrome outside this
|
|
259
|
+
wrapper — X/close, counter, Share/Delete/Info — is a sibling elsewhere in the tree and
|
|
260
|
+
is wholly unaffected. */}
|
|
261
|
+
<TouchableOpacity
|
|
262
|
+
style={StyleSheet.absoluteFill}
|
|
263
|
+
activeOpacity={1}
|
|
264
|
+
onPress={onVideoAreaPress}
|
|
265
|
+
accessibilityLabel={t('toggleVideoControls')}
|
|
266
|
+
/>
|
|
267
|
+
|
|
268
|
+
{controlsVisible && (
|
|
269
|
+
<>
|
|
270
|
+
<View style={styles.controlsOverlay} pointerEvents="box-none">
|
|
271
|
+
<TouchableOpacity
|
|
272
|
+
style={styles.skipButton}
|
|
273
|
+
activeOpacity={0.7}
|
|
274
|
+
hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
|
|
275
|
+
onPress={() => {
|
|
276
|
+
onControlInteraction();
|
|
277
|
+
handleSeekDelta(-SEEK_STEP_MS);
|
|
278
|
+
}}
|
|
279
|
+
accessibilityRole="button"
|
|
280
|
+
accessibilityLabel={t('seekBackward', seekLabel)}
|
|
281
|
+
>
|
|
282
|
+
<RenderIcon name="circular_seek" direction="back" label={seekLabel} size={24} color={palette.whiteA90} strokeWidth={2} />
|
|
283
|
+
</TouchableOpacity>
|
|
284
|
+
|
|
285
|
+
<TouchableOpacity
|
|
286
|
+
style={styles.playButton}
|
|
287
|
+
activeOpacity={0.8}
|
|
288
|
+
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
|
289
|
+
onPress={() => {
|
|
290
|
+
onControlInteraction();
|
|
291
|
+
handlePrimaryAction();
|
|
292
|
+
}}
|
|
293
|
+
accessibilityRole="button"
|
|
294
|
+
accessibilityLabel={t(paused ? 'play' : 'pause')}
|
|
295
|
+
>
|
|
296
|
+
<View style={styles.playBackdrop}>
|
|
297
|
+
{/* A play triangle is optically left-heavy in a circle — nudge it right. */}
|
|
298
|
+
<View style={{ paddingLeft: paused ? 3 : 0 }}>
|
|
299
|
+
<RenderIcon name={paused ? 'play' : 'pause'} size={30} color={palette.whiteA90} />
|
|
300
|
+
</View>
|
|
301
|
+
</View>
|
|
302
|
+
</TouchableOpacity>
|
|
303
|
+
|
|
304
|
+
<TouchableOpacity
|
|
305
|
+
style={styles.skipButton}
|
|
306
|
+
activeOpacity={0.7}
|
|
307
|
+
hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
|
|
308
|
+
onPress={() => {
|
|
309
|
+
onControlInteraction();
|
|
310
|
+
handleSeekDelta(SEEK_STEP_MS);
|
|
311
|
+
}}
|
|
312
|
+
accessibilityRole="button"
|
|
313
|
+
accessibilityLabel={t('seekForward', seekLabel)}
|
|
314
|
+
>
|
|
315
|
+
<RenderIcon name="circular_seek" direction="forward" label={seekLabel} size={24} color={palette.whiteA90} strokeWidth={2} />
|
|
316
|
+
</TouchableOpacity>
|
|
317
|
+
</View>
|
|
318
|
+
<View style={styles.scrubberWrap}>
|
|
319
|
+
<View style={styles.timeRow} pointerEvents="none">
|
|
320
|
+
<Text style={styles.timeLabel}>{formatTime(currentTimeMs, locale)}</Text>
|
|
321
|
+
<Text style={styles.timeLabel}>{formatTime(durationMs, locale)}</Text>
|
|
322
|
+
</View>
|
|
323
|
+
<View
|
|
324
|
+
style={styles.scrubberTouch}
|
|
325
|
+
onLayout={(event) => {
|
|
326
|
+
trackWidthRef.current = event.nativeEvent.layout.width;
|
|
327
|
+
}}
|
|
328
|
+
{...panResponder.panHandlers}
|
|
329
|
+
>
|
|
330
|
+
<View style={styles.scrubberTrack}>
|
|
331
|
+
<Animated.View
|
|
332
|
+
style={[
|
|
333
|
+
styles.scrubberFill,
|
|
334
|
+
{
|
|
335
|
+
width: scrubAnimationRef.interpolate({
|
|
336
|
+
inputRange: [0, 1],
|
|
337
|
+
outputRange: ['0%', '100%'],
|
|
338
|
+
}),
|
|
339
|
+
},
|
|
340
|
+
]}
|
|
341
|
+
/>
|
|
342
|
+
<Animated.View
|
|
343
|
+
style={[
|
|
344
|
+
styles.scrubberThumb,
|
|
345
|
+
{
|
|
346
|
+
left: scrubAnimationRef.interpolate({
|
|
347
|
+
inputRange: [0, 1],
|
|
348
|
+
outputRange: ['0%', '100%'],
|
|
349
|
+
}),
|
|
350
|
+
},
|
|
351
|
+
]}
|
|
352
|
+
/>
|
|
353
|
+
</View>
|
|
354
|
+
</View>
|
|
355
|
+
</View>
|
|
356
|
+
</>
|
|
357
|
+
)}
|
|
358
|
+
</View>
|
|
359
|
+
</View>
|
|
360
|
+
);
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
const makeStyles = (palette: LibraryPalette) =>
|
|
364
|
+
StyleSheet.create({
|
|
365
|
+
wrap: {
|
|
366
|
+
flex: 1,
|
|
367
|
+
width: '100%',
|
|
368
|
+
overflow: 'hidden',
|
|
369
|
+
},
|
|
370
|
+
videoWrapper: {
|
|
371
|
+
flex: 1,
|
|
372
|
+
justifyContent: 'center',
|
|
373
|
+
alignItems: 'center',
|
|
374
|
+
overflow: 'hidden',
|
|
375
|
+
position: 'relative',
|
|
376
|
+
minHeight: 220,
|
|
377
|
+
},
|
|
378
|
+
video: {
|
|
379
|
+
flex: 1,
|
|
380
|
+
width: '100%',
|
|
381
|
+
height: '100%',
|
|
382
|
+
},
|
|
383
|
+
controlsOverlay: {
|
|
384
|
+
position: 'absolute',
|
|
385
|
+
left: 0,
|
|
386
|
+
right: 0,
|
|
387
|
+
bottom: 0,
|
|
388
|
+
top: 0,
|
|
389
|
+
flexDirection: 'row',
|
|
390
|
+
justifyContent: 'center',
|
|
391
|
+
alignItems: 'center',
|
|
392
|
+
gap: 26,
|
|
393
|
+
},
|
|
394
|
+
skipButton: {
|
|
395
|
+
width: 44,
|
|
396
|
+
height: 44,
|
|
397
|
+
borderRadius: 22,
|
|
398
|
+
justifyContent: 'center',
|
|
399
|
+
alignItems: 'center',
|
|
400
|
+
backgroundColor: 'rgba(0,0,0,0.18)',
|
|
401
|
+
borderWidth: 1,
|
|
402
|
+
borderColor: 'rgba(255,255,255,0.12)',
|
|
403
|
+
},
|
|
404
|
+
playButton: {
|
|
405
|
+
justifyContent: 'center',
|
|
406
|
+
alignItems: 'center',
|
|
407
|
+
backgroundColor: 'transparent',
|
|
408
|
+
},
|
|
409
|
+
// Subtle scrim so the lighter icon stays clearly visible over any (even bright) frame.
|
|
410
|
+
playBackdrop: {
|
|
411
|
+
width: 58,
|
|
412
|
+
height: 58,
|
|
413
|
+
borderRadius: 29,
|
|
414
|
+
justifyContent: 'center',
|
|
415
|
+
alignItems: 'center',
|
|
416
|
+
backgroundColor: 'rgba(0,0,0,0.25)',
|
|
417
|
+
},
|
|
418
|
+
scrubberWrap: {
|
|
419
|
+
position: 'absolute',
|
|
420
|
+
left: 0,
|
|
421
|
+
right: 0,
|
|
422
|
+
bottom: 4,
|
|
423
|
+
width: '100%',
|
|
424
|
+
paddingHorizontal: 18,
|
|
425
|
+
paddingTop: 4,
|
|
426
|
+
paddingBottom: 2,
|
|
427
|
+
backgroundColor: 'rgba(0,0,0,0.22)',
|
|
428
|
+
},
|
|
429
|
+
// Tall, full-width hit area so the thin bar is still easy to grab and drag.
|
|
430
|
+
scrubberTouch: {
|
|
431
|
+
width: '100%',
|
|
432
|
+
height: 28,
|
|
433
|
+
justifyContent: 'center',
|
|
434
|
+
},
|
|
435
|
+
scrubberTrack: {
|
|
436
|
+
width: '100%',
|
|
437
|
+
height: 4,
|
|
438
|
+
borderRadius: 2,
|
|
439
|
+
position: 'relative',
|
|
440
|
+
justifyContent: 'center',
|
|
441
|
+
backgroundColor: 'rgba(255,255,255,0.25)',
|
|
442
|
+
},
|
|
443
|
+
scrubberFill: {
|
|
444
|
+
position: 'absolute',
|
|
445
|
+
left: 0,
|
|
446
|
+
top: 0,
|
|
447
|
+
height: 4,
|
|
448
|
+
borderRadius: 2,
|
|
449
|
+
backgroundColor: palette.primary,
|
|
450
|
+
},
|
|
451
|
+
scrubberThumb: {
|
|
452
|
+
position: 'absolute',
|
|
453
|
+
top: -5,
|
|
454
|
+
width: 14,
|
|
455
|
+
height: 14,
|
|
456
|
+
borderRadius: 7,
|
|
457
|
+
backgroundColor: palette.white,
|
|
458
|
+
marginLeft: -7,
|
|
459
|
+
elevation: 3,
|
|
460
|
+
shadowColor: '#000',
|
|
461
|
+
shadowOpacity: 0.25,
|
|
462
|
+
shadowRadius: 4,
|
|
463
|
+
shadowOffset: { width: 0, height: 2 },
|
|
464
|
+
},
|
|
465
|
+
timeRow: {
|
|
466
|
+
flexDirection: 'row',
|
|
467
|
+
justifyContent: 'space-between',
|
|
468
|
+
alignItems: 'center',
|
|
469
|
+
marginBottom: 2,
|
|
470
|
+
},
|
|
471
|
+
timeLabel: {
|
|
472
|
+
// Sits over the video (behind a dark scrubber scrim) — stays light in both themes.
|
|
473
|
+
color: palette.white,
|
|
474
|
+
fontSize: 12,
|
|
475
|
+
fontWeight: '500',
|
|
476
|
+
opacity: 0.9,
|
|
477
|
+
},
|
|
478
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ViewerCounter — the "3 / 16" position readout in the full-screen viewer's top-right corner.
|
|
3
|
+
*
|
|
4
|
+
* Exists as its own component purely for update cost. The counter has to track the finger, which
|
|
5
|
+
* means reacting to `onScroll` (~60 events/sec), and the viewer lives inside the app's root
|
|
6
|
+
* component — pushing the live index into that component's state would re-render the whole screen
|
|
7
|
+
* (and re-run the viewer FlatList's renderItem identity) on every slide crossing of a fast fling.
|
|
8
|
+
*
|
|
9
|
+
* So the parent drives this imperatively through a ref: `setIndex()` re-renders these two lines of
|
|
10
|
+
* text and nothing else. The `index` prop remains the source of truth for React-driven changes
|
|
11
|
+
* (opening the viewer, momentum settling, a resize re-snap) and re-syncs the local value whenever
|
|
12
|
+
* it changes, so the imperative fast path can never leave the counter out of step at rest.
|
|
13
|
+
*/
|
|
14
|
+
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
|
|
15
|
+
import { Text, type StyleProp, type TextStyle } from 'react-native';
|
|
16
|
+
import { useCameraLocalization } from '../../localization';
|
|
17
|
+
import { localizeDigits } from '../localizedFormat';
|
|
18
|
+
|
|
19
|
+
export interface ViewerCounterHandle {
|
|
20
|
+
/** Show `index` (0-based) immediately. Ignored when it doesn't change the rendered text. */
|
|
21
|
+
setIndex: (index: number) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ViewerCounterProps {
|
|
25
|
+
/** Settled 0-based position — re-syncs the counter when the parent moves it. */
|
|
26
|
+
index: number;
|
|
27
|
+
total: number;
|
|
28
|
+
style?: StyleProp<TextStyle>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const ViewerCounter = forwardRef<ViewerCounterHandle, ViewerCounterProps>(
|
|
32
|
+
({ index, total, style }, ref) => {
|
|
33
|
+
const { t, locale } = useCameraLocalization();
|
|
34
|
+
const [displayIndex, setDisplayIndex] = useState(index);
|
|
35
|
+
|
|
36
|
+
// Parent-driven moves (open, momentum end, resize re-snap) win over whatever the last
|
|
37
|
+
// scroll frame left behind.
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
setDisplayIndex(index);
|
|
40
|
+
}, [index]);
|
|
41
|
+
|
|
42
|
+
useImperativeHandle(
|
|
43
|
+
ref,
|
|
44
|
+
() => ({
|
|
45
|
+
setIndex: (next: number) => {
|
|
46
|
+
// Bail on an unchanged value so a 60Hz scroll stream costs one setState per slide
|
|
47
|
+
// crossing, not one per frame. React would bail out on an identical value anyway;
|
|
48
|
+
// this skips the dispatch entirely.
|
|
49
|
+
setDisplayIndex((prev) => (prev === next ? prev : next));
|
|
50
|
+
},
|
|
51
|
+
}),
|
|
52
|
+
[]
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// An empty list would render "1 / 0"; clamp so the readout stays sane while a delete is
|
|
56
|
+
// in flight.
|
|
57
|
+
const position = total > 0 ? Math.min(displayIndex, total - 1) + 1 : 0;
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Text style={style}>
|
|
61
|
+
{t(
|
|
62
|
+
'mediaCounter',
|
|
63
|
+
localizeDigits(String(position), locale),
|
|
64
|
+
localizeDigits(String(total), locale)
|
|
65
|
+
)}
|
|
66
|
+
</Text>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
ViewerCounter.displayName = 'ViewerCounter';
|