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,124 @@
|
|
|
1
|
+
package com.customcamera.gif
|
|
2
|
+
|
|
3
|
+
import android.os.Handler
|
|
4
|
+
import android.os.Looper
|
|
5
|
+
import java.util.concurrent.ExecutorService
|
|
6
|
+
import java.util.concurrent.Executors
|
|
7
|
+
import java.util.concurrent.atomic.AtomicLong
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Background-thread orchestrator between the GIF picker UI and a [GifProvider].
|
|
11
|
+
*
|
|
12
|
+
* The UI never touches a [GifProvider] directly: it calls the repository, which runs the blocking
|
|
13
|
+
* provider call on a worker thread and delivers the typed [GifResult] back on the main thread. A
|
|
14
|
+
* single generation counter implements "latest wins" — when the user starts a new search (or
|
|
15
|
+
* clears it back to trending) any still-in-flight list request is dropped so a slow earlier
|
|
16
|
+
* response can never overwrite the newer list. Pagination ([loadMore]) deliberately does NOT bump
|
|
17
|
+
* the generation, so it continues the current list, but it is dropped if the list changed while it
|
|
18
|
+
* was loading.
|
|
19
|
+
*
|
|
20
|
+
* Categories are cached after the first success (they change rarely) and replayed synchronously.
|
|
21
|
+
*
|
|
22
|
+
* The owner (the picker) must call [shutdown] when it closes to release the worker threads.
|
|
23
|
+
*/
|
|
24
|
+
class GifRepository(private val provider: GifProvider) {
|
|
25
|
+
|
|
26
|
+
private val executor: ExecutorService = Executors.newFixedThreadPool(2) { r ->
|
|
27
|
+
Thread(r, "gif-repo").apply { isDaemon = true }
|
|
28
|
+
}
|
|
29
|
+
private val main = Handler(Looper.getMainLooper())
|
|
30
|
+
|
|
31
|
+
/** Bumped by [refreshList]; a delivered result is discarded when this no longer matches. */
|
|
32
|
+
private val listGeneration = AtomicLong(0)
|
|
33
|
+
|
|
34
|
+
@Volatile private var cachedCategories: List<GifCategory>? = null
|
|
35
|
+
@Volatile private var shutdown = false
|
|
36
|
+
|
|
37
|
+
val attributionLabel: String? get() = provider.attributionLabel
|
|
38
|
+
|
|
39
|
+
fun isConfigured(): Boolean = provider.isConfigured()
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Load the first page of a list. [query] null/blank ⇒ trending; otherwise search results.
|
|
43
|
+
* Supersedes any earlier in-flight list request. [onResult] runs on the main thread.
|
|
44
|
+
*/
|
|
45
|
+
fun refreshList(query: String?, limit: Int, onResult: (GifResult<GifPage>) -> Unit) {
|
|
46
|
+
val generation = listGeneration.incrementAndGet()
|
|
47
|
+
if (!query.isNullOrBlank() && GifSafety.isBlockedQuery(query)) {
|
|
48
|
+
main.post { onResult(GifResult.Success(GifPage(emptyList(), null))) }
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
submitList(query, limit, cursor = null, generation = generation, onResult = onResult)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Load the next page of the CURRENT list (continuation of the last [refreshList]). The result is
|
|
56
|
+
* dropped if the user changed the list meanwhile. [cursor] comes from [GifPage.nextCursor].
|
|
57
|
+
*/
|
|
58
|
+
fun loadMore(query: String?, limit: Int, cursor: String, onResult: (GifResult<GifPage>) -> Unit) {
|
|
59
|
+
val generation = listGeneration.get()
|
|
60
|
+
submitList(query, limit, cursor = cursor, generation = generation, onResult = onResult)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private fun submitList(
|
|
64
|
+
query: String?,
|
|
65
|
+
limit: Int,
|
|
66
|
+
cursor: String?,
|
|
67
|
+
generation: Long,
|
|
68
|
+
onResult: (GifResult<GifPage>) -> Unit
|
|
69
|
+
) {
|
|
70
|
+
if (shutdown) return
|
|
71
|
+
execute {
|
|
72
|
+
val result = if (query.isNullOrBlank()) {
|
|
73
|
+
provider.trending(limit, cursor)
|
|
74
|
+
} else {
|
|
75
|
+
provider.search(query, limit, cursor)
|
|
76
|
+
}
|
|
77
|
+
val safeResult = when (result) {
|
|
78
|
+
is GifResult.Success -> GifResult.Success(GifSafety.filterPage(result.value))
|
|
79
|
+
is GifResult.Failure -> result
|
|
80
|
+
}
|
|
81
|
+
deliver(onResult, safeResult) { listGeneration.get() == generation }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Load browsable categories, served from cache after the first success. Main-thread callback. */
|
|
86
|
+
fun loadCategories(onResult: (GifResult<List<GifCategory>>) -> Unit) {
|
|
87
|
+
cachedCategories?.let { cached ->
|
|
88
|
+
main.post { onResult(GifResult.Success(cached)) }
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
if (shutdown) return
|
|
92
|
+
execute {
|
|
93
|
+
val result = provider.categories()
|
|
94
|
+
if (result is GifResult.Success) cachedCategories = result.value
|
|
95
|
+
deliver(onResult, result) { true }
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private fun <T> deliver(
|
|
100
|
+
onResult: (GifResult<T>) -> Unit,
|
|
101
|
+
result: GifResult<T>,
|
|
102
|
+
isStillCurrent: () -> Boolean
|
|
103
|
+
) {
|
|
104
|
+
main.post {
|
|
105
|
+
if (!shutdown && isStillCurrent()) onResult(result)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private fun execute(block: () -> Unit) {
|
|
110
|
+
try {
|
|
111
|
+
executor.execute {
|
|
112
|
+
if (!shutdown) block()
|
|
113
|
+
}
|
|
114
|
+
} catch (e: Exception) {
|
|
115
|
+
// Executor rejected (already shut down) — nothing to deliver.
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Stop delivering results and release worker threads. Safe to call more than once. */
|
|
120
|
+
fun shutdown() {
|
|
121
|
+
shutdown = true
|
|
122
|
+
executor.shutdownNow()
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
package com.customcamera.gif
|
|
2
|
+
|
|
3
|
+
/** Shared client-side guard for queries and provider-returned GIF descriptions. */
|
|
4
|
+
internal object GifSafety {
|
|
5
|
+
|
|
6
|
+
private val blockedTerms = setOf(
|
|
7
|
+
"kiss", "kissing", "makeout", "nude", "nudes", "naked", "nsfw", "porn", "porno",
|
|
8
|
+
"xxx", "sex", "sexual", "erotic", "hentai", "fetish", "topless", "uncensored",
|
|
9
|
+
"orgasm", "masturbat", "blowjob", "handjob", "intercourse", "vagina", "penis",
|
|
10
|
+
"dick", "pussy", "boob", "breast", "tits", "anal", "bdsm", "cum", "semen"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
fun isBlockedQuery(query: String): Boolean = containsBlockedTerm(query)
|
|
14
|
+
|
|
15
|
+
fun filterPage(page: GifPage): GifPage = page.copy(
|
|
16
|
+
items = page.items.filterNot { item ->
|
|
17
|
+
containsBlockedTerm(item.description) ||
|
|
18
|
+
containsBlockedTerm(item.previewUrl) ||
|
|
19
|
+
containsBlockedTerm(item.contentUrl)
|
|
20
|
+
}
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
private fun containsBlockedTerm(value: String): Boolean {
|
|
24
|
+
val normalized = value.lowercase()
|
|
25
|
+
return blockedTerms.any { term ->
|
|
26
|
+
if (term.length < 4) {
|
|
27
|
+
Regex("\\b${Regex.escape(term)}\\b").containsMatchIn(normalized)
|
|
28
|
+
} else {
|
|
29
|
+
normalized.contains(term)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
package com.customcamera.gif
|
|
2
|
+
|
|
3
|
+
import java.net.URLEncoder
|
|
4
|
+
import org.json.JSONObject
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* [GifProvider] backed by the GIPHY HTTP API (v1).
|
|
8
|
+
*
|
|
9
|
+
* All calls block on [GifHttp] and fold every failure into a typed [GifResult.Failure]; nothing
|
|
10
|
+
* throws. GIPHY paginates by integer offset, so the opaque [GifPage.nextCursor] carried across
|
|
11
|
+
* pages is simply the next offset rendered as a string.
|
|
12
|
+
*
|
|
13
|
+
* @param apiKey GIPHY API key; when null/blank the provider reports [isConfigured] == false and
|
|
14
|
+
* every call short-circuits with [GifError.NO_API_KEY].
|
|
15
|
+
*/
|
|
16
|
+
class GiphyGifProvider(private val apiKey: String?) : GifProvider {
|
|
17
|
+
|
|
18
|
+
override val id: String = "giphy"
|
|
19
|
+
|
|
20
|
+
override val attributionLabel: String? = "Powered by GIPHY"
|
|
21
|
+
|
|
22
|
+
override fun isConfigured(): Boolean = !apiKey.isNullOrBlank()
|
|
23
|
+
|
|
24
|
+
override fun trending(limit: Int, cursor: String?): GifResult<GifPage> {
|
|
25
|
+
val key = apiKey
|
|
26
|
+
if (key.isNullOrBlank()) return GifResult.Failure(GifError.NO_API_KEY)
|
|
27
|
+
val offset = cursor?.toIntOrNull() ?: 0
|
|
28
|
+
val url = "$BASE/gifs/trending?api_key=${enc(key)}&limit=$limit&offset=$offset" +
|
|
29
|
+
"&rating=g&bundle=messaging_non_clips"
|
|
30
|
+
return when (val res = GifHttp.getJson(url)) {
|
|
31
|
+
is GifResult.Failure -> res
|
|
32
|
+
is GifResult.Success -> parsePage(res.value, limit, offset)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
override fun search(query: String, limit: Int, cursor: String?): GifResult<GifPage> {
|
|
37
|
+
val key = apiKey
|
|
38
|
+
if (key.isNullOrBlank()) return GifResult.Failure(GifError.NO_API_KEY)
|
|
39
|
+
val offset = cursor?.toIntOrNull() ?: 0
|
|
40
|
+
val url = "$BASE/gifs/search?api_key=${enc(key)}&q=${enc(query)}&limit=$limit&offset=$offset" +
|
|
41
|
+
"&rating=g&lang=en&bundle=messaging_non_clips"
|
|
42
|
+
return when (val res = GifHttp.getJson(url)) {
|
|
43
|
+
is GifResult.Failure -> res
|
|
44
|
+
is GifResult.Success -> parsePage(res.value, limit, offset)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
override fun categories(): GifResult<List<GifCategory>> {
|
|
49
|
+
val key = apiKey
|
|
50
|
+
if (key.isNullOrBlank()) return GifResult.Failure(GifError.NO_API_KEY)
|
|
51
|
+
val url = "$BASE/gifs/categories?api_key=${enc(key)}"
|
|
52
|
+
val json = when (val res = GifHttp.getJson(url)) {
|
|
53
|
+
is GifResult.Failure -> return GifResult.Success(emptyList())
|
|
54
|
+
is GifResult.Success -> res.value
|
|
55
|
+
}
|
|
56
|
+
// Categories are optional: any parse failure degrades to an empty list, never a hard error.
|
|
57
|
+
val list = runCatching { parseCategories(json) }.getOrDefault(emptyList())
|
|
58
|
+
return GifResult.Success(list)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Parse a GIPHY list response ({ data, pagination, meta }) into a [GifPage]. */
|
|
62
|
+
private fun parsePage(json: JSONObject, limit: Int, offset: Int): GifResult<GifPage> {
|
|
63
|
+
// GIPHY echoes its own status inside meta; a >= 400 status can accompany an HTTP 200 body.
|
|
64
|
+
val status = json.optJSONObject("meta")?.optInt("status", 200) ?: 200
|
|
65
|
+
if (status >= 400) {
|
|
66
|
+
return GifResult.Failure(
|
|
67
|
+
when {
|
|
68
|
+
status == 429 -> GifError.RATE_LIMITED
|
|
69
|
+
status in 500..599 -> GifError.SERVER
|
|
70
|
+
else -> GifError.PARSE
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
val data = json.optJSONArray("data") ?: return GifResult.Failure(GifError.PARSE)
|
|
75
|
+
val items = ArrayList<GifItem>(data.length())
|
|
76
|
+
for (i in 0 until data.length()) {
|
|
77
|
+
val obj = data.optJSONObject(i) ?: continue
|
|
78
|
+
val images = obj.optJSONObject("images")
|
|
79
|
+
val preview = rendition(images, "fixed_width_downsampled", "fixed_width", "preview_gif") ?: continue
|
|
80
|
+
val content = rendition(images, "downsized", "original", "fixed_width") ?: continue
|
|
81
|
+
val (pUrl, pW, pH) = preview
|
|
82
|
+
val (cUrl, cW, cH) = content
|
|
83
|
+
items.add(
|
|
84
|
+
GifItem(
|
|
85
|
+
id = obj.optString("id"),
|
|
86
|
+
description = obj.optString("title"),
|
|
87
|
+
previewUrl = pUrl,
|
|
88
|
+
previewWidth = pW,
|
|
89
|
+
previewHeight = pH,
|
|
90
|
+
contentUrl = cUrl,
|
|
91
|
+
contentWidth = cW,
|
|
92
|
+
contentHeight = cH
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
val pagination = json.optJSONObject("pagination")
|
|
97
|
+
val count = pagination?.optInt("count", data.length()) ?: data.length()
|
|
98
|
+
// A missing total_count is treated as unbounded so pagination relies on the count < limit rule.
|
|
99
|
+
val totalCount = pagination?.optInt("total_count", Int.MAX_VALUE) ?: Int.MAX_VALUE
|
|
100
|
+
val nextOffset = offset + count
|
|
101
|
+
val nextCursor = when {
|
|
102
|
+
count < limit -> null
|
|
103
|
+
nextOffset >= totalCount -> null
|
|
104
|
+
else -> nextOffset.toString()
|
|
105
|
+
}
|
|
106
|
+
return GifResult.Success(GifPage(items, nextCursor))
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Parse the optional GIPHY categories response; the caller downgrades any throw to empty. */
|
|
110
|
+
private fun parseCategories(json: JSONObject): List<GifCategory> {
|
|
111
|
+
val data = json.optJSONArray("data") ?: return emptyList()
|
|
112
|
+
val out = ArrayList<GifCategory>(data.length())
|
|
113
|
+
for (i in 0 until data.length()) {
|
|
114
|
+
val obj = data.optJSONObject(i) ?: continue
|
|
115
|
+
val name = obj.optString("name")
|
|
116
|
+
if (name.isBlank()) continue
|
|
117
|
+
val images = obj.optJSONObject("gif")?.optJSONObject("images")
|
|
118
|
+
val imageUrl = rendition(images, "fixed_width", "downsized", "original", "preview_gif")?.first
|
|
119
|
+
out.add(GifCategory(name = name, searchTerm = name, imageUrl = imageUrl))
|
|
120
|
+
}
|
|
121
|
+
return out
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Pick the first present rendition among [names] and return its (url, width, height), or null
|
|
126
|
+
* when none has a usable (non-blank) url. GIPHY encodes width/height as strings.
|
|
127
|
+
*/
|
|
128
|
+
private fun rendition(images: JSONObject?, vararg names: String): Triple<String, Int, Int>? {
|
|
129
|
+
if (images == null) return null
|
|
130
|
+
for (name in names) {
|
|
131
|
+
val r = images.optJSONObject(name) ?: continue
|
|
132
|
+
val url = r.optString("url")
|
|
133
|
+
if (url.isBlank()) continue
|
|
134
|
+
val w = r.optString("width").toIntOrNull() ?: 0
|
|
135
|
+
val h = r.optString("height").toIntOrNull() ?: 0
|
|
136
|
+
return Triple(url, w, h)
|
|
137
|
+
}
|
|
138
|
+
return null
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private fun enc(value: String): String = URLEncoder.encode(value, "UTF-8")
|
|
142
|
+
|
|
143
|
+
companion object {
|
|
144
|
+
private const val BASE = "https://api.giphy.com/v1"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
package com.customcamera.gif
|
|
2
|
+
|
|
3
|
+
import java.io.IOException
|
|
4
|
+
import java.io.OutputStream
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* GIF-variant LZW compressor.
|
|
8
|
+
*
|
|
9
|
+
* Faithful Kotlin port of the LZWEncoder used by Kevin Weiner's [AnimatedGifEncoder], which is
|
|
10
|
+
* itself adapted (K Weiner 12/00) from Jef Poskanzer's Acme.JPM.Encoders GIF encoder by way of
|
|
11
|
+
* J. M. G. Elliott, ultimately derived from the public-domain `GIFCOMPR.C` / `compress` lineage
|
|
12
|
+
* (David Rowley's GIF modifications). This is a syntax-only translation; the emitted bitstream is
|
|
13
|
+
* intended to be byte-for-byte identical to the canonical Java implementation.
|
|
14
|
+
*
|
|
15
|
+
* @param width image width in pixels
|
|
16
|
+
* @param height image height in pixels
|
|
17
|
+
* @param pixels palette-indexed pixels, one byte per pixel, row-major
|
|
18
|
+
* @param colorDepth number of bits per pixel used to seed the initial code size
|
|
19
|
+
*/
|
|
20
|
+
class LZWEncoder(width: Int, height: Int, pixels: ByteArray, colorDepth: Int) {
|
|
21
|
+
|
|
22
|
+
private val imgW: Int = width
|
|
23
|
+
private val imgH: Int = height
|
|
24
|
+
private val pixAry: ByteArray = pixels
|
|
25
|
+
private val initCodeSize: Int = maxOf(2, colorDepth)
|
|
26
|
+
private var remaining: Int = 0
|
|
27
|
+
private var curPixel: Int = 0
|
|
28
|
+
|
|
29
|
+
// GIFCOMPR.C - GIF Image compression routines
|
|
30
|
+
//
|
|
31
|
+
// Lempel-Ziv compression based on 'compress'. GIF modifications by
|
|
32
|
+
// David Rowley (mgardi@watdcsu.waterloo.edu)
|
|
33
|
+
|
|
34
|
+
private val bits = 12
|
|
35
|
+
private val hsize = 5003 // 80% occupancy
|
|
36
|
+
|
|
37
|
+
// GIF Image compression - modified 'compress'
|
|
38
|
+
// Based on: compress.c - File compression ala IEEE Computer, June 1984.
|
|
39
|
+
// By Authors: Spencer W. Thomas, Jim McKie, Steve Davies, Ken Turkowski,
|
|
40
|
+
// James A. Woods, Joe Orost.
|
|
41
|
+
|
|
42
|
+
private var nBits = 0 // number of bits/code
|
|
43
|
+
private val maxbits = bits // user settable max # bits/code
|
|
44
|
+
private var maxcode = 0 // maximum code, given nBits
|
|
45
|
+
private val maxmaxcode = 1 shl bits // should NEVER generate this code
|
|
46
|
+
|
|
47
|
+
private val htab = IntArray(hsize)
|
|
48
|
+
private val codetab = IntArray(hsize)
|
|
49
|
+
|
|
50
|
+
private var freeEnt = 0 // first unused entry
|
|
51
|
+
|
|
52
|
+
// Block compression parameters -- after all codes are used up, and the
|
|
53
|
+
// compression rate changes, start over.
|
|
54
|
+
private var clearFlg = false
|
|
55
|
+
|
|
56
|
+
private var gInitBits = 0
|
|
57
|
+
private var clearCode = 0
|
|
58
|
+
private var eofCode = 0
|
|
59
|
+
|
|
60
|
+
// Output accumulator.
|
|
61
|
+
private var curAccum = 0
|
|
62
|
+
private var curBits = 0
|
|
63
|
+
|
|
64
|
+
private val masks = intArrayOf(
|
|
65
|
+
0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F,
|
|
66
|
+
0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
// Number of characters so far in this 'packet'.
|
|
70
|
+
private var aCount = 0
|
|
71
|
+
|
|
72
|
+
// Storage for the packet accumulator.
|
|
73
|
+
private val accum = ByteArray(256)
|
|
74
|
+
|
|
75
|
+
companion object {
|
|
76
|
+
private const val EOF = -1
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Adds a character to the end of the current packet, flushing to [outs] at 254 characters.
|
|
81
|
+
*/
|
|
82
|
+
private fun charOut(c: Byte, outs: OutputStream) {
|
|
83
|
+
accum[aCount++] = c
|
|
84
|
+
if (aCount >= 254) flushChar(outs)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Table clear for block compress.
|
|
89
|
+
*/
|
|
90
|
+
private fun clBlock(outs: OutputStream) {
|
|
91
|
+
clHash(hsize)
|
|
92
|
+
freeEnt = clearCode + 2
|
|
93
|
+
clearFlg = true
|
|
94
|
+
output(clearCode, outs)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Resets the hash table.
|
|
99
|
+
*/
|
|
100
|
+
private fun clHash(hsize: Int) {
|
|
101
|
+
for (i in 0 until hsize) htab[i] = -1
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Core compressor. See the GIFCOMPR lineage above. Uses open addressing double hashing (Knuth
|
|
106
|
+
* algorithm D with G. Knott's relatively-prime secondary probe) plus block compression with an
|
|
107
|
+
* adaptive reset when the table fills.
|
|
108
|
+
*/
|
|
109
|
+
private fun compress(initBits: Int, outs: OutputStream) {
|
|
110
|
+
var fcode = 0
|
|
111
|
+
var i = 0
|
|
112
|
+
var c = 0
|
|
113
|
+
var disp = 0
|
|
114
|
+
|
|
115
|
+
// Set up the globals: gInitBits - initial number of bits.
|
|
116
|
+
gInitBits = initBits
|
|
117
|
+
|
|
118
|
+
// Set up the necessary values.
|
|
119
|
+
clearFlg = false
|
|
120
|
+
nBits = gInitBits
|
|
121
|
+
maxcode = MAXCODE(nBits)
|
|
122
|
+
|
|
123
|
+
clearCode = 1 shl (initBits - 1)
|
|
124
|
+
eofCode = clearCode + 1
|
|
125
|
+
freeEnt = clearCode + 2
|
|
126
|
+
|
|
127
|
+
aCount = 0 // clear packet
|
|
128
|
+
|
|
129
|
+
var ent = nextPixel()
|
|
130
|
+
|
|
131
|
+
var hshift = 0
|
|
132
|
+
fcode = hsize
|
|
133
|
+
while (fcode < 65536) {
|
|
134
|
+
hshift++
|
|
135
|
+
fcode *= 2
|
|
136
|
+
}
|
|
137
|
+
hshift = 8 - hshift // set hash code range bound
|
|
138
|
+
|
|
139
|
+
val hsizeReg = hsize
|
|
140
|
+
clHash(hsizeReg) // clear hash table
|
|
141
|
+
|
|
142
|
+
output(clearCode, outs)
|
|
143
|
+
|
|
144
|
+
outerLoop@ while (true) {
|
|
145
|
+
c = nextPixel()
|
|
146
|
+
if (c == EOF) break
|
|
147
|
+
fcode = (c shl maxbits) + ent
|
|
148
|
+
i = (c shl hshift) xor ent // xor hashing
|
|
149
|
+
|
|
150
|
+
if (htab[i] == fcode) {
|
|
151
|
+
ent = codetab[i]
|
|
152
|
+
continue
|
|
153
|
+
} else if (htab[i] >= 0) { // non-empty slot
|
|
154
|
+
disp = hsizeReg - i // secondary hash (after G. Knott)
|
|
155
|
+
if (i == 0) disp = 1
|
|
156
|
+
do {
|
|
157
|
+
i -= disp
|
|
158
|
+
if (i < 0) i += hsizeReg
|
|
159
|
+
if (htab[i] == fcode) {
|
|
160
|
+
ent = codetab[i]
|
|
161
|
+
continue@outerLoop
|
|
162
|
+
}
|
|
163
|
+
} while (htab[i] >= 0)
|
|
164
|
+
}
|
|
165
|
+
output(ent, outs)
|
|
166
|
+
ent = c
|
|
167
|
+
if (freeEnt < maxmaxcode) {
|
|
168
|
+
codetab[i] = freeEnt++ // code -> hashtable
|
|
169
|
+
htab[i] = fcode
|
|
170
|
+
} else {
|
|
171
|
+
clBlock(outs)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Put out the final code.
|
|
175
|
+
output(ent, outs)
|
|
176
|
+
output(eofCode, outs)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Compresses and writes the pixel data to [os], framed by the initial code-size byte and the
|
|
181
|
+
* trailing block terminator. This is the public entry point used by [AnimatedGifEncoder].
|
|
182
|
+
*/
|
|
183
|
+
@Throws(IOException::class)
|
|
184
|
+
fun encode(os: OutputStream) {
|
|
185
|
+
os.write(initCodeSize) // write "initial code size" byte
|
|
186
|
+
remaining = imgW * imgH // reset navigation variables
|
|
187
|
+
curPixel = 0
|
|
188
|
+
compress(initCodeSize + 1, os) // compress and write the pixel data
|
|
189
|
+
os.write(0) // write block terminator
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Flushes the packet to [outs] and resets the accumulator.
|
|
194
|
+
*/
|
|
195
|
+
private fun flushChar(outs: OutputStream) {
|
|
196
|
+
if (aCount > 0) {
|
|
197
|
+
outs.write(aCount)
|
|
198
|
+
outs.write(accum, 0, aCount)
|
|
199
|
+
aCount = 0
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Largest code representable in [nBits] bits. */
|
|
204
|
+
private fun MAXCODE(nBits: Int): Int = (1 shl nBits) - 1
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Returns the next pixel from the image, or [EOF] when exhausted.
|
|
208
|
+
*/
|
|
209
|
+
private fun nextPixel(): Int {
|
|
210
|
+
if (remaining == 0) return EOF
|
|
211
|
+
remaining--
|
|
212
|
+
val pix = pixAry[curPixel++]
|
|
213
|
+
return pix.toInt() and 0xff
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Outputs the given [code], packing it into the bit accumulator and emitting full bytes. When
|
|
217
|
+
* [code] equals [eofCode] the remaining buffered bits are flushed.
|
|
218
|
+
*/
|
|
219
|
+
private fun output(code: Int, outs: OutputStream) {
|
|
220
|
+
curAccum = curAccum and masks[curBits]
|
|
221
|
+
|
|
222
|
+
if (curBits > 0) {
|
|
223
|
+
curAccum = curAccum or (code shl curBits)
|
|
224
|
+
} else {
|
|
225
|
+
curAccum = code
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
curBits += nBits
|
|
229
|
+
|
|
230
|
+
while (curBits >= 8) {
|
|
231
|
+
charOut((curAccum and 0xff).toByte(), outs)
|
|
232
|
+
curAccum = curAccum shr 8
|
|
233
|
+
curBits -= 8
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// If the next entry is going to be too big for the code size, increase it if possible.
|
|
237
|
+
if (freeEnt > maxcode || clearFlg) {
|
|
238
|
+
if (clearFlg) {
|
|
239
|
+
nBits = gInitBits
|
|
240
|
+
maxcode = MAXCODE(nBits)
|
|
241
|
+
clearFlg = false
|
|
242
|
+
} else {
|
|
243
|
+
nBits++
|
|
244
|
+
maxcode = if (nBits == maxbits) maxmaxcode else MAXCODE(nBits)
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (code == eofCode) {
|
|
249
|
+
// At EOF, write the rest of the buffer.
|
|
250
|
+
while (curBits > 0) {
|
|
251
|
+
charOut((curAccum and 0xff).toByte(), outs)
|
|
252
|
+
curAccum = curAccum shr 8
|
|
253
|
+
curBits -= 8
|
|
254
|
+
}
|
|
255
|
+
flushChar(outs)
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|