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.
Files changed (506) hide show
  1. package/CustomCamera.podspec +20 -0
  2. package/LICENSE +20 -0
  3. package/README.md +833 -0
  4. package/android/build.gradle +135 -0
  5. package/android/consumer-rules.pro +47 -0
  6. package/android/src/main/AndroidManifest.xml +72 -0
  7. package/android/src/main/java/android/print/PdfPrint.java +51 -0
  8. package/android/src/main/java/com/customcamera/AnimatedImageViewManager.kt +199 -0
  9. package/android/src/main/java/com/customcamera/AudioPlayerView.kt +322 -0
  10. package/android/src/main/java/com/customcamera/AudioRecorder.kt +506 -0
  11. package/android/src/main/java/com/customcamera/BarcodeScannerActivity.kt +361 -0
  12. package/android/src/main/java/com/customcamera/BlurBackgroundView.kt +199 -0
  13. package/android/src/main/java/com/customcamera/CacheCleanupManager.kt +386 -0
  14. package/android/src/main/java/com/customcamera/CameraAspectRatioMode.kt +77 -0
  15. package/android/src/main/java/com/customcamera/CameraAsset.kt +211 -0
  16. package/android/src/main/java/com/customcamera/CameraTheme.kt +479 -0
  17. package/android/src/main/java/com/customcamera/CompressionCacheStore.kt +504 -0
  18. package/android/src/main/java/com/customcamera/CompressionFileNameUtils.kt +7 -0
  19. package/android/src/main/java/com/customcamera/CompressionProfile.kt +195 -0
  20. package/android/src/main/java/com/customcamera/CustomCameraActivity.kt +7291 -0
  21. package/android/src/main/java/com/customcamera/CustomCameraFileProvider.kt +9 -0
  22. package/android/src/main/java/com/customcamera/CustomCameraModule.kt +2479 -0
  23. package/android/src/main/java/com/customcamera/CustomCameraPackage.kt +53 -0
  24. package/android/src/main/java/com/customcamera/DisplayUtils.kt +9 -0
  25. package/android/src/main/java/com/customcamera/DocumentPreviewView.kt +846 -0
  26. package/android/src/main/java/com/customcamera/DrawingView.kt +214 -0
  27. package/android/src/main/java/com/customcamera/EmojiPickerData.kt +228 -0
  28. package/android/src/main/java/com/customcamera/FilterStripAdapter.kt +158 -0
  29. package/android/src/main/java/com/customcamera/GifSupport.kt +215 -0
  30. package/android/src/main/java/com/customcamera/GlobalAudioPlayer.kt +320 -0
  31. package/android/src/main/java/com/customcamera/ImageExporter.kt +1394 -0
  32. package/android/src/main/java/com/customcamera/ImageFormatSupport.kt +163 -0
  33. package/android/src/main/java/com/customcamera/Localization.kt +206 -0
  34. package/android/src/main/java/com/customcamera/MediaAdapters.kt +758 -0
  35. package/android/src/main/java/com/customcamera/MediaCacheManager.kt +782 -0
  36. package/android/src/main/java/com/customcamera/MediaExportFormats.kt +201 -0
  37. package/android/src/main/java/com/customcamera/MediaFileIo.kt +310 -0
  38. package/android/src/main/java/com/customcamera/MediaMetadataStore.kt +494 -0
  39. package/android/src/main/java/com/customcamera/MediaPreviewEditor.kt +14865 -0
  40. package/android/src/main/java/com/customcamera/MediaPublisher.kt +423 -0
  41. package/android/src/main/java/com/customcamera/MediaStorageWorkflow.kt +722 -0
  42. package/android/src/main/java/com/customcamera/MediaStoreRepository.kt +378 -0
  43. package/android/src/main/java/com/customcamera/MediaThumbnailView.kt +286 -0
  44. package/android/src/main/java/com/customcamera/MediaUtils.kt +37 -0
  45. package/android/src/main/java/com/customcamera/NativeVideoViewManager.kt +845 -0
  46. package/android/src/main/java/com/customcamera/OfficeDocumentConverter.kt +2791 -0
  47. package/android/src/main/java/com/customcamera/PendingCaptureCrops.kt +88 -0
  48. package/android/src/main/java/com/customcamera/PowerPointPreview.kt +4077 -0
  49. package/android/src/main/java/com/customcamera/RecentPickerStore.kt +74 -0
  50. package/android/src/main/java/com/customcamera/SecureFileEraser.kt +411 -0
  51. package/android/src/main/java/com/customcamera/SecureKeyModule.kt +88 -0
  52. package/android/src/main/java/com/customcamera/SecureMediaDeleter.kt +493 -0
  53. package/android/src/main/java/com/customcamera/StickerPickerData.kt +107 -0
  54. package/android/src/main/java/com/customcamera/SvgDrawable.kt +175 -0
  55. package/android/src/main/java/com/customcamera/SvgIconViewManager.kt +77 -0
  56. package/android/src/main/java/com/customcamera/TextEntryController.kt +553 -0
  57. package/android/src/main/java/com/customcamera/ThumbnailLoader.kt +455 -0
  58. package/android/src/main/java/com/customcamera/UploadService.kt +909 -0
  59. package/android/src/main/java/com/customcamera/VideoEditUtils.kt +210 -0
  60. package/android/src/main/java/com/customcamera/VideoRotationTranscoder.kt +1992 -0
  61. package/android/src/main/java/com/customcamera/gif/AnimatedGifEncoder.kt +473 -0
  62. package/android/src/main/java/com/customcamera/gif/GifDecoder.kt +690 -0
  63. package/android/src/main/java/com/customcamera/gif/GifFramesDrawable.kt +160 -0
  64. package/android/src/main/java/com/customcamera/gif/GifHttp.kt +112 -0
  65. package/android/src/main/java/com/customcamera/gif/GifImageLoader.kt +186 -0
  66. package/android/src/main/java/com/customcamera/gif/GifModels.kt +74 -0
  67. package/android/src/main/java/com/customcamera/gif/GifProvider.kt +49 -0
  68. package/android/src/main/java/com/customcamera/gif/GifProviders.kt +27 -0
  69. package/android/src/main/java/com/customcamera/gif/GifRepository.kt +124 -0
  70. package/android/src/main/java/com/customcamera/gif/GifSafety.kt +33 -0
  71. package/android/src/main/java/com/customcamera/gif/GiphyGifProvider.kt +146 -0
  72. package/android/src/main/java/com/customcamera/gif/LZWEncoder.kt +258 -0
  73. package/android/src/main/java/com/customcamera/gif/NeuQuant.kt +435 -0
  74. package/android/src/main/java/com/customcamera/gif/TenorGifProvider.kt +147 -0
  75. package/android/src/main/res/drawable/bg_brush_selected.xml +5 -0
  76. package/android/src/main/res/drawable/bg_color_swatch.xml +5 -0
  77. package/android/src/main/res/drawable/bg_editor_toolbar.xml +6 -0
  78. package/android/src/main/res/drawable/bg_icon_circle.xml +5 -0
  79. package/android/src/main/res/drawable/bg_icon_circle_light.xml +5 -0
  80. package/android/src/main/res/drawable/bg_mode_tab_active.xml +6 -0
  81. package/android/src/main/res/drawable/bg_pill.xml +6 -0
  82. package/android/src/main/res/drawable/bg_recording_dot.xml +6 -0
  83. package/android/src/main/res/drawable/bg_selection_badge.xml +8 -0
  84. package/android/src/main/res/drawable/bg_send_button.xml +5 -0
  85. package/android/src/main/res/drawable/bg_shutter_inner.xml +5 -0
  86. package/android/src/main/res/drawable/bg_shutter_recording.xml +6 -0
  87. package/android/src/main/res/drawable/bg_shutter_ring.xml +8 -0
  88. package/android/src/main/res/drawable/bg_shutter_video_idle.xml +5 -0
  89. package/android/src/main/res/drawable/bg_thumbnail.xml +9 -0
  90. package/android/src/main/res/drawable/ic_aspect_ratio.xml +17 -0
  91. package/android/src/main/res/drawable/ic_audio.xml +10 -0
  92. package/android/src/main/res/drawable/ic_back.xml +10 -0
  93. package/android/src/main/res/drawable/ic_brush_medium.xml +12 -0
  94. package/android/src/main/res/drawable/ic_brush_thick.xml +12 -0
  95. package/android/src/main/res/drawable/ic_brush_thin.xml +12 -0
  96. package/android/src/main/res/drawable/ic_check.xml +17 -0
  97. package/android/src/main/res/drawable/ic_chevron_down.xml +10 -0
  98. package/android/src/main/res/drawable/ic_chevron_up.xml +13 -0
  99. package/android/src/main/res/drawable/ic_clear_drawing.xml +10 -0
  100. package/android/src/main/res/drawable/ic_close.xml +10 -0
  101. package/android/src/main/res/drawable/ic_cover.xml +9 -0
  102. package/android/src/main/res/drawable/ic_crop.xml +10 -0
  103. package/android/src/main/res/drawable/ic_delete.xml +9 -0
  104. package/android/src/main/res/drawable/ic_document.xml +10 -0
  105. package/android/src/main/res/drawable/ic_done.xml +10 -0
  106. package/android/src/main/res/drawable/ic_download.xml +10 -0
  107. package/android/src/main/res/drawable/ic_emoji.xml +10 -0
  108. package/android/src/main/res/drawable/ic_filter.xml +10 -0
  109. package/android/src/main/res/drawable/ic_flash_auto.xml +7 -0
  110. package/android/src/main/res/drawable/ic_flash_off.xml +23 -0
  111. package/android/src/main/res/drawable/ic_flash_on.xml +16 -0
  112. package/android/src/main/res/drawable/ic_flip.xml +15 -0
  113. package/android/src/main/res/drawable/ic_gallery.xml +10 -0
  114. package/android/src/main/res/drawable/ic_gif.xml +24 -0
  115. package/android/src/main/res/drawable/ic_lock.xml +19 -0
  116. package/android/src/main/res/drawable/ic_lock_open.xml +22 -0
  117. package/android/src/main/res/drawable/ic_marker.xml +10 -0
  118. package/android/src/main/res/drawable/ic_more_vert.xml +18 -0
  119. package/android/src/main/res/drawable/ic_overlay_close.xml +19 -0
  120. package/android/src/main/res/drawable/ic_overlay_resize.xml +18 -0
  121. package/android/src/main/res/drawable/ic_pause.xml +10 -0
  122. package/android/src/main/res/drawable/ic_photo_mode.xml +10 -0
  123. package/android/src/main/res/drawable/ic_play.xml +10 -0
  124. package/android/src/main/res/drawable/ic_redo.xml +10 -0
  125. package/android/src/main/res/drawable/ic_rotate.xml +9 -0
  126. package/android/src/main/res/drawable/ic_send.xml +10 -0
  127. package/android/src/main/res/drawable/ic_share.xml +10 -0
  128. package/android/src/main/res/drawable/ic_stat_upload.xml +10 -0
  129. package/android/src/main/res/drawable/ic_sticker.xml +24 -0
  130. package/android/src/main/res/drawable/ic_text.xml +10 -0
  131. package/android/src/main/res/drawable/ic_text_align_center.xml +11 -0
  132. package/android/src/main/res/drawable/ic_text_align_left.xml +11 -0
  133. package/android/src/main/res/drawable/ic_text_align_right.xml +11 -0
  134. package/android/src/main/res/drawable/ic_text_bg.xml +11 -0
  135. package/android/src/main/res/drawable/ic_trim.xml +23 -0
  136. package/android/src/main/res/drawable/ic_undo.xml +10 -0
  137. package/android/src/main/res/drawable/ic_video_mode.xml +10 -0
  138. package/android/src/main/res/drawable/ic_video_note.xml +13 -0
  139. package/android/src/main/res/drawable/ic_volume_off.xml +9 -0
  140. package/android/src/main/res/drawable/ic_volume_on.xml +9 -0
  141. package/android/src/main/res/drawable/sticker_heart.xml +9 -0
  142. package/android/src/main/res/drawable/sticker_smile.xml +9 -0
  143. package/android/src/main/res/drawable/sticker_star.xml +9 -0
  144. package/android/src/main/res/drawable/sticker_thumbsup.xml +9 -0
  145. package/android/src/main/res/values/colors.xml +34 -0
  146. package/android/src/main/res/values/ids.xml +15 -0
  147. package/android/src/main/res/values/strings.xml +15 -0
  148. package/android/src/main/res/values/styles.xml +20 -0
  149. package/android/src/main/res/xml/file_paths.xml +34 -0
  150. package/ios/CustomCamera.h +5 -0
  151. package/ios/CustomCamera.mm +214 -0
  152. package/lib/module/AudioPlayerContext.js +233 -0
  153. package/lib/module/AudioPlayerContext.js.map +1 -0
  154. package/lib/module/CameraPreview.js +304 -0
  155. package/lib/module/CameraPreview.js.map +1 -0
  156. package/lib/module/NativeAnimatedImageView.js +41 -0
  157. package/lib/module/NativeAnimatedImageView.js.map +1 -0
  158. package/lib/module/NativeAudioPlayerView.js +33 -0
  159. package/lib/module/NativeAudioPlayerView.js.map +1 -0
  160. package/lib/module/NativeBlurView.js +35 -0
  161. package/lib/module/NativeBlurView.js.map +1 -0
  162. package/lib/module/NativeCustomCamera.js +128 -0
  163. package/lib/module/NativeCustomCamera.js.map +1 -0
  164. package/lib/module/NativeCustomCamera.web.js +143 -0
  165. package/lib/module/NativeCustomCamera.web.js.map +1 -0
  166. package/lib/module/NativeCustomVideoView.js +5 -0
  167. package/lib/module/NativeCustomVideoView.js.map +1 -0
  168. package/lib/module/NativeDocumentPreviewView.js +156 -0
  169. package/lib/module/NativeDocumentPreviewView.js.map +1 -0
  170. package/lib/module/NativeMediaThumbnailView.js +110 -0
  171. package/lib/module/NativeMediaThumbnailView.js.map +1 -0
  172. package/lib/module/NativeSvgIcon.js +32 -0
  173. package/lib/module/NativeSvgIcon.js.map +1 -0
  174. package/lib/module/ResponsivePreviewContainer.js +171 -0
  175. package/lib/module/ResponsivePreviewContainer.js.map +1 -0
  176. package/lib/module/accessibility.js +61 -0
  177. package/lib/module/accessibility.js.map +1 -0
  178. package/lib/module/config.js +352 -0
  179. package/lib/module/config.js.map +1 -0
  180. package/lib/module/cpuOptimization.js +296 -0
  181. package/lib/module/cpuOptimization.js.map +1 -0
  182. package/lib/module/db/DatabaseManager.js +191 -0
  183. package/lib/module/db/DatabaseManager.js.map +1 -0
  184. package/lib/module/db/MediaMapper.js +284 -0
  185. package/lib/module/db/MediaMapper.js.map +1 -0
  186. package/lib/module/db/MediaRepository.js +242 -0
  187. package/lib/module/db/MediaRepository.js.map +1 -0
  188. package/lib/module/db/index.js +41 -0
  189. package/lib/module/db/index.js.map +1 -0
  190. package/lib/module/db/migrations.js +180 -0
  191. package/lib/module/db/migrations.js.map +1 -0
  192. package/lib/module/db/react-native-sqlcipher.d.js +2 -0
  193. package/lib/module/db/react-native-sqlcipher.d.js.map +1 -0
  194. package/lib/module/db/secureKey.js +87 -0
  195. package/lib/module/db/secureKey.js.map +1 -0
  196. package/lib/module/db/types.js +57 -0
  197. package/lib/module/db/types.js.map +1 -0
  198. package/lib/module/db/useMediaDatabase.js +123 -0
  199. package/lib/module/db/useMediaDatabase.js.map +1 -0
  200. package/lib/module/defaultIcons.js +2259 -0
  201. package/lib/module/defaultIcons.js.map +1 -0
  202. package/lib/module/deviceCapabilities.js +408 -0
  203. package/lib/module/deviceCapabilities.js.map +1 -0
  204. package/lib/module/errors.js +267 -0
  205. package/lib/module/errors.js.map +1 -0
  206. package/lib/module/iconConfig.js +796 -0
  207. package/lib/module/iconConfig.js.map +1 -0
  208. package/lib/module/icons.js +514 -0
  209. package/lib/module/icons.js.map +1 -0
  210. package/lib/module/index.js +251 -0
  211. package/lib/module/index.js.map +1 -0
  212. package/lib/module/jest-globals.d.js +2 -0
  213. package/lib/module/jest-globals.d.js.map +1 -0
  214. package/lib/module/library/MediaLibrary.js +107 -0
  215. package/lib/module/library/MediaLibrary.js.map +1 -0
  216. package/lib/module/library/MediaLibraryScreen.js +2597 -0
  217. package/lib/module/library/MediaLibraryScreen.js.map +1 -0
  218. package/lib/module/library/components/AudioPreview.js +74 -0
  219. package/lib/module/library/components/AudioPreview.js.map +1 -0
  220. package/lib/module/library/components/DocumentPreview.js +331 -0
  221. package/lib/module/library/components/DocumentPreview.js.map +1 -0
  222. package/lib/module/library/components/ExpandableFab.js +343 -0
  223. package/lib/module/library/components/ExpandableFab.js.map +1 -0
  224. package/lib/module/library/components/FileTiles.js +251 -0
  225. package/lib/module/library/components/FileTiles.js.map +1 -0
  226. package/lib/module/library/components/ImagePreview.js +70 -0
  227. package/lib/module/library/components/ImagePreview.js.map +1 -0
  228. package/lib/module/library/components/MediaMetadataHeader.js +175 -0
  229. package/lib/module/library/components/MediaMetadataHeader.js.map +1 -0
  230. package/lib/module/library/components/RecordAudioScreen.js +816 -0
  231. package/lib/module/library/components/RecordAudioScreen.js.map +1 -0
  232. package/lib/module/library/components/VideoPreview.js +453 -0
  233. package/lib/module/library/components/VideoPreview.js.map +1 -0
  234. package/lib/module/library/components/ViewerCounter.js +55 -0
  235. package/lib/module/library/components/ViewerCounter.js.map +1 -0
  236. package/lib/module/library/compressionEstimate.js +507 -0
  237. package/lib/module/library/compressionEstimate.js.map +1 -0
  238. package/lib/module/library/fileMetadata.js +196 -0
  239. package/lib/module/library/fileMetadata.js.map +1 -0
  240. package/lib/module/library/index.js +42 -0
  241. package/lib/module/library/index.js.map +1 -0
  242. package/lib/module/library/libraryIconRegistry.js +69 -0
  243. package/lib/module/library/libraryIconRegistry.js.map +1 -0
  244. package/lib/module/library/libraryIcons.js +858 -0
  245. package/lib/module/library/libraryIcons.js.map +1 -0
  246. package/lib/module/library/localizedFormat.js +181 -0
  247. package/lib/module/library/localizedFormat.js.map +1 -0
  248. package/lib/module/library/palette.js +225 -0
  249. package/lib/module/library/palette.js.map +1 -0
  250. package/lib/module/library/responsive.js +53 -0
  251. package/lib/module/library/responsive.js.map +1 -0
  252. package/lib/module/locales.js +416 -0
  253. package/lib/module/locales.js.map +1 -0
  254. package/lib/module/localization.js +1064 -0
  255. package/lib/module/localization.js.map +1 -0
  256. package/lib/module/logger.js +20 -0
  257. package/lib/module/logger.js.map +1 -0
  258. package/lib/module/lowMemoryCache.js +206 -0
  259. package/lib/module/lowMemoryCache.js.map +1 -0
  260. package/lib/module/mediaHistory.js +33 -0
  261. package/lib/module/mediaHistory.js.map +1 -0
  262. package/lib/module/mediaStorageService.js +402 -0
  263. package/lib/module/mediaStorageService.js.map +1 -0
  264. package/lib/module/memory.js +79 -0
  265. package/lib/module/memory.js.map +1 -0
  266. package/lib/module/nativeActions.js +307 -0
  267. package/lib/module/nativeActions.js.map +1 -0
  268. package/lib/module/nativeComponentSupport.js +61 -0
  269. package/lib/module/nativeComponentSupport.js.map +1 -0
  270. package/lib/module/networkPerformance.js +24 -0
  271. package/lib/module/networkPerformance.js.map +1 -0
  272. package/lib/module/package.json +1 -0
  273. package/lib/module/performance.js +104 -0
  274. package/lib/module/performance.js.map +1 -0
  275. package/lib/module/performanceMonitor.js +155 -0
  276. package/lib/module/performanceMonitor.js.map +1 -0
  277. package/lib/module/permissions.js +370 -0
  278. package/lib/module/permissions.js.map +1 -0
  279. package/lib/module/rendering.js +40 -0
  280. package/lib/module/rendering.js.map +1 -0
  281. package/lib/module/security.js +18 -0
  282. package/lib/module/security.js.map +1 -0
  283. package/lib/module/state.js +266 -0
  284. package/lib/module/state.js.map +1 -0
  285. package/lib/module/storage.js +400 -0
  286. package/lib/module/storage.js.map +1 -0
  287. package/lib/module/theme.js +390 -0
  288. package/lib/module/theme.js.map +1 -0
  289. package/lib/module/types.js +4 -0
  290. package/lib/module/types.js.map +1 -0
  291. package/lib/module/utils.js +115 -0
  292. package/lib/module/utils.js.map +1 -0
  293. package/lib/module/validation.js +288 -0
  294. package/lib/module/validation.js.map +1 -0
  295. package/lib/typescript/package.json +1 -0
  296. package/lib/typescript/src/AudioPlayerContext.d.ts +27 -0
  297. package/lib/typescript/src/AudioPlayerContext.d.ts.map +1 -0
  298. package/lib/typescript/src/CameraPreview.d.ts +13 -0
  299. package/lib/typescript/src/CameraPreview.d.ts.map +1 -0
  300. package/lib/typescript/src/NativeAnimatedImageView.d.ts +33 -0
  301. package/lib/typescript/src/NativeAnimatedImageView.d.ts.map +1 -0
  302. package/lib/typescript/src/NativeAudioPlayerView.d.ts +12 -0
  303. package/lib/typescript/src/NativeAudioPlayerView.d.ts.map +1 -0
  304. package/lib/typescript/src/NativeBlurView.d.ts +12 -0
  305. package/lib/typescript/src/NativeBlurView.d.ts.map +1 -0
  306. package/lib/typescript/src/NativeCustomCamera.d.ts +167 -0
  307. package/lib/typescript/src/NativeCustomCamera.d.ts.map +1 -0
  308. package/lib/typescript/src/NativeCustomCamera.web.d.ts +47 -0
  309. package/lib/typescript/src/NativeCustomCamera.web.d.ts.map +1 -0
  310. package/lib/typescript/src/NativeCustomVideoView.d.ts +30 -0
  311. package/lib/typescript/src/NativeCustomVideoView.d.ts.map +1 -0
  312. package/lib/typescript/src/NativeDocumentPreviewView.d.ts +48 -0
  313. package/lib/typescript/src/NativeDocumentPreviewView.d.ts.map +1 -0
  314. package/lib/typescript/src/NativeMediaThumbnailView.d.ts +54 -0
  315. package/lib/typescript/src/NativeMediaThumbnailView.d.ts.map +1 -0
  316. package/lib/typescript/src/NativeSvgIcon.d.ts +25 -0
  317. package/lib/typescript/src/NativeSvgIcon.d.ts.map +1 -0
  318. package/lib/typescript/src/ResponsivePreviewContainer.d.ts +92 -0
  319. package/lib/typescript/src/ResponsivePreviewContainer.d.ts.map +1 -0
  320. package/lib/typescript/src/accessibility.d.ts +20 -0
  321. package/lib/typescript/src/accessibility.d.ts.map +1 -0
  322. package/lib/typescript/src/config.d.ts +145 -0
  323. package/lib/typescript/src/config.d.ts.map +1 -0
  324. package/lib/typescript/src/cpuOptimization.d.ts +63 -0
  325. package/lib/typescript/src/cpuOptimization.d.ts.map +1 -0
  326. package/lib/typescript/src/db/DatabaseManager.d.ts +48 -0
  327. package/lib/typescript/src/db/DatabaseManager.d.ts.map +1 -0
  328. package/lib/typescript/src/db/MediaMapper.d.ts +77 -0
  329. package/lib/typescript/src/db/MediaMapper.d.ts.map +1 -0
  330. package/lib/typescript/src/db/MediaRepository.d.ts +66 -0
  331. package/lib/typescript/src/db/MediaRepository.d.ts.map +1 -0
  332. package/lib/typescript/src/db/index.d.ts +23 -0
  333. package/lib/typescript/src/db/index.d.ts.map +1 -0
  334. package/lib/typescript/src/db/migrations.d.ts +31 -0
  335. package/lib/typescript/src/db/migrations.d.ts.map +1 -0
  336. package/lib/typescript/src/db/secureKey.d.ts +10 -0
  337. package/lib/typescript/src/db/secureKey.d.ts.map +1 -0
  338. package/lib/typescript/src/db/types.d.ts +115 -0
  339. package/lib/typescript/src/db/types.d.ts.map +1 -0
  340. package/lib/typescript/src/db/useMediaDatabase.d.ts +41 -0
  341. package/lib/typescript/src/db/useMediaDatabase.d.ts.map +1 -0
  342. package/lib/typescript/src/defaultIcons.d.ts +139 -0
  343. package/lib/typescript/src/defaultIcons.d.ts.map +1 -0
  344. package/lib/typescript/src/deviceCapabilities.d.ts +92 -0
  345. package/lib/typescript/src/deviceCapabilities.d.ts.map +1 -0
  346. package/lib/typescript/src/errors.d.ts +95 -0
  347. package/lib/typescript/src/errors.d.ts.map +1 -0
  348. package/lib/typescript/src/iconConfig.d.ts +176 -0
  349. package/lib/typescript/src/iconConfig.d.ts.map +1 -0
  350. package/lib/typescript/src/icons.d.ts +217 -0
  351. package/lib/typescript/src/icons.d.ts.map +1 -0
  352. package/lib/typescript/src/index.d.ts +104 -0
  353. package/lib/typescript/src/index.d.ts.map +1 -0
  354. package/lib/typescript/src/library/MediaLibrary.d.ts +57 -0
  355. package/lib/typescript/src/library/MediaLibrary.d.ts.map +1 -0
  356. package/lib/typescript/src/library/MediaLibraryScreen.d.ts +51 -0
  357. package/lib/typescript/src/library/MediaLibraryScreen.d.ts.map +1 -0
  358. package/lib/typescript/src/library/components/AudioPreview.d.ts +6 -0
  359. package/lib/typescript/src/library/components/AudioPreview.d.ts.map +1 -0
  360. package/lib/typescript/src/library/components/DocumentPreview.d.ts +10 -0
  361. package/lib/typescript/src/library/components/DocumentPreview.d.ts.map +1 -0
  362. package/lib/typescript/src/library/components/ExpandableFab.d.ts +39 -0
  363. package/lib/typescript/src/library/components/ExpandableFab.d.ts.map +1 -0
  364. package/lib/typescript/src/library/components/FileTiles.d.ts +8 -0
  365. package/lib/typescript/src/library/components/FileTiles.d.ts.map +1 -0
  366. package/lib/typescript/src/library/components/ImagePreview.d.ts +5 -0
  367. package/lib/typescript/src/library/components/ImagePreview.d.ts.map +1 -0
  368. package/lib/typescript/src/library/components/MediaMetadataHeader.d.ts +16 -0
  369. package/lib/typescript/src/library/components/MediaMetadataHeader.d.ts.map +1 -0
  370. package/lib/typescript/src/library/components/RecordAudioScreen.d.ts +8 -0
  371. package/lib/typescript/src/library/components/RecordAudioScreen.d.ts.map +1 -0
  372. package/lib/typescript/src/library/components/VideoPreview.d.ts +20 -0
  373. package/lib/typescript/src/library/components/VideoPreview.d.ts.map +1 -0
  374. package/lib/typescript/src/library/components/ViewerCounter.d.ts +13 -0
  375. package/lib/typescript/src/library/components/ViewerCounter.d.ts.map +1 -0
  376. package/lib/typescript/src/library/compressionEstimate.d.ts +313 -0
  377. package/lib/typescript/src/library/compressionEstimate.d.ts.map +1 -0
  378. package/lib/typescript/src/library/fileMetadata.d.ts +33 -0
  379. package/lib/typescript/src/library/fileMetadata.d.ts.map +1 -0
  380. package/lib/typescript/src/library/index.d.ts +40 -0
  381. package/lib/typescript/src/library/index.d.ts.map +1 -0
  382. package/lib/typescript/src/library/libraryIconRegistry.d.ts +35 -0
  383. package/lib/typescript/src/library/libraryIconRegistry.d.ts.map +1 -0
  384. package/lib/typescript/src/library/libraryIcons.d.ts +85 -0
  385. package/lib/typescript/src/library/libraryIcons.d.ts.map +1 -0
  386. package/lib/typescript/src/library/localizedFormat.d.ts +49 -0
  387. package/lib/typescript/src/library/localizedFormat.d.ts.map +1 -0
  388. package/lib/typescript/src/library/palette.d.ts +104 -0
  389. package/lib/typescript/src/library/palette.d.ts.map +1 -0
  390. package/lib/typescript/src/library/responsive.d.ts +15 -0
  391. package/lib/typescript/src/library/responsive.d.ts.map +1 -0
  392. package/lib/typescript/src/locales.d.ts +103 -0
  393. package/lib/typescript/src/locales.d.ts.map +1 -0
  394. package/lib/typescript/src/localization.d.ts +1051 -0
  395. package/lib/typescript/src/localization.d.ts.map +1 -0
  396. package/lib/typescript/src/logger.d.ts +4 -0
  397. package/lib/typescript/src/logger.d.ts.map +1 -0
  398. package/lib/typescript/src/lowMemoryCache.d.ts +64 -0
  399. package/lib/typescript/src/lowMemoryCache.d.ts.map +1 -0
  400. package/lib/typescript/src/mediaHistory.d.ts +3 -0
  401. package/lib/typescript/src/mediaHistory.d.ts.map +1 -0
  402. package/lib/typescript/src/mediaStorageService.d.ts +155 -0
  403. package/lib/typescript/src/mediaStorageService.d.ts.map +1 -0
  404. package/lib/typescript/src/memory.d.ts +21 -0
  405. package/lib/typescript/src/memory.d.ts.map +1 -0
  406. package/lib/typescript/src/nativeActions.d.ts +174 -0
  407. package/lib/typescript/src/nativeActions.d.ts.map +1 -0
  408. package/lib/typescript/src/nativeComponentSupport.d.ts +30 -0
  409. package/lib/typescript/src/nativeComponentSupport.d.ts.map +1 -0
  410. package/lib/typescript/src/networkPerformance.d.ts +12 -0
  411. package/lib/typescript/src/networkPerformance.d.ts.map +1 -0
  412. package/lib/typescript/src/performance.d.ts +32 -0
  413. package/lib/typescript/src/performance.d.ts.map +1 -0
  414. package/lib/typescript/src/performanceMonitor.d.ts +45 -0
  415. package/lib/typescript/src/performanceMonitor.d.ts.map +1 -0
  416. package/lib/typescript/src/permissions.d.ts +132 -0
  417. package/lib/typescript/src/permissions.d.ts.map +1 -0
  418. package/lib/typescript/src/rendering.d.ts +9 -0
  419. package/lib/typescript/src/rendering.d.ts.map +1 -0
  420. package/lib/typescript/src/security.d.ts +6 -0
  421. package/lib/typescript/src/security.d.ts.map +1 -0
  422. package/lib/typescript/src/state.d.ts +102 -0
  423. package/lib/typescript/src/state.d.ts.map +1 -0
  424. package/lib/typescript/src/storage.d.ts +117 -0
  425. package/lib/typescript/src/storage.d.ts.map +1 -0
  426. package/lib/typescript/src/theme.d.ts +15 -0
  427. package/lib/typescript/src/theme.d.ts.map +1 -0
  428. package/lib/typescript/src/types.d.ts +802 -0
  429. package/lib/typescript/src/types.d.ts.map +1 -0
  430. package/lib/typescript/src/utils.d.ts +50 -0
  431. package/lib/typescript/src/utils.d.ts.map +1 -0
  432. package/lib/typescript/src/validation.d.ts +52 -0
  433. package/lib/typescript/src/validation.d.ts.map +1 -0
  434. package/package.json +204 -0
  435. package/react-native.config.js +17 -0
  436. package/src/AudioPlayerContext.tsx +220 -0
  437. package/src/CameraPreview.tsx +352 -0
  438. package/src/NativeAnimatedImageView.tsx +71 -0
  439. package/src/NativeAudioPlayerView.tsx +39 -0
  440. package/src/NativeBlurView.tsx +40 -0
  441. package/src/NativeCustomCamera.ts +305 -0
  442. package/src/NativeCustomCamera.web.ts +192 -0
  443. package/src/NativeCustomVideoView.ts +30 -0
  444. package/src/NativeDocumentPreviewView.tsx +196 -0
  445. package/src/NativeMediaThumbnailView.tsx +167 -0
  446. package/src/NativeSvgIcon.tsx +46 -0
  447. package/src/ResponsivePreviewContainer.tsx +227 -0
  448. package/src/accessibility.ts +80 -0
  449. package/src/config.ts +406 -0
  450. package/src/cpuOptimization.ts +365 -0
  451. package/src/db/DatabaseManager.ts +212 -0
  452. package/src/db/MediaMapper.ts +377 -0
  453. package/src/db/MediaRepository.ts +313 -0
  454. package/src/db/index.ts +73 -0
  455. package/src/db/migrations.ts +222 -0
  456. package/src/db/react-native-sqlcipher.d.ts +76 -0
  457. package/src/db/secureKey.ts +100 -0
  458. package/src/db/types.ts +123 -0
  459. package/src/db/useMediaDatabase.ts +191 -0
  460. package/src/defaultIcons.tsx +2390 -0
  461. package/src/deviceCapabilities.ts +438 -0
  462. package/src/errors.ts +350 -0
  463. package/src/iconConfig.tsx +962 -0
  464. package/src/icons.tsx +788 -0
  465. package/src/index.tsx +763 -0
  466. package/src/jest-globals.d.ts +9 -0
  467. package/src/library/MediaLibrary.tsx +141 -0
  468. package/src/library/MediaLibraryScreen.tsx +3003 -0
  469. package/src/library/components/AudioPreview.tsx +73 -0
  470. package/src/library/components/DocumentPreview.tsx +361 -0
  471. package/src/library/components/ExpandableFab.tsx +342 -0
  472. package/src/library/components/FileTiles.tsx +252 -0
  473. package/src/library/components/ImagePreview.tsx +72 -0
  474. package/src/library/components/MediaMetadataHeader.tsx +208 -0
  475. package/src/library/components/RecordAudioScreen.tsx +845 -0
  476. package/src/library/components/VideoPreview.tsx +478 -0
  477. package/src/library/components/ViewerCounter.tsx +71 -0
  478. package/src/library/compressionEstimate.ts +662 -0
  479. package/src/library/fileMetadata.ts +212 -0
  480. package/src/library/index.ts +66 -0
  481. package/src/library/libraryIconRegistry.tsx +86 -0
  482. package/src/library/libraryIcons.tsx +928 -0
  483. package/src/library/localizedFormat.ts +207 -0
  484. package/src/library/palette.ts +281 -0
  485. package/src/library/responsive.ts +49 -0
  486. package/src/locales.ts +381 -0
  487. package/src/localization.ts +1947 -0
  488. package/src/logger.ts +20 -0
  489. package/src/lowMemoryCache.ts +218 -0
  490. package/src/mediaHistory.ts +42 -0
  491. package/src/mediaStorageService.ts +546 -0
  492. package/src/memory.ts +102 -0
  493. package/src/nativeActions.ts +422 -0
  494. package/src/nativeComponentSupport.ts +60 -0
  495. package/src/networkPerformance.ts +30 -0
  496. package/src/performance.ts +137 -0
  497. package/src/performanceMonitor.ts +219 -0
  498. package/src/permissions.ts +403 -0
  499. package/src/rendering.ts +47 -0
  500. package/src/security.ts +19 -0
  501. package/src/state.ts +333 -0
  502. package/src/storage.ts +453 -0
  503. package/src/theme.tsx +467 -0
  504. package/src/types.ts +946 -0
  505. package/src/utils.ts +177 -0
  506. package/src/validation.ts +372 -0
@@ -0,0 +1,494 @@
1
+ package com.customcamera
2
+
3
+ import android.content.Context
4
+ import android.net.Uri
5
+ import android.util.Log
6
+ import kotlinx.coroutines.Dispatchers
7
+ import kotlinx.coroutines.withContext
8
+ import org.json.JSONArray
9
+ import org.json.JSONException
10
+ import org.json.JSONObject
11
+ import java.io.File
12
+ import java.util.concurrent.ConcurrentHashMap
13
+
14
+ /**
15
+ * MediaMetadataStore manages persistent metadata for all media files.
16
+ * Stores and retrieves metadata about cached and published media.
17
+ *
18
+ * Features:
19
+ * - Persistent JSON-based storage
20
+ * - In-memory caching for fast access
21
+ * - Thread-safe operations
22
+ * - Fast queries for cached/published/duplicate media
23
+ * - Automatic backup and recovery
24
+ */
25
+ class MediaMetadataStore private constructor(private val context: Context) {
26
+
27
+ companion object {
28
+ private const val TAG = "MediaMetadataStore"
29
+ private const val METADATA_FILE = "media_metadata.json"
30
+ private const val METADATA_BACKUP_FILE = "media_metadata_backup.json"
31
+
32
+ @Volatile
33
+ private var instance: MediaMetadataStore? = null
34
+
35
+ fun getInstance(context: Context): MediaMetadataStore {
36
+ return instance ?: synchronized(this) {
37
+ instance ?: MediaMetadataStore(context.applicationContext).also { instance = it }
38
+ }
39
+ }
40
+ }
41
+
42
+ private val metadataDir = File(context.filesDir, "metadata").apply { mkdirs() }
43
+ private val metadataFile = File(metadataDir, METADATA_FILE)
44
+ private val backupFile = File(metadataDir, METADATA_BACKUP_FILE)
45
+
46
+ // In-memory cache for fast access
47
+ private val metadataCache = ConcurrentHashMap<String, MediaStorageMetadata>()
48
+ private val hashIndex = ConcurrentHashMap<String, String>() // hash -> mediaId
49
+
50
+ /**
51
+ * Load metadata from disk
52
+ */
53
+ suspend fun loadMetadata() {
54
+ withContext(Dispatchers.IO) {
55
+ // Loading persisted metadata runs at app startup (via MediaStorageWorkflow.initialize).
56
+ // If it throws, the host app crashes on launch AND on every relaunch — a permanent
57
+ // "app won't open" state — because the same corrupt file is re-read each time. This
58
+ // path is therefore made total: it NEVER throws, NEVER recurses, and on unrecoverable
59
+ // corruption it discards the bad files and starts empty. `catch (Throwable)` is
60
+ // deliberate — a StackOverflowError/OutOfMemoryError from a huge/corrupt file is an
61
+ // Error (not an Exception) and would otherwise escape and crash the process.
62
+ try {
63
+ // 1) Try the main file. 2) Fall back to the backup exactly ONCE (no recursion).
64
+ // 3) If neither is usable, reset to empty and delete the corrupt files so the
65
+ // next launch is clean.
66
+ if (parseMetadataFile(metadataFile)) return@withContext
67
+
68
+ if (backupFile.exists() && parseMetadataFile(backupFile)) {
69
+ // Promote the good backup back into the main file for next time.
70
+ runCatching { backupFile.copyTo(metadataFile, overwrite = true) }
71
+ Log.i(TAG, "Recovered metadata from backup")
72
+ return@withContext
73
+ }
74
+
75
+ // Both missing/corrupt — start clean and remove the bad files so we can't loop.
76
+ metadataCache.clear()
77
+ hashIndex.clear()
78
+ runCatching { if (metadataFile.exists()) metadataFile.delete() }
79
+ runCatching { if (backupFile.exists()) backupFile.delete() }
80
+ Log.w(TAG, "No usable metadata file; starting with empty metadata")
81
+ } catch (t: Throwable) {
82
+ // Absolute backstop: a corrupt persisted file must never crash startup.
83
+ Log.e(TAG, "Metadata load failed; starting with empty metadata", t)
84
+ metadataCache.clear()
85
+ hashIndex.clear()
86
+ }
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Parse [file] into the in-memory cache. Returns true when the file existed and was
92
+ * parsed (individual malformed entries are skipped), or false when the file is missing,
93
+ * blank, or has corrupt top-level JSON. Never throws on a corrupt file (returns false),
94
+ * so callers can try the backup without any risk of mutual recursion.
95
+ */
96
+ private fun parseMetadataFile(file: File): Boolean {
97
+ if (!file.exists()) return false
98
+ val json = runCatching { file.readText() }.getOrNull() ?: return false
99
+ if (json.isBlank()) return false
100
+ val jsonArray = try {
101
+ JSONArray(json)
102
+ } catch (e: JSONException) {
103
+ Log.w(TAG, "Corrupt metadata file ${file.name}", e)
104
+ return false
105
+ }
106
+
107
+ metadataCache.clear()
108
+ hashIndex.clear()
109
+ var skipped = 0
110
+ for (i in 0 until jsonArray.length()) {
111
+ try {
112
+ val metadata = MediaStorageMetadata.fromJson(jsonArray.getJSONObject(i))
113
+ metadataCache[metadata.id] = metadata
114
+ if (metadata.fileHash != null) {
115
+ hashIndex[metadata.fileHash] = metadata.id
116
+ }
117
+ } catch (e: JSONException) {
118
+ skipped++
119
+ Log.w(TAG, "Skipping malformed metadata entry at index $i", e)
120
+ }
121
+ }
122
+ Log.i(TAG, "Loaded ${metadataCache.size} metadata entries from ${file.name} (skipped $skipped)")
123
+ return true
124
+ }
125
+
126
+ /**
127
+ * Add cached media metadata
128
+ */
129
+ suspend fun addCachedMedia(
130
+ id: String,
131
+ fileName: String,
132
+ cachePath: String,
133
+ fileType: String,
134
+ fileSize: Long,
135
+ width: Int? = null,
136
+ height: Int? = null,
137
+ duration: Long? = null,
138
+ mimeType: String? = null,
139
+ fileHash: String? = null
140
+ ) {
141
+ withContext(Dispatchers.IO) {
142
+ try {
143
+ val metadata = MediaStorageMetadata(
144
+ id = id,
145
+ fileName = fileName,
146
+ cachePath = cachePath,
147
+ fileType = fileType,
148
+ fileSize = fileSize,
149
+ width = width,
150
+ height = height,
151
+ duration = duration,
152
+ mimeType = mimeType,
153
+ fileHash = fileHash,
154
+ status = "cached",
155
+ cacheCreatedAt = System.currentTimeMillis(),
156
+ cacheLastModified = System.currentTimeMillis(),
157
+ isDuplicate = fileHash != null && hashIndex.containsKey(fileHash)
158
+ )
159
+
160
+ metadataCache[id] = metadata
161
+ if (fileHash != null) {
162
+ hashIndex[fileHash] = id
163
+ }
164
+
165
+ saveMetadata()
166
+ Log.i(TAG, "Cached media added: $id")
167
+ } catch (e: Exception) {
168
+ Log.e(TAG, "Error adding cached media", e)
169
+ }
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Update media status when published
175
+ */
176
+ suspend fun updateMediaStatus(
177
+ mediaId: String,
178
+ status: String,
179
+ publishedUri: String? = null,
180
+ publishedAt: Long? = null,
181
+ documentUri: String? = null
182
+ ) {
183
+ withContext(Dispatchers.IO) {
184
+ try {
185
+ val metadata = metadataCache[mediaId] ?: return@withContext
186
+
187
+ val updated = metadata.copy(
188
+ status = status,
189
+ documentUri = documentUri ?: metadata.documentUri,
190
+ publishedAt = publishedAt ?: metadata.publishedAt,
191
+ cacheLastModified = System.currentTimeMillis()
192
+ )
193
+
194
+ metadataCache[mediaId] = updated
195
+ saveMetadata()
196
+ Log.i(TAG, "Media status updated: $mediaId -> $status")
197
+ } catch (e: Exception) {
198
+ Log.e(TAG, "Error updating media status", e)
199
+ }
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Get cached media (not yet published)
205
+ */
206
+ suspend fun getCachedMedia(): List<MediaStorageMetadata> {
207
+ return withContext(Dispatchers.IO) {
208
+ metadataCache.values.filter { it.status == "cached" }
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Get published media
214
+ */
215
+ suspend fun getPublishedMedia(): List<MediaStorageMetadata> {
216
+ return withContext(Dispatchers.IO) {
217
+ metadataCache.values.filter { it.status == "published" }
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Get all media
223
+ */
224
+ suspend fun getAllMedia(): List<MediaStorageMetadata> {
225
+ return withContext(Dispatchers.IO) {
226
+ metadataCache.values.toList()
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Get media by ID
232
+ */
233
+ suspend fun getMediaMetadata(mediaId: String): MediaStorageMetadata? {
234
+ return withContext(Dispatchers.IO) {
235
+ metadataCache[mediaId]
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Get media by file hash (for duplicate detection)
241
+ */
242
+ suspend fun getMediaByHash(fileHash: String): MediaStorageMetadata? {
243
+ return withContext(Dispatchers.IO) {
244
+ val mediaId = hashIndex[fileHash] ?: return@withContext null
245
+ metadataCache[mediaId]
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Remove media from cache (after successful publish)
251
+ */
252
+ suspend fun removeFromCache(mediaId: String) {
253
+ withContext(Dispatchers.IO) {
254
+ try {
255
+ val metadata = metadataCache[mediaId] ?: return@withContext
256
+
257
+ val updated = metadata.copy(
258
+ cachePath = null,
259
+ status = "published"
260
+ )
261
+
262
+ metadataCache[mediaId] = updated
263
+ saveMetadata()
264
+ Log.i(TAG, "Media removed from cache: $mediaId")
265
+ } catch (e: Exception) {
266
+ Log.e(TAG, "Error removing media from cache", e)
267
+ }
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Remove media completely
273
+ */
274
+ suspend fun removeMedia(mediaId: String) {
275
+ withContext(Dispatchers.IO) {
276
+ try {
277
+ val metadata = metadataCache.remove(mediaId)
278
+ if (metadata?.fileHash != null) {
279
+ hashIndex.remove(metadata.fileHash)
280
+ }
281
+
282
+ saveMetadata()
283
+ Log.i(TAG, "Media removed: $mediaId")
284
+ } catch (e: Exception) {
285
+ Log.e(TAG, "Error removing media", e)
286
+ }
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Get duplicate media
292
+ */
293
+ suspend fun getDuplicateMedia(): List<MediaStorageMetadata> {
294
+ return withContext(Dispatchers.IO) {
295
+ metadataCache.values.filter { it.isDuplicate == true }
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Check if hash exists
301
+ */
302
+ suspend fun hashExists(fileHash: String): Boolean {
303
+ return withContext(Dispatchers.IO) {
304
+ hashIndex.containsKey(fileHash)
305
+ }
306
+ }
307
+
308
+ /**
309
+ * Save metadata to disk
310
+ */
311
+ private suspend fun saveMetadata() {
312
+ withContext(Dispatchers.IO) {
313
+ try {
314
+ val jsonArray = JSONArray()
315
+ metadataCache.values.forEach { metadata ->
316
+ jsonArray.put(metadata.toJson())
317
+ }
318
+ val payload = jsonArray.toString(2)
319
+
320
+ // ATOMIC write: serialize to a temp file, fsync-then-rename into place. writeText
321
+ // directly onto metadataFile is NOT atomic — a crash/kill mid-write leaves a
322
+ // truncated, unparseable file, which is the root cause of the "app won't reopen"
323
+ // startup crash. rename() is atomic on the same filesystem, so a reader always sees
324
+ // either the old complete file or the new complete file, never a partial one.
325
+ val tmpFile = File(metadataDir, "$METADATA_FILE.tmp")
326
+ tmpFile.writeText(payload)
327
+
328
+ // Keep the last known-good file as a backup before swapping the new one in.
329
+ if (metadataFile.exists()) {
330
+ runCatching { metadataFile.copyTo(backupFile, overwrite = true) }
331
+ }
332
+
333
+ if (!tmpFile.renameTo(metadataFile)) {
334
+ // renameTo can fail on some devices/filesystems; fall back to copy + delete.
335
+ tmpFile.copyTo(metadataFile, overwrite = true)
336
+ runCatching { tmpFile.delete() }
337
+ }
338
+ Log.i(TAG, "Metadata saved: ${metadataCache.size} entries")
339
+ } catch (e: Exception) {
340
+ Log.e(TAG, "Error saving metadata", e)
341
+ }
342
+ }
343
+ }
344
+
345
+ /**
346
+ * Clear all metadata (use with caution)
347
+ */
348
+ suspend fun clearAll() {
349
+ withContext(Dispatchers.IO) {
350
+ try {
351
+ metadataCache.clear()
352
+ hashIndex.clear()
353
+ metadataFile.delete()
354
+ backupFile.delete()
355
+ Log.w(TAG, "All metadata cleared")
356
+ } catch (e: Exception) {
357
+ Log.e(TAG, "Error clearing metadata", e)
358
+ }
359
+ }
360
+ }
361
+
362
+ /**
363
+ * Export metadata as JSON
364
+ */
365
+ suspend fun exportMetadata(): String {
366
+ return withContext(Dispatchers.IO) {
367
+ try {
368
+ val jsonArray = JSONArray()
369
+ metadataCache.values.forEach { metadata ->
370
+ jsonArray.put(metadata.toJson())
371
+ }
372
+ jsonArray.toString(2)
373
+ } catch (e: Exception) {
374
+ Log.e(TAG, "Error exporting metadata", e)
375
+ "{}"
376
+ }
377
+ }
378
+ }
379
+
380
+ /**
381
+ * Import metadata from JSON
382
+ */
383
+ suspend fun importMetadata(json: String) {
384
+ withContext(Dispatchers.IO) {
385
+ try {
386
+ metadataCache.clear()
387
+ hashIndex.clear()
388
+
389
+ val jsonArray = JSONArray(json)
390
+ for (i in 0 until jsonArray.length()) {
391
+ val metadata = MediaStorageMetadata.fromJson(jsonArray.getJSONObject(i))
392
+ metadataCache[metadata.id] = metadata
393
+ if (metadata.fileHash != null) {
394
+ hashIndex[metadata.fileHash] = metadata.id
395
+ }
396
+ }
397
+
398
+ saveMetadata()
399
+ Log.i(TAG, "Metadata imported: ${metadataCache.size} entries")
400
+ } catch (e: Exception) {
401
+ Log.e(TAG, "Error importing metadata", e)
402
+ }
403
+ }
404
+ }
405
+ }
406
+
407
+ /**
408
+ * Data class for storing media metadata
409
+ */
410
+ data class MediaStorageMetadata(
411
+ val id: String,
412
+ val fileName: String,
413
+ val cachePath: String?,
414
+ val fileType: String, // "photo" or "video"
415
+ val fileSize: Long,
416
+ val width: Int?,
417
+ val height: Int?,
418
+ val duration: Long?,
419
+ val mimeType: String?,
420
+ val fileHash: String?,
421
+ val dateTaken: Long? = null,
422
+ val status: String, // "cached", "published", etc.
423
+ val cacheCreatedAt: Long,
424
+ val cacheLastModified: Long,
425
+ val publishedAt: Long? = null,
426
+ val documentUri: String? = null,
427
+ val isDuplicate: Boolean = false,
428
+ val duplicateOf: String? = null,
429
+ val caption: String? = null,
430
+ val isEdited: Boolean = false,
431
+ val originalUri: String? = null
432
+ ) {
433
+ fun toJson(): JSONObject {
434
+ return JSONObject().apply {
435
+ put("id", id)
436
+ put("fileName", fileName)
437
+ put("cachePath", cachePath)
438
+ put("fileType", fileType)
439
+ put("fileSize", fileSize)
440
+ put("width", width)
441
+ put("height", height)
442
+ put("duration", duration)
443
+ put("mimeType", mimeType)
444
+ put("fileHash", fileHash)
445
+ put("dateTaken", dateTaken)
446
+ put("status", status)
447
+ put("cacheCreatedAt", cacheCreatedAt)
448
+ put("cacheLastModified", cacheLastModified)
449
+ put("publishedAt", publishedAt)
450
+ put("documentUri", documentUri)
451
+ put("isDuplicate", isDuplicate)
452
+ put("duplicateOf", duplicateOf)
453
+ put("caption", caption)
454
+ put("isEdited", isEdited)
455
+ put("originalUri", originalUri)
456
+ }
457
+ }
458
+
459
+ companion object {
460
+ fun fromJson(json: JSONObject): MediaStorageMetadata {
461
+ // Use opt* accessors (not get*) for EVERY field. get* throws JSONException on a
462
+ // missing key; because loadMetadata() parses entries in a loop inside a single
463
+ // try/catch that falls back to the backup file, one malformed/partial entry (e.g.
464
+ // written by an older app version, or a half-flushed save) would otherwise abort the
465
+ // whole parse and silently discard the user's ENTIRE persisted media library on the
466
+ // next launch. Reading defensively lets every well-formed entry survive; required
467
+ // string fields fall back to safe defaults so a single odd row is tolerated, not fatal.
468
+ return MediaStorageMetadata(
469
+ id = json.optString("id", null).takeIf { !it.isNullOrEmpty() }
470
+ ?: throw JSONException("metadata entry missing id"),
471
+ fileName = json.optString("fileName", "").ifEmpty { "media_${json.optString("id")}" },
472
+ cachePath = json.optString("cachePath", null).takeIf { it.isNotEmpty() },
473
+ fileType = json.optString("fileType", "").ifEmpty { "photo" },
474
+ fileSize = json.optLong("fileSize", 0L),
475
+ width = json.optInt("width", -1).takeIf { it != -1 },
476
+ height = json.optInt("height", -1).takeIf { it != -1 },
477
+ duration = json.optLong("duration", -1).takeIf { it != -1L },
478
+ mimeType = json.optString("mimeType", null).takeIf { it.isNotEmpty() },
479
+ fileHash = json.optString("fileHash", null).takeIf { it.isNotEmpty() },
480
+ dateTaken = json.optLong("dateTaken", -1).takeIf { it != -1L },
481
+ status = json.optString("status", "").ifEmpty { "cached" },
482
+ cacheCreatedAt = json.optLong("cacheCreatedAt", 0L),
483
+ cacheLastModified = json.optLong("cacheLastModified", 0L),
484
+ publishedAt = json.optLong("publishedAt", -1).takeIf { it != -1L },
485
+ documentUri = json.optString("documentUri", null).takeIf { it.isNotEmpty() },
486
+ isDuplicate = json.optBoolean("isDuplicate", false),
487
+ duplicateOf = json.optString("duplicateOf", null).takeIf { it.isNotEmpty() },
488
+ caption = json.optString("caption", null).takeIf { it.isNotEmpty() },
489
+ isEdited = json.optBoolean("isEdited", false),
490
+ originalUri = json.optString("originalUri", null).takeIf { it.isNotEmpty() }
491
+ )
492
+ }
493
+ }
494
+ }