@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
|
@@ -23,7 +23,8 @@ import { msgSortableMs } from '../../roomStore/roomsSlice';
|
|
|
23
23
|
import Composing from '../styled/StyledInputComponents/Composing';
|
|
24
24
|
import TreadLabel from '../styled/TreadLabel';
|
|
25
25
|
import { MessageContainer } from './MessageContainer';
|
|
26
|
-
import {
|
|
26
|
+
import { useSelector } from 'react-redux';
|
|
27
|
+
import type { RootState } from '../../roomStore';
|
|
27
28
|
import Loader from '../styled/Loader';
|
|
28
29
|
import { ArowDownIcon } from '../../assets/icons';
|
|
29
30
|
import CustomTypingIndicator from '../styled/StyledInputComponents/CustomTypingIndicator';
|
|
@@ -67,6 +68,43 @@ interface MessageListProps<TMessage extends IMessage> {
|
|
|
67
68
|
onReadBoundaryChange?: (boundaryTs: number | null) => void;
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
const mainIdCache = new WeakMap<object, string | null>();
|
|
72
|
+
const mainMessageIdOf = (m: IMessage): string | null => {
|
|
73
|
+
if (!m?.mainMessage) {return null;}
|
|
74
|
+
const cached = mainIdCache.get(m);
|
|
75
|
+
if (cached !== undefined) {return cached;}
|
|
76
|
+
let id: string | null = null;
|
|
77
|
+
try {
|
|
78
|
+
const parsed = JSON.parse(m.mainMessage);
|
|
79
|
+
id = parsed?.id != null ? String(parsed.id) : null;
|
|
80
|
+
} catch {
|
|
81
|
+
id = null;
|
|
82
|
+
}
|
|
83
|
+
mainIdCache.set(m, id);
|
|
84
|
+
return id;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const sortKeyCache = new WeakMap<object, number>();
|
|
88
|
+
const sortKeyOf = (m: IMessage): number => {
|
|
89
|
+
const cached = sortKeyCache.get(m);
|
|
90
|
+
if (cached !== undefined) {return cached;}
|
|
91
|
+
const key = new Date(m?.date as any).getTime() || 0;
|
|
92
|
+
sortKeyCache.set(m, key);
|
|
93
|
+
return key;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const dayKeyCache = new WeakMap<object, string>();
|
|
97
|
+
const dayKeyOf = (m: IMessage): string => {
|
|
98
|
+
const cached = dayKeyCache.get(m);
|
|
99
|
+
if (cached !== undefined) {return cached;}
|
|
100
|
+
const key = new Date(m.date).toDateString();
|
|
101
|
+
dayKeyCache.set(m, key);
|
|
102
|
+
return key;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const keyExtractor = (item: IMessage) => String(item.id);
|
|
106
|
+
const EMPTY_LIST: IMessage[] = [];
|
|
107
|
+
|
|
70
108
|
const MessageList = <TMessage extends IMessage>({
|
|
71
109
|
CustomMessage,
|
|
72
110
|
CustomDaySeparator,
|
|
@@ -80,8 +118,12 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
80
118
|
activeMessage,
|
|
81
119
|
onReadBoundaryChange,
|
|
82
120
|
}: MessageListProps<TMessage>) => {
|
|
83
|
-
const
|
|
84
|
-
|
|
121
|
+
const room = useSelector(
|
|
122
|
+
(state: RootState) => state.rooms.rooms?.[roomJID]
|
|
123
|
+
) as IRoom | undefined;
|
|
124
|
+
const composing = room?.composing;
|
|
125
|
+
const composingList = room?.composingList;
|
|
126
|
+
const messages = room?.messages || EMPTY_LIST;
|
|
85
127
|
const theme = useTheme();
|
|
86
128
|
const [isUserAtBottom, setIsUserAtBottom] = useState(true);
|
|
87
129
|
const [showNewMessageIndicator, setShowNewMessageIndicator] = useState(false);
|
|
@@ -107,17 +149,22 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
107
149
|
const flatListRef = useRef<FlatList<IMessage>>(null);
|
|
108
150
|
|
|
109
151
|
const addReplyMessages = useMemo(() => {
|
|
152
|
+
const repliesByParent = new Map<string, IMessage[]>();
|
|
153
|
+
for (const mess of messages) {
|
|
154
|
+
if (!mess?.mainMessage || mess.isDeleted) {continue;}
|
|
155
|
+
const parentId = mainMessageIdOf(mess);
|
|
156
|
+
if (!parentId) {continue;}
|
|
157
|
+
const list = repliesByParent.get(parentId);
|
|
158
|
+
if (list) {
|
|
159
|
+
list.push(mess);
|
|
160
|
+
} else {
|
|
161
|
+
repliesByParent.set(parentId, [mess]);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (repliesByParent.size === 0) {return messages;}
|
|
110
165
|
return messages.map((message: IMessage) => {
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
reply: messages.filter(
|
|
114
|
-
(mess: IMessage) =>
|
|
115
|
-
!!mess.mainMessage &&
|
|
116
|
-
JSON.parse(mess.mainMessage).id === message.id &&
|
|
117
|
-
!mess.isDeleted
|
|
118
|
-
),
|
|
119
|
-
};
|
|
120
|
-
return newMessage;
|
|
166
|
+
const reply = repliesByParent.get(String(message.id));
|
|
167
|
+
return reply ? { ...message, reply } : message;
|
|
121
168
|
});
|
|
122
169
|
}, [messages]);
|
|
123
170
|
|
|
@@ -134,7 +181,7 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
134
181
|
item.isReply &&
|
|
135
182
|
item.isReply === 'true' &&
|
|
136
183
|
item.mainMessage &&
|
|
137
|
-
|
|
184
|
+
mainMessageIdOf(item) === String(activeMessage?.id)
|
|
138
185
|
);
|
|
139
186
|
} else {
|
|
140
187
|
filtered = nonDeletedMessages.filter(
|
|
@@ -154,14 +201,21 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
154
201
|
// settles. Sorting here makes each render a stable, ordered view —
|
|
155
202
|
// even mid-stream — so the user sees them appear from oldest to
|
|
156
203
|
// newest with no swap animation.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
);
|
|
204
|
+
let sorted = filtered;
|
|
205
|
+
for (let i = 1; i < filtered.length; i++) {
|
|
206
|
+
if (sortKeyOf(filtered[i - 1]) > sortKeyOf(filtered[i])) {
|
|
207
|
+
sorted = filtered.slice().sort((a, b) => sortKeyOf(a) - sortKeyOf(b));
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const seen = new Set<string>();
|
|
212
|
+
const deduped: IMessage[] = [];
|
|
213
|
+
for (const m of sorted) {
|
|
214
|
+
const key = String(m.id);
|
|
215
|
+
if (seen.has(key)) {continue;}
|
|
216
|
+
seen.add(key);
|
|
217
|
+
deduped.push(m);
|
|
218
|
+
}
|
|
165
219
|
return deduped;
|
|
166
220
|
}, [addReplyMessages, isReply, roomJID, activeMessage]);
|
|
167
221
|
|
|
@@ -244,8 +298,21 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
244
298
|
return withDivider;
|
|
245
299
|
}, [memoizedMessages, isUserAtBottom, roomJID, unreadWhileScrolledUp]);
|
|
246
300
|
|
|
301
|
+
const dateLabelIds = useMemo(() => {
|
|
302
|
+
const ids = new Set<string>();
|
|
303
|
+
let nextDay: string | null = null;
|
|
304
|
+
for (let i = dataMessages.length - 1; i >= 0; i--) {
|
|
305
|
+
const item = dataMessages[i];
|
|
306
|
+
if (String(item.id).startsWith('delimiter-new')) {continue;}
|
|
307
|
+
const day = dayKeyOf(item);
|
|
308
|
+
if (nextDay === null || day !== nextDay) {ids.add(String(item.id));}
|
|
309
|
+
nextDay = day;
|
|
310
|
+
}
|
|
311
|
+
return ids;
|
|
312
|
+
}, [dataMessages]);
|
|
313
|
+
|
|
247
314
|
const renderMessage = useCallback(
|
|
248
|
-
({ item
|
|
315
|
+
({ item }: { item: IMessage }) => {
|
|
249
316
|
if (String(item.id).startsWith('delimiter-new')) {
|
|
250
317
|
return (
|
|
251
318
|
<MessageContainer
|
|
@@ -262,24 +329,7 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
262
329
|
);
|
|
263
330
|
}
|
|
264
331
|
|
|
265
|
-
const
|
|
266
|
-
let showDateLabel = false;
|
|
267
|
-
|
|
268
|
-
let nextMessage = null;
|
|
269
|
-
for (let i = index + 1; i < dataMessages.length; i++) {
|
|
270
|
-
const candidate = dataMessages[i];
|
|
271
|
-
if (!String(candidate.id).startsWith('delimiter-new')) {
|
|
272
|
-
nextMessage = candidate;
|
|
273
|
-
break;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
const nextMessageDate = nextMessage
|
|
277
|
-
? new Date(nextMessage.date).toDateString()
|
|
278
|
-
: null;
|
|
279
|
-
|
|
280
|
-
if (!nextMessage || messageDate !== nextMessageDate) {
|
|
281
|
-
showDateLabel = true;
|
|
282
|
-
}
|
|
332
|
+
const showDateLabel = dateLabelIds.has(String(item.id));
|
|
283
333
|
|
|
284
334
|
return (
|
|
285
335
|
<MessageContainer
|
|
@@ -301,7 +351,7 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
301
351
|
CustomDaySeparator,
|
|
302
352
|
CustomMessage,
|
|
303
353
|
CustomNewMessageLabel,
|
|
304
|
-
|
|
354
|
+
dateLabelIds,
|
|
305
355
|
isReply,
|
|
306
356
|
user.xmppUsername,
|
|
307
357
|
user.walletAddress,
|
|
@@ -452,7 +502,10 @@ const MessageList = <TMessage extends IMessage>({
|
|
|
452
502
|
ref={flatListRef}
|
|
453
503
|
data={dataMessages}
|
|
454
504
|
renderItem={renderMessage}
|
|
455
|
-
keyExtractor={
|
|
505
|
+
keyExtractor={keyExtractor}
|
|
506
|
+
initialNumToRender={15}
|
|
507
|
+
maxToRenderPerBatch={10}
|
|
508
|
+
windowSize={7}
|
|
456
509
|
onEndReached={handleLoadMore}
|
|
457
510
|
onScroll={handleScroll}
|
|
458
511
|
onContentSizeChange={handleContentSizeChange}
|
|
@@ -121,10 +121,16 @@ const RoomList: React.FC<RoomListProps> = ({
|
|
|
121
121
|
setSearchTerm(text);
|
|
122
122
|
}, []);
|
|
123
123
|
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
const activityOf = useCallback((chat: IRoom): number => {
|
|
125
|
+
const last = chat?.messages?.[chat?.messages.length - 1];
|
|
126
|
+
const fromLive = Number(last?.id);
|
|
127
|
+
if (Number.isFinite(fromLive) && fromLive > 0) {return fromLive;}
|
|
128
|
+
const fromStamp = Number(chat?.lastMessageTimestamp);
|
|
129
|
+
if (Number.isFinite(fromStamp) && fromStamp > 0) {return fromStamp;}
|
|
130
|
+
const fromSeed = Number(chat?.lastMessage?.id);
|
|
131
|
+
if (Number.isFinite(fromSeed) && fromSeed > 0) {return fromSeed;}
|
|
132
|
+
return 0;
|
|
133
|
+
}, []);
|
|
128
134
|
|
|
129
135
|
const filteredChats = useMemo(() => {
|
|
130
136
|
const lowerCaseSearchTerm = searchTerm.toLowerCase();
|
|
@@ -136,22 +142,13 @@ const RoomList: React.FC<RoomListProps> = ({
|
|
|
136
142
|
const hay = `${chat?.title || ''} ${chat?.name || ''}`.toLowerCase();
|
|
137
143
|
return hay.includes(lowerCaseSearchTerm);
|
|
138
144
|
})
|
|
139
|
-
.sort((a, b) =>
|
|
140
|
-
if (getLastMessage(a)?.id && getLastMessage(b)?.id) {
|
|
141
|
-
return Number(getLastMessage(b).id) - Number(getLastMessage(a).id);
|
|
142
|
-
} else if (getLastMessage(a)?.id) {
|
|
143
|
-
return -1;
|
|
144
|
-
} else if (getLastMessage(b)?.id) {
|
|
145
|
-
return 1;
|
|
146
|
-
}
|
|
147
|
-
return -1;
|
|
148
|
-
});
|
|
145
|
+
.sort((a, b) => activityOf(b) - activityOf(a));
|
|
149
146
|
|
|
150
147
|
chatsMap.set(lowerCaseSearchTerm, result);
|
|
151
148
|
}
|
|
152
149
|
|
|
153
150
|
return chatsMap.get(lowerCaseSearchTerm) || [];
|
|
154
|
-
}, [chats, searchTerm]);
|
|
151
|
+
}, [chats, searchTerm, activityOf]);
|
|
155
152
|
|
|
156
153
|
useEffect(() => {
|
|
157
154
|
if (burgerMenu) {
|
|
@@ -278,6 +275,21 @@ const RoomList: React.FC<RoomListProps> = ({
|
|
|
278
275
|
}
|
|
279
276
|
}, [isSearchFocused]);
|
|
280
277
|
|
|
278
|
+
const renderRoom = useCallback(
|
|
279
|
+
({ item }: { item: IRoom }) => (
|
|
280
|
+
<Pressable
|
|
281
|
+
testID={`room-${(item.jid || '').split('@')[0]}`}
|
|
282
|
+
accessibilityLabel={`room-${item.title || item.name}`}
|
|
283
|
+
onPress={() => performClick(item)}
|
|
284
|
+
onPressIn={handlePressIn}
|
|
285
|
+
onPressOut={handlePressOut}
|
|
286
|
+
>
|
|
287
|
+
<ChatRoomItem chat={item} config={config} />
|
|
288
|
+
</Pressable>
|
|
289
|
+
),
|
|
290
|
+
[performClick, handlePressIn, handlePressOut, config]
|
|
291
|
+
);
|
|
292
|
+
|
|
281
293
|
const toggleDrawer = () => {
|
|
282
294
|
if (isDrawerOpen) {
|
|
283
295
|
closeDrawer();
|
|
@@ -392,20 +404,7 @@ const RoomList: React.FC<RoomListProps> = ({
|
|
|
392
404
|
onMomentumScrollBegin={handleMomentumBegin}
|
|
393
405
|
onMomentumScrollEnd={handleMomentumEnd}
|
|
394
406
|
keyboardShouldPersistTaps="handled"
|
|
395
|
-
renderItem={
|
|
396
|
-
<Pressable
|
|
397
|
-
// Stable testID so e2e drivers can target a room
|
|
398
|
-
// row by its jid local-part (e.g. Main chat under
|
|
399
|
-
// app id `..._...759` → testID `room-...759`).
|
|
400
|
-
testID={`room-${(item.jid || '').split('@')[0]}`}
|
|
401
|
-
accessibilityLabel={`room-${item.title || item.name}`}
|
|
402
|
-
onPress={() => performClick(item)}
|
|
403
|
-
onPressIn={handlePressIn}
|
|
404
|
-
onPressOut={handlePressOut}
|
|
405
|
-
>
|
|
406
|
-
<ChatRoomItem chat={item} config={config} />
|
|
407
|
-
</Pressable>
|
|
408
|
-
)}
|
|
407
|
+
renderItem={renderRoom}
|
|
409
408
|
style={[
|
|
410
409
|
styles.chatList,
|
|
411
410
|
{ backgroundColor: theme.listBackground },
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
forwardRef,
|
|
3
|
+
memo,
|
|
4
|
+
ReactNode,
|
|
5
|
+
useCallback,
|
|
6
|
+
useEffect,
|
|
7
|
+
useImperativeHandle,
|
|
8
|
+
useMemo,
|
|
9
|
+
useRef,
|
|
10
|
+
useState,
|
|
11
|
+
} from 'react';
|
|
12
|
+
import {
|
|
13
|
+
Animated,
|
|
14
|
+
BackHandler,
|
|
15
|
+
Easing,
|
|
16
|
+
Keyboard,
|
|
17
|
+
LayoutChangeEvent,
|
|
18
|
+
StyleSheet,
|
|
19
|
+
useWindowDimensions,
|
|
20
|
+
View,
|
|
21
|
+
} from 'react-native';
|
|
22
|
+
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
23
|
+
|
|
24
|
+
// Width of the left-edge strip that starts the back swipe.
|
|
25
|
+
export const EDGE_WIDTH = 28;
|
|
26
|
+
// Released past this share of the width (or faster than the velocity
|
|
27
|
+
// below), the swipe completes; otherwise the room settles back.
|
|
28
|
+
export const COMPLETE_DISTANCE = 0.35;
|
|
29
|
+
export const COMPLETE_VELOCITY = 600;
|
|
30
|
+
// How far the list underneath is shifted left while fully covered.
|
|
31
|
+
const LIST_PARALLAX = 0.3;
|
|
32
|
+
export const LIST_DIM = 0.25;
|
|
33
|
+
|
|
34
|
+
export const PUSH = { duration: 320, easing: Easing.bezier(0.2, 0.8, 0.2, 1) };
|
|
35
|
+
export const POP = { duration: 240, easing: Easing.out(Easing.cubic) };
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Holds its children still while `frozen`: the list under an open room is
|
|
39
|
+
* fully covered, so re-rendering it on every store update (each incoming
|
|
40
|
+
* message) is wasted work on the JS thread. It thaws as soon as it is
|
|
41
|
+
* about to be seen again.
|
|
42
|
+
*/
|
|
43
|
+
const Freezable = memo(
|
|
44
|
+
({ children }: { frozen: boolean; children: ReactNode }) => <>{children}</>,
|
|
45
|
+
(_prev, next) => next.frozen
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
export interface RoomStackHandle {
|
|
49
|
+
/** Slide the room out, then call `onBack`. */
|
|
50
|
+
pop: () => void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface RoomStackProps {
|
|
54
|
+
/** The room list — stays mounted under the room so it is there to reveal. */
|
|
55
|
+
list: ReactNode;
|
|
56
|
+
/** The open room, or null while only the list is shown. */
|
|
57
|
+
room: ReactNode | null;
|
|
58
|
+
/** Called once the room has left the screen (swipe, back button, pop()). */
|
|
59
|
+
onBack: () => void;
|
|
60
|
+
/** Background behind the room's content. */
|
|
61
|
+
roomBackground?: string;
|
|
62
|
+
/** Android hardware back / system back gesture returns to the list. */
|
|
63
|
+
hardwareBack?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Two-layer stack for the list → room navigation: the room slides in over
|
|
68
|
+
* the list, and a swipe from the left edge drags it back out, following the
|
|
69
|
+
* finger, with the list parallaxing in underneath (the iOS navigation feel).
|
|
70
|
+
*
|
|
71
|
+
* Driven by RN's own `Animated` (native driver), not Reanimated: every layer
|
|
72
|
+
* derives from ONE value through interpolation, so the layers cannot drift
|
|
73
|
+
* apart, and a React re-render mid-flight cannot reset a layer to the style
|
|
74
|
+
* it was first rendered with.
|
|
75
|
+
*/
|
|
76
|
+
export const RoomStack = forwardRef<RoomStackHandle, RoomStackProps>(
|
|
77
|
+
({ list, room, onBack, roomBackground, hardwareBack = true }, ref) => {
|
|
78
|
+
const { width: windowWidth } = useWindowDimensions();
|
|
79
|
+
const [width, setWidth] = useState(windowWidth);
|
|
80
|
+
const widthRef = useRef(width);
|
|
81
|
+
widthRef.current = width;
|
|
82
|
+
const hasRoom = !!room;
|
|
83
|
+
// Room's horizontal offset: 0 = covering the list, `width` = off-screen.
|
|
84
|
+
// A room already open on the first render is shown in place.
|
|
85
|
+
const x = useRef(new Animated.Value(hasRoom ? 0 : windowWidth)).current;
|
|
86
|
+
const closing = useRef(false);
|
|
87
|
+
|
|
88
|
+
// True while the list is (about to be) visible under a moving room.
|
|
89
|
+
const [peeking, setPeeking] = useState(false);
|
|
90
|
+
// Bumped after every completed pop — see the settle effect below.
|
|
91
|
+
const [popCount, setPopCount] = useState(0);
|
|
92
|
+
|
|
93
|
+
const slideTo = useCallback(
|
|
94
|
+
(
|
|
95
|
+
toValue: number,
|
|
96
|
+
config: typeof PUSH,
|
|
97
|
+
done?: (finished: boolean) => void
|
|
98
|
+
) => {
|
|
99
|
+
Animated.timing(x, {
|
|
100
|
+
toValue,
|
|
101
|
+
...config,
|
|
102
|
+
useNativeDriver: true,
|
|
103
|
+
}).start(({ finished }) => done?.(finished));
|
|
104
|
+
},
|
|
105
|
+
[x]
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const isFirstRender = useRef(true);
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (isFirstRender.current) {
|
|
111
|
+
isFirstRender.current = false;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
closing.current = false;
|
|
115
|
+
setPeeking(false);
|
|
116
|
+
x.stopAnimation();
|
|
117
|
+
x.setValue(widthRef.current);
|
|
118
|
+
if (hasRoom) {
|
|
119
|
+
slideTo(0, PUSH);
|
|
120
|
+
}
|
|
121
|
+
}, [hasRoom]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
122
|
+
|
|
123
|
+
const onBackRef = useRef(onBack);
|
|
124
|
+
onBackRef.current = onBack;
|
|
125
|
+
const finish = useCallback(() => {
|
|
126
|
+
onBackRef.current();
|
|
127
|
+
setPopCount(count => count + 1);
|
|
128
|
+
}, []);
|
|
129
|
+
|
|
130
|
+
// `onBack` normally clears the room, and the effect above takes over.
|
|
131
|
+
// If the room is still (or again) there after a pop — something
|
|
132
|
+
// re-selected it — bring it back on screen: a room parked off-screen
|
|
133
|
+
// would leave the list visible but untouchable.
|
|
134
|
+
const hasRoomRef = useRef(hasRoom);
|
|
135
|
+
hasRoomRef.current = hasRoom;
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
if (popCount === 0 || !hasRoomRef.current) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
closing.current = false;
|
|
141
|
+
setPeeking(false);
|
|
142
|
+
slideTo(0, POP);
|
|
143
|
+
}, [popCount]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
144
|
+
|
|
145
|
+
const slideOut = useCallback(() => {
|
|
146
|
+
closing.current = true;
|
|
147
|
+
setPeeking(true);
|
|
148
|
+
slideTo(widthRef.current, POP, finished => {
|
|
149
|
+
if (finished) {
|
|
150
|
+
finish();
|
|
151
|
+
} else {
|
|
152
|
+
closing.current = false;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}, [finish, slideTo]);
|
|
156
|
+
|
|
157
|
+
const pop = useCallback(() => {
|
|
158
|
+
if (closing.current) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
Keyboard.dismiss();
|
|
162
|
+
slideOut();
|
|
163
|
+
}, [slideOut]);
|
|
164
|
+
|
|
165
|
+
useImperativeHandle(ref, () => ({ pop }), [pop]);
|
|
166
|
+
|
|
167
|
+
useEffect(() => {
|
|
168
|
+
if (!hasRoom || !hardwareBack) {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
const sub = BackHandler.addEventListener('hardwareBackPress', () => {
|
|
172
|
+
pop();
|
|
173
|
+
return true;
|
|
174
|
+
});
|
|
175
|
+
return () => sub.remove();
|
|
176
|
+
}, [hasRoom, hardwareBack, pop]);
|
|
177
|
+
|
|
178
|
+
const swipeBack = useMemo(
|
|
179
|
+
() =>
|
|
180
|
+
Gesture.Pan()
|
|
181
|
+
.runOnJS(true)
|
|
182
|
+
.hitSlop({ left: 0, width: EDGE_WIDTH })
|
|
183
|
+
.activeOffsetX(12)
|
|
184
|
+
.failOffsetY([-16, 16])
|
|
185
|
+
.onStart(() => {
|
|
186
|
+
if (closing.current) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
Keyboard.dismiss();
|
|
190
|
+
setPeeking(true);
|
|
191
|
+
x.stopAnimation();
|
|
192
|
+
})
|
|
193
|
+
.onUpdate(e => {
|
|
194
|
+
if (closing.current) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
x.setValue(Math.min(Math.max(e.translationX, 0), widthRef.current));
|
|
198
|
+
})
|
|
199
|
+
.onEnd(e => {
|
|
200
|
+
if (closing.current) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const complete =
|
|
204
|
+
e.translationX > widthRef.current * COMPLETE_DISTANCE ||
|
|
205
|
+
e.velocityX > COMPLETE_VELOCITY;
|
|
206
|
+
if (complete) {
|
|
207
|
+
slideOut();
|
|
208
|
+
} else {
|
|
209
|
+
slideTo(0, POP, () => setPeeking(false));
|
|
210
|
+
}
|
|
211
|
+
}),
|
|
212
|
+
[slideOut, slideTo, x]
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const onLayout = useCallback(
|
|
216
|
+
(e: LayoutChangeEvent) => {
|
|
217
|
+
const next = e.nativeEvent.layout.width;
|
|
218
|
+
if (next > 0 && next !== widthRef.current) {
|
|
219
|
+
// Keep an off-screen room off-screen when the container resizes.
|
|
220
|
+
if (!hasRoomRef.current) {
|
|
221
|
+
x.setValue(next);
|
|
222
|
+
}
|
|
223
|
+
setWidth(next);
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
[x]
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
const { listShift, dimOpacity } = useMemo(
|
|
230
|
+
() => ({
|
|
231
|
+
listShift: x.interpolate({
|
|
232
|
+
inputRange: [0, width],
|
|
233
|
+
outputRange: [-width * LIST_PARALLAX, 0],
|
|
234
|
+
extrapolate: 'clamp',
|
|
235
|
+
}),
|
|
236
|
+
dimOpacity: x.interpolate({
|
|
237
|
+
inputRange: [0, width],
|
|
238
|
+
outputRange: [LIST_DIM, 0],
|
|
239
|
+
extrapolate: 'clamp',
|
|
240
|
+
}),
|
|
241
|
+
}),
|
|
242
|
+
[x, width]
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
return (
|
|
246
|
+
<View style={styles.container} onLayout={onLayout}>
|
|
247
|
+
<Animated.View
|
|
248
|
+
style={[
|
|
249
|
+
styles.layer,
|
|
250
|
+
// Without a room the list always rests in place, whatever the
|
|
251
|
+
// animated value is doing.
|
|
252
|
+
hasRoom ? { transform: [{ translateX: listShift }] } : null,
|
|
253
|
+
]}
|
|
254
|
+
pointerEvents={hasRoom ? 'none' : 'auto'}
|
|
255
|
+
accessibilityElementsHidden={hasRoom}
|
|
256
|
+
importantForAccessibility={hasRoom ? 'no-hide-descendants' : 'auto'}
|
|
257
|
+
>
|
|
258
|
+
<Freezable frozen={hasRoom && !peeking}>{list}</Freezable>
|
|
259
|
+
</Animated.View>
|
|
260
|
+
{hasRoom && (
|
|
261
|
+
<>
|
|
262
|
+
<Animated.View
|
|
263
|
+
pointerEvents="none"
|
|
264
|
+
style={[styles.layer, styles.dim, { opacity: dimOpacity }]}
|
|
265
|
+
/>
|
|
266
|
+
<GestureDetector gesture={swipeBack}>
|
|
267
|
+
<Animated.View
|
|
268
|
+
style={[
|
|
269
|
+
styles.layer,
|
|
270
|
+
styles.room,
|
|
271
|
+
{ backgroundColor: roomBackground },
|
|
272
|
+
{ transform: [{ translateX: x }] },
|
|
273
|
+
]}
|
|
274
|
+
>
|
|
275
|
+
{room}
|
|
276
|
+
</Animated.View>
|
|
277
|
+
</GestureDetector>
|
|
278
|
+
</>
|
|
279
|
+
)}
|
|
280
|
+
</View>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
RoomStack.displayName = 'RoomStack';
|
|
286
|
+
|
|
287
|
+
const styles = StyleSheet.create({
|
|
288
|
+
container: {
|
|
289
|
+
flex: 1,
|
|
290
|
+
width: '100%',
|
|
291
|
+
overflow: 'hidden',
|
|
292
|
+
},
|
|
293
|
+
layer: {
|
|
294
|
+
position: 'absolute',
|
|
295
|
+
top: 0,
|
|
296
|
+
right: 0,
|
|
297
|
+
bottom: 0,
|
|
298
|
+
left: 0,
|
|
299
|
+
},
|
|
300
|
+
dim: {
|
|
301
|
+
backgroundColor: '#000',
|
|
302
|
+
},
|
|
303
|
+
room: {
|
|
304
|
+
shadowColor: '#000',
|
|
305
|
+
shadowOffset: { width: -4, height: 0 },
|
|
306
|
+
shadowOpacity: 0.18,
|
|
307
|
+
shadowRadius: 12,
|
|
308
|
+
},
|
|
309
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { View, Text, StyleSheet } from 'react-native';
|
|
3
|
+
import { useTheme } from '../../hooks/useTheme';
|
|
3
4
|
|
|
4
5
|
interface SystemMessageProps {
|
|
5
6
|
messageText?: string;
|
|
@@ -10,6 +11,9 @@ const SystemMessage: React.FC<SystemMessageProps> = ({
|
|
|
10
11
|
messageText,
|
|
11
12
|
colors,
|
|
12
13
|
}) => {
|
|
14
|
+
// Same pill as the day separator; `colors.secondary` is not a pill
|
|
15
|
+
// colour (see DateLabel).
|
|
16
|
+
const theme = useTheme();
|
|
13
17
|
return (
|
|
14
18
|
<View style={styles.container}>
|
|
15
19
|
{/* maxWidth lives on this View (not the Text) so the Text reliably
|
|
@@ -19,10 +23,10 @@ const SystemMessage: React.FC<SystemMessageProps> = ({
|
|
|
19
23
|
<View
|
|
20
24
|
style={[
|
|
21
25
|
styles.bubble,
|
|
22
|
-
{ backgroundColor:
|
|
26
|
+
{ backgroundColor: theme.dateLabelBackground },
|
|
23
27
|
]}
|
|
24
28
|
>
|
|
25
|
-
<Text style={[styles.text, { color: colors?.primary ||
|
|
29
|
+
<Text style={[styles.text, { color: colors?.primary || theme.dateLabel }]}>
|
|
26
30
|
{messageText}
|
|
27
31
|
</Text>
|
|
28
32
|
</View>
|
|
@@ -11,6 +11,8 @@ interface AvatarProps {
|
|
|
11
11
|
firstName?: string;
|
|
12
12
|
lastName?: string;
|
|
13
13
|
style?: object;
|
|
14
|
+
/** Initials size (default 16) — small avatars need smaller text. */
|
|
15
|
+
textSize?: number;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
const AvatarCircle = styled.View<{ bgColor?: string }>`
|
|
@@ -41,6 +43,7 @@ export const Avatar: React.FC<AvatarProps> = ({
|
|
|
41
43
|
firstName,
|
|
42
44
|
lastName,
|
|
43
45
|
style,
|
|
46
|
+
textSize,
|
|
44
47
|
}) => {
|
|
45
48
|
const { config } = useChatSettingState();
|
|
46
49
|
const backgroundColor = useMemo(() => {
|
|
@@ -85,7 +88,10 @@ export const Avatar: React.FC<AvatarProps> = ({
|
|
|
85
88
|
|
|
86
89
|
return (
|
|
87
90
|
<AvatarCircle style={style} bgColor={backgroundColor?.backgroundColor}>
|
|
88
|
-
<AvatarText
|
|
91
|
+
<AvatarText
|
|
92
|
+
color={getAvatarTextColor(backgroundColor?.backgroundColor)}
|
|
93
|
+
style={textSize ? { fontSize: textSize } : undefined}
|
|
94
|
+
>
|
|
89
95
|
{getInitials()}
|
|
90
96
|
</AvatarText>
|
|
91
97
|
</AvatarCircle>
|