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,506 @@
1
+ package com.customcamera
2
+
3
+ import android.Manifest
4
+ import android.content.Context
5
+ import android.content.pm.PackageManager
6
+ import android.media.MediaRecorder
7
+ import android.util.Log
8
+ import android.os.Build
9
+ import android.os.Handler
10
+ import android.os.HandlerThread
11
+ import android.os.Looper
12
+ import androidx.core.content.ContextCompat
13
+ import com.facebook.react.bridge.Arguments
14
+ import com.facebook.react.bridge.ReactApplicationContext
15
+ import com.facebook.react.bridge.WritableMap
16
+ import com.facebook.react.modules.core.DeviceEventManagerModule
17
+ import java.io.File
18
+ import java.io.IOException
19
+ import java.util.concurrent.CopyOnWriteArrayList
20
+
21
+ /**
22
+ * Singleton that manages audio recording using Android's native MediaRecorder API.
23
+ *
24
+ * No third-party libraries are used — only android.media.MediaRecorder, which is
25
+ * part of the Android SDK. Supports pause/resume (API 24+), amplitude metering
26
+ * for waveform visualisation, and emits JS events for real-time monitoring.
27
+ *
28
+ * Threading model:
29
+ * - All MediaRecorder operations run on the calling (React Native bridge) thread;
30
+ * MediaRecorder is not thread-safe so callers must not overlap invocations.
31
+ * - Metering runs on a dedicated background HandlerThread.
32
+ * - JS events fire on the main thread so React Native can consume them immediately.
33
+ */
34
+ object AudioRecorder {
35
+
36
+ private const val TAG = "AudioRecorder"
37
+ private const val EVENT_AUDIO_RECORDER_STATE = "onAudioRecorderState"
38
+ private const val EVENT_AUDIO_AMPLITUDE = "onAudioAmplitude"
39
+
40
+ /** Current high-level state of the recorder. */
41
+ enum class State { IDLE, RECORDING, PAUSED, ERROR }
42
+
43
+ /** Output format presets that map to [MediaRecorder.OutputFormat] constants. */
44
+ enum class OutputFormat(val apiLevel: Int = 1) {
45
+ MPEG_4,
46
+ AAC_ADTS,
47
+ AMR_NB,
48
+ AMR_WB,
49
+ THREE_GPP;
50
+
51
+ internal fun toMediaRecorderFormat(): Int = when (this) {
52
+ MPEG_4 -> MediaRecorder.OutputFormat.MPEG_4
53
+ AAC_ADTS -> MediaRecorder.OutputFormat.AAC_ADTS
54
+ AMR_NB -> MediaRecorder.OutputFormat.AMR_NB
55
+ AMR_WB -> MediaRecorder.OutputFormat.AMR_WB
56
+ THREE_GPP -> MediaRecorder.OutputFormat.THREE_GPP
57
+ }
58
+ }
59
+
60
+ /** Audio encoder presets that map to [MediaRecorder.AudioEncoder] constants. */
61
+ enum class AudioEncoder {
62
+ AAC, AMR_NB, AMR_WB, HE_AAC;
63
+
64
+ internal fun toMediaRecorderEncoder(): Int = when (this) {
65
+ AAC -> MediaRecorder.AudioEncoder.AAC
66
+ AMR_NB -> MediaRecorder.AudioEncoder.AMR_NB
67
+ AMR_WB -> MediaRecorder.AudioEncoder.AMR_WB
68
+ HE_AAC -> MediaRecorder.AudioEncoder.HE_AAC
69
+ }
70
+ }
71
+
72
+ /** Audio source presets that map to [MediaRecorder.AudioSource] constants. */
73
+ enum class AudioSource {
74
+ MIC, CAMCORDER, VOICE_RECOGNITION, VOICE_COMMUNICATION;
75
+
76
+ internal fun toMediaRecorderSource(): Int = when (this) {
77
+ MIC -> MediaRecorder.AudioSource.MIC
78
+ CAMCORDER -> MediaRecorder.AudioSource.CAMCORDER
79
+ VOICE_RECOGNITION -> MediaRecorder.AudioSource.VOICE_RECOGNITION
80
+ VOICE_COMMUNICATION -> MediaRecorder.AudioSource.VOICE_COMMUNICATION
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Configuration passed from JS when starting a recording.
86
+ * Every field has a sensible default so JS callers can omit everything.
87
+ */
88
+ data class Config(
89
+ val outputFormat: OutputFormat = OutputFormat.MPEG_4,
90
+ val audioEncoder: AudioEncoder = AudioEncoder.AAC,
91
+ val audioSource: AudioSource = AudioSource.MIC,
92
+ val bitRate: Int = 128000,
93
+ val sampleRate: Int = 44100,
94
+ val fileName: String? = null, // null → auto-generate
95
+ val meteringIntervalMs: Long = 0L, // 0 = no metering
96
+ )
97
+
98
+ // ── State ──────────────────────────────────────────────────────────────────
99
+
100
+ @Volatile
101
+ private var state: State = State.IDLE
102
+
103
+ @Volatile
104
+ private var startTimestamp: Long = 0L
105
+
106
+ @Volatile
107
+ private var totalPausedDuration: Long = 0L
108
+
109
+ @Volatile
110
+ private var pauseTimestamp: Long = 0L
111
+
112
+ private var mediaRecorder: MediaRecorder? = null
113
+ private var outputFilePath: String = ""
114
+ private var activeConfig: Config = Config()
115
+ private var reactContext: ReactApplicationContext? = null
116
+
117
+ // Handler on the main looper for emitting JS events.
118
+ private val mainHandler = Handler(Looper.getMainLooper())
119
+
120
+ // Metering thread.
121
+ private var meteringThread: HandlerThread? = null
122
+ private var meteringHandler: Handler? = null
123
+ private var meteringEnabled = false
124
+
125
+ // ── Public API ─────────────────────────────────────────────────────────────
126
+
127
+ /** Returns the current state. Thread-safe because [state] is volatile. */
128
+ fun getState(): State = state
129
+
130
+ /**
131
+ * True when the recorder is either recording or paused — i.e. a recording
132
+ * session is active and stopRecording() should eventually be called.
133
+ */
134
+ fun isActive(): Boolean = state == State.RECORDING || state == State.PAUSED
135
+
136
+ /**
137
+ * Must be called once before any recording operation so the singleton can
138
+ * emit JS events. Safe to call multiple times (overwrites the reference).
139
+ */
140
+ fun setReactContext(context: ReactApplicationContext) {
141
+ reactContext = context
142
+ }
143
+
144
+ /**
145
+ * Start recording audio to [outputDir] (defaults to the app's cacheDir).
146
+ *
147
+ * @param context Android context (used to resolve dirs).
148
+ * @param config Recording parameters.
149
+ * @return A map containing `{ filePath, mimeType }` for the new recording.
150
+ * @throws IllegalStateException if already recording.
151
+ * @throws SecurityException if RECORD_AUDIO permission is not granted.
152
+ * @throws IOException if the output file cannot be created.
153
+ */
154
+ @Throws(IllegalStateException::class, SecurityException::class, IOException::class)
155
+ fun startRecording(context: Context, config: Config = Config()): WritableMap {
156
+ if (state == State.RECORDING) {
157
+ throw IllegalStateException("Audio recorder is already recording")
158
+ }
159
+
160
+ // Check permission.
161
+ if (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO)
162
+ != PackageManager.PERMISSION_GRANTED
163
+ ) {
164
+ throw SecurityException("RECORD_AUDIO permission is not granted")
165
+ }
166
+
167
+ // Release any lingering recorder from a previous incomplete session.
168
+ releaseInternal()
169
+
170
+ activeConfig = config
171
+
172
+ // Determine output file path.
173
+ val dir = File(context.cacheDir, "audio_recordings").apply { mkdirs() }
174
+ val fileName = config.fileName
175
+ ?: "recording_${System.currentTimeMillis()}.${extensionFor(config.outputFormat)}"
176
+ outputFilePath = File(dir, fileName).absolutePath
177
+
178
+ // Configure and start MediaRecorder.
179
+ val recorder = MediaRecorder()
180
+ mediaRecorder = recorder
181
+
182
+ recorder.setAudioSource(config.audioSource.toMediaRecorderSource())
183
+ recorder.setOutputFormat(config.outputFormat.toMediaRecorderFormat())
184
+ recorder.setAudioEncoder(config.audioEncoder.toMediaRecorderEncoder())
185
+ recorder.setAudioSamplingRate(config.sampleRate)
186
+ recorder.setAudioEncodingBitRate(config.bitRate)
187
+ recorder.setOutputFile(outputFilePath)
188
+
189
+ recorder.prepare()
190
+ recorder.start()
191
+
192
+ state = State.RECORDING
193
+ startTimestamp = System.currentTimeMillis()
194
+ totalPausedDuration = 0L
195
+ pauseTimestamp = 0L
196
+
197
+ // Start metering loop if configured.
198
+ if (config.meteringIntervalMs > 0L) {
199
+ startMetering(config.meteringIntervalMs)
200
+ }
201
+
202
+ emitStateEvent()
203
+ Log.i(TAG, "Recording started → $outputFilePath")
204
+
205
+ return Arguments.createMap().apply {
206
+ putString("filePath", outputFilePath)
207
+ putString("mimeType", mimeTypeFor(config.outputFormat))
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Cancel the current recording and delete the temporary file.
213
+ *
214
+ * @return `true` if the temp file was deleted, `false` if no file existed.
215
+ * @throws IllegalStateException if no recording is active.
216
+ */
217
+ @Throws(IllegalStateException::class)
218
+ fun cancelRecording(): Boolean {
219
+ if (!isActive()) {
220
+ throw IllegalStateException("No active recording to cancel")
221
+ }
222
+
223
+ val filePath = outputFilePath
224
+
225
+ stopMetering()
226
+
227
+ try {
228
+ mediaRecorder?.apply {
229
+ try {
230
+ stop()
231
+ } catch (e: RuntimeException) {
232
+ Log.w(TAG, "MediaRecorder.stop() threw during cancel", e)
233
+ }
234
+ release()
235
+ }
236
+ mediaRecorder = null
237
+
238
+ // Delete the temporary file.
239
+ val deleted = if (filePath.isNotEmpty()) {
240
+ val f = File(filePath)
241
+ if (f.exists()) f.delete() else false
242
+ } else false
243
+
244
+ state = State.IDLE
245
+ activeConfig = Config()
246
+ startTimestamp = 0L
247
+ totalPausedDuration = 0L
248
+ pauseTimestamp = 0L
249
+ outputFilePath = ""
250
+
251
+ emitStateEvent()
252
+ Log.i(TAG, "Recording cancelled — temp file deleted=$deleted")
253
+ return deleted
254
+ } catch (e: Exception) {
255
+ state = State.ERROR
256
+ emitStateEvent()
257
+ Log.e(TAG, "Error cancelling recording", e)
258
+ throw e
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Stop the current recording session and finalise the audio file.
264
+ *
265
+ * @return A map containing the recorded file metadata:
266
+ * `{ filePath, durationMs, fileSizeBytes, mimeType }`.
267
+ * @throws IllegalStateException if no recording is active.
268
+ */
269
+ @Throws(IllegalStateException::class)
270
+ fun stopRecording(): WritableMap {
271
+ if (!isActive()) {
272
+ throw IllegalStateException("No active recording to stop")
273
+ }
274
+
275
+ val filePath = outputFilePath
276
+ val mimeType = mimeTypeFor(activeConfig.outputFormat)
277
+
278
+ stopMetering()
279
+
280
+ val durationMs: Long
281
+ val fileSizeBytes: Long
282
+
283
+ try {
284
+ // Stop & release the recorder.
285
+ mediaRecorder?.apply {
286
+ try {
287
+ stop() // May throw if called while paused on some OEMs; catch and continue.
288
+ } catch (e: RuntimeException) {
289
+ Log.w(TAG, "MediaRecorder.stop() threw — file may be incomplete", e)
290
+ }
291
+ release()
292
+ }
293
+ mediaRecorder = null
294
+
295
+ // Calculate effective duration, accounting for pauses.
296
+ val now = System.currentTimeMillis()
297
+ if (pauseTimestamp > 0L) {
298
+ totalPausedDuration += now - pauseTimestamp
299
+ }
300
+ durationMs = now - startTimestamp - totalPausedDuration
301
+
302
+ // Read final file size.
303
+ fileSizeBytes = File(filePath).let { if (it.exists()) it.length() else 0L }
304
+ } catch (e: Exception) {
305
+ state = State.ERROR
306
+ emitStateEvent()
307
+ Log.e(TAG, "Error stopping recording", e)
308
+ throw e
309
+ }
310
+
311
+ state = State.IDLE
312
+ emitStateEvent()
313
+ Log.i(TAG, "Recording stopped — duration=${durationMs}ms size=${fileSizeBytes}bytes")
314
+
315
+ return Arguments.createMap().apply {
316
+ putString("filePath", filePath)
317
+ putDouble("durationMs", durationMs.toDouble())
318
+ putDouble("fileSizeBytes", fileSizeBytes.toDouble())
319
+ putString("mimeType", mimeType)
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Pause the current recording.
325
+ *
326
+ * Requires API 24+ (Build.VERSION_CODES.N). On older API levels this
327
+ * throws [UnsupportedOperationException].
328
+ */
329
+ @Throws(IllegalStateException::class, UnsupportedOperationException::class)
330
+ fun pauseRecording() {
331
+ if (state != State.RECORDING) {
332
+ throw IllegalStateException("Cannot pause — recorder is not recording (state=$state)")
333
+ }
334
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
335
+ throw UnsupportedOperationException("Pause/resume requires API 24+")
336
+ }
337
+
338
+ mediaRecorder?.pause()
339
+ state = State.PAUSED
340
+ pauseTimestamp = System.currentTimeMillis()
341
+ stopMetering()
342
+ emitStateEvent()
343
+ Log.i(TAG, "Recording paused")
344
+ }
345
+
346
+ /**
347
+ * Resume a paused recording.
348
+ *
349
+ * Requires API 24+. On older API levels this throws [UnsupportedOperationException].
350
+ */
351
+ @Throws(IllegalStateException::class, UnsupportedOperationException::class)
352
+ fun resumeRecording() {
353
+ if (state != State.PAUSED) {
354
+ throw IllegalStateException("Cannot resume — recorder is not paused (state=$state)")
355
+ }
356
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
357
+ throw UnsupportedOperationException("Pause/resume requires API 24+")
358
+ }
359
+
360
+ mediaRecorder?.resume()
361
+ state = State.RECORDING
362
+ totalPausedDuration += System.currentTimeMillis() - pauseTimestamp
363
+ pauseTimestamp = 0L
364
+
365
+ if (activeConfig.meteringIntervalMs > 0L) {
366
+ startMetering(activeConfig.meteringIntervalMs)
367
+ }
368
+ emitStateEvent()
369
+ Log.i(TAG, "Recording resumed")
370
+ }
371
+
372
+ /**
373
+ * Get the current recording state as a WritableMap suitable for bridging to JS.
374
+ */
375
+ fun getStateMap(): WritableMap = Arguments.createMap().apply {
376
+ putString("state", state.name.lowercase())
377
+ putString("filePath", outputFilePath)
378
+ putDouble("durationMs", computeElapsedMs().toDouble())
379
+ putBoolean("isPauseSupported", Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
380
+ }
381
+
382
+ /**
383
+ * Get the current maximum amplitude from MediaRecorder (for metering).
384
+ * Returns 0 if no recorder is active.
385
+ */
386
+ fun getAmplitude(): Int {
387
+ return try {
388
+ mediaRecorder?.maxAmplitude ?: 0
389
+ } catch (e: Exception) {
390
+ 0
391
+ }
392
+ }
393
+
394
+ // ── Metering ───────────────────────────────────────────────────────────────
395
+
396
+ /**
397
+ * Start periodic amplitude sampling on a background thread.
398
+ * Emits [EVENT_AUDIO_AMPLITUDE] JS events every [intervalMs].
399
+ */
400
+ private fun startMetering(intervalMs: Long) {
401
+ stopMetering()
402
+ meteringEnabled = true
403
+
404
+ meteringThread = HandlerThread("AudioMetering").apply { start() }
405
+ meteringHandler = Handler(meteringThread!!.looper)
406
+
407
+ meteringHandler?.post(object : Runnable {
408
+ override fun run() {
409
+ if (!meteringEnabled) return
410
+ val amp = getAmplitude()
411
+ emitAmplitudeEvent(amp)
412
+ meteringHandler?.postDelayed(this, intervalMs)
413
+ }
414
+ })
415
+ }
416
+
417
+ /** Stop the metering loop and tear down its thread. */
418
+ private fun stopMetering() {
419
+ meteringEnabled = false
420
+ meteringHandler?.removeCallbacksAndMessages(null)
421
+ meteringHandler = null
422
+ meteringThread?.quitSafely()
423
+ meteringThread = null
424
+ }
425
+
426
+ // ── Internal helpers ───────────────────────────────────────────────────────
427
+
428
+ /**
429
+ * Compute the effective recording duration, excluding paused time.
430
+ */
431
+ private fun computeElapsedMs(): Long {
432
+ if (startTimestamp == 0L) return 0L
433
+ val now = System.currentTimeMillis()
434
+ var paused = totalPausedDuration
435
+ if (pauseTimestamp > 0L) {
436
+ paused += now - pauseTimestamp
437
+ }
438
+ return now - startTimestamp - paused
439
+ }
440
+
441
+ /**
442
+ * Release the current MediaRecorder without finalising the file.
443
+ * Called before starting a new recording or during cleanup.
444
+ */
445
+ private fun releaseInternal() {
446
+ stopMetering()
447
+ try {
448
+ mediaRecorder?.apply {
449
+ try {
450
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
451
+ // On API 24+ we can safely stop. On older versions this may throw.
452
+ try { stop() } catch (_: RuntimeException) {}
453
+ }
454
+ } catch (_: Exception) {}
455
+ release()
456
+ }
457
+ } catch (_: Exception) {}
458
+ mediaRecorder = null
459
+ state = State.IDLE
460
+ startTimestamp = 0L
461
+ totalPausedDuration = 0L
462
+ pauseTimestamp = 0L
463
+ outputFilePath = ""
464
+ }
465
+
466
+ /** Emit a state-change event to JS. */
467
+ private fun emitStateEvent() {
468
+ val ctx = reactContext ?: return
469
+ val map = getStateMap()
470
+ mainHandler.post {
471
+ try {
472
+ ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
473
+ .emit(EVENT_AUDIO_RECORDER_STATE, map)
474
+ } catch (_: Exception) {}
475
+ }
476
+ }
477
+
478
+ /** Emit an amplitude metering event to JS. */
479
+ private fun emitAmplitudeEvent(amplitude: Int) {
480
+ val ctx = reactContext ?: return
481
+ mainHandler.post {
482
+ try {
483
+ ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
484
+ .emit(EVENT_AUDIO_AMPLITUDE, amplitude)
485
+ } catch (_: Exception) {}
486
+ }
487
+ }
488
+
489
+ // ── MIME / extension helpers ───────────────────────────────────────────────
490
+
491
+ private fun mimeTypeFor(fmt: OutputFormat): String = when (fmt) {
492
+ OutputFormat.MPEG_4 -> "audio/mp4"
493
+ OutputFormat.AAC_ADTS -> "audio/aac"
494
+ OutputFormat.AMR_NB -> "audio/amr"
495
+ OutputFormat.AMR_WB -> "audio/amr-wb"
496
+ OutputFormat.THREE_GPP -> "audio/3gpp"
497
+ }
498
+
499
+ private fun extensionFor(fmt: OutputFormat): String = when (fmt) {
500
+ OutputFormat.MPEG_4 -> "m4a"
501
+ OutputFormat.AAC_ADTS -> "aac"
502
+ OutputFormat.AMR_NB -> "amr"
503
+ OutputFormat.AMR_WB -> "amr"
504
+ OutputFormat.THREE_GPP -> "3gp"
505
+ }
506
+ }