@ethora/chat-component-rn 26.7.5 → 26.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +62 -0
- package/README.md +31 -8
- package/lib/commonjs/assets/icons.js +7 -2
- package/lib/commonjs/assets/icons.js.map +1 -1
- package/lib/commonjs/components/Header/HeaderRoomList.js +26 -7
- package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatHeader.js +5 -2
- package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatRoom.js +36 -14
- package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatWrapper.js +2 -0
- package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MessageList.js +7 -23
- package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js +14 -13
- package/lib/commonjs/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
- package/lib/commonjs/components/MainComponents/RoomList.js +208 -35
- package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
- package/lib/commonjs/components/Menu/HeaderRoomListMenu.js +317 -98
- package/lib/commonjs/components/Menu/HeaderRoomListMenu.js.map +1 -1
- package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js +320 -110
- package/lib/commonjs/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +552 -213
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js +226 -0
- package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +6 -2
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/commonjs/components/Modals/Modal/Modal.js +8 -0
- package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
- package/lib/commonjs/components/Modals/NewChatModal/ModalContent.js +2 -1
- package/lib/commonjs/components/Modals/NewChatModal/ModalContent.js.map +1 -1
- package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js +202 -104
- package/lib/commonjs/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
- package/lib/commonjs/components/Modals/NewChatModal/UpdNewChatModal.js +8 -0
- package/lib/commonjs/components/Modals/NewChatModal/UpdNewChatModal.js.map +1 -1
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js +556 -0
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js +210 -0
- package/lib/commonjs/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
- package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
- package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
- package/lib/commonjs/components/Modals/UserProfileModal/EditUserModal.js +7 -21
- package/lib/commonjs/components/Modals/UserProfileModal/EditUserModal.js.map +1 -1
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +507 -244
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js +74 -46
- package/lib/commonjs/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
- package/lib/commonjs/components/Modals/styledModalComponents.js +9 -2
- package/lib/commonjs/components/Modals/styledModalComponents.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +17 -7
- package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
- package/lib/commonjs/components/styled/SendInput.js +80 -11
- package/lib/commonjs/components/styled/SendInput.js.map +1 -1
- package/lib/commonjs/components/styled/StyledComponents.js +9 -3
- package/lib/commonjs/components/styled/StyledComponents.js.map +1 -1
- package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
- package/lib/commonjs/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
- package/lib/commonjs/context/xmppProvider.js +32 -39
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/helpers/getChatBackground.js +23 -0
- package/lib/commonjs/helpers/getChatBackground.js.map +1 -0
- package/lib/commonjs/helpers/mediaLibraryRuntime.js +31 -0
- package/lib/commonjs/helpers/mediaLibraryRuntime.js.map +1 -0
- package/lib/commonjs/helpers/pickImageAsset.js +68 -0
- package/lib/commonjs/helpers/pickImageAsset.js.map +1 -0
- package/lib/commonjs/helpers/pushPayload.js +71 -0
- package/lib/commonjs/helpers/pushPayload.js.map +1 -0
- package/lib/commonjs/helpers/sheetGestures.js +32 -0
- package/lib/commonjs/helpers/sheetGestures.js.map +1 -0
- package/lib/commonjs/helpers/updateMessagesTillLast.js +12 -40
- package/lib/commonjs/helpers/updateMessagesTillLast.js.map +1 -1
- package/lib/commonjs/hooks/useChatRoomFocus.js +3 -9
- package/lib/commonjs/hooks/useChatRoomFocus.js.map +1 -1
- package/lib/commonjs/hooks/useLogout.js +0 -5
- package/lib/commonjs/hooks/useLogout.js.map +1 -1
- package/lib/commonjs/hooks/usePendingNotification.js +8 -11
- package/lib/commonjs/hooks/usePendingNotification.js.map +1 -1
- package/lib/commonjs/hooks/useSendMessage.js +23 -50
- package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
- package/lib/commonjs/i18n/strings.js +121 -1
- package/lib/commonjs/i18n/strings.js.map +1 -1
- package/lib/commonjs/main.js +19 -0
- package/lib/commonjs/main.js.map +1 -1
- package/lib/commonjs/networking/api-requests/user.api.js +59 -0
- package/lib/commonjs/networking/api-requests/user.api.js.map +1 -1
- package/lib/commonjs/networking/authRefresh.js +12 -2
- package/lib/commonjs/networking/authRefresh.js.map +1 -1
- package/lib/commonjs/networking/outboundQueue.js +0 -18
- package/lib/commonjs/networking/outboundQueue.js.map +1 -1
- package/lib/commonjs/networking/stanzaHandlers.js +1 -10
- package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
- package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js +8 -1
- package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/subscribeToRoomMessages.xmpp.js +5 -1
- package/lib/commonjs/networking/xmpp/subscribeToRoomMessages.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmppClient.js +62 -108
- package/lib/commonjs/networking/xmppClient.js.map +1 -1
- package/lib/commonjs/roomStore/chatSettingsSlice.js +3 -1
- package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
- package/lib/commonjs/roomStore/roomsSlice.js +3 -22
- package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
- package/lib/commonjs/services/pushSubscriptionService.js +15 -13
- package/lib/commonjs/services/pushSubscriptionService.js.map +1 -1
- package/lib/module/assets/icons.js +6 -1
- package/lib/module/assets/icons.js.map +1 -1
- package/lib/module/components/Header/HeaderRoomList.js +26 -7
- package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
- package/lib/module/components/MainComponents/ChatHeader.js +5 -2
- package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/module/components/MainComponents/ChatRoom.js +36 -14
- package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/module/components/MainComponents/ChatWrapper.js +2 -0
- package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
- package/lib/module/components/MainComponents/MessageList.js +8 -24
- package/lib/module/components/MainComponents/MessageList.js.map +1 -1
- package/lib/module/components/MainComponents/ProfileImagePlaceholder.js +14 -13
- package/lib/module/components/MainComponents/ProfileImagePlaceholder.js.map +1 -1
- package/lib/module/components/MainComponents/RoomList.js +207 -35
- package/lib/module/components/MainComponents/RoomList.js.map +1 -1
- package/lib/module/components/Menu/HeaderRoomListMenu.js +319 -101
- package/lib/module/components/Menu/HeaderRoomListMenu.js.map +1 -1
- package/lib/module/components/Modals/AttachSheet/AttachSheet.js +311 -113
- package/lib/module/components/Modals/AttachSheet/AttachSheet.js.map +1 -1
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +555 -217
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js +223 -0
- package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -0
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +6 -2
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/module/components/Modals/Modal/Modal.js +9 -1
- package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
- package/lib/module/components/Modals/NewChatModal/ModalContent.js +2 -1
- package/lib/module/components/Modals/NewChatModal/ModalContent.js.map +1 -1
- package/lib/module/components/Modals/NewChatModal/NewChatModal.js +205 -106
- package/lib/module/components/Modals/NewChatModal/NewChatModal.js.map +1 -1
- package/lib/module/components/Modals/NewChatModal/UpdNewChatModal.js +8 -0
- package/lib/module/components/Modals/NewChatModal/UpdNewChatModal.js.map +1 -1
- package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js +548 -0
- package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -0
- package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js +205 -0
- package/lib/module/components/Modals/ProfileHeader/ProfileMenu.js.map +1 -0
- package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js +4 -2
- package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
- package/lib/module/components/Modals/UserProfileModal/EditUserModal.js +9 -23
- package/lib/module/components/Modals/UserProfileModal/EditUserModal.js.map +1 -1
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +509 -248
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js +76 -48
- package/lib/module/components/Modals/UserSettingsModal/UserSettingsModal.js.map +1 -1
- package/lib/module/components/Modals/styledModalComponents.js +9 -2
- package/lib/module/components/Modals/styledModalComponents.js.map +1 -1
- package/lib/module/components/RoomComponents/ChatRoomItem.js +17 -7
- package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
- package/lib/module/components/styled/SendInput.js +81 -12
- package/lib/module/components/styled/SendInput.js.map +1 -1
- package/lib/module/components/styled/StyledComponents.js +9 -3
- package/lib/module/components/styled/StyledComponents.js.map +1 -1
- package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js +11 -4
- package/lib/module/components/styled/StyledInputComponents/StyledInputComponents.js.map +1 -1
- package/lib/module/context/xmppProvider.js +32 -39
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/helpers/getChatBackground.js +18 -0
- package/lib/module/helpers/getChatBackground.js.map +1 -0
- package/lib/module/helpers/mediaLibraryRuntime.js +25 -0
- package/lib/module/helpers/mediaLibraryRuntime.js.map +1 -0
- package/lib/module/helpers/pickImageAsset.js +63 -0
- package/lib/module/helpers/pickImageAsset.js.map +1 -0
- package/lib/module/helpers/pushPayload.js +63 -0
- package/lib/module/helpers/pushPayload.js.map +1 -0
- package/lib/module/helpers/sheetGestures.js +26 -0
- package/lib/module/helpers/sheetGestures.js.map +1 -0
- package/lib/module/helpers/updateMessagesTillLast.js +13 -41
- package/lib/module/helpers/updateMessagesTillLast.js.map +1 -1
- package/lib/module/hooks/useChatRoomFocus.js +3 -9
- package/lib/module/hooks/useChatRoomFocus.js.map +1 -1
- package/lib/module/hooks/useLogout.js +0 -5
- package/lib/module/hooks/useLogout.js.map +1 -1
- package/lib/module/hooks/usePendingNotification.js +8 -11
- package/lib/module/hooks/usePendingNotification.js.map +1 -1
- package/lib/module/hooks/useSendMessage.js +24 -51
- package/lib/module/hooks/useSendMessage.js.map +1 -1
- package/lib/module/i18n/strings.js +121 -1
- package/lib/module/i18n/strings.js.map +1 -1
- package/lib/module/main.js +2 -1
- package/lib/module/main.js.map +1 -1
- package/lib/module/networking/api-requests/user.api.js +56 -0
- package/lib/module/networking/api-requests/user.api.js.map +1 -1
- package/lib/module/networking/authRefresh.js +12 -2
- package/lib/module/networking/authRefresh.js.map +1 -1
- package/lib/module/networking/outboundQueue.js +0 -17
- package/lib/module/networking/outboundQueue.js.map +1 -1
- package/lib/module/networking/stanzaHandlers.js +1 -10
- package/lib/module/networking/stanzaHandlers.js.map +1 -1
- package/lib/module/networking/xmpp/presenceInRoom.xmpp.js +8 -1
- package/lib/module/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/subscribeToRoomMessages.xmpp.js +5 -1
- package/lib/module/networking/xmpp/subscribeToRoomMessages.xmpp.js.map +1 -1
- package/lib/module/networking/xmppClient.js +62 -108
- package/lib/module/networking/xmppClient.js.map +1 -1
- package/lib/module/roomStore/chatSettingsSlice.js +3 -1
- package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
- package/lib/module/roomStore/roomsSlice.js +2 -20
- package/lib/module/roomStore/roomsSlice.js.map +1 -1
- package/lib/module/services/pushSubscriptionService.js +15 -13
- package/lib/module/services/pushSubscriptionService.js.map +1 -1
- package/lib/typescript/assets/icons.d.ts +16 -0
- package/lib/typescript/assets/icons.d.ts.map +1 -1
- 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/MessageList.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ProfileImagePlaceholder.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/RoomList.d.ts +7 -0
- package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
- package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts +3 -0
- package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts.map +1 -1
- package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts +9 -0
- package/lib/typescript/components/Modals/AttachSheet/AttachSheet.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts +10 -0
- package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts +9 -0
- package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts.map +1 -0
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/NewChatModal/ModalContent.d.ts +4 -2
- package/lib/typescript/components/Modals/NewChatModal/ModalContent.d.ts.map +1 -1
- package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts +1 -1
- package/lib/typescript/components/Modals/NewChatModal/NewChatModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/NewChatModal/UpdNewChatModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts +75 -0
- package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts.map +1 -0
- package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts +25 -0
- package/lib/typescript/components/Modals/ProfileHeader/ProfileMenu.d.ts.map +1 -0
- package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts +6 -1
- package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserProfileModal/EditUserModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts +16 -0
- package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts +1 -0
- package/lib/typescript/components/Modals/UserSettingsModal/UserSettingsModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/styledModalComponents.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
- package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
- package/lib/typescript/components/styled/StyledComponents.d.ts.map +1 -1
- package/lib/typescript/components/styled/StyledInputComponents/StyledInputComponents.d.ts.map +1 -1
- package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
- package/lib/typescript/helpers/getChatBackground.d.ts +15 -0
- package/lib/typescript/helpers/getChatBackground.d.ts.map +1 -0
- package/lib/typescript/helpers/mediaLibraryRuntime.d.ts +3 -0
- package/lib/typescript/helpers/mediaLibraryRuntime.d.ts.map +1 -0
- package/lib/typescript/helpers/pickImageAsset.d.ts +27 -0
- package/lib/typescript/helpers/pickImageAsset.d.ts.map +1 -0
- package/lib/typescript/helpers/pushPayload.d.ts +7 -0
- package/lib/typescript/helpers/pushPayload.d.ts.map +1 -0
- package/lib/typescript/helpers/sheetGestures.d.ts +20 -0
- package/lib/typescript/helpers/sheetGestures.d.ts.map +1 -0
- package/lib/typescript/helpers/updateMessagesTillLast.d.ts.map +1 -1
- package/lib/typescript/hooks/useChatRoomFocus.d.ts.map +1 -1
- package/lib/typescript/hooks/useLogout.d.ts.map +1 -1
- package/lib/typescript/hooks/usePendingNotification.d.ts.map +1 -1
- package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/i18n/strings.d.ts.map +1 -1
- package/lib/typescript/main.d.ts +3 -1
- package/lib/typescript/main.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/user.api.d.ts +27 -0
- package/lib/typescript/networking/api-requests/user.api.d.ts.map +1 -1
- package/lib/typescript/networking/authRefresh.d.ts +4 -1
- package/lib/typescript/networking/authRefresh.d.ts.map +1 -1
- package/lib/typescript/networking/outboundQueue.d.ts +0 -16
- package/lib/typescript/networking/outboundQueue.d.ts.map +1 -1
- package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/subscribeToRoomMessages.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmppClient.d.ts +8 -33
- package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
- package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts +1 -18
- package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
- package/lib/typescript/services/pushSubscriptionService.d.ts +1 -1
- package/lib/typescript/services/pushSubscriptionService.d.ts.map +1 -1
- package/lib/typescript/types/models/room.model.d.ts +0 -15
- package/lib/typescript/types/models/room.model.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +31 -20
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/assets/icons.tsx +48 -9
- package/src/components/Header/HeaderRoomList.tsx +24 -6
- package/src/components/MainComponents/ChatHeader.tsx +5 -2
- package/src/components/MainComponents/ChatRoom.tsx +38 -20
- package/src/components/MainComponents/ChatWrapper.tsx +3 -0
- package/src/components/MainComponents/MessageList.tsx +8 -24
- package/src/components/MainComponents/ProfileImagePlaceholder.tsx +21 -14
- package/src/components/MainComponents/RoomList.tsx +236 -39
- package/src/components/Menu/HeaderRoomListMenu.tsx +328 -75
- package/src/components/Modals/AttachSheet/AttachSheet.tsx +331 -97
- package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +598 -279
- package/src/components/Modals/ChatProfileModal/ReportChatModal.tsx +244 -0
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +4 -2
- package/src/components/Modals/Modal/Modal.tsx +7 -0
- package/src/components/Modals/NewChatModal/ModalContent.tsx +6 -3
- package/src/components/Modals/NewChatModal/NewChatModal.tsx +219 -117
- package/src/components/Modals/NewChatModal/UpdNewChatModal.tsx +12 -1
- package/src/components/Modals/ProfileHeader/ProfileHeader.tsx +615 -0
- package/src/components/Modals/ProfileHeader/ProfileMenu.tsx +217 -0
- package/src/components/Modals/SelectUsersModal/SelectUsersModal.tsx +14 -4
- package/src/components/Modals/UserProfileModal/EditUserModal.tsx +9 -25
- package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +617 -307
- package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +75 -58
- package/src/components/Modals/styledModalComponents.tsx +9 -2
- package/src/components/RoomComponents/ChatRoomItem.tsx +14 -7
- package/src/components/styled/SendInput.tsx +83 -12
- package/src/components/styled/StyledComponents.ts +9 -3
- package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +11 -4
- package/src/context/xmppProvider.tsx +36 -47
- package/src/helpers/getChatBackground.ts +18 -0
- package/src/helpers/mediaLibraryRuntime.ts +25 -0
- package/src/helpers/pickImageAsset.ts +68 -0
- package/src/helpers/pushPayload.ts +62 -0
- package/src/helpers/sheetGestures.ts +25 -0
- package/src/helpers/updateMessagesTillLast.tsx +17 -42
- package/src/hooks/useChatRoomFocus.ts +3 -11
- package/src/hooks/useLogout.tsx +0 -7
- package/src/hooks/usePendingNotification.ts +5 -11
- package/src/hooks/useSendMessage.tsx +24 -60
- package/src/i18n/strings.ts +121 -1
- package/src/main.ts +4 -1
- package/src/networking/api-requests/user.api.ts +71 -0
- package/src/networking/authRefresh.ts +25 -4
- package/src/networking/outboundQueue.ts +0 -29
- package/src/networking/stanzaHandlers.ts +1 -9
- package/src/networking/xmpp/presenceInRoom.xmpp.ts +6 -1
- package/src/networking/xmpp/subscribeToRoomMessages.xmpp.ts +12 -1
- package/src/networking/xmppClient.ts +65 -119
- package/src/roomStore/chatSettingsSlice.ts +3 -1
- package/src/roomStore/roomsSlice.ts +2 -20
- package/src/services/pushSubscriptionService.ts +18 -13
- package/src/types/models/room.model.ts +0 -15
- package/src/types/types.ts +33 -20
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
/** @format */
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
Viewider,
|
|
6
|
-
Label,
|
|
7
|
-
LabelData,
|
|
8
|
-
BorderedContainer,
|
|
9
|
-
CenterContainer,
|
|
10
|
-
} from '../styledModalComponents';
|
|
11
|
-
import ModalHeaderComponent from '../ModalHeaderComponent';
|
|
12
|
-
import Button from '../../styled/Button';
|
|
3
|
+
import React, { useCallback, useMemo } from 'react';
|
|
4
|
+
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
|
13
5
|
import { useDispatch } from 'react-redux';
|
|
6
|
+
import { ModalContainerFullScreen } from '../styledModalComponents';
|
|
7
|
+
import ModalHeaderComponent from '../ModalHeaderComponent';
|
|
8
|
+
import { ArowDownIcon } from '../../../assets/icons';
|
|
14
9
|
import { setActiveModal } from '../../../roomStore/chatSettingsSlice';
|
|
15
10
|
import { MODAL_TYPES } from '../../../helpers/constants/MODAL_TYPES';
|
|
11
|
+
import { useChatSettingState } from '../../../hooks/useChatSettingState';
|
|
12
|
+
import { chatTextStyle } from '../../../helpers/typography';
|
|
13
|
+
import { useT } from '../../../i18n/useT';
|
|
16
14
|
|
|
17
15
|
interface UserSettingsModalProps {
|
|
18
16
|
handleCloseModal: any;
|
|
@@ -21,65 +19,84 @@ interface UserSettingsModalProps {
|
|
|
21
19
|
const UserSettingsModal: React.FC<UserSettingsModalProps> = ({
|
|
22
20
|
handleCloseModal,
|
|
23
21
|
}) => {
|
|
22
|
+
const t = useT();
|
|
23
|
+
const dispatch = useDispatch();
|
|
24
|
+
const { config } = useChatSettingState();
|
|
25
|
+
|
|
24
26
|
const options = useMemo(
|
|
25
27
|
() => [
|
|
26
|
-
{
|
|
27
|
-
{
|
|
28
|
-
// { value: 'Profile Shares', key: MODAL_TYPES.PROFILE_SHARES },
|
|
29
|
-
// { value: 'Document Shares', key: MODAL_TYPES.DOCUMENT_SHARES },
|
|
30
|
-
// { value: 'Blocked Users', key: MODAL_TYPES.BLOCKED_USERS },
|
|
31
|
-
// { value: 'Referrals', key: MODAL_TYPES.REFERRALS },
|
|
28
|
+
{ label: t('settings.manageData.title'), key: MODAL_TYPES.MANAGE_DATA },
|
|
29
|
+
{ label: t('settings.visibility.title'), key: MODAL_TYPES.VISIBILITY },
|
|
32
30
|
],
|
|
33
|
-
[]
|
|
31
|
+
[t]
|
|
34
32
|
);
|
|
35
33
|
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
const handleClick = useCallback(
|
|
35
|
+
(key: string) => {
|
|
36
|
+
dispatch(setActiveModal(key as any));
|
|
37
|
+
},
|
|
38
|
+
[dispatch]
|
|
39
|
+
);
|
|
41
40
|
|
|
42
41
|
return (
|
|
43
|
-
<ModalContainerFullScreen>
|
|
42
|
+
<ModalContainerFullScreen style={styles.screen}>
|
|
44
43
|
<ModalHeaderComponent
|
|
45
44
|
handleCloseModal={handleCloseModal}
|
|
46
|
-
headerTitle={'
|
|
45
|
+
headerTitle={t('settings.menu.title')}
|
|
46
|
+
titleStyle={chatTextStyle(config?.typography?.profile?.screenTitle)}
|
|
47
47
|
/>
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
gap: 2,
|
|
66
|
-
width: '100%',
|
|
67
|
-
justifyContent: 'center',
|
|
68
|
-
borderRadius: 0,
|
|
69
|
-
alignItems: 'flex-start',
|
|
70
|
-
}}
|
|
71
|
-
onPress={() => handleClick(option.key)}
|
|
72
|
-
>
|
|
73
|
-
<Label style={{ textAlign: 'center' }}>{option.value}</Label>
|
|
74
|
-
{[2, 3, 4].includes(index) && <LabelData>0</LabelData>}
|
|
75
|
-
</Button>
|
|
76
|
-
{index < 5 && <Viewider />}
|
|
77
|
-
</>
|
|
78
|
-
))}
|
|
79
|
-
</BorderedContainer>
|
|
80
|
-
</CenterContainer>
|
|
48
|
+
{/* One card per entry, rather than a single bordered block with
|
|
49
|
+
* hairline dividers — the rows are separate destinations, and the
|
|
50
|
+
* design gives each its own surface. */}
|
|
51
|
+
<View style={styles.body}>
|
|
52
|
+
{options.map((option) => (
|
|
53
|
+
<TouchableOpacity
|
|
54
|
+
key={option.key}
|
|
55
|
+
testID={`settings-row-${option.key}`}
|
|
56
|
+
activeOpacity={0.7}
|
|
57
|
+
style={styles.card}
|
|
58
|
+
onPress={() => handleClick(option.key)}
|
|
59
|
+
>
|
|
60
|
+
<Text style={styles.label}>{option.label}</Text>
|
|
61
|
+
<ArowDownIcon color="#8C8C8C" width={20} height={20} style={styles.chevron} />
|
|
62
|
+
</TouchableOpacity>
|
|
63
|
+
))}
|
|
64
|
+
</View>
|
|
81
65
|
</ModalContainerFullScreen>
|
|
82
66
|
);
|
|
83
67
|
};
|
|
84
68
|
|
|
69
|
+
const styles = StyleSheet.create({
|
|
70
|
+
screen: {
|
|
71
|
+
backgroundColor: '#E8EDF2',
|
|
72
|
+
},
|
|
73
|
+
body: {
|
|
74
|
+
width: '100%',
|
|
75
|
+
padding: 12,
|
|
76
|
+
gap: 12,
|
|
77
|
+
},
|
|
78
|
+
card: {
|
|
79
|
+
flexDirection: 'row',
|
|
80
|
+
alignItems: 'center',
|
|
81
|
+
justifyContent: 'space-between',
|
|
82
|
+
backgroundColor: '#FFFFFF',
|
|
83
|
+
borderRadius: 20,
|
|
84
|
+
paddingHorizontal: 20,
|
|
85
|
+
paddingVertical: 22,
|
|
86
|
+
shadowColor: '#101828',
|
|
87
|
+
shadowOffset: { width: 0, height: 4 },
|
|
88
|
+
shadowOpacity: 0.06,
|
|
89
|
+
shadowRadius: 12,
|
|
90
|
+
elevation: 3,
|
|
91
|
+
},
|
|
92
|
+
label: {
|
|
93
|
+
fontSize: 17,
|
|
94
|
+
fontWeight: '500',
|
|
95
|
+
color: '#141414',
|
|
96
|
+
},
|
|
97
|
+
chevron: {
|
|
98
|
+
transform: [{ rotate: '-90deg' }],
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
85
102
|
export default UserSettingsModal;
|
|
@@ -86,8 +86,15 @@ export const HeaderContainer = styled.View`
|
|
|
86
86
|
* button and 8px below — properly sized and properly centered. */
|
|
87
87
|
padding: 8px 16px;
|
|
88
88
|
background-color: #fff;
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
/* Same card treatment as the room-list header: rounded bottom corners
|
|
90
|
+
* and a soft drop shadow instead of a hairline rule. */
|
|
91
|
+
border-bottom-left-radius: 20px;
|
|
92
|
+
border-bottom-right-radius: 20px;
|
|
93
|
+
shadow-color: #101828;
|
|
94
|
+
shadow-offset: 0px 4px;
|
|
95
|
+
shadow-opacity: 0.06;
|
|
96
|
+
shadow-radius: 12px;
|
|
97
|
+
elevation: 4;
|
|
91
98
|
z-index: 1;
|
|
92
99
|
flex-direction: row;
|
|
93
100
|
justify-content: space-between;
|
|
@@ -90,11 +90,13 @@ const ChatRoomItem: React.FC<ChatRoomItemProps> = ({
|
|
|
90
90
|
|
|
91
91
|
return (
|
|
92
92
|
<ChatItem key={index}>
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
<View pointerEvents="none">
|
|
94
|
+
<ProfileImagePlaceholder
|
|
95
|
+
name={displayName}
|
|
96
|
+
icon={appendFileToken(chat?.icon, fileToken)}
|
|
97
|
+
active={false}
|
|
98
|
+
/>
|
|
99
|
+
</View>
|
|
98
100
|
<View
|
|
99
101
|
style={{
|
|
100
102
|
flexDirection: 'column',
|
|
@@ -104,7 +106,9 @@ const ChatRoomItem: React.FC<ChatRoomItemProps> = ({
|
|
|
104
106
|
paddingVertical: 8,
|
|
105
107
|
paddingRight: 8,
|
|
106
108
|
borderBottomWidth: 1,
|
|
107
|
-
|
|
109
|
+
// Reads against the list's #E8EDF2 ground; #F0F0F0 was lighter
|
|
110
|
+
// than the ground itself, so the row separators vanished.
|
|
111
|
+
borderBottomColor: '#C6CFDA',
|
|
108
112
|
}}
|
|
109
113
|
>
|
|
110
114
|
<View
|
|
@@ -215,8 +219,11 @@ const ChatRoomItem: React.FC<ChatRoomItemProps> = ({
|
|
|
215
219
|
) : null}
|
|
216
220
|
</View>
|
|
217
221
|
{isDriver && (
|
|
222
|
+
// Darker than the list's own ground (#E8EDF2), otherwise the
|
|
223
|
+
// separator disappears into it — white and the old #0052CD0D
|
|
224
|
+
// hairline both did.
|
|
218
225
|
<View
|
|
219
|
-
style={{ height: 1, backgroundColor: '#
|
|
226
|
+
style={{ height: 1, backgroundColor: '#C6CFDA', marginTop: 8 }}
|
|
220
227
|
/>
|
|
221
228
|
)}
|
|
222
229
|
</View>
|
|
@@ -10,14 +10,16 @@ import { IConfig, MediaFile } from '../../types/types';
|
|
|
10
10
|
import Button from './Button';
|
|
11
11
|
import { SendIcon, AttachIcon, RecordIcon } from '../../assets/icons';
|
|
12
12
|
import { KeyboardAvoidingView, Platform, View, Text, TouchableOpacity, Alert, Linking } from 'react-native';
|
|
13
|
-
import AttachSheet from '../Modals/AttachSheet/AttachSheet';
|
|
13
|
+
import AttachSheet, { PickedMedia } from '../Modals/AttachSheet/AttachSheet';
|
|
14
14
|
import { MediaFilePreview } from './MediaFilePreview';
|
|
15
15
|
import { getIconColor } from '../../helpers/getIconColor';
|
|
16
16
|
import { getElementFont } from '../../helpers/getElementFont';
|
|
17
17
|
import { useT } from '../../i18n/useT';
|
|
18
|
+
import { getMediaLibrary } from '../../helpers/mediaLibraryRuntime';
|
|
18
19
|
import * as ImagePicker from 'expo-image-picker';
|
|
19
20
|
import * as DocumentPicker from 'expo-document-picker';
|
|
20
21
|
import * as ImageManipulator from 'expo-image-manipulator';
|
|
22
|
+
import * as FileSystem from 'expo-file-system/legacy';
|
|
21
23
|
// expo-audio replaces the discontinued expo-av: `useAudioRecorder` owns a
|
|
22
24
|
// single reusable recorder for this input's lifetime (prepare → record →
|
|
23
25
|
// stop → prepare again), and the module-level helpers cover permissions
|
|
@@ -259,22 +261,59 @@ const SendInput: React.FC<SendInputProps> = ({
|
|
|
259
261
|
}
|
|
260
262
|
};
|
|
261
263
|
|
|
264
|
+
// A tap on a thumbnail in the attach sheet's recents strip. The sheet
|
|
265
|
+
// already resolved the asset to a real on-disk uri (iOS `ph://` ids are
|
|
266
|
+
// not uploadable); here we apply the same treatment the full-blown
|
|
267
|
+
// pickers get — HEIC→JPEG for images, and a size probe so the 50 MB cap
|
|
268
|
+
// is enforced before anything hits the network.
|
|
269
|
+
const handleRecentMediaSelection = async (media: PickedMedia) => {
|
|
270
|
+
try {
|
|
271
|
+
let size: number | undefined;
|
|
272
|
+
try {
|
|
273
|
+
const info = await FileSystem.getInfoAsync(media.uri);
|
|
274
|
+
if (info.exists && typeof (info as any).size === 'number') {
|
|
275
|
+
size = (info as any).size;
|
|
276
|
+
}
|
|
277
|
+
} catch {
|
|
278
|
+
// Size is a nice-to-have; the backend still rejects oversized bodies.
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (media.isVideo) {
|
|
282
|
+
handleFileSelect([
|
|
283
|
+
{
|
|
284
|
+
uri: media.uri,
|
|
285
|
+
type: media.mimeType || 'video/mp4',
|
|
286
|
+
name: media.name,
|
|
287
|
+
size,
|
|
288
|
+
},
|
|
289
|
+
]);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const normalized = await normalizeImageAsset({
|
|
294
|
+
uri: media.uri,
|
|
295
|
+
mimeType: media.mimeType,
|
|
296
|
+
fileName: media.name,
|
|
297
|
+
} as ImagePicker.ImagePickerAsset);
|
|
298
|
+
handleFileSelect([
|
|
299
|
+
{
|
|
300
|
+
uri: normalized.uri,
|
|
301
|
+
type: normalized.mime,
|
|
302
|
+
name: normalized.name,
|
|
303
|
+
size,
|
|
304
|
+
},
|
|
305
|
+
]);
|
|
306
|
+
} catch (error) {
|
|
307
|
+
console.error('Recent media error:', error);
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
262
311
|
const handleFileSelection = async () => {
|
|
263
312
|
// Drop overlapping invocations — a second getDocumentAsync while the
|
|
264
313
|
// first is still presented throws PickingInProgressException on iOS.
|
|
265
314
|
if (pickingDocRef.current) {return;}
|
|
266
315
|
pickingDocRef.current = true;
|
|
267
316
|
try {
|
|
268
|
-
// Let the attach-sheet's modal finish its NATIVE dismissal before we
|
|
269
|
-
// present the picker. The sheet fires this handler right after its
|
|
270
|
-
// slide-out animation, but the underlying RN Modal view-controller
|
|
271
|
-
// dismissal is async — presenting the document picker over a still-
|
|
272
|
-
// dismissing modal makes iOS tear it down without a cancel callback,
|
|
273
|
-
// which strands expo-document-picker's pickingContext and makes every
|
|
274
|
-
// subsequent open throw "Different document picking in progress".
|
|
275
|
-
if (Platform.OS === 'ios') {
|
|
276
|
-
await new Promise((resolve) => setTimeout(resolve, 350));
|
|
277
|
-
}
|
|
278
317
|
const result = await DocumentPicker.getDocumentAsync({
|
|
279
318
|
type: '*/*',
|
|
280
319
|
multiple: false,
|
|
@@ -297,8 +336,39 @@ const SendInput: React.FC<SendInputProps> = ({
|
|
|
297
336
|
}
|
|
298
337
|
};
|
|
299
338
|
|
|
339
|
+
// Photo-library access is requested HERE, not inside the sheet: iOS
|
|
340
|
+
// cannot present the permission alert while an RN <Modal> owns the
|
|
341
|
+
// screen (the same UIKit limitation that used to swallow the pickers),
|
|
342
|
+
// so asking from inside resolved to a silent "denied" and the recents
|
|
343
|
+
// strip stayed empty forever. Asking on the paperclip tap puts the
|
|
344
|
+
// system alert over the plain chat screen, where it can actually show.
|
|
345
|
+
// Only the first tap ever waits on it — afterwards the status is
|
|
346
|
+
// already determined and `getPermissionsAsync` returns immediately.
|
|
347
|
+
const ensureLibraryPermission = async () => {
|
|
348
|
+
const MediaLibrary = getMediaLibrary();
|
|
349
|
+
if (!MediaLibrary?.getPermissionsAsync) {return;}
|
|
350
|
+
try {
|
|
351
|
+
const perm = await MediaLibrary.getPermissionsAsync();
|
|
352
|
+
if (perm?.granted || perm?.canAskAgain === false) {return;}
|
|
353
|
+
await MediaLibrary.requestPermissionsAsync();
|
|
354
|
+
} catch (err) {
|
|
355
|
+
// Optional peer / unsupported platform: the sheet just shows the
|
|
356
|
+
// camera tile and the full-library route.
|
|
357
|
+
console.warn('Media library permission check failed:', err);
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
// Only the very first tap of a session goes through the permission
|
|
362
|
+
// check; afterwards the sheet opens with zero added latency.
|
|
363
|
+
const libraryPermissionCheckedRef = useRef(false);
|
|
364
|
+
|
|
300
365
|
const handleAttachPress = () => {
|
|
301
|
-
|
|
366
|
+
if (libraryPermissionCheckedRef.current) {
|
|
367
|
+
setShowMediaMenu(true);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
libraryPermissionCheckedRef.current = true;
|
|
371
|
+
ensureLibraryPermission().finally(() => setShowMediaMenu(true));
|
|
302
372
|
};
|
|
303
373
|
|
|
304
374
|
// ─── Voice recording ──────────────────────────────────────────────
|
|
@@ -702,6 +772,7 @@ const SendInput: React.FC<SendInputProps> = ({
|
|
|
702
772
|
onCamera={handleCameraSelection}
|
|
703
773
|
onGallery={handleGallerySelection}
|
|
704
774
|
onDocument={handleFileSelection}
|
|
775
|
+
onPickMedia={handleRecentMediaSelection}
|
|
705
776
|
primaryColor={getIconColor(config)}
|
|
706
777
|
/>
|
|
707
778
|
</InputContainer>
|
|
@@ -28,9 +28,15 @@ export const ChatContainerHeader = styled.View`
|
|
|
28
28
|
background-color: #ffffff;
|
|
29
29
|
align-items: center;
|
|
30
30
|
justify-content: space-between;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
border-
|
|
31
|
+
/* Rounded bottom corners + a soft drop shadow instead of the hairline
|
|
32
|
+
* rule, so the header reads as a card over the conversation. */
|
|
33
|
+
border-bottom-left-radius: 20px;
|
|
34
|
+
border-bottom-right-radius: 20px;
|
|
35
|
+
shadow-color: #101828;
|
|
36
|
+
shadow-offset: 0px 4px;
|
|
37
|
+
shadow-opacity: 0.06;
|
|
38
|
+
shadow-radius: 12px;
|
|
39
|
+
elevation: 4;
|
|
34
40
|
z-index: 1000;
|
|
35
41
|
`;
|
|
36
42
|
|
|
@@ -13,14 +13,21 @@ const colors = {
|
|
|
13
13
|
|
|
14
14
|
export const InputContainer = styled.View<{ isText?: boolean }>`
|
|
15
15
|
flex-direction: column;
|
|
16
|
-
padding:
|
|
17
|
-
|
|
16
|
+
padding: 12px 16px 8px 16px;
|
|
17
|
+
/* Transparent, so the dock's white surface — and its rounded top
|
|
18
|
+
* corners — are what shows. An opaque child painted straight over those
|
|
19
|
+
* corners (a parent's border radius does not clip children without
|
|
20
|
+
* overflow:hidden, and that would clip the dock's shadow too). */
|
|
21
|
+
background-color: transparent;
|
|
18
22
|
z-index: 100;
|
|
19
23
|
width: 100%;
|
|
20
24
|
bottom: 0;
|
|
21
25
|
left: 0;
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
/* No radius or shadow here: the dock this sits in (ChatRoom's
|
|
27
|
+
* InputDockTag) is the composer's outer surface and carries both. Having
|
|
28
|
+
* them on this inner view too drew its shadow onto the dock's white
|
|
29
|
+
* background — the faint seam that made the strip below look like a
|
|
30
|
+
* different colour. */
|
|
24
31
|
`;
|
|
25
32
|
|
|
26
33
|
export const MediaContainer = styled.View`
|
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
import { ensureScopedChatCache } from '../helpers/ensureScopedChatCache';
|
|
38
38
|
import { getRooms as prefetchRoomsViaRest } from '../networking/api-requests/rooms.api';
|
|
39
39
|
import { allRoomPresences } from '../networking/xmpp/allRoomPresences.xmpp';
|
|
40
|
+
import { pushSubscriptionService } from '../services/pushSubscriptionService';
|
|
40
41
|
import { store } from '../roomStore';
|
|
41
42
|
import { logout, setStoreClient, setConfig } from '../roomStore/chatSettingsSlice';
|
|
42
43
|
import {
|
|
@@ -83,6 +84,16 @@ interface XmppProviderProps {
|
|
|
83
84
|
|
|
84
85
|
const LOGOUT_EVENT = 'ethora-xmpp-logout';
|
|
85
86
|
|
|
87
|
+
const subscribeAllRoomsForPush = (client: any, reason: string) => {
|
|
88
|
+
const rooms = Object.keys(store.getState().rooms.rooms || {});
|
|
89
|
+
if (!client || !rooms.length) {return;}
|
|
90
|
+
const nick = client.jid?.getLocal();
|
|
91
|
+
pushSubscriptionService
|
|
92
|
+
.subscribeToRooms(client, rooms, nick)
|
|
93
|
+
.then(() => devPushLog('xmpp', `${reason}: mucsub ok for ${rooms.length} rooms`))
|
|
94
|
+
.catch((e) => devPushLog('warn', `${reason}: mucsub subscribe failed`, e));
|
|
95
|
+
};
|
|
96
|
+
|
|
86
97
|
export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, isVisible }) => {
|
|
87
98
|
const [client, setClient] = useState<XmppClient | null>(null);
|
|
88
99
|
const [providerBootstrapStatus, setProviderBootstrapStatus] =
|
|
@@ -115,7 +126,7 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
115
126
|
// the shared rotation point covers both the consumer-supplied
|
|
116
127
|
// function and the built-in endpoint.
|
|
117
128
|
if (config?.refreshTokens?.enabled) {
|
|
118
|
-
const rotated = await refreshAuthTokensQuietly();
|
|
129
|
+
const rotated = await refreshAuthTokensQuietly({ force: true });
|
|
119
130
|
|
|
120
131
|
if (rotated?.xmppPassword) {
|
|
121
132
|
const rotatedUser = store.getState().chatSettingStore.user;
|
|
@@ -229,9 +240,11 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
229
240
|
created.setOnOnline(() => {
|
|
230
241
|
const underlying = (created as any).client;
|
|
231
242
|
if (!underlying) {return;}
|
|
232
|
-
allRoomPresences(underlying)
|
|
233
|
-
|
|
234
|
-
|
|
243
|
+
allRoomPresences(underlying)
|
|
244
|
+
.catch((e) =>
|
|
245
|
+
devPushLog('warn', 'reconnect: allRoomPresences re-join failed', e)
|
|
246
|
+
)
|
|
247
|
+
.finally(() => subscribeAllRoomsForPush(underlying, 'reconnect'));
|
|
235
248
|
// Also refresh the private store so unread / lastViewed markers
|
|
236
249
|
// are accurate after a long reconnect — the MUC re-join above only
|
|
237
250
|
// restores delivery, not unread state. Idempotent on first connect.
|
|
@@ -384,7 +397,7 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
384
397
|
// jwtLogin is skipped: /users/client just minted fresh creds.
|
|
385
398
|
let connectPassword = resolved.xmppPassword;
|
|
386
399
|
if (config?.refreshTokens?.enabled && !config?.jwtLogin?.enabled) {
|
|
387
|
-
const rotated = await refreshAuthTokensQuietly();
|
|
400
|
+
const rotated = await refreshAuthTokensQuietly({ force: true });
|
|
388
401
|
if (cancelled) {return;}
|
|
389
402
|
if (rotated?.xmppPassword) {
|
|
390
403
|
connectPassword = rotated.xmppPassword;
|
|
@@ -436,6 +449,7 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
436
449
|
} catch (e) {
|
|
437
450
|
devPushLog('warn', 'initBeforeLoad: allRoomPresences failed', e);
|
|
438
451
|
}
|
|
452
|
+
subscribeAllRoomsForPush((c as any).client, 'initBeforeLoad');
|
|
439
453
|
|
|
440
454
|
store.dispatch(setStoreClient(c));
|
|
441
455
|
completedBootstrapKeyRef.current = key;
|
|
@@ -557,9 +571,7 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
557
571
|
devPushLog('rn', `watchdog: client ${client.status} → forceReconnect`);
|
|
558
572
|
client.forceReconnect();
|
|
559
573
|
} else {
|
|
560
|
-
|
|
561
|
-
// bypasses the throttle that keeps send-path probes rare.
|
|
562
|
-
client.ensureStreamAlive?.({ force: true, reason: 'watchdog' });
|
|
574
|
+
client.ensureStreamAlive?.();
|
|
563
575
|
}
|
|
564
576
|
}, 30000);
|
|
565
577
|
return () => clearInterval(id);
|
|
@@ -582,9 +594,14 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
582
594
|
// be re-marked visible on return. Lives in the effect closure (one per
|
|
583
595
|
// client) — persists across the listener's many invocations.
|
|
584
596
|
let visibleBeforeBackground: string | null = null;
|
|
597
|
+
const suspendInBackground = !config?.xmppSettings?.keepAliveInBackground;
|
|
585
598
|
const sub = AppState.addEventListener('change', (next) => {
|
|
586
599
|
const c = client;
|
|
587
600
|
if (next === 'active') {
|
|
601
|
+
if (c?.isSuspended) {
|
|
602
|
+
devPushLog('rn', 'AppState active: resuming suspended XMPP client');
|
|
603
|
+
c.resume();
|
|
604
|
+
}
|
|
588
605
|
// Returned to foreground. If the socket died while backgrounded
|
|
589
606
|
// (iOS suspends the WebSocket; long background kills it), the
|
|
590
607
|
// status may still read 'online' until xmpp.js notices the dead
|
|
@@ -612,6 +629,9 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
612
629
|
}
|
|
613
630
|
// Going to background/inactive (sleep / app switcher / tray):
|
|
614
631
|
if (!c) {return;}
|
|
632
|
+
if (next === 'background' && suspendInBackground) {
|
|
633
|
+
c.suspend().catch(() => undefined);
|
|
634
|
+
}
|
|
615
635
|
const state = store.getState();
|
|
616
636
|
const rooms = state.rooms?.rooms;
|
|
617
637
|
const visibleRoomJID = state.rooms?.visibleRoomJID || null;
|
|
@@ -624,19 +644,9 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
624
644
|
// the provider so consumers using the component as a package get
|
|
625
645
|
// correct unread without reaching into the chat store themselves.
|
|
626
646
|
visibleBeforeBackground = visibleRoomJID;
|
|
627
|
-
// Prefer the read boundary the user actually reached. Stamping
|
|
628
|
-
// `Date.now()` while they are scrolled up marks unseen messages as
|
|
629
|
-
// read, and because we flush to the server private store below the
|
|
630
|
-
// loss survives an app restart. Customer-reported #33.
|
|
631
|
-
const bgBoundaryTs = visibleRoomJID
|
|
632
|
-
? rooms?.[visibleRoomJID]?.readBoundaryTs ?? null
|
|
633
|
-
: null;
|
|
634
647
|
if (visibleRoomJID) {
|
|
635
648
|
store.dispatch(
|
|
636
|
-
setLastViewedTimestamp({
|
|
637
|
-
chatJID: visibleRoomJID,
|
|
638
|
-
timestamp: bgBoundaryTs ?? Date.now(),
|
|
639
|
-
})
|
|
649
|
+
setLastViewedTimestamp({ chatJID: visibleRoomJID, timestamp: Date.now() })
|
|
640
650
|
);
|
|
641
651
|
// Drop the "New messages" divider for the room we're leaving so it
|
|
642
652
|
// doesn't linger when the user comes back (mirrors ChatRoom's
|
|
@@ -648,13 +658,12 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
648
658
|
}
|
|
649
659
|
// Fire-and-forget — we're going to the background and don't
|
|
650
660
|
// care about the resolution path.
|
|
651
|
-
c.flushLastViewedToPrivateStoreStanza(rooms, {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
}).catch(() => {});
|
|
661
|
+
c.flushLastViewedToPrivateStoreStanza(rooms, { visibleRoomJID }).catch(
|
|
662
|
+
() => {}
|
|
663
|
+
);
|
|
655
664
|
});
|
|
656
665
|
return () => sub.remove();
|
|
657
|
-
}, [client]);
|
|
666
|
+
}, [client, config?.xmppSettings?.keepAliveInBackground]);
|
|
658
667
|
|
|
659
668
|
// -----------------------------------------------------------
|
|
660
669
|
// Consumer visibility signal (`isVisible` prop). For hosts that keep
|
|
@@ -682,16 +691,9 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
682
691
|
store.dispatch(setVisibleRoom({ roomJID: activeRoomJID }));
|
|
683
692
|
}
|
|
684
693
|
} else {
|
|
685
|
-
// Same read-boundary rule as the AppState path above (#33).
|
|
686
|
-
const hideBoundaryTs = activeRoomJID
|
|
687
|
-
? rooms?.[activeRoomJID]?.readBoundaryTs ?? null
|
|
688
|
-
: null;
|
|
689
694
|
if (wasVisible && activeRoomJID) {
|
|
690
695
|
store.dispatch(
|
|
691
|
-
setLastViewedTimestamp({
|
|
692
|
-
chatJID: activeRoomJID,
|
|
693
|
-
timestamp: hideBoundaryTs ?? Date.now(),
|
|
694
|
-
})
|
|
696
|
+
setLastViewedTimestamp({ chatJID: activeRoomJID, timestamp: Date.now() })
|
|
695
697
|
);
|
|
696
698
|
// Drop the "New messages" divider so it's gone when the user
|
|
697
699
|
// returns to the chat (mirrors ChatRoom's unmount cleanup).
|
|
@@ -703,10 +705,7 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
703
705
|
store.dispatch(clearVisibleRoom());
|
|
704
706
|
if (wasVisible && client?.flushLastViewedToPrivateStoreStanza) {
|
|
705
707
|
client
|
|
706
|
-
.flushLastViewedToPrivateStoreStanza(rooms, {
|
|
707
|
-
visibleRoomJID: activeRoomJID,
|
|
708
|
-
visibleRoomTs: hideBoundaryTs,
|
|
709
|
-
})
|
|
708
|
+
.flushLastViewedToPrivateStoreStanza(rooms, { visibleRoomJID: activeRoomJID })
|
|
710
709
|
.catch(() => {});
|
|
711
710
|
}
|
|
712
711
|
}
|
|
@@ -727,15 +726,6 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
727
726
|
if (room.messages === lastMessagesRef) {return;}
|
|
728
727
|
lastMessagesRef = room.messages;
|
|
729
728
|
|
|
730
|
-
// "Chat is on screen" does NOT mean "user is looking at the newest
|
|
731
|
-
// message". While they are scrolled up, MessageList publishes a read
|
|
732
|
-
// boundary; advancing the marker to `now` here would clear the very
|
|
733
|
-
// unread messages the scroll-up state exists to preserve — and the
|
|
734
|
-
// 2s flush below would push that loss to the server, making it
|
|
735
|
-
// survive an app restart. Leave the marker alone until they come
|
|
736
|
-
// back to the bottom (boundary back to null). Customer-reported #33.
|
|
737
|
-
if (room.readBoundaryTs != null) {return;}
|
|
738
|
-
|
|
739
729
|
let newest = 0;
|
|
740
730
|
const list = room.messages || [];
|
|
741
731
|
for (const m of list) {
|
|
@@ -794,8 +784,7 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
794
784
|
devPushLog('rn', `NetInfo: reachable & client ${client.status} → forceReconnect`);
|
|
795
785
|
client.forceReconnect();
|
|
796
786
|
} else if (client.status === 'online') {
|
|
797
|
-
|
|
798
|
-
client.ensureStreamAlive?.({ force: true, reason: 'netinfo' });
|
|
787
|
+
client.ensureStreamAlive?.();
|
|
799
788
|
}
|
|
800
789
|
});
|
|
801
790
|
return () => unsub();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** @format */
|
|
2
|
+
|
|
3
|
+
import type { IConfig } from '../types/types';
|
|
4
|
+
|
|
5
|
+
/** Ground behind the conversation, and behind the rounded corners of the
|
|
6
|
+
* header and the composer that sit over it. */
|
|
7
|
+
export const DEFAULT_CHAT_BACKGROUND = '#F3F6FC';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* One place for the conversation's background colour.
|
|
11
|
+
*
|
|
12
|
+
* The message list has always painted it; the chat container behind it was
|
|
13
|
+
* plain white, which is what made the header's rounded bottom corners and
|
|
14
|
+
* the composer's rounded top corners invisible — the corners revealed the
|
|
15
|
+
* white parent, not the conversation.
|
|
16
|
+
*/
|
|
17
|
+
export const getChatBackgroundColor = (config?: IConfig): string =>
|
|
18
|
+
config?.backgroundChat?.color || DEFAULT_CHAT_BACKGROUND;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
let cached: any | undefined;
|
|
2
|
+
|
|
3
|
+
export const getMediaLibrary = (): any | null => {
|
|
4
|
+
if (cached !== undefined) {return cached;}
|
|
5
|
+
try {
|
|
6
|
+
const legacy = require('expo-media-library/legacy');
|
|
7
|
+
|
|
8
|
+
if (legacy?.getAssetsAsync) {
|
|
9
|
+
cached = legacy;
|
|
10
|
+
return cached;
|
|
11
|
+
}
|
|
12
|
+
} catch {
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
cached = require('expo-media-library') ?? null;
|
|
17
|
+
} catch {
|
|
18
|
+
cached = null;
|
|
19
|
+
}
|
|
20
|
+
return cached;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const __resetMediaLibraryCache = () => {
|
|
24
|
+
cached = undefined;
|
|
25
|
+
};
|