@ethora/chat-component-rn 26.5.21 → 26.6.10
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/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/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 +12 -2
- 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/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/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/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 +12 -2
- 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/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/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/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/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/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/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 +15 -2
- 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/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
|
@@ -13,6 +13,8 @@ import { IRoom } from '../../types/types';
|
|
|
13
13
|
import { ProfileImagePlaceholder } from './ProfileImagePlaceholder';
|
|
14
14
|
import Button from '../styled/Button';
|
|
15
15
|
import { BackIcon, BurgerMenuIcon } from '../../assets/icons';
|
|
16
|
+
import { CallButtons } from '../VideoCalls/CallButtons';
|
|
17
|
+
import { LanguageSelectorButton } from './LanguageSelectorButton';
|
|
16
18
|
import { useDispatch } from 'react-redux';
|
|
17
19
|
import Composing from '../styled/StyledInputComponents/Composing';
|
|
18
20
|
import {
|
|
@@ -30,6 +32,7 @@ import { View, StyleSheet, Text, Keyboard } from 'react-native';
|
|
|
30
32
|
import { getIconColor } from '../../helpers/getIconColor';
|
|
31
33
|
import { resolveHeaderHeight } from '../../helpers/headerLayout';
|
|
32
34
|
import { getElementFont } from '../../helpers/getElementFont';
|
|
35
|
+
import { useT } from '../../i18n/useT';
|
|
33
36
|
|
|
34
37
|
interface ChatHeaderProps {
|
|
35
38
|
currentRoom: IRoom;
|
|
@@ -47,6 +50,7 @@ const ChatHeader: React.FC<ChatHeaderProps> = ({
|
|
|
47
50
|
const roomState = useRoomState(currentRoom.jid).room;
|
|
48
51
|
const composing = roomState?.composing;
|
|
49
52
|
const { config } = useChatSettingState();
|
|
53
|
+
const t = useT();
|
|
50
54
|
|
|
51
55
|
const handleChangeChat = (chat: IRoom) => {
|
|
52
56
|
dispatch(setCurrentRoom({ roomJID: chat.jid }));
|
|
@@ -172,7 +176,14 @@ const ChatHeader: React.FC<ChatHeaderProps> = ({
|
|
|
172
176
|
<ChatContainerHeaderLabel
|
|
173
177
|
style={[styles.subLabel, getElementFont(config, 'headerSubtitle')]}
|
|
174
178
|
>
|
|
175
|
-
<Text>
|
|
179
|
+
<Text>
|
|
180
|
+
{t(
|
|
181
|
+
Number(currentRoom?.usersCnt) === 1
|
|
182
|
+
? 'header.userCountSingular'
|
|
183
|
+
: 'header.userCountPlural',
|
|
184
|
+
{ count: Number(currentRoom?.usersCnt) || 0 }
|
|
185
|
+
)}
|
|
186
|
+
</Text>
|
|
176
187
|
</ChatContainerHeaderLabel>
|
|
177
188
|
)}
|
|
178
189
|
</View>
|
|
@@ -180,13 +191,15 @@ const ChatHeader: React.FC<ChatHeaderProps> = ({
|
|
|
180
191
|
</ChatContainerHeaderBoxInfo>
|
|
181
192
|
</CenterContainer>
|
|
182
193
|
|
|
183
|
-
{
|
|
184
|
-
|
|
194
|
+
<View style={styles.rightContainer}>
|
|
195
|
+
{/* Renders nothing unless config.videoCalls is on and this is a
|
|
196
|
+
1:1 room, so it costs non-call hosts nothing. */}
|
|
197
|
+
<LanguageSelectorButton />
|
|
198
|
+
<CallButtons />
|
|
199
|
+
{!config?.disableChatInfo?.disableRoomMenu && (
|
|
185
200
|
<RoomMenu handleLeaveClick={handleLeaveClick} />
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
<View style={styles.rightContainer} />
|
|
189
|
-
)}
|
|
201
|
+
)}
|
|
202
|
+
</View>
|
|
190
203
|
</ChatContainerHeader>
|
|
191
204
|
{config?.chatHeaderAdditional?.enabled &&
|
|
192
205
|
config.chatHeaderAdditional.element()}
|
|
@@ -209,8 +222,16 @@ const styles = StyleSheet.create({
|
|
|
209
222
|
width: '15%',
|
|
210
223
|
},
|
|
211
224
|
rightContainer: {
|
|
212
|
-
|
|
213
|
-
|
|
225
|
+
flexDirection: 'row',
|
|
226
|
+
alignItems: 'center',
|
|
227
|
+
justifyContent: 'flex-end',
|
|
228
|
+
gap: 4,
|
|
229
|
+
// Sized to its icons rather than a fixed 25%: the cluster is 1 to 4
|
|
230
|
+
// icons depending on config (globe, audio call, video call, room menu),
|
|
231
|
+
// and a fixed share either cramped them together or reserved dead space
|
|
232
|
+
// that the title could have used. `flexShrink: 0` keeps them intact
|
|
233
|
+
// while CenterContainer (flex:1, min-width:0) absorbs the difference.
|
|
234
|
+
flexShrink: 0,
|
|
214
235
|
},
|
|
215
236
|
});
|
|
216
237
|
|
|
@@ -129,6 +129,21 @@ const ChatWrapper: FC<ChatWrapperProps> = ({
|
|
|
129
129
|
client.setActiveRoomJid?.(activeRoomJID || null);
|
|
130
130
|
}, [client, activeRoomJID]);
|
|
131
131
|
|
|
132
|
+
// Pull the MUC roster as soon as a room opens (not just when the
|
|
133
|
+
// profile modal is opened — see ChatProfileModal). Message sender
|
|
134
|
+
// names fall back to the raw jid when a message doesn't carry its
|
|
135
|
+
// own senderFirstName/senderLastName, and that fallback depends on
|
|
136
|
+
// usersSet being populated; without this, any room the reader hasn't
|
|
137
|
+
// separately opened the profile modal for shows jids instead of names.
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
if (!client || !activeRoomJID) {return;}
|
|
140
|
+
try {
|
|
141
|
+
client.getRoomMembersStanza?.(activeRoomJID);
|
|
142
|
+
} catch {
|
|
143
|
+
/* non-fatal */
|
|
144
|
+
}
|
|
145
|
+
}, [client, activeRoomJID]);
|
|
146
|
+
|
|
132
147
|
const seededRoomJID = useMemo(
|
|
133
148
|
() =>
|
|
134
149
|
roomJID
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React, { FC, useState } from 'react';
|
|
2
|
+
import { StyleSheet, TouchableOpacity } from 'react-native';
|
|
3
|
+
import { useChatSettingState } from '../../hooks/useChatSettingState';
|
|
4
|
+
import { getIconColor } from '../../helpers/getIconColor';
|
|
5
|
+
import { useT } from '../../i18n/useT';
|
|
6
|
+
import { GlobeIcon, LanguageSelectorModal } from './LanguageSelectorModal';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Globe button in the chat header that opens the reader's language picker.
|
|
10
|
+
*
|
|
11
|
+
* Renders only when translation is on. A host that drives the reader's
|
|
12
|
+
* language from its own settings screen (via `config.translates
|
|
13
|
+
* .readerLocale`) can hide this with `showLanguageSelector: false` rather
|
|
14
|
+
* than shipping two competing controls.
|
|
15
|
+
*/
|
|
16
|
+
export const LanguageSelectorButton: FC = () => {
|
|
17
|
+
const { config } = useChatSettingState();
|
|
18
|
+
const t = useT();
|
|
19
|
+
const [open, setOpen] = useState(false);
|
|
20
|
+
|
|
21
|
+
const translates = config?.translates;
|
|
22
|
+
const enabled = Boolean(translates?.enabled || config?.enableTranslates);
|
|
23
|
+
if (!enabled || translates?.showLanguageSelector === false) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<>
|
|
29
|
+
<TouchableOpacity
|
|
30
|
+
accessibilityRole="button"
|
|
31
|
+
accessibilityLabel={t('language.select')}
|
|
32
|
+
onPress={() => setOpen(true)}
|
|
33
|
+
style={styles.button}
|
|
34
|
+
hitSlop={8}
|
|
35
|
+
>
|
|
36
|
+
<GlobeIcon color={getIconColor(config)} size={20} />
|
|
37
|
+
</TouchableOpacity>
|
|
38
|
+
<LanguageSelectorModal visible={open} onClose={() => setOpen(false)} />
|
|
39
|
+
</>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const styles = StyleSheet.create({
|
|
44
|
+
button: {
|
|
45
|
+
width: 36,
|
|
46
|
+
height: 36,
|
|
47
|
+
borderRadius: 18,
|
|
48
|
+
alignItems: 'center',
|
|
49
|
+
justifyContent: 'center',
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
export default LanguageSelectorButton;
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import React, { FC, useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Modal,
|
|
4
|
+
Pressable,
|
|
5
|
+
ScrollView,
|
|
6
|
+
StyleSheet,
|
|
7
|
+
Text,
|
|
8
|
+
TouchableOpacity,
|
|
9
|
+
View,
|
|
10
|
+
} from 'react-native';
|
|
11
|
+
import Svg, { Circle, Path } from 'react-native-svg';
|
|
12
|
+
import { useDispatch } from 'react-redux';
|
|
13
|
+
import {
|
|
14
|
+
setLangSource,
|
|
15
|
+
setTranslateMode,
|
|
16
|
+
} from '../../roomStore/chatSettingsSlice';
|
|
17
|
+
import { useChatSettingState } from '../../hooks/useChatSettingState';
|
|
18
|
+
import { LANGUAGE_OPTIONS } from '../../helpers/constants/LANGUAGE_OPTIONS';
|
|
19
|
+
import { Iso639_1Codes } from '../../types/models/language.model';
|
|
20
|
+
import {
|
|
21
|
+
canReaderChooseTranslateMode,
|
|
22
|
+
resolveTranslateMode,
|
|
23
|
+
} from '../../utils/translateModePolicy';
|
|
24
|
+
import { useT } from '../../i18n/useT';
|
|
25
|
+
import { toBaseLanguage } from '../../i18n/strings';
|
|
26
|
+
import { getIconColor } from '../../helpers/getIconColor';
|
|
27
|
+
|
|
28
|
+
const TEXT_PRIMARY = '#141414';
|
|
29
|
+
const TEXT_MUTED = '#8C8C8C';
|
|
30
|
+
const DIVIDER = '#F0F0F0';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Ported verbatim from the web SDK's GlobeIcon (src/assets/icons.tsx) so
|
|
34
|
+
* both platforms draw the same mark. The previous RN shape was hand-rolled
|
|
35
|
+
* on a 24-box with two mirrored beziers whose meridian bulged only ~21% of
|
|
36
|
+
* the radius, which collapsed into a thin lens rather than reading as a
|
|
37
|
+
* sphere.
|
|
38
|
+
*/
|
|
39
|
+
export const GlobeIcon: FC<{ color?: string; size?: number }> = ({
|
|
40
|
+
color = '#8C8C8C',
|
|
41
|
+
size = 20,
|
|
42
|
+
}) => (
|
|
43
|
+
<Svg width={size} height={size} viewBox="0 0 20 20" fill="none">
|
|
44
|
+
<Circle cx="10" cy="10" r="7.5" stroke={color} strokeWidth={1.5} />
|
|
45
|
+
<Path
|
|
46
|
+
d="M2.5 10h15M10 2.5c2 2.1 3 4.7 3 7.5s-1 5.4-3 7.5c-2-2.1-3-4.7-3-7.5s1-5.4 3-7.5Z"
|
|
47
|
+
stroke={color}
|
|
48
|
+
strokeWidth={1.5}
|
|
49
|
+
strokeLinecap="round"
|
|
50
|
+
strokeLinejoin="round"
|
|
51
|
+
fill="none"
|
|
52
|
+
/>
|
|
53
|
+
</Svg>
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The reader's language control.
|
|
58
|
+
*
|
|
59
|
+
* One switch drives two things on purpose: the language messages get
|
|
60
|
+
* translated INTO, and (through useT falling back to `langSource`) the
|
|
61
|
+
* language the interface itself is in. A reader who picks Français expects
|
|
62
|
+
* the whole chat in French, not French messages inside an English UI.
|
|
63
|
+
*
|
|
64
|
+
* The auto/manual switcher only renders when the host hasn't pinned
|
|
65
|
+
* `config.translates.forceType`, and the language list only when
|
|
66
|
+
* `showLanguageList` isn't false, for hosts that drive the reader's
|
|
67
|
+
* language from their own settings screen via `readerLocale`.
|
|
68
|
+
*/
|
|
69
|
+
export const LanguageSelectorModal: FC<{
|
|
70
|
+
visible: boolean;
|
|
71
|
+
onClose: () => void;
|
|
72
|
+
}> = ({ visible, onClose }) => {
|
|
73
|
+
const dispatch = useDispatch();
|
|
74
|
+
const t = useT();
|
|
75
|
+
const { config, langSource, translateMode } = useChatSettingState();
|
|
76
|
+
|
|
77
|
+
const translates = config?.translates;
|
|
78
|
+
const effectiveMode = resolveTranslateMode(translates, translateMode);
|
|
79
|
+
const showModeSwitcher = canReaderChooseTranslateMode(translates);
|
|
80
|
+
const showLanguageList = translates?.showLanguageList !== false;
|
|
81
|
+
const activeLocale = translates?.readerLocale || langSource;
|
|
82
|
+
|
|
83
|
+
const selectLanguage = useCallback(
|
|
84
|
+
(id: Iso639_1Codes) => {
|
|
85
|
+
dispatch(setLangSource(id));
|
|
86
|
+
onClose();
|
|
87
|
+
},
|
|
88
|
+
[dispatch, onClose]
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<Modal
|
|
93
|
+
visible={visible}
|
|
94
|
+
transparent
|
|
95
|
+
animationType="fade"
|
|
96
|
+
onRequestClose={onClose}
|
|
97
|
+
>
|
|
98
|
+
{/* Backdrop closes on tap; the card swallows the press so a tap
|
|
99
|
+
inside it doesn't dismiss. */}
|
|
100
|
+
<Pressable style={styles.backdrop} onPress={onClose}>
|
|
101
|
+
<Pressable style={styles.card} onPress={() => {}}>
|
|
102
|
+
<Text style={styles.title}>{t('language.select')}</Text>
|
|
103
|
+
|
|
104
|
+
{showModeSwitcher && (
|
|
105
|
+
<View style={styles.section}>
|
|
106
|
+
<Text style={styles.sectionLabel}>
|
|
107
|
+
{t('translation.modeLabel')}
|
|
108
|
+
</Text>
|
|
109
|
+
<View style={styles.segmented}>
|
|
110
|
+
{(['auto', 'manual'] as const).map((mode) => {
|
|
111
|
+
const selected = effectiveMode === mode;
|
|
112
|
+
return (
|
|
113
|
+
<TouchableOpacity
|
|
114
|
+
key={mode}
|
|
115
|
+
accessibilityRole="radio"
|
|
116
|
+
accessibilityState={{ selected }}
|
|
117
|
+
onPress={() => dispatch(setTranslateMode(mode))}
|
|
118
|
+
style={[
|
|
119
|
+
styles.segment,
|
|
120
|
+
selected && styles.segmentSelected,
|
|
121
|
+
]}
|
|
122
|
+
>
|
|
123
|
+
<Text
|
|
124
|
+
style={[
|
|
125
|
+
styles.segmentText,
|
|
126
|
+
selected && styles.segmentTextSelected,
|
|
127
|
+
]}
|
|
128
|
+
>
|
|
129
|
+
{mode === 'auto'
|
|
130
|
+
? t('translation.modeAuto')
|
|
131
|
+
: t('translation.modeManual')}
|
|
132
|
+
</Text>
|
|
133
|
+
</TouchableOpacity>
|
|
134
|
+
);
|
|
135
|
+
})}
|
|
136
|
+
</View>
|
|
137
|
+
</View>
|
|
138
|
+
)}
|
|
139
|
+
|
|
140
|
+
{showLanguageList && (
|
|
141
|
+
<View style={styles.section}>
|
|
142
|
+
<Text style={styles.sectionLabel}>{t('language.select')}</Text>
|
|
143
|
+
<ScrollView style={styles.list}>
|
|
144
|
+
{LANGUAGE_OPTIONS.map((option) => {
|
|
145
|
+
// Compare on the base language so a reader on "fr" still
|
|
146
|
+
// sees "Français" (id fr-CA) ticked.
|
|
147
|
+
const selected =
|
|
148
|
+
!!activeLocale &&
|
|
149
|
+
toBaseLanguage(activeLocale) === toBaseLanguage(option.id);
|
|
150
|
+
return (
|
|
151
|
+
<TouchableOpacity
|
|
152
|
+
key={option.id}
|
|
153
|
+
accessibilityRole="radio"
|
|
154
|
+
accessibilityState={{ selected }}
|
|
155
|
+
onPress={() => selectLanguage(option.id)}
|
|
156
|
+
style={styles.listRow}
|
|
157
|
+
>
|
|
158
|
+
<Text
|
|
159
|
+
style={[
|
|
160
|
+
styles.listRowText,
|
|
161
|
+
selected && styles.listRowTextSelected,
|
|
162
|
+
]}
|
|
163
|
+
>
|
|
164
|
+
{option.name}
|
|
165
|
+
</Text>
|
|
166
|
+
{selected && (
|
|
167
|
+
<Text
|
|
168
|
+
style={[
|
|
169
|
+
styles.check,
|
|
170
|
+
{ color: getIconColor(config) },
|
|
171
|
+
]}
|
|
172
|
+
>
|
|
173
|
+
✓
|
|
174
|
+
</Text>
|
|
175
|
+
)}
|
|
176
|
+
</TouchableOpacity>
|
|
177
|
+
);
|
|
178
|
+
})}
|
|
179
|
+
</ScrollView>
|
|
180
|
+
</View>
|
|
181
|
+
)}
|
|
182
|
+
|
|
183
|
+
<TouchableOpacity onPress={onClose} style={styles.closeButton}>
|
|
184
|
+
<Text style={[styles.closeText, { color: getIconColor(config) }]}>
|
|
185
|
+
{t('action.cancel')}
|
|
186
|
+
</Text>
|
|
187
|
+
</TouchableOpacity>
|
|
188
|
+
</Pressable>
|
|
189
|
+
</Pressable>
|
|
190
|
+
</Modal>
|
|
191
|
+
);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const styles = StyleSheet.create({
|
|
195
|
+
backdrop: {
|
|
196
|
+
flex: 1,
|
|
197
|
+
backgroundColor: 'rgba(0,0,0,0.4)',
|
|
198
|
+
alignItems: 'center',
|
|
199
|
+
justifyContent: 'center',
|
|
200
|
+
padding: 24,
|
|
201
|
+
},
|
|
202
|
+
card: {
|
|
203
|
+
width: '100%',
|
|
204
|
+
maxWidth: 420,
|
|
205
|
+
maxHeight: '80%',
|
|
206
|
+
backgroundColor: '#fff',
|
|
207
|
+
borderRadius: 20,
|
|
208
|
+
padding: 20,
|
|
209
|
+
gap: 16,
|
|
210
|
+
},
|
|
211
|
+
title: {
|
|
212
|
+
fontSize: 18,
|
|
213
|
+
color: TEXT_PRIMARY,
|
|
214
|
+
},
|
|
215
|
+
section: {
|
|
216
|
+
gap: 8,
|
|
217
|
+
},
|
|
218
|
+
sectionLabel: {
|
|
219
|
+
fontSize: 13,
|
|
220
|
+
color: TEXT_MUTED,
|
|
221
|
+
},
|
|
222
|
+
segmented: {
|
|
223
|
+
flexDirection: 'row',
|
|
224
|
+
borderRadius: 12,
|
|
225
|
+
backgroundColor: '#F5F7F9',
|
|
226
|
+
padding: 4,
|
|
227
|
+
gap: 4,
|
|
228
|
+
},
|
|
229
|
+
segment: {
|
|
230
|
+
flex: 1,
|
|
231
|
+
paddingVertical: 10,
|
|
232
|
+
borderRadius: 9,
|
|
233
|
+
alignItems: 'center',
|
|
234
|
+
},
|
|
235
|
+
segmentSelected: {
|
|
236
|
+
backgroundColor: '#fff',
|
|
237
|
+
},
|
|
238
|
+
segmentText: {
|
|
239
|
+
fontSize: 14,
|
|
240
|
+
color: TEXT_MUTED,
|
|
241
|
+
},
|
|
242
|
+
segmentTextSelected: {
|
|
243
|
+
color: TEXT_PRIMARY,
|
|
244
|
+
fontWeight: '600',
|
|
245
|
+
},
|
|
246
|
+
list: {
|
|
247
|
+
maxHeight: 260,
|
|
248
|
+
},
|
|
249
|
+
listRow: {
|
|
250
|
+
flexDirection: 'row',
|
|
251
|
+
alignItems: 'center',
|
|
252
|
+
justifyContent: 'space-between',
|
|
253
|
+
paddingVertical: 14,
|
|
254
|
+
borderBottomWidth: 1,
|
|
255
|
+
borderBottomColor: DIVIDER,
|
|
256
|
+
},
|
|
257
|
+
listRowText: {
|
|
258
|
+
fontSize: 16,
|
|
259
|
+
color: TEXT_PRIMARY,
|
|
260
|
+
},
|
|
261
|
+
listRowTextSelected: {
|
|
262
|
+
fontWeight: '600',
|
|
263
|
+
},
|
|
264
|
+
check: {
|
|
265
|
+
fontSize: 16,
|
|
266
|
+
},
|
|
267
|
+
closeButton: {
|
|
268
|
+
alignItems: 'center',
|
|
269
|
+
paddingVertical: 12,
|
|
270
|
+
},
|
|
271
|
+
closeText: {
|
|
272
|
+
fontSize: 15,
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
export default LanguageSelectorModal;
|
|
@@ -25,6 +25,7 @@ import Button from '../styled/Button';
|
|
|
25
25
|
import { HeaderRoomList } from '../Header/HeaderRoomList';
|
|
26
26
|
import { HeaderRoomListMenu } from '../Menu/HeaderRoomListMenu';
|
|
27
27
|
import { getIconColor } from '../../helpers/getIconColor';
|
|
28
|
+
import { useT } from '../../i18n/useT';
|
|
28
29
|
|
|
29
30
|
const LONG_PRESS_THRESHOLD = 200;
|
|
30
31
|
|
|
@@ -40,6 +41,7 @@ const RoomList: React.FC<RoomListProps> = ({
|
|
|
40
41
|
onRoomClick,
|
|
41
42
|
}) => {
|
|
42
43
|
const { config } = useChatSettingState();
|
|
44
|
+
const t = useT();
|
|
43
45
|
|
|
44
46
|
const [open, setOpen] = useState(false);
|
|
45
47
|
const [searchTerm, setSearchTerm] = useState('');
|
|
@@ -178,6 +180,20 @@ const RoomList: React.FC<RoomListProps> = ({
|
|
|
178
180
|
<>
|
|
179
181
|
<View style={styles.scrollContainer}>
|
|
180
182
|
<HeaderRoomList setDrawerOpen={toggleDrawer} />
|
|
183
|
+
{/* Search sits ABOVE the list rather than in its
|
|
184
|
+
ListHeaderComponent. As a list header it was simply the
|
|
185
|
+
first scrolling row, so the moment you scrolled the rooms
|
|
186
|
+
it slid up and disappeared behind the opaque header band.
|
|
187
|
+
Fixed here it stays reachable, which is the entire point
|
|
188
|
+
of a search field over a long list. */}
|
|
189
|
+
<View style={styles.searchBar}>
|
|
190
|
+
<SearchInput
|
|
191
|
+
icon={<SearchIcon height={20} />}
|
|
192
|
+
value={searchTerm}
|
|
193
|
+
onChangeText={handleSearchChange}
|
|
194
|
+
placeholder={t('search.placeholder')}
|
|
195
|
+
/>
|
|
196
|
+
</View>
|
|
181
197
|
<FlatList
|
|
182
198
|
data={filteredChats}
|
|
183
199
|
keyExtractor={(item) => item.jid}
|
|
@@ -195,14 +211,6 @@ const RoomList: React.FC<RoomListProps> = ({
|
|
|
195
211
|
<ChatRoomItem chat={item} config={config} />
|
|
196
212
|
</Pressable>
|
|
197
213
|
)}
|
|
198
|
-
ListHeaderComponent={
|
|
199
|
-
<SearchInput
|
|
200
|
-
icon={<SearchIcon height={20} />}
|
|
201
|
-
value={searchTerm}
|
|
202
|
-
onChangeText={handleSearchChange}
|
|
203
|
-
placeholder="Search..."
|
|
204
|
-
/>
|
|
205
|
-
}
|
|
206
214
|
style={styles.chatList}
|
|
207
215
|
/>
|
|
208
216
|
|
|
@@ -241,9 +249,19 @@ const styles = StyleSheet.create({
|
|
|
241
249
|
padding: 16,
|
|
242
250
|
justifyContent: 'space-between',
|
|
243
251
|
},
|
|
252
|
+
searchBar: {
|
|
253
|
+
// `row` matters: SearchInputWrapper is `flex: 1` plus a fixed 44px
|
|
254
|
+
// height. In a column parent that flex resolves VERTICALLY against a
|
|
255
|
+
// parent with no height of its own and collapses the field to nothing
|
|
256
|
+
// but its magnifier. As a row it resolves to width, which is what it
|
|
257
|
+
// meant back when the field was a list-header child.
|
|
258
|
+
flexDirection: 'row',
|
|
259
|
+
paddingTop: 8,
|
|
260
|
+
paddingHorizontal: 16,
|
|
261
|
+
backgroundColor: '#FAFAFA',
|
|
262
|
+
},
|
|
244
263
|
chatList: {
|
|
245
264
|
flex: 1,
|
|
246
|
-
paddingTop: 8,
|
|
247
265
|
paddingHorizontal: 16,
|
|
248
266
|
backgroundColor: '#FAFAFA',
|
|
249
267
|
},
|
|
@@ -25,7 +25,11 @@ import { setActiveMessage, setEditAction } from '../../roomStore/roomsSlice';
|
|
|
25
25
|
import styled from 'styled-components/native';
|
|
26
26
|
import { IUser, MessageProps } from '../../types/types';
|
|
27
27
|
import MediaMessage from '../MainComponents/MediaMessage';
|
|
28
|
-
import
|
|
28
|
+
import MessageTranslate from './MessageTranslate';
|
|
29
|
+
import { isUnresolvedSenderId } from '../../helpers/isUnresolvedSenderId';
|
|
30
|
+
import TranslatedMessageBody from './TranslatedMessageBody';
|
|
31
|
+
import { useMessageTranslation } from '../../hooks/useMessageTranslation';
|
|
32
|
+
import { resolveTranslateMode } from '../../utils/translateModePolicy';
|
|
29
33
|
import { useChatSettingState } from '../../hooks/useChatSettingState';
|
|
30
34
|
import { parseMessageBody } from '../../helpers/parseMessageBody';
|
|
31
35
|
import { chatTextStyle } from '../../helpers/typography';
|
|
@@ -139,7 +143,69 @@ const CustomTimestampRow = styled.View<{media: boolean}>`
|
|
|
139
143
|
const Message: React.FC<MessageProps> = ({ message, isUser, isReply }) => {
|
|
140
144
|
const dispatch = useDispatch();
|
|
141
145
|
const { client } = useXmppClient();
|
|
142
|
-
const { config, langSource, user} = useChatSettingState();
|
|
146
|
+
const { config, langSource, user, translateMode } = useChatSettingState();
|
|
147
|
+
|
|
148
|
+
// `enableTranslates` predates the `translates` config block; keep it
|
|
149
|
+
// working so existing hosts don't lose translations on upgrade.
|
|
150
|
+
const isTranslatesEnabled = Boolean(
|
|
151
|
+
config?.translates?.enabled || config?.enableTranslates
|
|
152
|
+
);
|
|
153
|
+
const effectiveTranslateMode = resolveTranslateMode(
|
|
154
|
+
config?.translates,
|
|
155
|
+
translateMode
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
// Auto mode (the default): show the translation inline as the primary body,
|
|
159
|
+
// with the original quoted above. Own messages are never translated — the
|
|
160
|
+
// sender already knows what they wrote (TranslatedMessageBody skips the
|
|
161
|
+
// quote for isUser, and we simply render the original for them). Mirrors
|
|
162
|
+
// the web SDK's Message.tsx.
|
|
163
|
+
const isAutoTranslate =
|
|
164
|
+
isTranslatesEnabled && effectiveTranslateMode !== 'manual';
|
|
165
|
+
const readerLocale =
|
|
166
|
+
config?.translates?.readerLocale || config?.i18n?.locale || langSource;
|
|
167
|
+
const translationDisplay = useMessageTranslation(
|
|
168
|
+
message,
|
|
169
|
+
readerLocale,
|
|
170
|
+
isAutoTranslate
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
// `usersSet` is the canonical, continuously-updated identity store; the
|
|
174
|
+
// copy riding on a message is a snapshot of whoever sent it, whenever
|
|
175
|
+
// they sent it. Resolve both the avatar and the display name through
|
|
176
|
+
// usersSet first, falling back to the message for senders usersSet has
|
|
177
|
+
// never seen (broadcast/system accounts).
|
|
178
|
+
//
|
|
179
|
+
// This matters more since the persist layer stopped caching per-message
|
|
180
|
+
// avatars: a cache-restored message carries no profileImage at all (see
|
|
181
|
+
// PERSISTED_MESSAGE_USER_FIELDS), so reading only the message-level copy
|
|
182
|
+
// leaves a blank initials circle for senders whose name resolved fine.
|
|
183
|
+
const usersSet = useSelector(
|
|
184
|
+
(state: RootState) => state.rooms.usersSet
|
|
185
|
+
) as Record<string, any> | undefined;
|
|
186
|
+
const senderRawId = String(message.user?.id || '');
|
|
187
|
+
const senderLocal = senderRawId.split('@')[0];
|
|
188
|
+
const senderEntry = usersSet?.[senderLocal] || usersSet?.[senderRawId];
|
|
189
|
+
// usersSet FIRST (mirrors the web SDK's Message.tsx): a message stored
|
|
190
|
+
// before usersSet hydrated carries the raw JID localpart as its
|
|
191
|
+
// `user.name`, so preferring `message.user.name` (as resolveSenderDisplayName
|
|
192
|
+
// does) would pin that JID on screen forever even after the real name is
|
|
193
|
+
// known. Reading usersSet first lets the name self-heal the moment the
|
|
194
|
+
// REST roster populates the cache. Falls back to the message's own name
|
|
195
|
+
// (which may carry senderFirstName/senderLastName from the wire) only when
|
|
196
|
+
// usersSet has never seen this sender.
|
|
197
|
+
const senderDisplayName = senderEntry
|
|
198
|
+
? `${senderEntry.firstName ?? ''} ${senderEntry.lastName ?? ''}`.trim() ||
|
|
199
|
+
senderEntry.name ||
|
|
200
|
+
senderLocal
|
|
201
|
+
: message.user?.name || senderLocal || 'Unknown';
|
|
202
|
+
// A broadcast posted by the app itself arrives with the ROOM's own id as
|
|
203
|
+
// its occupant resource, so no roster ever resolves it and the name chain
|
|
204
|
+
// ends at 50 characters of hex. Captioning a bubble with that tells the
|
|
205
|
+
// reader strictly less than showing nothing.
|
|
206
|
+
const hasRealSenderName = !isUnresolvedSenderId(senderDisplayName);
|
|
207
|
+
const senderProfileImage =
|
|
208
|
+
senderEntry?.profileImage || message.user?.profileImage || '';
|
|
143
209
|
const { idSet, failedIdSet } = useMessageHeapState();
|
|
144
210
|
const { retryMessage } = useSendMessage();
|
|
145
211
|
|
|
@@ -289,12 +355,19 @@ const Message: React.FC<MessageProps> = ({ message, isUser, isReply }) => {
|
|
|
289
355
|
// wraps content in <View>s which break Text-style inheritance, so the bubble
|
|
290
356
|
// wrapper's fontSize alone never reached the actual text.
|
|
291
357
|
const bodyTextStyle = chatTextStyle(config?.typography?.messageText);
|
|
358
|
+
// In auto mode, render the translation as the primary body — but NEVER for
|
|
359
|
+
// the reader's own messages (they wrote it; no point translating it back).
|
|
360
|
+
const showInlineTranslation =
|
|
361
|
+
isAutoTranslate && translationDisplay.hasTranslation && !isUser;
|
|
362
|
+
const bodyToRender = showInlineTranslation
|
|
363
|
+
? translationDisplay.displayText
|
|
364
|
+
: message.body;
|
|
292
365
|
const messageText = config?.messageTextFilter?.enabled
|
|
293
366
|
? parseMessageBody(
|
|
294
|
-
config?.messageTextFilter.filterFunction(
|
|
367
|
+
config?.messageTextFilter.filterFunction(bodyToRender),
|
|
295
368
|
bodyTextStyle
|
|
296
369
|
)
|
|
297
|
-
: parseMessageBody(
|
|
370
|
+
: parseMessageBody(bodyToRender, bodyTextStyle);
|
|
298
371
|
|
|
299
372
|
const isFailed = failedIdSet.has(message.id);
|
|
300
373
|
const isPending =
|
|
@@ -339,10 +412,10 @@ const Message: React.FC<MessageProps> = ({ message, isUser, isReply }) => {
|
|
|
339
412
|
disabled={!!config?.disableProfilesInteractions}
|
|
340
413
|
accessible={!config?.disableProfilesInteractions}
|
|
341
414
|
>
|
|
342
|
-
{
|
|
343
|
-
<CustomMessagePhoto source={{ uri:
|
|
415
|
+
{senderProfileImage ? (
|
|
416
|
+
<CustomMessagePhoto source={{ uri: senderProfileImage }} />
|
|
344
417
|
) : (
|
|
345
|
-
<Avatar username={
|
|
418
|
+
<Avatar username={senderDisplayName} />
|
|
346
419
|
)}
|
|
347
420
|
</CustomMessagePhotoContainer>
|
|
348
421
|
)}
|
|
@@ -382,14 +455,14 @@ const Message: React.FC<MessageProps> = ({ message, isUser, isReply }) => {
|
|
|
382
455
|
backgroundMessageUser={config?.messageColor?.backgroundMessageUser}
|
|
383
456
|
backgroundMessage={config?.messageColor?.backgroundMessage}
|
|
384
457
|
>
|
|
385
|
-
{!isUser && (
|
|
458
|
+
{!isUser && hasRealSenderName && (
|
|
386
459
|
<CustomUserName
|
|
387
460
|
color={config?.colors?.primary}
|
|
388
461
|
media={message?.isMediafile === 'true'}
|
|
389
462
|
fontSize={config?.typography?.senderName?.fontSize}
|
|
390
463
|
fontWeight={config?.typography?.senderName?.fontWeight as any}
|
|
391
464
|
>
|
|
392
|
-
{
|
|
465
|
+
{senderDisplayName}
|
|
393
466
|
</CustomUserName>
|
|
394
467
|
)}
|
|
395
468
|
{!isReply && message.mainMessage && (
|
|
@@ -421,18 +494,37 @@ const Message: React.FC<MessageProps> = ({ message, isUser, isReply }) => {
|
|
|
421
494
|
fontSize={config?.typography?.messageText?.fontSize}
|
|
422
495
|
fontWeight={config?.typography?.messageText?.fontWeight as any}
|
|
423
496
|
>
|
|
424
|
-
|
|
497
|
+
{/* Auto mode: the parsed body IS the translation; wrap it
|
|
498
|
+
so the original shows as a dimmed accent-bar quote
|
|
499
|
+
above it. Plain body otherwise. */}
|
|
500
|
+
{showInlineTranslation ? (
|
|
501
|
+
<TranslatedMessageBody
|
|
502
|
+
isUser={isUser}
|
|
503
|
+
originalText={translationDisplay.originalText}
|
|
504
|
+
accentColor={config?.colors?.primary}
|
|
505
|
+
>
|
|
506
|
+
<Text>{messageText}</Text>
|
|
507
|
+
</TranslatedMessageBody>
|
|
508
|
+
) : (
|
|
509
|
+
<Text>{messageText}</Text>
|
|
510
|
+
)}
|
|
425
511
|
</CustomMessageText>
|
|
426
512
|
)}
|
|
427
513
|
</>
|
|
428
514
|
)}
|
|
429
|
-
{
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
515
|
+
{/* Manual mode: a "Translate" link the reader taps (auto mode
|
|
516
|
+
renders the translation inline in the body above). Never on
|
|
517
|
+
the reader's own messages. */}
|
|
518
|
+
{!isUser &&
|
|
519
|
+
isTranslatesEnabled &&
|
|
520
|
+
effectiveTranslateMode === 'manual' && (
|
|
521
|
+
<MessageTranslate
|
|
522
|
+
message={message}
|
|
523
|
+
config={config}
|
|
524
|
+
isUser={isUser}
|
|
525
|
+
readerLocale={readerLocale}
|
|
526
|
+
/>
|
|
527
|
+
)}
|
|
436
528
|
{/* <View style={styles.timestampRow}> */}
|
|
437
529
|
<CustomTimestampRow media={message?.isMediafile === 'true'}>
|
|
438
530
|
{!config?.disableSentLogic && isUser && isPending && (
|