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,553 @@
1
+ package com.customcamera
2
+
3
+ import android.graphics.Color
4
+ import android.graphics.Rect
5
+ import android.graphics.Typeface
6
+ import android.graphics.drawable.GradientDrawable
7
+ import android.text.Layout
8
+ import android.util.TypedValue
9
+ import android.view.Gravity
10
+ import android.view.KeyEvent
11
+ import android.view.View
12
+ import android.view.ViewGroup
13
+ import android.view.ViewTreeObserver
14
+ import android.view.inputmethod.EditorInfo
15
+ import android.view.inputmethod.InputMethodManager
16
+ import android.widget.EditText
17
+ import android.widget.FrameLayout
18
+ import android.widget.HorizontalScrollView
19
+ import android.widget.ImageView
20
+ import android.widget.LinearLayout
21
+ import android.widget.TextView
22
+
23
+ /**
24
+ * Immutable description of one text overlay's styling. Stamped onto the overlay
25
+ * frame view (via R.id.tag_text_overlay_spec) when the text is applied, so the
26
+ * overlay can be re-opened for editing with its exact style restored, and so
27
+ * per-asset overlay state can be captured/restored across carousel navigation.
28
+ */
29
+ data class TextOverlaySpec(
30
+ val text: String,
31
+ val color: Int,
32
+ val fontIndex: Int,
33
+ val backgroundMode: Int,
34
+ val alignment: Int,
35
+ val textSizeSp: Float = TextEntryController.DEFAULT_TEXT_SIZE_SP
36
+ ) {
37
+ companion object {
38
+ const val DEFAULT_TEXT_SIZE_SP = 30f
39
+ const val BG_NONE = 0
40
+ const val BG_SOLID = 1
41
+ const val BG_TRANSLUCENT = 2
42
+ }
43
+
44
+ }
45
+
46
+ class TextEntryController(
47
+ private val activity: CustomCameraActivity,
48
+ private val host: FrameLayout,
49
+ private val statusBarHeight: () -> Int,
50
+ private val navigationBarHeight: () -> Int,
51
+ private val leftInset: () -> Int,
52
+ private val rightInset: () -> Int,
53
+ private val onDone: (TextOverlaySpec) -> Unit,
54
+ private val onDeleteExisting: () -> Unit,
55
+ private val onDismissed: () -> Unit
56
+ ) {
57
+ companion object {
58
+ const val DEFAULT_TEXT_SIZE_SP = 30f
59
+
60
+ /**
61
+ * The live entry field and the confirmed overlay must wrap at the SAME width, or
62
+ * the background pill re-sizes when the user taps Done. Single source of truth so
63
+ * both the live [EditText] and the confirmed library TextView cap wrapping identically.
64
+ */
65
+ const val TEXT_MAX_WIDTH_FRACTION = 0.86f
66
+
67
+ /** Background-pill geometry shared by the live field and the confirmed overlay. */
68
+ const val PILL_PADDING_H_DP = 12
69
+ const val PILL_PADDING_V_DP = 6
70
+ const val PILL_CORNER_DP = 8
71
+
72
+ /**
73
+ * Pins every text-measurement parameter that diverges between an editable
74
+ * [EditText] (the live preview) and a static TextView (the confirmed overlay), so
75
+ * the confirmed pill wraps and measures byte-identically to what the user saw while
76
+ * editing. The key offender is [Layout.BREAK_STRATEGY_SIMPLE]: an EditText defaults
77
+ * to it while a TextView defaults to [Layout.BREAK_STRATEGY_HIGH_QUALITY], so the
78
+ * same text breaks into different lines and the background pill visibly shrinks on
79
+ * Done. Applied to BOTH views (an EditText is a TextView) so neither can drift from
80
+ * theme defaults. Safe on this module's minSdk 24 (break/hyphenation APIs are 23+).
81
+ */
82
+ fun pinTextMetrics(view: TextView, screenWidthPx: Int) {
83
+ view.maxWidth = (screenWidthPx * TEXT_MAX_WIDTH_FRACTION).toInt()
84
+ view.maxLines = 8
85
+ view.setHorizontallyScrolling(false)
86
+ view.includeFontPadding = true
87
+ view.letterSpacing = 0f
88
+ view.setLineSpacing(0f, 1f)
89
+ view.breakStrategy = Layout.BREAK_STRATEGY_SIMPLE
90
+ view.hyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE
91
+ view.minWidth = 0
92
+ view.minHeight = 0
93
+ view.minimumWidth = 0
94
+ view.minimumHeight = 0
95
+ }
96
+
97
+ /**
98
+ * Two font weights toggled by the "Aa" control - system typefaces only,
99
+ * so no font files ship with the plugin.
100
+ *
101
+ * Index 0 = Bold, index 1 = Normal. A single tap flips between them.
102
+ * The chosen index is persisted in [TextOverlaySpec.fontIndex].
103
+ */
104
+ val FONTS: List<Typeface> = listOf(
105
+ Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD),
106
+ Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL)
107
+ )
108
+
109
+ /** Swatch palette - identical to the palette the old text dialog offered. */
110
+ fun palette(theme: CameraTheme): List<Int> = listOf(
111
+ theme.colors.primaryContrast,
112
+ theme.colors.background,
113
+ Color.RED,
114
+ Color.BLUE,
115
+ Color.GREEN,
116
+ Color.YELLOW,
117
+ Color.parseColor("#FFC0CB"),
118
+ Color.parseColor("#00FF00"),
119
+ Color.parseColor("#008080")
120
+ )
121
+ }
122
+
123
+ private val theme = activity.theme
124
+
125
+ var isShowing = false
126
+ private set
127
+
128
+ // Style state for the session — WhatsApp remembers the last-used style between
129
+ // text entries, so these persist across show()/hide() cycles.
130
+ private var color: Int = theme.colors.primaryContrast
131
+ private var fontIndex = 0
132
+ private var backgroundMode = TextOverlaySpec.BG_NONE
133
+ private var alignment = Gravity.CENTER_HORIZONTAL
134
+ private var textSizeSp = DEFAULT_TEXT_SIZE_SP
135
+
136
+ private var editingExisting = false
137
+
138
+ private var root: FrameLayout? = null
139
+ private var input: EditText? = null
140
+ private var swatchRow: View? = null
141
+ private var alignButton: ImageView? = null
142
+ private var keyboardListener: ViewTreeObserver.OnGlobalLayoutListener? = null
143
+
144
+ /** Opens the entry mode. [existing] pre-fills text + style for re-editing. */
145
+ fun show(existing: TextOverlaySpec? = null) {
146
+ if (isShowing) return
147
+ isShowing = true
148
+ editingExisting = existing != null
149
+ existing?.let {
150
+ color = it.color
151
+ fontIndex = it.fontIndex.coerceIn(FONTS.indices)
152
+ backgroundMode = it.backgroundMode
153
+ alignment = it.alignment
154
+ textSizeSp = it.textSizeSp
155
+ }
156
+ buildUi(existing?.text.orEmpty())
157
+ }
158
+
159
+ fun hide() {
160
+ if (!isShowing) return
161
+ isShowing = false
162
+ keyboardListener?.let {
163
+ host.viewTreeObserver.takeIf { vto -> vto.isAlive }?.removeOnGlobalLayoutListener(it)
164
+ }
165
+ keyboardListener = null
166
+ input?.let { hideKeyboard(it) }
167
+ root?.let { host.removeView(it) }
168
+ root = null
169
+ input = null
170
+ swatchRow = null
171
+ alignButton = null
172
+ onDismissed()
173
+ }
174
+
175
+ private fun currentSpec(): TextOverlaySpec = TextOverlaySpec(
176
+ text = input?.text?.toString()?.trim().orEmpty(),
177
+ color = color,
178
+ fontIndex = fontIndex,
179
+ backgroundMode = backgroundMode,
180
+ alignment = alignment,
181
+ textSizeSp = textSizeSp
182
+ )
183
+
184
+ private fun confirm() {
185
+ val spec = currentSpec()
186
+ if (spec.text.isEmpty()) {
187
+ // Empty on Done: adding nothing = cancel; emptying an existing overlay = delete.
188
+ if (editingExisting) onDeleteExisting()
189
+ hide()
190
+ return
191
+ }
192
+ // Apply BEFORE hide(): the host clears its "which overlay is being edited"
193
+ // state when onDismissed fires, so onDone must run while it is still set.
194
+ onDone(spec)
195
+ hide()
196
+ }
197
+
198
+ private fun buildUi(initialText: String) {
199
+ val screenWidth = activity.resources.displayMetrics.widthPixels
200
+
201
+ val container = FrameLayout(activity).apply {
202
+ setBackgroundColor(theme.componentColor("editor", "textEntryScrim", 0xB3000000.toInt()))
203
+ isClickable = true
204
+ isFocusable = true
205
+ elevation = dp(32).toFloat()
206
+ // Tapping the scrim (outside the text) confirms, like WhatsApp.
207
+ setOnClickListener { confirm() }
208
+ }
209
+ root = container
210
+
211
+ // ── Center: the live-styled text field ──────────────────────────────────
212
+ val field = EditText(activity).apply {
213
+ background = null
214
+ setText(initialText)
215
+ setSelection(initialText.length)
216
+ hint = Localization.getString("typeTextHint", "Type text")
217
+ setHintTextColor(theme.componentColor("editor", "hintText", 0x88FFFFFF.toInt()))
218
+ setTextSize(TypedValue.COMPLEX_UNIT_SP, textSizeSp)
219
+ imeOptions = EditorInfo.IME_ACTION_DONE
220
+ // Multiline while still surfacing a Done action on the IME.
221
+ setRawInputType(
222
+ EditorInfo.TYPE_CLASS_TEXT or
223
+ EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE or
224
+ EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
225
+ )
226
+ setHorizontallyScrolling(false)
227
+ maxLines = 8
228
+ setOnEditorActionListener { _, actionId, _ ->
229
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
230
+ confirm()
231
+ true
232
+ } else false
233
+ }
234
+ // Consume taps so the scrim's confirm click doesn't fire while typing.
235
+ setOnClickListener { }
236
+ // System Back (after the IME dismisses) closes the entry mode without
237
+ // applying — key events are delivered to the focused view, i.e. this field.
238
+ setOnKeyListener { _, keyCode, event ->
239
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
240
+ hide()
241
+ true
242
+ } else false
243
+ }
244
+ }
245
+ input = field
246
+ // Cap wrapping and pin every text-measurement metric so the live pill is the EXACT
247
+ // size the confirmed overlay will be. The confirmed overlay (PhotoEditor
248
+ // addText/editText) is a static TextView; MediaPreviewEditor runs the same
249
+ // pinTextMetrics on it, so both break lines identically and the background never
250
+ // shrinks when the user taps Done.
251
+ pinTextMetrics(field, screenWidth)
252
+ applyLiveStyle()
253
+ container.addView(
254
+ field,
255
+ FrameLayout.LayoutParams(
256
+ ViewGroup.LayoutParams.WRAP_CONTENT,
257
+ ViewGroup.LayoutParams.WRAP_CONTENT,
258
+ Gravity.CENTER
259
+ ).apply {
260
+ // Keep the field visually centered in the region above the keyboard.
261
+ bottomMargin = dp(64)
262
+ }
263
+ )
264
+
265
+ // ── Top action row: Cancel | spacer | Aa · align · bg · Done ────────────
266
+ val actionIconSize = if (screenWidth < dp(360)) dp(34) else dp(40)
267
+ val actionRow = LinearLayout(activity).apply {
268
+ orientation = LinearLayout.HORIZONTAL
269
+ gravity = Gravity.CENTER_VERTICAL
270
+ setPadding(dp(8), dp(6), dp(8), dp(6))
271
+ }
272
+
273
+ val cancelBtn = actionIcon(R.drawable.ic_close, actionIconSize) { hide() }
274
+ cancelBtn.bindDescription("textCancel", "Cancel text")
275
+ actionRow.addView(cancelBtn, actionParams(actionIconSize))
276
+ actionRow.addView(View(activity), LinearLayout.LayoutParams(0, 1, 1f))
277
+
278
+ val fontBtn = TextView(activity).apply {
279
+ text = Localization.getString("textFontSample", "Aa")
280
+ gravity = Gravity.CENTER
281
+ includeFontPadding = false
282
+ setTextColor(theme.colors.primaryContrast)
283
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, actionIconSize * 0.48f)
284
+ typeface = FONTS[fontIndex]
285
+ bindDescription("textFont", "Change font")
286
+ setOnClickListener {
287
+ fontIndex = if (fontIndex == 0) 1 else 0
288
+ typeface = FONTS[fontIndex]
289
+ applyLiveStyle()
290
+ }
291
+ }
292
+ actionRow.addView(fontBtn, actionParams(actionIconSize))
293
+
294
+ val alignBtn = actionIcon(alignBuiltinIconRes(), actionIconSize) {
295
+ alignment = when (alignment) {
296
+ Gravity.START -> Gravity.CENTER_HORIZONTAL
297
+ Gravity.CENTER_HORIZONTAL -> Gravity.END
298
+ else -> Gravity.START
299
+ }
300
+ alignButton?.let { applyAlignIcon(it) }
301
+ applyLiveStyle()
302
+ }
303
+ alignBtn.bindDescription("textAlignment", "Change text alignment")
304
+ alignButton = alignBtn
305
+ actionRow.addView(alignBtn, actionParams(actionIconSize))
306
+
307
+ val bgBtn = actionIcon(R.drawable.ic_text_bg, actionIconSize) {
308
+ backgroundMode = (backgroundMode + 1) % 3
309
+ applyLiveStyle()
310
+ }
311
+ bgBtn.bindDescription("textBackground", "Change text background")
312
+ actionRow.addView(bgBtn, actionParams(actionIconSize))
313
+
314
+ val doneBtn = actionIcon(R.drawable.ic_done, actionIconSize) { confirm() }
315
+ doneBtn.bindDescription("textDone", "Apply text")
316
+ actionRow.addView(doneBtn, actionParams(actionIconSize))
317
+
318
+ container.addView(
319
+ actionRow,
320
+ FrameLayout.LayoutParams(
321
+ ViewGroup.LayoutParams.MATCH_PARENT,
322
+ ViewGroup.LayoutParams.WRAP_CONTENT,
323
+ Gravity.TOP
324
+ ).apply {
325
+ topMargin = statusBarHeight() + dp(8)
326
+ marginStart = leftInset() + dp(8)
327
+ marginEnd = rightInset() + dp(8)
328
+ }
329
+ )
330
+
331
+ // ── Bottom: color swatches, repositioned above the keyboard ─────────────
332
+ val swatchSize = if (screenWidth < dp(360)) dp(30) else dp(34)
333
+ val swatches = LinearLayout(activity).apply {
334
+ orientation = LinearLayout.HORIZONTAL
335
+ gravity = Gravity.CENTER
336
+ setPadding(dp(8), dp(6), dp(8), dp(6))
337
+ }
338
+ val colors = palette(theme)
339
+ val selectedColor = color
340
+ val swatchViews = colors.map { c ->
341
+ View(activity).apply {
342
+ background = GradientDrawable().apply {
343
+ shape = GradientDrawable.OVAL
344
+ setColor(c)
345
+ setStroke(
346
+ if (c == selectedColor) dp(3) else dp(1),
347
+ if (c == selectedColor) theme.colors.primaryContrast
348
+ else theme.componentColor("editor", "swatchBorder", 0x55FFFFFF)
349
+ )
350
+ }
351
+ }
352
+ }
353
+ swatchViews.forEachIndexed { index, swatch ->
354
+ swatches.addView(swatch, LinearLayout.LayoutParams(swatchSize, swatchSize).apply {
355
+ setMargins(dp(6), dp(6), dp(6), dp(6))
356
+ })
357
+ swatch.setOnClickListener {
358
+ color = colors[index]
359
+ swatchViews.forEachIndexed { i, v ->
360
+ (v.background as GradientDrawable).setStroke(
361
+ if (i == index) dp(3) else dp(1),
362
+ if (i == index) theme.colors.primaryContrast
363
+ else theme.componentColor("editor", "swatchBorder", 0x55FFFFFF)
364
+ )
365
+ }
366
+ applyLiveStyle()
367
+ }
368
+ }
369
+ val swatchScroll = HorizontalScrollView(activity).apply {
370
+ isHorizontalScrollBarEnabled = false
371
+ addView(swatches)
372
+ }
373
+ swatchRow = swatchScroll
374
+ container.addView(
375
+ swatchScroll,
376
+ FrameLayout.LayoutParams(
377
+ ViewGroup.LayoutParams.WRAP_CONTENT,
378
+ ViewGroup.LayoutParams.WRAP_CONTENT,
379
+ Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
380
+ ).apply {
381
+ bottomMargin = navigationBarHeight() + dp(12)
382
+ }
383
+ )
384
+
385
+ // System Back closes the entry mode without applying.
386
+ container.isFocusableInTouchMode = true
387
+ container.setOnKeyListener { _, keyCode, event ->
388
+ if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
389
+ hide()
390
+ true
391
+ } else false
392
+ }
393
+
394
+ host.addView(
395
+ container,
396
+ FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
397
+ )
398
+
399
+ trackKeyboard(container)
400
+
401
+ field.requestFocus()
402
+ field.post {
403
+ (activity.getSystemService(android.content.Context.INPUT_METHOD_SERVICE) as? InputMethodManager)
404
+ ?.showSoftInput(field, InputMethodManager.SHOW_IMPLICIT)
405
+ }
406
+ }
407
+
408
+ /**
409
+ * Restyles the live EditText from the current style state so the preview always
410
+ * matches the final overlay exactly (same color/typeface/gravity/background the
411
+ * TextStyleBuilder applies at Done).
412
+ */
413
+ private fun applyLiveStyle() {
414
+ val field = input ?: return
415
+ field.typeface = FONTS[fontIndex]
416
+ field.gravity = alignment or Gravity.CENTER_VERTICAL
417
+ field.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSizeSp)
418
+ when (backgroundMode) {
419
+ TextOverlaySpec.BG_SOLID -> {
420
+ field.setTextColor(contrastOn(color))
421
+ field.background = backgroundPill(color, translucent = false)
422
+ field.setPadding(dp(PILL_PADDING_H_DP), dp(PILL_PADDING_V_DP), dp(PILL_PADDING_H_DP), dp(PILL_PADDING_V_DP))
423
+ }
424
+ TextOverlaySpec.BG_TRANSLUCENT -> {
425
+ field.setTextColor(theme.colors.primaryContrast)
426
+ field.background = backgroundPill(color, translucent = true)
427
+ field.setPadding(dp(PILL_PADDING_H_DP), dp(PILL_PADDING_V_DP), dp(PILL_PADDING_H_DP), dp(PILL_PADDING_V_DP))
428
+ }
429
+ else -> {
430
+ field.setTextColor(color)
431
+ field.background = null
432
+ field.setPadding(0, 0, 0, 0)
433
+ }
434
+ }
435
+ }
436
+
437
+ /**
438
+ * Tracks the soft keyboard height via the visible display frame (the activity
439
+ * runs fullscreen without adjustResize, so IME window insets never reach the
440
+ * layout) and keeps the swatch row pinned just above the keyboard.
441
+ */
442
+ private fun trackKeyboard(container: View) {
443
+ val listener = ViewTreeObserver.OnGlobalLayoutListener {
444
+ val visible = Rect()
445
+ container.getWindowVisibleDisplayFrame(visible)
446
+ val keyboardHeight = (container.rootView.height - visible.bottom).coerceAtLeast(0)
447
+ val row = swatchRow ?: return@OnGlobalLayoutListener
448
+ val lp = row.layoutParams as? FrameLayout.LayoutParams ?: return@OnGlobalLayoutListener
449
+ val target = if (keyboardHeight > dp(80)) {
450
+ keyboardHeight + dp(8)
451
+ } else {
452
+ navigationBarHeight() + dp(12)
453
+ }
454
+ if (lp.bottomMargin != target) {
455
+ lp.bottomMargin = target
456
+ row.layoutParams = lp
457
+ }
458
+ }
459
+ container.viewTreeObserver.addOnGlobalLayoutListener(listener)
460
+ keyboardListener = listener
461
+ }
462
+
463
+ // ── Small helpers (local mirrors of MediaPreviewEditor's private utilities) ──
464
+
465
+ /**
466
+ * Built-in drawable id → white-label icon name, so this screen's icons honour
467
+ * the same per-icon `resourceName` / `tintColor` config as the rest of the
468
+ * editor. Mirrors `MediaPreviewEditor.iconNames` for the drawables used here.
469
+ */
470
+ private val iconNames: Map<Int, String> = mapOf(
471
+ R.drawable.ic_close to "close",
472
+ R.drawable.ic_text_bg to "text_bg",
473
+ R.drawable.ic_text_align_left to "text_align_left",
474
+ R.drawable.ic_text_align_center to "text_align_center",
475
+ R.drawable.ic_text_align_right to "text_align_right",
476
+ R.drawable.ic_done to "done"
477
+ )
478
+
479
+ /**
480
+ * Sets [builtinRes] through the white-label config (host SVG → host
481
+ * `resourceName` → built-in) and tints it: a configured per-icon / global
482
+ * tint wins; a host-provided SVG keeps its OWN colours (a solid filter would
483
+ * flatten it); a plain glyph falls back to the dark-editor contrast colour so
484
+ * it stays visible. Mirrors `MediaPreviewEditor`'s resolution for this screen.
485
+ */
486
+ private fun ImageView.setThemedIcon(builtinRes: Int) {
487
+ val name = iconNames[builtinRes]
488
+ val drawable = theme.config.iconDrawable(activity, name ?: "", builtinRes)
489
+ setImageDrawable(drawable)
490
+ val tint =
491
+ if (name != null) {
492
+ theme.config.iconTintFor(name, drawable, theme.colors.primaryContrast)
493
+ } else {
494
+ theme.colors.primaryContrast
495
+ }
496
+ tint?.let { setColorFilter(it) } ?: clearColorFilter()
497
+ }
498
+
499
+ private fun alignBuiltinIconRes(): Int = when (alignment) {
500
+ Gravity.START -> R.drawable.ic_text_align_left
501
+ Gravity.END -> R.drawable.ic_text_align_right
502
+ else -> R.drawable.ic_text_align_center
503
+ }
504
+
505
+ /**
506
+ * Repaint the alignment button for the current alignment. Each of the three
507
+ * alignments is its own configurable icon, so the tint is re-resolved along
508
+ * with the drawable rather than only on first build.
509
+ */
510
+ private fun applyAlignIcon(view: ImageView) {
511
+ view.setThemedIcon(alignBuiltinIconRes())
512
+ }
513
+
514
+ private fun actionIcon(drawableRes: Int, size: Int, onClick: () -> Unit): ImageView =
515
+ ImageView(activity).apply {
516
+ setThemedIcon(drawableRes)
517
+ scaleType = ImageView.ScaleType.CENTER
518
+ setPadding(dp(4), dp(4), dp(4), dp(4))
519
+ setOnClickListener { onClick() }
520
+ }
521
+
522
+ private fun actionParams(size: Int): LinearLayout.LayoutParams =
523
+ LinearLayout.LayoutParams(size + dp(8), size + dp(8)).apply {
524
+ setMargins(dp(4), 0, dp(4), 0)
525
+ }
526
+
527
+ private fun View.bindDescription(key: String, default: String) {
528
+ contentDescription = Localization.getString(key, default)
529
+ }
530
+
531
+ private fun backgroundPill(base: Int, translucent: Boolean): GradientDrawable =
532
+ GradientDrawable().apply {
533
+ cornerRadius = dp(PILL_CORNER_DP).toFloat()
534
+ setColor(if (translucent) (base and 0x00FFFFFF) or 0x66000000 else base)
535
+ }
536
+
537
+ /** Black or white, whichever contrasts against [background] (WhatsApp behaviour). */
538
+ private fun contrastOn(background: Int): Int {
539
+ val r = Color.red(background)
540
+ val g = Color.green(background)
541
+ val b = Color.blue(background)
542
+ val luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255.0
543
+ return if (luminance > 0.6) Color.BLACK else Color.WHITE
544
+ }
545
+
546
+ private fun hideKeyboard(view: View) {
547
+ (activity.getSystemService(android.content.Context.INPUT_METHOD_SERVICE) as? InputMethodManager)
548
+ ?.hideSoftInputFromWindow(view.windowToken, 0)
549
+ }
550
+
551
+ private fun dp(value: Int): Int =
552
+ (value * activity.resources.displayMetrics.density).toInt()
553
+ }