@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.
Files changed (451) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +15 -0
  3. package/app.plugin.js +2 -0
  4. package/lib/commonjs/assets/icons.js +2 -2
  5. package/lib/commonjs/assets/icons.js.map +1 -1
  6. package/lib/commonjs/components/MainComponents/AlbumGrid.js +152 -0
  7. package/lib/commonjs/components/MainComponents/AlbumGrid.js.map +1 -0
  8. package/lib/commonjs/components/MainComponents/ChatRoom.js +2 -2
  9. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  10. package/lib/commonjs/components/MainComponents/MediaMessage.js +199 -123
  11. package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
  12. package/lib/commonjs/components/MainComponents/MediaUploadOverlay.js +109 -0
  13. package/lib/commonjs/components/MainComponents/MediaUploadOverlay.js.map +1 -0
  14. package/lib/commonjs/components/MessageBubble/MediaCaption.js +51 -0
  15. package/lib/commonjs/components/MessageBubble/MediaCaption.js.map +1 -0
  16. package/lib/commonjs/components/MessageBubble/Message.js +40 -1
  17. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  18. package/lib/commonjs/components/MessageBubble/MessageInteractions.js +2 -1
  19. package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
  20. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +75 -0
  21. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  22. package/lib/commonjs/components/RoomComponents/LastMessageItem.js +20 -4
  23. package/lib/commonjs/components/RoomComponents/LastMessageItem.js.map +1 -1
  24. package/lib/commonjs/components/RoomComponents/styled/LastAudioMessage.js +3 -2
  25. package/lib/commonjs/components/RoomComponents/styled/LastAudioMessage.js.map +1 -1
  26. package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js +3 -2
  27. package/lib/commonjs/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
  28. package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js +3 -2
  29. package/lib/commonjs/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
  30. package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js +3 -2
  31. package/lib/commonjs/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
  32. package/lib/commonjs/components/Thread/ThreadWrapper.js +3 -2
  33. package/lib/commonjs/components/Thread/ThreadWrapper.js.map +1 -1
  34. package/lib/commonjs/components/VideoCalls/ActiveCallBar.js +61 -16
  35. package/lib/commonjs/components/VideoCalls/ActiveCallBar.js.map +1 -1
  36. package/lib/commonjs/components/VideoCalls/CallIcons.js +41 -16
  37. package/lib/commonjs/components/VideoCalls/CallIcons.js.map +1 -1
  38. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js +183 -9
  39. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js.map +1 -1
  40. package/lib/commonjs/components/VideoCalls/VideoCallSession.js +40 -15
  41. package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -1
  42. package/lib/commonjs/components/VideoCalls/callSessionController.js +49 -26
  43. package/lib/commonjs/components/VideoCalls/callSessionController.js.map +1 -1
  44. package/lib/commonjs/components/VideoCalls/callUiStore.js +33 -4
  45. package/lib/commonjs/components/VideoCalls/callUiStore.js.map +1 -1
  46. package/lib/commonjs/components/VideoCalls/livekitRuntime.js +9 -1
  47. package/lib/commonjs/components/VideoCalls/livekitRuntime.js.map +1 -1
  48. package/lib/commonjs/components/VideoCalls/useCallKeep.js +197 -28
  49. package/lib/commonjs/components/VideoCalls/useCallKeep.js.map +1 -1
  50. package/lib/commonjs/components/VideoCalls/useOngoingCallNotification.js +88 -0
  51. package/lib/commonjs/components/VideoCalls/useOngoingCallNotification.js.map +1 -0
  52. package/lib/commonjs/components/VideoCalls/usePipTile.js +232 -0
  53. package/lib/commonjs/components/VideoCalls/usePipTile.js.map +1 -0
  54. package/lib/commonjs/components/styled/MediaFilePreview.js +60 -47
  55. package/lib/commonjs/components/styled/MediaFilePreview.js.map +1 -1
  56. package/lib/commonjs/components/styled/MessageImage.js +16 -6
  57. package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
  58. package/lib/commonjs/components/styled/SendInput.js +99 -68
  59. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  60. package/lib/commonjs/components/styled/VideoMessage.js +24 -10
  61. package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
  62. package/lib/commonjs/context/xmppProvider.js +46 -0
  63. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  64. package/lib/commonjs/e2ee/fileEnvelope.js +6 -0
  65. package/lib/commonjs/e2ee/fileEnvelope.js.map +1 -1
  66. package/lib/commonjs/e2ee/sealedBody.js +32 -2
  67. package/lib/commonjs/e2ee/sealedBody.js.map +1 -1
  68. package/lib/commonjs/helpers/albumLayout.js +150 -0
  69. package/lib/commonjs/helpers/albumLayout.js.map +1 -0
  70. package/lib/commonjs/helpers/attachments.js +255 -0
  71. package/lib/commonjs/helpers/attachments.js.map +1 -0
  72. package/lib/commonjs/helpers/caption.js +214 -0
  73. package/lib/commonjs/helpers/caption.js.map +1 -0
  74. package/lib/commonjs/helpers/createMainMessageForThread.js +5 -1
  75. package/lib/commonjs/helpers/createMainMessageForThread.js.map +1 -1
  76. package/lib/commonjs/helpers/createMessageFromXml.js +19 -5
  77. package/lib/commonjs/helpers/createMessageFromXml.js.map +1 -1
  78. package/lib/commonjs/helpers/fileKind.js +40 -0
  79. package/lib/commonjs/helpers/fileKind.js.map +1 -0
  80. package/lib/commonjs/helpers/getDataFromXml.js +6 -1
  81. package/lib/commonjs/helpers/getDataFromXml.js.map +1 -1
  82. package/lib/commonjs/helpers/mapWithConcurrency.js +41 -0
  83. package/lib/commonjs/helpers/mapWithConcurrency.js.map +1 -0
  84. package/lib/commonjs/helpers/mediaLimits.js +33 -0
  85. package/lib/commonjs/helpers/mediaLimits.js.map +1 -0
  86. package/lib/commonjs/helpers/mediaSendRetry.js +64 -0
  87. package/lib/commonjs/helpers/mediaSendRetry.js.map +1 -0
  88. package/lib/commonjs/helpers/mediaWireData.js +62 -0
  89. package/lib/commonjs/helpers/mediaWireData.js.map +1 -0
  90. package/lib/commonjs/helpers/mentionSpans.js +19 -0
  91. package/lib/commonjs/helpers/mentionSpans.js.map +1 -0
  92. package/lib/commonjs/helpers/mimeToExtension.js +45 -0
  93. package/lib/commonjs/helpers/mimeToExtension.js.map +1 -1
  94. package/lib/commonjs/helpers/readReceipts.js +173 -0
  95. package/lib/commonjs/helpers/readReceipts.js.map +1 -0
  96. package/lib/commonjs/helpers/repairFilenameEncoding.js +79 -0
  97. package/lib/commonjs/helpers/repairFilenameEncoding.js.map +1 -0
  98. package/lib/commonjs/helpers/safeJson.js +18 -0
  99. package/lib/commonjs/helpers/safeJson.js.map +1 -0
  100. package/lib/commonjs/helpers/updateMessagesTillLast.js +3 -1
  101. package/lib/commonjs/helpers/updateMessagesTillLast.js.map +1 -1
  102. package/lib/commonjs/hooks/useSendMessage.js +384 -193
  103. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  104. package/lib/commonjs/i18n/strings.js +144 -0
  105. package/lib/commonjs/i18n/strings.js.map +1 -1
  106. package/lib/commonjs/main.js.map +1 -1
  107. package/lib/commonjs/networking/api-requests/auth.api.js +62 -3
  108. package/lib/commonjs/networking/api-requests/auth.api.js.map +1 -1
  109. package/lib/commonjs/networking/stanzaHandlers.js +100 -3
  110. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  111. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +4 -2
  112. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  113. package/lib/commonjs/networking/xmpp/sendDisplayedMarker.xmpp.js +28 -0
  114. package/lib/commonjs/networking/xmpp/sendDisplayedMarker.xmpp.js.map +1 -0
  115. package/lib/commonjs/networking/xmpp/sendMediaMessage.xmpp.js +53 -2
  116. package/lib/commonjs/networking/xmpp/sendMediaMessage.xmpp.js.map +1 -1
  117. package/lib/commonjs/networking/xmpp/sendReceivedReceipt.xmpp.js +28 -0
  118. package/lib/commonjs/networking/xmpp/sendReceivedReceipt.xmpp.js.map +1 -0
  119. package/lib/commonjs/networking/xmppClient.js +64 -0
  120. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  121. package/lib/commonjs/roomStore/persistence.js +78 -5
  122. package/lib/commonjs/roomStore/persistence.js.map +1 -1
  123. package/lib/commonjs/roomStore/roomHeapSlice.js +4 -0
  124. package/lib/commonjs/roomStore/roomHeapSlice.js.map +1 -1
  125. package/lib/commonjs/roomStore/roomsSlice.js +114 -1
  126. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  127. package/lib/commonjs/types/models/attachment.model.js +2 -0
  128. package/lib/commonjs/types/models/attachment.model.js.map +1 -0
  129. package/lib/commonjs/version.js +1 -1
  130. package/lib/module/assets/icons.js +1 -1
  131. package/lib/module/assets/icons.js.map +1 -1
  132. package/lib/module/components/MainComponents/AlbumGrid.js +146 -0
  133. package/lib/module/components/MainComponents/AlbumGrid.js.map +1 -0
  134. package/lib/module/components/MainComponents/ChatRoom.js +2 -2
  135. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  136. package/lib/module/components/MainComponents/MediaMessage.js +200 -124
  137. package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
  138. package/lib/module/components/MainComponents/MediaUploadOverlay.js +104 -0
  139. package/lib/module/components/MainComponents/MediaUploadOverlay.js.map +1 -0
  140. package/lib/module/components/MessageBubble/MediaCaption.js +46 -0
  141. package/lib/module/components/MessageBubble/MediaCaption.js.map +1 -0
  142. package/lib/module/components/MessageBubble/Message.js +44 -5
  143. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  144. package/lib/module/components/MessageBubble/MessageInteractions.js +2 -1
  145. package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
  146. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +75 -0
  147. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  148. package/lib/module/components/RoomComponents/LastMessageItem.js +20 -4
  149. package/lib/module/components/RoomComponents/LastMessageItem.js.map +1 -1
  150. package/lib/module/components/RoomComponents/styled/LastAudioMessage.js +3 -2
  151. package/lib/module/components/RoomComponents/styled/LastAudioMessage.js.map +1 -1
  152. package/lib/module/components/RoomComponents/styled/LastMessageFile.js +3 -2
  153. package/lib/module/components/RoomComponents/styled/LastMessageFile.js.map +1 -1
  154. package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js +3 -2
  155. package/lib/module/components/RoomComponents/styled/LastMessagePhoto.js.map +1 -1
  156. package/lib/module/components/RoomComponents/styled/LastMessageVideo.js +3 -2
  157. package/lib/module/components/RoomComponents/styled/LastMessageVideo.js.map +1 -1
  158. package/lib/module/components/Thread/ThreadWrapper.js +3 -2
  159. package/lib/module/components/Thread/ThreadWrapper.js.map +1 -1
  160. package/lib/module/components/VideoCalls/ActiveCallBar.js +63 -18
  161. package/lib/module/components/VideoCalls/ActiveCallBar.js.map +1 -1
  162. package/lib/module/components/VideoCalls/CallIcons.js +38 -15
  163. package/lib/module/components/VideoCalls/CallIcons.js.map +1 -1
  164. package/lib/module/components/VideoCalls/VideoCallOverlay.js +185 -11
  165. package/lib/module/components/VideoCalls/VideoCallOverlay.js.map +1 -1
  166. package/lib/module/components/VideoCalls/VideoCallSession.js +41 -16
  167. package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -1
  168. package/lib/module/components/VideoCalls/callSessionController.js +46 -24
  169. package/lib/module/components/VideoCalls/callSessionController.js.map +1 -1
  170. package/lib/module/components/VideoCalls/callUiStore.js +30 -3
  171. package/lib/module/components/VideoCalls/callUiStore.js.map +1 -1
  172. package/lib/module/components/VideoCalls/livekitRuntime.js +9 -1
  173. package/lib/module/components/VideoCalls/livekitRuntime.js.map +1 -1
  174. package/lib/module/components/VideoCalls/useCallKeep.js +198 -29
  175. package/lib/module/components/VideoCalls/useCallKeep.js.map +1 -1
  176. package/lib/module/components/VideoCalls/useOngoingCallNotification.js +84 -0
  177. package/lib/module/components/VideoCalls/useOngoingCallNotification.js.map +1 -0
  178. package/lib/module/components/VideoCalls/usePipTile.js +228 -0
  179. package/lib/module/components/VideoCalls/usePipTile.js.map +1 -0
  180. package/lib/module/components/styled/MediaFilePreview.js +61 -48
  181. package/lib/module/components/styled/MediaFilePreview.js.map +1 -1
  182. package/lib/module/components/styled/MessageImage.js +16 -6
  183. package/lib/module/components/styled/MessageImage.js.map +1 -1
  184. package/lib/module/components/styled/SendInput.js +99 -68
  185. package/lib/module/components/styled/SendInput.js.map +1 -1
  186. package/lib/module/components/styled/VideoMessage.js +24 -10
  187. package/lib/module/components/styled/VideoMessage.js.map +1 -1
  188. package/lib/module/context/xmppProvider.js +46 -0
  189. package/lib/module/context/xmppProvider.js.map +1 -1
  190. package/lib/module/e2ee/fileEnvelope.js +1 -1
  191. package/lib/module/e2ee/fileEnvelope.js.map +1 -1
  192. package/lib/module/e2ee/sealedBody.js +32 -2
  193. package/lib/module/e2ee/sealedBody.js.map +1 -1
  194. package/lib/module/helpers/albumLayout.js +143 -0
  195. package/lib/module/helpers/albumLayout.js.map +1 -0
  196. package/lib/module/helpers/attachments.js +245 -0
  197. package/lib/module/helpers/attachments.js.map +1 -0
  198. package/lib/module/helpers/caption.js +207 -0
  199. package/lib/module/helpers/caption.js.map +1 -0
  200. package/lib/module/helpers/createMainMessageForThread.js +5 -1
  201. package/lib/module/helpers/createMainMessageForThread.js.map +1 -1
  202. package/lib/module/helpers/createMessageFromXml.js +20 -6
  203. package/lib/module/helpers/createMessageFromXml.js.map +1 -1
  204. package/lib/module/helpers/fileKind.js +34 -0
  205. package/lib/module/helpers/fileKind.js.map +1 -0
  206. package/lib/module/helpers/getDataFromXml.js +6 -1
  207. package/lib/module/helpers/getDataFromXml.js.map +1 -1
  208. package/lib/module/helpers/mapWithConcurrency.js +37 -0
  209. package/lib/module/helpers/mapWithConcurrency.js.map +1 -0
  210. package/lib/module/helpers/mediaLimits.js +27 -0
  211. package/lib/module/helpers/mediaLimits.js.map +1 -0
  212. package/lib/module/helpers/mediaSendRetry.js +55 -0
  213. package/lib/module/helpers/mediaSendRetry.js.map +1 -0
  214. package/lib/module/helpers/mediaWireData.js +58 -0
  215. package/lib/module/helpers/mediaWireData.js.map +1 -0
  216. package/lib/module/helpers/mentionSpans.js +14 -0
  217. package/lib/module/helpers/mentionSpans.js.map +1 -0
  218. package/lib/module/helpers/mimeToExtension.js +43 -0
  219. package/lib/module/helpers/mimeToExtension.js.map +1 -1
  220. package/lib/module/helpers/readReceipts.js +160 -0
  221. package/lib/module/helpers/readReceipts.js.map +1 -0
  222. package/lib/module/helpers/repairFilenameEncoding.js +74 -0
  223. package/lib/module/helpers/repairFilenameEncoding.js.map +1 -0
  224. package/lib/module/helpers/safeJson.js +13 -0
  225. package/lib/module/helpers/safeJson.js.map +1 -0
  226. package/lib/module/helpers/updateMessagesTillLast.js +3 -1
  227. package/lib/module/helpers/updateMessagesTillLast.js.map +1 -1
  228. package/lib/module/hooks/useSendMessage.js +387 -195
  229. package/lib/module/hooks/useSendMessage.js.map +1 -1
  230. package/lib/module/i18n/strings.js +144 -0
  231. package/lib/module/i18n/strings.js.map +1 -1
  232. package/lib/module/main.js.map +1 -1
  233. package/lib/module/networking/api-requests/auth.api.js +62 -3
  234. package/lib/module/networking/api-requests/auth.api.js.map +1 -1
  235. package/lib/module/networking/stanzaHandlers.js +97 -4
  236. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  237. package/lib/module/networking/xmpp/handleStanzas.xmpp.js +5 -3
  238. package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  239. package/lib/module/networking/xmpp/sendDisplayedMarker.xmpp.js +25 -0
  240. package/lib/module/networking/xmpp/sendDisplayedMarker.xmpp.js.map +1 -0
  241. package/lib/module/networking/xmpp/sendMediaMessage.xmpp.js +53 -2
  242. package/lib/module/networking/xmpp/sendMediaMessage.xmpp.js.map +1 -1
  243. package/lib/module/networking/xmpp/sendReceivedReceipt.xmpp.js +25 -0
  244. package/lib/module/networking/xmpp/sendReceivedReceipt.xmpp.js.map +1 -0
  245. package/lib/module/networking/xmppClient.js +64 -0
  246. package/lib/module/networking/xmppClient.js.map +1 -1
  247. package/lib/module/roomStore/persistence.js +78 -5
  248. package/lib/module/roomStore/persistence.js.map +1 -1
  249. package/lib/module/roomStore/roomHeapSlice.js +4 -0
  250. package/lib/module/roomStore/roomHeapSlice.js.map +1 -1
  251. package/lib/module/roomStore/roomsSlice.js +109 -0
  252. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  253. package/lib/module/types/models/attachment.model.js +2 -0
  254. package/lib/module/types/models/attachment.model.js.map +1 -0
  255. package/lib/module/version.js +1 -1
  256. package/lib/typescript/assets/icons.d.ts +6 -1
  257. package/lib/typescript/assets/icons.d.ts.map +1 -1
  258. package/lib/typescript/components/MainComponents/AlbumGrid.d.ts +21 -0
  259. package/lib/typescript/components/MainComponents/AlbumGrid.d.ts.map +1 -0
  260. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  261. package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
  262. package/lib/typescript/components/MainComponents/MediaUploadOverlay.d.ts +17 -0
  263. package/lib/typescript/components/MainComponents/MediaUploadOverlay.d.ts.map +1 -0
  264. package/lib/typescript/components/MessageBubble/MediaCaption.d.ts +12 -0
  265. package/lib/typescript/components/MessageBubble/MediaCaption.d.ts.map +1 -0
  266. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  267. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
  268. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
  269. package/lib/typescript/components/RoomComponents/LastMessageItem.d.ts.map +1 -1
  270. package/lib/typescript/components/RoomComponents/styled/LastAudioMessage.d.ts +2 -0
  271. package/lib/typescript/components/RoomComponents/styled/LastAudioMessage.d.ts.map +1 -1
  272. package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts +2 -0
  273. package/lib/typescript/components/RoomComponents/styled/LastMessageFile.d.ts.map +1 -1
  274. package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts +2 -0
  275. package/lib/typescript/components/RoomComponents/styled/LastMessagePhoto.d.ts.map +1 -1
  276. package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts +2 -0
  277. package/lib/typescript/components/RoomComponents/styled/LastMessageVideo.d.ts.map +1 -1
  278. package/lib/typescript/components/Thread/ThreadWrapper.d.ts.map +1 -1
  279. package/lib/typescript/components/VideoCalls/ActiveCallBar.d.ts +9 -3
  280. package/lib/typescript/components/VideoCalls/ActiveCallBar.d.ts.map +1 -1
  281. package/lib/typescript/components/VideoCalls/CallIcons.d.ts +9 -0
  282. package/lib/typescript/components/VideoCalls/CallIcons.d.ts.map +1 -1
  283. package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts.map +1 -1
  284. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -1
  285. package/lib/typescript/components/VideoCalls/callSessionController.d.ts +7 -0
  286. package/lib/typescript/components/VideoCalls/callSessionController.d.ts.map +1 -1
  287. package/lib/typescript/components/VideoCalls/callUiStore.d.ts +13 -0
  288. package/lib/typescript/components/VideoCalls/callUiStore.d.ts.map +1 -1
  289. package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts +5 -0
  290. package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts.map +1 -1
  291. package/lib/typescript/components/VideoCalls/useCallKeep.d.ts +12 -0
  292. package/lib/typescript/components/VideoCalls/useCallKeep.d.ts.map +1 -1
  293. package/lib/typescript/components/VideoCalls/useOngoingCallNotification.d.ts +10 -0
  294. package/lib/typescript/components/VideoCalls/useOngoingCallNotification.d.ts.map +1 -0
  295. package/lib/typescript/components/VideoCalls/usePipTile.d.ts +46 -0
  296. package/lib/typescript/components/VideoCalls/usePipTile.d.ts.map +1 -0
  297. package/lib/typescript/components/styled/MediaFilePreview.d.ts.map +1 -1
  298. package/lib/typescript/components/styled/MessageImage.d.ts +10 -0
  299. package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
  300. package/lib/typescript/components/styled/SendInput.d.ts +7 -1
  301. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  302. package/lib/typescript/components/styled/VideoMessage.d.ts +7 -0
  303. package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
  304. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  305. package/lib/typescript/e2ee/fileEnvelope.d.ts +1 -1
  306. package/lib/typescript/e2ee/fileEnvelope.d.ts.map +1 -1
  307. package/lib/typescript/e2ee/sealedBody.d.ts +16 -0
  308. package/lib/typescript/e2ee/sealedBody.d.ts.map +1 -1
  309. package/lib/typescript/helpers/albumLayout.d.ts +66 -0
  310. package/lib/typescript/helpers/albumLayout.d.ts.map +1 -0
  311. package/lib/typescript/helpers/attachments.d.ts +55 -0
  312. package/lib/typescript/helpers/attachments.d.ts.map +1 -0
  313. package/lib/typescript/helpers/caption.d.ts +64 -0
  314. package/lib/typescript/helpers/caption.d.ts.map +1 -0
  315. package/lib/typescript/helpers/createMainMessageForThread.d.ts.map +1 -1
  316. package/lib/typescript/helpers/createMessageFromXml.d.ts.map +1 -1
  317. package/lib/typescript/helpers/fileKind.d.ts +20 -0
  318. package/lib/typescript/helpers/fileKind.d.ts.map +1 -0
  319. package/lib/typescript/helpers/getDataFromXml.d.ts.map +1 -1
  320. package/lib/typescript/helpers/mapWithConcurrency.d.ts +9 -0
  321. package/lib/typescript/helpers/mapWithConcurrency.d.ts.map +1 -0
  322. package/lib/typescript/helpers/mediaLimits.d.ts +13 -0
  323. package/lib/typescript/helpers/mediaLimits.d.ts.map +1 -0
  324. package/lib/typescript/helpers/mediaSendRetry.d.ts +26 -0
  325. package/lib/typescript/helpers/mediaSendRetry.d.ts.map +1 -0
  326. package/lib/typescript/helpers/mediaWireData.d.ts +16 -0
  327. package/lib/typescript/helpers/mediaWireData.d.ts.map +1 -0
  328. package/lib/typescript/helpers/mentionSpans.d.ts +8 -0
  329. package/lib/typescript/helpers/mentionSpans.d.ts.map +1 -0
  330. package/lib/typescript/helpers/mimeToExtension.d.ts +7 -0
  331. package/lib/typescript/helpers/mimeToExtension.d.ts.map +1 -1
  332. package/lib/typescript/helpers/readReceipts.d.ts +82 -0
  333. package/lib/typescript/helpers/readReceipts.d.ts.map +1 -0
  334. package/lib/typescript/helpers/repairFilenameEncoding.d.ts +12 -0
  335. package/lib/typescript/helpers/repairFilenameEncoding.d.ts.map +1 -0
  336. package/lib/typescript/helpers/safeJson.d.ts +2 -0
  337. package/lib/typescript/helpers/safeJson.d.ts.map +1 -0
  338. package/lib/typescript/helpers/updateMessagesTillLast.d.ts.map +1 -1
  339. package/lib/typescript/hooks/useSendMessage.d.ts +2 -1
  340. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  341. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  342. package/lib/typescript/main.d.ts +1 -1
  343. package/lib/typescript/main.d.ts.map +1 -1
  344. package/lib/typescript/networking/api-requests/auth.api.d.ts +2 -0
  345. package/lib/typescript/networking/api-requests/auth.api.d.ts.map +1 -1
  346. package/lib/typescript/networking/stanzaHandlers.d.ts +7 -3
  347. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  348. package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
  349. package/lib/typescript/networking/xmpp/sendDisplayedMarker.xmpp.d.ts +3 -0
  350. package/lib/typescript/networking/xmpp/sendDisplayedMarker.xmpp.d.ts.map +1 -0
  351. package/lib/typescript/networking/xmpp/sendMediaMessage.xmpp.d.ts +12 -0
  352. package/lib/typescript/networking/xmpp/sendMediaMessage.xmpp.d.ts.map +1 -1
  353. package/lib/typescript/networking/xmpp/sendReceivedReceipt.xmpp.d.ts +3 -0
  354. package/lib/typescript/networking/xmpp/sendReceivedReceipt.xmpp.d.ts.map +1 -0
  355. package/lib/typescript/networking/xmppClient.d.ts +15 -0
  356. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  357. package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
  358. package/lib/typescript/roomStore/roomHeapSlice.d.ts +22 -1
  359. package/lib/typescript/roomStore/roomHeapSlice.d.ts.map +1 -1
  360. package/lib/typescript/roomStore/roomsSlice.d.ts +67 -3
  361. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  362. package/lib/typescript/types/models/attachment.model.d.ts +52 -0
  363. package/lib/typescript/types/models/attachment.model.d.ts.map +1 -0
  364. package/lib/typescript/types/models/message.model.d.ts +26 -0
  365. package/lib/typescript/types/models/message.model.d.ts.map +1 -1
  366. package/lib/typescript/types/models/modal.model.d.ts +7 -0
  367. package/lib/typescript/types/models/modal.model.d.ts.map +1 -1
  368. package/lib/typescript/types/models/room.model.d.ts +2 -0
  369. package/lib/typescript/types/models/room.model.d.ts.map +1 -1
  370. package/lib/typescript/types/types.d.ts +69 -1
  371. package/lib/typescript/types/types.d.ts.map +1 -1
  372. package/lib/typescript/version.d.ts +1 -1
  373. package/package.json +4 -1
  374. package/plugins/notification-service/Info.plist +31 -0
  375. package/plugins/notification-service/NotificationService.swift +82 -0
  376. package/plugins/withNotificationServiceExtension.js +137 -0
  377. package/src/assets/icons.tsx +20 -2
  378. package/src/components/MainComponents/AlbumGrid.tsx +183 -0
  379. package/src/components/MainComponents/ChatRoom.tsx +4 -2
  380. package/src/components/MainComponents/MediaMessage.tsx +246 -130
  381. package/src/components/MainComponents/MediaUploadOverlay.tsx +102 -0
  382. package/src/components/MessageBubble/MediaCaption.tsx +45 -0
  383. package/src/components/MessageBubble/Message.tsx +71 -3
  384. package/src/components/MessageBubble/MessageInteractions.tsx +2 -1
  385. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +64 -0
  386. package/src/components/RoomComponents/LastMessageItem.tsx +15 -4
  387. package/src/components/RoomComponents/styled/LastAudioMessage.tsx +6 -3
  388. package/src/components/RoomComponents/styled/LastMessageFile.tsx +6 -2
  389. package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +6 -2
  390. package/src/components/RoomComponents/styled/LastMessageVideo.tsx +6 -2
  391. package/src/components/Thread/ThreadWrapper.tsx +5 -9
  392. package/src/components/VideoCalls/ActiveCallBar.tsx +56 -10
  393. package/src/components/VideoCalls/CallIcons.tsx +36 -12
  394. package/src/components/VideoCalls/VideoCallOverlay.tsx +205 -8
  395. package/src/components/VideoCalls/VideoCallSession.tsx +45 -13
  396. package/src/components/VideoCalls/callSessionController.ts +51 -20
  397. package/src/components/VideoCalls/callUiStore.ts +33 -3
  398. package/src/components/VideoCalls/livekitRuntime.ts +13 -0
  399. package/src/components/VideoCalls/useCallKeep.ts +204 -33
  400. package/src/components/VideoCalls/useOngoingCallNotification.ts +113 -0
  401. package/src/components/VideoCalls/usePipTile.ts +214 -0
  402. package/src/components/styled/MediaFilePreview.tsx +49 -34
  403. package/src/components/styled/MessageImage.tsx +21 -5
  404. package/src/components/styled/SendInput.tsx +101 -87
  405. package/src/components/styled/VideoMessage.tsx +34 -9
  406. package/src/context/xmppProvider.tsx +32 -0
  407. package/src/e2ee/fileEnvelope.ts +1 -1
  408. package/src/e2ee/sealedBody.ts +44 -5
  409. package/src/helpers/albumLayout.ts +207 -0
  410. package/src/helpers/attachments.ts +316 -0
  411. package/src/helpers/caption.ts +283 -0
  412. package/src/helpers/createMainMessageForThread.ts +6 -1
  413. package/src/helpers/createMessageFromXml.ts +21 -5
  414. package/src/helpers/fileKind.ts +38 -0
  415. package/src/helpers/getDataFromXml.ts +5 -1
  416. package/src/helpers/mapWithConcurrency.ts +32 -0
  417. package/src/helpers/mediaLimits.ts +27 -0
  418. package/src/helpers/mediaSendRetry.ts +59 -0
  419. package/src/helpers/mediaWireData.ts +57 -0
  420. package/src/helpers/mentionSpans.ts +17 -0
  421. package/src/helpers/mimeToExtension.ts +51 -0
  422. package/src/helpers/readReceipts.ts +219 -0
  423. package/src/helpers/repairFilenameEncoding.ts +82 -0
  424. package/src/helpers/safeJson.ts +11 -0
  425. package/src/helpers/updateMessagesTillLast.tsx +2 -1
  426. package/src/hooks/useSendMessage.tsx +448 -249
  427. package/src/i18n/strings.ts +144 -0
  428. package/src/main.ts +3 -0
  429. package/src/networking/api-requests/auth.api.ts +60 -3
  430. package/src/networking/stanzaHandlers.ts +91 -2
  431. package/src/networking/xmpp/handleStanzas.xmpp.ts +6 -2
  432. package/src/networking/xmpp/sendDisplayedMarker.xmpp.ts +31 -0
  433. package/src/networking/xmpp/sendMediaMessage.xmpp.ts +60 -3
  434. package/src/networking/xmpp/sendReceivedReceipt.xmpp.ts +31 -0
  435. package/src/networking/xmppClient.ts +48 -0
  436. package/src/roomStore/persistence.ts +94 -3
  437. package/src/roomStore/roomHeapSlice.ts +23 -1
  438. package/src/roomStore/roomsSlice.ts +112 -1
  439. package/src/types/models/attachment.model.ts +51 -0
  440. package/src/types/models/message.model.ts +29 -0
  441. package/src/types/models/modal.model.ts +7 -0
  442. package/src/types/models/room.model.ts +2 -0
  443. package/src/types/types.ts +83 -1
  444. package/src/version.ts +1 -1
  445. package/lib/commonjs/components/VideoCalls/useDraggable.js +0 -59
  446. package/lib/commonjs/components/VideoCalls/useDraggable.js.map +0 -1
  447. package/lib/module/components/VideoCalls/useDraggable.js +0 -55
  448. package/lib/module/components/VideoCalls/useDraggable.js.map +0 -1
  449. package/lib/typescript/components/VideoCalls/useDraggable.d.ts +0 -19
  450. package/lib/typescript/components/VideoCalls/useDraggable.d.ts.map +0 -1
  451. package/src/components/VideoCalls/useDraggable.ts +0 -46
@@ -0,0 +1,102 @@
1
+ import React from 'react';
2
+ import { ActivityIndicator, Pressable, StyleSheet, Text, View } from 'react-native';
3
+ import { useT } from '../../i18n/useT';
4
+
5
+ interface MediaUploadOverlayProps {
6
+ /** `uploading` shows progress; `failed` shows the reason and a Retry. */
7
+ status: 'uploading' | 'failed';
8
+ /** 0 to 100, while uploading. */
9
+ progress?: number;
10
+ /** Re-runs this file's upload. Only offered for a failed file. */
11
+ onRetry?: () => void;
12
+ }
13
+
14
+ /**
15
+ * Covers one tile of an outgoing media message while its file uploads, and
16
+ * offers Retry when it did not. The scrim sits on the picture itself, so its
17
+ * colours are fixed rather than taken from the theme.
18
+ */
19
+ const MediaUploadOverlay: React.FC<MediaUploadOverlayProps> = ({
20
+ status,
21
+ progress = 0,
22
+ onRetry,
23
+ }) => {
24
+ const t = useT();
25
+ const percent = Math.min(100, Math.max(0, Math.round(progress)));
26
+
27
+ if (status === 'failed') {
28
+ return (
29
+ <View testID="media-upload-overlay" style={styles.overlay}>
30
+ <Text style={styles.failedText}>{t('attachment.uploadFailed')}</Text>
31
+ {onRetry && (
32
+ <Pressable
33
+ testID="media-upload-retry"
34
+ accessibilityRole="button"
35
+ accessibilityLabel={t('attachment.retryUpload')}
36
+ onPress={onRetry}
37
+ style={styles.retry}
38
+ >
39
+ <Text style={styles.retryText}>{t('attachment.retryUpload')}</Text>
40
+ </Pressable>
41
+ )}
42
+ </View>
43
+ );
44
+ }
45
+
46
+ return (
47
+ <View testID="media-upload-overlay" style={styles.overlay}>
48
+ <ActivityIndicator size="small" color="#FFFFFF" />
49
+ <Text style={styles.progressText}>{`${percent}%`}</Text>
50
+ <View style={styles.track} accessibilityRole="progressbar">
51
+ <View style={[styles.fill, { width: `${percent}%` }]} />
52
+ </View>
53
+ </View>
54
+ );
55
+ };
56
+
57
+ export default MediaUploadOverlay;
58
+
59
+ const styles = StyleSheet.create({
60
+ overlay: {
61
+ ...StyleSheet.absoluteFill,
62
+ alignItems: 'center',
63
+ justifyContent: 'center',
64
+ gap: 6,
65
+ padding: 8,
66
+ backgroundColor: 'rgba(8, 12, 24, 0.5)',
67
+ },
68
+ progressText: {
69
+ color: '#FFFFFF',
70
+ fontSize: 13,
71
+ fontWeight: '600',
72
+ },
73
+ track: {
74
+ position: 'absolute',
75
+ left: 0,
76
+ right: 0,
77
+ bottom: 0,
78
+ height: 3,
79
+ backgroundColor: 'rgba(255, 255, 255, 0.3)',
80
+ },
81
+ fill: {
82
+ height: 3,
83
+ backgroundColor: '#FFFFFF',
84
+ },
85
+ failedText: {
86
+ color: '#FFFFFF',
87
+ fontSize: 13,
88
+ fontWeight: '600',
89
+ textAlign: 'center',
90
+ },
91
+ retry: {
92
+ paddingHorizontal: 12,
93
+ paddingVertical: 5,
94
+ borderRadius: 14,
95
+ backgroundColor: '#FFFFFF',
96
+ },
97
+ retryText: {
98
+ color: '#111827',
99
+ fontSize: 13,
100
+ fontWeight: '700',
101
+ },
102
+ });
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { StyleSheet, Text } from 'react-native';
3
+ import { useChatSettingState } from '../../hooks/useChatSettingState';
4
+ import { useTheme } from '../../hooks/useTheme';
5
+
6
+ interface MediaCaptionProps {
7
+ text?: string;
8
+ isUser: boolean;
9
+ }
10
+
11
+ /**
12
+ * The text sent with a media message, under the media inside the bubble.
13
+ * Plain text: mention spans are stored on the message but not rendered here.
14
+ */
15
+ const MediaCaption: React.FC<MediaCaptionProps> = ({ text, isUser }) => {
16
+ const theme = useTheme();
17
+ const { config } = useChatSettingState();
18
+ if (!text) {return null;}
19
+ const typography = config?.typography?.messageText;
20
+ return (
21
+ <Text
22
+ testID="media-caption"
23
+ style={[
24
+ styles.caption,
25
+ { color: isUser ? theme.messageTextUser : theme.messageText },
26
+ typography?.fontSize ? { fontSize: typography.fontSize } : null,
27
+ typography?.fontWeight ? { fontWeight: typography.fontWeight as any } : null,
28
+ ]}
29
+ >
30
+ {text}
31
+ </Text>
32
+ );
33
+ };
34
+
35
+ export default MediaCaption;
36
+
37
+ const styles = StyleSheet.create({
38
+ caption: {
39
+ fontSize: 16,
40
+ paddingHorizontal: 12,
41
+ paddingTop: 6,
42
+ paddingBottom: 2,
43
+ alignSelf: 'stretch',
44
+ },
45
+ });
@@ -1,4 +1,5 @@
1
1
  import React, {
2
+ useCallback,
2
3
  useEffect,
3
4
  useMemo,
4
5
  useRef,
@@ -15,7 +16,7 @@ import {
15
16
  Text,
16
17
  Keyboard,
17
18
  } from 'react-native';
18
- import { useDispatch, useSelector } from 'react-redux';
19
+ import { shallowEqual, useDispatch, useSelector, useStore } from 'react-redux';
19
20
  import { RootState } from '../../roomStore';
20
21
  import { Avatar } from './Avatar';
21
22
  import { BubbleHighlight } from './BubbleHighlight';
@@ -43,7 +44,7 @@ import { useChatSettingState } from '../../hooks/useChatSettingState';
43
44
  import { parseMessageBody } from '../../helpers/parseMessageBody';
44
45
  import { chatTextStyle } from '../../helpers/typography';
45
46
  import { useMessageHeapState } from '../../hooks/useMessageHeapState';
46
- import { DoubleTick, LockIcon, LockOffIcon } from '../../assets/icons';
47
+ import { DoubleTick, LockIcon, LockOffIcon, SingleTick } from '../../assets/icons';
47
48
  import { useT } from '../../i18n/useT';
48
49
  import { useFileToken } from '../../hooks/useFileToken';
49
50
  import {
@@ -66,6 +67,17 @@ import {
66
67
  requestUsers,
67
68
  subscribeUserResolver,
68
69
  } from '../../helpers/userResolver';
70
+ import {
71
+ deliveredToOthers,
72
+ describeReceipt,
73
+ getReceiptStatus,
74
+ receiptNameFor,
75
+ selectSeenBy,
76
+ statusOf,
77
+ } from '../../helpers/readReceipts';
78
+
79
+ // Shared empty result for the seen-by selector (keeps shallowEqual cheap).
80
+ const NO_RECEIPT_VIEWERS: string[] = [];
69
81
 
70
82
  // Stable-width stand-in for the sender name while its lookup is pending.
71
83
  const SENDER_NAME_PLACEHOLDER = '\u2026';
@@ -507,6 +519,42 @@ const Message: React.FC<MessageProps> = ({ message, isUser, isReply }) => {
507
519
  const isPending =
508
520
  !isFailed && (idSet.has(message.id) || message?.pending || false);
509
521
 
522
+ // Delivery and read state of our own messages (XEP-0184 / XEP-0333). The
523
+ // seen list is a small array compared shallowly, so a bubble only renders
524
+ // again when its own readers change, not on every message in the room.
525
+ // Same identity the list uses to decide ownership (MessageList passes
526
+ // xmppUsername || walletAddress), so the tick and the watermark agree.
527
+ const selfXmppUsername = user?.xmppUsername || user?.walletAddress || '';
528
+ const seenBy = useSelector(
529
+ (state: RootState) =>
530
+ isUser
531
+ ? selectSeenBy(state, message.roomJid, String(message.id), selfXmppUsername)
532
+ : NO_RECEIPT_VIEWERS,
533
+ shallowEqual
534
+ );
535
+ const readStatus = statusOf(
536
+ seenBy,
537
+ isUser ? deliveredToOthers(message, selfXmppUsername) : []
538
+ );
539
+ const reduxStore = useStore<RootState>();
540
+ // Touch (no hover on mobile): the details sheet names who read or got it.
541
+ const onReceiptPress = useCallback(() => {
542
+ const state = reduxStore.getState();
543
+ const room = state.rooms.rooms[message.roomJid];
544
+ const details = getReceiptStatus(message, room, selfXmppUsername);
545
+ Alert.alert(
546
+ describeReceipt({
547
+ status: details.status,
548
+ isGroup: room?.type !== 'private',
549
+ seenBy: details.seenBy,
550
+ deliveredTo: details.deliveredTo,
551
+ nameOf: (xmppUsername) =>
552
+ receiptNameFor(state.rooms.usersSet, xmppUsername),
553
+ t,
554
+ })
555
+ );
556
+ }, [reduxStore, message, selfXmppUsername, t]);
557
+
510
558
  const onRetryPress = () => {
511
559
  if (isFailed) {retryMessage(message.id);}
512
560
  };
@@ -667,7 +715,27 @@ const Message: React.FC<MessageProps> = ({ message, isUser, isReply }) => {
667
715
  {timeLabel}
668
716
  </Text>
669
717
  {!config?.disableSentLogic && isUser && !isPending && !isFailed && (
670
- <DoubleTick />
718
+ <Pressable
719
+ onPress={onReceiptPress}
720
+ hitSlop={10}
721
+ accessibilityRole="button"
722
+ accessibilityLabel={
723
+ readStatus === 'seen'
724
+ ? t('message.receipt.read')
725
+ : readStatus === 'delivered'
726
+ ? t('message.receipt.delivered')
727
+ : t('message.receipt.sent')
728
+ }
729
+ testID="message-receipt-tick"
730
+ >
731
+ {readStatus === 'sent' ? (
732
+ <SingleTick stroke={theme.textMuted} />
733
+ ) : (
734
+ <DoubleTick
735
+ stroke={readStatus === 'seen' ? theme.primary : theme.textMuted}
736
+ />
737
+ )}
738
+ </Pressable>
671
739
  )}
672
740
  </CustomTimestampRow>
673
741
 
@@ -26,6 +26,7 @@ import { useInteractionsOverlay } from './InteractionsOverlay';
26
26
  import { useTheme } from '../../hooks/useTheme';
27
27
  import { useT } from '../../i18n/useT';
28
28
  import { getEmojiNativeById } from '../../helpers/emoji';
29
+ import { getMessageCaption } from '../../helpers/caption';
29
30
  import {
30
31
  quickReactionIds,
31
32
  reactionPickerEnabled,
@@ -376,7 +377,7 @@ const MessageInteractions: React.FC<MessageInteractionsProps> = ({
376
377
  <Delimeter />
377
378
  </>
378
379
  )}
379
- <MenuItem onPress={() => handleCopyMessage(message.body!)}>
380
+ <MenuItem onPress={() => handleCopyMessage(getMessageCaption(message) ?? message.body!)}>
380
381
  <Text style={[styles.menuText, themedStyles.text]}>
381
382
  {MESSAGE_INTERACTIONS.COPY}
382
383
  </Text>
@@ -430,6 +430,17 @@ const FilePreviewModal: React.FC<FilePreviewModalProps> = ({
430
430
  }
431
431
  };
432
432
 
433
+ // An album opens with its siblings; the viewer pages through them.
434
+ const albumSize = activeFile.siblings?.length ?? 0;
435
+ const albumIndex = activeFile.index ?? 0;
436
+ const goToSibling = (next: number) => {
437
+ const target = activeFile.siblings?.[next];
438
+ if (!target) {return;}
439
+ dispatch(
440
+ setActiveFile({ ...target, siblings: activeFile.siblings, index: next })
441
+ );
442
+ };
443
+
433
444
  const closeModal = () => {
434
445
  dispatch(
435
446
  setActiveFile({
@@ -606,6 +617,39 @@ const FilePreviewModal: React.FC<FilePreviewModalProps> = ({
606
617
  {getMediaComponent}
607
618
  </CenterContainer>
608
619
 
620
+ {albumSize > 1 && (
621
+ <View style={styles.albumNav} testID="file-preview-album-nav">
622
+ <TouchableOpacity
623
+ testID="file-preview-prev"
624
+ accessibilityRole="button"
625
+ accessibilityLabel={t('attachment.previous')}
626
+ disabled={albumIndex <= 0}
627
+ onPress={() => goToSibling(albumIndex - 1)}
628
+ hitSlop={12}
629
+ style={[styles.albumArrow, albumIndex <= 0 && styles.albumArrowOff]}
630
+ >
631
+ <Text style={[styles.albumArrowText, { color: theme.text }]}>{'\u2039'}</Text>
632
+ </TouchableOpacity>
633
+ <Text style={{ color: theme.textSecondary }}>
634
+ {t('attachment.position', { index: albumIndex + 1, total: albumSize })}
635
+ </Text>
636
+ <TouchableOpacity
637
+ testID="file-preview-next"
638
+ accessibilityRole="button"
639
+ accessibilityLabel={t('attachment.next')}
640
+ disabled={albumIndex >= albumSize - 1}
641
+ onPress={() => goToSibling(albumIndex + 1)}
642
+ hitSlop={12}
643
+ style={[
644
+ styles.albumArrow,
645
+ albumIndex >= albumSize - 1 && styles.albumArrowOff,
646
+ ]}
647
+ >
648
+ <Text style={[styles.albumArrowText, { color: theme.text }]}>{'\u203A'}</Text>
649
+ </TouchableOpacity>
650
+ </View>
651
+ )}
652
+
609
653
  </ModalContainerFullScreen>
610
654
  );
611
655
  };
@@ -629,6 +673,26 @@ const styles = StyleSheet.create({
629
673
  fontSize: 13,
630
674
  fontWeight: '600',
631
675
  },
676
+ albumNav: {
677
+ flexDirection: 'row',
678
+ alignItems: 'center',
679
+ justifyContent: 'center',
680
+ gap: 24,
681
+ paddingBottom: 24,
682
+ },
683
+ albumArrow: {
684
+ width: 44,
685
+ height: 44,
686
+ alignItems: 'center',
687
+ justifyContent: 'center',
688
+ },
689
+ albumArrowOff: {
690
+ opacity: 0.3,
691
+ },
692
+ albumArrowText: {
693
+ fontSize: 32,
694
+ lineHeight: 36,
695
+ },
632
696
  videoMessage: {
633
697
  alignItems: 'center',
634
698
  gap: 8,
@@ -7,12 +7,16 @@ import LastMessageEmoji from './styled/LastMessageEmoji';
7
7
  import LastMessageFile from './styled/LastMessageFile';
8
8
  import LastAudioMessage from './styled/LastAudioMessage';
9
9
  import LastMessageSealed from './styled/LastMessageSealed';
10
+ import { getMessageAttachments } from '../../helpers/attachments';
11
+ import { getMessageCaption } from '../../helpers/caption';
12
+ import { useT } from '../../i18n/useT';
10
13
 
11
14
  interface LastMessageItemProps {
12
15
  lastMessage: LastMessage;
13
16
  }
14
17
 
15
18
  const LastMessageItem: FC<LastMessageItemProps> = ({ lastMessage }) => {
19
+ const t = useT();
16
20
  const { body, emoji, mimetype } = lastMessage;
17
21
 
18
22
  if (lastMessage?.clientEncrypted === 'true') {
@@ -20,22 +24,29 @@ const LastMessageItem: FC<LastMessageItemProps> = ({ lastMessage }) => {
20
24
  }
21
25
 
22
26
  if (mimetype) {
27
+ // What the row says about the file: its caption, else how many files
28
+ // there are; undefined keeps the single file's own name.
29
+ const count = getMessageAttachments(lastMessage).length;
30
+ const label =
31
+ getMessageCaption(lastMessage, { isMedia: true }) ??
32
+ (count > 1 ? t('attachment.count', { count }) : undefined);
33
+
23
34
  if (mimetype.startsWith('image/')) {
24
- return <LastMessagePhoto {...lastMessage} />;
35
+ return <LastMessagePhoto {...lastMessage} label={label} />;
25
36
  }
26
37
 
27
38
  if (mimetype.startsWith('video/')) {
28
- return <LastMessageVideo {...lastMessage} />;
39
+ return <LastMessageVideo {...lastMessage} label={label} />;
29
40
  }
30
41
 
31
42
  if (
32
43
  mimetype.startsWith('audio/') ||
33
44
  mimetype.includes('application/octet-stream')
34
45
  ) {
35
- return <LastAudioMessage {...lastMessage} />;
46
+ return <LastAudioMessage {...lastMessage} label={label} />;
36
47
  }
37
48
 
38
- return <LastMessageFile {...lastMessage} />;
49
+ return <LastMessageFile {...lastMessage} label={label} />;
39
50
  }
40
51
 
41
52
  if (emoji) {
@@ -10,7 +10,10 @@ import { View } from 'react-native';
10
10
  import { PlayIcon } from '../../../assets/icons';
11
11
  import { useTheme } from '../../../hooks/useTheme';
12
12
 
13
- interface LastMessageEmojiProps extends Pick<LastMessage, 'user' | 'body'> {}
13
+ interface LastMessageEmojiProps extends Pick<LastMessage, 'user' | 'body'> {
14
+ /** Replaces the body: the caption, or the count of files. */
15
+ label?: string;
16
+ }
14
17
 
15
18
  const PlayButton = styled.View`
16
19
  width: 20px;
@@ -29,7 +32,7 @@ const AudioRow = styled.View`
29
32
  gap: 6px;
30
33
  `;
31
34
 
32
- const LastAudioMessage: FC<LastMessageEmojiProps> = ({ user, body }) => {
35
+ const LastAudioMessage: FC<LastMessageEmojiProps> = ({ user, body, label }) => {
33
36
  const theme = useTheme();
34
37
  return (
35
38
  <LastRoomMessageContainer>
@@ -41,7 +44,7 @@ const LastAudioMessage: FC<LastMessageEmojiProps> = ({ user, body }) => {
41
44
  <PlayIcon width={10} height={10} color={theme.dark ? theme.text : '#1F2937'} />
42
45
  </PlayButton>
43
46
  <LastRoomMessageText numberOfLines={1}>
44
- {body?.trim() ? body : 'audio'}
47
+ {label ?? (body?.trim() ? body : 'audio')}
45
48
  </LastRoomMessageText>
46
49
  </AudioRow>
47
50
  </LastRoomMessageContainer>
@@ -20,7 +20,10 @@ interface LastMessageFileProps
20
20
  extends Pick<
21
21
  LastMessage,
22
22
  'user' | 'originalName' | 'fileName' | 'mimetype' | 'locationPreview'
23
- > {}
23
+ > {
24
+ /** Replaces the file name: the caption, or the count of files. */
25
+ label?: string;
26
+ }
24
27
 
25
28
  const fallbackImage =
26
29
  'https://as2.ftcdn.net/v2/jpg/02/51/95/53/1000_F_251955356_FAQH0U1y1TZw3ZcdPGybwUkH90a3VAhb.jpg';
@@ -31,6 +34,7 @@ const LastMessageFile: FC<LastMessageFileProps> = ({
31
34
  fileName,
32
35
  mimetype,
33
36
  locationPreview,
37
+ label,
34
38
  }) => {
35
39
  const [imgSrc, setImgSrc] = useState(locationPreview);
36
40
  const fileToken = useFileToken();
@@ -69,7 +73,7 @@ const LastMessageFile: FC<LastMessageFileProps> = ({
69
73
  ) : (
70
74
  <FileIcon width={20} height={20} />
71
75
  )}
72
- <LastRoomMessageText>{displayName}</LastRoomMessageText>
76
+ <LastRoomMessageText>{label ?? displayName}</LastRoomMessageText>
73
77
  </View>
74
78
  </LastRoomMessageContainer>
75
79
  );
@@ -29,7 +29,10 @@ interface LastMessagePhotoProps
29
29
  extends Pick<
30
30
  LastMessage,
31
31
  'user' | 'originalName' | 'fileName' | 'mimetype' | 'locationPreview'
32
- > {}
32
+ > {
33
+ /** Replaces the file name: the caption, or the count of files. */
34
+ label?: string;
35
+ }
33
36
 
34
37
  const LastMessagePhoto: FC<LastMessagePhotoProps> = ({
35
38
  user,
@@ -37,6 +40,7 @@ const LastMessagePhoto: FC<LastMessagePhotoProps> = ({
37
40
  originalName,
38
41
  fileName,
39
42
  mimetype,
43
+ label,
40
44
  }) => {
41
45
  const fileToken = useFileToken();
42
46
  // Bug #40: prefer the sender's original name over the stored hash
@@ -60,7 +64,7 @@ const LastMessagePhoto: FC<LastMessagePhotoProps> = ({
60
64
  <LastMessageImg src={appendFileToken(locationPreview, fileToken)} />
61
65
  </ShadeWrapper>
62
66
  </PhotoContainer>
63
- <LastRoomMessageText>{displayName}</LastRoomMessageText>
67
+ <LastRoomMessageText>{label ?? displayName}</LastRoomMessageText>
64
68
  </View>
65
69
  </LastRoomMessageContainer>
66
70
  );
@@ -44,7 +44,10 @@ interface LastMessageVideoProps
44
44
  extends Pick<
45
45
  LastMessage,
46
46
  'user' | 'location' | 'originalName' | 'fileName' | 'mimetype'
47
- > {}
47
+ > {
48
+ /** Replaces the file name: the caption, or the count of files. */
49
+ label?: string;
50
+ }
48
51
 
49
52
  const LastMessageVideo: FC<LastMessageVideoProps> = ({
50
53
  user,
@@ -52,6 +55,7 @@ const LastMessageVideo: FC<LastMessageVideoProps> = ({
52
55
  originalName,
53
56
  fileName,
54
57
  mimetype,
58
+ label,
55
59
  }) => {
56
60
  const fileToken = useFileToken();
57
61
  // Bug #40: prefer the sender's original name over the stored hash
@@ -76,7 +80,7 @@ const LastMessageVideo: FC<LastMessageVideoProps> = ({
76
80
  </ShadeWrapper>
77
81
  <PlayButton><Text>▶</Text></PlayButton>
78
82
  </VideoContainer>
79
- <LastRoomMessageText>{displayName}</LastRoomMessageText>
83
+ <LastRoomMessageText>{label ?? displayName}</LastRoomMessageText>
80
84
  </View>
81
85
  </LastRoomMessageContainer>
82
86
  );
@@ -237,15 +237,11 @@ const ThreadWrapper: FC<ThreadWrapperProps> = ({
237
237
  );
238
238
 
239
239
  const sendMedia = useCallback(
240
- (data: any, type: string) => {
241
- return sendMessageMedia(
242
- data,
243
- type,
244
- roomJid,
245
- true,
246
- isChecked,
247
- createMainMessageForThread(activeMessage)
248
- );
240
+ (data: any, type: string, caption?: { text: string }) => {
241
+ const mainMessage = createMainMessageForThread(activeMessage);
242
+ return caption
243
+ ? sendMessageMedia(data, type, roomJid, true, isChecked, mainMessage, undefined, caption)
244
+ : sendMessageMedia(data, type, roomJid, true, isChecked, mainMessage);
249
245
  },
250
246
  [activeMessage, isChecked, roomJid, sendMessageMedia]
251
247
  );
@@ -1,4 +1,4 @@
1
- import React, { FC, useEffect, useState } from 'react';
1
+ import React, { FC, useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { Pressable, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
3
3
  import { useSelector } from 'react-redux';
4
4
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
@@ -9,10 +9,24 @@ import { useT } from '../../i18n/useT';
9
9
  import { ExpandIcon, HangUpIcon, MicOffIcon, MicOnIcon } from './CallIcons';
10
10
  import { toggleCallMic, useCallSession } from './callSessionController';
11
11
  import { terminateActiveCall } from './callActions';
12
- import { registerCallBarHost, setCallMinimized, useCallUi } from './callUiStore';
12
+ import {
13
+ registerCallBarHost,
14
+ setCallBarAnchor,
15
+ setCallMinimized,
16
+ useCallUi,
17
+ } from './callUiStore';
13
18
  import { formatCallDuration, useSharedCallElapsed } from './VideoCallSession';
14
19
 
15
20
  const DANGER = '#E53935';
21
+
22
+ /**
23
+ * The strip's geometry: a floating bubble under the header. Exported so the
24
+ * collapse animation of the full-screen call lands exactly on it.
25
+ */
26
+ export const CALL_BAR_HEIGHT = 52;
27
+ export const CALL_BAR_MARGIN_X = 8;
28
+ export const CALL_BAR_MARGIN_TOP = 6;
29
+ export const CALL_BAR_RADIUS = 18;
16
30
  const ON_BAR = '#FFFFFF';
17
31
  const CONTROL = 'rgba(255, 255, 255, 0.2)';
18
32
 
@@ -33,7 +47,7 @@ const useShowCallBar = (): boolean => {
33
47
  * Tapping anywhere on it (outside the buttons) brings the call back
34
48
  * full-screen, like Telegram's "return to call" bar.
35
49
  */
36
- export const ActiveCallBar: FC<{ topInset?: number }> = ({ topInset = 0 }) => {
50
+ export const ActiveCallBar: FC = () => {
37
51
  const t = useT();
38
52
  const theme = useTheme();
39
53
  const { icons } = useChatSettingState().config?.videoCalls || {};
@@ -60,7 +74,7 @@ export const ActiveCallBar: FC<{ topInset?: number }> = ({ topInset = 0 }) => {
60
74
  onPress={expand}
61
75
  accessibilityRole="button"
62
76
  accessibilityLabel={t('call.action.expand')}
63
- style={[styles.bar, { backgroundColor: theme.success, paddingTop: 8 + topInset }]}
77
+ style={[styles.bar, { backgroundColor: theme.success }]}
64
78
  >
65
79
  <View style={styles.info}>
66
80
  <Text numberOfLines={1} style={styles.name}>
@@ -112,12 +126,31 @@ export const HeaderCallBar: FC = () => {
112
126
  const [hostId, setHostId] = useState<number | null>(null);
113
127
  const { barHost } = useCallUi();
114
128
  const show = useShowCallBar();
129
+ const anchorRef = useRef<View>(null);
130
+ const isHost = hostId !== null && barHost === hostId;
115
131
 
116
132
  // Returns its own unregister, which is the effect's cleanup.
117
133
  useEffect(() => registerCallBarHost(setHostId), []);
118
134
 
119
- if (!show || hostId === null || barHost !== hostId) {return null;}
120
- return <ActiveCallBar />;
135
+ // Where the strip goes on screen, for the collapse animation to aim at.
136
+ const measure = useCallback(() => {
137
+ if (hostId === null) {return;}
138
+ anchorRef.current?.measureInWindow((_x, y) => {
139
+ if (Number.isFinite(y)) {setCallBarAnchor(hostId, y);}
140
+ });
141
+ }, [hostId]);
142
+
143
+ useEffect(() => {
144
+ if (isHost) {measure();}
145
+ }, [isHost, measure]);
146
+
147
+ return (
148
+ <>
149
+ {/* Zero-height marker at the top of the strip slot. */}
150
+ <View ref={anchorRef} collapsable={false} onLayout={measure} style={styles.anchor} />
151
+ {show && isHost ? <ActiveCallBar /> : null}
152
+ </>
153
+ );
121
154
  };
122
155
 
123
156
  /**
@@ -130,8 +163,8 @@ export const DockedCallBar: FC = () => {
130
163
  const show = useShowCallBar();
131
164
  if (!show || barHost !== null) {return null;}
132
165
  return (
133
- <View style={styles.docked} pointerEvents="box-none">
134
- <ActiveCallBar topInset={insets.top} />
166
+ <View style={[styles.docked, { paddingTop: insets.top }]} pointerEvents="box-none">
167
+ <ActiveCallBar />
135
168
  </View>
136
169
  );
137
170
  };
@@ -141,8 +174,21 @@ const styles = StyleSheet.create({
141
174
  flexDirection: 'row',
142
175
  alignItems: 'center',
143
176
  gap: 10,
144
- paddingHorizontal: 16,
145
- paddingBottom: 8,
177
+ height: CALL_BAR_HEIGHT,
178
+ marginHorizontal: CALL_BAR_MARGIN_X,
179
+ marginTop: CALL_BAR_MARGIN_TOP,
180
+ marginBottom: 2,
181
+ paddingLeft: 16,
182
+ paddingRight: 9,
183
+ borderRadius: CALL_BAR_RADIUS,
184
+ shadowColor: '#000',
185
+ shadowOpacity: 0.12,
186
+ shadowRadius: 8,
187
+ shadowOffset: { width: 0, height: 2 },
188
+ elevation: 3,
189
+ },
190
+ anchor: {
191
+ height: 0,
146
192
  },
147
193
  info: {
148
194
  flex: 1,