@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.
- package/CHANGELOG.md +80 -0
- package/README.md +3 -3
- package/index.js +1 -1
- package/lib/commonjs/components/MainComponents/ChatHeader.js +20 -8
- package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatWrapper.js +17 -0
- package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/LanguageSelectorButton.js +62 -0
- package/lib/commonjs/components/MainComponents/LanguageSelectorButton.js.map +1 -0
- package/lib/commonjs/components/MainComponents/LanguageSelectorModal.js +253 -0
- package/lib/commonjs/components/MainComponents/LanguageSelectorModal.js.map +1 -0
- package/lib/commonjs/components/MainComponents/MediaMessage.js +7 -1
- package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/commonjs/components/MainComponents/RoomList.js +23 -9
- package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/Message.js +72 -11
- package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/MessageTranslate.js +160 -0
- package/lib/commonjs/components/MessageBubble/MessageTranslate.js.map +1 -0
- package/lib/commonjs/components/MessageBubble/TranslatedMessageBody.js +59 -0
- package/lib/commonjs/components/MessageBubble/TranslatedMessageBody.js.map +1 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +3 -3
- package/lib/commonjs/components/UsersList/UsersList.js +3 -1
- package/lib/commonjs/components/UsersList/UsersList.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/CallButtons.js +159 -0
- package/lib/commonjs/components/VideoCalls/CallButtons.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/CallIcons.js +328 -0
- package/lib/commonjs/components/VideoCalls/CallIcons.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js +550 -0
- package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js +636 -0
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/livekitRuntime.js +91 -0
- package/lib/commonjs/components/VideoCalls/livekitRuntime.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/useCallKeep.js +215 -0
- package/lib/commonjs/components/VideoCalls/useCallKeep.js.map +1 -0
- package/lib/commonjs/components/styled/AudioMessage.js +91 -33
- package/lib/commonjs/components/styled/AudioMessage.js.map +1 -1
- package/lib/commonjs/components/styled/RoomListComponents/index.js +13 -1
- package/lib/commonjs/components/styled/RoomListComponents/index.js.map +1 -1
- package/lib/commonjs/components/styled/SendInput.js +83 -49
- package/lib/commonjs/components/styled/SendInput.js.map +1 -1
- package/lib/commonjs/components/styled/StyledComponents.js +9 -4
- package/lib/commonjs/components/styled/StyledComponents.js.map +1 -1
- package/lib/commonjs/components/styled/StyledInputComponents/Composing.js +2 -0
- package/lib/commonjs/components/styled/StyledInputComponents/Composing.js.map +1 -1
- package/lib/commonjs/components/styled/VideoMessage.js +110 -26
- package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
- package/lib/commonjs/context/xmppProvider.js +10 -3
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/helpers/callLogMessage.js +162 -0
- package/lib/commonjs/helpers/callLogMessage.js.map +1 -0
- package/lib/commonjs/helpers/callPush.js +61 -0
- package/lib/commonjs/helpers/callPush.js.map +1 -0
- package/lib/commonjs/helpers/constants/LANGUAGE_OPTIONS.js +24 -12
- package/lib/commonjs/helpers/constants/LANGUAGE_OPTIONS.js.map +1 -1
- package/lib/commonjs/helpers/createUserNameFromSetUser.js +51 -2
- package/lib/commonjs/helpers/createUserNameFromSetUser.js.map +1 -1
- package/lib/commonjs/helpers/getDataFromXml.js +19 -1
- package/lib/commonjs/helpers/getDataFromXml.js.map +1 -1
- package/lib/commonjs/helpers/incomingCallFromPush.js +74 -0
- package/lib/commonjs/helpers/incomingCallFromPush.js.map +1 -0
- package/lib/commonjs/helpers/insertMessageWithDelimiter.js +13 -1
- package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
- package/lib/commonjs/helpers/isUnresolvedSenderId.js +32 -0
- package/lib/commonjs/helpers/isUnresolvedSenderId.js.map +1 -0
- package/lib/commonjs/hooks/useChatSettingState.js +2 -0
- package/lib/commonjs/hooks/useChatSettingState.js.map +1 -1
- package/lib/commonjs/hooks/useMessageTranslation.js +51 -0
- package/lib/commonjs/hooks/useMessageTranslation.js.map +1 -0
- package/lib/commonjs/hooks/usePushNotifications.js +13 -3
- package/lib/commonjs/hooks/usePushNotifications.js.map +1 -1
- package/lib/commonjs/hooks/useSendMessage.js +14 -4
- package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
- package/lib/commonjs/i18n/strings.js +1308 -0
- package/lib/commonjs/i18n/strings.js.map +1 -0
- package/lib/commonjs/i18n/useT.js +60 -0
- package/lib/commonjs/i18n/useT.js.map +1 -0
- package/lib/commonjs/main.js +44 -0
- package/lib/commonjs/main.js.map +1 -1
- package/lib/commonjs/networking/api-requests/auth.api.js +81 -52
- package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
- package/lib/commonjs/networking/api-requests/push.api.js +34 -5
- package/lib/commonjs/networking/api-requests/push.api.js.map +1 -1
- package/lib/commonjs/networking/api-requests/rooms.api.js +108 -0
- package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
- package/lib/commonjs/networking/callTokenStanza.js +531 -0
- package/lib/commonjs/networking/callTokenStanza.js.map +1 -0
- package/lib/commonjs/networking/outboundQueue.js.map +1 -1
- package/lib/commonjs/networking/stanzaHandlers.js +75 -8
- package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
- package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +47 -11
- package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js +2 -1
- package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js +42 -5
- package/lib/commonjs/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmppClient.js +78 -16
- package/lib/commonjs/networking/xmppClient.js.map +1 -1
- package/lib/commonjs/roomStore/callSlice.js +144 -0
- package/lib/commonjs/roomStore/callSlice.js.map +1 -0
- package/lib/commonjs/roomStore/chatSettingsSlice.js +8 -2
- package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
- package/lib/commonjs/roomStore/index.js +7 -1
- package/lib/commonjs/roomStore/index.js.map +1 -1
- package/lib/commonjs/roomStore/persistence.js +69 -5
- package/lib/commonjs/roomStore/persistence.js.map +1 -1
- package/lib/commonjs/roomStore/roomsSlice.js +136 -6
- package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
- package/lib/commonjs/utils/translateModePolicy.js +33 -0
- package/lib/commonjs/utils/translateModePolicy.js.map +1 -0
- package/lib/module/components/MainComponents/ChatHeader.js +20 -8
- package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/module/components/MainComponents/ChatWrapper.js +17 -0
- package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/LanguageSelectorButton.js +57 -0
- package/lib/module/components/MainComponents/LanguageSelectorButton.js.map +1 -0
- package/lib/module/components/MainComponents/LanguageSelectorModal.js +246 -0
- package/lib/module/components/MainComponents/LanguageSelectorModal.js.map +1 -0
- package/lib/module/components/MainComponents/MediaMessage.js +7 -1
- package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/module/components/MainComponents/RoomList.js +23 -9
- package/lib/module/components/MainComponents/RoomList.js.map +1 -1
- package/lib/module/components/MessageBubble/Message.js +73 -12
- package/lib/module/components/MessageBubble/Message.js.map +1 -1
- package/lib/module/components/MessageBubble/MessageTranslate.js +155 -0
- package/lib/module/components/MessageBubble/MessageTranslate.js.map +1 -0
- package/lib/module/components/MessageBubble/TranslatedMessageBody.js +53 -0
- package/lib/module/components/MessageBubble/TranslatedMessageBody.js.map +1 -0
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +3 -3
- package/lib/module/components/UsersList/UsersList.js +3 -1
- package/lib/module/components/UsersList/UsersList.js.map +1 -1
- package/lib/module/components/VideoCalls/CallButtons.js +154 -0
- package/lib/module/components/VideoCalls/CallButtons.js.map +1 -0
- package/lib/module/components/VideoCalls/CallIcons.js +309 -0
- package/lib/module/components/VideoCalls/CallIcons.js.map +1 -0
- package/lib/module/components/VideoCalls/VideoCallOverlay.js +544 -0
- package/lib/module/components/VideoCalls/VideoCallOverlay.js.map +1 -0
- package/lib/module/components/VideoCalls/VideoCallSession.js +630 -0
- package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -0
- package/lib/module/components/VideoCalls/livekitRuntime.js +83 -0
- package/lib/module/components/VideoCalls/livekitRuntime.js.map +1 -0
- package/lib/module/components/VideoCalls/useCallKeep.js +210 -0
- package/lib/module/components/VideoCalls/useCallKeep.js.map +1 -0
- package/lib/module/components/styled/AudioMessage.js +91 -33
- package/lib/module/components/styled/AudioMessage.js.map +1 -1
- package/lib/module/components/styled/RoomListComponents/index.js +13 -1
- package/lib/module/components/styled/RoomListComponents/index.js.map +1 -1
- package/lib/module/components/styled/SendInput.js +83 -49
- package/lib/module/components/styled/SendInput.js.map +1 -1
- package/lib/module/components/styled/StyledComponents.js +9 -4
- package/lib/module/components/styled/StyledComponents.js.map +1 -1
- package/lib/module/components/styled/StyledInputComponents/Composing.js +2 -0
- package/lib/module/components/styled/StyledInputComponents/Composing.js.map +1 -1
- package/lib/module/components/styled/VideoMessage.js +111 -27
- package/lib/module/components/styled/VideoMessage.js.map +1 -1
- package/lib/module/context/xmppProvider.js +11 -4
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/helpers/callLogMessage.js +152 -0
- package/lib/module/helpers/callLogMessage.js.map +1 -0
- package/lib/module/helpers/callPush.js +55 -0
- package/lib/module/helpers/callPush.js.map +1 -0
- package/lib/module/helpers/constants/LANGUAGE_OPTIONS.js +24 -12
- package/lib/module/helpers/constants/LANGUAGE_OPTIONS.js.map +1 -1
- package/lib/module/helpers/createUserNameFromSetUser.js +49 -1
- package/lib/module/helpers/createUserNameFromSetUser.js.map +1 -1
- package/lib/module/helpers/getDataFromXml.js +20 -1
- package/lib/module/helpers/getDataFromXml.js.map +1 -1
- package/lib/module/helpers/incomingCallFromPush.js +70 -0
- package/lib/module/helpers/incomingCallFromPush.js.map +1 -0
- package/lib/module/helpers/insertMessageWithDelimiter.js +13 -1
- package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
- package/lib/module/helpers/isUnresolvedSenderId.js +27 -0
- package/lib/module/helpers/isUnresolvedSenderId.js.map +1 -0
- package/lib/module/hooks/useChatSettingState.js +2 -0
- package/lib/module/hooks/useChatSettingState.js.map +1 -1
- package/lib/module/hooks/useMessageTranslation.js +46 -0
- package/lib/module/hooks/useMessageTranslation.js.map +1 -0
- package/lib/module/hooks/usePushNotifications.js +13 -3
- package/lib/module/hooks/usePushNotifications.js.map +1 -1
- package/lib/module/hooks/useSendMessage.js +15 -5
- package/lib/module/hooks/useSendMessage.js.map +1 -1
- package/lib/module/i18n/strings.js +1300 -0
- package/lib/module/i18n/strings.js.map +1 -0
- package/lib/module/i18n/useT.js +55 -0
- package/lib/module/i18n/useT.js.map +1 -0
- package/lib/module/main.js +7 -1
- package/lib/module/main.js.map +1 -1
- package/lib/module/networking/api-requests/auth.api.js +80 -51
- package/lib/module/networking/api-requests/auth.api.js.map +1 -1
- package/lib/module/networking/api-requests/push.api.js +35 -5
- package/lib/module/networking/api-requests/push.api.js.map +1 -1
- package/lib/module/networking/api-requests/rooms.api.js +109 -1
- package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
- package/lib/module/networking/callTokenStanza.js +526 -0
- package/lib/module/networking/callTokenStanza.js.map +1 -0
- package/lib/module/networking/outboundQueue.js.map +1 -1
- package/lib/module/networking/stanzaHandlers.js +76 -9
- package/lib/module/networking/stanzaHandlers.js.map +1 -1
- package/lib/module/networking/xmpp/handleStanzas.xmpp.js +48 -11
- package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/sendTextMessage.xmpp.js +1 -1
- package/lib/module/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js +43 -5
- package/lib/module/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js.map +1 -1
- package/lib/module/networking/xmppClient.js +78 -16
- package/lib/module/networking/xmppClient.js.map +1 -1
- package/lib/module/roomStore/callSlice.js +130 -0
- package/lib/module/roomStore/callSlice.js.map +1 -0
- package/lib/module/roomStore/chatSettingsSlice.js +6 -1
- package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
- package/lib/module/roomStore/index.js +6 -1
- package/lib/module/roomStore/index.js.map +1 -1
- package/lib/module/roomStore/persistence.js +69 -5
- package/lib/module/roomStore/persistence.js.map +1 -1
- package/lib/module/roomStore/roomsSlice.js +134 -5
- package/lib/module/roomStore/roomsSlice.js.map +1 -1
- package/lib/module/utils/translateModePolicy.js +27 -0
- package/lib/module/utils/translateModePolicy.js.map +1 -0
- package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/LanguageSelectorButton.d.ts +12 -0
- package/lib/typescript/components/MainComponents/LanguageSelectorButton.d.ts.map +1 -0
- package/lib/typescript/components/MainComponents/LanguageSelectorModal.d.ts +31 -0
- package/lib/typescript/components/MainComponents/LanguageSelectorModal.d.ts.map +1 -0
- package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/MessageTranslate.d.ts +44 -0
- package/lib/typescript/components/MessageBubble/MessageTranslate.d.ts.map +1 -0
- package/lib/typescript/components/MessageBubble/TranslatedMessageBody.d.ts +24 -0
- package/lib/typescript/components/MessageBubble/TranslatedMessageBody.d.ts.map +1 -0
- package/lib/typescript/components/UsersList/UsersList.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/CallButtons.d.ts +16 -0
- package/lib/typescript/components/VideoCalls/CallButtons.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/CallIcons.d.ts +30 -0
- package/lib/typescript/components/VideoCalls/CallIcons.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts +10 -0
- package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts +38 -0
- package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts +52 -0
- package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/useCallKeep.d.ts +32 -0
- package/lib/typescript/components/VideoCalls/useCallKeep.d.ts.map +1 -0
- package/lib/typescript/components/styled/AudioMessage.d.ts.map +1 -1
- package/lib/typescript/components/styled/RoomListComponents/index.d.ts.map +1 -1
- package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
- package/lib/typescript/components/styled/StyledComponents.d.ts.map +1 -1
- package/lib/typescript/components/styled/StyledInputComponents/Composing.d.ts.map +1 -1
- package/lib/typescript/components/styled/VideoMessage.d.ts +2 -0
- package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
- package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
- package/lib/typescript/helpers/callLogMessage.d.ts +34 -0
- package/lib/typescript/helpers/callLogMessage.d.ts.map +1 -0
- package/lib/typescript/helpers/callPush.d.ts +23 -0
- package/lib/typescript/helpers/callPush.d.ts.map +1 -0
- package/lib/typescript/helpers/constants/LANGUAGE_OPTIONS.d.ts +14 -0
- package/lib/typescript/helpers/constants/LANGUAGE_OPTIONS.d.ts.map +1 -1
- package/lib/typescript/helpers/createUserNameFromSetUser.d.ts +33 -1
- package/lib/typescript/helpers/createUserNameFromSetUser.d.ts.map +1 -1
- package/lib/typescript/helpers/getDataFromXml.d.ts.map +1 -1
- package/lib/typescript/helpers/incomingCallFromPush.d.ts +14 -0
- package/lib/typescript/helpers/incomingCallFromPush.d.ts.map +1 -0
- package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
- package/lib/typescript/helpers/isUnresolvedSenderId.d.ts +2 -0
- package/lib/typescript/helpers/isUnresolvedSenderId.d.ts.map +1 -0
- package/lib/typescript/hooks/useChatSettingState.d.ts +2 -1
- package/lib/typescript/hooks/useChatSettingState.d.ts.map +1 -1
- package/lib/typescript/hooks/useMessageTranslation.d.ts +25 -0
- package/lib/typescript/hooks/useMessageTranslation.d.ts.map +1 -0
- package/lib/typescript/hooks/usePushNotifications.d.ts.map +1 -1
- package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/i18n/strings.d.ts +16 -0
- package/lib/typescript/i18n/strings.d.ts.map +1 -0
- package/lib/typescript/i18n/useT.d.ts +34 -0
- package/lib/typescript/i18n/useT.d.ts.map +1 -0
- package/lib/typescript/main.d.ts +6 -1
- package/lib/typescript/main.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/auth.api.d.ts +27 -1
- package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/push.api.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/rooms.api.d.ts +3 -0
- package/lib/typescript/networking/api-requests/rooms.api.d.ts.map +1 -1
- package/lib/typescript/networking/callTokenStanza.d.ts +14 -0
- package/lib/typescript/networking/callTokenStanza.d.ts.map +1 -0
- package/lib/typescript/networking/outboundQueue.d.ts +1 -0
- package/lib/typescript/networking/outboundQueue.d.ts.map +1 -1
- package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/sendTextMessage.xmpp.d.ts +10 -0
- package/lib/typescript/networking/xmpp/sendTextMessage.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.d.ts +16 -1
- package/lib/typescript/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmppClient.d.ts +1 -1
- package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
- package/lib/typescript/roomStore/callSlice.d.ts +39 -0
- package/lib/typescript/roomStore/callSlice.d.ts.map +1 -0
- package/lib/typescript/roomStore/chatSettingsSlice.d.ts +10 -1
- package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
- package/lib/typescript/roomStore/index.d.ts +4 -0
- package/lib/typescript/roomStore/index.d.ts.map +1 -1
- package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts +6 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
- package/lib/typescript/types/models/language.model.d.ts +1 -1
- package/lib/typescript/types/models/language.model.d.ts.map +1 -1
- package/lib/typescript/types/models/message.model.d.ts +7 -0
- package/lib/typescript/types/models/message.model.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +135 -1
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/lib/typescript/utils/translateModePolicy.d.ts +20 -0
- package/lib/typescript/utils/translateModePolicy.d.ts.map +1 -0
- package/package.json +20 -4
- package/src/components/MainComponents/ChatHeader.tsx +30 -9
- package/src/components/MainComponents/ChatWrapper.tsx +15 -0
- package/src/components/MainComponents/LanguageSelectorButton.tsx +53 -0
- package/src/components/MainComponents/LanguageSelectorModal.tsx +276 -0
- package/src/components/MainComponents/MediaMessage.tsx +5 -0
- package/src/components/MainComponents/RoomList.tsx +27 -9
- package/src/components/MessageBubble/Message.tsx +109 -17
- package/src/components/MessageBubble/MessageTranslate.tsx +182 -0
- package/src/components/MessageBubble/TranslatedMessageBody.tsx +59 -0
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +3 -3
- package/src/components/UsersList/UsersList.tsx +3 -1
- package/src/components/VideoCalls/CallButtons.tsx +171 -0
- package/src/components/VideoCalls/CallIcons.tsx +246 -0
- package/src/components/VideoCalls/VideoCallOverlay.tsx +627 -0
- package/src/components/VideoCalls/VideoCallSession.tsx +675 -0
- package/src/components/VideoCalls/livekitRuntime.ts +100 -0
- package/src/components/VideoCalls/useCallKeep.ts +252 -0
- package/src/components/styled/AudioMessage.tsx +97 -37
- package/src/components/styled/RoomListComponents/index.tsx +15 -3
- package/src/components/styled/SendInput.tsx +94 -51
- package/src/components/styled/StyledComponents.ts +9 -6
- package/src/components/styled/StyledInputComponents/Composing.tsx +7 -1
- package/src/components/styled/VideoMessage.tsx +114 -20
- package/src/context/xmppProvider.tsx +14 -1
- package/src/helpers/callLogMessage.ts +174 -0
- package/src/helpers/callPush.ts +90 -0
- package/src/helpers/constants/LANGUAGE_OPTIONS.ts +20 -5
- package/src/helpers/createUserNameFromSetUser.ts +68 -2
- package/src/helpers/getDataFromXml.ts +40 -4
- package/src/helpers/incomingCallFromPush.ts +83 -0
- package/src/helpers/insertMessageWithDelimiter.ts +27 -9
- package/src/helpers/isUnresolvedSenderId.ts +25 -0
- package/src/hooks/useChatSettingState.tsx +4 -0
- package/src/hooks/useMessageTranslation.ts +70 -0
- package/src/hooks/usePushNotifications.ts +15 -3
- package/src/hooks/useSendMessage.tsx +18 -5
- package/src/i18n/strings.ts +1322 -0
- package/src/i18n/useT.ts +56 -0
- package/src/main.ts +18 -1
- package/src/networking/api-requests/auth.api.ts +79 -44
- package/src/networking/api-requests/push.api.ts +39 -8
- package/src/networking/api-requests/rooms.api.ts +109 -1
- package/src/networking/callTokenStanza.ts +636 -0
- package/src/networking/outboundQueue.ts +1 -0
- package/src/networking/stanzaHandlers.ts +74 -15
- package/src/networking/xmpp/handleStanzas.xmpp.ts +52 -11
- package/src/networking/xmpp/sendTextMessage.xmpp.ts +1 -1
- package/src/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.ts +41 -5
- package/src/networking/xmppClient.ts +97 -28
- package/src/roomStore/callSlice.ts +190 -0
- package/src/roomStore/chatSettingsSlice.ts +16 -0
- package/src/roomStore/index.ts +5 -0
- package/src/roomStore/persistence.ts +103 -3
- package/src/roomStore/roomsSlice.ts +149 -4
- package/src/types/models/language.model.ts +17 -1
- package/src/types/models/message.model.ts +9 -0
- package/src/types/types.ts +142 -2
- package/src/utils/translateModePolicy.ts +31 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { IMessage } from '../types/types';
|
|
2
|
+
|
|
3
|
+
// A server "call-state" stanza is emitted into the room when a call session
|
|
4
|
+
// concludes (someone leaves the LiveKit room). It carries:
|
|
5
|
+
// type="call-state" callId="..." durationMs="<ms>"
|
|
6
|
+
// callerXmppUsername="<who started the call>" isSystemMessage="true"
|
|
7
|
+
// We turn it into a friendly chat-log entry, Telegram/WhatsApp style:
|
|
8
|
+
// - durationMs > 0 -> "Outgoing call · 12 sec" / "Incoming call · 1 min"
|
|
9
|
+
// - durationMs == 0 -> "No answer" (we called) / "Missed call" (they called)
|
|
10
|
+
// Direction is derived from callerXmppUsername vs the logged-in user.
|
|
11
|
+
|
|
12
|
+
export interface CallLogMeta {
|
|
13
|
+
callId: string;
|
|
14
|
+
direction: 'outgoing' | 'incoming';
|
|
15
|
+
durationMs: number;
|
|
16
|
+
missed: boolean;
|
|
17
|
+
kind: 'audio' | 'video';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const isCallLogMessage = (message: unknown): boolean => {
|
|
21
|
+
const type = String((message as any)?.type || '').toLowerCase();
|
|
22
|
+
return type === 'call-state';
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Only a call-state that actually carries log metadata (a caller and/or a
|
|
26
|
+
// duration) is worth rendering. Bare client-side signaling frames
|
|
27
|
+
// (state=cancelled/declined/ended with no caller/duration) must NOT become
|
|
28
|
+
// chat entries, they're real-time teardown only.
|
|
29
|
+
export const callStateHasLogData = (attrs: Record<string, any>): boolean => {
|
|
30
|
+
if (!attrs) {return false;}
|
|
31
|
+
const hasCaller = !!String(attrs.callerXmppUsername || '').trim();
|
|
32
|
+
const hasDuration =
|
|
33
|
+
attrs.durationMs !== undefined &&
|
|
34
|
+
attrs.durationMs !== null &&
|
|
35
|
+
attrs.durationMs !== '';
|
|
36
|
+
return hasCaller || hasDuration;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const formatCallDuration = (ms: number): string => {
|
|
40
|
+
const totalSeconds = Math.max(0, Math.round(ms / 1000));
|
|
41
|
+
if (totalSeconds < 60) {return `${totalSeconds} sec`;}
|
|
42
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
43
|
+
const seconds = totalSeconds % 60;
|
|
44
|
+
if (seconds === 0) {return `${minutes} min`;}
|
|
45
|
+
return `${minutes} min ${seconds} sec`;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const transformCallLogMessage = (
|
|
49
|
+
message: IMessage,
|
|
50
|
+
selfXmppUsername: string
|
|
51
|
+
): IMessage => {
|
|
52
|
+
if (!isCallLogMessage(message)) {return message;}
|
|
53
|
+
|
|
54
|
+
const raw = message as any;
|
|
55
|
+
const callerLocal = String(raw.callerXmppUsername || '')
|
|
56
|
+
.split('@')[0]
|
|
57
|
+
.trim();
|
|
58
|
+
const selfLocal = String(selfXmppUsername || '').split('@')[0].trim();
|
|
59
|
+
// When we know the caller, "outgoing" means we started it. With no
|
|
60
|
+
// caller info, default to incoming (safer label than claiming we dialed).
|
|
61
|
+
const isOutgoing = !!callerLocal && callerLocal === selfLocal;
|
|
62
|
+
const durationMs = Number(raw.durationMs || 0);
|
|
63
|
+
const kind: 'audio' | 'video' =
|
|
64
|
+
String(raw.kind || '').toLowerCase() === 'audio' ? 'audio' : 'video';
|
|
65
|
+
|
|
66
|
+
let body: string;
|
|
67
|
+
if (durationMs > 0) {
|
|
68
|
+
body = `${isOutgoing ? 'Outgoing' : 'Incoming'} call · ${formatCallDuration(durationMs)}`;
|
|
69
|
+
} else {
|
|
70
|
+
body = isOutgoing ? 'No answer' : 'Missed call';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const callLog: CallLogMeta = {
|
|
74
|
+
callId: String(raw.callId || raw.callid || '').trim(),
|
|
75
|
+
direction: isOutgoing ? 'outgoing' : 'incoming',
|
|
76
|
+
durationMs,
|
|
77
|
+
missed: durationMs === 0,
|
|
78
|
+
kind,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
...message,
|
|
83
|
+
body,
|
|
84
|
+
// Render through the existing centered SystemMessage pipeline.
|
|
85
|
+
isSystemMessage: 'true',
|
|
86
|
+
callLog,
|
|
87
|
+
} as IMessage;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Build a "call ended" log entry locally (client-side) when a call finishes.
|
|
91
|
+
// The authoritative entry is a SERVER `call-state` broadcast, but that isn't
|
|
92
|
+
// guaranteed to arrive (see header comment). This fallback keeps the chat log
|
|
93
|
+
// working regardless. It's deduplicated against any server copy in
|
|
94
|
+
// `addRoomMessage` by `callLog.callId` (the entry with the largest duration
|
|
95
|
+
// wins), so if the server does broadcast, the two collapse into one.
|
|
96
|
+
export const buildLocalCallLogMessage = (params: {
|
|
97
|
+
callId: string;
|
|
98
|
+
direction: 'outgoing' | 'incoming';
|
|
99
|
+
durationMs: number;
|
|
100
|
+
kind: 'audio' | 'video';
|
|
101
|
+
selfXmppUsername: string;
|
|
102
|
+
}): IMessage => {
|
|
103
|
+
const { callId, direction, durationMs, kind, selfXmppUsername } = params;
|
|
104
|
+
const isOutgoing = direction === 'outgoing';
|
|
105
|
+
const safeDuration = Math.max(0, Math.round(durationMs || 0));
|
|
106
|
+
|
|
107
|
+
let body: string;
|
|
108
|
+
if (safeDuration > 0) {
|
|
109
|
+
body = `${isOutgoing ? 'Outgoing' : 'Incoming'} call · ${formatCallDuration(safeDuration)}`;
|
|
110
|
+
} else {
|
|
111
|
+
body = isOutgoing ? 'No answer' : 'Missed call';
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const callLog: CallLogMeta = {
|
|
115
|
+
callId,
|
|
116
|
+
direction,
|
|
117
|
+
durationMs: safeDuration,
|
|
118
|
+
missed: safeDuration === 0,
|
|
119
|
+
kind,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
// Deterministic id so a re-fire for the same call collapses in place.
|
|
124
|
+
id: callId ? `calllog-${callId}` : `calllog-${Date.now()}`,
|
|
125
|
+
body,
|
|
126
|
+
date: new Date().toISOString(),
|
|
127
|
+
isSystemMessage: 'true',
|
|
128
|
+
type: 'call-state',
|
|
129
|
+
callLog,
|
|
130
|
+
user: { id: selfXmppUsername },
|
|
131
|
+
} as unknown as IMessage;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The label for a call-log entry, built at RENDER time from the callLog
|
|
136
|
+
* meta rather than read off `message.body`.
|
|
137
|
+
*
|
|
138
|
+
* transformCallLogMessage bakes an English sentence into `body` the moment
|
|
139
|
+
* the stanza arrives, which freezes the language: switch to French and
|
|
140
|
+
* every call log you already received stays English forever, because the
|
|
141
|
+
* text is data by then, not a rendering. The meta (direction/duration/
|
|
142
|
+
* missed) is the actual fact, the sentence is a view of it, so it belongs
|
|
143
|
+
* where the view is. `body` stays as the fallback for entries received
|
|
144
|
+
* before this existed, and for the notification/room-list preview paths
|
|
145
|
+
* that only have the raw message.
|
|
146
|
+
*/
|
|
147
|
+
export const formatCallLogLabel = (
|
|
148
|
+
callLog: CallLogMeta | undefined,
|
|
149
|
+
t: (key: string, vars?: Record<string, string | number>) => string,
|
|
150
|
+
fallbackBody = ''
|
|
151
|
+
): string => {
|
|
152
|
+
if (!callLog) {return fallbackBody;}
|
|
153
|
+
|
|
154
|
+
if (!callLog.durationMs || callLog.durationMs <= 0) {
|
|
155
|
+
return callLog.direction === 'outgoing'
|
|
156
|
+
? t('call.noAnswer')
|
|
157
|
+
: t('call.missed');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const totalSeconds = Math.max(0, Math.round(callLog.durationMs / 1000));
|
|
161
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
162
|
+
const seconds = totalSeconds % 60;
|
|
163
|
+
const duration =
|
|
164
|
+
totalSeconds < 60
|
|
165
|
+
? t('call.durationSec', { n: totalSeconds })
|
|
166
|
+
: seconds === 0
|
|
167
|
+
? t('call.durationMin', { n: minutes })
|
|
168
|
+
: t('call.durationMinSec', { m: minutes, s: seconds });
|
|
169
|
+
|
|
170
|
+
const direction =
|
|
171
|
+
callLog.direction === 'outgoing' ? t('call.outgoing') : t('call.incoming');
|
|
172
|
+
|
|
173
|
+
return `${direction} · ${duration}`;
|
|
174
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Recognise and parse an *incoming call* push notification.
|
|
2
|
+
//
|
|
3
|
+
// Calls normally ring via a live XMPP `call-token` stanza, which only arrives
|
|
4
|
+
// while the socket is connected. On mobile the socket is dead whenever the OS
|
|
5
|
+
// backgrounds or kills the app, so the backend also delivers the call over
|
|
6
|
+
// push, in the same `data`-payload format as message pushes. This helper lets
|
|
7
|
+
// the push layer tell a call push apart from a chat push and pull the call
|
|
8
|
+
// fields out, tolerating the field-name variations backends tend to use.
|
|
9
|
+
|
|
10
|
+
export interface ParsedCallPush {
|
|
11
|
+
callId: string | null;
|
|
12
|
+
/** LiveKit token, if the push carried one (lets us ring + accept offline). */
|
|
13
|
+
token: string | null;
|
|
14
|
+
kind: 'audio' | 'video';
|
|
15
|
+
/** Bare room name (JID localpart) the call belongs to. */
|
|
16
|
+
roomBareName: string | null;
|
|
17
|
+
/** Raw room reference from the payload (full JID or bare name). */
|
|
18
|
+
roomRef: string | null;
|
|
19
|
+
/** Display name for the ring screen (caller). */
|
|
20
|
+
callerName: string | null;
|
|
21
|
+
/** Caller's xmpp localpart, when provided. */
|
|
22
|
+
callerXmppUsername: string | null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const pick = (data: Record<string, any>, keys: string[]): string => {
|
|
26
|
+
for (const k of keys) {
|
|
27
|
+
const v = data?.[k];
|
|
28
|
+
if (v !== undefined && v !== null && String(v).trim() !== '') {
|
|
29
|
+
return String(v).trim();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return '';
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* True when a push `data` payload represents an incoming call. Matches on an
|
|
37
|
+
* explicit call marker (`type`/`pushType`/`category`/`event` === "call"-ish)
|
|
38
|
+
* or on a callId paired with a call-specific field, so a normal message push
|
|
39
|
+
* is never misread as a call.
|
|
40
|
+
*/
|
|
41
|
+
export const isCallPush = (
|
|
42
|
+
data: Record<string, any> | null | undefined
|
|
43
|
+
): boolean => {
|
|
44
|
+
if (!data) {return false;}
|
|
45
|
+
const marker = pick(data, [
|
|
46
|
+
'type',
|
|
47
|
+
'pushType',
|
|
48
|
+
'category',
|
|
49
|
+
'messageType',
|
|
50
|
+
'event',
|
|
51
|
+
]).toLowerCase();
|
|
52
|
+
if (
|
|
53
|
+
marker === 'call' ||
|
|
54
|
+
marker === 'incoming-call' ||
|
|
55
|
+
marker === 'call-token' ||
|
|
56
|
+
marker === 'call-invite'
|
|
57
|
+
) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
const callId = pick(data, ['callId', 'callid', 'callID']);
|
|
61
|
+
const hasCallField =
|
|
62
|
+
!!pick(data, ['callToken', 'livekitToken']) ||
|
|
63
|
+
!!pick(data, ['callKind']) ||
|
|
64
|
+
pick(data, ['kind']).toLowerCase() === 'audio' ||
|
|
65
|
+
pick(data, ['kind']).toLowerCase() === 'video';
|
|
66
|
+
return !!callId && hasCallField;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const parseCallPush = (
|
|
70
|
+
data: Record<string, any> | null | undefined
|
|
71
|
+
): ParsedCallPush => {
|
|
72
|
+
const d = data || {};
|
|
73
|
+
const roomRef =
|
|
74
|
+
pick(d, ['callRoom', 'room', 'roomJid', 'jid', 'chatId']) || null;
|
|
75
|
+
const roomBareName = roomRef ? roomRef.split('@')[0] || roomRef : null;
|
|
76
|
+
const kindRaw = pick(d, ['callKind', 'kind']).toLowerCase();
|
|
77
|
+
return {
|
|
78
|
+
callId: pick(d, ['callId', 'callid', 'callID']) || null,
|
|
79
|
+
token: pick(d, ['callToken', 'livekitToken', 'token']) || null,
|
|
80
|
+
kind: kindRaw === 'audio' ? 'audio' : 'video',
|
|
81
|
+
roomBareName,
|
|
82
|
+
roomRef,
|
|
83
|
+
callerName:
|
|
84
|
+
pick(d, ['callerName', 'callerDisplayName', 'senderName', 'title']) ||
|
|
85
|
+
null,
|
|
86
|
+
callerXmppUsername:
|
|
87
|
+
pick(d, ['callerXmppUsername', 'callerUsername', 'userJid', 'senderJid'])
|
|
88
|
+
.split('@')[0] || null,
|
|
89
|
+
};
|
|
90
|
+
};
|
|
@@ -5,10 +5,25 @@ type LanguageOption = {
|
|
|
5
5
|
id: Iso639_1Codes;
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Languages the in-chat globe picker offers.
|
|
10
|
+
*
|
|
11
|
+
* Names are AUTONYMS (each language written in itself), which is what
|
|
12
|
+
* every mainstream language picker does: a reader who only speaks French
|
|
13
|
+
* can find "Français" but not "French". Ids carry the region because the
|
|
14
|
+
* deployment's readers are Canadian and US, and the region is forwarded to
|
|
15
|
+
* the translation service so it can tell fr-CA from fr-FR. Base-language
|
|
16
|
+
* lookups (i18n tables, Translate-button visibility) strip it via
|
|
17
|
+
* toBaseLanguage, so both forms interoperate.
|
|
18
|
+
*
|
|
19
|
+
* Commented-out entries still have full string tables in i18n/strings.ts,
|
|
20
|
+
* they're just not offered to readers in the current deployment.
|
|
21
|
+
*/
|
|
8
22
|
export const LANGUAGE_OPTIONS: LanguageOption[] = [
|
|
9
|
-
{ name: 'English', id: 'en' },
|
|
10
|
-
{ name: '
|
|
11
|
-
{ name: '
|
|
12
|
-
{ name: '
|
|
13
|
-
{ name: '
|
|
23
|
+
{ name: 'English', id: 'en-CA' },
|
|
24
|
+
{ name: 'Español', id: 'es-US' },
|
|
25
|
+
{ name: 'Français', id: 'fr-CA' },
|
|
26
|
+
// { name: 'Português', id: 'pt' },
|
|
27
|
+
// { name: 'Kreyòl ayisyen', id: 'ht' },
|
|
28
|
+
// { name: '中文', id: 'zh' },
|
|
14
29
|
];
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import { RoomMember } from '../types/types';
|
|
1
|
+
import { IMessage, RoomMember } from '../types/types';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Cache-only lookup. Returns the literal "Deleted User" as a MISS sentinel
|
|
5
|
+
* when `usersSet` has no entry for `userId` yet, callers that want a
|
|
6
|
+
* better fallback (e.g. resolveSenderDisplayName below) check for that
|
|
7
|
+
* exact string rather than treating it as a real name.
|
|
8
|
+
*/
|
|
3
9
|
export const createUserNameFromSetUser = (
|
|
4
10
|
usersSet: Record<string, RoomMember>,
|
|
5
11
|
userId: string
|
|
@@ -10,6 +16,66 @@ export const createUserNameFromSetUser = (
|
|
|
10
16
|
|
|
11
17
|
const firstName = user.firstName?.trim() || '';
|
|
12
18
|
const lastName = user.lastName?.trim() || '';
|
|
19
|
+
// REST-loaded members carry firstName/lastName; XMPP-roster-only
|
|
20
|
+
// members (no REST match yet) carry just the roster `name` attr —
|
|
21
|
+
// fall back to that before giving up and returning the raw id.
|
|
22
|
+
const bareName = user.name?.trim() || '';
|
|
13
23
|
|
|
14
|
-
return `${firstName} ${lastName}`.trim() || userId;
|
|
24
|
+
return `${firstName} ${lastName}`.trim() || bareName || userId;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The sender's display name, resolved WITHOUT depending on `usersSet`
|
|
29
|
+
* having already been hydrated.
|
|
30
|
+
*
|
|
31
|
+
* `usersSet` is populated by a separate fetch (member list / presence) that
|
|
32
|
+
* can still be in flight when a message arrives, most reliably right after
|
|
33
|
+
* reconnect, when a burst of catch-up messages can land before that fetch
|
|
34
|
+
* resolves. A cache-only lookup shows the literal "Deleted User" for every
|
|
35
|
+
* one of those messages, even though the sender is very much not deleted.
|
|
36
|
+
* On mobile this is the common case, not the rare one: every return from
|
|
37
|
+
* background reconnects.
|
|
38
|
+
*
|
|
39
|
+
* The message itself already carries the sender's name on the wire: every
|
|
40
|
+
* client that sends through this SDK stamps `senderFirstName` /
|
|
41
|
+
* `senderLastName` / `fullName` onto the outgoing stanza's `<data>` element
|
|
42
|
+
* (see sendTextMessage.xmpp.ts / sendTextMessageWithTranslateTag.xmpp.ts),
|
|
43
|
+
* and createMessageFromXml spreads those onto the top-level message object.
|
|
44
|
+
* Preferring that over the cache removes the timing dependency entirely for
|
|
45
|
+
* the common case, and "Deleted User" becomes what it should have always
|
|
46
|
+
* been: a rare last resort, not "usersSet hasn't loaded yet".
|
|
47
|
+
*/
|
|
48
|
+
export const resolveSenderDisplayName = (
|
|
49
|
+
message: Pick<IMessage, 'user'> & {
|
|
50
|
+
fullName?: string;
|
|
51
|
+
senderFirstName?: string;
|
|
52
|
+
senderLastName?: string;
|
|
53
|
+
},
|
|
54
|
+
usersSet: Record<string, RoomMember>
|
|
55
|
+
): string => {
|
|
56
|
+
const rawUserId = String(message?.user?.id || '');
|
|
57
|
+
const localUserId = rawUserId.split('@')[0];
|
|
58
|
+
const currentNameRaw = String(message?.user?.name || '').trim();
|
|
59
|
+
// A previously-resolved "Deleted User" is itself a miss sentinel, not a
|
|
60
|
+
// real name, don't let it short-circuit the fallback chain below.
|
|
61
|
+
const currentName = currentNameRaw === 'Deleted User' ? '' : currentNameRaw;
|
|
62
|
+
|
|
63
|
+
const dataFullName = String(message?.fullName || '').trim();
|
|
64
|
+
const dataFirst = String(message?.senderFirstName || '').trim();
|
|
65
|
+
const dataLast = String(message?.senderLastName || '').trim();
|
|
66
|
+
const composedFromData = dataFullName || `${dataFirst} ${dataLast}`.trim();
|
|
67
|
+
|
|
68
|
+
const usersSetName = createUserNameFromSetUser(usersSet, localUserId);
|
|
69
|
+
const usersSetNameAlt = createUserNameFromSetUser(usersSet, rawUserId);
|
|
70
|
+
const isUsersSetUseful = (name: string) => !!name && name !== 'Deleted User';
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
currentName ||
|
|
74
|
+
(isUsersSetUseful(usersSetName) && usersSetName) ||
|
|
75
|
+
(isUsersSetUseful(usersSetNameAlt) && usersSetNameAlt) ||
|
|
76
|
+
composedFromData ||
|
|
77
|
+
localUserId ||
|
|
78
|
+
rawUserId ||
|
|
79
|
+
'Deleted User'
|
|
80
|
+
);
|
|
15
81
|
};
|
|
@@ -2,6 +2,38 @@ import { Element } from 'ltx';
|
|
|
2
2
|
import { Iso639_1Codes, IUser } from '../types/types';
|
|
3
3
|
import { transformArrayToObject } from './transformTranslatations';
|
|
4
4
|
|
|
5
|
+
// Tolerant JSON parse: a malformed `translations` attr must not reject the
|
|
6
|
+
// whole stanza (which would silently drop the message). Mirrors the web
|
|
7
|
+
// SDK's safeJsonParse.
|
|
8
|
+
const safeJsonParse = <T,>(value: unknown, fallback: T): T => {
|
|
9
|
+
if (typeof value !== 'string' || !value) {return fallback;}
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(value) as T;
|
|
12
|
+
} catch {
|
|
13
|
+
return fallback;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// Keep only well-formed translation entries (drops partial/garbage items),
|
|
18
|
+
// same shape guard the web SDK applies before transformArrayToObject.
|
|
19
|
+
const normalizeTranslations = (value: unknown) =>
|
|
20
|
+
Array.isArray(value)
|
|
21
|
+
? value.filter(
|
|
22
|
+
(
|
|
23
|
+
item
|
|
24
|
+
): item is {
|
|
25
|
+
translatedText: string;
|
|
26
|
+
language: string;
|
|
27
|
+
languageName: string;
|
|
28
|
+
} =>
|
|
29
|
+
!!item &&
|
|
30
|
+
typeof item === 'object' &&
|
|
31
|
+
typeof (item as any).translatedText === 'string' &&
|
|
32
|
+
typeof (item as any).language === 'string' &&
|
|
33
|
+
typeof (item as any).languageName === 'string'
|
|
34
|
+
)
|
|
35
|
+
: [];
|
|
36
|
+
|
|
5
37
|
const extractTimestamp = (str: string, stanza?: any): string | null => {
|
|
6
38
|
if (!str) {return null;}
|
|
7
39
|
if (typeof str !== 'string') {
|
|
@@ -43,12 +75,16 @@ export const getDataFromXml = async (stanza: Element): Promise<DataXml | undefin
|
|
|
43
75
|
|
|
44
76
|
const body = fullData?.getChild('body')?.getText() || undefined;
|
|
45
77
|
const deleted = !!fullData?.getChild('deleted');
|
|
78
|
+
const translationPayload = safeJsonParse<{ translates?: unknown[] }>(
|
|
79
|
+
fullData?.getChild('translations')?.attrs?.value,
|
|
80
|
+
{}
|
|
81
|
+
);
|
|
46
82
|
const translations = fullData?.getChild('translations')?.attrs?.value
|
|
47
|
-
? transformArrayToObject(
|
|
48
|
-
JSON.parse(fullData.getChild('translations')!.attrs.value).translates
|
|
49
|
-
)
|
|
83
|
+
? transformArrayToObject(normalizeTranslations(translationPayload.translates))
|
|
50
84
|
: undefined;
|
|
51
|
-
const langSource = fullData?.getChild('translate')?.attrs?.source
|
|
85
|
+
const langSource = fullData?.getChild('translate')?.attrs?.source as
|
|
86
|
+
| Iso639_1Codes
|
|
87
|
+
| undefined;
|
|
52
88
|
const numericPart = /\d{13,}/.exec(id || '')?.[0];
|
|
53
89
|
const date = numericPart
|
|
54
90
|
? new Date(+numericPart.slice(0, 13)).toISOString()
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { store } from '../roomStore';
|
|
2
|
+
import { setIncomingCallToken } from '../roomStore/callSlice';
|
|
3
|
+
import { isCallPush, parseCallPush } from './callPush';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Turn an incoming-call push into a ringing call.
|
|
7
|
+
*
|
|
8
|
+
* On mobile the XMPP socket dies whenever the OS backgrounds or kills the
|
|
9
|
+
* app, and the `call-token` stanza that normally opens the ring screen is
|
|
10
|
+
* lost with it. The backend also delivers the call as a data push, so this
|
|
11
|
+
* is the path every call takes when the app was not in the foreground.
|
|
12
|
+
*
|
|
13
|
+
* Returns true when the payload WAS a call push (whether or not it could
|
|
14
|
+
* be rung), so the caller knows to stop and not also show it as a chat
|
|
15
|
+
* notification. A user should never get a "new message: call-state" toast.
|
|
16
|
+
*/
|
|
17
|
+
export const handleCallPush = (
|
|
18
|
+
data: Record<string, any> | null | undefined
|
|
19
|
+
): boolean => {
|
|
20
|
+
if (!isCallPush(data)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const parsed = parseCallPush(data);
|
|
25
|
+
const state = store.getState();
|
|
26
|
+
|
|
27
|
+
// Calls off in this deployment: swallow the push rather than ringing a
|
|
28
|
+
// screen the host never opted into.
|
|
29
|
+
if (state.chatSettingStore.config?.videoCalls?.enabled !== true) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Already ringing or in this exact call (the push raced the stanza, or
|
|
34
|
+
// two pushes arrived). Re-dispatching would reset startedAt and restart
|
|
35
|
+
// the ring, so leave the existing call alone.
|
|
36
|
+
const current = state.call;
|
|
37
|
+
if (current.phase !== 'idle') {
|
|
38
|
+
const sameCall =
|
|
39
|
+
(!!parsed.callId && parsed.callId === current.callId) ||
|
|
40
|
+
(!!parsed.roomBareName && parsed.roomBareName === current.roomBareName);
|
|
41
|
+
if (sameCall || current.phase === 'in-call') {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Without a LiveKit token there is nothing to accept: the push is only
|
|
47
|
+
// an alert. Ringing anyway would give the user an Accept button that
|
|
48
|
+
// cannot work, so treat it as handled and let the stanza (once the
|
|
49
|
+
// socket is back up) open the real ring screen.
|
|
50
|
+
if (!parsed.token) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Resolve the full room JID from the local room map. The push carries
|
|
55
|
+
// the bare name; callSlice and the hangup signal both want the JID.
|
|
56
|
+
const rooms = state.rooms.rooms || {};
|
|
57
|
+
const resolved = Object.values(rooms).find(
|
|
58
|
+
(room: any) =>
|
|
59
|
+
(room?.jid || '').split('@')[0] === parsed.roomBareName ||
|
|
60
|
+
room?.jid === parsed.roomRef
|
|
61
|
+
) as { jid?: string; name?: string } | undefined;
|
|
62
|
+
|
|
63
|
+
const roomJid =
|
|
64
|
+
resolved?.jid ||
|
|
65
|
+
(parsed.roomRef && parsed.roomRef.includes('@') ? parsed.roomRef : '');
|
|
66
|
+
if (!roomJid) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
store.dispatch(
|
|
71
|
+
setIncomingCallToken({
|
|
72
|
+
roomJid,
|
|
73
|
+
roomName: parsed.callerName || resolved?.name || null,
|
|
74
|
+
roomBareName: parsed.roomBareName,
|
|
75
|
+
token: parsed.token,
|
|
76
|
+
kind: parsed.kind,
|
|
77
|
+
callId: parsed.callId,
|
|
78
|
+
peerXmppUsername: parsed.callerXmppUsername,
|
|
79
|
+
})
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
return true;
|
|
83
|
+
};
|
|
@@ -71,20 +71,38 @@ export function insertMessageWithDelimiter(
|
|
|
71
71
|
isDateAfter(msg.date?.toString() ?? '', lastViewedTimestamp.toString())
|
|
72
72
|
);
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
if (delimiterIndex !== -1) {
|
|
75
|
+
// The divider's date is what ORDERS it: roomsSlice re-sorts every
|
|
76
|
+
// merged page by timestamp (see `byMs`), so a divider stamped with
|
|
77
|
+
// `new Date()` — i.e. now — sorted past every real message and
|
|
78
|
+
// rendered at the very bottom, BELOW the new messages it is
|
|
79
|
+
// supposed to introduce. Anchor it a hair before the first unread
|
|
80
|
+
// instead, which is where it belongs and where any later sort keeps
|
|
81
|
+
// it. Derived from that message rather than from
|
|
82
|
+
// lastViewedTimestamp so it works whatever format the caller passes.
|
|
83
|
+
const firstUnreadMs = Date.parse(
|
|
84
|
+
String(roomMessages[delimiterIndex]?.date ?? '')
|
|
85
|
+
);
|
|
86
|
+
const rawLastViewed = lastViewedTimestamp.toString();
|
|
87
|
+
const lastViewedMs =
|
|
88
|
+
Date.parse(rawLastViewed) || Number(rawLastViewed) || Date.now();
|
|
89
|
+
const anchorMs = Number.isFinite(firstUnreadMs)
|
|
90
|
+
? firstUnreadMs - 1
|
|
91
|
+
: lastViewedMs;
|
|
92
|
+
|
|
93
|
+
roomMessages.splice(delimiterIndex, 0, {
|
|
94
|
+
id: 'delimiter-new',
|
|
95
|
+
user: {
|
|
78
96
|
id: 'system',
|
|
79
97
|
name: undefined,
|
|
80
98
|
token: '',
|
|
81
99
|
refreshToken: '',
|
|
82
100
|
},
|
|
83
|
-
date: new Date().
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
101
|
+
date: new Date(anchorMs).toISOString(),
|
|
102
|
+
body: 'New Messages',
|
|
103
|
+
roomJid: '',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
88
106
|
}
|
|
89
107
|
} else if (
|
|
90
108
|
isDateBefore(newMessageDate.toString(), firstMessage?.date?.toString() ?? '')
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a resolved sender "name" is really just an unresolved id.
|
|
3
|
+
*
|
|
4
|
+
* The name chain ends at the sender's JID localpart when `usersSet` has no
|
|
5
|
+
* entry and the wire carried no name. For a real member that never happens
|
|
6
|
+
* for long — the REST roster fills the cache in. But some senders are not
|
|
7
|
+
* members at all: a broadcast posted by the app itself arrives with the
|
|
8
|
+
* ROOM's own id as its occupant resource (e.g.
|
|
9
|
+
* `646cc8dc96d4a4dc8f7b2f2d_67f6823cf5995841ba431f06`), so no roster will
|
|
10
|
+
* ever resolve it and the bubble ends up captioned with 50 characters of
|
|
11
|
+
* hex.
|
|
12
|
+
*
|
|
13
|
+
* Ethora ids are `<24-hex appId>_<24-hex objectId>`, which is what this
|
|
14
|
+
* matches. A raw objectId on its own is matched too, since some senders
|
|
15
|
+
* carry only that half.
|
|
16
|
+
*/
|
|
17
|
+
const ETHORA_ID = /^[0-9a-f]{24}(_[0-9a-f]{24})?$/i;
|
|
18
|
+
|
|
19
|
+
export const isUnresolvedSenderId = (name?: string): boolean => {
|
|
20
|
+
const trimmed = String(name || '').trim();
|
|
21
|
+
if (!trimmed) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
return ETHORA_ID.test(trimmed);
|
|
25
|
+
};
|
|
@@ -24,6 +24,9 @@ export const useChatSettingState = () => {
|
|
|
24
24
|
const client = useSelector(
|
|
25
25
|
(state: RootState) => state.chatSettingStore.client
|
|
26
26
|
);
|
|
27
|
+
const translateMode = useSelector(
|
|
28
|
+
(state: RootState) => state.chatSettingStore.translateMode
|
|
29
|
+
);
|
|
27
30
|
|
|
28
31
|
return {
|
|
29
32
|
user,
|
|
@@ -33,6 +36,7 @@ export const useChatSettingState = () => {
|
|
|
33
36
|
deleteModal,
|
|
34
37
|
selectedUser,
|
|
35
38
|
langSource,
|
|
39
|
+
translateMode,
|
|
36
40
|
client,
|
|
37
41
|
};
|
|
38
42
|
};
|