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,1064 @@
1
+ "use strict";
2
+
3
+ import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
4
+ import { I18nManager, NativeModules, StyleSheet } from 'react-native';
5
+ import { DEFAULT_LOCALE, isRtlLocale, normalizeLocale, resolveLocaleTranslations } from "./locales.js";
6
+
7
+ /**
8
+ * Translations for many languages at once, keyed by language identifier.
9
+ *
10
+ * Keys are BCP-47 tags in whatever spelling the host already uses — `fr`,
11
+ * `pt-BR`, `zh_CN`, `zh-Hant` all work, and lookup is case- and
12
+ * separator-insensitive. Register the whole set once and switch languages with
13
+ * {@link setCameraLanguage}.
14
+ *
15
+ * ```ts
16
+ * const bundles: CameraTranslationBundles = {
17
+ * fr: { send: 'Envoyer', cancel: 'Annuler' },
18
+ * ar: { send: 'إرسال', cancel: 'إلغاء' },
19
+ * };
20
+ * ```
21
+ */
22
+
23
+ /**
24
+ * Whatever a host's `subscribe` happens to hand back. Functions, RN's
25
+ * `EmitterSubscription` (`remove`), and Rx-style subscriptions (`unsubscribe`)
26
+ * are all accepted so the provider can usually be a one-line adapter over an
27
+ * i18n library the host already has; returning nothing is fine too.
28
+ */
29
+
30
+ /**
31
+ * A live view of the host app's active language. Bind one once at startup and
32
+ * every plugin surface — React Native screens *and* the native Android camera —
33
+ * follows the host from then on, with no further calls on language change.
34
+ *
35
+ * The host stays the single source of truth: the plugin only reads this, never
36
+ * the device locale, and keeps no language state of its own beyond the last
37
+ * value read here.
38
+ *
39
+ * ```ts
40
+ * configureCameraPlugin({
41
+ * language: {
42
+ * get: () => i18n.language,
43
+ * subscribe: (onChange) => {
44
+ * i18n.on('languageChanged', onChange);
45
+ * return () => i18n.off('languageChanged', onChange);
46
+ * },
47
+ * },
48
+ * translations: myBundles,
49
+ * });
50
+ * ```
51
+ */
52
+
53
+ export const defaultTranslations = {
54
+ all: 'All',
55
+ photos: 'Photos',
56
+ videos: 'Videos',
57
+ documents: 'Documents',
58
+ cancel: 'Cancel',
59
+ done: 'Done',
60
+ ok: 'OK',
61
+ use: 'Use',
62
+ trim: 'Trim',
63
+ selectCover: 'Select cover',
64
+ add: 'Add',
65
+ addMore: 'Add more',
66
+ addMorePlus: '+ Add more',
67
+ mediaCounter: '{0} / {1}',
68
+ trimRangeLabel: '{0} – {1}',
69
+ durationZero: '0:00',
70
+ fileSizeBytes: '{0} B',
71
+ fileSizeKb: '{0} KB',
72
+ fileSizeMb: '{0} MB',
73
+ fileSizeGb: '{0} GB',
74
+ dateFormatPattern: 'MMM dd, yyyy',
75
+ openSettings: 'Open Settings',
76
+ close: 'Close',
77
+ back: 'Back',
78
+ send: 'Send',
79
+ save: 'Save',
80
+ delete: 'Delete',
81
+ deleteFile: 'Delete file',
82
+ clear: 'Clear',
83
+ clearFilter: 'Clear applied filter',
84
+ filterClearSuffix: '{0} (Clear)',
85
+ audio: 'Audio',
86
+ document: 'Document',
87
+ openingCamera: 'Opening camera...',
88
+ initializingCamera: 'Initializing camera...',
89
+ gallery: 'Gallery',
90
+ selectedCount: '{0} selected',
91
+ openGallery: 'Open gallery',
92
+ openWith: 'Open with',
93
+ libraryEmptyTitle: 'Nothing here yet',
94
+ libraryEmptyMessage: 'Tap the + button to capture photos and videos with the camera',
95
+ share: 'Share',
96
+ photoMode: 'Photo',
97
+ videoMode: 'Video',
98
+ recording: 'Recording',
99
+ shutterCapture: 'Capture',
100
+ shutterHoldToRecord: 'Capture. Hold to record video',
101
+ holdForVideo: 'Hold for video, tap for photo',
102
+ slideUpToLock: 'Slide up to lock',
103
+ slideToCancel: 'Slide to cancel',
104
+ cancelRecording: 'Cancel',
105
+ releaseToCancel: 'Release to cancel',
106
+ recordingLocked: 'Recording locked · Tap to stop',
107
+ flashOn: 'Flash on',
108
+ flashOff: 'Flash off',
109
+ flashAuto: 'Flash auto',
110
+ switchCamera: 'Switch camera',
111
+ toggleFlashlight: 'Toggle flashlight',
112
+ pointCameraAtBarcode: 'Point the camera at a QR code or barcode',
113
+ closeScanner: 'Close scanner',
114
+ permissionRequiredTitle: 'Permission required',
115
+ permissionRequiredMessage: 'Camera and media access are needed to use the camera. Please enable the permissions for this app in Settings.',
116
+ permissionCameraRequiredMessage: 'Camera access is needed to use the camera. Please enable it for this app in Settings.',
117
+ permissionMediaRequiredTitle: 'Gallery access required',
118
+ permissionMediaRequiredMessage: 'Photo and video access is needed to browse your gallery. Please enable it for this app in Settings.',
119
+ permissionRationaleCameraPersistentMessage: 'This app needs camera access to take photos and record video. When the system asks, choose "While using the app" so you are not asked again each time you reopen the app.',
120
+ permissionContinue: 'Continue',
121
+ permissionRationaleCameraTitle: 'Camera Permission Required',
122
+ permissionRationaleCameraMessage: 'This app needs camera access to take photos and record videos.',
123
+ permissionRationaleStorageTitle: 'Storage Permission Required',
124
+ permissionRationaleStorageMessage: 'This app needs storage access to save photos and videos to your gallery.',
125
+ permissionRationaleMicrophoneTitle: 'Microphone Permission Required',
126
+ permissionRationaleMicrophoneMessage: 'This app needs microphone access to record audio with videos.',
127
+ permissionGrant: 'Grant',
128
+ permissionDeny: 'Deny',
129
+ cameraUnavailable: 'Camera not available on this device',
130
+ cameraNotFound: 'No camera found. Check device settings.',
131
+ cameraInitializationFailed: 'Failed to initialize camera. Please try again.',
132
+ cameraPermissionDenied: 'Camera permission denied',
133
+ cameraPermissionRequired: 'Camera permission is required to use this feature',
134
+ tapToScan: 'Tap to scan',
135
+ preparingVideo: 'Preparing video...',
136
+ selectionTooShort: 'Selection too short',
137
+ trimming: 'Trimming...',
138
+ trimFailed: 'Trim failed',
139
+ cropping: 'Cropping...',
140
+ cropFailed: 'Crop failed',
141
+ savingCover: 'Saving cover...',
142
+ couldNotSetCover: 'Could not set cover',
143
+ coverUpdated: 'Cover updated',
144
+ saving: 'Saving...',
145
+ savedToGallery: 'Saved to gallery',
146
+ failedToSaveMedia: 'Failed to save media',
147
+ sending: 'Sending...',
148
+ failedToSendMedia: 'Failed to send media',
149
+ couldNotSaveEditsSendingOriginal: 'Could not save edits, sending original',
150
+ sendFailed: 'Send failed',
151
+ sendFailedWithMessage: 'Send failed: {0}',
152
+ addTextTitle: 'Add text',
153
+ addTextButton: 'Add',
154
+ typeTextHint: 'Type text',
155
+ sizeLabel: 'Size: {0}',
156
+ drawOnImage: 'Draw on the image',
157
+ preparing: 'Preparing...',
158
+ couldNotPrepareEditsForCropping: 'Could not prepare edits for cropping',
159
+ useTwoFingersToResizeOrRotate: 'Use two fingers to resize or rotate',
160
+ operationTimedOut: 'Operation timed out',
161
+ audioMuted: 'Audio muted',
162
+ audioOn: 'Audio on',
163
+ compressVideo: 'Compress Video',
164
+ originalVideo: 'Original video',
165
+ compressImage: 'Compress Image',
166
+ originalImage: 'Original image',
167
+ compressionProfile: 'Compression',
168
+ profileRecommended: 'Recommended',
169
+ compressionAlreadyMinimal: 'Already as small as it gets — keeping the original',
170
+ compressEstimatedSize: '{0} (~{1})',
171
+ compressOriginalSize: '{0} ({1})',
172
+ compressSizeRange: '{0} – {1}',
173
+ compressedToSize: 'Compressed to {0} ({1}% smaller)',
174
+ compressedToSizeOnly: 'Compressed to {0}',
175
+ compressionFailed: 'Compression failed',
176
+ compressingSecondsLeft: 'Compressing ({0}s left)',
177
+ finalizingCompression: 'Finalizing...',
178
+ compressActiveLabel: '{0}% quality',
179
+ compressSmallerByPercent: 'Smaller by {0}%',
180
+ selectedOption: '{0}, selected',
181
+ moreOptions: 'More options',
182
+ exportBy: 'Save As',
183
+ exportActiveDesc: 'Save format: {0}',
184
+ originalFormat: 'Original',
185
+ exportingMedia: 'Saving…',
186
+ convertingSecondsLeft: 'Exporting ({0}s left)',
187
+ exportFailed: 'Export failed',
188
+ exportedTo: 'Exported as {0}',
189
+ exportedToFormat: 'Exported as {0} ({1})',
190
+ exportedAudioDropped: 'Exported as {0} — {1} cannot carry this audio track, so audio was removed',
191
+ convertGifExportMessage: 'Exporting this GIF to another format will remove its animation and save it as a still image.',
192
+ convertGifCompressMessage: 'Compressing this GIF will remove its animation and save it as a still image.',
193
+ convertGifTitle: 'Convert GIF to image?',
194
+ keepAnimation: 'Keep animation',
195
+ convertToImage: 'Convert',
196
+ clearAppliedFilter: 'Clear applied filter',
197
+ toggleAudio: 'Toggle audio',
198
+ trimVideo: 'Trim video',
199
+ rotate90Degrees: 'Rotate 90 degrees',
200
+ cropAspectRatio: 'Aspect ratio',
201
+ cropAspectFree: 'Free',
202
+ noStickersAvailable: 'No stickers available',
203
+ noEmojisAvailable: 'No emojis available',
204
+ filterClearLabel: '{0} (Clear)',
205
+ emptyFile: '(empty file)',
206
+ previewTruncated: 'preview truncated',
207
+ unsupportedPreviewKind: 'Unsupported preview kind: {0}',
208
+ fileNotPreviewableText: 'File is not previewable text',
209
+ couldNotOpenPdf: 'Could not open PDF: {0}',
210
+ cannotOpenDocumentStream: 'Cannot open document stream',
211
+ couldNotReadFile: 'Could not read file: {0}',
212
+ webViewUnavailable: 'WebView unavailable: {0}',
213
+ notDecodableImage: 'Not a decodable image',
214
+ couldNotDecodeImage: 'Could not decode image: {0}',
215
+ documentPreviewUnavailable: 'Document preview unavailable',
216
+ filterNone: 'None',
217
+ filterAuto: 'Auto',
218
+ filterGray: 'Gray',
219
+ filterNegative: 'Negative',
220
+ filterBright: 'Bright',
221
+ filterContrast: 'Contrast',
222
+ filterSharpen: 'Sharpen',
223
+ filterFilm: 'Film',
224
+ filterTint: 'Tint',
225
+ filterVignette: 'Vignette',
226
+ filterSoft: 'Soft',
227
+ filterDark: 'Dark',
228
+ filterLight: 'Light',
229
+ filterDesaturate: 'Desaturate',
230
+ filterEnhance: 'Enhance',
231
+ filterCinematic: 'Cinematic',
232
+ filterBW: 'B&W',
233
+ filterSepia: 'Sepia',
234
+ filterVintage: 'Vintage',
235
+ filterCool: 'Cool',
236
+ filterWarm: 'Warm',
237
+ filterSaturate: 'Saturate',
238
+ filterFade: 'Fade',
239
+ filterVivid: 'Vivid',
240
+ filterNormal75: 'Normal (75%)',
241
+ categoryClassic: 'Classic',
242
+ categoryFaces: 'Faces',
243
+ categoryLove: 'Love',
244
+ categoryCelebration: 'Celebration',
245
+ categoryAnimals: 'Animals',
246
+ categoryFood: 'Food',
247
+ categoryVibes: 'Vibes',
248
+ categorySmileys: 'Smileys',
249
+ categoryPeople: 'People',
250
+ categoryAnimalsAndNature: 'Animals & Nature',
251
+ categoryFoodAndDrink: 'Food & Drink',
252
+ categoryActivities: 'Activities',
253
+ categoryTravelAndPlaces: 'Travel & Places',
254
+ categoryObjects: 'Objects',
255
+ categorySymbols: 'Symbols',
256
+ categoryFlags: 'Flags',
257
+ categoryRecent: 'Recent',
258
+ uploadProgressTitle: 'Upload Progress',
259
+ uploadProgressDescription: 'Displays progress of background uploads',
260
+ uploadStatusTitle: 'Upload Status',
261
+ uploadStatusDescription: 'Notifies when a background upload completes or fails',
262
+ uploadInterruptedTitle: 'Upload interrupted',
263
+ uploadInterruptedMessage: 'A previous upload stopped before completing (file {0} of {1}).',
264
+ uploadRetrying: 'Retrying file {0} of {1} (attempt {2} of {3})...',
265
+ uploadCompletedTitle: 'Upload completed',
266
+ uploadCompletedMessage: 'Successfully uploaded {0} file(s).',
267
+ uploadFailedTitle: 'Upload failed',
268
+ uploadFailedMessage: 'Uploaded {0} of {1} file(s) - {2} failed. {3}',
269
+ uploadingFileProgress: 'Uploading file {0} of {1} ({2}%)',
270
+ preparingFilesProgress: 'Preparing files... ({0}%)',
271
+ uploadingMediaTitle: 'Uploading media',
272
+ validationSelectionLimitNonNegativeInteger: 'Selection limit must be a non-negative integer',
273
+ validationInitialCameraInvalid: 'Initial camera must be either "back" or "front"',
274
+ validationMediaTypesInvalid: 'Media type must be one of: "all", "photo", "video"',
275
+ validationHoldToRecordDelayInvalid: 'Hold-to-record delay must be a non-negative number of milliseconds (0 = system long-press timeout)',
276
+ validationMinRecordDurationInvalid: 'Minimum recording duration must be a non-negative number of milliseconds',
277
+ validationUrisMustBeArray: 'Media URIs must be an array',
278
+ validationUrisCannotBeEmpty: 'Media URIs cannot be empty',
279
+ validationTooManyFiles: 'Cannot process more than {0} files at once',
280
+ validationInvalidUriAtIndex: 'Invalid URI at index {0}: {1}',
281
+ validationAlbumNameRequired: 'Album name must be a non-empty string',
282
+ validationAlbumNameTooLong: 'Album name cannot exceed {0} characters',
283
+ validationAlbumNameInvalidCharacters: 'Album name contains invalid characters: / : * ? " < > |',
284
+ validationCaptionMustBeString: 'Caption must be a string',
285
+ validationCaptionTooLong: 'Caption cannot exceed {0} characters',
286
+ validationDelayMustBeNumber: 'Delay must be a valid number',
287
+ validationDelayCannotBeNegative: 'Delay cannot be negative',
288
+ validationDelayTooLong: 'Delay cannot exceed {0} seconds',
289
+ validationStartTimeInvalid: 'Start time must be a non-negative number',
290
+ validationEndTimeInvalid: 'End time must be a non-negative number',
291
+ validationStartBeforeEnd: 'Start time must be less than end time',
292
+ validationTrimDurationTooLong: 'Trim duration cannot exceed {0} seconds',
293
+ validationUploadUrlRequired: 'Upload URL must be a non-empty string',
294
+ validationUploadUrlInvalid: 'Upload URL must be a valid URL',
295
+ validationFileTooLarge: '{0} is too large ({1}MB). Maximum allowed size is {2}MB',
296
+ validationAlbumIdRequired: 'Album ID must be a non-empty string',
297
+ validationAlbumIdTooLong: 'Album ID cannot exceed {0} characters',
298
+ validationDegreesMustBeNumber: 'Degrees must be a valid number',
299
+ validationDegreesInvalid: 'Degrees must be one of: 0, 90, 180, 270',
300
+ validationWidthPositive: 'Width must be a positive number',
301
+ validationHeightPositive: 'Height must be a positive number',
302
+ validationXNumber: 'X coordinate must be a number',
303
+ validationYNumber: 'Y coordinate must be a number',
304
+ validationFilterTypeInvalid: 'Invalid filter type: {0}. Valid options: {1}',
305
+ validationFlashModeInvalid: 'Invalid flash mode: {0}. Valid options: {1}',
306
+ validationFaceEffectInvalid: 'Invalid face effect: {0}. Valid options: {1}',
307
+ validationThemeInvalid: 'Invalid camera theme: {0}. Valid options: {1}',
308
+ errorCameraPermission: 'Camera permission is required to use this feature',
309
+ errorPleaseEnableCameraPermission: 'Please enable camera permission in settings',
310
+ errorMicrophonePermission: 'Microphone permission is required for video recording',
311
+ errorMicrophoneDeniedSilentVideo: 'Microphone access denied — this video will be recorded without sound',
312
+ errorStoragePermission: 'Storage permission is required to save media',
313
+ errorGalleryPermission: 'Gallery permission is required to browse your media',
314
+ errorInvalidUri: 'Invalid media file',
315
+ errorFileNotFound: 'Media file not found',
316
+ errorFileTooLarge: 'File is too large to process',
317
+ errorOperationCancelled: 'Operation was cancelled',
318
+ errorCameraUnavailable: 'Camera is not available on this device',
319
+ errorInsufficientStorage: 'Not enough storage space available',
320
+ errorStorageFullVideo: 'Not enough storage space to record a video.',
321
+ noticeStorageFullStopped: 'Storage is full — recording stopped.',
322
+ storageAlmostFullTitle: 'Storage almost full',
323
+ storageAlmostFullMessage: 'Storage space is almost full. The current recording will be finalized to prevent data loss.',
324
+ memoryCriticalTitle: 'Low memory',
325
+ memoryCriticalMessage: 'Your device is running critically low on memory. The current recording will be finalized to prevent crashes or data loss.',
326
+ next: 'Next',
327
+ errorRecordingFailed: 'Recording could not be saved. Please try again.',
328
+ errorNetworkUnavailable: 'Network connection is required',
329
+ errorUploadFailed: 'Failed to upload media',
330
+ errorMediaLoadFailed: 'Unable to open the selected media',
331
+ errorUnknown: 'An error occurred',
332
+ statusReady: 'Ready',
333
+ statusProcessingWithProgress: 'Processing... {0}%',
334
+ statusProcessing: 'Processing...',
335
+ statusSuccess: 'Completed successfully',
336
+ statusUnknown: 'Unknown status',
337
+ // ===== Multilingual coverage additions =====
338
+ unknown: 'Unknown',
339
+ untitled: 'Untitled',
340
+ preview: 'Preview',
341
+ media: 'Media',
342
+ image: 'Image',
343
+ video: 'Video',
344
+ deleteConfirmTitle: 'Delete this item?',
345
+ deleteConfirmMessage: 'Are you sure you want to delete this item? This action cannot be undone.',
346
+ notSecurelyErasedTitle: 'Removed, but not securely erased',
347
+ notSecurelyErasedMessage: 'This item was removed from your library, but its file data could not be fully overwritten. It may still be recoverable from device storage.',
348
+ deleteMedia: 'Delete media',
349
+ shareMedia: 'Share media',
350
+ toolFilter: 'Filter',
351
+ toolCrop: 'Crop',
352
+ toolText: 'Text',
353
+ toolEmoji: 'Emoji',
354
+ toolGrid: 'Grid',
355
+ emoji: 'Emoji',
356
+ stickers: 'Stickers',
357
+ toolGif: 'GIF',
358
+ gifPickerTitle: 'Add GIF',
359
+ gifSearchPlaceholder: 'Search GIFs',
360
+ gifTrending: 'Trending',
361
+ gifCategories: 'Categories',
362
+ noGifsFound: 'No GIFs found',
363
+ gifLoadError: "Couldn't load GIFs",
364
+ gifOfflineError: 'No internet connection',
365
+ gifNotConfigured: 'GIF picker is not set up',
366
+ gifRateLimited: 'Too many requests. Try again shortly.',
367
+ gifLoading: 'Loading GIFs…',
368
+ deleteGif: 'Delete GIF',
369
+ categoryGestures: 'Gestures',
370
+ playVideo: 'Play video',
371
+ pauseVideo: 'Pause video',
372
+ deleteSticker: 'Delete sticker',
373
+ closeEditor: 'Close editor',
374
+ download: 'Download',
375
+ selectedVideo: 'Selected video',
376
+ selectedPhoto: 'Selected photo',
377
+ removeSelectedItem: 'Remove selected item',
378
+ addMoreMedia: 'Add more media',
379
+ compressingPleaseWait: 'Compressing, please wait',
380
+ compressingEllipsis: 'Compressing…',
381
+ selectFilterTitle: 'Select Filter',
382
+ filterAccessibilityLabel: '{0} filter',
383
+ closeFilters: 'Close filters',
384
+ recordAudio: 'Record Audio',
385
+ browseAudio: 'Browse Audio',
386
+ camera: 'Camera',
387
+ closeActionsMenu: 'Close actions menu',
388
+ openActionsMenu: 'Open actions menu',
389
+ micPermanentlyDenied: 'Microphone permission permanently denied. Please enable it in Settings.',
390
+ micPermissionDenied: 'Microphone permission denied.',
391
+ micPermissionRequestFailed: 'Failed to request microphone permission.',
392
+ failedToStartRecording: 'Failed to start recording',
393
+ micPermissionNotGranted: 'Microphone permission not granted.',
394
+ recordingTooShort: 'Recording too short. Hold for at least 0.5 seconds.',
395
+ failedToSaveRecording: 'Failed to save recording',
396
+ requestingPermission: 'Requesting Permission',
397
+ allowMicAccess: 'Please allow microphone access to record audio.',
398
+ recordingError: 'Recording Error',
399
+ tryAgain: 'Try Again',
400
+ pausedBadge: 'PAUSED',
401
+ paused: 'Paused',
402
+ tapToStartRecording: 'Tap the button below to start recording',
403
+ discard: 'Discard',
404
+ pause: 'Pause',
405
+ resume: 'Resume',
406
+ savingRecording: 'Saving recording…',
407
+ micRationaleMessage: 'This app needs microphone access to record audio.',
408
+ unknownSize: 'Unknown size',
409
+ noAppToOpenFile: 'No app available to open this file.',
410
+ couldNotOpenFile: 'Could not open this file.',
411
+ pageCountSingular: '{0} page',
412
+ pageCountPlural: '{0} pages',
413
+ fileCouldNotBePreviewed: 'This file could not be previewed.',
414
+ noInAppPreview: 'No in-app preview for this format.',
415
+ openNamed: 'Open {0}',
416
+ open: 'Open',
417
+ opening: 'Opening…',
418
+ compressing: 'Compressing...',
419
+ errorProcessPhoto: 'Failed to process captured photo.',
420
+ errorCapturePhoto: 'Failed to capture photo. Please try again.',
421
+ uploadErrorCouldNotOpenStream: 'Could not open the file to upload',
422
+ uploadErrorCouldNotOpenFile: 'Could not open file: {0}',
423
+ uploadErrorServerCode: 'Server returned error code: {0}',
424
+ uploadErrorNetwork: 'Network error: {0}',
425
+ powerPointPresentationTitle: 'PowerPoint presentation',
426
+ couldNotOpenPresentation: 'Could not open presentation: {0}',
427
+ couldNotReadPowerPoint: 'Could not read PowerPoint presentation: {0}',
428
+ couldNotOpenDocument: 'Could not open document: {0}',
429
+ couldNotConvertDocument: 'Could not convert document: {0}',
430
+ officeBinaryPreviewNote: 'Text preview shown below — open in PowerPoint, Google Slides, or WPS Office for full formatting and images.',
431
+ unableToExtractBinaryText: 'Unable to extract text from this binary file. Open in PowerPoint for the best experience.',
432
+ openInOfficeAppNote: 'Open this file in PowerPoint, Google Slides, or WPS Office for the best viewing experience.',
433
+ previewTruncatedRowsCols: 'Preview truncated — showing first {0} rows / {1} columns',
434
+ previewTruncatedRows: 'Preview truncated — showing first {0} rows',
435
+ previewTruncatedChapters: 'Preview truncated — first {0} chapters',
436
+ previewTruncatedNotice: 'Preview truncated',
437
+ powerPointNoSlides: 'No slides',
438
+ unknownDate: 'Unknown date',
439
+ aspectRatioOriginal: 'Original',
440
+ aspectRatioFull: 'Full',
441
+ aspectRatioOriginalShort: 'Original',
442
+ gifBadge: 'GIF',
443
+ textFontSample: 'Aa',
444
+ slideNumberLabel: 'SLIDE {0}',
445
+ docTypePowerpoint: 'PowerPoint Presentation',
446
+ docTypeWord: 'Word Document',
447
+ docTypeExcel: 'Excel Spreadsheet',
448
+ docTypeOffice: 'Office Document',
449
+ compressActiveDesc: 'Quality: {0}%',
450
+ convertGifMessage: 'Editing this GIF will remove its animation and save it as a still image.',
451
+ convertGifCropMessage: 'Cropping this GIF will remove its animation and save it as a still image.',
452
+ couldNotDecodeImageGeneric: 'Could not decode image',
453
+ memoryWarningMessage: 'Low memory detected. Background operations are being reduced to keep recording stable.',
454
+ savingEdits: 'Saving edits...',
455
+ textCancel: 'Cancel text',
456
+ textFont: 'Change font',
457
+ textAlignment: 'Change text alignment',
458
+ textBackground: 'Change text background',
459
+ textDone: 'Apply text',
460
+ // GIF picker / overlay (native MediaPreviewEditor). gifNotConfigured, gifRateLimited
461
+ // and gifLoadError already have defaults in the "Editor GIF picker" section above.
462
+ gifSearchHint: 'Search GIFs',
463
+ addingGif: 'Adding GIF…',
464
+ gifLoadFailed: "Couldn't load that GIF",
465
+ gifOffline: 'No internet connection',
466
+ gifTimeout: 'The request timed out',
467
+ gifServerError: 'The GIF service is unavailable',
468
+ gifNoResults: 'No GIFs found',
469
+ // Media library shell — details sheet, metadata rows and formatting units
470
+ mediaDetails: 'Media details',
471
+ photoDetails: 'Photo details',
472
+ videoDetails: 'Video details',
473
+ metaFileName: 'File name',
474
+ metaFileType: 'File type',
475
+ metaFileSize: 'File size',
476
+ metaDuration: 'Duration',
477
+ metaResolution: 'Resolution',
478
+ metaDate: 'Date',
479
+ metaPath: 'Path',
480
+ pixelsUnit: 'px',
481
+ viewDetails: 'View details',
482
+ fileTypeGeneric: 'FILE',
483
+ audioTypeGeneric: 'AUD',
484
+ // Full-screen viewer video controls
485
+ play: 'Play',
486
+ toggleVideoControls: 'Toggle video controls',
487
+ seekBackward: 'Rewind {0} seconds',
488
+ seekForward: 'Forward {0} seconds'
489
+ };
490
+ export const cameraLocalizationKeys = Object.freeze(Object.keys(defaultTranslations));
491
+ function normalizeTranslations(translations) {
492
+ if (!translations) return {};
493
+ return cameraLocalizationKeys.reduce((acc, key) => {
494
+ const value = translations[key];
495
+ if (typeof value === 'string' && value.length > 0) {
496
+ acc[key] = value;
497
+ }
498
+ return acc;
499
+ }, {});
500
+ }
501
+ function formatMessage(message, args) {
502
+ return args.reduce((text, arg, index) => text.split(`{${index}}`).join(arg == null ? '' : String(arg)), message);
503
+ }
504
+ function resolveIsRtl(isRtl, locale) {
505
+ // Precedence: an explicit override, then the direction implied by the active
506
+ // language, then whatever direction the host app itself is running in.
507
+ if (typeof isRtl === 'boolean') return isRtl;
508
+ if (locale && normalizeLocale(locale).length > 0) return isRtlLocale(locale);
509
+ return I18nManager.isRTL;
510
+ }
511
+
512
+ /**
513
+ * Normalizes whatever a host's `subscribe` returned into a plain unsubscriber.
514
+ *
515
+ * Returning `undefined` for an unrecognized shape is deliberate: the binding
516
+ * still works, it simply cannot be released — better than calling an arbitrary
517
+ * method on a host object and guessing wrong.
518
+ */
519
+ function toLanguageUnsubscribe(subscription) {
520
+ if (typeof subscription === 'function') return subscription;
521
+ if (typeof subscription !== 'object' || subscription === null) return undefined;
522
+ const remove = subscription.remove;
523
+ if (typeof remove === 'function') {
524
+ return () => remove.call(subscription);
525
+ }
526
+ const unsubscribe = subscription.unsubscribe;
527
+ if (typeof unsubscribe === 'function') {
528
+ return () => unsubscribe.call(subscription);
529
+ }
530
+ return undefined;
531
+ }
532
+
533
+ /**
534
+ * True when a value looks like a {@link CameraLanguageProvider} rather than a
535
+ * language tag. Lets a single `language` option accept either one.
536
+ */
537
+ export function isCameraLanguageProvider(value) {
538
+ if (typeof value !== 'object' || value === null) return false;
539
+ const candidate = value;
540
+ return typeof candidate.get === 'function' && typeof candidate.subscribe === 'function';
541
+ }
542
+ class LocalizationManagerImpl {
543
+ bundles = {};
544
+ fallbackLocale = DEFAULT_LOCALE;
545
+ locale = '';
546
+ translations = {
547
+ ...defaultTranslations
548
+ };
549
+ isRtl = resolveIsRtl();
550
+ listeners = new Set();
551
+ /**
552
+ * The host's language authority, when one is bound. Held by identity so a
553
+ * re-bind of the same object is recognized as a no-op.
554
+ */
555
+
556
+ /** Releases {@link languageProvider}'s subscription. One at a time, always. */
557
+
558
+ /**
559
+ * Binds the host app's language provider — the plugin's language authority for
560
+ * as long as it stays bound.
561
+ *
562
+ * Leak- and duplicate-safe by construction: the previous subscription is always
563
+ * released before a new one is taken, and re-binding the *same* provider object
564
+ * only re-reads it, so a startup path that runs more than once (Fast Refresh, a
565
+ * remount, a second `configureCameraPlugin`) cannot stack listeners.
566
+ *
567
+ * @param options.resolve `false` for callers that are about to
568
+ * {@link LocalizationManagerImpl.resolve} anyway, keeping a config change to a
569
+ * single re-render and a single native push.
570
+ */
571
+ bindLanguageProvider(provider, options = {}) {
572
+ const shouldResolve = options.resolve !== false;
573
+ if (provider && provider === this.languageProvider) {
574
+ // Already bound: adopt whatever it reads now, in case the host changed
575
+ // language through a path that does not notify.
576
+ if (this.adoptProviderLocale() && shouldResolve) this.resolve();
577
+ return;
578
+ }
579
+ this.releaseLanguageProvider();
580
+ if (!provider) return;
581
+ this.languageProvider = provider;
582
+
583
+ // Adopt the CURRENT language before subscribing, so a provider bound at
584
+ // startup takes effect without waiting for a first change event, and so a
585
+ // provider that notifies synchronously on subscribe finds state in place.
586
+ const changed = this.adoptProviderLocale();
587
+ let subscription;
588
+ try {
589
+ subscription = provider.subscribe(next => {
590
+ this.handleProviderLanguageChange(next);
591
+ });
592
+ } catch {
593
+ // A provider that cannot be subscribed to still drives the language it
594
+ // reported above; it just will not push later changes.
595
+ subscription = undefined;
596
+ }
597
+ this.releaseProviderSubscription = toLanguageUnsubscribe(subscription);
598
+ if (changed && shouldResolve) this.resolve();
599
+ }
600
+
601
+ /** Detaches the bound provider, if any. The active language is left as-is. */
602
+ unbindLanguageProvider() {
603
+ this.releaseLanguageProvider();
604
+ }
605
+
606
+ /**
607
+ * Re-reads the bound provider and republishes if its language moved. The manual
608
+ * escape hatch for a host whose provider cannot notify.
609
+ */
610
+ syncLanguageFromProvider() {
611
+ if (!this.languageProvider) return;
612
+ if (this.adoptProviderLocale()) this.resolve();
613
+ }
614
+
615
+ /** The bound provider, for hosts that need to check whether auto-sync is on. */
616
+ getLanguageProvider() {
617
+ return this.languageProvider;
618
+ }
619
+ releaseLanguageProvider() {
620
+ const release = this.releaseProviderSubscription;
621
+ this.releaseProviderSubscription = undefined;
622
+ this.languageProvider = undefined;
623
+ if (!release) return;
624
+ try {
625
+ release();
626
+ } catch {
627
+ // Teardown is host-owned; a throwing unsubscriber must not break re-binding.
628
+ }
629
+ }
630
+ readProviderLocale() {
631
+ try {
632
+ return this.languageProvider?.get();
633
+ } catch {
634
+ // A throwing `get()` must not silently drop the plugin back to English.
635
+ return this.locale;
636
+ }
637
+ }
638
+
639
+ /**
640
+ * Pulls the provider's language into `locale`. Returns whether it moved, which
641
+ * is what lets callers skip a redundant re-render and native push.
642
+ */
643
+ adoptProviderLocale() {
644
+ const next = normalizeLocale(this.readProviderLocale());
645
+ if (next === this.locale) return false;
646
+ this.locale = next;
647
+ return true;
648
+ }
649
+ handleProviderLanguageChange(next) {
650
+ // The tag may arrive with the notification (i18next passes `lng`) or not at
651
+ // all, in which case `get()` is the authority.
652
+ const reported = typeof next === 'string' ? next : this.readProviderLocale();
653
+ const normalized = normalizeLocale(reported);
654
+ if (normalized === this.locale) return;
655
+ this.locale = normalized;
656
+ this.resolve();
657
+ }
658
+
659
+ /**
660
+ * Re-asserts a bound provider's language over any `locale` a config carried, so
661
+ * the host stays the single source of truth even when the two disagree.
662
+ */
663
+ assertLanguageAuthority() {
664
+ if (this.languageProvider) this.adoptProviderLocale();
665
+ }
666
+
667
+ /**
668
+ * Replaces the whole localization configuration. Anything omitted is cleared,
669
+ * which is what makes `setCameraLocalization({})` a reset.
670
+ *
671
+ * A bound language provider is the one exception: it is only touched when the
672
+ * config actually carries a `languageProvider` key. Otherwise a screen that
673
+ * pushes its own bundles would silently switch off auto-sync that was set up at
674
+ * startup. Pass `languageProvider: null` to detach on purpose.
675
+ */
676
+ setLocalization(config = {}) {
677
+ this.translateFn = config.translate;
678
+ this.hostTranslations = config.translations;
679
+ this.bundles = config.bundles ? {
680
+ ...config.bundles
681
+ } : {};
682
+ this.fallbackLocale = normalizeLocale(config.fallbackLocale) || DEFAULT_LOCALE;
683
+ this.locale = normalizeLocale(config.locale);
684
+ this.explicitIsRtl = config.isRtl;
685
+ if ('languageProvider' in config) {
686
+ this.bindLanguageProvider(config.languageProvider, {
687
+ resolve: false
688
+ });
689
+ }
690
+ this.assertLanguageAuthority();
691
+ this.resolve();
692
+ }
693
+
694
+ /**
695
+ * Merges a partial configuration into the current one. Use this to add bundles
696
+ * or change the language without re-sending everything else.
697
+ */
698
+ updateLocalization(config = {}) {
699
+ if ('translate' in config) this.translateFn = config.translate;
700
+ if ('translations' in config) this.hostTranslations = config.translations;
701
+ if (config.bundles) this.bundles = {
702
+ ...this.bundles,
703
+ ...config.bundles
704
+ };
705
+ if (config.fallbackLocale !== undefined) {
706
+ this.fallbackLocale = normalizeLocale(config.fallbackLocale) || DEFAULT_LOCALE;
707
+ }
708
+ if (config.locale !== undefined) this.locale = normalizeLocale(config.locale);
709
+ if ('isRtl' in config) this.explicitIsRtl = config.isRtl;
710
+ if ('languageProvider' in config) {
711
+ this.bindLanguageProvider(config.languageProvider, {
712
+ resolve: false
713
+ });
714
+ }
715
+ this.assertLanguageAuthority();
716
+ this.resolve();
717
+ }
718
+
719
+ /**
720
+ * Switches the active language, keeping registered bundles and callbacks.
721
+ *
722
+ * Remains available as a manual fallback while a provider is bound; the next
723
+ * change the provider reports simply wins, since the host owns the language.
724
+ */
725
+ setLanguage(locale) {
726
+ this.locale = normalizeLocale(locale);
727
+ this.resolve();
728
+ }
729
+
730
+ /**
731
+ * Rebuilds the resolved translation table and text direction, pushes both to
732
+ * the native camera, and notifies every subscribed component.
733
+ *
734
+ * Priority, lowest to highest: shipped English defaults, locale bundles along
735
+ * the fallback chain, the host's translate callback, then explicit overrides.
736
+ */
737
+ resolve() {
738
+ this.isRtl = resolveIsRtl(this.explicitIsRtl, this.locale);
739
+ const bundleTranslations = normalizeTranslations(resolveLocaleTranslations(this.locale, this.bundles, this.fallbackLocale));
740
+ const generatedTranslations = {};
741
+ if (this.translateFn) {
742
+ cameraLocalizationKeys.forEach(key => {
743
+ try {
744
+ const translated = this.translateFn?.(key);
745
+ if (typeof translated === 'string' && translated.length > 0) {
746
+ generatedTranslations[key] = translated;
747
+ }
748
+ } catch {
749
+ // Translation callbacks are host-owned; missing keys fall back below.
750
+ }
751
+ });
752
+ }
753
+ this.translations = {
754
+ ...defaultTranslations,
755
+ ...bundleTranslations,
756
+ ...generatedTranslations,
757
+ ...normalizeTranslations(this.hostTranslations)
758
+ };
759
+ try {
760
+ NativeModules.CustomCamera?.setLocalization?.(this.translations, this.isRtl, this.locale);
761
+ } catch {
762
+ // Native localization is best-effort for test, web, and non-Android contexts.
763
+ }
764
+ this.notifyListeners();
765
+ }
766
+ subscribe(listener) {
767
+ this.listeners.add(listener);
768
+ return () => {
769
+ this.listeners.delete(listener);
770
+ };
771
+ }
772
+ getString(key, ...args) {
773
+ let text;
774
+ if (this.translateFn) {
775
+ try {
776
+ text = this.translateFn(key, ...args);
777
+ } catch {
778
+ text = undefined;
779
+ }
780
+ }
781
+ const message = typeof text === 'string' && text.length > 0 ? text : this.translations[key] || defaultTranslations[key] || String(key);
782
+ return formatMessage(message, args);
783
+ }
784
+ getIsRtl() {
785
+ return this.isRtl;
786
+ }
787
+
788
+ /** The active language, or `''` when the host has not set one. */
789
+ getLocale() {
790
+ return this.locale;
791
+ }
792
+
793
+ /** The language used to fill gaps in the active one. `'en'` unless changed. */
794
+ getFallbackLocale() {
795
+ return this.fallbackLocale;
796
+ }
797
+
798
+ /** Every locale the host has registered a bundle for. */
799
+ getAvailableLocales() {
800
+ return Object.keys(this.bundles);
801
+ }
802
+ getTextAlign() {
803
+ return this.isRtl ? 'right' : 'left';
804
+ }
805
+ getFlexDirection() {
806
+ return this.isRtl ? 'row-reverse' : 'row';
807
+ }
808
+ getTranslations() {
809
+ return this.translations;
810
+ }
811
+ notifyListeners() {
812
+ this.listeners.forEach(listener => listener());
813
+ }
814
+ }
815
+ export const LocalizationManager = new LocalizationManagerImpl();
816
+
817
+ /**
818
+ * Hands the host app's language and translations to the plugin. This is the
819
+ * single integration point — call it once at startup, and either bind a
820
+ * `languageProvider` so later switches are picked up automatically or call
821
+ * {@link setCameraLanguage} on each change.
822
+ *
823
+ * ```ts
824
+ * setCameraLocalization({
825
+ * bundles: myBundles,
826
+ * // Bound once; every later host language change follows automatically.
827
+ * languageProvider: {
828
+ * get: () => i18n.language,
829
+ * subscribe: (onChange) => {
830
+ * i18n.on('languageChanged', onChange);
831
+ * return () => i18n.off('languageChanged', onChange);
832
+ * },
833
+ * },
834
+ * translate: (key) => i18n.t(`camera.${key}`),
835
+ * });
836
+ * ```
837
+ *
838
+ * Every field is optional and omitted fields are cleared, so `{}` restores the
839
+ * shipped English strings — with one deliberate exception: a language provider
840
+ * bound by {@link setCameraLanguageProvider} is kept unless the config explicitly
841
+ * carries `languageProvider`, so automatic synchronization set up once at startup
842
+ * cannot be switched off by a later config push.
843
+ */
844
+ export function setCameraLocalization(config = {}) {
845
+ LocalizationManager.setLocalization(config);
846
+ }
847
+
848
+ /**
849
+ * Merges into the current configuration instead of replacing it. Handy for
850
+ * registering more bundles later, or changing one field on its own.
851
+ */
852
+ export function updateCameraLocalization(config = {}) {
853
+ LocalizationManager.updateLocalization(config);
854
+ }
855
+
856
+ /**
857
+ * Turns on one-time automatic language synchronization: bind the host app's
858
+ * language once and every plugin surface follows it from then on.
859
+ *
860
+ * On each host language change the plugin re-resolves its translation table,
861
+ * re-renders every React Native screen and component, and pushes the new
862
+ * translations, locale, and RTL direction across the bridge to the native Android
863
+ * camera and editor — no further calls needed.
864
+ *
865
+ * Safe to call more than once: the same provider object re-binds without stacking
866
+ * a listener, a different one releases the previous subscription first, and `null`
867
+ * detaches (after which {@link setCameraLanguage} is the way to switch).
868
+ *
869
+ * ```ts
870
+ * // i18next
871
+ * setCameraLanguageProvider({
872
+ * get: () => i18n.language,
873
+ * subscribe: (onChange) => {
874
+ * i18n.on('languageChanged', onChange);
875
+ * return () => i18n.off('languageChanged', onChange);
876
+ * },
877
+ * });
878
+ *
879
+ * // a plain store / context
880
+ * setCameraLanguageProvider({
881
+ * get: () => store.getState().language,
882
+ * subscribe: (onChange) => store.subscribe(onChange),
883
+ * });
884
+ * ```
885
+ */
886
+ export function setCameraLanguageProvider(provider) {
887
+ LocalizationManager.bindLanguageProvider(provider);
888
+ }
889
+
890
+ /** Turns automatic synchronization back off. The active language is kept. */
891
+ export function clearCameraLanguageProvider() {
892
+ LocalizationManager.unbindLanguageProvider();
893
+ }
894
+
895
+ /**
896
+ * Re-reads the bound language provider and republishes if it moved. Only needed
897
+ * for a host whose language can change without notifying — normally the
898
+ * subscription covers this.
899
+ */
900
+ export function syncCameraLanguage() {
901
+ LocalizationManager.syncLanguageFromProvider();
902
+ }
903
+
904
+ /** The bound language provider, or `undefined` when auto-sync is off. */
905
+ export function getCameraLanguageProvider() {
906
+ return LocalizationManager.getLanguageProvider();
907
+ }
908
+
909
+ /**
910
+ * Switches the plugin to the host's newly selected language — the manual
911
+ * alternative to {@link setCameraLanguageProvider}, and still supported.
912
+ *
913
+ * Registered bundles and the host's translate callback are kept, so this is the
914
+ * one call to make from a language-change handler. Text direction is re-derived
915
+ * from the tag, so Arabic and Persian flip the plugin to RTL automatically. Open
916
+ * plugin screens and the native camera update immediately — no restart.
917
+ *
918
+ * ```ts
919
+ * i18n.on('languageChanged', setCameraLanguage);
920
+ * ```
921
+ */
922
+ export function setCameraLanguage(locale) {
923
+ // Accepting a provider here too means a host that reaches for the familiar
924
+ // function gets automatic synchronization instead of a mangled language tag.
925
+ if (isCameraLanguageProvider(locale)) {
926
+ LocalizationManager.bindLanguageProvider(locale);
927
+ return;
928
+ }
929
+ LocalizationManager.setLanguage(locale);
930
+ }
931
+
932
+ /** Registers (or replaces) translations for one or more languages. */
933
+ export function registerCameraTranslations(bundles) {
934
+ LocalizationManager.updateLocalization({
935
+ bundles
936
+ });
937
+ }
938
+
939
+ /** The plugin's active language, or `''` when the host has not set one. */
940
+ export function getCameraLocale() {
941
+ return LocalizationManager.getLocale();
942
+ }
943
+
944
+ /** Whether plugin UI is currently laid out right-to-left. */
945
+ export function getCameraIsRtl() {
946
+ return LocalizationManager.getIsRtl();
947
+ }
948
+ const CameraLocalizationContext = /*#__PURE__*/createContext(null);
949
+ export function CameraLocalizationProvider({
950
+ children,
951
+ translate,
952
+ translations,
953
+ bundles,
954
+ fallbackLocale,
955
+ isRtl,
956
+ locale,
957
+ languageProvider,
958
+ version
959
+ }) {
960
+ useEffect(() => {
961
+ setCameraLocalization({
962
+ // A non-string `locale` is a legacy cache-busting token, not a language tag.
963
+ locale: typeof locale === 'string' ? locale : undefined,
964
+ translate,
965
+ translations,
966
+ bundles,
967
+ fallbackLocale,
968
+ isRtl,
969
+ // Spread rather than always passing the key: an absent prop must leave a
970
+ // provider bound elsewhere (at startup) alone, while `null` still detaches.
971
+ ...(languageProvider === undefined ? null : {
972
+ languageProvider
973
+ })
974
+ });
975
+ }, [translate, translations, bundles, fallbackLocale, isRtl, locale, languageProvider, version]);
976
+ const value = useCameraLocalization();
977
+ return /*#__PURE__*/React.createElement(CameraLocalizationContext.Provider, {
978
+ value
979
+ }, children);
980
+ }
981
+ export function useCameraLocalization() {
982
+ const [revision, setRevision] = useState(0);
983
+ useEffect(() => {
984
+ return LocalizationManager.subscribe(() => {
985
+ setRevision(tick => tick + 1);
986
+ });
987
+ }, []);
988
+ return useMemo(() => {
989
+ const isRtl = LocalizationManager.getIsRtl();
990
+ return {
991
+ t: (key, ...args) => LocalizationManager.getString(key, ...args),
992
+ /** The host's active language, or `''` when it has not set one. */
993
+ locale: LocalizationManager.getLocale(),
994
+ isRtl,
995
+ direction: isRtl ? 'rtl' : 'ltr',
996
+ textAlign: LocalizationManager.getTextAlign(),
997
+ flexDirection: LocalizationManager.getFlexDirection(),
998
+ rtlStyle: (ltr, rtl) => isRtl ? rtl : ltr,
999
+ writingDirectionStyle: {
1000
+ writingDirection: isRtl ? 'rtl' : 'ltr',
1001
+ textAlign: isRtl ? 'right' : 'left'
1002
+ },
1003
+ layoutDirectionStyle: {
1004
+ direction: isRtl ? 'rtl' : 'ltr'
1005
+ },
1006
+ /** Row/text styles that follow the active language's direction. */
1007
+ styles: isRtl ? rtlDirectionalStyles.rtl : rtlDirectionalStyles.ltr,
1008
+ translations: LocalizationManager.getTranslations()
1009
+ };
1010
+ }, [revision]);
1011
+ }
1012
+ export function useCameraLocalizationContext() {
1013
+ const context = useContext(CameraLocalizationContext);
1014
+ const fallback = useCameraLocalization();
1015
+ return context ?? fallback;
1016
+ }
1017
+
1018
+ /**
1019
+ * Both directions, created up front. `StyleSheet.create` runs once at module
1020
+ * load, so the only way to stay correct across a live language switch is to
1021
+ * build both variants and choose between them at read time.
1022
+ */
1023
+ const rtlDirectionalStyles = {
1024
+ ltr: StyleSheet.create({
1025
+ row: {
1026
+ flexDirection: 'row'
1027
+ },
1028
+ text: {
1029
+ writingDirection: 'ltr',
1030
+ textAlign: 'left'
1031
+ }
1032
+ }),
1033
+ rtl: StyleSheet.create({
1034
+ row: {
1035
+ flexDirection: 'row-reverse'
1036
+ },
1037
+ text: {
1038
+ writingDirection: 'rtl',
1039
+ textAlign: 'right'
1040
+ }
1041
+ })
1042
+ };
1043
+
1044
+ /** Row/text styles for the active language. Prefer the hook inside components. */
1045
+ export function getRtlAwareStyles() {
1046
+ return LocalizationManager.getIsRtl() ? rtlDirectionalStyles.rtl : rtlDirectionalStyles.ltr;
1047
+ }
1048
+
1049
+ /**
1050
+ * Direction-aware styles that re-read the active language on every access.
1051
+ *
1052
+ * Defined with getters rather than a plain object: the language can change at
1053
+ * any time, and a value captured at module load would keep an Arabic UI
1054
+ * left-to-right until the app restarted.
1055
+ */
1056
+ export const rtlAwareStyles = {
1057
+ get row() {
1058
+ return getRtlAwareStyles().row;
1059
+ },
1060
+ get text() {
1061
+ return getRtlAwareStyles().text;
1062
+ }
1063
+ };
1064
+ //# sourceMappingURL=localization.js.map