@ethora/chat-component-rn 26.10.4 → 26.10.6

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 (451) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +15 -0
  3. package/app.plugin.js +2 -0
  4. package/lib/commonjs/assets/icons.js +2 -2
  5. package/lib/commonjs/assets/icons.js.map +1 -1
  6. package/lib/commonjs/components/MainComponents/AlbumGrid.js +152 -0
  7. package/lib/commonjs/components/MainComponents/AlbumGrid.js.map +1 -0
  8. package/lib/commonjs/components/MainComponents/ChatRoom.js +2 -2
  9. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  10. package/lib/commonjs/components/MainComponents/MediaMessage.js +199 -123
  11. package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
  12. package/lib/commonjs/components/MainComponents/MediaUploadOverlay.js +109 -0
  13. package/lib/commonjs/components/MainComponents/MediaUploadOverlay.js.map +1 -0
  14. package/lib/commonjs/components/MessageBubble/MediaCaption.js +51 -0
  15. package/lib/commonjs/components/MessageBubble/MediaCaption.js.map +1 -0
  16. package/lib/commonjs/components/MessageBubble/Message.js +40 -1
  17. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  18. package/lib/commonjs/components/MessageBubble/MessageInteractions.js +2 -1
  19. package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
  20. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +75 -0
  21. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  22. package/lib/commonjs/components/RoomComponents/LastMessageItem.js +20 -4
  23. package/lib/commonjs/components/RoomComponents/LastMessageItem.js.map +1 -1
  24. package/lib/commonjs/components/RoomComponents/styled/LastAudioMessage.js +3 -2
  25. package/lib/commonjs/components/RoomComponents/styled/LastAudioMessage.js.map +1 -1
  26. package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js +3 -2
  27. package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
  28. package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js +3 -2
  29. package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
  30. package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js +3 -2
  31. package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
  32. package/lib/commonjs/components/Thread/ThreadWrapper.js +3 -2
  33. package/lib/commonjs/components/Thread/ThreadWrapper.js.map +1 -1
  34. package/lib/commonjs/components/VideoCalls/ActiveCallBar.js +61 -16
  35. package/lib/commonjs/components/VideoCalls/ActiveCallBar.js.map +1 -1
  36. package/lib/commonjs/components/VideoCalls/CallIcons.js +41 -16
  37. package/lib/commonjs/components/VideoCalls/CallIcons.js.map +1 -1
  38. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js +183 -9
  39. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js.map +1 -1
  40. package/lib/commonjs/components/VideoCalls/VideoCallSession.js +40 -15
  41. package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -1
  42. package/lib/commonjs/components/VideoCalls/callSessionController.js +49 -26
  43. package/lib/commonjs/components/VideoCalls/callSessionController.js.map +1 -1
  44. package/lib/commonjs/components/VideoCalls/callUiStore.js +33 -4
  45. package/lib/commonjs/components/VideoCalls/callUiStore.js.map +1 -1
  46. package/lib/commonjs/components/VideoCalls/livekitRuntime.js +9 -1
  47. package/lib/commonjs/components/VideoCalls/livekitRuntime.js.map +1 -1
  48. package/lib/commonjs/components/VideoCalls/useCallKeep.js +197 -28
  49. package/lib/commonjs/components/VideoCalls/useCallKeep.js.map +1 -1
  50. package/lib/commonjs/components/VideoCalls/useOngoingCallNotification.js +88 -0
  51. package/lib/commonjs/components/VideoCalls/useOngoingCallNotification.js.map +1 -0
  52. package/lib/commonjs/components/VideoCalls/usePipTile.js +232 -0
  53. package/lib/commonjs/components/VideoCalls/usePipTile.js.map +1 -0
  54. package/lib/commonjs/components/styled/MediaFilePreview.js +60 -47
  55. package/lib/commonjs/components/styled/MediaFilePreview.js.map +1 -1
  56. package/lib/commonjs/components/styled/MessageImage.js +16 -6
  57. package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
  58. package/lib/commonjs/components/styled/SendInput.js +99 -68
  59. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  60. package/lib/commonjs/components/styled/VideoMessage.js +24 -10
  61. package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
  62. package/lib/commonjs/context/xmppProvider.js +46 -0
  63. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  64. package/lib/commonjs/e2ee/fileEnvelope.js +6 -0
  65. package/lib/commonjs/e2ee/fileEnvelope.js.map +1 -1
  66. package/lib/commonjs/e2ee/sealedBody.js +32 -2
  67. package/lib/commonjs/e2ee/sealedBody.js.map +1 -1
  68. package/lib/commonjs/helpers/albumLayout.js +150 -0
  69. package/lib/commonjs/helpers/albumLayout.js.map +1 -0
  70. package/lib/commonjs/helpers/attachments.js +255 -0
  71. package/lib/commonjs/helpers/attachments.js.map +1 -0
  72. package/lib/commonjs/helpers/caption.js +214 -0
  73. package/lib/commonjs/helpers/caption.js.map +1 -0
  74. package/lib/commonjs/helpers/createMainMessageForThread.js +5 -1
  75. package/lib/commonjs/helpers/createMainMessageForThread.js.map +1 -1
  76. package/lib/commonjs/helpers/createMessageFromXml.js +19 -5
  77. package/lib/commonjs/helpers/createMessageFromXml.js.map +1 -1
  78. package/lib/commonjs/helpers/fileKind.js +40 -0
  79. package/lib/commonjs/helpers/fileKind.js.map +1 -0
  80. package/lib/commonjs/helpers/getDataFromXml.js +6 -1
  81. package/lib/commonjs/helpers/getDataFromXml.js.map +1 -1
  82. package/lib/commonjs/helpers/mapWithConcurrency.js +41 -0
  83. package/lib/commonjs/helpers/mapWithConcurrency.js.map +1 -0
  84. package/lib/commonjs/helpers/mediaLimits.js +33 -0
  85. package/lib/commonjs/helpers/mediaLimits.js.map +1 -0
  86. package/lib/commonjs/helpers/mediaSendRetry.js +64 -0
  87. package/lib/commonjs/helpers/mediaSendRetry.js.map +1 -0
  88. package/lib/commonjs/helpers/mediaWireData.js +62 -0
  89. package/lib/commonjs/helpers/mediaWireData.js.map +1 -0
  90. package/lib/commonjs/helpers/mentionSpans.js +19 -0
  91. package/lib/commonjs/helpers/mentionSpans.js.map +1 -0
  92. package/lib/commonjs/helpers/mimeToExtension.js +45 -0
  93. package/lib/commonjs/helpers/mimeToExtension.js.map +1 -1
  94. package/lib/commonjs/helpers/readReceipts.js +173 -0
  95. package/lib/commonjs/helpers/readReceipts.js.map +1 -0
  96. package/lib/commonjs/helpers/repairFilenameEncoding.js +79 -0
  97. package/lib/commonjs/helpers/repairFilenameEncoding.js.map +1 -0
  98. package/lib/commonjs/helpers/safeJson.js +18 -0
  99. package/lib/commonjs/helpers/safeJson.js.map +1 -0
  100. package/lib/commonjs/helpers/updateMessagesTillLast.js +3 -1
  101. package/lib/commonjs/helpers/updateMessagesTillLast.js.map +1 -1
  102. package/lib/commonjs/hooks/useSendMessage.js +384 -193
  103. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  104. package/lib/commonjs/i18n/strings.js +144 -0
  105. package/lib/commonjs/i18n/strings.js.map +1 -1
  106. package/lib/commonjs/main.js.map +1 -1
  107. package/lib/commonjs/networking/api-requests/auth.api.js +62 -3
  108. package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
  109. package/lib/commonjs/networking/stanzaHandlers.js +100 -3
  110. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  111. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +4 -2
  112. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  113. package/lib/commonjs/networking/xmpp/sendDisplayedMarker.xmpp.js +28 -0
  114. package/lib/commonjs/networking/xmpp/sendDisplayedMarker.xmpp.js.map +1 -0
  115. package/lib/commonjs/networking/xmpp/sendMediaMessage.xmpp.js +53 -2
  116. package/lib/commonjs/networking/xmpp/sendMediaMessage.xmpp.js.map +1 -1
  117. package/lib/commonjs/networking/xmpp/sendReceivedReceipt.xmpp.js +28 -0
  118. package/lib/commonjs/networking/xmpp/sendReceivedReceipt.xmpp.js.map +1 -0
  119. package/lib/commonjs/networking/xmppClient.js +64 -0
  120. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  121. package/lib/commonjs/roomStore/persistence.js +78 -5
  122. package/lib/commonjs/roomStore/persistence.js.map +1 -1
  123. package/lib/commonjs/roomStore/roomHeapSlice.js +4 -0
  124. package/lib/commonjs/roomStore/roomHeapSlice.js.map +1 -1
  125. package/lib/commonjs/roomStore/roomsSlice.js +114 -1
  126. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  127. package/lib/commonjs/types/models/attachment.model.js +2 -0
  128. package/lib/commonjs/types/models/attachment.model.js.map +1 -0
  129. package/lib/commonjs/version.js +1 -1
  130. package/lib/module/assets/icons.js +1 -1
  131. package/lib/module/assets/icons.js.map +1 -1
  132. package/lib/module/components/MainComponents/AlbumGrid.js +146 -0
  133. package/lib/module/components/MainComponents/AlbumGrid.js.map +1 -0
  134. package/lib/module/components/MainComponents/ChatRoom.js +2 -2
  135. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  136. package/lib/module/components/MainComponents/MediaMessage.js +200 -124
  137. package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
  138. package/lib/module/components/MainComponents/MediaUploadOverlay.js +104 -0
  139. package/lib/module/components/MainComponents/MediaUploadOverlay.js.map +1 -0
  140. package/lib/module/components/MessageBubble/MediaCaption.js +46 -0
  141. package/lib/module/components/MessageBubble/MediaCaption.js.map +1 -0
  142. package/lib/module/components/MessageBubble/Message.js +44 -5
  143. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  144. package/lib/module/components/MessageBubble/MessageInteractions.js +2 -1
  145. package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
  146. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +75 -0
  147. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  148. package/lib/module/components/RoomComponents/LastMessageItem.js +20 -4
  149. package/lib/module/components/RoomComponents/LastMessageItem.js.map +1 -1
  150. package/lib/module/components/RoomComponents/styled/LastAudioMessage.js +3 -2
  151. package/lib/module/components/RoomComponents/styled/LastAudioMessage.js.map +1 -1
  152. package/lib/module/components/RoomComponents/styled/LastMessageFile.js +3 -2
  153. package/lib/module/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
  154. package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js +3 -2
  155. package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
  156. package/lib/module/components/RoomComponents/styled/LastMessageVideo.js +3 -2
  157. package/lib/module/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
  158. package/lib/module/components/Thread/ThreadWrapper.js +3 -2
  159. package/lib/module/components/Thread/ThreadWrapper.js.map +1 -1
  160. package/lib/module/components/VideoCalls/ActiveCallBar.js +63 -18
  161. package/lib/module/components/VideoCalls/ActiveCallBar.js.map +1 -1
  162. package/lib/module/components/VideoCalls/CallIcons.js +38 -15
  163. package/lib/module/components/VideoCalls/CallIcons.js.map +1 -1
  164. package/lib/module/components/VideoCalls/VideoCallOverlay.js +185 -11
  165. package/lib/module/components/VideoCalls/VideoCallOverlay.js.map +1 -1
  166. package/lib/module/components/VideoCalls/VideoCallSession.js +41 -16
  167. package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -1
  168. package/lib/module/components/VideoCalls/callSessionController.js +46 -24
  169. package/lib/module/components/VideoCalls/callSessionController.js.map +1 -1
  170. package/lib/module/components/VideoCalls/callUiStore.js +30 -3
  171. package/lib/module/components/VideoCalls/callUiStore.js.map +1 -1
  172. package/lib/module/components/VideoCalls/livekitRuntime.js +9 -1
  173. package/lib/module/components/VideoCalls/livekitRuntime.js.map +1 -1
  174. package/lib/module/components/VideoCalls/useCallKeep.js +198 -29
  175. package/lib/module/components/VideoCalls/useCallKeep.js.map +1 -1
  176. package/lib/module/components/VideoCalls/useOngoingCallNotification.js +84 -0
  177. package/lib/module/components/VideoCalls/useOngoingCallNotification.js.map +1 -0
  178. package/lib/module/components/VideoCalls/usePipTile.js +228 -0
  179. package/lib/module/components/VideoCalls/usePipTile.js.map +1 -0
  180. package/lib/module/components/styled/MediaFilePreview.js +61 -48
  181. package/lib/module/components/styled/MediaFilePreview.js.map +1 -1
  182. package/lib/module/components/styled/MessageImage.js +16 -6
  183. package/lib/module/components/styled/MessageImage.js.map +1 -1
  184. package/lib/module/components/styled/SendInput.js +99 -68
  185. package/lib/module/components/styled/SendInput.js.map +1 -1
  186. package/lib/module/components/styled/VideoMessage.js +24 -10
  187. package/lib/module/components/styled/VideoMessage.js.map +1 -1
  188. package/lib/module/context/xmppProvider.js +46 -0
  189. package/lib/module/context/xmppProvider.js.map +1 -1
  190. package/lib/module/e2ee/fileEnvelope.js +1 -1
  191. package/lib/module/e2ee/fileEnvelope.js.map +1 -1
  192. package/lib/module/e2ee/sealedBody.js +32 -2
  193. package/lib/module/e2ee/sealedBody.js.map +1 -1
  194. package/lib/module/helpers/albumLayout.js +143 -0
  195. package/lib/module/helpers/albumLayout.js.map +1 -0
  196. package/lib/module/helpers/attachments.js +245 -0
  197. package/lib/module/helpers/attachments.js.map +1 -0
  198. package/lib/module/helpers/caption.js +207 -0
  199. package/lib/module/helpers/caption.js.map +1 -0
  200. package/lib/module/helpers/createMainMessageForThread.js +5 -1
  201. package/lib/module/helpers/createMainMessageForThread.js.map +1 -1
  202. package/lib/module/helpers/createMessageFromXml.js +20 -6
  203. package/lib/module/helpers/createMessageFromXml.js.map +1 -1
  204. package/lib/module/helpers/fileKind.js +34 -0
  205. package/lib/module/helpers/fileKind.js.map +1 -0
  206. package/lib/module/helpers/getDataFromXml.js +6 -1
  207. package/lib/module/helpers/getDataFromXml.js.map +1 -1
  208. package/lib/module/helpers/mapWithConcurrency.js +37 -0
  209. package/lib/module/helpers/mapWithConcurrency.js.map +1 -0
  210. package/lib/module/helpers/mediaLimits.js +27 -0
  211. package/lib/module/helpers/mediaLimits.js.map +1 -0
  212. package/lib/module/helpers/mediaSendRetry.js +55 -0
  213. package/lib/module/helpers/mediaSendRetry.js.map +1 -0
  214. package/lib/module/helpers/mediaWireData.js +58 -0
  215. package/lib/module/helpers/mediaWireData.js.map +1 -0
  216. package/lib/module/helpers/mentionSpans.js +14 -0
  217. package/lib/module/helpers/mentionSpans.js.map +1 -0
  218. package/lib/module/helpers/mimeToExtension.js +43 -0
  219. package/lib/module/helpers/mimeToExtension.js.map +1 -1
  220. package/lib/module/helpers/readReceipts.js +160 -0
  221. package/lib/module/helpers/readReceipts.js.map +1 -0
  222. package/lib/module/helpers/repairFilenameEncoding.js +74 -0
  223. package/lib/module/helpers/repairFilenameEncoding.js.map +1 -0
  224. package/lib/module/helpers/safeJson.js +13 -0
  225. package/lib/module/helpers/safeJson.js.map +1 -0
  226. package/lib/module/helpers/updateMessagesTillLast.js +3 -1
  227. package/lib/module/helpers/updateMessagesTillLast.js.map +1 -1
  228. package/lib/module/hooks/useSendMessage.js +387 -195
  229. package/lib/module/hooks/useSendMessage.js.map +1 -1
  230. package/lib/module/i18n/strings.js +144 -0
  231. package/lib/module/i18n/strings.js.map +1 -1
  232. package/lib/module/main.js.map +1 -1
  233. package/lib/module/networking/api-requests/auth.api.js +62 -3
  234. package/lib/module/networking/api-requests/auth.api.js.map +1 -1
  235. package/lib/module/networking/stanzaHandlers.js +97 -4
  236. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  237. package/lib/module/networking/xmpp/handleStanzas.xmpp.js +5 -3
  238. package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  239. package/lib/module/networking/xmpp/sendDisplayedMarker.xmpp.js +25 -0
  240. package/lib/module/networking/xmpp/sendDisplayedMarker.xmpp.js.map +1 -0
  241. package/lib/module/networking/xmpp/sendMediaMessage.xmpp.js +53 -2
  242. package/lib/module/networking/xmpp/sendMediaMessage.xmpp.js.map +1 -1
  243. package/lib/module/networking/xmpp/sendReceivedReceipt.xmpp.js +25 -0
  244. package/lib/module/networking/xmpp/sendReceivedReceipt.xmpp.js.map +1 -0
  245. package/lib/module/networking/xmppClient.js +64 -0
  246. package/lib/module/networking/xmppClient.js.map +1 -1
  247. package/lib/module/roomStore/persistence.js +78 -5
  248. package/lib/module/roomStore/persistence.js.map +1 -1
  249. package/lib/module/roomStore/roomHeapSlice.js +4 -0
  250. package/lib/module/roomStore/roomHeapSlice.js.map +1 -1
  251. package/lib/module/roomStore/roomsSlice.js +109 -0
  252. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  253. package/lib/module/types/models/attachment.model.js +2 -0
  254. package/lib/module/types/models/attachment.model.js.map +1 -0
  255. package/lib/module/version.js +1 -1
  256. package/lib/typescript/assets/icons.d.ts +6 -1
  257. package/lib/typescript/assets/icons.d.ts.map +1 -1
  258. package/lib/typescript/components/MainComponents/AlbumGrid.d.ts +21 -0
  259. package/lib/typescript/components/MainComponents/AlbumGrid.d.ts.map +1 -0
  260. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  261. package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
  262. package/lib/typescript/components/MainComponents/MediaUploadOverlay.d.ts +17 -0
  263. package/lib/typescript/components/MainComponents/MediaUploadOverlay.d.ts.map +1 -0
  264. package/lib/typescript/components/MessageBubble/MediaCaption.d.ts +12 -0
  265. package/lib/typescript/components/MessageBubble/MediaCaption.d.ts.map +1 -0
  266. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  267. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
  268. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
  269. package/lib/typescript/components/RoomComponents/LastMessageItem.d.ts.map +1 -1
  270. package/lib/typescript/components/RoomComponents/styled/LastAudioMessage.d.ts +2 -0
  271. package/lib/typescript/components/RoomComponents/styled/LastAudioMessage.d.ts.map +1 -1
  272. package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts +2 -0
  273. package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts.map +1 -1
  274. package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts +2 -0
  275. package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts.map +1 -1
  276. package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts +2 -0
  277. package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts.map +1 -1
  278. package/lib/typescript/components/Thread/ThreadWrapper.d.ts.map +1 -1
  279. package/lib/typescript/components/VideoCalls/ActiveCallBar.d.ts +9 -3
  280. package/lib/typescript/components/VideoCalls/ActiveCallBar.d.ts.map +1 -1
  281. package/lib/typescript/components/VideoCalls/CallIcons.d.ts +9 -0
  282. package/lib/typescript/components/VideoCalls/CallIcons.d.ts.map +1 -1
  283. package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts.map +1 -1
  284. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -1
  285. package/lib/typescript/components/VideoCalls/callSessionController.d.ts +7 -0
  286. package/lib/typescript/components/VideoCalls/callSessionController.d.ts.map +1 -1
  287. package/lib/typescript/components/VideoCalls/callUiStore.d.ts +13 -0
  288. package/lib/typescript/components/VideoCalls/callUiStore.d.ts.map +1 -1
  289. package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts +5 -0
  290. package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts.map +1 -1
  291. package/lib/typescript/components/VideoCalls/useCallKeep.d.ts +12 -0
  292. package/lib/typescript/components/VideoCalls/useCallKeep.d.ts.map +1 -1
  293. package/lib/typescript/components/VideoCalls/useOngoingCallNotification.d.ts +10 -0
  294. package/lib/typescript/components/VideoCalls/useOngoingCallNotification.d.ts.map +1 -0
  295. package/lib/typescript/components/VideoCalls/usePipTile.d.ts +46 -0
  296. package/lib/typescript/components/VideoCalls/usePipTile.d.ts.map +1 -0
  297. package/lib/typescript/components/styled/MediaFilePreview.d.ts.map +1 -1
  298. package/lib/typescript/components/styled/MessageImage.d.ts +10 -0
  299. package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
  300. package/lib/typescript/components/styled/SendInput.d.ts +7 -1
  301. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  302. package/lib/typescript/components/styled/VideoMessage.d.ts +7 -0
  303. package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
  304. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  305. package/lib/typescript/e2ee/fileEnvelope.d.ts +1 -1
  306. package/lib/typescript/e2ee/fileEnvelope.d.ts.map +1 -1
  307. package/lib/typescript/e2ee/sealedBody.d.ts +16 -0
  308. package/lib/typescript/e2ee/sealedBody.d.ts.map +1 -1
  309. package/lib/typescript/helpers/albumLayout.d.ts +66 -0
  310. package/lib/typescript/helpers/albumLayout.d.ts.map +1 -0
  311. package/lib/typescript/helpers/attachments.d.ts +55 -0
  312. package/lib/typescript/helpers/attachments.d.ts.map +1 -0
  313. package/lib/typescript/helpers/caption.d.ts +64 -0
  314. package/lib/typescript/helpers/caption.d.ts.map +1 -0
  315. package/lib/typescript/helpers/createMainMessageForThread.d.ts.map +1 -1
  316. package/lib/typescript/helpers/createMessageFromXml.d.ts.map +1 -1
  317. package/lib/typescript/helpers/fileKind.d.ts +20 -0
  318. package/lib/typescript/helpers/fileKind.d.ts.map +1 -0
  319. package/lib/typescript/helpers/getDataFromXml.d.ts.map +1 -1
  320. package/lib/typescript/helpers/mapWithConcurrency.d.ts +9 -0
  321. package/lib/typescript/helpers/mapWithConcurrency.d.ts.map +1 -0
  322. package/lib/typescript/helpers/mediaLimits.d.ts +13 -0
  323. package/lib/typescript/helpers/mediaLimits.d.ts.map +1 -0
  324. package/lib/typescript/helpers/mediaSendRetry.d.ts +26 -0
  325. package/lib/typescript/helpers/mediaSendRetry.d.ts.map +1 -0
  326. package/lib/typescript/helpers/mediaWireData.d.ts +16 -0
  327. package/lib/typescript/helpers/mediaWireData.d.ts.map +1 -0
  328. package/lib/typescript/helpers/mentionSpans.d.ts +8 -0
  329. package/lib/typescript/helpers/mentionSpans.d.ts.map +1 -0
  330. package/lib/typescript/helpers/mimeToExtension.d.ts +7 -0
  331. package/lib/typescript/helpers/mimeToExtension.d.ts.map +1 -1
  332. package/lib/typescript/helpers/readReceipts.d.ts +82 -0
  333. package/lib/typescript/helpers/readReceipts.d.ts.map +1 -0
  334. package/lib/typescript/helpers/repairFilenameEncoding.d.ts +12 -0
  335. package/lib/typescript/helpers/repairFilenameEncoding.d.ts.map +1 -0
  336. package/lib/typescript/helpers/safeJson.d.ts +2 -0
  337. package/lib/typescript/helpers/safeJson.d.ts.map +1 -0
  338. package/lib/typescript/helpers/updateMessagesTillLast.d.ts.map +1 -1
  339. package/lib/typescript/hooks/useSendMessage.d.ts +2 -1
  340. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  341. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  342. package/lib/typescript/main.d.ts +1 -1
  343. package/lib/typescript/main.d.ts.map +1 -1
  344. package/lib/typescript/networking/api-requests/auth.api.d.ts +2 -0
  345. package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
  346. package/lib/typescript/networking/stanzaHandlers.d.ts +7 -3
  347. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  348. package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
  349. package/lib/typescript/networking/xmpp/sendDisplayedMarker.xmpp.d.ts +3 -0
  350. package/lib/typescript/networking/xmpp/sendDisplayedMarker.xmpp.d.ts.map +1 -0
  351. package/lib/typescript/networking/xmpp/sendMediaMessage.xmpp.d.ts +12 -0
  352. package/lib/typescript/networking/xmpp/sendMediaMessage.xmpp.d.ts.map +1 -1
  353. package/lib/typescript/networking/xmpp/sendReceivedReceipt.xmpp.d.ts +3 -0
  354. package/lib/typescript/networking/xmpp/sendReceivedReceipt.xmpp.d.ts.map +1 -0
  355. package/lib/typescript/networking/xmppClient.d.ts +15 -0
  356. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  357. package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
  358. package/lib/typescript/roomStore/roomHeapSlice.d.ts +22 -1
  359. package/lib/typescript/roomStore/roomHeapSlice.d.ts.map +1 -1
  360. package/lib/typescript/roomStore/roomsSlice.d.ts +67 -3
  361. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  362. package/lib/typescript/types/models/attachment.model.d.ts +52 -0
  363. package/lib/typescript/types/models/attachment.model.d.ts.map +1 -0
  364. package/lib/typescript/types/models/message.model.d.ts +26 -0
  365. package/lib/typescript/types/models/message.model.d.ts.map +1 -1
  366. package/lib/typescript/types/models/modal.model.d.ts +7 -0
  367. package/lib/typescript/types/models/modal.model.d.ts.map +1 -1
  368. package/lib/typescript/types/models/room.model.d.ts +2 -0
  369. package/lib/typescript/types/models/room.model.d.ts.map +1 -1
  370. package/lib/typescript/types/types.d.ts +69 -1
  371. package/lib/typescript/types/types.d.ts.map +1 -1
  372. package/lib/typescript/version.d.ts +1 -1
  373. package/package.json +4 -1
  374. package/plugins/notification-service/Info.plist +31 -0
  375. package/plugins/notification-service/NotificationService.swift +82 -0
  376. package/plugins/withNotificationServiceExtension.js +137 -0
  377. package/src/assets/icons.tsx +20 -2
  378. package/src/components/MainComponents/AlbumGrid.tsx +183 -0
  379. package/src/components/MainComponents/ChatRoom.tsx +4 -2
  380. package/src/components/MainComponents/MediaMessage.tsx +246 -130
  381. package/src/components/MainComponents/MediaUploadOverlay.tsx +102 -0
  382. package/src/components/MessageBubble/MediaCaption.tsx +45 -0
  383. package/src/components/MessageBubble/Message.tsx +71 -3
  384. package/src/components/MessageBubble/MessageInteractions.tsx +2 -1
  385. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +64 -0
  386. package/src/components/RoomComponents/LastMessageItem.tsx +15 -4
  387. package/src/components/RoomComponents/styled/LastAudioMessage.tsx +6 -3
  388. package/src/components/RoomComponents/styled/LastMessageFile.tsx +6 -2
  389. package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +6 -2
  390. package/src/components/RoomComponents/styled/LastMessageVideo.tsx +6 -2
  391. package/src/components/Thread/ThreadWrapper.tsx +5 -9
  392. package/src/components/VideoCalls/ActiveCallBar.tsx +56 -10
  393. package/src/components/VideoCalls/CallIcons.tsx +36 -12
  394. package/src/components/VideoCalls/VideoCallOverlay.tsx +205 -8
  395. package/src/components/VideoCalls/VideoCallSession.tsx +45 -13
  396. package/src/components/VideoCalls/callSessionController.ts +51 -20
  397. package/src/components/VideoCalls/callUiStore.ts +33 -3
  398. package/src/components/VideoCalls/livekitRuntime.ts +13 -0
  399. package/src/components/VideoCalls/useCallKeep.ts +204 -33
  400. package/src/components/VideoCalls/useOngoingCallNotification.ts +113 -0
  401. package/src/components/VideoCalls/usePipTile.ts +214 -0
  402. package/src/components/styled/MediaFilePreview.tsx +49 -34
  403. package/src/components/styled/MessageImage.tsx +21 -5
  404. package/src/components/styled/SendInput.tsx +101 -87
  405. package/src/components/styled/VideoMessage.tsx +34 -9
  406. package/src/context/xmppProvider.tsx +32 -0
  407. package/src/e2ee/fileEnvelope.ts +1 -1
  408. package/src/e2ee/sealedBody.ts +44 -5
  409. package/src/helpers/albumLayout.ts +207 -0
  410. package/src/helpers/attachments.ts +316 -0
  411. package/src/helpers/caption.ts +283 -0
  412. package/src/helpers/createMainMessageForThread.ts +6 -1
  413. package/src/helpers/createMessageFromXml.ts +21 -5
  414. package/src/helpers/fileKind.ts +38 -0
  415. package/src/helpers/getDataFromXml.ts +5 -1
  416. package/src/helpers/mapWithConcurrency.ts +32 -0
  417. package/src/helpers/mediaLimits.ts +27 -0
  418. package/src/helpers/mediaSendRetry.ts +59 -0
  419. package/src/helpers/mediaWireData.ts +57 -0
  420. package/src/helpers/mentionSpans.ts +17 -0
  421. package/src/helpers/mimeToExtension.ts +51 -0
  422. package/src/helpers/readReceipts.ts +219 -0
  423. package/src/helpers/repairFilenameEncoding.ts +82 -0
  424. package/src/helpers/safeJson.ts +11 -0
  425. package/src/helpers/updateMessagesTillLast.tsx +2 -1
  426. package/src/hooks/useSendMessage.tsx +448 -249
  427. package/src/i18n/strings.ts +144 -0
  428. package/src/main.ts +3 -0
  429. package/src/networking/api-requests/auth.api.ts +60 -3
  430. package/src/networking/stanzaHandlers.ts +91 -2
  431. package/src/networking/xmpp/handleStanzas.xmpp.ts +6 -2
  432. package/src/networking/xmpp/sendDisplayedMarker.xmpp.ts +31 -0
  433. package/src/networking/xmpp/sendMediaMessage.xmpp.ts +60 -3
  434. package/src/networking/xmpp/sendReceivedReceipt.xmpp.ts +31 -0
  435. package/src/networking/xmppClient.ts +48 -0
  436. package/src/roomStore/persistence.ts +94 -3
  437. package/src/roomStore/roomHeapSlice.ts +23 -1
  438. package/src/roomStore/roomsSlice.ts +112 -1
  439. package/src/types/models/attachment.model.ts +51 -0
  440. package/src/types/models/message.model.ts +29 -0
  441. package/src/types/models/modal.model.ts +7 -0
  442. package/src/types/models/room.model.ts +2 -0
  443. package/src/types/types.ts +83 -1
  444. package/src/version.ts +1 -1
  445. package/lib/commonjs/components/VideoCalls/useDraggable.js +0 -59
  446. package/lib/commonjs/components/VideoCalls/useDraggable.js.map +0 -1
  447. package/lib/module/components/VideoCalls/useDraggable.js +0 -55
  448. package/lib/module/components/VideoCalls/useDraggable.js.map +0 -1
  449. package/lib/typescript/components/VideoCalls/useDraggable.d.ts +0 -19
  450. package/lib/typescript/components/VideoCalls/useDraggable.d.ts.map +0 -1
  451. package/src/components/VideoCalls/useDraggable.ts +0 -46
@@ -16,11 +16,26 @@ import { store } from '../../roomStore';
16
16
 
17
17
  interface CallUiState {
18
18
  minimized: boolean;
19
+ /**
20
+ * iOS shows this incoming call in its own CallKit UI (banner / full
21
+ * screen), so the in-app ring card stays hidden instead of doubling it.
22
+ */
23
+ systemRinging: boolean;
19
24
  /** Id of the header that shows the strip, or null when none is mounted. */
20
25
  barHost: number | null;
26
+ /**
27
+ * Window y of the top of the strip slot under the hosting header, so the
28
+ * collapse animation can land exactly on the strip. Null: no header.
29
+ */
30
+ barAnchorY: number | null;
21
31
  }
22
32
 
23
- let state: CallUiState = { minimized: false, barHost: null };
33
+ let state: CallUiState = {
34
+ minimized: false,
35
+ systemRinging: false,
36
+ barHost: null,
37
+ barAnchorY: null,
38
+ };
24
39
  const hosts: number[] = [];
25
40
  let nextHostId = 1;
26
41
  const listeners = new Set<() => void>();
@@ -35,9 +50,13 @@ const emit = (patch: Partial<CallUiState>) => {
35
50
  const ensureStoreWatcher = () => {
36
51
  if (storeUnsubscribe) {return;}
37
52
  storeUnsubscribe = store.subscribe(() => {
38
- if (state.minimized && store.getState().call.phase === 'idle') {
53
+ const phase = store.getState().call.phase;
54
+ if (state.minimized && phase === 'idle') {
39
55
  emit({ minimized: false });
40
56
  }
57
+ if (state.systemRinging && phase !== 'ringing-incoming') {
58
+ emit({ systemRinging: false });
59
+ }
41
60
  });
42
61
  };
43
62
 
@@ -61,6 +80,10 @@ export const setCallMinimized = (minimized: boolean): void => {
61
80
  if (state.minimized !== minimized) {emit({ minimized });}
62
81
  };
63
82
 
83
+ export const setCallSystemRinging = (systemRinging: boolean): void => {
84
+ if (state.systemRinging !== systemRinging) {emit({ systemRinging });}
85
+ };
86
+
64
87
  export const registerCallBarHost = (
65
88
  onId?: (id: number) => void
66
89
  ): (() => void) => {
@@ -71,6 +94,13 @@ export const registerCallBarHost = (
71
94
  return () => {
72
95
  const index = hosts.indexOf(id);
73
96
  if (index >= 0) {hosts.splice(index, 1);}
74
- emit({ barHost: hosts.length ? hosts[hosts.length - 1] : null });
97
+ const next = hosts.length ? hosts[hosts.length - 1] : null;
98
+ emit({ barHost: next, barAnchorY: next === null ? null : state.barAnchorY });
75
99
  };
76
100
  };
101
+
102
+ /** The hosting header reports where its strip slot is on screen. */
103
+ export const setCallBarAnchor = (hostId: number, y: number): void => {
104
+ if (state.barHost !== hostId || state.barAnchorY === y) {return;}
105
+ emit({ barAnchorY: y });
106
+ };
@@ -34,6 +34,11 @@ export interface LiveKitRuntime {
34
34
  AudioSession: any;
35
35
  /** Installs the WebRTC globals livekit-client expects. */
36
36
  registerGlobals: () => void;
37
+ /**
38
+ * `@livekit/react-native-webrtc` RTCAudioSession: tells WebRTC when
39
+ * CallKit activates/deactivates the iOS audio session.
40
+ */
41
+ RTCAudioSession: any;
37
42
  }
38
43
 
39
44
  let cached: LiveKitRuntime | null | undefined;
@@ -59,6 +64,13 @@ export const loadLiveKit = (): LiveKitRuntime | null => {
59
64
  // moving subset across versions, the core package does not.
60
65
  // eslint-disable-next-line @typescript-eslint/no-require-imports
61
66
  const core = require('livekit-client');
67
+ let webrtc: any = null;
68
+ try {
69
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
70
+ webrtc = require('@livekit/react-native-webrtc');
71
+ } catch {
72
+ // Only needed for CallKit; calls work without it.
73
+ }
62
74
 
63
75
  cached = {
64
76
  Room: core.Room,
@@ -69,6 +81,7 @@ export const loadLiveKit = (): LiveKitRuntime | null => {
69
81
  VideoTrack: rn.VideoTrack,
70
82
  AudioSession: rn.AudioSession,
71
83
  registerGlobals: rn.registerGlobals,
84
+ RTCAudioSession: webrtc?.RTCAudioSession ?? null,
72
85
  };
73
86
  } catch {
74
87
  cached = null;
@@ -1,9 +1,13 @@
1
- import { useEffect, useMemo, useRef } from 'react';
1
+ import { useEffect, useMemo, useRef, useState } from 'react';
2
2
  import { Platform } from 'react-native';
3
3
  import { useDispatch, useSelector } from 'react-redux';
4
4
  import { RootState, store } from '../../roomStore';
5
5
  import { acceptIncomingCall, declineIncomingCall } from '../../roomStore/callSlice';
6
6
  import { sendCallStateSignal } from '../../networking/callTokenStanza';
7
+ import { terminateActiveCall } from './callActions';
8
+ import { setCallMicEnabled, useCallSession } from './callSessionController';
9
+ import { loadLiveKit } from './livekitRuntime';
10
+ import { setCallSystemRinging } from './callUiStore';
7
11
 
8
12
  /**
9
13
  * Native incoming-call UI (Android ConnectionService / iOS CallKit) via
@@ -14,6 +18,12 @@ import { sendCallStateSignal } from '../../networking/callTokenStanza';
14
18
  * loaded lazily exactly like the LiveKit packages, so hosts that don't
15
19
  * install it get the plain in-app ring screen and nothing breaks.
16
20
  *
21
+ * On iOS every call, incoming or outgoing, is also reported to CallKit for
22
+ * as long as it lasts. That is what puts it in the Dynamic Island / the
23
+ * green status-bar pill when the app is in the background, with the
24
+ * system's own mute and end buttons, and what keeps the call's audio
25
+ * running in the background.
26
+ *
17
27
  * Platform reality, stated plainly:
18
28
  * - Android: full value. A ConnectionService call shows the system
19
29
  * incoming-call screen over the lock screen.
@@ -35,6 +45,18 @@ interface CallKeepModule {
35
45
  ) => void;
36
46
  endCall: (uuid: string) => void;
37
47
  endAllCalls: () => void;
48
+ startCall?: (
49
+ uuid: string,
50
+ handle: string,
51
+ contactIdentifier?: string,
52
+ handleType?: string,
53
+ hasVideo?: boolean
54
+ ) => void;
55
+ answerIncomingCall?: (uuid: string) => void;
56
+ reportConnectingOutgoingCallWithUUID?: (uuid: string) => void;
57
+ reportConnectedOutgoingCallWithUUID?: (uuid: string) => void;
58
+ reportEndCallWithUUID?: (uuid: string, reason: number) => void;
59
+ setMutedCall?: (uuid: string, muted: boolean) => void;
38
60
  addEventListener: (event: string, handler: (payload: any) => void) => void;
39
61
  removeEventListener: (event: string) => void;
40
62
  setAvailable?: (available: boolean) => void;
@@ -95,16 +117,32 @@ const toUuid = (seed: string): string => {
95
117
  ].join('-');
96
118
  };
97
119
 
120
+ const trace = (...args: unknown[]) => {
121
+ if (__DEV__) {console.log('[calls] CallKit:', ...args);}
122
+ };
123
+
98
124
  export const useCallKeep = (): void => {
99
125
  const dispatch = useDispatch();
100
126
  const call = useSelector((state: RootState) => state.call);
127
+ const session = useCallSession();
101
128
  const callKeep = useMemo(() => loadCallKeep(), []);
129
+ const [ready, setReady] = useState(false);
102
130
  const activeUuidRef = useRef<string | null>(null);
103
- const readyRef = useRef(false);
131
+ // The CallKit call has been answered (from the system screen or in-app).
132
+ const answeredRef = useRef(false);
133
+ const outgoingReportedRef = useRef<'none' | 'connecting' | 'connected'>('none');
134
+ const isIOS = Platform.OS === 'ios';
104
135
 
105
136
  // One-time native setup.
106
137
  useEffect(() => {
107
- if (!callKeep) {return;}
138
+ if (!callKeep) {
139
+ if (isIOS) {
140
+ // The usual reason for "no Dynamic Island": the JS package is there
141
+ // but the binary was built without the RNCallKeep pod.
142
+ trace('unavailable (react-native-callkeep is not linked in this build)');
143
+ }
144
+ return;
145
+ }
108
146
  let cancelled = false;
109
147
 
110
148
  (async () => {
@@ -113,6 +151,11 @@ export const useCallKeep = (): void => {
113
151
  ios: {
114
152
  appName: 'Ethora',
115
153
  supportsVideo: true,
154
+ maximumCallGroups: '1',
155
+ maximumCallsPerCallGroup: '1',
156
+ // Our calls are not phone calls: keep them out of the Phone
157
+ // app's Recents, whose entries would dial back into nowhere.
158
+ includesCallsInRecents: false,
116
159
  },
117
160
  android: {
118
161
  alertTitle: 'Permissions required',
@@ -130,28 +173,35 @@ export const useCallKeep = (): void => {
130
173
  });
131
174
  if (cancelled) {return;}
132
175
  callKeep.setAvailable?.(true);
133
- readyRef.current = true;
134
- } catch {
176
+ trace('ready');
177
+ setReady(true);
178
+ } catch (error) {
179
+ trace('setup failed', error);
135
180
  // Host didn't grant phone-account permission, or the module isn't
136
181
  // linked. The in-app ring screen still works, so stay quiet.
137
- readyRef.current = false;
182
+ setReady(false);
138
183
  }
139
184
  })();
140
185
 
141
186
  return () => {
142
187
  cancelled = true;
143
188
  };
144
- }, [callKeep]);
189
+ }, [callKeep, isIOS]);
145
190
 
146
- // Bridge native answer/end actions back into Redux.
191
+ // Bridge native actions back into the call.
147
192
  useEffect(() => {
148
193
  if (!callKeep) {return;}
149
194
 
150
195
  const onAnswer = () => {
196
+ answeredRef.current = true;
151
197
  // The user answered from the system screen, which on Android may
152
198
  // mean the app was not even in the foreground.
153
199
  callKeep.backToForeground?.();
154
- if (store.getState().call.direction === 'incoming') {
200
+ // Only from the ring: CallKit also reports the answer we make on its
201
+ // behalf after an in-app accept, and re-accepting then would drop an
202
+ // in-progress call back to 'connecting'.
203
+ const current = store.getState().call;
204
+ if (current.direction === 'incoming' && current.phase === 'ringing-incoming') {
155
205
  dispatch(acceptIncomingCall());
156
206
  }
157
207
  };
@@ -165,73 +215,198 @@ export const useCallKeep = (): void => {
165
215
  ) {
166
216
  sendCallStateSignal('declined');
167
217
  dispatch(declineIncomingCall());
218
+ return;
219
+ }
220
+ // Ended from the Dynamic Island, the lock screen or a headset.
221
+ if (snapshot.phase === 'error') {return;}
222
+ terminateActiveCall(snapshot.phase === 'requesting' ? 'cancelled' : 'ended');
223
+ };
224
+
225
+ // The system mute button (Dynamic Island, lock screen, CarPlay).
226
+ const onMuted = ({ muted }: { muted: boolean }) => {
227
+ void setCallMicEnabled(!muted);
228
+ };
229
+
230
+ // Another call (e.g. a phone call) put ours on hold: stop sending audio.
231
+ const onHold = ({ hold }: { hold: boolean }) => {
232
+ if (hold) {void setCallMicEnabled(false);}
233
+ };
234
+
235
+ // CallKit owns the iOS audio session: WebRTC may only start its audio
236
+ // unit once CallKit has activated the session.
237
+ const onAudioActivated = () => {
238
+ try {
239
+ loadLiveKit()?.RTCAudioSession?.audioSessionDidActivate?.();
240
+ } catch {
241
+ // Older webrtc builds manage the session on their own.
242
+ }
243
+ };
244
+ const onAudioDeactivated = () => {
245
+ try {
246
+ loadLiveKit()?.RTCAudioSession?.audioSessionDidDeactivate?.();
247
+ } catch {
248
+ // noop
168
249
  }
169
250
  };
170
251
 
171
252
  callKeep.addEventListener('answerCall', onAnswer);
172
253
  callKeep.addEventListener('endCall', onEnd);
254
+ callKeep.addEventListener('didPerformSetMutedCallAction', onMuted);
255
+ callKeep.addEventListener('didToggleHoldCallAction', onHold);
256
+ callKeep.addEventListener('didActivateAudioSession', onAudioActivated);
257
+ // CallKit rejected or dropped our calls (e.g. a build without the voip
258
+ // background mode): there is nothing to end any more.
259
+ const onReset = () => {
260
+ trace('provider reset');
261
+ };
262
+ callKeep.addEventListener('didResetProvider', onReset);
263
+ // The system's verdict on displayIncomingCall ("Unentitled" means the
264
+ // app lacks the voip background mode).
265
+ const onDisplayed = ({ error, errorCode }: { error?: string; errorCode?: string }) => {
266
+ trace('incoming call shown', error ? `failed: ${errorCode || ''} ${error}` : 'ok');
267
+ // CallKit refused it (Do Not Disturb, unentitled...): bring the
268
+ // in-app ring card back so the call can still be answered.
269
+ if (error) {setCallSystemRinging(false);}
270
+ };
271
+ callKeep.addEventListener('didDisplayIncomingCall', onDisplayed);
272
+ callKeep.addEventListener('didDeactivateAudioSession', onAudioDeactivated);
173
273
 
174
274
  return () => {
175
275
  callKeep.removeEventListener('answerCall');
176
276
  callKeep.removeEventListener('endCall');
277
+ callKeep.removeEventListener('didPerformSetMutedCallAction');
278
+ callKeep.removeEventListener('didToggleHoldCallAction');
279
+ callKeep.removeEventListener('didActivateAudioSession');
280
+ callKeep.removeEventListener('didDeactivateAudioSession');
281
+ callKeep.removeEventListener('didResetProvider');
282
+ callKeep.removeEventListener('didDisplayIncomingCall');
177
283
  };
178
284
  }, [callKeep, dispatch]);
179
285
 
180
- // Show / dismiss the native screen as the call state changes.
286
+ const displayName = call.roomName || 'Ethora';
287
+ const isRinging =
288
+ call.direction === 'incoming' && call.phase === 'ringing-incoming';
289
+ const isLive = call.phase === 'connecting' || call.phase === 'in-call';
290
+ const isOutgoing = call.direction === 'outgoing';
291
+ const peerConnected = session.anchorAt !== null;
292
+
293
+ // Report the call to the system as its state changes.
181
294
  useEffect(() => {
182
- if (!callKeep || !readyRef.current) {return;}
295
+ if (!callKeep || !ready) {return;}
183
296
 
184
- const isRinging =
185
- call.direction === 'incoming' && call.phase === 'ringing-incoming';
297
+ const release = () => {
298
+ if (!activeUuidRef.current) {return;}
299
+ try {
300
+ callKeep.endCall(activeUuidRef.current);
301
+ } catch {
302
+ // Screen already gone.
303
+ }
304
+ activeUuidRef.current = null;
305
+ answeredRef.current = false;
306
+ outgoingReportedRef.current = 'none';
307
+ };
186
308
 
187
- if (isRinging && !activeUuidRef.current) {
309
+ if (call.phase === 'idle' || call.phase === 'error') {
310
+ release();
311
+ return;
312
+ }
313
+
314
+ if (isRinging) {
315
+ if (activeUuidRef.current) {return;}
188
316
  const uuid = toUuid(call.callId || call.roomJid || String(Date.now()));
189
317
  activeUuidRef.current = uuid;
318
+ answeredRef.current = false;
319
+ // iOS: the system banner is the ring UI (Telegram-style); the in-app
320
+ // card would only cover the screen under it.
321
+ if (isIOS) {setCallSystemRinging(true);}
190
322
  try {
191
323
  callKeep.displayIncomingCall(
192
324
  uuid,
193
- call.peerXmppUsername || call.roomName || 'Ethora',
194
- call.roomName || undefined,
325
+ displayName,
326
+ displayName,
195
327
  'generic',
196
328
  call.kind === 'video'
197
329
  );
198
330
  } catch {
199
331
  activeUuidRef.current = null;
332
+ setCallSystemRinging(false);
200
333
  }
201
334
  return;
202
335
  }
203
336
 
204
- // Any exit from ringing (answered in-app, declined, peer cancelled)
205
- // must tear the system screen down or it hangs around ringing.
206
- if (!isRinging && activeUuidRef.current && call.phase !== 'connecting' && call.phase !== 'in-call') {
337
+ // iOS: an outgoing call is a CallKit call from the first ring, so it
338
+ // shows in the Dynamic Island even before the peer answers.
339
+ if (isIOS && isOutgoing && !activeUuidRef.current && callKeep.startCall) {
340
+ // Unique per call: CallKit refuses a UUID it has seen before, and
341
+ // the callId only arrives with the token.
342
+ const uuid = toUuid(`${call.roomJid || ''}|${call.startedAt || Date.now()}`);
343
+ activeUuidRef.current = uuid;
344
+ outgoingReportedRef.current = 'none';
345
+ trace('startCall', uuid);
207
346
  try {
208
- callKeep.endCall(activeUuidRef.current);
347
+ callKeep.startCall(uuid, displayName, displayName, 'generic', call.kind === 'video');
209
348
  } catch {
210
- // Screen already gone.
349
+ activeUuidRef.current = null;
211
350
  }
212
- activeUuidRef.current = null;
351
+ return;
352
+ }
353
+
354
+ const uuid = activeUuidRef.current;
355
+ if (!uuid) {return;}
356
+
357
+ if (isIOS && isOutgoing) {
358
+ if (peerConnected && outgoingReportedRef.current !== 'connected') {
359
+ outgoingReportedRef.current = 'connected';
360
+ callKeep.reportConnectedOutgoingCallWithUUID?.(uuid);
361
+ } else if (
362
+ isLive &&
363
+ !peerConnected &&
364
+ outgoingReportedRef.current === 'none'
365
+ ) {
366
+ outgoingReportedRef.current = 'connecting';
367
+ callKeep.reportConnectingOutgoingCallWithUUID?.(uuid);
368
+ }
369
+ return;
213
370
  }
214
371
 
215
- if (call.phase === 'idle' && activeUuidRef.current) {
372
+ // Incoming, accepted with the in-app button: tell CallKit, or its
373
+ // screen keeps ringing on top of the call.
374
+ if (isIOS && isLive && !answeredRef.current) {
375
+ answeredRef.current = true;
216
376
  try {
217
- callKeep.endCall(activeUuidRef.current);
377
+ callKeep.answerIncomingCall?.(uuid);
218
378
  } catch {
219
379
  // noop
220
380
  }
221
- activeUuidRef.current = null;
222
381
  }
223
382
  }, [
224
383
  callKeep,
225
- call.direction,
384
+ ready,
385
+ isIOS,
386
+ isRinging,
387
+ isLive,
388
+ isOutgoing,
389
+ peerConnected,
390
+ displayName,
226
391
  call.phase,
227
392
  call.callId,
228
393
  call.roomJid,
229
- call.roomName,
230
- call.peerXmppUsername,
394
+ call.startedAt,
231
395
  call.kind,
232
396
  ]);
233
397
 
234
- // Nothing to clean up on unmount beyond the active screen: this hook
398
+ // Keep the system mute button in step with ours.
399
+ useEffect(() => {
400
+ const uuid = activeUuidRef.current;
401
+ if (!callKeep || !ready || !isIOS || !uuid || !isLive) {return;}
402
+ try {
403
+ callKeep.setMutedCall?.(uuid, !session.micOn);
404
+ } catch {
405
+ // noop
406
+ }
407
+ }, [callKeep, ready, isIOS, isLive, session.micOn]);
408
+
409
+ // Nothing to clean up on unmount beyond the active call: this hook
235
410
  // lives for the lifetime of the provider.
236
411
  useEffect(
237
412
  () => () => {
@@ -245,8 +420,4 @@ export const useCallKeep = (): void => {
245
420
  },
246
421
  [callKeep]
247
422
  );
248
-
249
- // iOS-only note kept as a runtime no-op so the import isn't unused when
250
- // the platform check is tree-shaken in release builds.
251
- void Platform.OS;
252
423
  };
@@ -0,0 +1,113 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { useSelector } from 'react-redux';
3
+ import { RootState } from '../../roomStore';
4
+ import { useT } from '../../i18n/useT';
5
+ import type {
6
+ OngoingCallNotification,
7
+ OngoingCallNotificationAction,
8
+ } from '../../types/types';
9
+ import { terminateActiveCall } from './callActions';
10
+ import { toggleCallCamera, toggleCallMic, useCallSession } from './callSessionController';
11
+ import { setCallMinimized } from './callUiStore';
12
+
13
+ /**
14
+ * Drives the host's ongoing-call notification (`videoCalls.
15
+ * ongoingCallNotification`, an Android foreground-service notification in
16
+ * the Ethora app): shown while a call is connecting or connected, updated
17
+ * when the mic, camera or timer anchor change, and its buttons act on the
18
+ * call like the in-app ones.
19
+ */
20
+ export const useOngoingCallNotification = (
21
+ adapter: OngoingCallNotification | undefined
22
+ ): void => {
23
+ const t = useT();
24
+ const call = useSelector((state: RootState) => state.call);
25
+ const session = useCallSession();
26
+ const shownRef = useRef(false);
27
+
28
+ const live =
29
+ !!call.token && (call.phase === 'connecting' || call.phase === 'in-call');
30
+
31
+ useEffect(() => {
32
+ if (!adapter) {return;}
33
+ return adapter.addActionListener((action: OngoingCallNotificationAction) => {
34
+ switch (action) {
35
+ case 'hangUp':
36
+ terminateActiveCall('ended');
37
+ break;
38
+ case 'toggleMic':
39
+ void toggleCallMic();
40
+ break;
41
+ case 'toggleCamera':
42
+ void toggleCallCamera();
43
+ break;
44
+ case 'open':
45
+ // Back from the notification: show the call, not the strip.
46
+ setCallMinimized(false);
47
+ break;
48
+ }
49
+ });
50
+ }, [adapter]);
51
+
52
+ const isVideo = call.kind === 'video';
53
+ const connectedAt = session.anchorAt;
54
+ const text =
55
+ connectedAt !== null
56
+ ? isVideo
57
+ ? t('call.notification.ongoingVideo')
58
+ : t('call.notification.ongoing')
59
+ : !session.connected
60
+ ? t('call.status.connecting')
61
+ : t('call.status.waitingForPeer');
62
+
63
+ useEffect(() => {
64
+ if (!adapter) {return;}
65
+ if (!live) {
66
+ if (shownRef.current) {
67
+ shownRef.current = false;
68
+ adapter.hide();
69
+ }
70
+ return;
71
+ }
72
+ shownRef.current = true;
73
+ adapter.show({
74
+ callId: call.callId || call.roomJid || 'call',
75
+ title: call.roomName || t('call.unknownCaller'),
76
+ text,
77
+ kind: call.kind,
78
+ connectedAt,
79
+ micOn: session.micOn,
80
+ cameraOn: isVideo && session.cameraOn,
81
+ labels: {
82
+ hangUp: t('call.action.hangUp'),
83
+ mute: t('call.notification.mute'),
84
+ unmute: t('call.notification.unmute'),
85
+ cameraOn: t('call.notification.cameraOn'),
86
+ cameraOff: t('call.notification.cameraOff'),
87
+ },
88
+ });
89
+ }, [
90
+ adapter,
91
+ live,
92
+ t,
93
+ text,
94
+ connectedAt,
95
+ isVideo,
96
+ call.callId,
97
+ call.roomJid,
98
+ call.roomName,
99
+ call.kind,
100
+ session.micOn,
101
+ session.cameraOn,
102
+ ]);
103
+
104
+ useEffect(
105
+ () => () => {
106
+ if (adapter && shownRef.current) {
107
+ shownRef.current = false;
108
+ adapter.hide();
109
+ }
110
+ },
111
+ [adapter]
112
+ );
113
+ };