@ethora/chat-component-rn 26.8.4 → 26.8.6
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/README.md +55 -0
- package/lib/commonjs/assets/emojiData.js +40 -0
- package/lib/commonjs/assets/emojiData.js.map +1 -0
- package/lib/commonjs/assets/icons.js +1 -1
- package/lib/commonjs/assets/icons.js.map +1 -1
- package/lib/commonjs/components/Header/HeaderRoomList.js +12 -7
- package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatHeader.js +7 -9
- package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatRoom.js +47 -26
- package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatWrapper.js +58 -21
- package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/KeyboardInputDock.js +40 -0
- package/lib/commonjs/components/MainComponents/KeyboardInputDock.js.map +1 -0
- package/lib/commonjs/components/MainComponents/MessageContainer.js +4 -12
- package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MessageList.js +110 -35
- package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
- package/lib/commonjs/components/MainComponents/RoomList.js +32 -29
- package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
- package/lib/commonjs/components/MainComponents/RoomStack.js +270 -0
- package/lib/commonjs/components/MainComponents/RoomStack.js.map +1 -0
- package/lib/commonjs/components/MainComponents/SystemMessage.js +6 -2
- package/lib/commonjs/components/MainComponents/SystemMessage.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/Avatar.js +5 -1
- package/lib/commonjs/components/MessageBubble/Avatar.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/BottomReplyContainer.js +17 -21
- package/lib/commonjs/components/MessageBubble/BottomReplyContainer.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/EmojiPickerSheet.js +447 -0
- package/lib/commonjs/components/MessageBubble/EmojiPickerSheet.js.map +1 -0
- package/lib/commonjs/components/MessageBubble/Message.js +200 -132
- package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js +213 -12
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/MessageReaction.js +113 -94
- package/lib/commonjs/components/MessageBubble/MessageReaction.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/MessageReply.js +66 -24
- package/lib/commonjs/components/MessageBubble/MessageReply.js.map +1 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +6 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/Modal/Modal.js +24 -0
- package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
- package/lib/commonjs/components/Modals/Modal/SwipeBackLayer.js +178 -0
- package/lib/commonjs/components/Modals/Modal/SwipeBackLayer.js.map +1 -0
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js +28 -10
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -1
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +9 -3
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +5 -4
- package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessageEmoji.js +8 -9
- package/lib/commonjs/components/RoomComponents/styled/LastMessageEmoji.js.map +1 -1
- package/lib/commonjs/components/Thread/ThreadWrapper.js +265 -152
- package/lib/commonjs/components/Thread/ThreadWrapper.js.map +1 -1
- package/lib/commonjs/components/styled/DateLabel.js +6 -3
- package/lib/commonjs/components/styled/DateLabel.js.map +1 -1
- package/lib/commonjs/context/MessageNotificationContext.js +188 -9
- package/lib/commonjs/context/MessageNotificationContext.js.map +1 -1
- package/lib/commonjs/context/xmppProvider.js +22 -7
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/helpers/createRoomFromApi.js +36 -2
- package/lib/commonjs/helpers/createRoomFromApi.js.map +1 -1
- package/lib/commonjs/helpers/emoji.js +51 -0
- package/lib/commonjs/helpers/emoji.js.map +1 -0
- package/lib/commonjs/helpers/haptics.js +29 -0
- package/lib/commonjs/helpers/haptics.js.map +1 -0
- package/lib/commonjs/helpers/historyPreloadScheduler.js +32 -66
- package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
- package/lib/commonjs/helpers/insertMessageWithDelimiter.js +21 -12
- package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
- package/lib/commonjs/helpers/keyboardLayout.js +23 -1
- package/lib/commonjs/helpers/keyboardLayout.js.map +1 -1
- package/lib/commonjs/helpers/mamReactions.js +57 -0
- package/lib/commonjs/helpers/mamReactions.js.map +1 -0
- package/lib/commonjs/helpers/parseMessageReference.js +42 -0
- package/lib/commonjs/helpers/parseMessageReference.js.map +1 -0
- package/lib/commonjs/helpers/reactionsConfig.js +17 -0
- package/lib/commonjs/helpers/reactionsConfig.js.map +1 -0
- package/lib/commonjs/helpers/updateMessagesTillLast.js +17 -2
- package/lib/commonjs/helpers/updateMessagesTillLast.js.map +1 -1
- package/lib/commonjs/hooks/useHeapSender.js +3 -1
- package/lib/commonjs/hooks/useHeapSender.js.map +1 -1
- package/lib/commonjs/hooks/useMessageHeapState.js +3 -2
- package/lib/commonjs/hooks/useMessageHeapState.js.map +1 -1
- package/lib/commonjs/hooks/useRoomInitialization.js +16 -7
- package/lib/commonjs/hooks/useRoomInitialization.js.map +1 -1
- package/lib/commonjs/hooks/useSendMessage.js +14 -8
- package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
- package/lib/commonjs/hooks/useUnreadMessagesCounter.js +1 -1
- package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
- package/lib/commonjs/networking/stanzaHandlers.js +106 -50
- package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
- package/lib/commonjs/networking/xmpp/getHistory.xmpp.js +29 -74
- package/lib/commonjs/networking/xmpp/getHistory.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +4 -0
- package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/mamRouter.js +186 -0
- package/lib/commonjs/networking/xmpp/mamRouter.js.map +1 -0
- package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js +41 -4
- package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmppClient.js +98 -23
- package/lib/commonjs/networking/xmppClient.js.map +1 -1
- package/lib/commonjs/roomStore/Middleware/newMessageMidlleware.js +29 -34
- package/lib/commonjs/roomStore/Middleware/newMessageMidlleware.js.map +1 -1
- package/lib/commonjs/roomStore/Middleware/perfMiddleware.js +51 -0
- package/lib/commonjs/roomStore/Middleware/perfMiddleware.js.map +1 -0
- package/lib/commonjs/roomStore/Middleware/reactionsMiddleware.js +66 -43
- package/lib/commonjs/roomStore/Middleware/reactionsMiddleware.js.map +1 -1
- package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js +88 -68
- package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js.map +1 -1
- package/lib/commonjs/roomStore/index.js +18 -14
- package/lib/commonjs/roomStore/index.js.map +1 -1
- package/lib/commonjs/roomStore/persistBackend.js +96 -0
- package/lib/commonjs/roomStore/persistBackend.js.map +1 -0
- package/lib/commonjs/roomStore/persistence.js +245 -50
- package/lib/commonjs/roomStore/persistence.js.map +1 -1
- package/lib/commonjs/roomStore/roomsSlice.js +282 -136
- package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
- package/lib/commonjs/theme/theme.js +3 -0
- package/lib/commonjs/theme/theme.js.map +1 -1
- package/lib/commonjs/utils/devLogger.js +14 -0
- package/lib/commonjs/utils/devLogger.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/module/assets/emojiData.js +36 -0
- package/lib/module/assets/emojiData.js.map +1 -0
- package/lib/module/assets/icons.js +1 -1
- package/lib/module/assets/icons.js.map +1 -1
- package/lib/module/components/Header/HeaderRoomList.js +12 -7
- package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
- package/lib/module/components/MainComponents/ChatHeader.js +8 -10
- package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/module/components/MainComponents/ChatRoom.js +49 -28
- package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/module/components/MainComponents/ChatWrapper.js +60 -23
- package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/KeyboardInputDock.js +33 -0
- package/lib/module/components/MainComponents/KeyboardInputDock.js.map +1 -0
- package/lib/module/components/MainComponents/MessageContainer.js +7 -14
- package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
- package/lib/module/components/MainComponents/MessageList.js +110 -35
- package/lib/module/components/MainComponents/MessageList.js.map +1 -1
- package/lib/module/components/MainComponents/RoomList.js +32 -29
- package/lib/module/components/MainComponents/RoomList.js.map +1 -1
- package/lib/module/components/MainComponents/RoomStack.js +266 -0
- package/lib/module/components/MainComponents/RoomStack.js.map +1 -0
- package/lib/module/components/MainComponents/SystemMessage.js +6 -2
- package/lib/module/components/MainComponents/SystemMessage.js.map +1 -1
- package/lib/module/components/MessageBubble/Avatar.js +5 -1
- package/lib/module/components/MessageBubble/Avatar.js.map +1 -1
- package/lib/module/components/MessageBubble/BottomReplyContainer.js +18 -22
- package/lib/module/components/MessageBubble/BottomReplyContainer.js.map +1 -1
- package/lib/module/components/MessageBubble/EmojiPickerSheet.js +438 -0
- package/lib/module/components/MessageBubble/EmojiPickerSheet.js.map +1 -0
- package/lib/module/components/MessageBubble/Message.js +203 -134
- package/lib/module/components/MessageBubble/Message.js.map +1 -1
- package/lib/module/components/MessageBubble/MessageInteractions.js +215 -14
- package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/module/components/MessageBubble/MessageReaction.js +115 -94
- package/lib/module/components/MessageBubble/MessageReaction.js.map +1 -1
- package/lib/module/components/MessageBubble/MessageReply.js +65 -24
- package/lib/module/components/MessageBubble/MessageReply.js.map +1 -1
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +6 -1
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/module/components/Modals/Modal/Modal.js +25 -1
- package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
- package/lib/module/components/Modals/Modal/SwipeBackLayer.js +172 -0
- package/lib/module/components/Modals/Modal/SwipeBackLayer.js.map +1 -0
- package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js +29 -11
- package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -1
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +10 -4
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/module/components/RoomComponents/ChatRoomItem.js +5 -4
- package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessageEmoji.js +8 -9
- package/lib/module/components/RoomComponents/styled/LastMessageEmoji.js.map +1 -1
- package/lib/module/components/Thread/ThreadWrapper.js +264 -152
- package/lib/module/components/Thread/ThreadWrapper.js.map +1 -1
- package/lib/module/components/styled/DateLabel.js +6 -3
- package/lib/module/components/styled/DateLabel.js.map +1 -1
- package/lib/module/context/MessageNotificationContext.js +190 -11
- package/lib/module/context/MessageNotificationContext.js.map +1 -1
- package/lib/module/context/xmppProvider.js +22 -7
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/helpers/createRoomFromApi.js +36 -2
- package/lib/module/helpers/createRoomFromApi.js.map +1 -1
- package/lib/module/helpers/emoji.js +44 -0
- package/lib/module/helpers/emoji.js.map +1 -0
- package/lib/module/helpers/haptics.js +24 -0
- package/lib/module/helpers/haptics.js.map +1 -0
- package/lib/module/helpers/historyPreloadScheduler.js +32 -66
- package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
- package/lib/module/helpers/insertMessageWithDelimiter.js +21 -12
- package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
- package/lib/module/helpers/keyboardLayout.js +20 -0
- package/lib/module/helpers/keyboardLayout.js.map +1 -1
- package/lib/module/helpers/mamReactions.js +51 -0
- package/lib/module/helpers/mamReactions.js.map +1 -0
- package/lib/module/helpers/parseMessageReference.js +37 -0
- package/lib/module/helpers/parseMessageReference.js.map +1 -0
- package/lib/module/helpers/reactionsConfig.js +10 -0
- package/lib/module/helpers/reactionsConfig.js.map +1 -0
- package/lib/module/helpers/updateMessagesTillLast.js +17 -2
- package/lib/module/helpers/updateMessagesTillLast.js.map +1 -1
- package/lib/module/hooks/useHeapSender.js +3 -1
- package/lib/module/hooks/useHeapSender.js.map +1 -1
- package/lib/module/hooks/useMessageHeapState.js +3 -2
- package/lib/module/hooks/useMessageHeapState.js.map +1 -1
- package/lib/module/hooks/useRoomInitialization.js +17 -8
- package/lib/module/hooks/useRoomInitialization.js.map +1 -1
- package/lib/module/hooks/useSendMessage.js +14 -8
- package/lib/module/hooks/useSendMessage.js.map +1 -1
- package/lib/module/hooks/useUnreadMessagesCounter.js +1 -1
- package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
- package/lib/module/networking/stanzaHandlers.js +107 -51
- package/lib/module/networking/stanzaHandlers.js.map +1 -1
- package/lib/module/networking/xmpp/getHistory.xmpp.js +29 -74
- package/lib/module/networking/xmpp/getHistory.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/handleStanzas.xmpp.js +4 -0
- package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/mamRouter.js +175 -0
- package/lib/module/networking/xmpp/mamRouter.js.map +1 -0
- package/lib/module/networking/xmpp/presenceInRoom.xmpp.js +38 -2
- package/lib/module/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
- package/lib/module/networking/xmppClient.js +99 -24
- package/lib/module/networking/xmppClient.js.map +1 -1
- package/lib/module/roomStore/Middleware/newMessageMidlleware.js +29 -34
- package/lib/module/roomStore/Middleware/newMessageMidlleware.js.map +1 -1
- package/lib/module/roomStore/Middleware/perfMiddleware.js +45 -0
- package/lib/module/roomStore/Middleware/perfMiddleware.js.map +1 -0
- package/lib/module/roomStore/Middleware/reactionsMiddleware.js +66 -43
- package/lib/module/roomStore/Middleware/reactionsMiddleware.js.map +1 -1
- package/lib/module/roomStore/Middleware/unreadMidlleware.js +89 -69
- package/lib/module/roomStore/Middleware/unreadMidlleware.js.map +1 -1
- package/lib/module/roomStore/index.js +19 -15
- package/lib/module/roomStore/index.js.map +1 -1
- package/lib/module/roomStore/persistBackend.js +89 -0
- package/lib/module/roomStore/persistBackend.js.map +1 -0
- package/lib/module/roomStore/persistence.js +245 -48
- package/lib/module/roomStore/persistence.js.map +1 -1
- package/lib/module/roomStore/roomsSlice.js +275 -134
- package/lib/module/roomStore/roomsSlice.js.map +1 -1
- package/lib/module/theme/theme.js +3 -0
- package/lib/module/theme/theme.js.map +1 -1
- package/lib/module/utils/devLogger.js +13 -0
- package/lib/module/utils/devLogger.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/assets/emojiData.d.ts +8 -0
- package/lib/typescript/assets/emojiData.d.ts.map +1 -0
- package/lib/typescript/components/Header/HeaderRoomList.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/KeyboardInputDock.d.ts +16 -0
- package/lib/typescript/components/MainComponents/KeyboardInputDock.d.ts.map +1 -0
- package/lib/typescript/components/MainComponents/MessageContainer.d.ts +2 -2
- 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/RoomList.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/RoomStack.d.ts +42 -0
- package/lib/typescript/components/MainComponents/RoomStack.d.ts.map +1 -0
- package/lib/typescript/components/MainComponents/SystemMessage.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/Avatar.d.ts +2 -0
- package/lib/typescript/components/MessageBubble/Avatar.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/BottomReplyContainer.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/EmojiPickerSheet.d.ts +11 -0
- package/lib/typescript/components/MessageBubble/EmojiPickerSheet.d.ts.map +1 -0
- package/lib/typescript/components/MessageBubble/Message.d.ts +2 -2
- package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts +2 -0
- package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/MessageReaction.d.ts +1 -0
- package/lib/typescript/components/MessageBubble/MessageReaction.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/MessageReply.d.ts +7 -7
- package/lib/typescript/components/MessageBubble/MessageReply.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/Modal/SwipeBackLayer.d.ts +16 -0
- package/lib/typescript/components/Modals/Modal/SwipeBackLayer.d.ts.map +1 -0
- package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts +2 -2
- package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessageEmoji.d.ts +3 -6
- package/lib/typescript/components/RoomComponents/styled/LastMessageEmoji.d.ts.map +1 -1
- package/lib/typescript/components/Thread/ThreadWrapper.d.ts +7 -1
- package/lib/typescript/components/Thread/ThreadWrapper.d.ts.map +1 -1
- package/lib/typescript/components/styled/DateLabel.d.ts +1 -0
- package/lib/typescript/components/styled/DateLabel.d.ts.map +1 -1
- package/lib/typescript/context/MessageNotificationContext.d.ts.map +1 -1
- package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
- package/lib/typescript/helpers/createRoomFromApi.d.ts.map +1 -1
- package/lib/typescript/helpers/emoji.d.ts +6 -0
- package/lib/typescript/helpers/emoji.d.ts.map +1 -0
- package/lib/typescript/helpers/haptics.d.ts +3 -0
- package/lib/typescript/helpers/haptics.d.ts.map +1 -0
- package/lib/typescript/helpers/historyPreloadScheduler.d.ts +1 -0
- 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 +6 -0
- package/lib/typescript/helpers/keyboardLayout.d.ts.map +1 -1
- package/lib/typescript/helpers/mamReactions.d.ts +13 -0
- package/lib/typescript/helpers/mamReactions.d.ts.map +1 -0
- package/lib/typescript/helpers/parseMessageReference.d.ts +16 -0
- package/lib/typescript/helpers/parseMessageReference.d.ts.map +1 -0
- package/lib/typescript/helpers/reactionsConfig.d.ts +5 -0
- package/lib/typescript/helpers/reactionsConfig.d.ts.map +1 -0
- package/lib/typescript/helpers/updateMessagesTillLast.d.ts.map +1 -1
- package/lib/typescript/hooks/useHeapSender.d.ts.map +1 -1
- package/lib/typescript/hooks/useMessageHeapState.d.ts.map +1 -1
- package/lib/typescript/hooks/useRoomInitialization.d.ts +2 -2
- package/lib/typescript/hooks/useRoomInitialization.d.ts.map +1 -1
- package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/networking/stanzaHandlers.d.ts +4 -2
- package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/getHistory.xmpp.d.ts +3 -1
- package/lib/typescript/networking/xmpp/getHistory.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/mamRouter.d.ts +23 -0
- package/lib/typescript/networking/xmpp/mamRouter.d.ts.map +1 -0
- package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts +1 -0
- package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmppClient.d.ts +22 -1
- package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
- package/lib/typescript/roomStore/Middleware/newMessageMidlleware.d.ts.map +1 -1
- package/lib/typescript/roomStore/Middleware/perfMiddleware.d.ts +4 -0
- package/lib/typescript/roomStore/Middleware/perfMiddleware.d.ts.map +1 -0
- package/lib/typescript/roomStore/Middleware/reactionsMiddleware.d.ts +9 -0
- package/lib/typescript/roomStore/Middleware/reactionsMiddleware.d.ts.map +1 -1
- package/lib/typescript/roomStore/Middleware/unreadMidlleware.d.ts.map +1 -1
- package/lib/typescript/roomStore/index.d.ts.map +1 -1
- package/lib/typescript/roomStore/persistBackend.d.ts +11 -0
- package/lib/typescript/roomStore/persistBackend.d.ts.map +1 -0
- package/lib/typescript/roomStore/persistence.d.ts +5 -6
- package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts +41 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
- package/lib/typescript/theme/theme.d.ts +4 -1
- package/lib/typescript/theme/theme.d.ts.map +1 -1
- package/lib/typescript/types/models/message.model.d.ts +4 -0
- package/lib/typescript/types/models/message.model.d.ts.map +1 -1
- package/lib/typescript/types/models/room.model.d.ts +16 -0
- package/lib/typescript/types/models/room.model.d.ts.map +1 -1
- package/lib/typescript/types/models/xmpp.model.d.ts +6 -1
- package/lib/typescript/types/models/xmpp.model.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +15 -3
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/lib/typescript/utils/devLogger.d.ts +8 -0
- package/lib/typescript/utils/devLogger.d.ts.map +1 -1
- package/lib/typescript/version.d.ts +1 -1
- package/package.json +10 -1
- package/src/assets/emojiData.ts +2146 -0
- package/src/assets/icons.tsx +5 -5
- package/src/components/Header/HeaderRoomList.tsx +7 -5
- package/src/components/MainComponents/ChatHeader.tsx +16 -7
- package/src/components/MainComponents/ChatRoom.tsx +64 -32
- package/src/components/MainComponents/ChatWrapper.tsx +73 -21
- package/src/components/MainComponents/KeyboardInputDock.tsx +47 -0
- package/src/components/MainComponents/MessageContainer.tsx +7 -15
- package/src/components/MainComponents/MessageList.tsx +96 -43
- package/src/components/MainComponents/RoomList.tsx +28 -29
- package/src/components/MainComponents/RoomStack.tsx +309 -0
- package/src/components/MainComponents/SystemMessage.tsx +6 -2
- package/src/components/MessageBubble/Avatar.tsx +7 -1
- package/src/components/MessageBubble/BottomReplyContainer.tsx +19 -21
- package/src/components/MessageBubble/EmojiPickerSheet.tsx +468 -0
- package/src/components/MessageBubble/Message.tsx +146 -87
- package/src/components/MessageBubble/MessageInteractions.tsx +213 -12
- package/src/components/MessageBubble/MessageReaction.tsx +120 -96
- package/src/components/MessageBubble/MessageReply.tsx +65 -32
- package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +4 -0
- package/src/components/Modals/Modal/Modal.tsx +32 -1
- package/src/components/Modals/Modal/SwipeBackLayer.tsx +221 -0
- package/src/components/Modals/ProfileHeader/ProfileHeader.tsx +29 -8
- package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +6 -3
- package/src/components/RoomComponents/ChatRoomItem.tsx +11 -4
- package/src/components/RoomComponents/styled/LastMessageEmoji.tsx +7 -8
- package/src/components/Thread/ThreadWrapper.tsx +274 -198
- package/src/components/styled/DateLabel.tsx +7 -3
- package/src/context/MessageNotificationContext.tsx +205 -7
- package/src/context/xmppProvider.tsx +29 -9
- package/src/helpers/createRoomFromApi.tsx +37 -1
- package/src/helpers/emoji.ts +39 -0
- package/src/helpers/haptics.ts +19 -0
- package/src/helpers/historyPreloadScheduler.ts +37 -69
- package/src/helpers/insertMessageWithDelimiter.ts +23 -16
- package/src/helpers/keyboardLayout.ts +26 -0
- package/src/helpers/mamReactions.ts +59 -0
- package/src/helpers/parseMessageReference.ts +38 -0
- package/src/helpers/reactionsConfig.ts +13 -0
- package/src/helpers/updateMessagesTillLast.tsx +14 -2
- package/src/hooks/useHeapSender.tsx +3 -2
- package/src/hooks/useMessageHeapState.tsx +6 -2
- package/src/hooks/useRoomInitialization.tsx +32 -15
- package/src/hooks/useSendMessage.tsx +18 -11
- package/src/hooks/useUnreadMessagesCounter.ts +1 -1
- package/src/networking/stanzaHandlers.ts +116 -60
- package/src/networking/xmpp/getHistory.xmpp.ts +44 -106
- package/src/networking/xmpp/handleStanzas.xmpp.ts +2 -0
- package/src/networking/xmpp/mamRouter.ts +176 -0
- package/src/networking/xmpp/presenceInRoom.xmpp.ts +46 -3
- package/src/networking/xmppClient.ts +105 -20
- package/src/roomStore/Middleware/newMessageMidlleware.tsx +35 -38
- package/src/roomStore/Middleware/perfMiddleware.ts +50 -0
- package/src/roomStore/Middleware/reactionsMiddleware.tsx +53 -52
- package/src/roomStore/Middleware/unreadMidlleware.tsx +92 -80
- package/src/roomStore/index.ts +28 -27
- package/src/roomStore/persistBackend.ts +96 -0
- package/src/roomStore/persistence.ts +280 -73
- package/src/roomStore/roomsSlice.ts +304 -155
- package/src/theme/theme.ts +10 -1
- package/src/types/models/message.model.ts +4 -0
- package/src/types/models/room.model.ts +17 -0
- package/src/types/models/xmpp.model.ts +4 -2
- package/src/types/types.ts +15 -3
- package/src/utils/devLogger.ts +16 -0
- package/src/version.ts +1 -1
|
@@ -15,6 +15,9 @@ import type XmppClient from '../networking/xmppClient';
|
|
|
15
15
|
// page backward arbitrarily far without instantly losing what they
|
|
16
16
|
// just fetched. After cap eviction we drop from the head (oldest).
|
|
17
17
|
export const RUNTIME_MESSAGE_LIMIT = 100;
|
|
18
|
+
/** One preload page: "N+" badges only ever mean "at least this many". */
|
|
19
|
+
export const UNREAD_CAP_PAGE = 10;
|
|
20
|
+
export const RUNTIME_MESSAGE_CEILING = 2000;
|
|
18
21
|
|
|
19
22
|
// Body strings the server uses for call signaling broadcasts (call-token,
|
|
20
23
|
// call-state ringing/ended, etc). These should never reach the chat
|
|
@@ -107,11 +110,215 @@ const collapseCallLogDuplicates = (messages: IMessage[]): IMessage[] => {
|
|
|
107
110
|
});
|
|
108
111
|
};
|
|
109
112
|
|
|
110
|
-
|
|
113
|
+
type InsertOutcome = { grew: boolean; atHead: boolean };
|
|
114
|
+
const NO_GROWTH: InsertOutcome = { grew: false, atHead: false };
|
|
115
|
+
|
|
116
|
+
const insertRoomMessage = (
|
|
117
|
+
state: WritableDraft<RoomMessagesState>,
|
|
118
|
+
roomJID: string,
|
|
119
|
+
message: IMessage,
|
|
120
|
+
start?: boolean
|
|
121
|
+
): InsertOutcome => {
|
|
122
|
+
if (isCallSignalMessage(message)) {
|
|
123
|
+
return NO_GROWTH;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (!state.rooms[roomJID]) {
|
|
127
|
+
return NO_GROWTH;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!state.rooms[roomJID].messages) {
|
|
131
|
+
state.rooms[roomJID].messages = [];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const roomMessages = state.rooms[roomJID].messages!;
|
|
135
|
+
|
|
136
|
+
const incomingCallLog = message.callLog;
|
|
137
|
+
if (incomingCallLog?.callId) {
|
|
138
|
+
const existingCallIdx = roomMessages.findIndex(
|
|
139
|
+
(msg) => msg.callLog?.callId === incomingCallLog.callId
|
|
140
|
+
);
|
|
141
|
+
if (existingCallIdx !== -1) {
|
|
142
|
+
const existing = roomMessages[existingCallIdx];
|
|
143
|
+
const merged = mergeCallLogEntries(existing as IMessage, message);
|
|
144
|
+
if (merged !== (existing as IMessage)) {
|
|
145
|
+
roomMessages[existingCallIdx] = merged;
|
|
146
|
+
}
|
|
147
|
+
return NO_GROWTH;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
takePendingReactions(state, roomJID, message);
|
|
152
|
+
const lengthBefore = roomMessages.length;
|
|
153
|
+
const tailBefore = roomMessages[lengthBefore - 1];
|
|
154
|
+
|
|
155
|
+
if (roomMessages.length === 0 || start) {
|
|
156
|
+
roomMessages.unshift(message);
|
|
157
|
+
} else {
|
|
158
|
+
const lastViewedValue = state.rooms[roomJID].lastViewedTimestamp;
|
|
159
|
+
const lastViewedTimestamp =
|
|
160
|
+
state.visibleRoomJID === roomJID
|
|
161
|
+
? null
|
|
162
|
+
: lastViewedValue
|
|
163
|
+
? lastViewedValue
|
|
164
|
+
: null;
|
|
165
|
+
|
|
166
|
+
insertMessageWithDelimiter(roomMessages, message, lastViewedTimestamp);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const grew = roomMessages.length > lengthBefore;
|
|
170
|
+
const atHead =
|
|
171
|
+
grew &&
|
|
172
|
+
lengthBefore > 0 &&
|
|
173
|
+
roomMessages[roomMessages.length - 1] === tailBefore;
|
|
174
|
+
return { grew, atHead };
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const capAfterGrowth = (
|
|
178
|
+
messages: IMessage[],
|
|
179
|
+
lengthBefore: number,
|
|
180
|
+
atHead: boolean
|
|
181
|
+
): void => {
|
|
182
|
+
if (atHead) {
|
|
183
|
+
enforceMessageCap(messages, RUNTIME_MESSAGE_CEILING);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
enforceMessageCap(
|
|
187
|
+
messages,
|
|
188
|
+
Math.min(RUNTIME_MESSAGE_CEILING, Math.max(RUNTIME_MESSAGE_LIMIT, lengthBefore))
|
|
189
|
+
);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const bumpLastMessageTimestamp = (
|
|
193
|
+
state: WritableDraft<RoomMessagesState>,
|
|
194
|
+
roomJID: string,
|
|
195
|
+
message: IMessage
|
|
196
|
+
): void => {
|
|
197
|
+
const room = state.rooms[roomJID];
|
|
198
|
+
if (!room || message?.id === 'delimiter-new') {return;}
|
|
199
|
+
const ts = Number(message?.id);
|
|
200
|
+
if (!Number.isFinite(ts)) {return;}
|
|
201
|
+
if ((room.lastMessageTimestamp ?? 0) <= ts) {
|
|
202
|
+
room.lastMessageTimestamp = ts;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const upsertRoom = (
|
|
207
|
+
state: WritableDraft<RoomMessagesState>,
|
|
208
|
+
roomData: IRoom
|
|
209
|
+
): void => {
|
|
210
|
+
const existing = state.rooms[roomData.jid];
|
|
211
|
+
let lastViewed: number;
|
|
212
|
+
const serverMarker = state.privateStoreMarkers?.[roomData.jid] || 0;
|
|
213
|
+
|
|
214
|
+
if (roomData.lastViewedTimestamp != null && roomData.lastViewedTimestamp !== 0) {
|
|
215
|
+
lastViewed = roomData.lastViewedTimestamp;
|
|
216
|
+
} else if (existing?.lastViewedTimestamp != null && existing.lastViewedTimestamp > 0) {
|
|
217
|
+
lastViewed = existing.lastViewedTimestamp;
|
|
218
|
+
} else if (serverMarker > 0) {
|
|
219
|
+
lastViewed = serverMarker;
|
|
220
|
+
} else {
|
|
221
|
+
const msgs = roomData.messages || [];
|
|
222
|
+
let newest = 0;
|
|
223
|
+
for (const m of msgs) {
|
|
224
|
+
const t = (m as any)?.messageTimestampMs ||
|
|
225
|
+
(m?.date ? new Date(m.date).getTime() : 0);
|
|
226
|
+
if (t > newest) {newest = t;}
|
|
227
|
+
}
|
|
228
|
+
lastViewed = newest; // 0 if no messages → cold-start safe
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const incomingMessages = Array.isArray(roomData.messages)
|
|
232
|
+
? roomData.messages
|
|
233
|
+
: [];
|
|
234
|
+
const existingMessages = Array.isArray(existing?.messages)
|
|
235
|
+
? existing!.messages
|
|
236
|
+
: [];
|
|
237
|
+
state.rooms[roomData.jid] = {
|
|
238
|
+
...roomData,
|
|
239
|
+
icon: roomData.icon !== undefined ? roomData.icon : existing?.icon,
|
|
240
|
+
roomBg: roomData.roomBg !== undefined ? roomData.roomBg : existing?.roomBg,
|
|
241
|
+
messages:
|
|
242
|
+
existingMessages.length > 0 ? existingMessages : incomingMessages,
|
|
243
|
+
lastViewedTimestamp: lastViewed,
|
|
244
|
+
unreadMessages:
|
|
245
|
+
roomData.unreadMessages ?? existing?.unreadMessages ?? 0,
|
|
246
|
+
unreadBaselineTimestamp:
|
|
247
|
+
existing?.unreadBaselineTimestamp ??
|
|
248
|
+
existing?.lastViewedTimestamp ??
|
|
249
|
+
(roomData as any).unreadBaselineTimestamp ??
|
|
250
|
+
0,
|
|
251
|
+
};
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
/** Order two numeric stanza ids (microsecond timestamps, too long for a
|
|
255
|
+
* double) without BigInt: by length, then lexicographically. */
|
|
256
|
+
export const compareStanzaIds = (a: string, b: string): number =>
|
|
257
|
+
a.length !== b.length ? a.length - b.length : a < b ? -1 : a > b ? 1 : 0;
|
|
258
|
+
|
|
259
|
+
export const applyReactionToMessage = (
|
|
260
|
+
message: IMessage,
|
|
261
|
+
from: string | undefined,
|
|
262
|
+
reactions: string[],
|
|
263
|
+
data?: Record<string, string>,
|
|
264
|
+
ts?: string
|
|
265
|
+
): void => {
|
|
266
|
+
const fromId = String(from || '').split('/')[0].split('@')[0];
|
|
267
|
+
if (!fromId) {return;}
|
|
268
|
+
const list = (reactions || []).filter((r) => !!r);
|
|
269
|
+
const current = { ...(message.reaction || {}) };
|
|
270
|
+
const prev = current[fromId];
|
|
271
|
+
// An older reaction (from a history page loaded after a newer one) never
|
|
272
|
+
// overwrites what is already known.
|
|
273
|
+
if (ts && prev?.ts && compareStanzaIds(ts, prev.ts) < 0) {return;}
|
|
274
|
+
if (list.length === 0) {
|
|
275
|
+
if (ts) {
|
|
276
|
+
// Keep a "removed" marker so an older reaction can't come back.
|
|
277
|
+
current[fromId] = { emoji: [], data: data || {}, ts };
|
|
278
|
+
} else {
|
|
279
|
+
delete current[fromId];
|
|
280
|
+
}
|
|
281
|
+
} else {
|
|
282
|
+
current[fromId] = { emoji: list, data: data || {}, ...(ts ? { ts } : {}) };
|
|
283
|
+
}
|
|
284
|
+
const anyShown = Object.values(current).some((r) => r?.emoji?.length);
|
|
285
|
+
message.reaction = anyShown || Object.keys(current).length ? current : undefined;
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
type PendingReaction = {
|
|
289
|
+
from: string;
|
|
290
|
+
reactions: string[];
|
|
291
|
+
data?: Record<string, string>;
|
|
292
|
+
ts?: string;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
/** Reactions whose message is not loaded yet — applied when it arrives. */
|
|
296
|
+
const takePendingReactions = (
|
|
297
|
+
state: WritableDraft<RoomMessagesState>,
|
|
298
|
+
roomJID: string,
|
|
299
|
+
message: IMessage
|
|
300
|
+
): void => {
|
|
301
|
+
const byMessage = state.pendingReactions?.[roomJID];
|
|
302
|
+
if (!byMessage) {return;}
|
|
303
|
+
const keys = [String(message.id), message.xmppId ? String(message.xmppId) : ''];
|
|
304
|
+
for (const key of keys) {
|
|
305
|
+
const list = key ? byMessage[key] : undefined;
|
|
306
|
+
if (!list) {continue;}
|
|
307
|
+
for (const r of list) {
|
|
308
|
+
applyReactionToMessage(message, r.from, r.reactions, r.data, r.ts);
|
|
309
|
+
}
|
|
310
|
+
delete byMessage[key];
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const enforceMessageCap = (
|
|
315
|
+
messages: IMessage[],
|
|
316
|
+
limit: number = RUNTIME_MESSAGE_LIMIT
|
|
317
|
+
): void => {
|
|
111
318
|
// Trim oldest until we're at/under the limit. Mutates in place
|
|
112
319
|
// (immer-compatible inside reducers).
|
|
113
|
-
|
|
114
|
-
messages.
|
|
320
|
+
if (messages.length > limit) {
|
|
321
|
+
messages.splice(0, messages.length - limit);
|
|
115
322
|
}
|
|
116
323
|
};
|
|
117
324
|
|
|
@@ -202,10 +409,16 @@ function mergeHistoryIntoCache(
|
|
|
202
409
|
// body). Preserve `isEdited` from the cached copy so a message edited
|
|
203
410
|
// before reload keeps its marker instead of losing it on history sync.
|
|
204
411
|
const prev = byId.get(String(m.id));
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
412
|
+
let next = prev?.isEdited && !m.isEdited ? { ...m, isEdited: true } : m;
|
|
413
|
+
|
|
414
|
+
if (prev?.reaction && !next.reaction) {
|
|
415
|
+
next = { ...next, reaction: prev.reaction };
|
|
416
|
+
}
|
|
417
|
+
// A history merge must not close a thread the user has open.
|
|
418
|
+
if ((prev as any)?.activeMessage && !(next as any).activeMessage) {
|
|
419
|
+
next = { ...next, activeMessage: true } as IMessage;
|
|
420
|
+
}
|
|
421
|
+
byId.set(String(m.id), next);
|
|
209
422
|
}
|
|
210
423
|
const merged = collapseCallLogDuplicates(
|
|
211
424
|
Array.from(byId.values()).sort(byMs)
|
|
@@ -237,6 +450,9 @@ export interface RoomMessagesState {
|
|
|
237
450
|
// — see `applyPrivateStoreMarkers`. Re-fetched every init/reconnect,
|
|
238
451
|
// so it is intentionally NOT persisted.
|
|
239
452
|
privateStoreMarkers: Record<string, number>;
|
|
453
|
+
/** `{ roomJID: { messageId: reactions[] } }` — reactions that arrived
|
|
454
|
+
* before their message (a newer history page), applied on insert. */
|
|
455
|
+
pendingReactions?: Record<string, Record<string, PendingReaction[]>>;
|
|
240
456
|
// The single source of truth for "read up to here, but the user
|
|
241
457
|
// hasn't reached the bottom yet" (`{ roomJID: boundaryMs }`).
|
|
242
458
|
// Set by MessageList (via ChatRoom's `onReadBoundaryChange`) the
|
|
@@ -281,6 +497,7 @@ const initialState: RoomMessagesState = {
|
|
|
281
497
|
pendingNotificationJid: null,
|
|
282
498
|
privateStoreMarkers: {},
|
|
283
499
|
readBoundaries: {},
|
|
500
|
+
pendingReactions: {},
|
|
284
501
|
};
|
|
285
502
|
|
|
286
503
|
const isValidRoomJid = (jid: unknown): jid is string => {
|
|
@@ -306,81 +523,26 @@ export const addRoomViaApi = createAsyncThunk(
|
|
|
306
523
|
// emitted .d.ts (TS4023). See chatSettingsSlice.ts for the same pattern.
|
|
307
524
|
const reducers = {
|
|
308
525
|
addRoom(state: WritableDraft<RoomMessagesState>, action: PayloadAction<{ roomData: IRoom }>) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
// let that 0 win and OVERWROTE the persisted/hydrated marker from
|
|
329
|
-
// the previous session, so cold-start showed no unread badge for
|
|
330
|
-
// messages received while the app was closed (bug #19/#20). A real
|
|
331
|
-
// (non-zero) explicit value still wins; otherwise keep the existing
|
|
332
|
-
// value; otherwise fall back to the server-side read marker fetched
|
|
333
|
-
// from the private store (so a room the user has NEVER opened this
|
|
334
|
-
// session still gets a real baseline — without it the unread
|
|
335
|
-
// middleware's `lastViewedTimestamp > 0` gate skipped the room
|
|
336
|
-
// forever and the badge never lit up); otherwise anchor to the
|
|
337
|
-
// newest message in the payload.
|
|
338
|
-
const serverMarker = state.privateStoreMarkers?.[roomData.jid] || 0;
|
|
339
|
-
if (roomData.lastViewedTimestamp != null && roomData.lastViewedTimestamp !== 0) {
|
|
340
|
-
lastViewed = roomData.lastViewedTimestamp;
|
|
341
|
-
} else if (existing?.lastViewedTimestamp != null && existing.lastViewedTimestamp > 0) {
|
|
342
|
-
lastViewed = existing.lastViewedTimestamp;
|
|
343
|
-
} else if (serverMarker > 0) {
|
|
344
|
-
lastViewed = serverMarker;
|
|
345
|
-
} else {
|
|
346
|
-
const msgs = roomData.messages || [];
|
|
347
|
-
let newest = 0;
|
|
348
|
-
for (const m of msgs) {
|
|
349
|
-
const t = (m as any)?.messageTimestampMs ||
|
|
350
|
-
(m?.date ? new Date(m.date).getTime() : 0);
|
|
351
|
-
if (t > newest) {newest = t;}
|
|
352
|
-
}
|
|
353
|
-
lastViewed = newest; // 0 if no messages → cold-start safe
|
|
526
|
+
upsertRoom(state, action.payload.roomData);
|
|
527
|
+
},
|
|
528
|
+
|
|
529
|
+
setUnreadCounts(state: WritableDraft<RoomMessagesState>, action: PayloadAction<Record<string, number>>) {
|
|
530
|
+
for (const [jid, count] of Object.entries(action.payload || {})) {
|
|
531
|
+
const room = state.rooms[jid];
|
|
532
|
+
if (!room) {continue;}
|
|
533
|
+
if (room.unreadMessages !== count) {room.unreadMessages = count;}
|
|
534
|
+
// "N+" only means "a whole page was unread"; an exact count below a
|
|
535
|
+
// page (or read to zero) settles it.
|
|
536
|
+
if (room.unreadCapped && count < UNREAD_CAP_PAGE) {room.unreadCapped = false;}
|
|
537
|
+
}
|
|
538
|
+
},
|
|
539
|
+
/** Several rooms in one action — the cold-start rehydrate of the whole
|
|
540
|
+
* cache used to be one `addRoom` per room, each running every
|
|
541
|
+
* middleware over every room already added (O(rooms²)). */
|
|
542
|
+
addRooms(state: WritableDraft<RoomMessagesState>, action: PayloadAction<{ rooms: IRoom[] }>) {
|
|
543
|
+
for (const roomData of action.payload.rooms || []) {
|
|
544
|
+
if (roomData?.jid) {upsertRoom(state, roomData);}
|
|
354
545
|
}
|
|
355
|
-
// Preserve cached messages + unread when the incoming room carries
|
|
356
|
-
// none. The /chats/my fetch (rooms.api) builds rooms with
|
|
357
|
-
// `messages: []` and no unread; without this guard, re-entering the
|
|
358
|
-
// app replaced every cached room with an empty one — wiping history
|
|
359
|
-
// AND the unread badge before the history scheduler could re-merge
|
|
360
|
-
// (the user's "it clears cache, unread and messages" bug). New rooms
|
|
361
|
-
// (no existing) fall through to the incoming values. Mirrors
|
|
362
|
-
// addRoomFromApi's preservation.
|
|
363
|
-
const incomingMessages = Array.isArray(roomData.messages)
|
|
364
|
-
? roomData.messages
|
|
365
|
-
: [];
|
|
366
|
-
const existingMessages = Array.isArray(existing?.messages)
|
|
367
|
-
? existing!.messages
|
|
368
|
-
: [];
|
|
369
|
-
state.rooms[roomData.jid] = {
|
|
370
|
-
...roomData,
|
|
371
|
-
icon: roomData.icon !== undefined ? roomData.icon : existing?.icon,
|
|
372
|
-
roomBg: roomData.roomBg !== undefined ? roomData.roomBg : existing?.roomBg,
|
|
373
|
-
messages:
|
|
374
|
-
existingMessages.length > 0 ? existingMessages : incomingMessages,
|
|
375
|
-
lastViewedTimestamp: lastViewed,
|
|
376
|
-
unreadMessages:
|
|
377
|
-
roomData.unreadMessages ?? existing?.unreadMessages ?? 0,
|
|
378
|
-
unreadBaselineTimestamp:
|
|
379
|
-
existing?.unreadBaselineTimestamp ??
|
|
380
|
-
existing?.lastViewedTimestamp ??
|
|
381
|
-
(roomData as any).unreadBaselineTimestamp ??
|
|
382
|
-
0,
|
|
383
|
-
};
|
|
384
546
|
},
|
|
385
547
|
deleteRoom(state: WritableDraft<RoomMessagesState>, action: PayloadAction<{ jid: string }>) {
|
|
386
548
|
const { jid } = action.payload;
|
|
@@ -441,6 +603,7 @@ const reducers = {
|
|
|
441
603
|
room.messages.map((message) => {
|
|
442
604
|
if (message.id === messageId) {
|
|
443
605
|
message.isDeleted = true;
|
|
606
|
+
message.reaction = undefined;
|
|
444
607
|
}
|
|
445
608
|
});
|
|
446
609
|
},
|
|
@@ -486,79 +649,51 @@ const reducers = {
|
|
|
486
649
|
}>
|
|
487
650
|
) {
|
|
488
651
|
const { roomJID, message, start } = action.payload;
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
// or the room-list "last message" preview.
|
|
494
|
-
if (isCallSignalMessage(message)) {
|
|
495
|
-
return;
|
|
652
|
+
const lengthBefore = state.rooms[roomJID]?.messages?.length || 0;
|
|
653
|
+
const outcome = insertRoomMessage(state, roomJID, message, start);
|
|
654
|
+
if (outcome.grew) {
|
|
655
|
+
capAfterGrowth(state.rooms[roomJID].messages!, lengthBefore, outcome.atHead);
|
|
496
656
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
657
|
+
bumpLastMessageTimestamp(state, roomJID, message);
|
|
658
|
+
},
|
|
659
|
+
/**
|
|
660
|
+
* A whole page of messages (a MAM history page) in ONE action: the same
|
|
661
|
+
* per-message insert as `addRoomMessage`, but the cap, the middleware
|
|
662
|
+
* chain and every subscriber run once per page instead of once per
|
|
663
|
+
* message.
|
|
664
|
+
*/
|
|
665
|
+
addRoomMessages(
|
|
666
|
+
state: WritableDraft<RoomMessagesState>,
|
|
667
|
+
action: PayloadAction<{
|
|
668
|
+
roomJID: string;
|
|
669
|
+
messages: IMessage[];
|
|
670
|
+
start?: boolean;
|
|
671
|
+
}>
|
|
672
|
+
) {
|
|
673
|
+
const { roomJID, messages, start } = action.payload;
|
|
674
|
+
if (!state.rooms[roomJID] || !Array.isArray(messages)) {
|
|
505
675
|
return;
|
|
506
676
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
// - the SERVER copy is canonical for identity (id/date/xmppId): its
|
|
520
|
-
// archive id is what MAM and the catch-up anchor return later, so
|
|
521
|
-
// keeping a local "calllog-" id around breaks anchor matching and
|
|
522
|
-
// duplicates the entry on the next history merge;
|
|
523
|
-
// - the LARGEST duration wins for display, so a 2-minute call doesn't
|
|
524
|
-
// render as "2 sec".
|
|
525
|
-
const incomingCallLog = message.callLog;
|
|
526
|
-
if (incomingCallLog?.callId) {
|
|
527
|
-
const existingCallIdx = roomMessages.findIndex(
|
|
528
|
-
(msg) => msg.callLog?.callId === incomingCallLog.callId
|
|
529
|
-
);
|
|
530
|
-
if (existingCallIdx !== -1) {
|
|
531
|
-
const existing = roomMessages[existingCallIdx];
|
|
532
|
-
const merged = mergeCallLogEntries(existing as IMessage, message);
|
|
533
|
-
if (merged !== (existing as IMessage)) {
|
|
534
|
-
roomMessages[existingCallIdx] = merged;
|
|
535
|
-
}
|
|
536
|
-
return;
|
|
677
|
+
const lengthBefore = state.rooms[roomJID].messages?.length || 0;
|
|
678
|
+
let grew = false;
|
|
679
|
+
let anyAtTail = false;
|
|
680
|
+
let newest: IMessage | undefined;
|
|
681
|
+
for (const message of messages) {
|
|
682
|
+
const outcome = insertRoomMessage(state, roomJID, message, start);
|
|
683
|
+
if (outcome.grew) {
|
|
684
|
+
grew = true;
|
|
685
|
+
if (!outcome.atHead) {anyAtTail = true;}
|
|
686
|
+
}
|
|
687
|
+
if (!newest || Number(message?.id) > Number(newest.id)) {
|
|
688
|
+
newest = message;
|
|
537
689
|
}
|
|
538
690
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
if (roomMessages.length === 0 || start) {
|
|
543
|
-
roomMessages.unshift(message);
|
|
544
|
-
} else {
|
|
545
|
-
const lastViewedValue = state.rooms[roomJID].lastViewedTimestamp;
|
|
546
|
-
const lastViewedTimestamp =
|
|
547
|
-
state.visibleRoomJID === roomJID
|
|
548
|
-
? null
|
|
549
|
-
: lastViewedValue
|
|
550
|
-
? lastViewedValue
|
|
551
|
-
: null;
|
|
552
|
-
|
|
553
|
-
insertMessageWithDelimiter(roomMessages, message, lastViewedTimestamp);
|
|
691
|
+
if (grew) {
|
|
692
|
+
// A page that only prepended older history is never trimmed.
|
|
693
|
+
capAfterGrowth(state.rooms[roomJID].messages!, lengthBefore, !anyAtTail);
|
|
554
694
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
// (i.e. this wasn't a dedupe/merge that left length unchanged).
|
|
558
|
-
// Otherwise repeated echoes of the same message would chip away
|
|
559
|
-
// at the oldest history for no reason.
|
|
560
|
-
if (roomMessages.length > lengthBefore) {
|
|
561
|
-
enforceMessageCap(roomMessages);
|
|
695
|
+
if (newest) {
|
|
696
|
+
bumpLastMessageTimestamp(state, roomJID, newest);
|
|
562
697
|
}
|
|
563
698
|
},
|
|
564
699
|
deleteAllRooms(state: WritableDraft<RoomMessagesState>) {
|
|
@@ -798,18 +933,28 @@ const reducers = {
|
|
|
798
933
|
data?: Record<string, string>;
|
|
799
934
|
}>
|
|
800
935
|
) => {
|
|
801
|
-
const { roomJID, messageId, reactions } =
|
|
936
|
+
const { roomJID, messageId, reactions, from, data, latestReactionTimestamp } =
|
|
937
|
+
action.payload;
|
|
938
|
+
if (!from) {return;}
|
|
802
939
|
const room = state.rooms[roomJID];
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
940
|
+
const target = room?.messages?.find(
|
|
941
|
+
(msg) => msg?.id === messageId || msg?.xmppId === messageId
|
|
942
|
+
);
|
|
943
|
+
if (target) {
|
|
944
|
+
applyReactionToMessage(target as IMessage, from, reactions, data, latestReactionTimestamp);
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
// The message is not loaded (yet): keep the reaction for it.
|
|
948
|
+
if (!state.pendingReactions) {state.pendingReactions = {};}
|
|
949
|
+
const byMessage = (state.pendingReactions[roomJID] ||= {});
|
|
950
|
+
const list = (byMessage[messageId] ||= []);
|
|
951
|
+
if (list.length < 50) {
|
|
952
|
+
list.push({ from, reactions, data, ts: latestReactionTimestamp });
|
|
809
953
|
}
|
|
810
954
|
},
|
|
811
955
|
setLogoutState: (state: WritableDraft<RoomMessagesState>) => {
|
|
812
956
|
state.rooms = {};
|
|
957
|
+
state.pendingReactions = {};
|
|
813
958
|
state.activeRoomJID = null;
|
|
814
959
|
state.visibleRoomJID = null;
|
|
815
960
|
state.isLoading = false;
|
|
@@ -911,6 +1056,7 @@ const reducers = {
|
|
|
911
1056
|
room.historyComplete = patch.historyComplete;
|
|
912
1057
|
}
|
|
913
1058
|
if (Array.isArray(patch.messages)) {
|
|
1059
|
+
for (const m of patch.messages) {takePendingReactions(state, patch.jid, m);}
|
|
914
1060
|
// Merge the fetched page into cache by message id rather than
|
|
915
1061
|
// replacing — preserves older history + unread on re-entry. Only
|
|
916
1062
|
// a true gap (no overlapping id) clears this chat's cache. See
|
|
@@ -1043,6 +1189,9 @@ export const {
|
|
|
1043
1189
|
deleteRoom,
|
|
1044
1190
|
updateRoom,
|
|
1045
1191
|
applyRoomsPreloadBatch,
|
|
1192
|
+
addRoomMessages,
|
|
1193
|
+
addRooms,
|
|
1194
|
+
setUnreadCounts,
|
|
1046
1195
|
setPendingNotificationJid,
|
|
1047
1196
|
clearPendingNotificationJid,
|
|
1048
1197
|
setReactions,
|
package/src/theme/theme.ts
CHANGED
|
@@ -33,8 +33,10 @@ export interface ChatThemeColors {
|
|
|
33
33
|
icon: string;
|
|
34
34
|
/** Sender name above incoming bubbles. */
|
|
35
35
|
senderName: string;
|
|
36
|
-
/** Day-separator pill text
|
|
36
|
+
/** Day-separator pill text (also system-message pills). */
|
|
37
37
|
dateLabel: string;
|
|
38
|
+
/** Day-separator / system-message pill background. */
|
|
39
|
+
dateLabelBackground: string;
|
|
38
40
|
|
|
39
41
|
/** Ground of the room list screen. */
|
|
40
42
|
listBackground: string;
|
|
@@ -100,6 +102,7 @@ export const LIGHT_THEME: ChatThemeColors = {
|
|
|
100
102
|
icon: DEFAULT_PRIMARY,
|
|
101
103
|
senderName: DEFAULT_PRIMARY,
|
|
102
104
|
dateLabel: DEFAULT_PRIMARY,
|
|
105
|
+
dateLabelBackground: '#E7EDF9',
|
|
103
106
|
|
|
104
107
|
listBackground: '#E8EDF2',
|
|
105
108
|
chatBackground: '#F3F6FC',
|
|
@@ -133,6 +136,7 @@ export const DARK_THEME: ChatThemeColors = {
|
|
|
133
136
|
icon: '#4C8DFF',
|
|
134
137
|
senderName: '#7FB0FF',
|
|
135
138
|
dateLabel: '#7FB0FF',
|
|
139
|
+
dateLabelBackground: '#26303D',
|
|
136
140
|
|
|
137
141
|
listBackground: '#0F1216',
|
|
138
142
|
chatBackground: '#141A21',
|
|
@@ -174,6 +178,7 @@ export interface ThemeConfigInput {
|
|
|
174
178
|
icon?: string;
|
|
175
179
|
senderName?: string;
|
|
176
180
|
dateLabel?: string;
|
|
181
|
+
dateLabelBackground?: string;
|
|
177
182
|
};
|
|
178
183
|
messageColor?: {
|
|
179
184
|
backgroundMessage?: string;
|
|
@@ -239,6 +244,10 @@ export const resolveTheme = (
|
|
|
239
244
|
icon: pick(c?.icon, c?.primary, LIGHT_THEME.icon)!,
|
|
240
245
|
senderName: pick(c?.senderName, c?.primary, LIGHT_THEME.senderName)!,
|
|
241
246
|
dateLabel: pick(c?.dateLabel, c?.primary, LIGHT_THEME.dateLabel)!,
|
|
247
|
+
dateLabelBackground: pick(
|
|
248
|
+
c?.dateLabelBackground,
|
|
249
|
+
LIGHT_THEME.dateLabelBackground
|
|
250
|
+
)!,
|
|
242
251
|
chatBackground: pick(config?.backgroundChat?.color, LIGHT_THEME.chatBackground)!,
|
|
243
252
|
messageBackground: pick(
|
|
244
253
|
config?.messageColor?.backgroundMessage,
|
|
@@ -50,6 +50,10 @@ export interface IMessage {
|
|
|
50
50
|
export interface ReactionMessage {
|
|
51
51
|
emoji: string[];
|
|
52
52
|
data: Record<string, string> | undefined;
|
|
53
|
+
/** Server stanza id of the reaction (microsecond timestamp). History
|
|
54
|
+
* pages arrive newest-first, so an older reaction must never overwrite
|
|
55
|
+
* a newer one; an empty `emoji` with a `ts` is a "removed" marker. */
|
|
56
|
+
ts?: string;
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
export interface IReply extends IMessage {}
|
|
@@ -60,6 +60,21 @@ export interface IRoom {
|
|
|
60
60
|
historyComplete?: boolean;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/** The flattened last-message doc `GET /v1/chats/my` embeds per room.
|
|
64
|
+
* Only present when the backend supports it; every field is optional. */
|
|
65
|
+
export interface ApiRoomLastMessage {
|
|
66
|
+
body?: string;
|
|
67
|
+
truncated?: boolean;
|
|
68
|
+
from?: string;
|
|
69
|
+
fromUserId?: string;
|
|
70
|
+
messageId?: string;
|
|
71
|
+
stanzaId?: string;
|
|
72
|
+
createdAt?: string;
|
|
73
|
+
isOwn?: boolean;
|
|
74
|
+
senderFirstName?: string;
|
|
75
|
+
senderLastName?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
63
78
|
export interface ApiRoom {
|
|
64
79
|
name: string;
|
|
65
80
|
type: 'public' | 'group' | 'private';
|
|
@@ -80,6 +95,8 @@ export interface ApiRoom {
|
|
|
80
95
|
participants?: number;
|
|
81
96
|
icon?: string;
|
|
82
97
|
muted?: boolean;
|
|
98
|
+
/** See ApiRoomLastMessage. */
|
|
99
|
+
lastMessage?: ApiRoomLastMessage;
|
|
83
100
|
}
|
|
84
101
|
|
|
85
102
|
export interface PostRoom {
|
|
@@ -32,6 +32,8 @@ export interface HistoryFetchOptions {
|
|
|
32
32
|
coalesceRoom?: boolean;
|
|
33
33
|
skipIfPreloaded?: boolean;
|
|
34
34
|
source?: HistorySource;
|
|
35
|
+
/** The caller merges the page into the store itself. */
|
|
36
|
+
selfApplied?: boolean;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
export interface XmppClientInterface {
|
|
@@ -133,11 +135,11 @@ export interface XmppClientInterface {
|
|
|
133
135
|
chats?: string[]
|
|
134
136
|
): Promise<void>;
|
|
135
137
|
sendMediaMessageStanza(roomJID: string, data: any, id?: string): void;
|
|
136
|
-
sendMessageReactionStanza
|
|
138
|
+
sendMessageReactionStanza(
|
|
137
139
|
messageId: string,
|
|
138
140
|
roomJid: string,
|
|
139
141
|
reactionsList: string[],
|
|
140
|
-
|
|
142
|
+
data?: { firstName?: string; lastName?: string }
|
|
141
143
|
): void;
|
|
142
144
|
sendTextMessageWithTranslateTagStanza?(
|
|
143
145
|
roomJID: string,
|