@ethora/chat-component-rn 26.10.4 → 26.10.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/CHANGELOG.md +8 -0
- package/README.md +15 -0
- package/app.plugin.js +2 -0
- package/lib/commonjs/assets/icons.js +2 -2
- package/lib/commonjs/assets/icons.js.map +1 -1
- package/lib/commonjs/components/MainComponents/AlbumGrid.js +152 -0
- package/lib/commonjs/components/MainComponents/AlbumGrid.js.map +1 -0
- package/lib/commonjs/components/MainComponents/ChatRoom.js +2 -2
- package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MediaMessage.js +199 -123
- package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MediaUploadOverlay.js +109 -0
- package/lib/commonjs/components/MainComponents/MediaUploadOverlay.js.map +1 -0
- package/lib/commonjs/components/MessageBubble/MediaCaption.js +51 -0
- package/lib/commonjs/components/MessageBubble/MediaCaption.js.map +1 -0
- package/lib/commonjs/components/MessageBubble/Message.js +40 -1
- package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js +2 -1
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +75 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/LastMessageItem.js +20 -4
- package/lib/commonjs/components/RoomComponents/LastMessageItem.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastAudioMessage.js +3 -2
- package/lib/commonjs/components/RoomComponents/styled/LastAudioMessage.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js +3 -2
- package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js +3 -2
- package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js +3 -2
- package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
- package/lib/commonjs/components/Thread/ThreadWrapper.js +3 -2
- package/lib/commonjs/components/Thread/ThreadWrapper.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/ActiveCallBar.js +61 -16
- package/lib/commonjs/components/VideoCalls/ActiveCallBar.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/CallIcons.js +41 -16
- package/lib/commonjs/components/VideoCalls/CallIcons.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js +183 -9
- package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js +40 -15
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/callSessionController.js +49 -26
- package/lib/commonjs/components/VideoCalls/callSessionController.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/callUiStore.js +33 -4
- package/lib/commonjs/components/VideoCalls/callUiStore.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/livekitRuntime.js +9 -1
- package/lib/commonjs/components/VideoCalls/livekitRuntime.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/useCallKeep.js +197 -28
- package/lib/commonjs/components/VideoCalls/useCallKeep.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/useOngoingCallNotification.js +88 -0
- package/lib/commonjs/components/VideoCalls/useOngoingCallNotification.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/usePipTile.js +232 -0
- package/lib/commonjs/components/VideoCalls/usePipTile.js.map +1 -0
- package/lib/commonjs/components/styled/MediaFilePreview.js +60 -47
- package/lib/commonjs/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/commonjs/components/styled/MessageImage.js +16 -6
- package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
- package/lib/commonjs/components/styled/SendInput.js +99 -68
- package/lib/commonjs/components/styled/SendInput.js.map +1 -1
- package/lib/commonjs/components/styled/VideoMessage.js +24 -10
- package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
- package/lib/commonjs/context/xmppProvider.js +46 -0
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/e2ee/fileEnvelope.js +6 -0
- package/lib/commonjs/e2ee/fileEnvelope.js.map +1 -1
- package/lib/commonjs/e2ee/sealedBody.js +32 -2
- package/lib/commonjs/e2ee/sealedBody.js.map +1 -1
- package/lib/commonjs/helpers/albumLayout.js +150 -0
- package/lib/commonjs/helpers/albumLayout.js.map +1 -0
- package/lib/commonjs/helpers/attachments.js +255 -0
- package/lib/commonjs/helpers/attachments.js.map +1 -0
- package/lib/commonjs/helpers/caption.js +214 -0
- package/lib/commonjs/helpers/caption.js.map +1 -0
- package/lib/commonjs/helpers/createMainMessageForThread.js +5 -1
- package/lib/commonjs/helpers/createMainMessageForThread.js.map +1 -1
- package/lib/commonjs/helpers/createMessageFromXml.js +19 -5
- package/lib/commonjs/helpers/createMessageFromXml.js.map +1 -1
- package/lib/commonjs/helpers/fileKind.js +40 -0
- package/lib/commonjs/helpers/fileKind.js.map +1 -0
- package/lib/commonjs/helpers/getDataFromXml.js +6 -1
- package/lib/commonjs/helpers/getDataFromXml.js.map +1 -1
- package/lib/commonjs/helpers/mapWithConcurrency.js +41 -0
- package/lib/commonjs/helpers/mapWithConcurrency.js.map +1 -0
- package/lib/commonjs/helpers/mediaLimits.js +33 -0
- package/lib/commonjs/helpers/mediaLimits.js.map +1 -0
- package/lib/commonjs/helpers/mediaSendRetry.js +64 -0
- package/lib/commonjs/helpers/mediaSendRetry.js.map +1 -0
- package/lib/commonjs/helpers/mediaWireData.js +62 -0
- package/lib/commonjs/helpers/mediaWireData.js.map +1 -0
- package/lib/commonjs/helpers/mentionSpans.js +19 -0
- package/lib/commonjs/helpers/mentionSpans.js.map +1 -0
- package/lib/commonjs/helpers/mimeToExtension.js +45 -0
- package/lib/commonjs/helpers/mimeToExtension.js.map +1 -1
- package/lib/commonjs/helpers/readReceipts.js +173 -0
- package/lib/commonjs/helpers/readReceipts.js.map +1 -0
- package/lib/commonjs/helpers/repairFilenameEncoding.js +79 -0
- package/lib/commonjs/helpers/repairFilenameEncoding.js.map +1 -0
- package/lib/commonjs/helpers/safeJson.js +18 -0
- package/lib/commonjs/helpers/safeJson.js.map +1 -0
- package/lib/commonjs/helpers/updateMessagesTillLast.js +3 -1
- package/lib/commonjs/helpers/updateMessagesTillLast.js.map +1 -1
- package/lib/commonjs/hooks/useSendMessage.js +384 -193
- package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
- package/lib/commonjs/i18n/strings.js +144 -0
- package/lib/commonjs/i18n/strings.js.map +1 -1
- package/lib/commonjs/main.js.map +1 -1
- package/lib/commonjs/networking/api-requests/auth.api.js +62 -3
- package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
- package/lib/commonjs/networking/stanzaHandlers.js +100 -3
- package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
- package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +4 -2
- package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/sendDisplayedMarker.xmpp.js +28 -0
- package/lib/commonjs/networking/xmpp/sendDisplayedMarker.xmpp.js.map +1 -0
- package/lib/commonjs/networking/xmpp/sendMediaMessage.xmpp.js +53 -2
- package/lib/commonjs/networking/xmpp/sendMediaMessage.xmpp.js.map +1 -1
- package/lib/commonjs/networking/xmpp/sendReceivedReceipt.xmpp.js +28 -0
- package/lib/commonjs/networking/xmpp/sendReceivedReceipt.xmpp.js.map +1 -0
- package/lib/commonjs/networking/xmppClient.js +64 -0
- package/lib/commonjs/networking/xmppClient.js.map +1 -1
- package/lib/commonjs/roomStore/persistence.js +78 -5
- package/lib/commonjs/roomStore/persistence.js.map +1 -1
- package/lib/commonjs/roomStore/roomHeapSlice.js +4 -0
- package/lib/commonjs/roomStore/roomHeapSlice.js.map +1 -1
- package/lib/commonjs/roomStore/roomsSlice.js +114 -1
- package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
- package/lib/commonjs/types/models/attachment.model.js +2 -0
- package/lib/commonjs/types/models/attachment.model.js.map +1 -0
- package/lib/commonjs/version.js +1 -1
- package/lib/module/assets/icons.js +1 -1
- package/lib/module/assets/icons.js.map +1 -1
- package/lib/module/components/MainComponents/AlbumGrid.js +146 -0
- package/lib/module/components/MainComponents/AlbumGrid.js.map +1 -0
- package/lib/module/components/MainComponents/ChatRoom.js +2 -2
- package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/module/components/MainComponents/MediaMessage.js +200 -124
- package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/module/components/MainComponents/MediaUploadOverlay.js +104 -0
- package/lib/module/components/MainComponents/MediaUploadOverlay.js.map +1 -0
- package/lib/module/components/MessageBubble/MediaCaption.js +46 -0
- package/lib/module/components/MessageBubble/MediaCaption.js.map +1 -0
- package/lib/module/components/MessageBubble/Message.js +44 -5
- package/lib/module/components/MessageBubble/Message.js.map +1 -1
- package/lib/module/components/MessageBubble/MessageInteractions.js +2 -1
- package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +75 -0
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/module/components/RoomComponents/LastMessageItem.js +20 -4
- package/lib/module/components/RoomComponents/LastMessageItem.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastAudioMessage.js +3 -2
- package/lib/module/components/RoomComponents/styled/LastAudioMessage.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessageFile.js +3 -2
- package/lib/module/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js +3 -2
- package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastMessageVideo.js +3 -2
- package/lib/module/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
- package/lib/module/components/Thread/ThreadWrapper.js +3 -2
- package/lib/module/components/Thread/ThreadWrapper.js.map +1 -1
- package/lib/module/components/VideoCalls/ActiveCallBar.js +63 -18
- package/lib/module/components/VideoCalls/ActiveCallBar.js.map +1 -1
- package/lib/module/components/VideoCalls/CallIcons.js +38 -15
- package/lib/module/components/VideoCalls/CallIcons.js.map +1 -1
- package/lib/module/components/VideoCalls/VideoCallOverlay.js +185 -11
- package/lib/module/components/VideoCalls/VideoCallOverlay.js.map +1 -1
- package/lib/module/components/VideoCalls/VideoCallSession.js +41 -16
- package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -1
- package/lib/module/components/VideoCalls/callSessionController.js +46 -24
- package/lib/module/components/VideoCalls/callSessionController.js.map +1 -1
- package/lib/module/components/VideoCalls/callUiStore.js +30 -3
- package/lib/module/components/VideoCalls/callUiStore.js.map +1 -1
- package/lib/module/components/VideoCalls/livekitRuntime.js +9 -1
- package/lib/module/components/VideoCalls/livekitRuntime.js.map +1 -1
- package/lib/module/components/VideoCalls/useCallKeep.js +198 -29
- package/lib/module/components/VideoCalls/useCallKeep.js.map +1 -1
- package/lib/module/components/VideoCalls/useOngoingCallNotification.js +84 -0
- package/lib/module/components/VideoCalls/useOngoingCallNotification.js.map +1 -0
- package/lib/module/components/VideoCalls/usePipTile.js +228 -0
- package/lib/module/components/VideoCalls/usePipTile.js.map +1 -0
- package/lib/module/components/styled/MediaFilePreview.js +61 -48
- package/lib/module/components/styled/MediaFilePreview.js.map +1 -1
- package/lib/module/components/styled/MessageImage.js +16 -6
- package/lib/module/components/styled/MessageImage.js.map +1 -1
- package/lib/module/components/styled/SendInput.js +99 -68
- package/lib/module/components/styled/SendInput.js.map +1 -1
- package/lib/module/components/styled/VideoMessage.js +24 -10
- package/lib/module/components/styled/VideoMessage.js.map +1 -1
- package/lib/module/context/xmppProvider.js +46 -0
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/e2ee/fileEnvelope.js +1 -1
- package/lib/module/e2ee/fileEnvelope.js.map +1 -1
- package/lib/module/e2ee/sealedBody.js +32 -2
- package/lib/module/e2ee/sealedBody.js.map +1 -1
- package/lib/module/helpers/albumLayout.js +143 -0
- package/lib/module/helpers/albumLayout.js.map +1 -0
- package/lib/module/helpers/attachments.js +245 -0
- package/lib/module/helpers/attachments.js.map +1 -0
- package/lib/module/helpers/caption.js +207 -0
- package/lib/module/helpers/caption.js.map +1 -0
- package/lib/module/helpers/createMainMessageForThread.js +5 -1
- package/lib/module/helpers/createMainMessageForThread.js.map +1 -1
- package/lib/module/helpers/createMessageFromXml.js +20 -6
- package/lib/module/helpers/createMessageFromXml.js.map +1 -1
- package/lib/module/helpers/fileKind.js +34 -0
- package/lib/module/helpers/fileKind.js.map +1 -0
- package/lib/module/helpers/getDataFromXml.js +6 -1
- package/lib/module/helpers/getDataFromXml.js.map +1 -1
- package/lib/module/helpers/mapWithConcurrency.js +37 -0
- package/lib/module/helpers/mapWithConcurrency.js.map +1 -0
- package/lib/module/helpers/mediaLimits.js +27 -0
- package/lib/module/helpers/mediaLimits.js.map +1 -0
- package/lib/module/helpers/mediaSendRetry.js +55 -0
- package/lib/module/helpers/mediaSendRetry.js.map +1 -0
- package/lib/module/helpers/mediaWireData.js +58 -0
- package/lib/module/helpers/mediaWireData.js.map +1 -0
- package/lib/module/helpers/mentionSpans.js +14 -0
- package/lib/module/helpers/mentionSpans.js.map +1 -0
- package/lib/module/helpers/mimeToExtension.js +43 -0
- package/lib/module/helpers/mimeToExtension.js.map +1 -1
- package/lib/module/helpers/readReceipts.js +160 -0
- package/lib/module/helpers/readReceipts.js.map +1 -0
- package/lib/module/helpers/repairFilenameEncoding.js +74 -0
- package/lib/module/helpers/repairFilenameEncoding.js.map +1 -0
- package/lib/module/helpers/safeJson.js +13 -0
- package/lib/module/helpers/safeJson.js.map +1 -0
- package/lib/module/helpers/updateMessagesTillLast.js +3 -1
- package/lib/module/helpers/updateMessagesTillLast.js.map +1 -1
- package/lib/module/hooks/useSendMessage.js +387 -195
- package/lib/module/hooks/useSendMessage.js.map +1 -1
- package/lib/module/i18n/strings.js +144 -0
- package/lib/module/i18n/strings.js.map +1 -1
- package/lib/module/main.js.map +1 -1
- package/lib/module/networking/api-requests/auth.api.js +62 -3
- package/lib/module/networking/api-requests/auth.api.js.map +1 -1
- package/lib/module/networking/stanzaHandlers.js +97 -4
- package/lib/module/networking/stanzaHandlers.js.map +1 -1
- package/lib/module/networking/xmpp/handleStanzas.xmpp.js +5 -3
- package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/sendDisplayedMarker.xmpp.js +25 -0
- package/lib/module/networking/xmpp/sendDisplayedMarker.xmpp.js.map +1 -0
- package/lib/module/networking/xmpp/sendMediaMessage.xmpp.js +53 -2
- package/lib/module/networking/xmpp/sendMediaMessage.xmpp.js.map +1 -1
- package/lib/module/networking/xmpp/sendReceivedReceipt.xmpp.js +25 -0
- package/lib/module/networking/xmpp/sendReceivedReceipt.xmpp.js.map +1 -0
- package/lib/module/networking/xmppClient.js +64 -0
- package/lib/module/networking/xmppClient.js.map +1 -1
- package/lib/module/roomStore/persistence.js +78 -5
- package/lib/module/roomStore/persistence.js.map +1 -1
- package/lib/module/roomStore/roomHeapSlice.js +4 -0
- package/lib/module/roomStore/roomHeapSlice.js.map +1 -1
- package/lib/module/roomStore/roomsSlice.js +109 -0
- package/lib/module/roomStore/roomsSlice.js.map +1 -1
- package/lib/module/types/models/attachment.model.js +2 -0
- package/lib/module/types/models/attachment.model.js.map +1 -0
- package/lib/module/version.js +1 -1
- package/lib/typescript/assets/icons.d.ts +6 -1
- package/lib/typescript/assets/icons.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/AlbumGrid.d.ts +21 -0
- package/lib/typescript/components/MainComponents/AlbumGrid.d.ts.map +1 -0
- package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MediaUploadOverlay.d.ts +17 -0
- package/lib/typescript/components/MainComponents/MediaUploadOverlay.d.ts.map +1 -0
- package/lib/typescript/components/MessageBubble/MediaCaption.d.ts +12 -0
- package/lib/typescript/components/MessageBubble/MediaCaption.d.ts.map +1 -0
- package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/LastMessageItem.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastAudioMessage.d.ts +2 -0
- package/lib/typescript/components/RoomComponents/styled/LastAudioMessage.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts +2 -0
- package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts +2 -0
- package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts +2 -0
- package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts.map +1 -1
- package/lib/typescript/components/Thread/ThreadWrapper.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/ActiveCallBar.d.ts +9 -3
- package/lib/typescript/components/VideoCalls/ActiveCallBar.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/CallIcons.d.ts +9 -0
- package/lib/typescript/components/VideoCalls/CallIcons.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/callSessionController.d.ts +7 -0
- package/lib/typescript/components/VideoCalls/callSessionController.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/callUiStore.d.ts +13 -0
- package/lib/typescript/components/VideoCalls/callUiStore.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts +5 -0
- package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/useCallKeep.d.ts +12 -0
- package/lib/typescript/components/VideoCalls/useCallKeep.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/useOngoingCallNotification.d.ts +10 -0
- package/lib/typescript/components/VideoCalls/useOngoingCallNotification.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/usePipTile.d.ts +46 -0
- package/lib/typescript/components/VideoCalls/usePipTile.d.ts.map +1 -0
- package/lib/typescript/components/styled/MediaFilePreview.d.ts.map +1 -1
- package/lib/typescript/components/styled/MessageImage.d.ts +10 -0
- package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
- package/lib/typescript/components/styled/SendInput.d.ts +7 -1
- package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
- package/lib/typescript/components/styled/VideoMessage.d.ts +7 -0
- package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
- package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
- package/lib/typescript/e2ee/fileEnvelope.d.ts +1 -1
- package/lib/typescript/e2ee/fileEnvelope.d.ts.map +1 -1
- package/lib/typescript/e2ee/sealedBody.d.ts +16 -0
- package/lib/typescript/e2ee/sealedBody.d.ts.map +1 -1
- package/lib/typescript/helpers/albumLayout.d.ts +66 -0
- package/lib/typescript/helpers/albumLayout.d.ts.map +1 -0
- package/lib/typescript/helpers/attachments.d.ts +55 -0
- package/lib/typescript/helpers/attachments.d.ts.map +1 -0
- package/lib/typescript/helpers/caption.d.ts +64 -0
- package/lib/typescript/helpers/caption.d.ts.map +1 -0
- package/lib/typescript/helpers/createMainMessageForThread.d.ts.map +1 -1
- package/lib/typescript/helpers/createMessageFromXml.d.ts.map +1 -1
- package/lib/typescript/helpers/fileKind.d.ts +20 -0
- package/lib/typescript/helpers/fileKind.d.ts.map +1 -0
- package/lib/typescript/helpers/getDataFromXml.d.ts.map +1 -1
- package/lib/typescript/helpers/mapWithConcurrency.d.ts +9 -0
- package/lib/typescript/helpers/mapWithConcurrency.d.ts.map +1 -0
- package/lib/typescript/helpers/mediaLimits.d.ts +13 -0
- package/lib/typescript/helpers/mediaLimits.d.ts.map +1 -0
- package/lib/typescript/helpers/mediaSendRetry.d.ts +26 -0
- package/lib/typescript/helpers/mediaSendRetry.d.ts.map +1 -0
- package/lib/typescript/helpers/mediaWireData.d.ts +16 -0
- package/lib/typescript/helpers/mediaWireData.d.ts.map +1 -0
- package/lib/typescript/helpers/mentionSpans.d.ts +8 -0
- package/lib/typescript/helpers/mentionSpans.d.ts.map +1 -0
- package/lib/typescript/helpers/mimeToExtension.d.ts +7 -0
- package/lib/typescript/helpers/mimeToExtension.d.ts.map +1 -1
- package/lib/typescript/helpers/readReceipts.d.ts +82 -0
- package/lib/typescript/helpers/readReceipts.d.ts.map +1 -0
- package/lib/typescript/helpers/repairFilenameEncoding.d.ts +12 -0
- package/lib/typescript/helpers/repairFilenameEncoding.d.ts.map +1 -0
- package/lib/typescript/helpers/safeJson.d.ts +2 -0
- package/lib/typescript/helpers/safeJson.d.ts.map +1 -0
- package/lib/typescript/helpers/updateMessagesTillLast.d.ts.map +1 -1
- package/lib/typescript/hooks/useSendMessage.d.ts +2 -1
- package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/i18n/strings.d.ts.map +1 -1
- package/lib/typescript/main.d.ts +1 -1
- package/lib/typescript/main.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/auth.api.d.ts +2 -0
- package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
- package/lib/typescript/networking/stanzaHandlers.d.ts +7 -3
- package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/sendDisplayedMarker.xmpp.d.ts +3 -0
- package/lib/typescript/networking/xmpp/sendDisplayedMarker.xmpp.d.ts.map +1 -0
- package/lib/typescript/networking/xmpp/sendMediaMessage.xmpp.d.ts +12 -0
- package/lib/typescript/networking/xmpp/sendMediaMessage.xmpp.d.ts.map +1 -1
- package/lib/typescript/networking/xmpp/sendReceivedReceipt.xmpp.d.ts +3 -0
- package/lib/typescript/networking/xmpp/sendReceivedReceipt.xmpp.d.ts.map +1 -0
- package/lib/typescript/networking/xmppClient.d.ts +15 -0
- package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
- package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomHeapSlice.d.ts +22 -1
- package/lib/typescript/roomStore/roomHeapSlice.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts +67 -3
- package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
- package/lib/typescript/types/models/attachment.model.d.ts +52 -0
- package/lib/typescript/types/models/attachment.model.d.ts.map +1 -0
- package/lib/typescript/types/models/message.model.d.ts +26 -0
- package/lib/typescript/types/models/message.model.d.ts.map +1 -1
- package/lib/typescript/types/models/modal.model.d.ts +7 -0
- package/lib/typescript/types/models/modal.model.d.ts.map +1 -1
- package/lib/typescript/types/models/room.model.d.ts +2 -0
- package/lib/typescript/types/models/room.model.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +69 -1
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/lib/typescript/version.d.ts +1 -1
- package/package.json +4 -1
- package/plugins/notification-service/Info.plist +31 -0
- package/plugins/notification-service/NotificationService.swift +82 -0
- package/plugins/withNotificationServiceExtension.js +137 -0
- package/src/assets/icons.tsx +20 -2
- package/src/components/MainComponents/AlbumGrid.tsx +183 -0
- package/src/components/MainComponents/ChatRoom.tsx +4 -2
- package/src/components/MainComponents/MediaMessage.tsx +246 -130
- package/src/components/MainComponents/MediaUploadOverlay.tsx +102 -0
- package/src/components/MessageBubble/MediaCaption.tsx +45 -0
- package/src/components/MessageBubble/Message.tsx +71 -3
- package/src/components/MessageBubble/MessageInteractions.tsx +2 -1
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +64 -0
- package/src/components/RoomComponents/LastMessageItem.tsx +15 -4
- package/src/components/RoomComponents/styled/LastAudioMessage.tsx +6 -3
- package/src/components/RoomComponents/styled/LastMessageFile.tsx +6 -2
- package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +6 -2
- package/src/components/RoomComponents/styled/LastMessageVideo.tsx +6 -2
- package/src/components/Thread/ThreadWrapper.tsx +5 -9
- package/src/components/VideoCalls/ActiveCallBar.tsx +56 -10
- package/src/components/VideoCalls/CallIcons.tsx +36 -12
- package/src/components/VideoCalls/VideoCallOverlay.tsx +205 -8
- package/src/components/VideoCalls/VideoCallSession.tsx +45 -13
- package/src/components/VideoCalls/callSessionController.ts +51 -20
- package/src/components/VideoCalls/callUiStore.ts +33 -3
- package/src/components/VideoCalls/livekitRuntime.ts +13 -0
- package/src/components/VideoCalls/useCallKeep.ts +204 -33
- package/src/components/VideoCalls/useOngoingCallNotification.ts +113 -0
- package/src/components/VideoCalls/usePipTile.ts +214 -0
- package/src/components/styled/MediaFilePreview.tsx +49 -34
- package/src/components/styled/MessageImage.tsx +21 -5
- package/src/components/styled/SendInput.tsx +101 -87
- package/src/components/styled/VideoMessage.tsx +34 -9
- package/src/context/xmppProvider.tsx +32 -0
- package/src/e2ee/fileEnvelope.ts +1 -1
- package/src/e2ee/sealedBody.ts +44 -5
- package/src/helpers/albumLayout.ts +207 -0
- package/src/helpers/attachments.ts +316 -0
- package/src/helpers/caption.ts +283 -0
- package/src/helpers/createMainMessageForThread.ts +6 -1
- package/src/helpers/createMessageFromXml.ts +21 -5
- package/src/helpers/fileKind.ts +38 -0
- package/src/helpers/getDataFromXml.ts +5 -1
- package/src/helpers/mapWithConcurrency.ts +32 -0
- package/src/helpers/mediaLimits.ts +27 -0
- package/src/helpers/mediaSendRetry.ts +59 -0
- package/src/helpers/mediaWireData.ts +57 -0
- package/src/helpers/mentionSpans.ts +17 -0
- package/src/helpers/mimeToExtension.ts +51 -0
- package/src/helpers/readReceipts.ts +219 -0
- package/src/helpers/repairFilenameEncoding.ts +82 -0
- package/src/helpers/safeJson.ts +11 -0
- package/src/helpers/updateMessagesTillLast.tsx +2 -1
- package/src/hooks/useSendMessage.tsx +448 -249
- package/src/i18n/strings.ts +144 -0
- package/src/main.ts +3 -0
- package/src/networking/api-requests/auth.api.ts +60 -3
- package/src/networking/stanzaHandlers.ts +91 -2
- package/src/networking/xmpp/handleStanzas.xmpp.ts +6 -2
- package/src/networking/xmpp/sendDisplayedMarker.xmpp.ts +31 -0
- package/src/networking/xmpp/sendMediaMessage.xmpp.ts +60 -3
- package/src/networking/xmpp/sendReceivedReceipt.xmpp.ts +31 -0
- package/src/networking/xmppClient.ts +48 -0
- package/src/roomStore/persistence.ts +94 -3
- package/src/roomStore/roomHeapSlice.ts +23 -1
- package/src/roomStore/roomsSlice.ts +112 -1
- package/src/types/models/attachment.model.ts +51 -0
- package/src/types/models/message.model.ts +29 -0
- package/src/types/models/modal.model.ts +7 -0
- package/src/types/models/room.model.ts +2 -0
- package/src/types/types.ts +83 -1
- package/src/version.ts +1 -1
- package/lib/commonjs/components/VideoCalls/useDraggable.js +0 -59
- package/lib/commonjs/components/VideoCalls/useDraggable.js.map +0 -1
- package/lib/module/components/VideoCalls/useDraggable.js +0 -55
- package/lib/module/components/VideoCalls/useDraggable.js.map +0 -1
- package/lib/typescript/components/VideoCalls/useDraggable.d.ts +0 -19
- package/lib/typescript/components/VideoCalls/useDraggable.d.ts.map +0 -1
- package/src/components/VideoCalls/useDraggable.ts +0 -46
|
@@ -29,6 +29,10 @@ interface CustomMessageVideoProps {
|
|
|
29
29
|
mimetype: string;
|
|
30
30
|
/** The backend-generated poster frame (message.locationPreview). */
|
|
31
31
|
previewURL?: string;
|
|
32
|
+
/** Album mode: fill a tile of exactly this size (square corners; the tile clips). */
|
|
33
|
+
tile?: { width: number; height: number };
|
|
34
|
+
/** Replaces the default "open this one file" tap, e.g. to open an album at an index. */
|
|
35
|
+
onOpen?: () => void;
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
const PlayBadge: React.FC = () => (
|
|
@@ -51,11 +55,13 @@ const PosterVideo: React.FC<{
|
|
|
51
55
|
previewURL: string;
|
|
52
56
|
onOpen: () => void;
|
|
53
57
|
onPosterError: () => void;
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
tile?: { width: number; height: number };
|
|
59
|
+
}> = ({ previewURL, onOpen, onPosterError, tile }) => {
|
|
60
|
+
const [measured, setDims] = useState<MediaDims>(defaultMediaDims());
|
|
61
|
+
const dims: MediaDims = tile ?? measured;
|
|
56
62
|
|
|
57
63
|
useEffect(() => {
|
|
58
|
-
if (!previewURL) {
|
|
64
|
+
if (!previewURL || tile) {
|
|
59
65
|
return;
|
|
60
66
|
}
|
|
61
67
|
let active = true;
|
|
@@ -73,12 +79,16 @@ const PosterVideo: React.FC<{
|
|
|
73
79
|
return () => {
|
|
74
80
|
active = false;
|
|
75
81
|
};
|
|
76
|
-
}, [previewURL]);
|
|
82
|
+
}, [previewURL, tile]);
|
|
77
83
|
|
|
78
84
|
return (
|
|
79
85
|
<Pressable
|
|
80
86
|
onPress={onOpen}
|
|
81
|
-
style={[
|
|
87
|
+
style={[
|
|
88
|
+
styles.wrapper,
|
|
89
|
+
{ width: dims.width, height: dims.height },
|
|
90
|
+
tile && styles.tileWrapper,
|
|
91
|
+
]}
|
|
82
92
|
accessibilityRole="button"
|
|
83
93
|
accessibilityLabel="Play video"
|
|
84
94
|
>
|
|
@@ -115,13 +125,18 @@ const PosterVideo: React.FC<{
|
|
|
115
125
|
*/
|
|
116
126
|
const PlaceholderVideo: React.FC<{
|
|
117
127
|
onOpen: () => void;
|
|
118
|
-
|
|
119
|
-
|
|
128
|
+
tile?: { width: number; height: number };
|
|
129
|
+
}> = ({ onOpen, tile }) => {
|
|
130
|
+
const dims = tile ?? defaultMediaDims();
|
|
120
131
|
|
|
121
132
|
return (
|
|
122
133
|
<Pressable
|
|
123
134
|
onPress={onOpen}
|
|
124
|
-
style={[
|
|
135
|
+
style={[
|
|
136
|
+
styles.wrapper,
|
|
137
|
+
{ width: dims.width, height: dims.height },
|
|
138
|
+
tile && styles.tileWrapper,
|
|
139
|
+
]}
|
|
125
140
|
accessibilityRole="button"
|
|
126
141
|
accessibilityLabel="Play video"
|
|
127
142
|
>
|
|
@@ -136,11 +151,17 @@ const CustomMessageVideo: React.FC<CustomMessageVideoProps> = ({
|
|
|
136
151
|
fileURL,
|
|
137
152
|
mimetype,
|
|
138
153
|
previewURL,
|
|
154
|
+
tile,
|
|
155
|
+
onOpen,
|
|
139
156
|
}) => {
|
|
140
157
|
const dispatch = useDispatch();
|
|
141
158
|
const [posterFailed, setPosterFailed] = useState(false);
|
|
142
159
|
|
|
143
160
|
const handleOpen = () => {
|
|
161
|
+
if (onOpen) {
|
|
162
|
+
onOpen();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
144
165
|
dispatch(setActiveFile({ fileName, fileURL, mimetype, originalName }));
|
|
145
166
|
dispatch(setActiveModal(MODAL_TYPES.FILE_PREVIEW));
|
|
146
167
|
};
|
|
@@ -150,6 +171,7 @@ const CustomMessageVideo: React.FC<CustomMessageVideoProps> = ({
|
|
|
150
171
|
<PosterVideo
|
|
151
172
|
previewURL={previewURL}
|
|
152
173
|
onOpen={handleOpen}
|
|
174
|
+
tile={tile}
|
|
153
175
|
onPosterError={() => {
|
|
154
176
|
if (isSecureFileUrl(previewURL)) {
|
|
155
177
|
requestFileTokenRecovery();
|
|
@@ -160,7 +182,7 @@ const CustomMessageVideo: React.FC<CustomMessageVideoProps> = ({
|
|
|
160
182
|
);
|
|
161
183
|
}
|
|
162
184
|
|
|
163
|
-
return <PlaceholderVideo onOpen={handleOpen} />;
|
|
185
|
+
return <PlaceholderVideo onOpen={handleOpen} tile={tile} />;
|
|
164
186
|
};
|
|
165
187
|
|
|
166
188
|
export default CustomMessageVideo;
|
|
@@ -171,6 +193,9 @@ const styles = StyleSheet.create({
|
|
|
171
193
|
overflow: 'hidden',
|
|
172
194
|
backgroundColor: '#000',
|
|
173
195
|
},
|
|
196
|
+
tileWrapper: {
|
|
197
|
+
borderRadius: 0,
|
|
198
|
+
},
|
|
174
199
|
video: {
|
|
175
200
|
width: '100%',
|
|
176
201
|
height: '100%',
|
|
@@ -63,6 +63,7 @@ import { updateMessagesTillLast } from '../helpers/updateMessagesTillLast';
|
|
|
63
63
|
import { secureUserStorage } from '../helpers/secureUserStorage';
|
|
64
64
|
import { clearPersistedState } from '../roomStore/persistence';
|
|
65
65
|
import { pushLog as devPushLog } from '../utils/devLogger';
|
|
66
|
+
import { computeReadWatermark } from '../helpers/readReceipts';
|
|
66
67
|
|
|
67
68
|
interface InitMode {
|
|
68
69
|
current: 'provider' | 'chat';
|
|
@@ -794,6 +795,26 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
794
795
|
let lastMessagesRef: any = null;
|
|
795
796
|
let lastStampedMs = 0;
|
|
796
797
|
let flushTimer: ReturnType<typeof setTimeout> | null = null;
|
|
798
|
+
// Room whose XEP-0333 marker is waiting on the 2 s debounce below. Set
|
|
799
|
+
// only while that room is the one on screen.
|
|
800
|
+
let pendingMarkerJid: string | null = null;
|
|
801
|
+
|
|
802
|
+
// Sends the waiting marker now: the debounce is cut short because the
|
|
803
|
+
// user left the room or the app, so it would otherwise be lost. The room
|
|
804
|
+
// counts as on screen for this one call (it was when the marker was
|
|
805
|
+
// queued); the jump window, the scroll boundary and the disable flags
|
|
806
|
+
// still apply inside computeReadWatermark.
|
|
807
|
+
const flushPendingMarker = () => {
|
|
808
|
+
const jid = pendingMarkerJid;
|
|
809
|
+
pendingMarkerJid = null;
|
|
810
|
+
if (!jid) {return;}
|
|
811
|
+
const st = store.getState();
|
|
812
|
+
const watermark = computeReadWatermark(
|
|
813
|
+
{ ...st, rooms: { ...st.rooms, visibleRoomJID: jid } } as any,
|
|
814
|
+
jid
|
|
815
|
+
);
|
|
816
|
+
if (watermark) {client?.sendDisplayedMarkerStanza?.(watermark, jid);}
|
|
817
|
+
};
|
|
797
818
|
|
|
798
819
|
const advance = () => {
|
|
799
820
|
const s = store.getState();
|
|
@@ -826,9 +847,13 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
826
847
|
setLastViewedTimestamp({ chatJID: jid, timestamp: newest })
|
|
827
848
|
);
|
|
828
849
|
|
|
850
|
+
// Another room took over the debounce: send the old room's marker first.
|
|
851
|
+
if (pendingMarkerJid && pendingMarkerJid !== jid) {flushPendingMarker();}
|
|
829
852
|
if (flushTimer) {clearTimeout(flushTimer);}
|
|
830
853
|
if (client?.flushLastViewedToPrivateStoreStanza) {
|
|
854
|
+
if (s.rooms?.visibleRoomJID === jid) {pendingMarkerJid = jid;}
|
|
831
855
|
flushTimer = setTimeout(() => {
|
|
856
|
+
pendingMarkerJid = null;
|
|
832
857
|
// Re-read fresh state rather than closing over `boundaryTs`:
|
|
833
858
|
// the user may have scrolled back to the bottom (clearing the
|
|
834
859
|
// boundary) in the 2s between the stamp and this flush, and
|
|
@@ -845,6 +870,12 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
845
870
|
),
|
|
846
871
|
})
|
|
847
872
|
.catch(() => {});
|
|
873
|
+
// XEP-0333 read marker, on the same debounce as the private-store
|
|
874
|
+
// write above. computeReadWatermark sends nothing unless the room is
|
|
875
|
+
// still on screen, no jump window is open and the newest message
|
|
876
|
+
// is someone else's.
|
|
877
|
+
const watermark = computeReadWatermark(freshState, jid);
|
|
878
|
+
if (watermark) {client.sendDisplayedMarkerStanza?.(watermark, jid);}
|
|
848
879
|
}, 2000);
|
|
849
880
|
}
|
|
850
881
|
};
|
|
@@ -854,6 +885,7 @@ export const XmppProvider: React.FC<XmppProviderProps> = ({ children, config, is
|
|
|
854
885
|
return () => {
|
|
855
886
|
unsub();
|
|
856
887
|
if (flushTimer) {clearTimeout(flushTimer);}
|
|
888
|
+
flushPendingMarker();
|
|
857
889
|
};
|
|
858
890
|
}, [isVisible, client]);
|
|
859
891
|
|
package/src/e2ee/fileEnvelope.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
type Progress,
|
|
13
13
|
} from './fileCipher';
|
|
14
14
|
|
|
15
|
-
export { parseSealedMediaBody } from './sealedBody';
|
|
15
|
+
export { parseSealedMediaBody, parseSealedMediaPayload } from './sealedBody';
|
|
16
16
|
|
|
17
17
|
const MAGIC = Uint8Array.from([0x45, 0x54, 0x48, 0x4f, 0x46, 0x49, 0x4c, 0x45]);
|
|
18
18
|
const VERSION = 1;
|
package/src/e2ee/sealedBody.ts
CHANGED
|
@@ -1,17 +1,56 @@
|
|
|
1
|
-
|
|
1
|
+
import type { IMentionSpan } from '../types/models/message.model';
|
|
2
|
+
import { normalizeCaptionInput } from '../helpers/caption';
|
|
3
|
+
|
|
4
|
+
/** What a sealed media <body> carries besides the keys. */
|
|
5
|
+
export interface SealedMediaPayload {
|
|
6
|
+
keys: string[];
|
|
7
|
+
/** The text typed with the files. Sealed here, never on <data>. */
|
|
8
|
+
caption?: string;
|
|
9
|
+
captionMentions?: IMentionSpan[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Pulls the attachment keys (and the caption, when there is one) out of a
|
|
14
|
+
* decrypted media <body>: `{v:1,keys:[...],caption?,captionMentions?}`, which
|
|
15
|
+
* the sender writes in place of the usual literal "media". Undefined for
|
|
16
|
+
* anything else, so an ordinary media message falls through untouched.
|
|
17
|
+
*/
|
|
18
|
+
export function parseSealedMediaPayload(
|
|
19
|
+
body?: string
|
|
20
|
+
): SealedMediaPayload | undefined {
|
|
2
21
|
const text = String(body || '').trim();
|
|
3
22
|
if (!text.startsWith('{')) {return undefined;}
|
|
4
23
|
|
|
5
24
|
try {
|
|
6
|
-
const parsed = JSON.parse(text) as {
|
|
25
|
+
const parsed = JSON.parse(text) as {
|
|
26
|
+
v?: unknown;
|
|
27
|
+
keys?: unknown;
|
|
28
|
+
caption?: unknown;
|
|
29
|
+
captionMentions?: unknown;
|
|
30
|
+
};
|
|
7
31
|
if (parsed?.v !== 1 || !Array.isArray(parsed.keys)) {return undefined;}
|
|
8
32
|
const keys = parsed.keys.filter(
|
|
9
33
|
(k): k is string => typeof k === 'string' && k.length > 0
|
|
10
34
|
);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
35
|
+
if (!(keys.length === parsed.keys.length && keys.length > 0)) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const caption = normalizeCaptionInput({
|
|
40
|
+
text: typeof parsed.caption === 'string' ? parsed.caption : '',
|
|
41
|
+
mentions: parsed.captionMentions as IMentionSpan[] | undefined,
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
keys,
|
|
45
|
+
...(caption ? { caption: caption.caption } : {}),
|
|
46
|
+
...(caption?.mentions ? { captionMentions: caption.mentions } : {}),
|
|
47
|
+
};
|
|
14
48
|
} catch {
|
|
15
49
|
return undefined;
|
|
16
50
|
}
|
|
17
51
|
}
|
|
52
|
+
|
|
53
|
+
/** The attachment keys out of a sealed media <body>; see parseSealedMediaPayload. */
|
|
54
|
+
export function parseSealedMediaBody(body?: string): string[] | undefined {
|
|
55
|
+
return parseSealedMediaPayload(body)?.keys;
|
|
56
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import type { ViewStyle } from 'react-native';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Geometry for a multi-media album bubble. Pure numbers and RN style objects,
|
|
5
|
+
* so AlbumGrid stays a dumb renderer and the rules are testable without a
|
|
6
|
+
* renderer.
|
|
7
|
+
*
|
|
8
|
+
* 1 item full width, 4:3
|
|
9
|
+
* 2 items side by side, 2:1 (square cells)
|
|
10
|
+
* 3 items one large cell on the left, two stacked on the right
|
|
11
|
+
* 4 items 2 x 2
|
|
12
|
+
* 5+ items 2 x 2 showing the first four, the last cell carries "+N"
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** Gap between neighbouring tiles. */
|
|
16
|
+
export const ALBUM_GAP = 3;
|
|
17
|
+
/** Radius of a tile corner that sits on the bubble's own corner. */
|
|
18
|
+
export const ALBUM_OUTER_RADIUS = 10;
|
|
19
|
+
/** Radius of every other tile corner, the ones that face a neighbour. */
|
|
20
|
+
export const ALBUM_INNER_RADIUS = 3;
|
|
21
|
+
|
|
22
|
+
export interface AlbumCellPlacement {
|
|
23
|
+
/** 0-based grid column and row of the tile's top-left cell. */
|
|
24
|
+
column: number;
|
|
25
|
+
row: number;
|
|
26
|
+
columnSpan: number;
|
|
27
|
+
rowSpan: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type AlbumKind = 'full' | 'pair' | 'hero' | 'quad';
|
|
31
|
+
|
|
32
|
+
export interface AlbumLayout {
|
|
33
|
+
kind: AlbumKind;
|
|
34
|
+
/** Number of tiles actually drawn. */
|
|
35
|
+
visible: number;
|
|
36
|
+
/** Items folded into the "+N" overlay on the last visible tile. */
|
|
37
|
+
hidden: number;
|
|
38
|
+
/** Relative width of each grid column. */
|
|
39
|
+
columns: number[];
|
|
40
|
+
/** Relative height of each grid row. */
|
|
41
|
+
rows: number[];
|
|
42
|
+
/** Width divided by height of the whole grid. */
|
|
43
|
+
aspectRatio: number;
|
|
44
|
+
/** One entry per visible tile, in order. */
|
|
45
|
+
placements: AlbumCellPlacement[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const cell = (
|
|
49
|
+
column: number,
|
|
50
|
+
row: number,
|
|
51
|
+
rowSpan = 1
|
|
52
|
+
): AlbumCellPlacement => ({ column, row, columnSpan: 1, rowSpan });
|
|
53
|
+
|
|
54
|
+
const LAYOUTS: Record<AlbumKind, Omit<AlbumLayout, 'visible' | 'hidden'>> = {
|
|
55
|
+
full: {
|
|
56
|
+
kind: 'full',
|
|
57
|
+
columns: [1],
|
|
58
|
+
rows: [1],
|
|
59
|
+
aspectRatio: 4 / 3,
|
|
60
|
+
placements: [cell(0, 0)],
|
|
61
|
+
},
|
|
62
|
+
pair: {
|
|
63
|
+
kind: 'pair',
|
|
64
|
+
columns: [1, 1],
|
|
65
|
+
rows: [1],
|
|
66
|
+
aspectRatio: 2,
|
|
67
|
+
placements: [cell(0, 0), cell(1, 0)],
|
|
68
|
+
},
|
|
69
|
+
hero: {
|
|
70
|
+
kind: 'hero',
|
|
71
|
+
columns: [2, 1],
|
|
72
|
+
rows: [1, 1],
|
|
73
|
+
aspectRatio: 4 / 3,
|
|
74
|
+
placements: [cell(0, 0, 2), cell(1, 0), cell(1, 1)],
|
|
75
|
+
},
|
|
76
|
+
quad: {
|
|
77
|
+
kind: 'quad',
|
|
78
|
+
columns: [1, 1],
|
|
79
|
+
rows: [1, 1],
|
|
80
|
+
aspectRatio: 1,
|
|
81
|
+
placements: [cell(0, 0), cell(1, 0), cell(0, 1), cell(1, 1)],
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/** Layout for `count` media tiles. Counts below 1 are treated as 1. */
|
|
86
|
+
export const getAlbumLayout = (count: number): AlbumLayout => {
|
|
87
|
+
const total = Math.max(1, Math.floor(Number.isFinite(count) ? count : 1));
|
|
88
|
+
const kind: AlbumKind =
|
|
89
|
+
total === 1 ? 'full' : total === 2 ? 'pair' : total === 3 ? 'hero' : 'quad';
|
|
90
|
+
const base = LAYOUTS[kind];
|
|
91
|
+
const visible = base.placements.length;
|
|
92
|
+
return {
|
|
93
|
+
...base,
|
|
94
|
+
columns: [...base.columns],
|
|
95
|
+
rows: [...base.rows],
|
|
96
|
+
placements: base.placements.map((placement) => ({ ...placement })),
|
|
97
|
+
visible,
|
|
98
|
+
hidden: Math.max(0, total - visible),
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/** Splits `total` across weighted tracks, leaving `gap` between neighbours. */
|
|
103
|
+
const trackSizes = (weights: number[], total: number, gap: number): number[] => {
|
|
104
|
+
const room = total - gap * (weights.length - 1);
|
|
105
|
+
const sum = weights.reduce((acc, weight) => acc + weight, 0);
|
|
106
|
+
return weights.map((weight) => (room * weight) / sum);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export interface AlbumFrame {
|
|
110
|
+
width: number;
|
|
111
|
+
height: number;
|
|
112
|
+
/** One absolutely positioned style per visible tile, in order. */
|
|
113
|
+
tiles: ViewStyle[];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Pixel frame of the grid and of every tile for a grid `width` wide. */
|
|
117
|
+
export const getAlbumFrame = (layout: AlbumLayout, width: number): AlbumFrame => {
|
|
118
|
+
const height = Math.round(width / layout.aspectRatio);
|
|
119
|
+
const colWidths = trackSizes(layout.columns, width, ALBUM_GAP);
|
|
120
|
+
const rowHeights = trackSizes(layout.rows, height, ALBUM_GAP);
|
|
121
|
+
const offset = (sizes: number[], index: number) =>
|
|
122
|
+
sizes.slice(0, index).reduce((acc, size) => acc + size + ALBUM_GAP, 0);
|
|
123
|
+
const span = (sizes: number[], index: number, count: number) =>
|
|
124
|
+
sizes.slice(index, index + count).reduce((acc, size) => acc + size, 0) +
|
|
125
|
+
ALBUM_GAP * (count - 1);
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
width,
|
|
129
|
+
height,
|
|
130
|
+
tiles: layout.placements.map((placement, position) => ({
|
|
131
|
+
position: 'absolute',
|
|
132
|
+
left: Math.round(offset(colWidths, placement.column)),
|
|
133
|
+
top: Math.round(offset(rowHeights, placement.row)),
|
|
134
|
+
width: Math.round(span(colWidths, placement.column, placement.columnSpan)),
|
|
135
|
+
height: Math.round(span(rowHeights, placement.row, placement.rowSpan)),
|
|
136
|
+
overflow: 'hidden',
|
|
137
|
+
...getTileBorderRadius(layout, position),
|
|
138
|
+
})),
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Which corners of one tile lie on the bubble's outer edge. Only those get
|
|
144
|
+
* the large radius; corners that face a neighbour get the small inner one.
|
|
145
|
+
*/
|
|
146
|
+
export interface TileCorners {
|
|
147
|
+
topLeft: boolean;
|
|
148
|
+
topRight: boolean;
|
|
149
|
+
bottomRight: boolean;
|
|
150
|
+
bottomLeft: boolean;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const corners = (
|
|
154
|
+
topLeft: boolean,
|
|
155
|
+
topRight: boolean,
|
|
156
|
+
bottomRight: boolean,
|
|
157
|
+
bottomLeft: boolean
|
|
158
|
+
): TileCorners => ({ topLeft, topRight, bottomRight, bottomLeft });
|
|
159
|
+
|
|
160
|
+
const OUTER_CORNERS: Record<AlbumKind, TileCorners[]> = {
|
|
161
|
+
full: [corners(true, true, true, true)],
|
|
162
|
+
pair: [corners(true, false, false, true), corners(false, true, true, false)],
|
|
163
|
+
// Hero: the tall left cell owns both left corners; the right column owns
|
|
164
|
+
// its top-right and bottom-right corners respectively.
|
|
165
|
+
hero: [
|
|
166
|
+
corners(true, false, false, true),
|
|
167
|
+
corners(false, true, false, false),
|
|
168
|
+
corners(false, false, true, false),
|
|
169
|
+
],
|
|
170
|
+
quad: [
|
|
171
|
+
corners(true, false, false, false),
|
|
172
|
+
corners(false, true, false, false),
|
|
173
|
+
corners(false, false, false, true),
|
|
174
|
+
corners(false, false, true, false),
|
|
175
|
+
],
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/** Outer-corner flags for the tile at `position` (0-based) of `layout`. */
|
|
179
|
+
export const getTileCorners = (
|
|
180
|
+
layout: AlbumLayout,
|
|
181
|
+
position: number
|
|
182
|
+
): TileCorners => {
|
|
183
|
+
const found = OUTER_CORNERS[layout.kind][position];
|
|
184
|
+
return found ? { ...found } : corners(false, false, false, false);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/** The four border radii of one tile, as RN style props. */
|
|
188
|
+
export const getTileBorderRadius = (
|
|
189
|
+
layout: AlbumLayout,
|
|
190
|
+
position: number
|
|
191
|
+
): Pick<
|
|
192
|
+
ViewStyle,
|
|
193
|
+
| 'borderTopLeftRadius'
|
|
194
|
+
| 'borderTopRightRadius'
|
|
195
|
+
| 'borderBottomRightRadius'
|
|
196
|
+
| 'borderBottomLeftRadius'
|
|
197
|
+
> => {
|
|
198
|
+
const c = getTileCorners(layout, position);
|
|
199
|
+
const radius = (outer: boolean) =>
|
|
200
|
+
outer ? ALBUM_OUTER_RADIUS : ALBUM_INNER_RADIUS;
|
|
201
|
+
return {
|
|
202
|
+
borderTopLeftRadius: radius(c.topLeft),
|
|
203
|
+
borderTopRightRadius: radius(c.topRight),
|
|
204
|
+
borderBottomRightRadius: radius(c.bottomRight),
|
|
205
|
+
borderBottomLeftRadius: radius(c.bottomLeft),
|
|
206
|
+
};
|
|
207
|
+
};
|