@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
@@ -10,6 +10,7 @@ import {
10
10
  User,
11
11
  } from '../types/types';
12
12
  import { Iso639_1Codes } from '../types/models/language.model';
13
+ import type { TranslateMode } from '../utils/translateModePolicy';
13
14
  import { localStorageConstants } from '../helpers/constants/LOCAL_STORAGE';
14
15
  import { asyncLocalStorage } from '../hooks/useLocalStorage';
15
16
 
@@ -22,6 +23,13 @@ export interface ChatState {
22
23
  activeFile?: ModalFile;
23
24
  client?: any;
24
25
  langSource?: Iso639_1Codes;
26
+ /**
27
+ * The reader's own auto/manual pick from the language modal's switcher.
28
+ * Undefined until they touch it, at which point it wins over the host's
29
+ * `config.translates.mode` default (unless the host pinned `forceType`).
30
+ * See utils/translateModePolicy.
31
+ */
32
+ translateMode?: TranslateMode;
25
33
  }
26
34
 
27
35
  export const unpackAndTransform = (input?: User): User => {
@@ -152,6 +160,7 @@ const reducers = {
152
160
  state.config = undefined;
153
161
  state.client = undefined;
154
162
  state.langSource = undefined;
163
+ state.translateMode = undefined;
155
164
  asyncLocalStorage(localStorageConstants.ETHORA_USER).remove();
156
165
  },
157
166
  setLangSource: (
@@ -160,6 +169,12 @@ const reducers = {
160
169
  ) => {
161
170
  state.langSource = action.payload;
162
171
  },
172
+ setTranslateMode: (
173
+ state: WritableDraft<ChatState>,
174
+ action: PayloadAction<TranslateMode | undefined>
175
+ ) => {
176
+ state.translateMode = action.payload;
177
+ },
163
178
  };
164
179
 
165
180
  export const chatSlice: Slice<ChatState, typeof reducers, 'chat'> = createSlice({
@@ -180,6 +195,7 @@ export const {
180
195
  setActiveFile,
181
196
  setStoreClient,
182
197
  setLangSource,
198
+ setTranslateMode,
183
199
  } = chatSlice.actions;
184
200
 
185
201
  export default chatSlice.reducer;
@@ -2,6 +2,7 @@ import { configureStore, combineReducers } from '@reduxjs/toolkit';
2
2
  import chatSettingsReducer, { setUser } from './chatSettingsSlice';
3
3
  import roomsSlice, { addRoom } from './roomsSlice';
4
4
  import { roomHeapSlice } from './roomHeapSlice';
5
+ import callReducer from './callSlice';
5
6
  import { IRoom } from '../types/types';
6
7
  import { unreadMiddleware } from './Middleware/unreadMidlleware';
7
8
  import { logoutMiddleware } from './Middleware/logoutMiddleware';
@@ -13,6 +14,10 @@ const rootReducer = combineReducers({
13
14
  chatSettingStore: chatSettingsReducer,
14
15
  rooms: roomsSlice,
15
16
  roomHeapSlice: roomHeapSlice.reducer,
17
+ // Live call state. Deliberately NOT persisted: a call that was ringing
18
+ // when the app was killed is over by the time it reopens, and restoring
19
+ // it would put the user straight into a dead LiveKit room.
20
+ call: callReducer,
16
21
  });
17
22
 
18
23
  export type RootState = ReturnType<typeof rootReducer>;
@@ -49,10 +49,99 @@ const sanitizeUser = (user?: User): User | null => {
49
49
  } as User;
50
50
  };
51
51
 
52
+ // What a persisted message is FOR: instantly painting a recent transcript
53
+ // on reload before MAM catches up. That needs the fields the bubbles and
54
+ // room-list previews actually read, nothing else. Everything outside this
55
+ // list is either re-derived on render or re-fetched from the server.
56
+ const PERSISTED_MESSAGE_FIELDS: (keyof IMessage)[] = [
57
+ 'id',
58
+ 'xmppId',
59
+ 'xmppFrom',
60
+ 'body',
61
+ 'date',
62
+ 'timestamp',
63
+ 'roomJid',
64
+ 'isSystemMessage',
65
+ 'isMediafile',
66
+ 'isDeleted',
67
+ 'isEdited',
68
+ 'isReply',
69
+ 'showInChannel',
70
+ 'mainMessage',
71
+ 'mimetype',
72
+ 'location',
73
+ 'locationPreview',
74
+ 'fileName',
75
+ 'originalName',
76
+ 'size',
77
+ 'langSource',
78
+ 'callLog',
79
+ ];
80
+
81
+ // The sender identity that rides along on every message over the wire
82
+ // (senderFirstName / senderLastName / photo, which createMessageFromXml
83
+ // folds into message.user) is NOT what the UI reads back, and is not ours
84
+ // to cache: `usersSet` is the canonical store for names and avatars, and
85
+ // the renderers resolve through it, re-deriving the name every time
86
+ // usersSet updates. That is what keeps a renamed user from staying stale.
87
+ //
88
+ // Persisting a copy per message duplicated the same handful of identities
89
+ // across every message of every room, and optimistic sends spread the
90
+ // ENTIRE logged-in user into message.user (see useSendMessage), auth
91
+ // material included.
92
+ //
93
+ // Keep `id` (the key usersSet is looked up by) and `name`, nothing else.
94
+ // `name` earns its ~15 chars: broadcast/system senders ("Ethora") never
95
+ // enter usersSet at all, so for those the message is the only place the
96
+ // name exists.
97
+ const PERSISTED_MESSAGE_USER_FIELDS = ['id', 'name'] as const;
98
+
99
+ // Room fields that are pure server state, re-fetched on every load, and so
100
+ // must never sit in the message cache, let alone compete with messages for
101
+ // AsyncStorage space.
102
+ //
103
+ // `members` is the one that matters. A 3.5k-member room serializes to
104
+ // roughly 840k chars, several hundred times the rest of the room object
105
+ // put together. A handful of such rooms is megabytes of roster written on
106
+ // every debounce tick, and on Android AsyncStorage that means blown
107
+ // cursor-window limits and multi-second writes, for data createRoomFromApi
108
+ // repopulates from /chats/my on the very next load. `usersCnt`, which the
109
+ // header actually reads, is its own scalar field and is preserved below.
110
+ const REFETCHED_ROOM_FIELDS = ['members'] as const;
111
+
112
+ const pickDefined = <T extends object>(
113
+ source: T,
114
+ keys: readonly (keyof T)[]
115
+ ): Partial<T> => {
116
+ const out: Partial<T> = {};
117
+ for (const key of keys) {
118
+ const value = source?.[key];
119
+ if (value !== undefined) {
120
+ out[key] = value;
121
+ }
122
+ }
123
+ return out;
124
+ };
125
+
126
+ const compactMessageForPersist = (message: IMessage): IMessage => {
127
+ const compact = pickDefined(message, PERSISTED_MESSAGE_FIELDS) as IMessage;
128
+ const user = message?.user as Record<string, any> | undefined;
129
+ if (user) {
130
+ compact.user = pickDefined(
131
+ user,
132
+ PERSISTED_MESSAGE_USER_FIELDS as unknown as readonly string[]
133
+ ) as IMessage['user'];
134
+ }
135
+ return compact;
136
+ };
137
+
52
138
  const sanitizeMessages = (messages: IMessage[]): IMessage[] => {
53
139
  if (!Array.isArray(messages)) {return [];}
54
- if (messages.length <= MESSAGE_LIMIT) {return messages;}
55
- return messages.slice(-MESSAGE_LIMIT);
140
+ const capped =
141
+ messages.length > MESSAGE_LIMIT
142
+ ? messages.slice(-MESSAGE_LIMIT)
143
+ : messages;
144
+ return capped.map(compactMessageForPersist);
56
145
  };
57
146
 
58
147
  const sanitizeRooms = (
@@ -63,8 +152,19 @@ const sanitizeRooms = (
63
152
  for (const [jid, room] of Object.entries(rooms)) {
64
153
  if (!jid || typeof jid !== 'string' || !jid.includes('@')) {continue;}
65
154
  if (!room || typeof room !== 'object' || Array.isArray(room)) {continue;}
155
+
156
+ const compactRoom = { ...room } as Record<string, any>;
157
+ // Preserve the count the header reads before dropping the roster it
158
+ // would otherwise be derived from.
159
+ if (compactRoom.usersCnt === undefined && Array.isArray(room.members)) {
160
+ compactRoom.usersCnt = room.members.length;
161
+ }
162
+ for (const field of REFETCHED_ROOM_FIELDS) {
163
+ delete compactRoom[field];
164
+ }
165
+
66
166
  out[jid] = {
67
- ...room,
167
+ ...(compactRoom as IRoom),
68
168
  messages: sanitizeMessages(room?.messages || []),
69
169
  composing: false,
70
170
  composingList: [],
@@ -15,6 +15,97 @@ import type XmppClient from '../networking/xmppClient';
15
15
  // just fetched. After cap eviction we drop from the head (oldest).
16
16
  const RUNTIME_MESSAGE_LIMIT = 100;
17
17
 
18
+ // Body strings the server uses for call signaling broadcasts (call-token,
19
+ // call-state ringing/ended, etc). These should never reach the chat
20
+ // transcript or the room-list "last message" preview, they're control
21
+ // frames, not user-visible content. The XMPP handler (onCallTokenMessage)
22
+ // already swallows them in the live stream, but they can still arrive via
23
+ // MAM history, mucsub catchup, or be present in persisted state from
24
+ // before that filter existed. Drop them at the reducer boundary so the
25
+ // transcript stays clean regardless of source.
26
+ const CALL_SIGNAL_BODIES = new Set([
27
+ 'call-token',
28
+ 'call-state',
29
+ 'call-ringing',
30
+ 'call-ended',
31
+ 'call-declined',
32
+ 'call-cancelled',
33
+ 'call-canceled',
34
+ 'call-timeout',
35
+ 'call-rejected',
36
+ 'call-invite',
37
+ ]);
38
+
39
+ const isCallSignalMessage = (message: IMessage | undefined | null): boolean => {
40
+ if (!message) {return false;}
41
+ const body = String(message.body || '').trim().toLowerCase();
42
+ return CALL_SIGNAL_BODIES.has(body);
43
+ };
44
+
45
+ const stripCallSignals = (messages: IMessage[] | undefined): IMessage[] =>
46
+ Array.isArray(messages)
47
+ ? messages.filter((message) => !isCallSignalMessage(message))
48
+ : [];
49
+
50
+ // True for the client-side call-log fallback written at hangup: it exists
51
+ // only in this client's store (id "calllog-<callId>"), never on the server.
52
+ const isLocalCallLogEntry = (message: IMessage | undefined | null): boolean =>
53
+ String(message?.id || '').startsWith('calllog-');
54
+
55
+ // Merge two log entries for the SAME callId into one. Identity (id/date/
56
+ // xmppId) comes from the server copy when one side is the local fallback,
57
+ // the server archive id is what MAM pages and the catch-up anchor will
58
+ // match against later. Display (body/callLog) comes from whichever copy
59
+ // saw the larger duration, so partial per-participant call-states don't
60
+ // shrink it.
61
+ const mergeCallLogEntries = (a: IMessage, b: IMessage): IMessage => {
62
+ const aLocal = isLocalCallLogEntry(a);
63
+ const bLocal = isLocalCallLogEntry(b);
64
+ const identity = aLocal === bLocal ? a : aLocal ? b : a;
65
+ const display =
66
+ (a.callLog?.durationMs || 0) >= (b.callLog?.durationMs || 0) ? a : b;
67
+ if (identity === display) {return identity;}
68
+ return {
69
+ ...display,
70
+ id: identity.id,
71
+ xmppId: identity.xmppId ?? display.xmppId,
72
+ date: identity.date ?? display.date,
73
+ };
74
+ };
75
+
76
+ // Collapse call-log duplicates for the same callId inside a merged history
77
+ // list (the live path dedups in addRoomMessage, but a MAM page merged over
78
+ // a persisted local fallback entry would otherwise show the call twice).
79
+ const collapseCallLogDuplicates = (messages: IMessage[]): IMessage[] => {
80
+ const byCallId = new Map<string, IMessage>();
81
+ let hasDuplicates = false;
82
+ for (const message of messages) {
83
+ const callId = message?.callLog?.callId;
84
+ if (!callId) {continue;}
85
+ const existing = byCallId.get(callId);
86
+ if (existing) {
87
+ hasDuplicates = true;
88
+ byCallId.set(callId, mergeCallLogEntries(existing, message));
89
+ } else {
90
+ byCallId.set(callId, message);
91
+ }
92
+ }
93
+ if (!hasDuplicates) {return messages;}
94
+ const emitted = new Set<string>();
95
+ return messages
96
+ .filter((message) => {
97
+ const callId = message?.callLog?.callId;
98
+ if (!callId) {return true;}
99
+ if (emitted.has(callId)) {return false;}
100
+ emitted.add(callId);
101
+ return true;
102
+ })
103
+ .map((message) => {
104
+ const callId = message?.callLog?.callId;
105
+ return callId ? byCallId.get(callId) || message : message;
106
+ });
107
+ };
108
+
18
109
  const enforceMessageCap = (messages: IMessage[]): void => {
19
110
  // Trim oldest until we're at/under the limit. Mutates in place
20
111
  // (immer-compatible inside reducers).
@@ -45,8 +136,11 @@ function mergeHistoryIntoCache(
45
136
  existing: IMessage[] | undefined,
46
137
  fetched: IMessage[] | undefined
47
138
  ): IMessage[] {
48
- const ex = Array.isArray(existing) ? existing : [];
49
- const fe = Array.isArray(fetched) ? fetched : [];
139
+ // Strip call control frames on BOTH sides before merging: they can be
140
+ // in the cache (persisted from before this filter existed) and in the
141
+ // fetched MAM page (the live-stream swallow doesn't cover history).
142
+ const ex = stripCallSignals(existing);
143
+ const fe = stripCallSignals(fetched);
50
144
 
51
145
  const pending = ex.filter((m) => m?.pending);
52
146
  const realExisting = ex.filter(
@@ -69,7 +163,10 @@ function mergeHistoryIntoCache(
69
163
 
70
164
  // Cold room, or a gap (no shared id) → can't merge → use the fresh page.
71
165
  if (realExisting.length === 0 || !overlaps) {
72
- return [...capTail(realFetched.slice().sort(byMs)), ...pending];
166
+ return [
167
+ ...capTail(collapseCallLogDuplicates(realFetched.slice().sort(byMs))),
168
+ ...pending,
169
+ ];
73
170
  }
74
171
 
75
172
  // Overlap → union + dedupe by id. Fetched wins on collision: it carries
@@ -87,7 +184,9 @@ function mergeHistoryIntoCache(
87
184
  prev?.isEdited && !m.isEdited ? { ...m, isEdited: true } : m
88
185
  );
89
186
  }
90
- const merged = Array.from(byId.values()).sort(byMs);
187
+ const merged = collapseCallLogDuplicates(
188
+ Array.from(byId.values()).sort(byMs)
189
+ );
91
190
  return [...capTail(merged), ...pending];
92
191
  }
93
192
 
@@ -335,6 +434,14 @@ const reducers = {
335
434
  ) {
336
435
  const { roomJID, message, start } = action.payload;
337
436
 
437
+ // Call signaling broadcasts ("call-token", "call-state", etc.)
438
+ // sometimes slip past the live XMPP filter (MAM history, mucsub
439
+ // catch-up), drop them here so they never land in the transcript
440
+ // or the room-list "last message" preview.
441
+ if (isCallSignalMessage(message)) {
442
+ return;
443
+ }
444
+
338
445
  // Guard against the "stanza arrived before /chats/my completed"
339
446
  // race — without this, the optional-chain `?.messages` falls
340
447
  // back to undefined, and the assignment below tries to set
@@ -350,6 +457,33 @@ const reducers = {
350
457
  }
351
458
 
352
459
  const roomMessages = state.rooms[roomJID].messages;
460
+
461
+ // Collapse multiple call-state events for the same call into a single
462
+ // log entry. Sources: the client-side fallback written at hangup (id
463
+ // "calllog-<callId>", exists only locally) and the server broadcast(s),
464
+ // which can fire once per participant leaving (earlier ones carry a
465
+ // partial durationMs). Rules:
466
+ // - the SERVER copy is canonical for identity (id/date/xmppId): its
467
+ // archive id is what MAM and the catch-up anchor return later, so
468
+ // keeping a local "calllog-" id around breaks anchor matching and
469
+ // duplicates the entry on the next history merge;
470
+ // - the LARGEST duration wins for display, so a 2-minute call doesn't
471
+ // render as "2 sec".
472
+ const incomingCallLog = message.callLog;
473
+ if (incomingCallLog?.callId) {
474
+ const existingCallIdx = roomMessages.findIndex(
475
+ (msg) => msg.callLog?.callId === incomingCallLog.callId
476
+ );
477
+ if (existingCallIdx !== -1) {
478
+ const existing = roomMessages[existingCallIdx];
479
+ const merged = mergeCallLogEntries(existing as IMessage, message);
480
+ if (merged !== (existing as IMessage)) {
481
+ roomMessages[existingCallIdx] = merged;
482
+ }
483
+ return;
484
+ }
485
+ }
486
+
353
487
  const lengthBefore = roomMessages.length;
354
488
 
355
489
  if (roomMessages.length === 0 || start) {
@@ -666,6 +800,16 @@ const reducers = {
666
800
  }
667
801
  }
668
802
  },
803
+ // Merges resolved room members into the identity cache Message.tsx /
804
+ // resolveSenderDisplayName read from. Keyed by BOTH the bare local
805
+ // part and the full jid so either lookup style hits — a message's
806
+ // `user.id` can be either depending on how it was parsed.
807
+ mergeUsersSet(
808
+ state: WritableDraft<RoomMessagesState>,
809
+ action: PayloadAction<{ members: Record<string, any> }>
810
+ ) {
811
+ state.usersSet = { ...(state.usersSet || {}), ...action.payload.members };
812
+ },
669
813
  };
670
814
 
671
815
  export const roomsStore: Slice<RoomMessagesState, typeof reducers, 'roomMessages'> = createSlice({
@@ -770,6 +914,7 @@ export const {
770
914
  setPendingNotificationJid,
771
915
  clearPendingNotificationJid,
772
916
  setReactions,
917
+ mergeUsersSet,
773
918
  } = roomsStore.actions;
774
919
 
775
920
  export default roomsStore.reducer;
@@ -1,4 +1,20 @@
1
- export type Iso639_1Codes = 'en' | 'es' | 'pt' | 'ht' | 'zh';
1
+ // Regional variants for the three languages LANGUAGE_OPTIONS currently
2
+ // offers, matching the deployment's actual reader regions: Canadian
3
+ // English/French, US Spanish. Bare 2-letter codes stay valid alongside
4
+ // them (toBaseLanguage reduces either form to the same base for i18n
5
+ // string-table lookups and translation-language comparisons), since other
6
+ // flows (config.translates.translations) still produce or accept the bare
7
+ // form.
8
+ export type Iso639_1Codes =
9
+ | 'en'
10
+ | 'en-CA'
11
+ | 'es'
12
+ | 'es-US'
13
+ | 'pt'
14
+ | 'ht'
15
+ | 'fr'
16
+ | 'fr-CA'
17
+ | 'zh';
2
18
 
3
19
  export interface Language {
4
20
  iso639_1: Iso639_1Codes;
@@ -36,6 +36,15 @@ export interface IMessage {
36
36
  // Set once a message has been corrected via XEP-0308 (<replace>), so the
37
37
  // bubble can show a small "edited" marker (Slack/WhatsApp style).
38
38
  isEdited?: boolean;
39
+ // Present when this message is a call-log entry derived from a
40
+ // `<data type="call-state">` stanza (see helpers/callLogMessage.ts).
41
+ callLog?: {
42
+ callId: string;
43
+ direction: 'outgoing' | 'incoming';
44
+ durationMs: number;
45
+ missed: boolean;
46
+ kind: 'audio' | 'video';
47
+ };
39
48
  }
40
49
 
41
50
  export interface ReactionMessage {
@@ -401,7 +401,7 @@ export interface IConfig {
401
401
  * When `true`, an idle input (no text, no attachments) shows a
402
402
  * microphone in the send-button slot; tap → start recording → stop &
403
403
  * send. iOS apps need `NSMicrophoneUsageDescription` in Info.plist
404
- * (add via `expo-av`'s plugin block in `app.json`). Receiving voice
404
+ * (add via `expo-audio`'s plugin block in `app.json`). Receiving voice
405
405
  * messages from other clients (incl. legacy web `.bin` voicemails) is
406
406
  * independent of this flag — incoming audio plays regardless.
407
407
  */
@@ -594,13 +594,96 @@ export interface IConfig {
594
594
  customSystemMessage?: React.ComponentType<MessageProps>;
595
595
 
596
596
  // ----- translations -----
597
- translates?: { enabled: boolean; translations?: Iso639_1Codes };
597
+ translates?: {
598
+ enabled: boolean;
599
+ translations?: Iso639_1Codes;
600
+ /**
601
+ * 'auto' shows the translation inline automatically. 'manual' shows a
602
+ * "Translate" link the reader taps (LinkedIn-style), then renders the
603
+ * result inline with a "Show original" toggle. Default 'auto'.
604
+ *
605
+ * Neither mode calls any translation service, both only ever display
606
+ * `message.translations`, whatever arrived attached to the stanza (see
607
+ * `readerLocale` below for how a message gets translated in the first
608
+ * place). This is purely a display choice: show it immediately, or let
609
+ * the reader ask for it.
610
+ */
611
+ mode?: 'auto' | 'manual';
612
+ /**
613
+ * Pins `mode` as fixed host policy. When true, the language-selector
614
+ * modal's auto/manual switcher does not render at all, and the reader
615
+ * has no way to override `mode`, it's always whatever the host set.
616
+ * Defaults to false: the reader can flip between auto and manual
617
+ * themselves via the switcher, which then wins over `mode` (the host's
618
+ * declared default, used until the reader touches it).
619
+ */
620
+ forceType?: boolean;
621
+ /**
622
+ * Reader's full locale (BCP-47, e.g. "fr-CA"). Falls back to
623
+ * `config.i18n.locale`. The region is passed through to `onTranslate` so
624
+ * the service can distinguish fr-CA vs fr-FR; the Translate button
625
+ * visibility comparison ignores the region (en-US vs en-CA => no button).
626
+ *
627
+ * This is also how a host drives the reader's language from OUTSIDE the
628
+ * chat component: set it (e.g. from your own app's language switcher)
629
+ * and pass the updated config down as a normal prop.
630
+ */
631
+ readerLocale?: string;
632
+ /**
633
+ * Shows/hides the globe-icon language picker in the chat header.
634
+ * Defaults to true whenever `enabled` is true. Set to false when the
635
+ * host manages the reader's language itself (via `readerLocale`) and
636
+ * an in-chat picker would just be a second, redundant control.
637
+ */
638
+ showLanguageSelector?: boolean;
639
+ /**
640
+ * Shows/hides the list of selectable languages INSIDE the picker
641
+ * (English/Espanol/...). Defaults to true. Set to false to keep only
642
+ * the enable/disable-translates toggle.
643
+ */
644
+ showLanguageList?: boolean;
645
+ /**
646
+ * Host-provided translation function. When set, the manual Translate
647
+ * action calls this, wire it to your own service, instead of reading
648
+ * `message.translations`. Optional; omit to use only what already
649
+ * arrived over XMPP.
650
+ */
651
+ onTranslate?: (
652
+ text: string,
653
+ ctx: { sourceLocale?: string; targetLocale: string; message: IMessage }
654
+ ) => Promise<string>;
655
+ /**
656
+ * Host predicate deciding whether to show the Translate action for a
657
+ * given message. When omitted, the component compares base languages
658
+ * (message source vs reader, region ignored) and shows the action when
659
+ * they differ.
660
+ */
661
+ showTranslateForMessage?: (message: IMessage) => boolean;
662
+ };
663
+ /**
664
+ * Static UI i18n (interface captions like "Search...", "Type message").
665
+ * `locale` is a BCP-47 tag the host passes from the device/user (e.g. "en",
666
+ * "fr-CA", "es-US"); captions resolve to its base language. `strings`
667
+ * overrides or extends any built-in caption by key (see src/i18n/strings.ts).
668
+ * Built-in languages: en, fr, es, pt, ht, zh. Independent from `translates`
669
+ * (dynamic per-message translation).
670
+ */
671
+ i18n?: {
672
+ locale?: string;
673
+ strings?: Record<string, string>;
674
+ };
598
675
  enableTranslates?: boolean;
599
676
 
600
677
  // ----- notifications -----
601
678
  inAppNotifications?: InAppNotificationConfig;
602
679
  pushNotifications?: {
603
680
  enabled?: boolean;
681
+ /**
682
+ * Base URL of the push subscription service, including the version
683
+ * segment (e.g. "https://push.chat.ethora.com/api/v1"). Set this for
684
+ * self-hosted or enterprise deployments; omit to use Ethora's.
685
+ */
686
+ apiUrl?: string;
604
687
  iconPath?: string;
605
688
  badgePath?: string;
606
689
  onClick?: (params: {
@@ -640,6 +723,63 @@ export interface IConfig {
640
723
  messageType: 'text' | 'media';
641
724
  }) => void;
642
725
  };
726
+
727
+ // ----- audio / video calls -----
728
+ /**
729
+ * LiveKit-backed 1:1 audio and video calls. Off unless `enabled` is
730
+ * explicitly `true`. Requires the native peer dependencies
731
+ * `@livekit/react-native` and `@livekit/react-native-webrtc`, plus
732
+ * microphone/camera permissions and the background audio modes listed
733
+ * in the README. Expo Go cannot run these, the host app needs a dev
734
+ * build or a prebuilt binary.
735
+ */
736
+ videoCalls?: VideoCallsConfig;
737
+ }
738
+
739
+ /**
740
+ * Override the icons used by the in-call control bar and the incoming-call
741
+ * ring screen. Each value is any React node. When omitted, the chat's
742
+ * built-in icon is used. The mic/camera/screen-share toggles take separate
743
+ * on/off icons so the host can express active vs muted however they like.
744
+ */
745
+ export interface VideoCallIcons {
746
+ micOn?: React.ReactNode;
747
+ micOff?: React.ReactNode;
748
+ cameraOn?: React.ReactNode;
749
+ cameraOff?: React.ReactNode;
750
+ screenShareOn?: React.ReactNode;
751
+ screenShareOff?: React.ReactNode;
752
+ hangup?: React.ReactNode;
753
+ accept?: React.ReactNode;
754
+ decline?: React.ReactNode;
755
+ }
756
+
757
+ export interface VideoCallsConfig {
758
+ enabled: boolean;
759
+ livekitUrl: string;
760
+ allowedRoomTypes?: Array<'private'>;
761
+ /**
762
+ * Show the audio-only call button next to the video-call button. Off by
763
+ * default: it's a separate opt-in feature. An audio call uses the same
764
+ * call backend as video (no server changes needed); the client just
765
+ * starts the session with `kind: 'audio'` so no camera track is
766
+ * published, and the callee learns the kind from the direct
767
+ * `call-invite` signal. Requires `enabled` and a `livekitUrl` like
768
+ * video calls.
769
+ */
770
+ enableAudioCalls?: boolean;
771
+ /** Start a video call with the camera already on. Default true. */
772
+ startWithCameraOn?: boolean;
773
+ /** Start a call with the microphone already on. Default true. */
774
+ startWithMicOn?: boolean;
775
+ /**
776
+ * Show the screen-share control. Default false on React Native: screen
777
+ * capture needs a foreground service on Android and a Broadcast Upload
778
+ * Extension on iOS, neither of which the SDK can add to a host app.
779
+ */
780
+ showScreenShare?: boolean;
781
+ /** Custom icons for the call control bar / ring screen. */
782
+ icons?: VideoCallIcons;
643
783
  }
644
784
 
645
785
  interface ConfigRoom {
@@ -0,0 +1,31 @@
1
+ import { IConfig } from '../types/types';
2
+
3
+ export type TranslateMode = 'auto' | 'manual';
4
+
5
+ /**
6
+ * Whether the reader is allowed to pick auto vs manual themselves via the
7
+ * language-selector modal's switcher. `forceType: true` means the host has
8
+ * pinned `translates.mode` as policy, the switcher must not even render,
9
+ * let alone let a reader flip it.
10
+ */
11
+ export const canReaderChooseTranslateMode = (
12
+ translates?: IConfig['translates']
13
+ ): boolean => !translates?.forceType;
14
+
15
+ /**
16
+ * The mode actually in effect for this reader right now.
17
+ *
18
+ * `forceType` wins unconditionally, even a leftover `readerMode` from
19
+ * before the host turned forcing on must not leak through. Otherwise the
20
+ * reader's own pick (if they've touched the switcher) wins over the host's
21
+ * declared default, and the host's `mode` (defaulting to 'auto') is the
22
+ * fallback for a reader who never has.
23
+ */
24
+ export const resolveTranslateMode = (
25
+ translates?: IConfig['translates'],
26
+ readerMode?: TranslateMode
27
+ ): TranslateMode => {
28
+ const hostDefault: TranslateMode = translates?.mode || 'auto';
29
+ if (translates?.forceType) {return hostDefault;}
30
+ return readerMode || hostDefault;
31
+ };