@ethora/chat-component-rn 26.5.5 → 26.5.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 +177 -0
- package/README.md +67 -10
- package/index.js +24 -0
- package/lib/commonjs/assets/icons.js +5 -1
- package/lib/commonjs/assets/icons.js.map +1 -1
- package/lib/commonjs/components/ContextMenu/ContextMenuComponents.js +11 -5
- package/lib/commonjs/components/ContextMenu/ContextMenuComponents.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatHeader.js +7 -1
- package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatRoom.js +66 -34
- package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatWrapper.js +59 -14
- package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MediaMessage.js +15 -7
- package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MessageContainer.js +2 -2
- package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MessageList.js +175 -30
- package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ReduxWrapper.js +17 -8
- package/lib/commonjs/components/MainComponents/ReduxWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/SystemMessage.js +34 -22
- package/lib/commonjs/components/MainComponents/SystemMessage.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/Message.js +117 -19
- package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js +82 -22
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js +16 -4
- package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/DocumentViewer.js +104 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/DocumentViewer.js.map +1 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +175 -40
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js +29 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
- package/lib/commonjs/components/Modals/Modal/Modal.js +5 -1
- package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
- package/lib/commonjs/components/Modals/ModalWrapper/ModalWrapper.js +78 -39
- package/lib/commonjs/components/Modals/ModalWrapper/ModalWrapper.js.map +1 -1
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +3 -3
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/styledModalComponents.js +4 -9
- package/lib/commonjs/components/Modals/styledModalComponents.js.map +1 -1
- package/lib/commonjs/components/styled/MediaFilePreview.js +115 -5
- package/lib/commonjs/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/commonjs/components/styled/MessageImage.js +49 -10
- package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
- package/lib/commonjs/components/styled/NewMessageLabel.js +8 -6
- package/lib/commonjs/components/styled/NewMessageLabel.js.map +1 -1
- package/lib/commonjs/components/styled/SendInput.js +53 -29
- package/lib/commonjs/components/styled/SendInput.js.map +1 -1
- package/lib/commonjs/components/styled/StyledInputComponents/MediaComponents.js +14 -4
- package/lib/commonjs/components/styled/StyledInputComponents/MediaComponents.js.map +1 -1
- package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js +7 -2
- package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
- package/lib/commonjs/components/styled/UnsupportedType.js +5 -1
- package/lib/commonjs/components/styled/UnsupportedType.js.map +1 -1
- package/lib/commonjs/components/styled/VideoMessage.js +60 -22
- package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
- package/lib/commonjs/context/MessageNotificationContext.js +7 -7
- package/lib/commonjs/context/MessageNotificationContext.js.map +1 -1
- package/lib/commonjs/context/xmppProvider.js +315 -34
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/helpers/chatAutoEnterer.js +2 -7
- package/lib/commonjs/helpers/chatAutoEnterer.js.map +1 -1
- package/lib/commonjs/helpers/historyPreloadScheduler.js +4 -1
- package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
- package/lib/commonjs/helpers/insertMessageWithDelimiter.js +15 -5
- package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
- package/lib/commonjs/helpers/keyboardLayout.js +18 -0
- package/lib/commonjs/helpers/keyboardLayout.js.map +1 -0
- package/lib/commonjs/helpers/mediaDimensions.js +51 -0
- package/lib/commonjs/helpers/mediaDimensions.js.map +1 -0
- package/lib/commonjs/helpers/mimeToExtension.js +131 -0
- package/lib/commonjs/helpers/mimeToExtension.js.map +1 -0
- package/lib/commonjs/helpers/normalizeRoomJid.js +20 -0
- package/lib/commonjs/helpers/normalizeRoomJid.js.map +1 -0
- package/lib/commonjs/helpers/resolveInitBeforeLoadUser.js +73 -1
- package/lib/commonjs/helpers/resolveInitBeforeLoadUser.js.map +1 -1
- package/lib/commonjs/hooks/useChatRoomFocus.js +87 -0
- package/lib/commonjs/hooks/useChatRoomFocus.js.map +1 -0
- package/lib/commonjs/hooks/useChatWrapperInit.js +22 -10
- package/lib/commonjs/hooks/useChatWrapperInit.js.map +1 -1
- package/lib/commonjs/hooks/useEventHandlers.js +9 -1
- package/lib/commonjs/hooks/useEventHandlers.js.map +1 -1
- package/lib/commonjs/hooks/useHeapSender.js +1 -1
- package/lib/commonjs/hooks/useHeapSender.js.map +1 -1
- package/lib/commonjs/hooks/useLogout.js +3 -3
- package/lib/commonjs/hooks/useLogout.js.map +1 -1
- package/lib/commonjs/hooks/useMessageHeapState.js +6 -2
- package/lib/commonjs/hooks/useMessageHeapState.js.map +1 -1
- package/lib/commonjs/hooks/usePushNotifications.js +6 -2
- package/lib/commonjs/hooks/usePushNotifications.js.map +1 -1
- package/lib/commonjs/hooks/useRoomState.js +2 -0
- package/lib/commonjs/hooks/useRoomState.js.map +1 -1
- package/lib/commonjs/hooks/useSendMessage.js +249 -14
- package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
- package/lib/commonjs/hooks/useUnreadMessagesCounter.js +12 -14
- package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
- package/lib/commonjs/main.js +7 -0
- package/lib/commonjs/main.js.map +1 -1
- package/lib/commonjs/networking/api-requests/auth.api.js +74 -1
- package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
- package/lib/commonjs/networking/apiClient.js +2 -1
- package/lib/commonjs/networking/apiClient.js.map +1 -1
- package/lib/commonjs/networking/outboundQueue.js +92 -0
- package/lib/commonjs/networking/outboundQueue.js.map +1 -0
- package/lib/commonjs/networking/xmpp/createTimeoutPromise.xmpp.js +4 -1
- package/lib/commonjs/networking/xmpp/createTimeoutPromise.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js +7 -8
- package/lib/commonjs/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
- package/lib/commonjs/networking/xmpp/getRoomsPaged.xmpp.js +26 -3
- package/lib/commonjs/networking/xmpp/getRoomsPaged.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js +26 -8
- package/lib/commonjs/networking/xmpp/presenceInRoom.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/xmppClient.js +371 -26
- package/lib/commonjs/networking/xmppClient.js.map +1 -1
- package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js +22 -6
- package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js.map +1 -1
- package/lib/commonjs/roomStore/roomHeapSlice.js +26 -8
- package/lib/commonjs/roomStore/roomHeapSlice.js.map +1 -1
- package/lib/commonjs/roomStore/roomsSlice.js +157 -23
- package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
- package/lib/commonjs/utils/installPromiseRejectionTracker.js +83 -0
- package/lib/commonjs/utils/installPromiseRejectionTracker.js.map +1 -0
- package/lib/commonjs/utils/resendMessage.js +1 -1
- package/lib/commonjs/utils/resendMessage.js.map +1 -1
- package/lib/module/assets/icons.js +5 -1
- package/lib/module/assets/icons.js.map +1 -1
- package/lib/module/components/ContextMenu/ContextMenuComponents.js +11 -5
- package/lib/module/components/ContextMenu/ContextMenuComponents.js.map +1 -1
- package/lib/module/components/MainComponents/ChatHeader.js +7 -1
- package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/module/components/MainComponents/ChatRoom.js +67 -35
- package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/module/components/MainComponents/ChatWrapper.js +59 -14
- package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/MediaMessage.js +15 -7
- package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/module/components/MainComponents/MessageContainer.js +2 -2
- package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
- package/lib/module/components/MainComponents/MessageList.js +176 -31
- package/lib/module/components/MainComponents/MessageList.js.map +1 -1
- package/lib/module/components/MainComponents/ReduxWrapper.js +18 -8
- package/lib/module/components/MainComponents/ReduxWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/SystemMessage.js +33 -21
- package/lib/module/components/MainComponents/SystemMessage.js.map +1 -1
- package/lib/module/components/MessageBubble/Message.js +118 -20
- package/lib/module/components/MessageBubble/Message.js.map +1 -1
- package/lib/module/components/MessageBubble/MessageInteractions.js +84 -24
- package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/module/components/Modals/AttachSheet/AttachSheet.js +15 -3
- package/lib/module/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/DocumentViewer.js +99 -0
- package/lib/module/components/Modals/FilePreviewModal/DocumentViewer.js.map +1 -0
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +179 -42
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/PdfView.js +31 -3
- package/lib/module/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
- package/lib/module/components/Modals/Modal/Modal.js +5 -1
- package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
- package/lib/module/components/Modals/ModalWrapper/ModalWrapper.js +80 -41
- package/lib/module/components/Modals/ModalWrapper/ModalWrapper.js.map +1 -1
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +3 -3
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/module/components/Modals/styledModalComponents.js +4 -9
- package/lib/module/components/Modals/styledModalComponents.js.map +1 -1
- package/lib/module/components/styled/MediaFilePreview.js +116 -6
- package/lib/module/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/module/components/styled/MessageImage.js +51 -12
- package/lib/module/components/styled/MessageImage.js.map +1 -1
- package/lib/module/components/styled/NewMessageLabel.js +8 -6
- package/lib/module/components/styled/NewMessageLabel.js.map +1 -1
- package/lib/module/components/styled/SendInput.js +54 -30
- package/lib/module/components/styled/SendInput.js.map +1 -1
- package/lib/module/components/styled/StyledInputComponents/MediaComponents.js +14 -4
- package/lib/module/components/styled/StyledInputComponents/MediaComponents.js.map +1 -1
- package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js +7 -2
- package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
- package/lib/module/components/styled/UnsupportedType.js +5 -1
- package/lib/module/components/styled/UnsupportedType.js.map +1 -1
- package/lib/module/components/styled/VideoMessage.js +61 -23
- package/lib/module/components/styled/VideoMessage.js.map +1 -1
- package/lib/module/context/MessageNotificationContext.js +7 -7
- package/lib/module/context/MessageNotificationContext.js.map +1 -1
- package/lib/module/context/xmppProvider.js +319 -37
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/helpers/chatAutoEnterer.js +2 -7
- package/lib/module/helpers/chatAutoEnterer.js.map +1 -1
- package/lib/module/helpers/historyPreloadScheduler.js +4 -1
- package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
- package/lib/module/helpers/insertMessageWithDelimiter.js +15 -5
- package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
- package/lib/module/helpers/keyboardLayout.js +12 -0
- package/lib/module/helpers/keyboardLayout.js.map +1 -0
- package/lib/module/helpers/mediaDimensions.js +46 -0
- package/lib/module/helpers/mediaDimensions.js.map +1 -0
- package/lib/module/helpers/mimeToExtension.js +124 -0
- package/lib/module/helpers/mimeToExtension.js.map +1 -0
- package/lib/module/helpers/normalizeRoomJid.js +15 -0
- package/lib/module/helpers/normalizeRoomJid.js.map +1 -0
- package/lib/module/helpers/resolveInitBeforeLoadUser.js +71 -0
- package/lib/module/helpers/resolveInitBeforeLoadUser.js.map +1 -1
- package/lib/module/hooks/useChatRoomFocus.js +82 -0
- package/lib/module/hooks/useChatRoomFocus.js.map +1 -0
- package/lib/module/hooks/useChatWrapperInit.js +22 -10
- package/lib/module/hooks/useChatWrapperInit.js.map +1 -1
- package/lib/module/hooks/useEventHandlers.js +9 -1
- package/lib/module/hooks/useEventHandlers.js.map +1 -1
- package/lib/module/hooks/useHeapSender.js +1 -1
- package/lib/module/hooks/useHeapSender.js.map +1 -1
- package/lib/module/hooks/useLogout.js +3 -3
- package/lib/module/hooks/useLogout.js.map +1 -1
- package/lib/module/hooks/useMessageHeapState.js +6 -2
- package/lib/module/hooks/useMessageHeapState.js.map +1 -1
- package/lib/module/hooks/usePushNotifications.js +6 -2
- package/lib/module/hooks/usePushNotifications.js.map +1 -1
- package/lib/module/hooks/useRoomState.js +2 -0
- package/lib/module/hooks/useRoomState.js.map +1 -1
- package/lib/module/hooks/useSendMessage.js +252 -17
- package/lib/module/hooks/useSendMessage.js.map +1 -1
- package/lib/module/hooks/useUnreadMessagesCounter.js +12 -14
- package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
- package/lib/module/main.js +1 -0
- package/lib/module/main.js.map +1 -1
- package/lib/module/networking/api-requests/auth.api.js +74 -2
- package/lib/module/networking/api-requests/auth.api.js.map +1 -1
- package/lib/module/networking/apiClient.js +2 -1
- package/lib/module/networking/apiClient.js.map +1 -1
- package/lib/module/networking/outboundQueue.js +84 -0
- package/lib/module/networking/outboundQueue.js.map +1 -0
- package/lib/module/networking/xmpp/createTimeoutPromise.xmpp.js +4 -1
- package/lib/module/networking/xmpp/createTimeoutPromise.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js +7 -8
- package/lib/module/networking/xmpp/flushLastViewedToPrivateStore.js.map +1 -1
- package/lib/module/networking/xmpp/getRoomsPaged.xmpp.js +26 -3
- package/lib/module/networking/xmpp/getRoomsPaged.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/presenceInRoom.xmpp.js +26 -8
- package/lib/module/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/sendTextMessage.xmpp.js +2 -1
- package/lib/module/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
- package/lib/module/networking/xmppClient.js +371 -26
- package/lib/module/networking/xmppClient.js.map +1 -1
- package/lib/module/roomStore/Middleware/unreadMidlleware.js +22 -6
- package/lib/module/roomStore/Middleware/unreadMidlleware.js.map +1 -1
- package/lib/module/roomStore/roomHeapSlice.js +24 -7
- package/lib/module/roomStore/roomHeapSlice.js.map +1 -1
- package/lib/module/roomStore/roomsSlice.js +154 -22
- package/lib/module/roomStore/roomsSlice.js.map +1 -1
- package/lib/module/utils/installPromiseRejectionTracker.js +78 -0
- package/lib/module/utils/installPromiseRejectionTracker.js.map +1 -0
- package/lib/module/utils/resendMessage.js +1 -1
- package/lib/module/utils/resendMessage.js.map +1 -1
- package/lib/typescript/assets/icons.d.ts +8 -4
- package/lib/typescript/assets/icons.d.ts.map +1 -1
- package/lib/typescript/components/ContextMenu/ContextMenuComponents.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MediaMessage.d.ts +1 -0
- package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MessageContainer.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ReduxWrapper.d.ts +1 -0
- package/lib/typescript/components/MainComponents/ReduxWrapper.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/SystemMessage.d.ts +0 -7
- package/lib/typescript/components/MainComponents/SystemMessage.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts +4 -2
- package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
- package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/DocumentViewer.d.ts +29 -0
- package/lib/typescript/components/Modals/FilePreviewModal/DocumentViewer.d.ts.map +1 -0
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts +0 -1
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/PdfView.d.ts.map +1 -1
- package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ModalWrapper/ModalWrapper.d.ts +6 -0
- package/lib/typescript/components/Modals/ModalWrapper/ModalWrapper.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/styledModalComponents.d.ts.map +1 -1
- package/lib/typescript/components/styled/MediaFilePreview.d.ts.map +1 -1
- package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
- package/lib/typescript/components/styled/NewMessageLabel.d.ts +1 -5
- package/lib/typescript/components/styled/NewMessageLabel.d.ts.map +1 -1
- package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
- package/lib/typescript/components/styled/StyledInputComponents/MediaComponents.d.ts +9 -1
- package/lib/typescript/components/styled/StyledInputComponents/MediaComponents.d.ts.map +1 -1
- package/lib/typescript/components/styled/StyledInputComponents/StyledInputComponents.d.ts.map +1 -1
- package/lib/typescript/components/styled/UnsupportedType.d.ts +1 -0
- package/lib/typescript/components/styled/UnsupportedType.d.ts.map +1 -1
- package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
- package/lib/typescript/context/xmppProvider.d.ts +1 -0
- package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
- package/lib/typescript/helpers/chatAutoEnterer.d.ts.map +1 -1
- package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
- package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
- package/lib/typescript/helpers/keyboardLayout.d.ts +9 -0
- package/lib/typescript/helpers/keyboardLayout.d.ts.map +1 -0
- package/lib/typescript/helpers/mediaDimensions.d.ts +9 -0
- package/lib/typescript/helpers/mediaDimensions.d.ts.map +1 -0
- package/lib/typescript/helpers/mimeToExtension.d.ts +37 -0
- package/lib/typescript/helpers/mimeToExtension.d.ts.map +1 -0
- package/lib/typescript/helpers/normalizeRoomJid.d.ts +2 -0
- package/lib/typescript/helpers/normalizeRoomJid.d.ts.map +1 -0
- package/lib/typescript/helpers/resolveInitBeforeLoadUser.d.ts +18 -0
- package/lib/typescript/helpers/resolveInitBeforeLoadUser.d.ts.map +1 -1
- package/lib/typescript/hooks/useChatRoomFocus.d.ts +42 -0
- package/lib/typescript/hooks/useChatRoomFocus.d.ts.map +1 -0
- package/lib/typescript/hooks/useChatWrapperInit.d.ts.map +1 -1
- package/lib/typescript/hooks/useEventHandlers.d.ts +6 -0
- package/lib/typescript/hooks/useEventHandlers.d.ts.map +1 -1
- package/lib/typescript/hooks/useHeapSender.d.ts.map +1 -1
- package/lib/typescript/hooks/useMessageHeapState.d.ts +2 -0
- package/lib/typescript/hooks/useMessageHeapState.d.ts.map +1 -1
- package/lib/typescript/hooks/usePushNotifications.d.ts.map +1 -1
- package/lib/typescript/hooks/useRoomState.d.ts +1 -0
- package/lib/typescript/hooks/useRoomState.d.ts.map +1 -1
- package/lib/typescript/hooks/useSendMessage.d.ts +2 -1
- package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/hooks/useUnreadMessagesCounter.d.ts.map +1 -1
- package/lib/typescript/main.d.ts +1 -0
- package/lib/typescript/main.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/auth.api.d.ts +3 -0
- package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
- package/lib/typescript/networking/apiClient.d.ts.map +1 -1
- package/lib/typescript/networking/outboundQueue.d.ts +57 -0
- package/lib/typescript/networking/outboundQueue.d.ts.map +1 -0
- package/lib/typescript/networking/xmpp/createTimeoutPromise.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts +1 -1
- package/lib/typescript/networking/xmpp/flushLastViewedToPrivateStore.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/getRoomsPaged.xmpp.d.ts +1 -1
- package/lib/typescript/networking/xmpp/getRoomsPaged.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/sendTextMessage.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmppClient.d.ts +58 -5
- package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
- package/lib/typescript/roomStore/Middleware/unreadMidlleware.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomHeapSlice.d.ts +22 -1
- package/lib/typescript/roomStore/roomHeapSlice.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts +8 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
- package/lib/typescript/types/models/media.model.d.ts +1 -0
- package/lib/typescript/types/models/media.model.d.ts.map +1 -1
- package/lib/typescript/types/models/xmpp.model.d.ts +1 -1
- package/lib/typescript/types/models/xmpp.model.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +10 -0
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/lib/typescript/utils/installPromiseRejectionTracker.d.ts +20 -0
- package/lib/typescript/utils/installPromiseRejectionTracker.d.ts.map +1 -0
- package/lib/typescript/utils/resendMessage.d.ts.map +1 -1
- package/package.json +18 -2
- package/src/assets/icons.tsx +23 -14
- package/src/components/ContextMenu/ContextMenuComponents.tsx +10 -5
- package/src/components/MainComponents/ChatHeader.tsx +5 -1
- package/src/components/MainComponents/ChatRoom.tsx +81 -61
- package/src/components/MainComponents/ChatWrapper.tsx +100 -21
- package/src/components/MainComponents/MediaMessage.tsx +18 -8
- package/src/components/MainComponents/MessageContainer.tsx +4 -2
- package/src/components/MainComponents/MessageList.tsx +185 -31
- package/src/components/MainComponents/ReduxWrapper.tsx +19 -9
- package/src/components/MainComponents/SystemMessage.tsx +38 -26
- package/src/components/MessageBubble/Message.tsx +110 -27
- package/src/components/MessageBubble/MessageInteractions.tsx +98 -29
- package/src/components/Modals/AttachSheet/AttachSheet.tsx +17 -3
- package/src/components/Modals/FilePreviewModal/DocumentViewer.tsx +93 -0
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +182 -37
- package/src/components/Modals/FilePreviewModal/PdfView.tsx +32 -4
- package/src/components/Modals/Modal/Modal.tsx +4 -1
- package/src/components/Modals/ModalWrapper/ModalWrapper.tsx +77 -44
- package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +19 -15
- package/src/components/Modals/styledModalComponents.tsx +4 -9
- package/src/components/styled/MediaFilePreview.tsx +111 -5
- package/src/components/styled/MessageImage.tsx +58 -14
- package/src/components/styled/NewMessageLabel.tsx +8 -5
- package/src/components/styled/SendInput.tsx +67 -29
- package/src/components/styled/StyledInputComponents/MediaComponents.tsx +15 -5
- package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +7 -2
- package/src/components/styled/UnsupportedType.tsx +7 -1
- package/src/components/styled/VideoMessage.tsx +59 -18
- package/src/context/MessageNotificationContext.tsx +8 -8
- package/src/context/xmppProvider.tsx +337 -32
- package/src/helpers/chatAutoEnterer.ts +2 -8
- package/src/helpers/historyPreloadScheduler.ts +4 -1
- package/src/helpers/insertMessageWithDelimiter.ts +22 -15
- package/src/helpers/keyboardLayout.ts +18 -0
- package/src/helpers/mediaDimensions.ts +47 -0
- package/src/helpers/mimeToExtension.ts +135 -0
- package/src/helpers/normalizeRoomJid.ts +6 -0
- package/src/helpers/resolveInitBeforeLoadUser.ts +79 -0
- package/src/hooks/useChatRoomFocus.ts +95 -0
- package/src/hooks/useChatWrapperInit.ts +51 -46
- package/src/hooks/useEventHandlers.tsx +24 -1
- package/src/hooks/useHeapSender.tsx +2 -1
- package/src/hooks/useLogout.tsx +3 -3
- package/src/hooks/useMessageHeapState.tsx +6 -2
- package/src/hooks/usePushNotifications.ts +21 -8
- package/src/hooks/useRoomState.tsx +4 -0
- package/src/hooks/useSendMessage.tsx +333 -17
- package/src/hooks/useUnreadMessagesCounter.ts +13 -16
- package/src/main.ts +1 -0
- package/src/networking/api-requests/auth.api.ts +60 -2
- package/src/networking/apiClient.ts +2 -1
- package/src/networking/outboundQueue.ts +98 -0
- package/src/networking/xmpp/createTimeoutPromise.xmpp.ts +5 -1
- package/src/networking/xmpp/flushLastViewedToPrivateStore.ts +11 -13
- package/src/networking/xmpp/getRoomsPaged.xmpp.ts +27 -3
- package/src/networking/xmpp/presenceInRoom.xmpp.ts +24 -9
- package/src/networking/xmpp/sendTextMessage.xmpp.ts +2 -1
- package/src/networking/xmppClient.ts +399 -31
- package/src/roomStore/Middleware/unreadMidlleware.tsx +23 -5
- package/src/roomStore/roomHeapSlice.ts +47 -4
- package/src/roomStore/roomsSlice.ts +177 -27
- package/src/types/models/media.model.ts +3 -0
- package/src/types/models/xmpp.model.ts +2 -1
- package/src/types/types.ts +25 -0
- package/src/utils/installPromiseRejectionTracker.ts +91 -0
- package/src/utils/resendMessage.ts +2 -1
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from '../../roomStore/chatSettingsSlice';
|
|
10
10
|
import {ChatWrapperBox} from '../styled/ChatWrapperBox';
|
|
11
11
|
import {Overlay, StyledModal} from '../styled/MediaModal';
|
|
12
|
+
import ConnectionBanner from './ConnectionBanner';
|
|
12
13
|
import {Message} from '../MessageBubble/Message';
|
|
13
14
|
import {IConfig, IRoom, MessageProps, ModalType, User} from '../../types/types';
|
|
14
15
|
import {useXmppClient} from '../../context/xmppProvider';
|
|
@@ -30,6 +31,7 @@ import {ModalWrapper} from '../Modals/ModalWrapper/ModalWrapper';
|
|
|
30
31
|
import {useChatSettingState} from '../../hooks/useChatSettingState';
|
|
31
32
|
import {DeviceEventEmitter, Pressable, Text, View} from 'react-native';
|
|
32
33
|
import {pushLog as devPushLog} from '../../utils/devLogger';
|
|
34
|
+
import {normalizeRoomJid} from '../../helpers/normalizeRoomJid';
|
|
33
35
|
|
|
34
36
|
interface ChatWrapperProps {
|
|
35
37
|
token?: string;
|
|
@@ -126,7 +128,11 @@ const ChatWrapper: FC<ChatWrapperProps> = ({
|
|
|
126
128
|
|
|
127
129
|
useEffect(() => {
|
|
128
130
|
if (roomJID) {
|
|
129
|
-
dispatch(
|
|
131
|
+
dispatch(
|
|
132
|
+
setCurrentRoom({
|
|
133
|
+
roomJID: normalizeRoomJid(roomJID, config?.xmppSettings?.conference),
|
|
134
|
+
}),
|
|
135
|
+
);
|
|
130
136
|
}
|
|
131
137
|
|
|
132
138
|
const initXmmpClient = async () => {
|
|
@@ -186,45 +192,79 @@ const ChatWrapper: FC<ChatWrapperProps> = ({
|
|
|
186
192
|
|
|
187
193
|
if (!client && !storedClient) {
|
|
188
194
|
devPushLog('rn', 'ChatWrapper: initing xmpp client (legacy path)');
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
195
|
+
// The outer `.then(c => {...})` used to lack a `.catch()` —
|
|
196
|
+
// if initializeClient rejected (network / SASL), the outer
|
|
197
|
+
// try/catch couldn't see it because the rejection happens in
|
|
198
|
+
// the .then handler, not in the awaited promise itself.
|
|
199
|
+
// Convert to await + try/catch.
|
|
200
|
+
try {
|
|
201
|
+
const c = await initializeClient(
|
|
202
|
+
user.xmppUsername || user.defaultWallet?.walletAddress,
|
|
203
|
+
user.xmppPassword,
|
|
204
|
+
config?.xmppSettings
|
|
205
|
+
);
|
|
206
|
+
try {
|
|
207
|
+
await c.getRoomsStanza();
|
|
208
|
+
c.getChatsPrivateStoreRequestStanza().catch((err: unknown) =>
|
|
209
|
+
console.warn('getChatsPrivateStoreRequestStanza failed', err)
|
|
210
|
+
);
|
|
211
|
+
dispatch(setStoreClient(c));
|
|
212
|
+
setClient(c);
|
|
213
|
+
} catch (err) {
|
|
214
|
+
console.warn('getRoomsStanza failed', err);
|
|
215
|
+
}
|
|
216
|
+
} catch (err) {
|
|
217
|
+
devPushLog('warn', 'initializeClient failed (legacy path)', err);
|
|
218
|
+
}
|
|
202
219
|
setInited(true);
|
|
203
|
-
if (config?.refreshTokens?.enabled) {
|
|
220
|
+
if (config?.refreshTokens?.enabled) {
|
|
221
|
+
// refresh() is fire-and-forget but rejects on bad
|
|
222
|
+
// refreshToken / network — surface via .catch instead of
|
|
223
|
+
// leaving the rejection unhandled (was bug #4, id:2).
|
|
224
|
+
refresh().catch((err) =>
|
|
225
|
+
console.warn('refresh failed', err)
|
|
226
|
+
);
|
|
227
|
+
}
|
|
204
228
|
} else if (storedClient) {
|
|
205
229
|
devPushLog('rn', 'ChatWrapper: reusing storedClient');
|
|
206
230
|
setClient(storedClient);
|
|
207
231
|
if (!activeRoomJID) {
|
|
208
232
|
storedClient.getRoomsStanza()
|
|
209
233
|
.then(() => {
|
|
210
|
-
storedClient.getChatsPrivateStoreRequestStanza()
|
|
234
|
+
storedClient.getChatsPrivateStoreRequestStanza().catch(
|
|
235
|
+
(err: unknown) =>
|
|
236
|
+
console.warn('getChatsPrivateStoreRequestStanza failed', err)
|
|
237
|
+
);
|
|
211
238
|
})
|
|
212
239
|
.catch((err: unknown) => console.warn('getRoomsStanza failed', err));
|
|
213
240
|
}
|
|
214
241
|
setInited(true);
|
|
215
|
-
if (config?.refreshTokens?.enabled) {
|
|
242
|
+
if (config?.refreshTokens?.enabled) {
|
|
243
|
+
refresh().catch((err) =>
|
|
244
|
+
console.warn('refresh failed', err)
|
|
245
|
+
);
|
|
246
|
+
}
|
|
216
247
|
} else if (client) {
|
|
217
248
|
devPushLog('rn', 'ChatWrapper: reusing provider client');
|
|
218
249
|
if (!activeRoomJID) {
|
|
219
250
|
client.getRoomsStanza()
|
|
220
251
|
.then(() => {
|
|
221
|
-
client.getChatsPrivateStoreRequestStanza()
|
|
252
|
+
client.getChatsPrivateStoreRequestStanza().catch(
|
|
253
|
+
(err: unknown) =>
|
|
254
|
+
console.warn('getChatsPrivateStoreRequestStanza failed', err)
|
|
255
|
+
);
|
|
222
256
|
})
|
|
223
257
|
.catch((err: unknown) => console.warn('getRoomsStanza failed', err));
|
|
224
258
|
}
|
|
225
|
-
client.getChatsPrivateStoreRequestStanza()
|
|
259
|
+
client.getChatsPrivateStoreRequestStanza().catch((err: unknown) =>
|
|
260
|
+
console.warn('getChatsPrivateStoreRequestStanza failed', err)
|
|
261
|
+
);
|
|
226
262
|
setInited(true);
|
|
227
|
-
if (config?.refreshTokens?.enabled) {
|
|
263
|
+
if (config?.refreshTokens?.enabled) {
|
|
264
|
+
refresh().catch((err) =>
|
|
265
|
+
console.warn('refresh failed', err)
|
|
266
|
+
);
|
|
267
|
+
}
|
|
228
268
|
}
|
|
229
269
|
|
|
230
270
|
dispatch(setIsLoading({loading: false}));
|
|
@@ -250,6 +290,38 @@ const ChatWrapper: FC<ChatWrapperProps> = ({
|
|
|
250
290
|
config?.initBeforeLoad,
|
|
251
291
|
]);
|
|
252
292
|
|
|
293
|
+
// Cache-first display (initBeforeLoad). The main effect above only marks
|
|
294
|
+
// the chat `inited` once the provider bootstrap reaches 'ready' — which
|
|
295
|
+
// waits on the cold XMPP connect. On re-entry that left the user staring
|
|
296
|
+
// at a loader while fully-cached rooms/messages sat in redux-persist
|
|
297
|
+
// ("pulls a new connection for 100 years"). Here we render the cached
|
|
298
|
+
// content the instant rehydration lands; the live client gets wired by
|
|
299
|
+
// the main effect when the connect completes (send/loadMore activate
|
|
300
|
+
// then). Mirrors web showing cached rooms immediately + refreshing in
|
|
301
|
+
// the background.
|
|
302
|
+
useEffect(() => {
|
|
303
|
+
if (!config?.initBeforeLoad || initMode !== 'provider') {return;}
|
|
304
|
+
if (isInited || showModal) {return;}
|
|
305
|
+
if (providerBootstrapStatus === 'failed') {return;}
|
|
306
|
+
const haveCachedRooms = !!rooms && Object.keys(rooms).length > 0;
|
|
307
|
+
const haveUser =
|
|
308
|
+
!!user?.xmppUsername || !!user?.defaultWallet?.walletAddress;
|
|
309
|
+
if (haveCachedRooms && haveUser) {
|
|
310
|
+
devPushLog('rn', 'ChatWrapper: cache-first — showing persisted rooms while provider connects');
|
|
311
|
+
setShowModal(false);
|
|
312
|
+
setInited(true);
|
|
313
|
+
}
|
|
314
|
+
}, [
|
|
315
|
+
config?.initBeforeLoad,
|
|
316
|
+
initMode,
|
|
317
|
+
isInited,
|
|
318
|
+
showModal,
|
|
319
|
+
providerBootstrapStatus,
|
|
320
|
+
rooms,
|
|
321
|
+
user?.xmppUsername,
|
|
322
|
+
user?.defaultWallet?.walletAddress,
|
|
323
|
+
]);
|
|
324
|
+
|
|
253
325
|
// Skip the legacy email/password LoginForm entirely when XmppProvider
|
|
254
326
|
// is driving auth via initBeforeLoad — the bootstrap effect will
|
|
255
327
|
// populate the user shortly. Showing LoginForm here causes a flicker
|
|
@@ -270,7 +342,13 @@ const ChatWrapper: FC<ChatWrapperProps> = ({
|
|
|
270
342
|
|
|
271
343
|
return (
|
|
272
344
|
<>
|
|
273
|
-
{
|
|
345
|
+
{/* Connection/bootstrap error UI. For patient-facing apps the
|
|
346
|
+
full-screen dark overlay reads as a crash, so
|
|
347
|
+
`disableConnectionErrorOverlay` swaps it for a subtle inline
|
|
348
|
+
"Connection lost. Retrying…" banner (and reconnect + re-join now
|
|
349
|
+
recover automatically). */}
|
|
350
|
+
{showModal && config?.disableConnectionErrorOverlay && <ConnectionBanner />}
|
|
351
|
+
{showModal && !config?.disableConnectionErrorOverlay && (
|
|
274
352
|
<Overlay>
|
|
275
353
|
<View
|
|
276
354
|
style={{
|
|
@@ -356,6 +434,7 @@ const ChatWrapper: FC<ChatWrapperProps> = ({
|
|
|
356
434
|
backgroundColorButton="#E53935"
|
|
357
435
|
handleClick={handleDeleteClick}
|
|
358
436
|
handleCloseModal={handleCloseDeleteModal}
|
|
437
|
+
compact
|
|
359
438
|
/>
|
|
360
439
|
)}
|
|
361
440
|
</ChatWrapperBox>
|
|
@@ -5,12 +5,14 @@ import CustomMessageImage from '../styled/MessageImage';
|
|
|
5
5
|
import CustomMessageVideo from '../styled/VideoMessage';
|
|
6
6
|
import AudioMessage from '../styled/AudioMessage';
|
|
7
7
|
import { Text } from 'react-native';
|
|
8
|
+
import { deriveDisplayFilename } from '../../helpers/mimeToExtension';
|
|
8
9
|
|
|
9
10
|
interface MediaMessageProps {
|
|
10
11
|
mimeType?: string;
|
|
11
12
|
message?: IMessage;
|
|
12
13
|
location?: string;
|
|
13
14
|
messageText?: string;
|
|
15
|
+
isUser: boolean;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
const MediaMessage: React.FC<MediaMessageProps> = ({
|
|
@@ -18,13 +20,20 @@ const MediaMessage: React.FC<MediaMessageProps> = ({
|
|
|
18
20
|
location,
|
|
19
21
|
messageText,
|
|
20
22
|
message,
|
|
23
|
+
isUser,
|
|
21
24
|
}) => {
|
|
22
|
-
if (mimeType)
|
|
23
|
-
|
|
25
|
+
if (mimeType) {
|
|
26
|
+
const displayName = deriveDisplayFilename({
|
|
27
|
+
fileName: message?.fileName,
|
|
28
|
+
originalName: (message as any)?.originalName,
|
|
29
|
+
url: location || messageText,
|
|
30
|
+
mime: mimeType,
|
|
31
|
+
});
|
|
32
|
+
switch (true) {
|
|
24
33
|
case mimeType.startsWith('image/'):
|
|
25
34
|
return (
|
|
26
35
|
<CustomMessageImage
|
|
27
|
-
fileName={
|
|
36
|
+
fileName={displayName}
|
|
28
37
|
fileURL={messageText || ''}
|
|
29
38
|
mimetype={mimeType}
|
|
30
39
|
/>
|
|
@@ -32,7 +41,7 @@ const MediaMessage: React.FC<MediaMessageProps> = ({
|
|
|
32
41
|
case mimeType.startsWith('video/'):
|
|
33
42
|
return (
|
|
34
43
|
<CustomMessageVideo
|
|
35
|
-
fileName={
|
|
44
|
+
fileName={displayName}
|
|
36
45
|
fileURL={location || ''}
|
|
37
46
|
mimetype={mimeType}
|
|
38
47
|
/>
|
|
@@ -44,21 +53,22 @@ const MediaMessage: React.FC<MediaMessageProps> = ({
|
|
|
44
53
|
// Many backends tag binary payloads (PDFs, DOCX, archives) as
|
|
45
54
|
// application/octet-stream; sniff the filename extension for the
|
|
46
55
|
// legitimate audio case before falling through to FileDownload.
|
|
47
|
-
const fileName = message?.fileName || location?.split('/')?.pop() || 'MediaFile';
|
|
48
56
|
if (mimeType.includes('application/octet-stream')) {
|
|
49
|
-
if (/\.(mp3|m4a|wav|aac|ogg|flac)$/i.test(
|
|
57
|
+
if (/\.(mp3|m4a|wav|aac|ogg|flac)$/i.test(displayName)) {
|
|
50
58
|
return <AudioMessage src={location || ''} />;
|
|
51
59
|
}
|
|
52
60
|
}
|
|
53
61
|
return (
|
|
54
62
|
<FileDownload
|
|
55
63
|
fileURL={location ? location : ''}
|
|
56
|
-
fileName={
|
|
64
|
+
fileName={displayName}
|
|
57
65
|
mimetype={mimeType}
|
|
66
|
+
isUser={isUser}
|
|
58
67
|
/>
|
|
59
68
|
);
|
|
60
69
|
}
|
|
61
|
-
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
62
72
|
return <Text>Unsupported media type</Text>;
|
|
63
73
|
};
|
|
64
74
|
|
|
@@ -73,7 +73,7 @@ export const MessageContainer: FC<MessageContainerProps> = ({
|
|
|
73
73
|
);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
if (message?.id
|
|
76
|
+
if (String(message?.id || '').startsWith('delimiter-new')) {
|
|
77
77
|
return CustomNewMessageLabel ? (
|
|
78
78
|
<CustomNewMessageLabel color={config?.colors?.primary} />
|
|
79
79
|
) : (
|
|
@@ -85,7 +85,9 @@ export const MessageContainer: FC<MessageContainerProps> = ({
|
|
|
85
85
|
|
|
86
86
|
return (
|
|
87
87
|
<View key={message.id}>
|
|
88
|
-
{showDateLabel &&
|
|
88
|
+
{showDateLabel &&
|
|
89
|
+
!activeMessage &&
|
|
90
|
+
!String(message.id || '').startsWith('delimiter-new') ? (
|
|
89
91
|
CustomDaySeparator ? (
|
|
90
92
|
<CustomDaySeparator
|
|
91
93
|
date={messageDate}
|
|
@@ -9,16 +9,17 @@ import React, {
|
|
|
9
9
|
} from 'react';
|
|
10
10
|
import {
|
|
11
11
|
View,
|
|
12
|
+
Text,
|
|
12
13
|
StyleSheet,
|
|
13
14
|
FlatList,
|
|
14
15
|
Image,
|
|
15
16
|
NativeSyntheticEvent,
|
|
16
17
|
NativeScrollEvent,
|
|
17
18
|
TouchableOpacity,
|
|
18
|
-
Keyboard,
|
|
19
19
|
ImageSourcePropType,
|
|
20
20
|
} from 'react-native';
|
|
21
21
|
import { IMessage, User, IConfig, IRoom } from '../../types/types';
|
|
22
|
+
import { msgSortableMs } from '../../roomStore/roomsSlice';
|
|
22
23
|
import Composing from '../styled/StyledInputComponents/Composing';
|
|
23
24
|
import TreadLabel from '../styled/TreadLabel';
|
|
24
25
|
import { MessageContainer } from './MessageContainer';
|
|
@@ -69,10 +70,24 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
69
70
|
.room! as IRoom;
|
|
70
71
|
const [isUserAtBottom, setIsUserAtBottom] = useState(true);
|
|
71
72
|
const [showNewMessageIndicator, setShowNewMessageIndicator] = useState(false);
|
|
72
|
-
const [isContentOffset, setIsContentOffset] = useState(false);
|
|
73
73
|
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
|
74
74
|
const [isScrollBlocked, setIsScrollBlocked] = useState(false);
|
|
75
|
-
|
|
75
|
+
// Count of messages that arrived while the user was scrolled up.
|
|
76
|
+
// Renders as a badge on the scroll-to-bottom arrow so they know how
|
|
77
|
+
// much they're missing without having to scroll to find out.
|
|
78
|
+
const [unreadWhileScrolledUp, setUnreadWhileScrolledUp] = useState(0);
|
|
79
|
+
// Newest message timestamp at the moment the user scrolled away from
|
|
80
|
+
// the bottom. The badge counts only messages NEWER than this, so
|
|
81
|
+
// back-pagination (loading OLDER history while scrolled up) never
|
|
82
|
+
// inflates the count. Was previously a message-COUNT snapshot, which
|
|
83
|
+
// wrongly counted back-paginated old messages as "new" (Android repro).
|
|
84
|
+
const newestSeenTsRef = useRef<number | null>(null);
|
|
85
|
+
// Refs mirror the viewport state synchronously. The auto-follow logic
|
|
86
|
+
// runs from FlatList callbacks where setState hasn't necessarily
|
|
87
|
+
// committed yet; relying on stale React state is what caused the chat
|
|
88
|
+
// to jump back to the bottom when a new message landed mid-scroll.
|
|
89
|
+
const isUserAtBottomRef = useRef(true);
|
|
90
|
+
const hasUserScrolledRef = useRef(false);
|
|
76
91
|
|
|
77
92
|
const flatListRef = useRef<FlatList<IMessage>>(null);
|
|
78
93
|
|
|
@@ -129,7 +144,10 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
129
144
|
const bNum = new Date(b?.date as any).getTime() || 0;
|
|
130
145
|
return aNum - bNum;
|
|
131
146
|
});
|
|
132
|
-
|
|
147
|
+
const deduped = Array.from(
|
|
148
|
+
new Map(sorted.map((m) => [m.id, m])).values()
|
|
149
|
+
);
|
|
150
|
+
return deduped;
|
|
133
151
|
}, [addReplyMessages, isReply, roomJID, activeMessage]);
|
|
134
152
|
|
|
135
153
|
const handleLoadMore = useCallback(async () => {
|
|
@@ -174,16 +192,72 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
174
192
|
]);
|
|
175
193
|
|
|
176
194
|
const dataMessages = useMemo(() => {
|
|
177
|
-
|
|
178
|
-
|
|
195
|
+
const base = memoizedMessages.slice().reverse();
|
|
196
|
+
const boundaryTs = newestSeenTsRef.current;
|
|
197
|
+
if (
|
|
198
|
+
isUserAtBottomRef.current ||
|
|
199
|
+
boundaryTs === null ||
|
|
200
|
+
unreadWhileScrolledUp === 0
|
|
201
|
+
) {
|
|
202
|
+
return base;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
let lastNewIndex = -1;
|
|
206
|
+
for (let i = 0; i < base.length; i++) {
|
|
207
|
+
if (msgSortableMs(base[i]) > boundaryTs) {
|
|
208
|
+
lastNewIndex = i;
|
|
209
|
+
} else {
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (lastNewIndex === -1) {return base;}
|
|
215
|
+
|
|
216
|
+
const withDivider = base.slice();
|
|
217
|
+
withDivider.splice(lastNewIndex + 1, 0, {
|
|
218
|
+
id: 'delimiter-new-local',
|
|
219
|
+
user: {
|
|
220
|
+
id: 'system',
|
|
221
|
+
name: undefined,
|
|
222
|
+
token: '',
|
|
223
|
+
refreshToken: '',
|
|
224
|
+
} as any,
|
|
225
|
+
date: new Date(boundaryTs).toISOString(),
|
|
226
|
+
body: 'New Messages',
|
|
227
|
+
roomJid: roomJID,
|
|
228
|
+
} as IMessage);
|
|
229
|
+
return withDivider;
|
|
230
|
+
}, [memoizedMessages, isUserAtBottom, roomJID, unreadWhileScrolledUp]);
|
|
179
231
|
|
|
180
232
|
const renderMessage = useCallback(
|
|
181
233
|
({ item, index }: { item: IMessage; index: number }) => {
|
|
234
|
+
if (String(item.id).startsWith('delimiter-new')) {
|
|
235
|
+
return (
|
|
236
|
+
<MessageContainer
|
|
237
|
+
CustomMessage={CustomMessage}
|
|
238
|
+
CustomDaySeparator={CustomDaySeparator}
|
|
239
|
+
CustomNewMessageLabel={CustomNewMessageLabel}
|
|
240
|
+
message={item}
|
|
241
|
+
activeMessage={activeMessage}
|
|
242
|
+
config={config}
|
|
243
|
+
walletAddress={user.xmppUsername || user.walletAddress}
|
|
244
|
+
isReply={isReply}
|
|
245
|
+
showDateLabel={false}
|
|
246
|
+
/>
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
182
250
|
const messageDate = new Date(item.date).toDateString();
|
|
183
251
|
let showDateLabel = false;
|
|
184
252
|
|
|
185
|
-
|
|
186
|
-
|
|
253
|
+
let nextMessage = null;
|
|
254
|
+
for (let i = index + 1; i < dataMessages.length; i++) {
|
|
255
|
+
const candidate = dataMessages[i];
|
|
256
|
+
if (!String(candidate.id).startsWith('delimiter-new')) {
|
|
257
|
+
nextMessage = candidate;
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
187
261
|
const nextMessageDate = nextMessage
|
|
188
262
|
? new Date(nextMessage.date).toDateString()
|
|
189
263
|
: null;
|
|
@@ -209,10 +283,13 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
209
283
|
[
|
|
210
284
|
activeMessage,
|
|
211
285
|
config,
|
|
286
|
+
CustomDaySeparator,
|
|
287
|
+
CustomMessage,
|
|
288
|
+
CustomNewMessageLabel,
|
|
289
|
+
dataMessages,
|
|
290
|
+
isReply,
|
|
212
291
|
user.xmppUsername,
|
|
213
292
|
user.walletAddress,
|
|
214
|
-
isReply,
|
|
215
|
-
memoizedMessages.length,
|
|
216
293
|
]
|
|
217
294
|
);
|
|
218
295
|
|
|
@@ -226,57 +303,94 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
226
303
|
}, [flatListRef]);
|
|
227
304
|
|
|
228
305
|
const handleContentSizeChange = useCallback(() => {
|
|
229
|
-
if (
|
|
230
|
-
scrollToBottom();
|
|
231
|
-
setIsContentOffset(false);
|
|
232
|
-
}
|
|
233
|
-
if (!isLoadingMore && flatListRef.current && isUserAtBottom) {
|
|
306
|
+
if (!isLoadingMore && flatListRef.current && isUserAtBottomRef.current) {
|
|
234
307
|
scrollToBottom();
|
|
235
|
-
} else if (!isLoadingMore &&
|
|
308
|
+
} else if (!isLoadingMore && hasUserScrolledRef.current) {
|
|
236
309
|
setShowNewMessageIndicator(true);
|
|
237
310
|
}
|
|
238
|
-
}, [
|
|
311
|
+
}, [scrollToBottom, isLoadingMore]);
|
|
239
312
|
|
|
240
313
|
const handleScroll = useCallback(
|
|
241
314
|
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
242
315
|
const contentOffset = event.nativeEvent.contentOffset.y;
|
|
243
316
|
|
|
244
|
-
|
|
317
|
+
// Don't force-dismiss the keyboard on every scroll event — any
|
|
318
|
+
// touch on the message list used to close it, which made replying
|
|
319
|
+
// to a long thread feel broken. Drag-to-dismiss still works via
|
|
320
|
+
// FlatList's keyboardDismissMode="interactive" below.
|
|
245
321
|
|
|
246
|
-
if (contentOffset > 150 && !
|
|
247
|
-
|
|
322
|
+
if (contentOffset > 150 && !hasUserScrolledRef.current) {
|
|
323
|
+
hasUserScrolledRef.current = true;
|
|
248
324
|
}
|
|
249
325
|
|
|
250
326
|
if (contentOffset < 150) {
|
|
251
|
-
|
|
327
|
+
isUserAtBottomRef.current = true;
|
|
252
328
|
setShowNewMessageIndicator(false);
|
|
253
329
|
setIsUserAtBottom(true);
|
|
330
|
+
// Back at the bottom — clear the unread-while-scrolled-up
|
|
331
|
+
// counter so the badge disappears with the arrow.
|
|
332
|
+
setUnreadWhileScrolledUp(0);
|
|
333
|
+
newestSeenTsRef.current = null;
|
|
254
334
|
} else {
|
|
255
|
-
|
|
256
|
-
if (
|
|
335
|
+
isUserAtBottomRef.current = false;
|
|
336
|
+
if (hasUserScrolledRef.current) {
|
|
257
337
|
setShowNewMessageIndicator(true);
|
|
258
338
|
}
|
|
339
|
+
if (newestSeenTsRef.current === null) {
|
|
340
|
+
// Snapshot the NEWEST message's timestamp the moment the user
|
|
341
|
+
// first leaves the bottom. Anything newer than this that
|
|
342
|
+
// arrives later is genuinely "new"; older history loaded by
|
|
343
|
+
// back-pagination is < this and never counts.
|
|
344
|
+
newestSeenTsRef.current = memoizedMessages.reduce(
|
|
345
|
+
(mx: number, m: IMessage) => {
|
|
346
|
+
const t = msgSortableMs(m);
|
|
347
|
+
return t > mx ? t : mx;
|
|
348
|
+
},
|
|
349
|
+
0
|
|
350
|
+
);
|
|
351
|
+
}
|
|
259
352
|
setIsUserAtBottom(false);
|
|
260
353
|
}
|
|
261
354
|
},
|
|
262
|
-
[
|
|
355
|
+
[memoizedMessages]
|
|
263
356
|
);
|
|
264
357
|
|
|
358
|
+
// Keep the badge in sync with messages that arrive while the user is
|
|
359
|
+
// scrolled up. Count ONLY messages newer than the newest-seen snapshot
|
|
360
|
+
// — so loading older history (back-pagination) doesn't inflate it.
|
|
361
|
+
useEffect(() => {
|
|
362
|
+
if (isUserAtBottomRef.current) {return;}
|
|
363
|
+
if (newestSeenTsRef.current === null) {return;}
|
|
364
|
+
const since = newestSeenTsRef.current;
|
|
365
|
+
const count = memoizedMessages.reduce(
|
|
366
|
+
(n: number, m: IMessage) => (msgSortableMs(m) > since ? n + 1 : n),
|
|
367
|
+
0
|
|
368
|
+
);
|
|
369
|
+
setUnreadWhileScrolledUp(count);
|
|
370
|
+
}, [memoizedMessages, isUserAtBottom]);
|
|
371
|
+
|
|
265
372
|
const handleLayout = () => {
|
|
266
|
-
|
|
373
|
+
isUserAtBottomRef.current = true;
|
|
374
|
+
hasUserScrolledRef.current = false;
|
|
267
375
|
setIsUserAtBottom(true);
|
|
268
376
|
};
|
|
269
377
|
|
|
270
378
|
const handleNewMessageIndicatorPress = () => {
|
|
379
|
+
isUserAtBottomRef.current = true;
|
|
271
380
|
setShowNewMessageIndicator(false);
|
|
272
381
|
setIsUserAtBottom(true);
|
|
382
|
+
setUnreadWhileScrolledUp(0);
|
|
383
|
+
newestSeenTsRef.current = null;
|
|
273
384
|
scrollToBottom();
|
|
274
385
|
};
|
|
275
386
|
|
|
276
387
|
useEffect(() => {
|
|
277
|
-
|
|
388
|
+
hasUserScrolledRef.current = false;
|
|
389
|
+
isUserAtBottomRef.current = true;
|
|
278
390
|
setShowNewMessageIndicator(false);
|
|
279
391
|
setIsUserAtBottom(true);
|
|
392
|
+
setUnreadWhileScrolledUp(0);
|
|
393
|
+
newestSeenTsRef.current = null;
|
|
280
394
|
}, [roomJID]);
|
|
281
395
|
|
|
282
396
|
const BackgroundImage = useMemo(() => {
|
|
@@ -316,7 +430,7 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
316
430
|
)}
|
|
317
431
|
<FlatList
|
|
318
432
|
ref={flatListRef}
|
|
319
|
-
data={
|
|
433
|
+
data={dataMessages}
|
|
320
434
|
renderItem={renderMessage}
|
|
321
435
|
keyExtractor={(item) => item.id.toString()}
|
|
322
436
|
onEndReached={handleLoadMore}
|
|
@@ -326,6 +440,8 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
326
440
|
scrollEventThrottle={16}
|
|
327
441
|
onLayout={handleLayout}
|
|
328
442
|
inverted={true}
|
|
443
|
+
keyboardShouldPersistTaps="handled"
|
|
444
|
+
keyboardDismissMode="interactive"
|
|
329
445
|
contentContainerStyle={styles.flatListContent}
|
|
330
446
|
ListFooterComponent={
|
|
331
447
|
loading && memoizedMessages.length > 15 ? (
|
|
@@ -337,11 +453,21 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
337
453
|
<TouchableOpacity
|
|
338
454
|
style={[
|
|
339
455
|
styles.newMessageIndicator,
|
|
340
|
-
{ backgroundColor: config?.colors?.
|
|
456
|
+
{ backgroundColor: config?.colors?.primary || '#0052CD' },
|
|
341
457
|
]}
|
|
342
458
|
onPress={handleNewMessageIndicatorPress}
|
|
343
459
|
>
|
|
344
|
-
|
|
460
|
+
{/* White chevron on the saturated FAB. The icon's default
|
|
461
|
+
color is white, which was invisible against the previous
|
|
462
|
+
light `secondary` background — hence "no icon". */}
|
|
463
|
+
<ArowDownIcon color="#FFFFFF" width={22} height={22} />
|
|
464
|
+
{unreadWhileScrolledUp > 0 && (
|
|
465
|
+
<View style={styles.newMessageBadge}>
|
|
466
|
+
<Text style={styles.newMessageBadgeText}>
|
|
467
|
+
{unreadWhileScrolledUp > 99 ? '99+' : unreadWhileScrolledUp}
|
|
468
|
+
</Text>
|
|
469
|
+
</View>
|
|
470
|
+
)}
|
|
345
471
|
</TouchableOpacity>
|
|
346
472
|
)}
|
|
347
473
|
{config?.customTypingIndicator?.enabled && composing && (
|
|
@@ -400,12 +526,40 @@ const styles = StyleSheet.create({
|
|
|
400
526
|
height: 40,
|
|
401
527
|
bottom: 20,
|
|
402
528
|
right: 20,
|
|
403
|
-
backgroundColor: '#
|
|
404
|
-
padding: 10,
|
|
529
|
+
backgroundColor: '#0052CD',
|
|
405
530
|
borderRadius: 20,
|
|
531
|
+
justifyContent: 'center',
|
|
532
|
+
alignItems: 'center',
|
|
533
|
+
// Lift the FAB off the chat background so it reads as a button.
|
|
534
|
+
shadowColor: '#000',
|
|
535
|
+
shadowOffset: { width: 0, height: 2 },
|
|
536
|
+
shadowOpacity: 0.2,
|
|
537
|
+
shadowRadius: 3,
|
|
538
|
+
elevation: 4,
|
|
406
539
|
},
|
|
407
540
|
newMessageText: {
|
|
408
541
|
color: '#fff',
|
|
409
542
|
fontWeight: 'bold',
|
|
410
543
|
},
|
|
544
|
+
newMessageBadge: {
|
|
545
|
+
position: 'absolute',
|
|
546
|
+
top: -6,
|
|
547
|
+
right: -6,
|
|
548
|
+
minWidth: 20,
|
|
549
|
+
height: 20,
|
|
550
|
+
paddingHorizontal: 6,
|
|
551
|
+
borderRadius: 10,
|
|
552
|
+
justifyContent: 'center',
|
|
553
|
+
alignItems: 'center',
|
|
554
|
+
// Fixed red so it stays distinct from the (primary-coloured) FAB,
|
|
555
|
+
// with a white ring to separate the two.
|
|
556
|
+
backgroundColor: '#E53935',
|
|
557
|
+
borderWidth: 2,
|
|
558
|
+
borderColor: '#fff',
|
|
559
|
+
},
|
|
560
|
+
newMessageBadgeText: {
|
|
561
|
+
color: '#fff',
|
|
562
|
+
fontWeight: 'bold',
|
|
563
|
+
fontSize: 11,
|
|
564
|
+
},
|
|
411
565
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, {useMemo} from 'react';
|
|
2
2
|
import {Provider} from 'react-redux';
|
|
3
3
|
import {KeyboardProvider} from 'react-native-keyboard-controller';
|
|
4
|
+
import {SafeAreaProvider} from 'react-native-safe-area-context';
|
|
4
5
|
import {store} from '../../roomStore';
|
|
5
6
|
import {ConfigUser, IConfig, MessageProps} from '../../types/types';
|
|
6
7
|
import {XmppProvider} from '../../context/xmppProvider';
|
|
@@ -8,6 +9,12 @@ import {MessageNotificationProvider} from '../../context/MessageNotificationCont
|
|
|
8
9
|
import {ToastProvider} from '../../context/ToastContext';
|
|
9
10
|
import LoginWrapper from './LoginWrapper';
|
|
10
11
|
import '../../helpers/storeConsole';
|
|
12
|
+
import {installPromiseRejectionTracker} from '../../utils/installPromiseRejectionTracker';
|
|
13
|
+
|
|
14
|
+
// Mount-time, dev-only — wire a global unhandled-promise-rejection
|
|
15
|
+
// tracker so any future leak surfaces with a real stack trace in Metro
|
|
16
|
+
// logs (bug #4 follow-up). No-op in production.
|
|
17
|
+
installPromiseRejectionTracker();
|
|
11
18
|
|
|
12
19
|
interface ChatWrapperProps {
|
|
13
20
|
token?: string;
|
|
@@ -17,6 +24,7 @@ interface ChatWrapperProps {
|
|
|
17
24
|
MainComponentStyles?: React.CSSProperties;
|
|
18
25
|
CustomMessageComponent?: React.ComponentType<MessageProps>;
|
|
19
26
|
config?: IConfig;
|
|
27
|
+
isVisible?: boolean;
|
|
20
28
|
}
|
|
21
29
|
|
|
22
30
|
export const ReduxWrapper: React.FC<ChatWrapperProps> = React.memo(
|
|
@@ -27,15 +35,17 @@ export const ReduxWrapper: React.FC<ChatWrapperProps> = React.memo(
|
|
|
27
35
|
|
|
28
36
|
return (
|
|
29
37
|
<Provider store={store}>
|
|
30
|
-
<
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
<
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
<SafeAreaProvider>
|
|
39
|
+
<KeyboardProvider>
|
|
40
|
+
<XmppProvider config={memoizedConfig} isVisible={props.isVisible}>
|
|
41
|
+
<ToastProvider>
|
|
42
|
+
<MessageNotificationProvider config={memoizedConfig}>
|
|
43
|
+
<LoginWrapper config={memoizedConfig} {...props} />
|
|
44
|
+
</MessageNotificationProvider>
|
|
45
|
+
</ToastProvider>
|
|
46
|
+
</XmppProvider>
|
|
47
|
+
</KeyboardProvider>
|
|
48
|
+
</SafeAreaProvider>
|
|
39
49
|
</Provider>
|
|
40
50
|
);
|
|
41
51
|
},
|