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,386 @@
1
+ package com.customcamera
2
+
3
+ import android.content.Context
4
+ import android.os.Environment
5
+ import android.util.Log
6
+ import kotlinx.coroutines.Dispatchers
7
+ import kotlinx.coroutines.withContext
8
+ import java.io.File
9
+ import java.util.concurrent.TimeUnit
10
+
11
+ /**
12
+ * CacheCleanupManager handles automatic and manual cleanup of cache files.
13
+ *
14
+ * Features:
15
+ * - Automatic cleanup of old files (configurable age)
16
+ * - Size-based cleanup (when cache exceeds max size)
17
+ * - Cleanup of orphaned files (files without metadata)
18
+ * - Cleanup of duplicate files
19
+ * - Retry mechanism for failed deletions
20
+ * - Background scheduling support
21
+ */
22
+ class CacheCleanupManager private constructor(private val context: Context) {
23
+
24
+ companion object {
25
+ private const val TAG = "CacheCleanupManager"
26
+
27
+ // Default cleanup configuration
28
+ private const val DEFAULT_MAX_CACHE_SIZE_MB = 500L
29
+ private const val DEFAULT_CLEANUP_AGE_DAYS = 7
30
+ private const val DEFAULT_ORPHAN_FILE_AGE_HOURS = 24
31
+
32
+ @Volatile
33
+ private var instance: CacheCleanupManager? = null
34
+
35
+ fun getInstance(context: Context): CacheCleanupManager {
36
+ return instance ?: synchronized(this) {
37
+ instance ?: CacheCleanupManager(context.applicationContext).also { instance = it }
38
+ }
39
+ }
40
+ }
41
+
42
+ private val metadataStore = MediaMetadataStore.getInstance(context)
43
+ private var maxCacheSizeMB = DEFAULT_MAX_CACHE_SIZE_MB
44
+ private var cleanupAgeDays = DEFAULT_CLEANUP_AGE_DAYS
45
+ private var orphanFileAgeHours = DEFAULT_ORPHAN_FILE_AGE_HOURS
46
+
47
+ /**
48
+ * Perform cleanup based on age
49
+ */
50
+ suspend fun cleanupOldFiles(olderThanDays: Int = cleanupAgeDays): CleanupResult {
51
+ return withContext(Dispatchers.IO) {
52
+ try {
53
+ val cacheDir = getCacheDir()
54
+ if (!cacheDir.exists()) {
55
+ return@withContext CleanupResult(
56
+ success = true,
57
+ filesRemoved = 0,
58
+ spaceFreedMB = 0.0
59
+ )
60
+ }
61
+
62
+ val cutoffTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(olderThanDays.toLong())
63
+ var filesRemoved = 0
64
+ var spaceFreed = 0L
65
+ val erroredFiles = mutableListOf<ErroredFile>()
66
+
67
+ // Build a cachePath -> mediaId lookup ONCE up front instead of re-reading and
68
+ // re-scanning the entire metadata store for every deleted file (previously an
69
+ // O(files × metadata) pass that dominated cleanup on large caches). One O(metadata)
70
+ // build + O(1) lookups is equivalent in behaviour and far cheaper.
71
+ val pathToMediaId: Map<String, String> = metadataStore.getAllMedia()
72
+ .mapNotNull { m -> m.cachePath?.let { it to m.id } }
73
+ .toMap()
74
+
75
+ cacheDir.walkTopDown().forEach { file ->
76
+ if (file.isFile && file.lastModified() < cutoffTime) {
77
+ try {
78
+ spaceFreed += file.length()
79
+ if (file.delete()) {
80
+ filesRemoved++
81
+ // Remove from metadata by matching cachePath -> id
82
+ try {
83
+ pathToMediaId[file.absolutePath]?.let { metadataStore.removeMedia(it) }
84
+ } catch (e: Exception) {
85
+ Log.w(TAG, "Failed to remove metadata for deleted file: ${file.absolutePath}", e)
86
+ }
87
+ } else {
88
+ erroredFiles.add(ErroredFile(file.absolutePath, "Failed to delete"))
89
+ }
90
+ } catch (e: Exception) {
91
+ erroredFiles.add(ErroredFile(file.absolutePath, e.message ?: "Unknown error"))
92
+ }
93
+ }
94
+ }
95
+
96
+ Log.i(TAG, "Cleanup completed: $filesRemoved files removed, ${spaceFreed / (1024 * 1024)}MB freed")
97
+
98
+ CleanupResult(
99
+ success = true,
100
+ filesRemoved = filesRemoved,
101
+ spaceFreedMB = spaceFreed.toDouble() / (1024 * 1024),
102
+ erroredFiles = erroredFiles
103
+ )
104
+ } catch (e: Exception) {
105
+ Log.e(TAG, "Cleanup operation failed", e)
106
+ CleanupResult(
107
+ success = false,
108
+ filesRemoved = 0,
109
+ spaceFreedMB = 0.0,
110
+ erroredFiles = emptyList(),
111
+ error = e.message
112
+ )
113
+ }
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Cleanup when cache size exceeds maximum
119
+ */
120
+ suspend fun cleanupBySize(maxSizeMB: Long = maxCacheSizeMB): CleanupResult {
121
+ return withContext(Dispatchers.IO) {
122
+ try {
123
+ val cacheDir = getCacheDir()
124
+ if (!cacheDir.exists()) {
125
+ return@withContext CleanupResult(
126
+ success = true,
127
+ filesRemoved = 0,
128
+ spaceFreedMB = 0.0
129
+ )
130
+ }
131
+
132
+ val currentSizeBytes = cacheDir.getTotalSize()
133
+ val maxSizeBytes = maxSizeMB * 1024 * 1024
134
+
135
+ if (currentSizeBytes <= maxSizeBytes) {
136
+ return@withContext CleanupResult(
137
+ success = true,
138
+ filesRemoved = 0,
139
+ spaceFreedMB = 0.0
140
+ )
141
+ }
142
+
143
+ // Need to delete oldest files until size is below threshold
144
+ val targetSizeBytes = (maxSizeMB / 2) * 1024 * 1024 // Clean to 50% of max
145
+ val files = cacheDir.walkTopDown()
146
+ .filter { it.isFile }
147
+ .sortedBy { it.lastModified() } // Oldest first
148
+ .toMutableList()
149
+
150
+ var spaceFreed = 0L
151
+ var filesRemoved = 0
152
+ val erroredFiles = mutableListOf<ErroredFile>()
153
+
154
+ // One-time cachePath -> mediaId lookup (see cleanupOldFiles): avoids re-reading the
155
+ // whole metadata store for every file deleted in the size-eviction loop.
156
+ val pathToMediaId: Map<String, String> = metadataStore.getAllMedia()
157
+ .mapNotNull { m -> m.cachePath?.let { it to m.id } }
158
+ .toMap()
159
+
160
+ for (file in files) {
161
+ if (currentSizeBytes - spaceFreed <= targetSizeBytes) break
162
+
163
+ try {
164
+ spaceFreed += file.length()
165
+ if (file.delete()) {
166
+ filesRemoved++
167
+ try {
168
+ pathToMediaId[file.absolutePath]?.let { metadataStore.removeMedia(it) }
169
+ } catch (e: Exception) {
170
+ Log.w(TAG, "Failed to remove metadata for deleted file: ${file.absolutePath}", e)
171
+ }
172
+ } else {
173
+ erroredFiles.add(ErroredFile(file.absolutePath, "Failed to delete"))
174
+ }
175
+ } catch (e: Exception) {
176
+ erroredFiles.add(ErroredFile(file.absolutePath, e.message ?: "Unknown error"))
177
+ }
178
+ }
179
+
180
+ Log.i(TAG, "Size-based cleanup completed: $filesRemoved files removed, ${spaceFreed / (1024 * 1024)}MB freed")
181
+
182
+ CleanupResult(
183
+ success = true,
184
+ filesRemoved = filesRemoved,
185
+ spaceFreedMB = spaceFreed.toDouble() / (1024 * 1024),
186
+ erroredFiles = erroredFiles
187
+ )
188
+ } catch (e: Exception) {
189
+ Log.e(TAG, "Size-based cleanup failed", e)
190
+ CleanupResult(
191
+ success = false,
192
+ filesRemoved = 0,
193
+ spaceFreedMB = 0.0,
194
+ error = e.message
195
+ )
196
+ }
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Cleanup orphaned files (files without metadata)
202
+ */
203
+ suspend fun cleanupOrphanedFiles(olderThanHours: Int = orphanFileAgeHours): CleanupResult {
204
+ return withContext(Dispatchers.IO) {
205
+ try {
206
+ val cacheDir = getCacheDir()
207
+ if (!cacheDir.exists()) {
208
+ return@withContext CleanupResult(
209
+ success = true,
210
+ filesRemoved = 0,
211
+ spaceFreedMB = 0.0
212
+ )
213
+ }
214
+
215
+ val allMetadata = metadataStore.getAllMedia()
216
+ val metadataFilePaths = allMetadata.mapNotNull { it.cachePath }.toSet()
217
+ val cutoffTime = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(olderThanHours.toLong())
218
+
219
+ var filesRemoved = 0
220
+ var spaceFreed = 0L
221
+ val erroredFiles = mutableListOf<ErroredFile>()
222
+
223
+ cacheDir.walkTopDown().forEach { file ->
224
+ if (file.isFile && file.absolutePath !in metadataFilePaths && file.lastModified() < cutoffTime) {
225
+ try {
226
+ spaceFreed += file.length()
227
+ if (file.delete()) {
228
+ filesRemoved++
229
+ } else {
230
+ erroredFiles.add(ErroredFile(file.absolutePath, "Failed to delete"))
231
+ }
232
+ } catch (e: Exception) {
233
+ erroredFiles.add(ErroredFile(file.absolutePath, e.message ?: "Unknown error"))
234
+ }
235
+ }
236
+ }
237
+
238
+ Log.i(TAG, "Orphaned file cleanup completed: $filesRemoved files removed")
239
+
240
+ CleanupResult(
241
+ success = true,
242
+ filesRemoved = filesRemoved,
243
+ spaceFreedMB = spaceFreed.toDouble() / (1024 * 1024),
244
+ erroredFiles = erroredFiles
245
+ )
246
+ } catch (e: Exception) {
247
+ Log.e(TAG, "Orphaned file cleanup failed", e)
248
+ CleanupResult(
249
+ success = false,
250
+ filesRemoved = 0,
251
+ spaceFreedMB = 0.0,
252
+ error = e.message
253
+ )
254
+ }
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Cleanup duplicate files (keep only one)
260
+ */
261
+ suspend fun cleanupDuplicates(): CleanupResult {
262
+ return withContext(Dispatchers.IO) {
263
+ try {
264
+ val duplicates = metadataStore.getDuplicateMedia()
265
+
266
+ var filesRemoved = 0
267
+ var spaceFreed = 0L
268
+ val erroredFiles = mutableListOf<ErroredFile>()
269
+
270
+ // Group by hash
271
+ val hashGroups = duplicates.groupBy { it.fileHash }
272
+
273
+ hashGroups.forEach { (_, group) ->
274
+ if (group.size > 1) {
275
+ // Keep the first one, delete the rest
276
+ group.drop(1).forEach { duplicate ->
277
+ try {
278
+ val file = File(duplicate.cachePath ?: return@forEach)
279
+ if (file.exists()) {
280
+ spaceFreed += file.length()
281
+ if (file.delete()) {
282
+ filesRemoved++
283
+ metadataStore.removeMedia(duplicate.id)
284
+ } else {
285
+ erroredFiles.add(ErroredFile(file.absolutePath, "Failed to delete"))
286
+ }
287
+ }
288
+ } catch (e: Exception) {
289
+ erroredFiles.add(ErroredFile(duplicate.cachePath ?: "unknown", e.message ?: "Unknown error"))
290
+ }
291
+ }
292
+ }
293
+ }
294
+
295
+ Log.i(TAG, "Duplicate cleanup completed: $filesRemoved duplicate files removed")
296
+
297
+ CleanupResult(
298
+ success = true,
299
+ filesRemoved = filesRemoved,
300
+ spaceFreedMB = spaceFreed.toDouble() / (1024 * 1024),
301
+ erroredFiles = erroredFiles
302
+ )
303
+ } catch (e: Exception) {
304
+ Log.e(TAG, "Duplicate cleanup failed", e)
305
+ CleanupResult(
306
+ success = false,
307
+ filesRemoved = 0,
308
+ spaceFreedMB = 0.0,
309
+ error = e.message
310
+ )
311
+ }
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Perform comprehensive cleanup
317
+ */
318
+ suspend fun performCleanup(): CleanupResult {
319
+ return withContext(Dispatchers.IO) {
320
+ try {
321
+ val results = mutableListOf<CleanupResult>()
322
+
323
+ // Run cleanups in sequence
324
+ results.add(cleanupOrphanedFiles())
325
+ results.add(cleanupOldFiles())
326
+ results.add(cleanupDuplicates())
327
+
328
+ val totalRemoved = results.sumOf { it.filesRemoved }
329
+ val totalSpaceFreed = results.sumOf { it.spaceFreedMB }
330
+ val allErrors = results.flatMap { it.erroredFiles }
331
+
332
+ CleanupResult(
333
+ success = true,
334
+ filesRemoved = totalRemoved,
335
+ spaceFreedMB = totalSpaceFreed,
336
+ erroredFiles = allErrors
337
+ )
338
+ } catch (e: Exception) {
339
+ Log.e(TAG, "Comprehensive cleanup failed", e)
340
+ CleanupResult(
341
+ success = false,
342
+ filesRemoved = 0,
343
+ spaceFreedMB = 0.0,
344
+ error = e.message
345
+ )
346
+ }
347
+ }
348
+ }
349
+
350
+ /**
351
+ * Configure cleanup parameters
352
+ */
353
+ fun configure(maxCacheSizeMB: Long, cleanupAgeDays: Int, orphanFileAgeHours: Int) {
354
+ this.maxCacheSizeMB = maxCacheSizeMB
355
+ this.cleanupAgeDays = cleanupAgeDays
356
+ this.orphanFileAgeHours = orphanFileAgeHours
357
+ }
358
+
359
+ /**
360
+ * Get cache directory
361
+ */
362
+ private fun getCacheDir(): File {
363
+ return File(context.cacheDir, "media_cache").apply { mkdirs() }
364
+ }
365
+
366
+ data class CleanupResult(
367
+ val success: Boolean,
368
+ val filesRemoved: Int,
369
+ val spaceFreedMB: Double,
370
+ val erroredFiles: List<ErroredFile> = emptyList(),
371
+ val error: String? = null
372
+ )
373
+
374
+ data class ErroredFile(
375
+ val path: String,
376
+ val error: String
377
+ )
378
+ }
379
+
380
+ private fun File.getTotalSize(): Long {
381
+ return if (isDirectory) {
382
+ listFiles()?.sumOf { it.getTotalSize() } ?: 0L
383
+ } else {
384
+ length()
385
+ }
386
+ }
@@ -0,0 +1,77 @@
1
+ package com.customcamera
2
+
3
+ object CameraAspectRatioMode {
4
+ const val ORIGINAL_LABEL = "Original"
5
+ const val FULL_LABEL = "Full"
6
+
7
+ data class Mode(val label: String, val ratio: Float)
8
+
9
+ private const val DEFAULT_RATIO = 720f / 1165f
10
+
11
+ fun availableLabels(): List<String> = listOf(ORIGINAL_LABEL, FULL_LABEL, "4:3", "16:9", "1:1", "9:16", "4:5")
12
+
13
+ fun fromLabel(label: String?, fallbackRatio: Float = DEFAULT_RATIO): Mode? = when (label) {
14
+ ORIGINAL_LABEL -> Mode(ORIGINAL_LABEL, fallbackRatio)
15
+ FULL_LABEL -> Mode(FULL_LABEL, fallbackRatio)
16
+ "4:3" -> Mode("4:3", 4f / 3f)
17
+ "16:9" -> Mode("16:9", 16f / 9f)
18
+ "1:1" -> Mode("1:1", 1f)
19
+ "9:16" -> Mode("9:16", 9f / 16f)
20
+ "4:5" -> Mode("4:5", 4f / 5f)
21
+ else -> null
22
+ }
23
+
24
+ fun resolveRatio(label: String?, screenAspectRatio: Float, fallbackRatio: Float = DEFAULT_RATIO): Float =
25
+ fromLabel(label, fallbackRatio)?.let { mode ->
26
+ if (mode.label == FULL_LABEL) screenAspectRatio else mode.ratio
27
+ } ?: fallbackRatio
28
+
29
+ private const val RATIO_16_9 = 16f / 9f
30
+
31
+ // Tolerance for classifying a preview-container ratio (derived from integer pixel dimensions,
32
+ // so it drifts a hair from the exact fraction) against a named aspect. Far tighter than the
33
+ // gap between any two selectable ratios (4:3 ≈ 1.333 vs 16:9 ≈ 1.778), so it never confuses
34
+ // one for another.
35
+ private const val LANDSCAPE_RATIO_MATCH_EPSILON = 0.02f
36
+
37
+ /**
38
+ * Whether a LANDSCAPE capture of [ratio] (the portrait-locked viewfinder box's width / height)
39
+ * must have BOTH its capture crop and its editor framing INVERTED to the box's inverse aspect,
40
+ * so the saved image/video reproduces EXACTLY the region the viewfinder framed — true WYSIWYG,
41
+ * with no camera content revealed outside the capture frame.
42
+ *
43
+ * A box held sideways frames its INVERSE aspect (its on-screen width axis points vertically in
44
+ * the world), so:
45
+ * - every ratio <= 1 (9:16, 4:5, 1:1, Original, Full-on-portrait) inverts, and
46
+ * - 16:9 inverts too: a wide "16:9" box held sideways frames a TALL upright region, so keeping
47
+ * it wide pulled in extra left/right scene the viewfinder never showed.
48
+ * 4:3 is the sole remaining exception — it is deliberately KEPT WIDE for a landscape capture
49
+ * (fills the editor width), an accepted tradeoff. Portrait captures never invert (callers gate
50
+ * on their own rotatedToPortrait flag).
51
+ *
52
+ * This is the single source of truth shared by the capture crop (CustomCameraActivity's photo
53
+ * normalize + video crop-transcode) and the editor framing
54
+ * (MediaPreviewEditor.shouldInvertForLandscape), so the saved file and the editor box stay
55
+ * pixel-for-pixel consistent.
56
+ */
57
+ fun invertsForLandscape(ratio: Float): Boolean =
58
+ ratio > 0f && (ratio <= 1f || Math.abs(ratio - RATIO_16_9) <= LANDSCAPE_RATIO_MATCH_EPSILON)
59
+
60
+ /**
61
+ * User-facing full-word label for a popup-menu row. The [ORIGINAL_LABEL] / [FULL_LABEL]
62
+ * constants stay as stable internal identifiers (used for matching); this maps them to
63
+ * their localized display text. Ratio notation ("4:3", "16:9"…) is universal and passes
64
+ * through unchanged.
65
+ */
66
+ fun displayLabel(label: String?): String = when (label) {
67
+ ORIGINAL_LABEL, null -> Localization.getString("aspectRatioOriginal", "Original")
68
+ FULL_LABEL -> Localization.getString("aspectRatioFull", "Full")
69
+ else -> label
70
+ }
71
+
72
+ fun buttonLabel(label: String?): String = when (label) {
73
+ ORIGINAL_LABEL, null -> Localization.getString("aspectRatioOriginalShort", "Original")
74
+ FULL_LABEL -> Localization.getString("aspectRatioFull", "Full")
75
+ else -> label
76
+ }
77
+ }
@@ -0,0 +1,211 @@
1
+ package com.customcamera
2
+
3
+ import android.content.Context
4
+ import android.net.Uri
5
+ import android.os.Build
6
+ import android.os.Bundle
7
+ import java.io.File
8
+
9
+ data class CameraAsset(
10
+ val id: String,
11
+ val uri: Uri,
12
+ val type: String,
13
+ val fileName: String?,
14
+ val mimeType: String?,
15
+ val width: Int?,
16
+ val height: Int?,
17
+ val duration: Long?,
18
+ val size: Long?,
19
+ val dateTaken: Long?,
20
+ val caption: String? = null,
21
+ val cachePath: String? = null,
22
+ val isCached: Boolean = false,
23
+ val cacheCreatedAt: Long? = null,
24
+ val cacheLastModified: Long? = null,
25
+ val originalUri: String? = null,
26
+ val documentUri: String? = null,
27
+ /**
28
+ * The aspect ratio (width / height) of the live camera preview at the time of capture.
29
+ * Used to render the captured media with identical framing as the viewfinder — true WYSIWYG.
30
+ * Stored as a Float (e.g. 1.33f for 4:3, 1.78f for 16:9) or null if unknown.
31
+ */
32
+ val previewAspectRatio: Float? = null,
33
+ /**
34
+ * True when this photo was captured in landscape orientation. This helps distinguish
35
+ * between images natively captured in portrait (9:16 aspect ratio) versus landscape
36
+ * (captured while the device was held horizontally). Both are now cropped to the selected
37
+ * aspect ratio and stored with previewAspectRatio set, ensuring WYSIWYG behavior where
38
+ * the editor preview exactly matches the capture framing. This flag is provided for
39
+ * editor logic that may need to handle landscape and portrait captures differently.
40
+ */
41
+ val rotatedToPortrait: Boolean = false,
42
+ /**
43
+ * For videos: a content:// (or file://) URI of the user-selected cover frame, extracted as a
44
+ * JPEG in the editor. Purely a poster/thumbnail — the video file itself is unchanged. Surfaced
45
+ * to JS as `coverUri` and preferred by [ThumbnailLoader] for the in-app strip.
46
+ */
47
+ val coverUri: String? = null,
48
+
49
+ /** The exact container width (in pixels) used for the camera preview at capture time. */
50
+ val captureContainerWidth: Int? = null,
51
+
52
+ /** The exact container height (in pixels) used for the camera preview at capture time. */
53
+ val captureContainerHeight: Int? = null,
54
+
55
+ /**
56
+ * True when [size] is a DISPLAY convention rather than the exact bytes on disk. Set for a
57
+ * compressed video published from the editor: the file the encoder writes copies its audio and
58
+ * container through and so sits above the proportional figure the user picked, but the preview /
59
+ * Info screen must quote the SAME proportional size the compression dropdown and the completion
60
+ * toast quote (`original × (1 - percent/100)`). This flag tells JS ([refreshAssetMetadata]) to
61
+ * keep [size] as-is for that clip instead of re-statting the file and overwriting the convention.
62
+ * Everything without a compressed re-encode (originals, muted/trimmed clips, stills) leaves this
63
+ * false, so those still re-stat normally.
64
+ */
65
+ val sizeIsDisplayEstimate: Boolean = false
66
+ ) {
67
+ fun toBundle(): Bundle =
68
+ Bundle().apply {
69
+ putString("id", id)
70
+ putString("uri", uri.toString())
71
+ putString("type", type)
72
+ fileName?.let { putString("fileName", it) }
73
+ mimeType?.let { putString("mimeType", it) }
74
+ width?.let { putInt("width", it) }
75
+ height?.let { putInt("height", it) }
76
+ duration?.let { putDouble("duration", it.toDouble()) }
77
+ size?.let { putDouble("size", it.toDouble()) }
78
+ dateTaken?.let { putDouble("dateTaken", it.toDouble()) }
79
+ caption?.takeIf { it.isNotBlank() }?.let { putString("caption", it) }
80
+ cachePath?.let { putString("cachePath", it) }
81
+ putBoolean("isCached", isCached)
82
+ cacheCreatedAt?.let { putDouble("cacheCreatedAt", it.toDouble()) }
83
+ cacheLastModified?.let { putDouble("cacheLastModified", it.toDouble()) }
84
+ originalUri?.let { putString("originalUri", it) }
85
+ documentUri?.let { putString("documentUri", it) }
86
+ previewAspectRatio?.let { putFloat("previewAspectRatio", it) }
87
+ putBoolean("rotatedToPortrait", rotatedToPortrait)
88
+ coverUri?.let { putString("coverUri", it) }
89
+ captureContainerWidth?.let { putInt("captureContainerWidth", it) }
90
+ captureContainerHeight?.let { putInt("captureContainerHeight", it) }
91
+ putBoolean("sizeIsDisplayEstimate", sizeIsDisplayEstimate)
92
+ }
93
+
94
+ companion object {
95
+ fun fromBundle(bundle: Bundle): CameraAsset {
96
+ return CameraAsset(
97
+ id = bundle.getString("id") ?: "",
98
+ uri = Uri.parse(bundle.getString("uri")),
99
+ type = bundle.getString("type") ?: "photo",
100
+ fileName = bundle.getString("fileName"),
101
+ mimeType = bundle.getString("mimeType"),
102
+ width = if (bundle.containsKey("width")) bundle.getInt("width") else null,
103
+ height = if (bundle.containsKey("height")) bundle.getInt("height") else null,
104
+ duration = if (bundle.containsKey("duration")) bundle.getLong("duration") else null,
105
+ size = if (bundle.containsKey("size")) bundle.getLong("size") else null,
106
+ dateTaken = if (bundle.containsKey("dateTaken")) bundle.getLong("dateTaken") else null,
107
+ caption = bundle.getString("caption"),
108
+ cachePath = bundle.getString("cachePath"),
109
+ isCached = bundle.getBoolean("isCached", false),
110
+ cacheCreatedAt = if (bundle.containsKey("cacheCreatedAt")) bundle.getLong("cacheCreatedAt") else null,
111
+ cacheLastModified = if (bundle.containsKey("cacheLastModified")) bundle.getLong("cacheLastModified") else null,
112
+ originalUri = bundle.getString("originalUri"),
113
+ documentUri = bundle.getString("documentUri"),
114
+ previewAspectRatio = if (bundle.containsKey("previewAspectRatio")) bundle.getFloat("previewAspectRatio") else null,
115
+ rotatedToPortrait = bundle.getBoolean("rotatedToPortrait", false),
116
+ coverUri = bundle.getString("coverUri"),
117
+ captureContainerWidth = if (bundle.containsKey("captureContainerWidth")) bundle.getInt("captureContainerWidth") else null,
118
+ captureContainerHeight = if (bundle.containsKey("captureContainerHeight")) bundle.getInt("captureContainerHeight") else null,
119
+ sizeIsDisplayEstimate = bundle.getBoolean("sizeIsDisplayEstimate", false)
120
+ )
121
+ }
122
+
123
+ fun fromCacheMetadata(
124
+ metadata: MediaCacheManager.MediaCacheMetadata,
125
+ publishedUri: Uri? = null,
126
+ context: Context? = null
127
+ ): CameraAsset {
128
+ val uri = publishedUri ?: if (context != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
129
+ try {
130
+ androidx.core.content.FileProvider.getUriForFile(
131
+ context,
132
+ "${context.packageName}.camera.fileprovider",
133
+ File(metadata.cachePath)
134
+ )
135
+ } catch (e: Exception) {
136
+ Uri.fromFile(File(metadata.cachePath))
137
+ }
138
+ } else {
139
+ Uri.fromFile(File(metadata.cachePath))
140
+ }
141
+
142
+ return CameraAsset(
143
+ id = metadata.id,
144
+ uri = uri,
145
+ type = metadata.fileType,
146
+ fileName = metadata.fileName,
147
+ mimeType = metadata.mimeType,
148
+ width = metadata.width,
149
+ height = metadata.height,
150
+ duration = metadata.duration,
151
+ size = metadata.fileSize,
152
+ dateTaken = metadata.createdAt,
153
+ cachePath = metadata.cachePath,
154
+ isCached = true,
155
+ cacheCreatedAt = metadata.createdAt,
156
+ cacheLastModified = metadata.lastModified,
157
+ originalUri = metadata.originalUri,
158
+ documentUri = publishedUri?.toString(),
159
+ previewAspectRatio = null
160
+ )
161
+ }
162
+ fun fromCacheMediaResult(
163
+ result: MediaStorageWorkflow.CacheMediaResult,
164
+ fileType: String,
165
+ publishedUri: Uri? = null,
166
+ originalUri: String? = null,
167
+ context: Context? = null,
168
+ previewAspectRatio: Float? = null,
169
+ rotatedToPortrait: Boolean = false,
170
+ captureContainerWidth: Int? = null,
171
+ captureContainerHeight: Int? = null
172
+ ): CameraAsset {
173
+ val uri = publishedUri ?: if (context != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
174
+ try {
175
+ androidx.core.content.FileProvider.getUriForFile(
176
+ context,
177
+ "${context.packageName}.camera.fileprovider",
178
+ File(result.cachePath)
179
+ )
180
+ } catch (e: Exception) {
181
+ Uri.fromFile(File(result.cachePath))
182
+ }
183
+ } else {
184
+ Uri.fromFile(File(result.cachePath))
185
+ }
186
+
187
+ return CameraAsset(
188
+ id = result.mediaId,
189
+ uri = uri,
190
+ type = fileType,
191
+ fileName = result.fileName,
192
+ mimeType = result.mimeType,
193
+ width = result.width,
194
+ height = result.height,
195
+ duration = result.duration,
196
+ size = result.fileSize,
197
+ dateTaken = System.currentTimeMillis(),
198
+ cachePath = result.cachePath,
199
+ isCached = true,
200
+ cacheCreatedAt = System.currentTimeMillis(),
201
+ cacheLastModified = System.currentTimeMillis(),
202
+ originalUri = originalUri,
203
+ documentUri = publishedUri?.toString(),
204
+ previewAspectRatio = previewAspectRatio,
205
+ rotatedToPortrait = rotatedToPortrait,
206
+ captureContainerWidth = captureContainerWidth,
207
+ captureContainerHeight = captureContainerHeight
208
+ )
209
+ }
210
+ }
211
+ }