@ethora/chat-component-rn 26.5.21 → 26.6.11

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 (372) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +3 -3
  3. package/index.js +1 -1
  4. package/lib/commonjs/components/MainComponents/ChatHeader.js +20 -8
  5. package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
  6. package/lib/commonjs/components/MainComponents/ChatWrapper.js +17 -0
  7. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  8. package/lib/commonjs/components/MainComponents/LanguageSelectorButton.js +62 -0
  9. package/lib/commonjs/components/MainComponents/LanguageSelectorButton.js.map +1 -0
  10. package/lib/commonjs/components/MainComponents/LanguageSelectorModal.js +253 -0
  11. package/lib/commonjs/components/MainComponents/LanguageSelectorModal.js.map +1 -0
  12. package/lib/commonjs/components/MainComponents/MediaMessage.js +7 -1
  13. package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
  14. package/lib/commonjs/components/MainComponents/RoomList.js +23 -9
  15. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  16. package/lib/commonjs/components/MessageBubble/Message.js +72 -11
  17. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  18. package/lib/commonjs/components/MessageBubble/MessageTranslate.js +160 -0
  19. package/lib/commonjs/components/MessageBubble/MessageTranslate.js.map +1 -0
  20. package/lib/commonjs/components/MessageBubble/TranslatedMessageBody.js +59 -0
  21. package/lib/commonjs/components/MessageBubble/TranslatedMessageBody.js.map +1 -0
  22. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +3 -3
  23. package/lib/commonjs/components/UsersList/UsersList.js +3 -1
  24. package/lib/commonjs/components/UsersList/UsersList.js.map +1 -1
  25. package/lib/commonjs/components/VideoCalls/CallButtons.js +159 -0
  26. package/lib/commonjs/components/VideoCalls/CallButtons.js.map +1 -0
  27. package/lib/commonjs/components/VideoCalls/CallIcons.js +328 -0
  28. package/lib/commonjs/components/VideoCalls/CallIcons.js.map +1 -0
  29. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js +550 -0
  30. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js.map +1 -0
  31. package/lib/commonjs/components/VideoCalls/VideoCallSession.js +636 -0
  32. package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -0
  33. package/lib/commonjs/components/VideoCalls/livekitRuntime.js +91 -0
  34. package/lib/commonjs/components/VideoCalls/livekitRuntime.js.map +1 -0
  35. package/lib/commonjs/components/VideoCalls/useCallKeep.js +215 -0
  36. package/lib/commonjs/components/VideoCalls/useCallKeep.js.map +1 -0
  37. package/lib/commonjs/components/styled/AudioMessage.js +91 -33
  38. package/lib/commonjs/components/styled/AudioMessage.js.map +1 -1
  39. package/lib/commonjs/components/styled/RoomListComponents/index.js +13 -1
  40. package/lib/commonjs/components/styled/RoomListComponents/index.js.map +1 -1
  41. package/lib/commonjs/components/styled/SendInput.js +83 -49
  42. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  43. package/lib/commonjs/components/styled/StyledComponents.js +9 -4
  44. package/lib/commonjs/components/styled/StyledComponents.js.map +1 -1
  45. package/lib/commonjs/components/styled/StyledInputComponents/Composing.js +2 -0
  46. package/lib/commonjs/components/styled/StyledInputComponents/Composing.js.map +1 -1
  47. package/lib/commonjs/components/styled/VideoMessage.js +110 -26
  48. package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
  49. package/lib/commonjs/context/xmppProvider.js +10 -3
  50. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  51. package/lib/commonjs/helpers/callLogMessage.js +162 -0
  52. package/lib/commonjs/helpers/callLogMessage.js.map +1 -0
  53. package/lib/commonjs/helpers/callPush.js +61 -0
  54. package/lib/commonjs/helpers/callPush.js.map +1 -0
  55. package/lib/commonjs/helpers/constants/LANGUAGE_OPTIONS.js +24 -12
  56. package/lib/commonjs/helpers/constants/LANGUAGE_OPTIONS.js.map +1 -1
  57. package/lib/commonjs/helpers/createUserNameFromSetUser.js +51 -2
  58. package/lib/commonjs/helpers/createUserNameFromSetUser.js.map +1 -1
  59. package/lib/commonjs/helpers/getDataFromXml.js +19 -1
  60. package/lib/commonjs/helpers/getDataFromXml.js.map +1 -1
  61. package/lib/commonjs/helpers/incomingCallFromPush.js +74 -0
  62. package/lib/commonjs/helpers/incomingCallFromPush.js.map +1 -0
  63. package/lib/commonjs/helpers/insertMessageWithDelimiter.js +13 -1
  64. package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
  65. package/lib/commonjs/helpers/isUnresolvedSenderId.js +32 -0
  66. package/lib/commonjs/helpers/isUnresolvedSenderId.js.map +1 -0
  67. package/lib/commonjs/hooks/useChatSettingState.js +2 -0
  68. package/lib/commonjs/hooks/useChatSettingState.js.map +1 -1
  69. package/lib/commonjs/hooks/useMessageTranslation.js +51 -0
  70. package/lib/commonjs/hooks/useMessageTranslation.js.map +1 -0
  71. package/lib/commonjs/hooks/usePushNotifications.js +13 -3
  72. package/lib/commonjs/hooks/usePushNotifications.js.map +1 -1
  73. package/lib/commonjs/hooks/useSendMessage.js +14 -4
  74. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  75. package/lib/commonjs/i18n/strings.js +1308 -0
  76. package/lib/commonjs/i18n/strings.js.map +1 -0
  77. package/lib/commonjs/i18n/useT.js +60 -0
  78. package/lib/commonjs/i18n/useT.js.map +1 -0
  79. package/lib/commonjs/main.js +44 -0
  80. package/lib/commonjs/main.js.map +1 -1
  81. package/lib/commonjs/networking/api-requests/auth.api.js +81 -52
  82. package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
  83. package/lib/commonjs/networking/api-requests/push.api.js +34 -5
  84. package/lib/commonjs/networking/api-requests/push.api.js.map +1 -1
  85. package/lib/commonjs/networking/api-requests/rooms.api.js +108 -0
  86. package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
  87. package/lib/commonjs/networking/callTokenStanza.js +531 -0
  88. package/lib/commonjs/networking/callTokenStanza.js.map +1 -0
  89. package/lib/commonjs/networking/outboundQueue.js.map +1 -1
  90. package/lib/commonjs/networking/stanzaHandlers.js +75 -8
  91. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  92. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +47 -11
  93. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  94. package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js +2 -1
  95. package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
  96. package/lib/commonjs/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js +42 -5
  97. package/lib/commonjs/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js.map +1 -1
  98. package/lib/commonjs/networking/xmppClient.js +78 -16
  99. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  100. package/lib/commonjs/roomStore/callSlice.js +144 -0
  101. package/lib/commonjs/roomStore/callSlice.js.map +1 -0
  102. package/lib/commonjs/roomStore/chatSettingsSlice.js +8 -2
  103. package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
  104. package/lib/commonjs/roomStore/index.js +7 -1
  105. package/lib/commonjs/roomStore/index.js.map +1 -1
  106. package/lib/commonjs/roomStore/persistence.js +69 -5
  107. package/lib/commonjs/roomStore/persistence.js.map +1 -1
  108. package/lib/commonjs/roomStore/roomsSlice.js +136 -6
  109. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  110. package/lib/commonjs/utils/translateModePolicy.js +33 -0
  111. package/lib/commonjs/utils/translateModePolicy.js.map +1 -0
  112. package/lib/module/components/MainComponents/ChatHeader.js +20 -8
  113. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  114. package/lib/module/components/MainComponents/ChatWrapper.js +17 -0
  115. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  116. package/lib/module/components/MainComponents/LanguageSelectorButton.js +57 -0
  117. package/lib/module/components/MainComponents/LanguageSelectorButton.js.map +1 -0
  118. package/lib/module/components/MainComponents/LanguageSelectorModal.js +246 -0
  119. package/lib/module/components/MainComponents/LanguageSelectorModal.js.map +1 -0
  120. package/lib/module/components/MainComponents/MediaMessage.js +7 -1
  121. package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
  122. package/lib/module/components/MainComponents/RoomList.js +23 -9
  123. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  124. package/lib/module/components/MessageBubble/Message.js +73 -12
  125. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  126. package/lib/module/components/MessageBubble/MessageTranslate.js +155 -0
  127. package/lib/module/components/MessageBubble/MessageTranslate.js.map +1 -0
  128. package/lib/module/components/MessageBubble/TranslatedMessageBody.js +53 -0
  129. package/lib/module/components/MessageBubble/TranslatedMessageBody.js.map +1 -0
  130. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +3 -3
  131. package/lib/module/components/UsersList/UsersList.js +3 -1
  132. package/lib/module/components/UsersList/UsersList.js.map +1 -1
  133. package/lib/module/components/VideoCalls/CallButtons.js +154 -0
  134. package/lib/module/components/VideoCalls/CallButtons.js.map +1 -0
  135. package/lib/module/components/VideoCalls/CallIcons.js +309 -0
  136. package/lib/module/components/VideoCalls/CallIcons.js.map +1 -0
  137. package/lib/module/components/VideoCalls/VideoCallOverlay.js +544 -0
  138. package/lib/module/components/VideoCalls/VideoCallOverlay.js.map +1 -0
  139. package/lib/module/components/VideoCalls/VideoCallSession.js +630 -0
  140. package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -0
  141. package/lib/module/components/VideoCalls/livekitRuntime.js +83 -0
  142. package/lib/module/components/VideoCalls/livekitRuntime.js.map +1 -0
  143. package/lib/module/components/VideoCalls/useCallKeep.js +210 -0
  144. package/lib/module/components/VideoCalls/useCallKeep.js.map +1 -0
  145. package/lib/module/components/styled/AudioMessage.js +91 -33
  146. package/lib/module/components/styled/AudioMessage.js.map +1 -1
  147. package/lib/module/components/styled/RoomListComponents/index.js +13 -1
  148. package/lib/module/components/styled/RoomListComponents/index.js.map +1 -1
  149. package/lib/module/components/styled/SendInput.js +83 -49
  150. package/lib/module/components/styled/SendInput.js.map +1 -1
  151. package/lib/module/components/styled/StyledComponents.js +9 -4
  152. package/lib/module/components/styled/StyledComponents.js.map +1 -1
  153. package/lib/module/components/styled/StyledInputComponents/Composing.js +2 -0
  154. package/lib/module/components/styled/StyledInputComponents/Composing.js.map +1 -1
  155. package/lib/module/components/styled/VideoMessage.js +111 -27
  156. package/lib/module/components/styled/VideoMessage.js.map +1 -1
  157. package/lib/module/context/xmppProvider.js +11 -4
  158. package/lib/module/context/xmppProvider.js.map +1 -1
  159. package/lib/module/helpers/callLogMessage.js +152 -0
  160. package/lib/module/helpers/callLogMessage.js.map +1 -0
  161. package/lib/module/helpers/callPush.js +55 -0
  162. package/lib/module/helpers/callPush.js.map +1 -0
  163. package/lib/module/helpers/constants/LANGUAGE_OPTIONS.js +24 -12
  164. package/lib/module/helpers/constants/LANGUAGE_OPTIONS.js.map +1 -1
  165. package/lib/module/helpers/createUserNameFromSetUser.js +49 -1
  166. package/lib/module/helpers/createUserNameFromSetUser.js.map +1 -1
  167. package/lib/module/helpers/getDataFromXml.js +20 -1
  168. package/lib/module/helpers/getDataFromXml.js.map +1 -1
  169. package/lib/module/helpers/incomingCallFromPush.js +70 -0
  170. package/lib/module/helpers/incomingCallFromPush.js.map +1 -0
  171. package/lib/module/helpers/insertMessageWithDelimiter.js +13 -1
  172. package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
  173. package/lib/module/helpers/isUnresolvedSenderId.js +27 -0
  174. package/lib/module/helpers/isUnresolvedSenderId.js.map +1 -0
  175. package/lib/module/hooks/useChatSettingState.js +2 -0
  176. package/lib/module/hooks/useChatSettingState.js.map +1 -1
  177. package/lib/module/hooks/useMessageTranslation.js +46 -0
  178. package/lib/module/hooks/useMessageTranslation.js.map +1 -0
  179. package/lib/module/hooks/usePushNotifications.js +13 -3
  180. package/lib/module/hooks/usePushNotifications.js.map +1 -1
  181. package/lib/module/hooks/useSendMessage.js +15 -5
  182. package/lib/module/hooks/useSendMessage.js.map +1 -1
  183. package/lib/module/i18n/strings.js +1300 -0
  184. package/lib/module/i18n/strings.js.map +1 -0
  185. package/lib/module/i18n/useT.js +55 -0
  186. package/lib/module/i18n/useT.js.map +1 -0
  187. package/lib/module/main.js +7 -1
  188. package/lib/module/main.js.map +1 -1
  189. package/lib/module/networking/api-requests/auth.api.js +80 -51
  190. package/lib/module/networking/api-requests/auth.api.js.map +1 -1
  191. package/lib/module/networking/api-requests/push.api.js +35 -5
  192. package/lib/module/networking/api-requests/push.api.js.map +1 -1
  193. package/lib/module/networking/api-requests/rooms.api.js +109 -1
  194. package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
  195. package/lib/module/networking/callTokenStanza.js +526 -0
  196. package/lib/module/networking/callTokenStanza.js.map +1 -0
  197. package/lib/module/networking/outboundQueue.js.map +1 -1
  198. package/lib/module/networking/stanzaHandlers.js +76 -9
  199. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  200. package/lib/module/networking/xmpp/handleStanzas.xmpp.js +48 -11
  201. package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  202. package/lib/module/networking/xmpp/sendTextMessage.xmpp.js +1 -1
  203. package/lib/module/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
  204. package/lib/module/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js +43 -5
  205. package/lib/module/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js.map +1 -1
  206. package/lib/module/networking/xmppClient.js +78 -16
  207. package/lib/module/networking/xmppClient.js.map +1 -1
  208. package/lib/module/roomStore/callSlice.js +130 -0
  209. package/lib/module/roomStore/callSlice.js.map +1 -0
  210. package/lib/module/roomStore/chatSettingsSlice.js +6 -1
  211. package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
  212. package/lib/module/roomStore/index.js +6 -1
  213. package/lib/module/roomStore/index.js.map +1 -1
  214. package/lib/module/roomStore/persistence.js +69 -5
  215. package/lib/module/roomStore/persistence.js.map +1 -1
  216. package/lib/module/roomStore/roomsSlice.js +134 -5
  217. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  218. package/lib/module/utils/translateModePolicy.js +27 -0
  219. package/lib/module/utils/translateModePolicy.js.map +1 -0
  220. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  221. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  222. package/lib/typescript/components/MainComponents/LanguageSelectorButton.d.ts +12 -0
  223. package/lib/typescript/components/MainComponents/LanguageSelectorButton.d.ts.map +1 -0
  224. package/lib/typescript/components/MainComponents/LanguageSelectorModal.d.ts +31 -0
  225. package/lib/typescript/components/MainComponents/LanguageSelectorModal.d.ts.map +1 -0
  226. package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
  227. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  228. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  229. package/lib/typescript/components/MessageBubble/MessageTranslate.d.ts +44 -0
  230. package/lib/typescript/components/MessageBubble/MessageTranslate.d.ts.map +1 -0
  231. package/lib/typescript/components/MessageBubble/TranslatedMessageBody.d.ts +24 -0
  232. package/lib/typescript/components/MessageBubble/TranslatedMessageBody.d.ts.map +1 -0
  233. package/lib/typescript/components/UsersList/UsersList.d.ts.map +1 -1
  234. package/lib/typescript/components/VideoCalls/CallButtons.d.ts +16 -0
  235. package/lib/typescript/components/VideoCalls/CallButtons.d.ts.map +1 -0
  236. package/lib/typescript/components/VideoCalls/CallIcons.d.ts +30 -0
  237. package/lib/typescript/components/VideoCalls/CallIcons.d.ts.map +1 -0
  238. package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts +10 -0
  239. package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts.map +1 -0
  240. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts +38 -0
  241. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -0
  242. package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts +52 -0
  243. package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts.map +1 -0
  244. package/lib/typescript/components/VideoCalls/useCallKeep.d.ts +32 -0
  245. package/lib/typescript/components/VideoCalls/useCallKeep.d.ts.map +1 -0
  246. package/lib/typescript/components/styled/AudioMessage.d.ts.map +1 -1
  247. package/lib/typescript/components/styled/RoomListComponents/index.d.ts.map +1 -1
  248. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  249. package/lib/typescript/components/styled/StyledComponents.d.ts.map +1 -1
  250. package/lib/typescript/components/styled/StyledInputComponents/Composing.d.ts.map +1 -1
  251. package/lib/typescript/components/styled/VideoMessage.d.ts +2 -0
  252. package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
  253. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  254. package/lib/typescript/helpers/callLogMessage.d.ts +34 -0
  255. package/lib/typescript/helpers/callLogMessage.d.ts.map +1 -0
  256. package/lib/typescript/helpers/callPush.d.ts +23 -0
  257. package/lib/typescript/helpers/callPush.d.ts.map +1 -0
  258. package/lib/typescript/helpers/constants/LANGUAGE_OPTIONS.d.ts +14 -0
  259. package/lib/typescript/helpers/constants/LANGUAGE_OPTIONS.d.ts.map +1 -1
  260. package/lib/typescript/helpers/createUserNameFromSetUser.d.ts +33 -1
  261. package/lib/typescript/helpers/createUserNameFromSetUser.d.ts.map +1 -1
  262. package/lib/typescript/helpers/getDataFromXml.d.ts.map +1 -1
  263. package/lib/typescript/helpers/incomingCallFromPush.d.ts +14 -0
  264. package/lib/typescript/helpers/incomingCallFromPush.d.ts.map +1 -0
  265. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
  266. package/lib/typescript/helpers/isUnresolvedSenderId.d.ts +2 -0
  267. package/lib/typescript/helpers/isUnresolvedSenderId.d.ts.map +1 -0
  268. package/lib/typescript/hooks/useChatSettingState.d.ts +2 -1
  269. package/lib/typescript/hooks/useChatSettingState.d.ts.map +1 -1
  270. package/lib/typescript/hooks/useMessageTranslation.d.ts +25 -0
  271. package/lib/typescript/hooks/useMessageTranslation.d.ts.map +1 -0
  272. package/lib/typescript/hooks/usePushNotifications.d.ts.map +1 -1
  273. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  274. package/lib/typescript/i18n/strings.d.ts +16 -0
  275. package/lib/typescript/i18n/strings.d.ts.map +1 -0
  276. package/lib/typescript/i18n/useT.d.ts +34 -0
  277. package/lib/typescript/i18n/useT.d.ts.map +1 -0
  278. package/lib/typescript/main.d.ts +6 -1
  279. package/lib/typescript/main.d.ts.map +1 -1
  280. package/lib/typescript/networking/api-requests/auth.api.d.ts +27 -1
  281. package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
  282. package/lib/typescript/networking/api-requests/push.api.d.ts.map +1 -1
  283. package/lib/typescript/networking/api-requests/rooms.api.d.ts +3 -0
  284. package/lib/typescript/networking/api-requests/rooms.api.d.ts.map +1 -1
  285. package/lib/typescript/networking/callTokenStanza.d.ts +14 -0
  286. package/lib/typescript/networking/callTokenStanza.d.ts.map +1 -0
  287. package/lib/typescript/networking/outboundQueue.d.ts +1 -0
  288. package/lib/typescript/networking/outboundQueue.d.ts.map +1 -1
  289. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  290. package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
  291. package/lib/typescript/networking/xmpp/sendTextMessage.xmpp.d.ts +10 -0
  292. package/lib/typescript/networking/xmpp/sendTextMessage.xmpp.d.ts.map +1 -1
  293. package/lib/typescript/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.d.ts +16 -1
  294. package/lib/typescript/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.d.ts.map +1 -1
  295. package/lib/typescript/networking/xmppClient.d.ts +1 -1
  296. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  297. package/lib/typescript/roomStore/callSlice.d.ts +39 -0
  298. package/lib/typescript/roomStore/callSlice.d.ts.map +1 -0
  299. package/lib/typescript/roomStore/chatSettingsSlice.d.ts +10 -1
  300. package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
  301. package/lib/typescript/roomStore/index.d.ts +4 -0
  302. package/lib/typescript/roomStore/index.d.ts.map +1 -1
  303. package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
  304. package/lib/typescript/roomStore/roomsSlice.d.ts +6 -1
  305. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  306. package/lib/typescript/types/models/language.model.d.ts +1 -1
  307. package/lib/typescript/types/models/language.model.d.ts.map +1 -1
  308. package/lib/typescript/types/models/message.model.d.ts +7 -0
  309. package/lib/typescript/types/models/message.model.d.ts.map +1 -1
  310. package/lib/typescript/types/types.d.ts +135 -1
  311. package/lib/typescript/types/types.d.ts.map +1 -1
  312. package/lib/typescript/utils/translateModePolicy.d.ts +20 -0
  313. package/lib/typescript/utils/translateModePolicy.d.ts.map +1 -0
  314. package/package.json +20 -4
  315. package/src/components/MainComponents/ChatHeader.tsx +30 -9
  316. package/src/components/MainComponents/ChatWrapper.tsx +15 -0
  317. package/src/components/MainComponents/LanguageSelectorButton.tsx +53 -0
  318. package/src/components/MainComponents/LanguageSelectorModal.tsx +276 -0
  319. package/src/components/MainComponents/MediaMessage.tsx +5 -0
  320. package/src/components/MainComponents/RoomList.tsx +27 -9
  321. package/src/components/MessageBubble/Message.tsx +109 -17
  322. package/src/components/MessageBubble/MessageTranslate.tsx +182 -0
  323. package/src/components/MessageBubble/TranslatedMessageBody.tsx +59 -0
  324. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +3 -3
  325. package/src/components/UsersList/UsersList.tsx +3 -1
  326. package/src/components/VideoCalls/CallButtons.tsx +171 -0
  327. package/src/components/VideoCalls/CallIcons.tsx +246 -0
  328. package/src/components/VideoCalls/VideoCallOverlay.tsx +627 -0
  329. package/src/components/VideoCalls/VideoCallSession.tsx +675 -0
  330. package/src/components/VideoCalls/livekitRuntime.ts +100 -0
  331. package/src/components/VideoCalls/useCallKeep.ts +252 -0
  332. package/src/components/styled/AudioMessage.tsx +97 -37
  333. package/src/components/styled/RoomListComponents/index.tsx +15 -3
  334. package/src/components/styled/SendInput.tsx +94 -51
  335. package/src/components/styled/StyledComponents.ts +9 -6
  336. package/src/components/styled/StyledInputComponents/Composing.tsx +7 -1
  337. package/src/components/styled/VideoMessage.tsx +114 -20
  338. package/src/context/xmppProvider.tsx +14 -1
  339. package/src/helpers/callLogMessage.ts +174 -0
  340. package/src/helpers/callPush.ts +90 -0
  341. package/src/helpers/constants/LANGUAGE_OPTIONS.ts +20 -5
  342. package/src/helpers/createUserNameFromSetUser.ts +68 -2
  343. package/src/helpers/getDataFromXml.ts +40 -4
  344. package/src/helpers/incomingCallFromPush.ts +83 -0
  345. package/src/helpers/insertMessageWithDelimiter.ts +27 -9
  346. package/src/helpers/isUnresolvedSenderId.ts +25 -0
  347. package/src/hooks/useChatSettingState.tsx +4 -0
  348. package/src/hooks/useMessageTranslation.ts +70 -0
  349. package/src/hooks/usePushNotifications.ts +15 -3
  350. package/src/hooks/useSendMessage.tsx +18 -5
  351. package/src/i18n/strings.ts +1322 -0
  352. package/src/i18n/useT.ts +56 -0
  353. package/src/main.ts +18 -1
  354. package/src/networking/api-requests/auth.api.ts +79 -44
  355. package/src/networking/api-requests/push.api.ts +39 -8
  356. package/src/networking/api-requests/rooms.api.ts +109 -1
  357. package/src/networking/callTokenStanza.ts +636 -0
  358. package/src/networking/outboundQueue.ts +1 -0
  359. package/src/networking/stanzaHandlers.ts +74 -15
  360. package/src/networking/xmpp/handleStanzas.xmpp.ts +52 -11
  361. package/src/networking/xmpp/sendTextMessage.xmpp.ts +1 -1
  362. package/src/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.ts +41 -5
  363. package/src/networking/xmppClient.ts +97 -28
  364. package/src/roomStore/callSlice.ts +190 -0
  365. package/src/roomStore/chatSettingsSlice.ts +16 -0
  366. package/src/roomStore/index.ts +5 -0
  367. package/src/roomStore/persistence.ts +103 -3
  368. package/src/roomStore/roomsSlice.ts +149 -4
  369. package/src/types/models/language.model.ts +17 -1
  370. package/src/types/models/message.model.ts +9 -0
  371. package/src/types/types.ts +142 -2
  372. package/src/utils/translateModePolicy.ts +31 -0
@@ -14,12 +14,20 @@ import AttachSheet from '../Modals/AttachSheet/AttachSheet';
14
14
  import { MediaFilePreview } from './MediaFilePreview';
15
15
  import { getIconColor } from '../../helpers/getIconColor';
16
16
  import { getElementFont } from '../../helpers/getElementFont';
17
+ import { useT } from '../../i18n/useT';
17
18
  import * as ImagePicker from 'expo-image-picker';
18
19
  import * as DocumentPicker from 'expo-document-picker';
19
20
  import * as ImageManipulator from 'expo-image-manipulator';
20
- // `Audio` namespace gives us permissions, audio mode, presets, and the
21
- // Recording class — same pattern AudioMessage uses for Audio.Sound.
22
- import { Audio } from 'expo-av';
21
+ // expo-audio replaces the discontinued expo-av: `useAudioRecorder` owns a
22
+ // single reusable recorder for this input's lifetime (prepare → record →
23
+ // stop → prepare again), and the module-level helpers cover permissions
24
+ // and the iOS audio session.
25
+ import {
26
+ useAudioRecorder,
27
+ setAudioModeAsync,
28
+ requestRecordingPermissionsAsync,
29
+ RecordingPresets,
30
+ } from 'expo-audio';
23
31
 
24
32
  // iOS photos default to HEIC; many web backends (incl. ours) 500 on
25
33
  // HEIC uploads because they can't decode it. Convert to JPEG before
@@ -88,6 +96,7 @@ const SendInput: React.FC<SendInputProps> = ({
88
96
  isLoading,
89
97
  isMessageProcessing,
90
98
  }) => {
99
+ const t = useT();
91
100
  const [message, setMessage] = useState('');
92
101
  const [isRecording, setIsRecording] = useState(false);
93
102
  // Live counter (seconds) for the recording overlay. Updated by a
@@ -97,14 +106,20 @@ const SendInput: React.FC<SendInputProps> = ({
97
106
  const [filePreviews, setFilePreviews] = useState<MediaFile[]>([]);
98
107
  const [showMediaMenu, setShowMediaMenu] = useState(false);
99
108
 
100
- // expo-av's Audio.Recording instance for the in-progress recording.
101
- // Kept in a ref (not state) because handlers fire synchronously and we
102
- // need the latest instance without waiting for a re-render.
103
- // Typed via InstanceType<typeof Audio.Recording> because direct
104
- // `Audio.Recording` as a type-position lookup fails under bundler
105
- // resolution even though the class is in the Audio namespace at
106
- // runtime. InstanceType resolves through the typeof of the value.
107
- const recordingRef = useRef<InstanceType<typeof Audio.Recording> | null>(null);
109
+ // expo-audio's recorder is a long-lived native object owned by the hook
110
+ // (released automatically on unmount) and reused across recordings, so
111
+ // unlike expo-av's one-shot `Audio.Recording` there is no per-recording
112
+ // instance to hold. The hook has to run unconditionally, but the
113
+ // constructor is inert on both platforms — iOS allocates a bare
114
+ // AVAudioRecorder (no file), Android leaves its MediaRecorder null.
115
+ // Nothing claims the mic, writes a file, or switches the iOS session to
116
+ // playAndRecord until `prepareToRecordAsync`, so consumers with
117
+ // `enableAudio` off carry an idle object and nothing more.
118
+ const audioRecorder = useAudioRecorder(RecordingPresets.HIGH_QUALITY);
119
+ // Tracks whether a recording is actually in flight, so cancel/stop and
120
+ // the unmount teardown can tell "never started" from "needs stopping"
121
+ // without reading native state.
122
+ const isRecordingRef = useRef(false);
108
123
  const recordingTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
109
124
 
110
125
  // Refs shadow `message` and `filePreviews` so handleSendClick can:
@@ -290,7 +305,7 @@ const SendInput: React.FC<SendInputProps> = ({
290
305
  //
291
306
  // Mirrors the web experience: tap mic → start recording → either tap
292
307
  // X to discard, or tap send to stop + immediately upload + post the
293
- // voice message. Uses expo-av's Audio.Recording (already a peer dep
308
+ // voice message. Uses expo-audio's AudioRecorder (already a peer dep
294
309
  // for AudioMessage playback). Filename is `voice-<timestamp>.m4a` with
295
310
  // mimetype `audio/m4a` so the receiver routes through the audio
296
311
  // branch in MediaMessage directly, no octet-stream sniffing needed.
@@ -306,9 +321,9 @@ const SendInput: React.FC<SendInputProps> = ({
306
321
  // playback elsewhere in the app isn't routed to the earpiece.
307
322
  const restoreAudioMode = async () => {
308
323
  try {
309
- await Audio.setAudioModeAsync({
310
- allowsRecordingIOS: false,
311
- playsInSilentModeIOS: true,
324
+ await setAudioModeAsync({
325
+ allowsRecording: false,
326
+ playsInSilentMode: true,
312
327
  });
313
328
  } catch {
314
329
  /* non-fatal */
@@ -316,27 +331,30 @@ const SendInput: React.FC<SendInputProps> = ({
316
331
  };
317
332
 
318
333
  const handleStartRecording = async () => {
319
- if (isRecording || recordingRef.current) {return;}
334
+ if (isRecording || isRecordingRef.current) {return;}
320
335
  try {
321
- const perm = await Audio.requestPermissionsAsync();
336
+ const perm = await requestRecordingPermissionsAsync();
322
337
  if (!perm.granted) {
323
338
  promptOpenSettings(
324
339
  'Microphone permission is needed to record voice messages.'
325
340
  );
326
341
  return;
327
342
  }
328
- // iOS: recording requires `allowsRecordingIOS:true`; we'll
329
- // flip it back in restoreAudioMode after stop/cancel.
330
- await Audio.setAudioModeAsync({
331
- allowsRecordingIOS: true,
332
- playsInSilentModeIOS: true,
343
+ // `allowsRecording` is not just an iOS session flag: expo-audio's
344
+ // recorder throws RecordingDisabledException from record() when the
345
+ // audio mode has it off. Flipped back in restoreAudioMode after
346
+ // stop/cancel so playback elsewhere isn't stuck on the earpiece.
347
+ await setAudioModeAsync({
348
+ allowsRecording: true,
349
+ playsInSilentMode: true,
333
350
  });
334
- const rec = new Audio.Recording();
335
- await rec.prepareToRecordAsync(
336
- Audio.RecordingOptionsPresets.HIGH_QUALITY
337
- );
338
- await rec.startAsync();
339
- recordingRef.current = rec;
351
+ // Passing the preset (rather than preparing bare) makes the native
352
+ // side allocate a FRESH output file for this take. Without it the
353
+ // recorder reuses the previous URL, so a second voice message would
354
+ // overwrite the first while its upload is still in flight.
355
+ await audioRecorder.prepareToRecordAsync(RecordingPresets.HIGH_QUALITY);
356
+ audioRecorder.record();
357
+ isRecordingRef.current = true;
340
358
  setIsRecording(true);
341
359
  setRecordingDuration(0);
342
360
  const startedAt = Date.now();
@@ -346,7 +364,7 @@ const SendInput: React.FC<SendInputProps> = ({
346
364
  }, 250);
347
365
  } catch (err) {
348
366
  console.warn('startRecording failed', err);
349
- recordingRef.current = null;
367
+ isRecordingRef.current = false;
350
368
  setIsRecording(false);
351
369
  setRecordingDuration(0);
352
370
  await restoreAudioMode();
@@ -355,15 +373,15 @@ const SendInput: React.FC<SendInputProps> = ({
355
373
 
356
374
  const handleCancelRecording = async () => {
357
375
  stopRecordingTimer();
358
- const rec = recordingRef.current;
359
- recordingRef.current = null;
376
+ const wasRecording = isRecordingRef.current;
377
+ isRecordingRef.current = false;
360
378
  setIsRecording(false);
361
379
  setRecordingDuration(0);
362
- if (rec) {
380
+ if (wasRecording) {
363
381
  try {
364
- await rec.stopAndUnloadAsync();
382
+ await audioRecorder.stop();
365
383
  } catch {
366
- /* already stopped / unloaded — fine */
384
+ /* already stopped — fine */
367
385
  }
368
386
  }
369
387
  await restoreAudioMode();
@@ -371,12 +389,12 @@ const SendInput: React.FC<SendInputProps> = ({
371
389
 
372
390
  const handleStopAndSendRecording = async () => {
373
391
  stopRecordingTimer();
374
- const rec = recordingRef.current;
375
- recordingRef.current = null;
392
+ const wasRecording = isRecordingRef.current;
393
+ isRecordingRef.current = false;
376
394
  setIsRecording(false);
377
395
  const seconds = recordingDuration;
378
396
  setRecordingDuration(0);
379
- if (!rec) {
397
+ if (!wasRecording) {
380
398
  await restoreAudioMode();
381
399
  return;
382
400
  }
@@ -384,18 +402,20 @@ const SendInput: React.FC<SendInputProps> = ({
384
402
  // within the same tick there's nothing audible to send.
385
403
  if (seconds < 1) {
386
404
  try {
387
- await rec.stopAndUnloadAsync();
405
+ await audioRecorder.stop();
388
406
  } catch {}
389
407
  await restoreAudioMode();
390
408
  return;
391
409
  }
392
410
  try {
393
- await rec.stopAndUnloadAsync();
411
+ await audioRecorder.stop();
394
412
  } catch (err) {
395
- console.warn('stopAndUnloadAsync failed', err);
413
+ console.warn('recorder.stop failed', err);
396
414
  }
415
+ // Read the URI while it still points at THIS take — the next
416
+ // prepareToRecordAsync() swaps in a new output file.
417
+ const uri = audioRecorder.uri;
397
418
  await restoreAudioMode();
398
- const uri = rec.getURI();
399
419
  if (!uri) {return;}
400
420
  // HIGH_QUALITY preset writes AAC in an M4A container on both iOS
401
421
  // and Android, so a single mimetype works. `voice-<ts>.m4a`
@@ -419,14 +439,16 @@ const SendInput: React.FC<SendInputProps> = ({
419
439
  useEffect(() => {
420
440
  return () => {
421
441
  stopRecordingTimer();
422
- const rec = recordingRef.current;
423
- recordingRef.current = null;
424
- if (rec) {
425
- rec.stopAndUnloadAsync().catch(() => {});
442
+ if (isRecordingRef.current) {
443
+ isRecordingRef.current = false;
444
+ audioRecorder.stop().catch(() => {});
426
445
  }
427
446
  restoreAudioMode();
428
447
  };
429
- }, []);
448
+ // The hook's recorder identity is stable (its options never change),
449
+ // so this teardown runs on unmount only.
450
+ // eslint-disable-next-line react-hooks/exhaustive-deps
451
+ }, [audioRecorder]);
430
452
 
431
453
  const handleRemoveImage = (index: number) => {
432
454
  const next = filePreviewsRef.current.filter((_, i) => i !== index);
@@ -487,6 +509,24 @@ const SendInput: React.FC<SendInputProps> = ({
487
509
  setMessage(next);
488
510
  }, [editMessage]);
489
511
 
512
+ // iOS's multiline TextInput always top-aligns its content (UITextView
513
+ // has no vertical-centering API RN can hook into — `textAlignVertical`
514
+ // is Android-only), so a `minHeight` taller than one text line leaves
515
+ // the placeholder/cursor pinned near the top instead of centered. Fix:
516
+ // derive vertical padding from the actual line height so the box's
517
+ // resting height already equals its content height — nothing is left
518
+ // to look top-aligned.
519
+ const inputFontSize =
520
+ config?.typography?.input?.fontSize ??
521
+ config?.typography?.elements?.inputText?.fontSize ??
522
+ 16;
523
+ const inputMinHeight = config?.typography?.input?.minHeight ?? 40;
524
+ const estimatedLineHeight = inputFontSize * 1.2;
525
+ const inputVerticalPadding = Math.max(
526
+ 4,
527
+ (inputMinHeight - estimatedLineHeight) / 2
528
+ );
529
+
490
530
  return (
491
531
  <InputContainer isText={!!message}>
492
532
  {filePreviews.length > 0 && (
@@ -521,7 +561,7 @@ const SendInput: React.FC<SendInputProps> = ({
521
561
  color={config?.colors?.primary}
522
562
  fontSize={config?.typography?.input?.fontSize}
523
563
  fontWeight={config?.typography?.input?.fontWeight as any}
524
- placeholder="Type message"
564
+ placeholder={t('input.placeholder')}
525
565
  placeholderTextColor="#999"
526
566
  value={message}
527
567
  onChangeText={(text) => {
@@ -541,13 +581,16 @@ const SendInput: React.FC<SendInputProps> = ({
541
581
  // No fixed height: a multiline TextInput auto-grows to fit
542
582
  // its content between min/max. Locking `height` made iOS
543
583
  // top-align the text inside the taller box (it looked like
544
- // the text had dropped). minHeight keeps the 40px tap
545
- // target; the row's align-items:center vertically centres
546
- // the content-sized input.
584
+ // the text had dropped). paddingVertical (computed above)
585
+ // makes the resting box height equal minHeight without
586
+ // leaving slack above the text, which is what actually
587
+ // centers it on iOS.
547
588
  style={[
548
589
  {
549
- minHeight: config?.typography?.input?.minHeight ?? 40,
590
+ minHeight: inputMinHeight,
550
591
  maxHeight: config?.typography?.input?.maxHeight ?? 120,
592
+ paddingTop: inputVerticalPadding,
593
+ paddingBottom: inputVerticalPadding,
551
594
  flex: 1,
552
595
  },
553
596
  getElementFont(config, 'inputText'),
@@ -40,12 +40,15 @@ export const CenterContainer = styled.View<{
40
40
  }>`
41
41
  align-items: center;
42
42
  justify-content: center;
43
- width: ${({ rightSpace, leftSpace }) =>
44
- rightSpace && !leftSpace
45
- ? '100%'
46
- : rightSpace || !leftSpace
47
- ? '90%'
48
- : '70%'};
43
+ /* flex:1 so the title fills the space BETWEEN the left (back/avatar) and
44
+ * right (globe / call / menu) clusters and shrinks to make room for them.
45
+ * The previous fixed 90% width overflowed the row (15% left + 90% center
46
+ * + 25% right = 130%), pushing the right cluster — the translate globe,
47
+ * call and room-menu icons — off-screen where it rendered but was clipped
48
+ * by the device edge. min-width:0 lets the title ellipsize instead of
49
+ * forcing the row wider. Mirrors the web header's flexbox layout. */
50
+ flex: 1;
51
+ min-width: 0;
49
52
  padding-right: ${({ rightSpace }) => (rightSpace ? '16' : '0')}px;
50
53
  padding-left: ${({ leftSpace }) => (leftSpace ? '16' : '0')}px;
51
54
  `;
@@ -51,7 +51,13 @@ const Composing: FC<ComposingProps> = ({ usersTyping = ['User'], style }) => {
51
51
  return (
52
52
  <View style={[styles.wrapper, style]}>
53
53
  {typingText ? (
54
- <Text style={styles.typingText}>{typingText}</Text>
54
+ <Text
55
+ style={styles.typingText}
56
+ numberOfLines={1}
57
+ ellipsizeMode="tail"
58
+ >
59
+ {typingText}
60
+ </Text>
55
61
  ) : (
56
62
  <View />
57
63
  )}
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useState } from 'react';
2
- import { Pressable, StyleSheet, View } from 'react-native';
2
+ import { Image, Pressable, StyleSheet, View } from 'react-native';
3
3
  import { useVideoPlayer, VideoView } from 'expo-video';
4
4
  import { useDispatch } from 'react-redux';
5
5
  import {
@@ -18,14 +18,90 @@ interface CustomMessageVideoProps {
18
18
  fileName: string;
19
19
  fileURL: string;
20
20
  mimetype: string;
21
+ /** The backend-generated poster frame (message.locationPreview). */
22
+ previewURL?: string;
21
23
  }
22
24
 
23
- const CustomMessageVideo: React.FC<CustomMessageVideoProps> = ({
24
- fileName,
25
- fileURL,
26
- mimetype,
27
- }) => {
28
- const dispatch = useDispatch();
25
+ const PlayBadge: React.FC = () => (
26
+ <View style={styles.overlay} pointerEvents="none">
27
+ <View style={styles.playButton}>
28
+ <PlayIcon width={28} height={28} />
29
+ </View>
30
+ </View>
31
+ );
32
+
33
+ /**
34
+ * Poster path — taken whenever the message carries a `locationPreview`.
35
+ *
36
+ * A chat row only ever needs a still and a play affordance; actual
37
+ * playback happens in the full-screen preview. Drawing that still with a
38
+ * plain <Image> keeps the whole bubble inside the RN view hierarchy, so
39
+ * the play badge is guaranteed to composite on top of it.
40
+ *
41
+ * The VideoView path below cannot make that promise: expo-video draws
42
+ * into a native surface, and depending on platform, expo-video version
43
+ * and surfaceType that surface can end up above its sibling RN views —
44
+ * swallowing the badge and leaving the video looking like a plain photo.
45
+ * It is also cheaper: no video player instance per row in a long list.
46
+ */
47
+ const PosterVideo: React.FC<{
48
+ previewURL: string;
49
+ onOpen: () => void;
50
+ onPosterError: () => void;
51
+ }> = ({ previewURL, onOpen, onPosterError }) => {
52
+ const [dims, setDims] = useState<MediaDims>(defaultMediaDims());
53
+
54
+ useEffect(() => {
55
+ if (!previewURL) {
56
+ return;
57
+ }
58
+ let active = true;
59
+ Image.getSize(
60
+ previewURL,
61
+ (w, h) => {
62
+ if (active) {
63
+ setDims(fitMediaDimensions(w, h));
64
+ }
65
+ },
66
+ () => {
67
+ /* keep the default box if the size probe fails */
68
+ }
69
+ );
70
+ return () => {
71
+ active = false;
72
+ };
73
+ }, [previewURL]);
74
+
75
+ return (
76
+ <Pressable
77
+ onPress={onOpen}
78
+ style={[styles.wrapper, { width: dims.width, height: dims.height }]}
79
+ accessibilityRole="button"
80
+ accessibilityLabel="Play video"
81
+ >
82
+ <Image
83
+ source={{ uri: previewURL }}
84
+ style={styles.video}
85
+ resizeMode="cover"
86
+ // Not every backend returns a real still — some set
87
+ // locationPreview to the video URL itself, which decodes to
88
+ // nothing. Rather than show an empty box, hand the row back to
89
+ // the player so it can paint a first frame.
90
+ onError={onPosterError}
91
+ />
92
+ <PlayBadge />
93
+ </Pressable>
94
+ );
95
+ };
96
+
97
+ /**
98
+ * Fallback for messages with no usable poster frame: mount the player
99
+ * purely to paint its first frame.
100
+ */
101
+ const VideoSurfaceVideo: React.FC<{
102
+ fileURL: string;
103
+ onOpen: () => void;
104
+ }> = ({ fileURL, onOpen }) => {
29
105
  const [dims, setDims] = useState<MediaDims>(defaultMediaDims());
30
106
 
31
107
  const player = useVideoPlayer(fileURL, (p) => {
@@ -42,11 +118,6 @@ const CustomMessageVideo: React.FC<CustomMessageVideoProps> = ({
42
118
  return () => sub.remove();
43
119
  }, [player]);
44
120
 
45
- const handleOpen = () => {
46
- dispatch(setActiveFile({ fileName, fileURL, mimetype }));
47
- dispatch(setActiveModal(MODAL_TYPES.FILE_PREVIEW));
48
- };
49
-
50
121
  return (
51
122
  // Capture-overlay pattern: VideoView sits underneath without ANY
52
123
  // touch participation; a transparent absolute-fill <Pressable> on
@@ -56,7 +127,7 @@ const CustomMessageVideo: React.FC<CustomMessageVideoProps> = ({
56
127
  // VideoView still intercepted gestures despite that hint, so
57
128
  // tapping the poster did nothing. Customer-reported #9 (video
58
129
  // preview unresponsive). The Pressable now guarantees the tap
59
- // reaches `handleOpen`.
130
+ // reaches `onOpen`.
60
131
  <View
61
132
  style={[styles.wrapper, { width: dims.width, height: dims.height }]}
62
133
  >
@@ -68,16 +139,12 @@ const CustomMessageVideo: React.FC<CustomMessageVideoProps> = ({
68
139
  surfaceType="textureView"
69
140
  pointerEvents="none"
70
141
  />
71
- <View style={styles.overlay} pointerEvents="none">
72
- <View style={styles.playButton}>
73
- <PlayIcon width={28} height={28} />
74
- </View>
75
- </View>
142
+ <PlayBadge />
76
143
  <Pressable
77
- onPress={handleOpen}
144
+ onPress={onOpen}
78
145
  // Sits ON TOP of VideoView + the play-button overlay; transparent
79
146
  // so the poster + play icon show through. Captures the tap and
80
- // routes to handleOpen → setActiveModal(FILE_PREVIEW).
147
+ // routes to onOpen → setActiveModal(FILE_PREVIEW).
81
148
  style={StyleSheet.absoluteFill}
82
149
  accessibilityRole="button"
83
150
  accessibilityLabel="Play video"
@@ -86,6 +153,33 @@ const CustomMessageVideo: React.FC<CustomMessageVideoProps> = ({
86
153
  );
87
154
  };
88
155
 
156
+ const CustomMessageVideo: React.FC<CustomMessageVideoProps> = ({
157
+ fileName,
158
+ fileURL,
159
+ mimetype,
160
+ previewURL,
161
+ }) => {
162
+ const dispatch = useDispatch();
163
+ const [posterFailed, setPosterFailed] = useState(false);
164
+
165
+ const handleOpen = () => {
166
+ dispatch(setActiveFile({ fileName, fileURL, mimetype }));
167
+ dispatch(setActiveModal(MODAL_TYPES.FILE_PREVIEW));
168
+ };
169
+
170
+ if (previewURL && !posterFailed) {
171
+ return (
172
+ <PosterVideo
173
+ previewURL={previewURL}
174
+ onOpen={handleOpen}
175
+ onPosterError={() => setPosterFailed(true)}
176
+ />
177
+ );
178
+ }
179
+
180
+ return <VideoSurfaceVideo fileURL={fileURL} onOpen={handleOpen} />;
181
+ };
182
+
89
183
  export default CustomMessageVideo;
90
184
 
91
185
  const styles = StyleSheet.create({
@@ -10,6 +10,7 @@ import React, {
10
10
  } from 'react';
11
11
  import { AppState, DeviceEventEmitter } from 'react-native';
12
12
  import NetInfo from '@react-native-community/netinfo';
13
+ import { VideoCallOverlay } from '../components/VideoCalls/VideoCallOverlay';
13
14
  import XmppClient, {
14
15
  XmppCredentialsProvider,
15
16
  } from '../networking/xmppClient';
@@ -506,7 +507,13 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
506
507
  useEffect(() => {
507
508
  if (!client) {return;}
508
509
  const id = setInterval(() => {
509
- if (AppState.currentState !== 'active') {return;}
510
+ // Only skip while genuinely backgrounded. iOS also reports 'inactive'
511
+ // for transient states the user still sees the chat through (control
512
+ // centre, an incoming-call banner, app-switcher preview, and — on the
513
+ // simulator — whenever the window is not focused). Gating on
514
+ // `!== 'active'` meant the watchdog silently stopped running in all of
515
+ // those, so a socket that dropped during one never got revived.
516
+ if (AppState.currentState === 'background') {return;}
510
517
  if (client.suppressReconnect) {return;}
511
518
  if (client.status !== 'online') {
512
519
  devPushLog('rn', `watchdog: client ${client.status} → forceReconnect`);
@@ -770,6 +777,12 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
770
777
  }}
771
778
  >
772
779
  {children}
780
+ {/* Lives here, not inside <Chat>: an incoming call-token can arrive
781
+ (and must still ring) while the user is on a different screen of
782
+ the host app, as long as the socket is up. VideoCallOverlay reads
783
+ config and call state from Redux itself, so it needs nothing
784
+ passed in, and renders null whenever no call is in flight. */}
785
+ <VideoCallOverlay />
773
786
  </XmppContext.Provider>
774
787
  );
775
788
  };