@ethora/chat-component-rn 26.8.4 → 26.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. package/README.md +55 -0
  2. package/lib/commonjs/assets/emojiData.js +40 -0
  3. package/lib/commonjs/assets/emojiData.js.map +1 -0
  4. package/lib/commonjs/assets/icons.js +1 -1
  5. package/lib/commonjs/assets/icons.js.map +1 -1
  6. package/lib/commonjs/components/Header/HeaderRoomList.js +12 -7
  7. package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
  8. package/lib/commonjs/components/MainComponents/ChatHeader.js +7 -9
  9. package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
  10. package/lib/commonjs/components/MainComponents/ChatRoom.js +47 -26
  11. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  12. package/lib/commonjs/components/MainComponents/ChatWrapper.js +58 -21
  13. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  14. package/lib/commonjs/components/MainComponents/KeyboardInputDock.js +40 -0
  15. package/lib/commonjs/components/MainComponents/KeyboardInputDock.js.map +1 -0
  16. package/lib/commonjs/components/MainComponents/MessageContainer.js +4 -12
  17. package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
  18. package/lib/commonjs/components/MainComponents/MessageList.js +110 -35
  19. package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
  20. package/lib/commonjs/components/MainComponents/RoomList.js +32 -29
  21. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  22. package/lib/commonjs/components/MainComponents/RoomStack.js +270 -0
  23. package/lib/commonjs/components/MainComponents/RoomStack.js.map +1 -0
  24. package/lib/commonjs/components/MainComponents/SystemMessage.js +6 -2
  25. package/lib/commonjs/components/MainComponents/SystemMessage.js.map +1 -1
  26. package/lib/commonjs/components/MessageBubble/Avatar.js +5 -1
  27. package/lib/commonjs/components/MessageBubble/Avatar.js.map +1 -1
  28. package/lib/commonjs/components/MessageBubble/BottomReplyContainer.js +17 -21
  29. package/lib/commonjs/components/MessageBubble/BottomReplyContainer.js.map +1 -1
  30. package/lib/commonjs/components/MessageBubble/EmojiPickerSheet.js +447 -0
  31. package/lib/commonjs/components/MessageBubble/EmojiPickerSheet.js.map +1 -0
  32. package/lib/commonjs/components/MessageBubble/Message.js +200 -132
  33. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  34. package/lib/commonjs/components/MessageBubble/MessageInteractions.js +213 -12
  35. package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
  36. package/lib/commonjs/components/MessageBubble/MessageReaction.js +113 -94
  37. package/lib/commonjs/components/MessageBubble/MessageReaction.js.map +1 -1
  38. package/lib/commonjs/components/MessageBubble/MessageReply.js +66 -24
  39. package/lib/commonjs/components/MessageBubble/MessageReply.js.map +1 -1
  40. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +6 -1
  41. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  42. package/lib/commonjs/components/Modals/Modal/Modal.js +24 -0
  43. package/lib/commonjs/components/Modals/Modal/Modal.js.map +1 -1
  44. package/lib/commonjs/components/Modals/Modal/SwipeBackLayer.js +178 -0
  45. package/lib/commonjs/components/Modals/Modal/SwipeBackLayer.js.map +1 -0
  46. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js +28 -10
  47. package/lib/commonjs/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -1
  48. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +9 -3
  49. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  50. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +5 -4
  51. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
  52. package/lib/commonjs/components/RoomComponents/styled/LastMessageEmoji.js +8 -9
  53. package/lib/commonjs/components/RoomComponents/styled/LastMessageEmoji.js.map +1 -1
  54. package/lib/commonjs/components/Thread/ThreadWrapper.js +265 -152
  55. package/lib/commonjs/components/Thread/ThreadWrapper.js.map +1 -1
  56. package/lib/commonjs/components/styled/DateLabel.js +6 -3
  57. package/lib/commonjs/components/styled/DateLabel.js.map +1 -1
  58. package/lib/commonjs/context/MessageNotificationContext.js +188 -9
  59. package/lib/commonjs/context/MessageNotificationContext.js.map +1 -1
  60. package/lib/commonjs/context/xmppProvider.js +22 -7
  61. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  62. package/lib/commonjs/helpers/createRoomFromApi.js +36 -2
  63. package/lib/commonjs/helpers/createRoomFromApi.js.map +1 -1
  64. package/lib/commonjs/helpers/emoji.js +51 -0
  65. package/lib/commonjs/helpers/emoji.js.map +1 -0
  66. package/lib/commonjs/helpers/haptics.js +29 -0
  67. package/lib/commonjs/helpers/haptics.js.map +1 -0
  68. package/lib/commonjs/helpers/historyPreloadScheduler.js +32 -66
  69. package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
  70. package/lib/commonjs/helpers/insertMessageWithDelimiter.js +21 -12
  71. package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
  72. package/lib/commonjs/helpers/keyboardLayout.js +23 -1
  73. package/lib/commonjs/helpers/keyboardLayout.js.map +1 -1
  74. package/lib/commonjs/helpers/mamReactions.js +57 -0
  75. package/lib/commonjs/helpers/mamReactions.js.map +1 -0
  76. package/lib/commonjs/helpers/parseMessageReference.js +42 -0
  77. package/lib/commonjs/helpers/parseMessageReference.js.map +1 -0
  78. package/lib/commonjs/helpers/reactionsConfig.js +17 -0
  79. package/lib/commonjs/helpers/reactionsConfig.js.map +1 -0
  80. package/lib/commonjs/helpers/updateMessagesTillLast.js +17 -2
  81. package/lib/commonjs/helpers/updateMessagesTillLast.js.map +1 -1
  82. package/lib/commonjs/hooks/useHeapSender.js +3 -1
  83. package/lib/commonjs/hooks/useHeapSender.js.map +1 -1
  84. package/lib/commonjs/hooks/useMessageHeapState.js +3 -2
  85. package/lib/commonjs/hooks/useMessageHeapState.js.map +1 -1
  86. package/lib/commonjs/hooks/useRoomInitialization.js +16 -7
  87. package/lib/commonjs/hooks/useRoomInitialization.js.map +1 -1
  88. package/lib/commonjs/hooks/useSendMessage.js +14 -8
  89. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  90. package/lib/commonjs/hooks/useUnreadMessagesCounter.js +1 -1
  91. package/lib/commonjs/hooks/useUnreadMessagesCounter.js.map +1 -1
  92. package/lib/commonjs/networking/stanzaHandlers.js +106 -50
  93. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  94. package/lib/commonjs/networking/xmpp/getHistory.xmpp.js +29 -74
  95. package/lib/commonjs/networking/xmpp/getHistory.xmpp.js.map +1 -1
  96. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +4 -0
  97. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  98. package/lib/commonjs/networking/xmpp/mamRouter.js +186 -0
  99. package/lib/commonjs/networking/xmpp/mamRouter.js.map +1 -0
  100. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js +41 -4
  101. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  102. package/lib/commonjs/networking/xmppClient.js +98 -23
  103. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  104. package/lib/commonjs/roomStore/Middleware/newMessageMidlleware.js +29 -34
  105. package/lib/commonjs/roomStore/Middleware/newMessageMidlleware.js.map +1 -1
  106. package/lib/commonjs/roomStore/Middleware/perfMiddleware.js +51 -0
  107. package/lib/commonjs/roomStore/Middleware/perfMiddleware.js.map +1 -0
  108. package/lib/commonjs/roomStore/Middleware/reactionsMiddleware.js +66 -43
  109. package/lib/commonjs/roomStore/Middleware/reactionsMiddleware.js.map +1 -1
  110. package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js +88 -68
  111. package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js.map +1 -1
  112. package/lib/commonjs/roomStore/index.js +18 -14
  113. package/lib/commonjs/roomStore/index.js.map +1 -1
  114. package/lib/commonjs/roomStore/persistBackend.js +96 -0
  115. package/lib/commonjs/roomStore/persistBackend.js.map +1 -0
  116. package/lib/commonjs/roomStore/persistence.js +245 -50
  117. package/lib/commonjs/roomStore/persistence.js.map +1 -1
  118. package/lib/commonjs/roomStore/roomsSlice.js +282 -136
  119. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  120. package/lib/commonjs/theme/theme.js +3 -0
  121. package/lib/commonjs/theme/theme.js.map +1 -1
  122. package/lib/commonjs/utils/devLogger.js +14 -0
  123. package/lib/commonjs/utils/devLogger.js.map +1 -1
  124. package/lib/commonjs/version.js +1 -1
  125. package/lib/module/assets/emojiData.js +36 -0
  126. package/lib/module/assets/emojiData.js.map +1 -0
  127. package/lib/module/assets/icons.js +1 -1
  128. package/lib/module/assets/icons.js.map +1 -1
  129. package/lib/module/components/Header/HeaderRoomList.js +12 -7
  130. package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
  131. package/lib/module/components/MainComponents/ChatHeader.js +8 -10
  132. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  133. package/lib/module/components/MainComponents/ChatRoom.js +49 -28
  134. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  135. package/lib/module/components/MainComponents/ChatWrapper.js +60 -23
  136. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  137. package/lib/module/components/MainComponents/KeyboardInputDock.js +33 -0
  138. package/lib/module/components/MainComponents/KeyboardInputDock.js.map +1 -0
  139. package/lib/module/components/MainComponents/MessageContainer.js +7 -14
  140. package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
  141. package/lib/module/components/MainComponents/MessageList.js +110 -35
  142. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  143. package/lib/module/components/MainComponents/RoomList.js +32 -29
  144. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  145. package/lib/module/components/MainComponents/RoomStack.js +266 -0
  146. package/lib/module/components/MainComponents/RoomStack.js.map +1 -0
  147. package/lib/module/components/MainComponents/SystemMessage.js +6 -2
  148. package/lib/module/components/MainComponents/SystemMessage.js.map +1 -1
  149. package/lib/module/components/MessageBubble/Avatar.js +5 -1
  150. package/lib/module/components/MessageBubble/Avatar.js.map +1 -1
  151. package/lib/module/components/MessageBubble/BottomReplyContainer.js +18 -22
  152. package/lib/module/components/MessageBubble/BottomReplyContainer.js.map +1 -1
  153. package/lib/module/components/MessageBubble/EmojiPickerSheet.js +438 -0
  154. package/lib/module/components/MessageBubble/EmojiPickerSheet.js.map +1 -0
  155. package/lib/module/components/MessageBubble/Message.js +203 -134
  156. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  157. package/lib/module/components/MessageBubble/MessageInteractions.js +215 -14
  158. package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
  159. package/lib/module/components/MessageBubble/MessageReaction.js +115 -94
  160. package/lib/module/components/MessageBubble/MessageReaction.js.map +1 -1
  161. package/lib/module/components/MessageBubble/MessageReply.js +65 -24
  162. package/lib/module/components/MessageBubble/MessageReply.js.map +1 -1
  163. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +6 -1
  164. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  165. package/lib/module/components/Modals/Modal/Modal.js +25 -1
  166. package/lib/module/components/Modals/Modal/Modal.js.map +1 -1
  167. package/lib/module/components/Modals/Modal/SwipeBackLayer.js +172 -0
  168. package/lib/module/components/Modals/Modal/SwipeBackLayer.js.map +1 -0
  169. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js +29 -11
  170. package/lib/module/components/Modals/ProfileHeader/ProfileHeader.js.map +1 -1
  171. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +10 -4
  172. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  173. package/lib/module/components/RoomComponents/ChatRoomItem.js +5 -4
  174. package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
  175. package/lib/module/components/RoomComponents/styled/LastMessageEmoji.js +8 -9
  176. package/lib/module/components/RoomComponents/styled/LastMessageEmoji.js.map +1 -1
  177. package/lib/module/components/Thread/ThreadWrapper.js +264 -152
  178. package/lib/module/components/Thread/ThreadWrapper.js.map +1 -1
  179. package/lib/module/components/styled/DateLabel.js +6 -3
  180. package/lib/module/components/styled/DateLabel.js.map +1 -1
  181. package/lib/module/context/MessageNotificationContext.js +190 -11
  182. package/lib/module/context/MessageNotificationContext.js.map +1 -1
  183. package/lib/module/context/xmppProvider.js +22 -7
  184. package/lib/module/context/xmppProvider.js.map +1 -1
  185. package/lib/module/helpers/createRoomFromApi.js +36 -2
  186. package/lib/module/helpers/createRoomFromApi.js.map +1 -1
  187. package/lib/module/helpers/emoji.js +44 -0
  188. package/lib/module/helpers/emoji.js.map +1 -0
  189. package/lib/module/helpers/haptics.js +24 -0
  190. package/lib/module/helpers/haptics.js.map +1 -0
  191. package/lib/module/helpers/historyPreloadScheduler.js +32 -66
  192. package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
  193. package/lib/module/helpers/insertMessageWithDelimiter.js +21 -12
  194. package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
  195. package/lib/module/helpers/keyboardLayout.js +20 -0
  196. package/lib/module/helpers/keyboardLayout.js.map +1 -1
  197. package/lib/module/helpers/mamReactions.js +51 -0
  198. package/lib/module/helpers/mamReactions.js.map +1 -0
  199. package/lib/module/helpers/parseMessageReference.js +37 -0
  200. package/lib/module/helpers/parseMessageReference.js.map +1 -0
  201. package/lib/module/helpers/reactionsConfig.js +10 -0
  202. package/lib/module/helpers/reactionsConfig.js.map +1 -0
  203. package/lib/module/helpers/updateMessagesTillLast.js +17 -2
  204. package/lib/module/helpers/updateMessagesTillLast.js.map +1 -1
  205. package/lib/module/hooks/useHeapSender.js +3 -1
  206. package/lib/module/hooks/useHeapSender.js.map +1 -1
  207. package/lib/module/hooks/useMessageHeapState.js +3 -2
  208. package/lib/module/hooks/useMessageHeapState.js.map +1 -1
  209. package/lib/module/hooks/useRoomInitialization.js +17 -8
  210. package/lib/module/hooks/useRoomInitialization.js.map +1 -1
  211. package/lib/module/hooks/useSendMessage.js +14 -8
  212. package/lib/module/hooks/useSendMessage.js.map +1 -1
  213. package/lib/module/hooks/useUnreadMessagesCounter.js +1 -1
  214. package/lib/module/hooks/useUnreadMessagesCounter.js.map +1 -1
  215. package/lib/module/networking/stanzaHandlers.js +107 -51
  216. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  217. package/lib/module/networking/xmpp/getHistory.xmpp.js +29 -74
  218. package/lib/module/networking/xmpp/getHistory.xmpp.js.map +1 -1
  219. package/lib/module/networking/xmpp/handleStanzas.xmpp.js +4 -0
  220. package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  221. package/lib/module/networking/xmpp/mamRouter.js +175 -0
  222. package/lib/module/networking/xmpp/mamRouter.js.map +1 -0
  223. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js +38 -2
  224. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  225. package/lib/module/networking/xmppClient.js +99 -24
  226. package/lib/module/networking/xmppClient.js.map +1 -1
  227. package/lib/module/roomStore/Middleware/newMessageMidlleware.js +29 -34
  228. package/lib/module/roomStore/Middleware/newMessageMidlleware.js.map +1 -1
  229. package/lib/module/roomStore/Middleware/perfMiddleware.js +45 -0
  230. package/lib/module/roomStore/Middleware/perfMiddleware.js.map +1 -0
  231. package/lib/module/roomStore/Middleware/reactionsMiddleware.js +66 -43
  232. package/lib/module/roomStore/Middleware/reactionsMiddleware.js.map +1 -1
  233. package/lib/module/roomStore/Middleware/unreadMidlleware.js +89 -69
  234. package/lib/module/roomStore/Middleware/unreadMidlleware.js.map +1 -1
  235. package/lib/module/roomStore/index.js +19 -15
  236. package/lib/module/roomStore/index.js.map +1 -1
  237. package/lib/module/roomStore/persistBackend.js +89 -0
  238. package/lib/module/roomStore/persistBackend.js.map +1 -0
  239. package/lib/module/roomStore/persistence.js +245 -48
  240. package/lib/module/roomStore/persistence.js.map +1 -1
  241. package/lib/module/roomStore/roomsSlice.js +275 -134
  242. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  243. package/lib/module/theme/theme.js +3 -0
  244. package/lib/module/theme/theme.js.map +1 -1
  245. package/lib/module/utils/devLogger.js +13 -0
  246. package/lib/module/utils/devLogger.js.map +1 -1
  247. package/lib/module/version.js +1 -1
  248. package/lib/typescript/assets/emojiData.d.ts +8 -0
  249. package/lib/typescript/assets/emojiData.d.ts.map +1 -0
  250. package/lib/typescript/components/Header/HeaderRoomList.d.ts.map +1 -1
  251. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  252. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  253. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  254. package/lib/typescript/components/MainComponents/KeyboardInputDock.d.ts +16 -0
  255. package/lib/typescript/components/MainComponents/KeyboardInputDock.d.ts.map +1 -0
  256. package/lib/typescript/components/MainComponents/MessageContainer.d.ts +2 -2
  257. package/lib/typescript/components/MainComponents/MessageContainer.d.ts.map +1 -1
  258. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  259. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  260. package/lib/typescript/components/MainComponents/RoomStack.d.ts +42 -0
  261. package/lib/typescript/components/MainComponents/RoomStack.d.ts.map +1 -0
  262. package/lib/typescript/components/MainComponents/SystemMessage.d.ts.map +1 -1
  263. package/lib/typescript/components/MessageBubble/Avatar.d.ts +2 -0
  264. package/lib/typescript/components/MessageBubble/Avatar.d.ts.map +1 -1
  265. package/lib/typescript/components/MessageBubble/BottomReplyContainer.d.ts.map +1 -1
  266. package/lib/typescript/components/MessageBubble/EmojiPickerSheet.d.ts +11 -0
  267. package/lib/typescript/components/MessageBubble/EmojiPickerSheet.d.ts.map +1 -0
  268. package/lib/typescript/components/MessageBubble/Message.d.ts +2 -2
  269. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  270. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts +2 -0
  271. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
  272. package/lib/typescript/components/MessageBubble/MessageReaction.d.ts +1 -0
  273. package/lib/typescript/components/MessageBubble/MessageReaction.d.ts.map +1 -1
  274. package/lib/typescript/components/MessageBubble/MessageReply.d.ts +7 -7
  275. package/lib/typescript/components/MessageBubble/MessageReply.d.ts.map +1 -1
  276. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
  277. package/lib/typescript/components/Modals/Modal/Modal.d.ts.map +1 -1
  278. package/lib/typescript/components/Modals/Modal/SwipeBackLayer.d.ts +16 -0
  279. package/lib/typescript/components/Modals/Modal/SwipeBackLayer.d.ts.map +1 -0
  280. package/lib/typescript/components/Modals/ProfileHeader/ProfileHeader.d.ts.map +1 -1
  281. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
  282. package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts +2 -2
  283. package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
  284. package/lib/typescript/components/RoomComponents/styled/LastMessageEmoji.d.ts +3 -6
  285. package/lib/typescript/components/RoomComponents/styled/LastMessageEmoji.d.ts.map +1 -1
  286. package/lib/typescript/components/Thread/ThreadWrapper.d.ts +7 -1
  287. package/lib/typescript/components/Thread/ThreadWrapper.d.ts.map +1 -1
  288. package/lib/typescript/components/styled/DateLabel.d.ts +1 -0
  289. package/lib/typescript/components/styled/DateLabel.d.ts.map +1 -1
  290. package/lib/typescript/context/MessageNotificationContext.d.ts.map +1 -1
  291. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  292. package/lib/typescript/helpers/createRoomFromApi.d.ts.map +1 -1
  293. package/lib/typescript/helpers/emoji.d.ts +6 -0
  294. package/lib/typescript/helpers/emoji.d.ts.map +1 -0
  295. package/lib/typescript/helpers/haptics.d.ts +3 -0
  296. package/lib/typescript/helpers/haptics.d.ts.map +1 -0
  297. package/lib/typescript/helpers/historyPreloadScheduler.d.ts +1 -0
  298. package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
  299. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
  300. package/lib/typescript/helpers/keyboardLayout.d.ts +6 -0
  301. package/lib/typescript/helpers/keyboardLayout.d.ts.map +1 -1
  302. package/lib/typescript/helpers/mamReactions.d.ts +13 -0
  303. package/lib/typescript/helpers/mamReactions.d.ts.map +1 -0
  304. package/lib/typescript/helpers/parseMessageReference.d.ts +16 -0
  305. package/lib/typescript/helpers/parseMessageReference.d.ts.map +1 -0
  306. package/lib/typescript/helpers/reactionsConfig.d.ts +5 -0
  307. package/lib/typescript/helpers/reactionsConfig.d.ts.map +1 -0
  308. package/lib/typescript/helpers/updateMessagesTillLast.d.ts.map +1 -1
  309. package/lib/typescript/hooks/useHeapSender.d.ts.map +1 -1
  310. package/lib/typescript/hooks/useMessageHeapState.d.ts.map +1 -1
  311. package/lib/typescript/hooks/useRoomInitialization.d.ts +2 -2
  312. package/lib/typescript/hooks/useRoomInitialization.d.ts.map +1 -1
  313. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  314. package/lib/typescript/networking/stanzaHandlers.d.ts +4 -2
  315. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  316. package/lib/typescript/networking/xmpp/getHistory.xmpp.d.ts +3 -1
  317. package/lib/typescript/networking/xmpp/getHistory.xmpp.d.ts.map +1 -1
  318. package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
  319. package/lib/typescript/networking/xmpp/mamRouter.d.ts +23 -0
  320. package/lib/typescript/networking/xmpp/mamRouter.d.ts.map +1 -0
  321. package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts +1 -0
  322. package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts.map +1 -1
  323. package/lib/typescript/networking/xmppClient.d.ts +22 -1
  324. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  325. package/lib/typescript/roomStore/Middleware/newMessageMidlleware.d.ts.map +1 -1
  326. package/lib/typescript/roomStore/Middleware/perfMiddleware.d.ts +4 -0
  327. package/lib/typescript/roomStore/Middleware/perfMiddleware.d.ts.map +1 -0
  328. package/lib/typescript/roomStore/Middleware/reactionsMiddleware.d.ts +9 -0
  329. package/lib/typescript/roomStore/Middleware/reactionsMiddleware.d.ts.map +1 -1
  330. package/lib/typescript/roomStore/Middleware/unreadMidlleware.d.ts.map +1 -1
  331. package/lib/typescript/roomStore/index.d.ts.map +1 -1
  332. package/lib/typescript/roomStore/persistBackend.d.ts +11 -0
  333. package/lib/typescript/roomStore/persistBackend.d.ts.map +1 -0
  334. package/lib/typescript/roomStore/persistence.d.ts +5 -6
  335. package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
  336. package/lib/typescript/roomStore/roomsSlice.d.ts +41 -1
  337. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  338. package/lib/typescript/theme/theme.d.ts +4 -1
  339. package/lib/typescript/theme/theme.d.ts.map +1 -1
  340. package/lib/typescript/types/models/message.model.d.ts +4 -0
  341. package/lib/typescript/types/models/message.model.d.ts.map +1 -1
  342. package/lib/typescript/types/models/room.model.d.ts +16 -0
  343. package/lib/typescript/types/models/room.model.d.ts.map +1 -1
  344. package/lib/typescript/types/models/xmpp.model.d.ts +6 -1
  345. package/lib/typescript/types/models/xmpp.model.d.ts.map +1 -1
  346. package/lib/typescript/types/types.d.ts +15 -3
  347. package/lib/typescript/types/types.d.ts.map +1 -1
  348. package/lib/typescript/utils/devLogger.d.ts +8 -0
  349. package/lib/typescript/utils/devLogger.d.ts.map +1 -1
  350. package/lib/typescript/version.d.ts +1 -1
  351. package/package.json +10 -1
  352. package/src/assets/emojiData.ts +2146 -0
  353. package/src/assets/icons.tsx +5 -5
  354. package/src/components/Header/HeaderRoomList.tsx +7 -5
  355. package/src/components/MainComponents/ChatHeader.tsx +16 -7
  356. package/src/components/MainComponents/ChatRoom.tsx +64 -32
  357. package/src/components/MainComponents/ChatWrapper.tsx +73 -21
  358. package/src/components/MainComponents/KeyboardInputDock.tsx +47 -0
  359. package/src/components/MainComponents/MessageContainer.tsx +7 -15
  360. package/src/components/MainComponents/MessageList.tsx +96 -43
  361. package/src/components/MainComponents/RoomList.tsx +28 -29
  362. package/src/components/MainComponents/RoomStack.tsx +309 -0
  363. package/src/components/MainComponents/SystemMessage.tsx +6 -2
  364. package/src/components/MessageBubble/Avatar.tsx +7 -1
  365. package/src/components/MessageBubble/BottomReplyContainer.tsx +19 -21
  366. package/src/components/MessageBubble/EmojiPickerSheet.tsx +468 -0
  367. package/src/components/MessageBubble/Message.tsx +146 -87
  368. package/src/components/MessageBubble/MessageInteractions.tsx +213 -12
  369. package/src/components/MessageBubble/MessageReaction.tsx +120 -96
  370. package/src/components/MessageBubble/MessageReply.tsx +65 -32
  371. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +4 -0
  372. package/src/components/Modals/Modal/Modal.tsx +32 -1
  373. package/src/components/Modals/Modal/SwipeBackLayer.tsx +221 -0
  374. package/src/components/Modals/ProfileHeader/ProfileHeader.tsx +29 -8
  375. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +6 -3
  376. package/src/components/RoomComponents/ChatRoomItem.tsx +11 -4
  377. package/src/components/RoomComponents/styled/LastMessageEmoji.tsx +7 -8
  378. package/src/components/Thread/ThreadWrapper.tsx +274 -198
  379. package/src/components/styled/DateLabel.tsx +7 -3
  380. package/src/context/MessageNotificationContext.tsx +205 -7
  381. package/src/context/xmppProvider.tsx +29 -9
  382. package/src/helpers/createRoomFromApi.tsx +37 -1
  383. package/src/helpers/emoji.ts +39 -0
  384. package/src/helpers/haptics.ts +19 -0
  385. package/src/helpers/historyPreloadScheduler.ts +37 -69
  386. package/src/helpers/insertMessageWithDelimiter.ts +23 -16
  387. package/src/helpers/keyboardLayout.ts +26 -0
  388. package/src/helpers/mamReactions.ts +59 -0
  389. package/src/helpers/parseMessageReference.ts +38 -0
  390. package/src/helpers/reactionsConfig.ts +13 -0
  391. package/src/helpers/updateMessagesTillLast.tsx +14 -2
  392. package/src/hooks/useHeapSender.tsx +3 -2
  393. package/src/hooks/useMessageHeapState.tsx +6 -2
  394. package/src/hooks/useRoomInitialization.tsx +32 -15
  395. package/src/hooks/useSendMessage.tsx +18 -11
  396. package/src/hooks/useUnreadMessagesCounter.ts +1 -1
  397. package/src/networking/stanzaHandlers.ts +116 -60
  398. package/src/networking/xmpp/getHistory.xmpp.ts +44 -106
  399. package/src/networking/xmpp/handleStanzas.xmpp.ts +2 -0
  400. package/src/networking/xmpp/mamRouter.ts +176 -0
  401. package/src/networking/xmpp/presenceInRoom.xmpp.ts +46 -3
  402. package/src/networking/xmppClient.ts +105 -20
  403. package/src/roomStore/Middleware/newMessageMidlleware.tsx +35 -38
  404. package/src/roomStore/Middleware/perfMiddleware.ts +50 -0
  405. package/src/roomStore/Middleware/reactionsMiddleware.tsx +53 -52
  406. package/src/roomStore/Middleware/unreadMidlleware.tsx +92 -80
  407. package/src/roomStore/index.ts +28 -27
  408. package/src/roomStore/persistBackend.ts +96 -0
  409. package/src/roomStore/persistence.ts +280 -73
  410. package/src/roomStore/roomsSlice.ts +304 -155
  411. package/src/theme/theme.ts +10 -1
  412. package/src/types/models/message.model.ts +4 -0
  413. package/src/types/models/room.model.ts +17 -0
  414. package/src/types/models/xmpp.model.ts +4 -2
  415. package/src/types/types.ts +15 -3
  416. package/src/utils/devLogger.ts +16 -0
  417. package/src/version.ts +1 -1
@@ -3,14 +3,14 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.mergeUsersSet = exports.editRoomMessage = exports.deleteRoomMessage = exports.deleteRoom = exports.deleteAllRooms = exports.default = exports.clearVisibleRoom = exports.clearReadBoundary = exports.clearPendingNotificationJid = exports.applyRoomsPreloadBatch = exports.applyPrivateStoreMarkers = exports.addRoomViaApi = exports.addRoomMessage = exports.addRoom = exports.RUNTIME_MESSAGE_LIMIT = void 0;
6
+ exports.mergeUsersSet = exports.editRoomMessage = exports.deleteRoomMessage = exports.deleteRoom = exports.deleteAllRooms = exports.default = exports.compareStanzaIds = exports.clearVisibleRoom = exports.clearReadBoundary = exports.clearPendingNotificationJid = exports.applyRoomsPreloadBatch = exports.applyReactionToMessage = exports.applyPrivateStoreMarkers = exports.addRooms = exports.addRoomViaApi = exports.addRoomMessages = exports.addRoomMessage = exports.addRoom = exports.UNREAD_CAP_PAGE = exports.RUNTIME_MESSAGE_LIMIT = exports.RUNTIME_MESSAGE_CEILING = void 0;
7
7
  Object.defineProperty(exports, "msgSortableMs", {
8
8
  enumerable: true,
9
9
  get: function () {
10
10
  return _msgSortableMs.msgSortableMs;
11
11
  }
12
12
  });
13
- exports.updateRoom = exports.setVisibleRoom = exports.setUnreadSyncing = exports.setRoomRole = exports.setRoomNoMessages = exports.setRoomMessages = exports.setReadBoundary = exports.setReactions = exports.setPendingNotificationJid = exports.setLogoutState = exports.setLastViewedTimestamp = exports.setIsLoading = exports.setEditAction = exports.setCurrentRoom = exports.setComposing = exports.setCloseActiveMessage = exports.setActiveMessage = exports.roomsStore = void 0;
13
+ exports.updateRoom = exports.setVisibleRoom = exports.setUnreadSyncing = exports.setUnreadCounts = exports.setRoomRole = exports.setRoomNoMessages = exports.setRoomMessages = exports.setReadBoundary = exports.setReactions = exports.setPendingNotificationJid = exports.setLogoutState = exports.setLastViewedTimestamp = exports.setIsLoading = exports.setEditAction = exports.setCurrentRoom = exports.setComposing = exports.setCloseActiveMessage = exports.setActiveMessage = exports.roomsStore = void 0;
14
14
  var _toolkit = require("@reduxjs/toolkit");
15
15
  var _insertMessageWithDelimiter = require("../helpers/insertMessageWithDelimiter");
16
16
  var _msgSortableMs = require("../helpers/msgSortableMs");
@@ -24,6 +24,9 @@ var _msgSortableMs = require("../helpers/msgSortableMs");
24
24
  // page backward arbitrarily far without instantly losing what they
25
25
  // just fetched. After cap eviction we drop from the head (oldest).
26
26
  const RUNTIME_MESSAGE_LIMIT = exports.RUNTIME_MESSAGE_LIMIT = 100;
27
+ /** One preload page: "N+" badges only ever mean "at least this many". */
28
+ const UNREAD_CAP_PAGE = exports.UNREAD_CAP_PAGE = 10;
29
+ const RUNTIME_MESSAGE_CEILING = exports.RUNTIME_MESSAGE_CEILING = 2000;
27
30
 
28
31
  // Body strings the server uses for call signaling broadcasts (call-token,
29
32
  // call-state ringing/ended, etc). These should never reach the chat
@@ -107,11 +110,170 @@ const collapseCallLogDuplicates = messages => {
107
110
  return callId ? byCallId.get(callId) || message : message;
108
111
  });
109
112
  };
110
- const enforceMessageCap = messages => {
113
+ const NO_GROWTH = {
114
+ grew: false,
115
+ atHead: false
116
+ };
117
+ const insertRoomMessage = (state, roomJID, message, start) => {
118
+ if (isCallSignalMessage(message)) {
119
+ return NO_GROWTH;
120
+ }
121
+ if (!state.rooms[roomJID]) {
122
+ return NO_GROWTH;
123
+ }
124
+ if (!state.rooms[roomJID].messages) {
125
+ state.rooms[roomJID].messages = [];
126
+ }
127
+ const roomMessages = state.rooms[roomJID].messages;
128
+ const incomingCallLog = message.callLog;
129
+ if (incomingCallLog?.callId) {
130
+ const existingCallIdx = roomMessages.findIndex(msg => msg.callLog?.callId === incomingCallLog.callId);
131
+ if (existingCallIdx !== -1) {
132
+ const existing = roomMessages[existingCallIdx];
133
+ const merged = mergeCallLogEntries(existing, message);
134
+ if (merged !== existing) {
135
+ roomMessages[existingCallIdx] = merged;
136
+ }
137
+ return NO_GROWTH;
138
+ }
139
+ }
140
+ takePendingReactions(state, roomJID, message);
141
+ const lengthBefore = roomMessages.length;
142
+ const tailBefore = roomMessages[lengthBefore - 1];
143
+ if (roomMessages.length === 0 || start) {
144
+ roomMessages.unshift(message);
145
+ } else {
146
+ const lastViewedValue = state.rooms[roomJID].lastViewedTimestamp;
147
+ const lastViewedTimestamp = state.visibleRoomJID === roomJID ? null : lastViewedValue ? lastViewedValue : null;
148
+ (0, _insertMessageWithDelimiter.insertMessageWithDelimiter)(roomMessages, message, lastViewedTimestamp);
149
+ }
150
+ const grew = roomMessages.length > lengthBefore;
151
+ const atHead = grew && lengthBefore > 0 && roomMessages[roomMessages.length - 1] === tailBefore;
152
+ return {
153
+ grew,
154
+ atHead
155
+ };
156
+ };
157
+ const capAfterGrowth = (messages, lengthBefore, atHead) => {
158
+ if (atHead) {
159
+ enforceMessageCap(messages, RUNTIME_MESSAGE_CEILING);
160
+ return;
161
+ }
162
+ enforceMessageCap(messages, Math.min(RUNTIME_MESSAGE_CEILING, Math.max(RUNTIME_MESSAGE_LIMIT, lengthBefore)));
163
+ };
164
+ const bumpLastMessageTimestamp = (state, roomJID, message) => {
165
+ const room = state.rooms[roomJID];
166
+ if (!room || message?.id === 'delimiter-new') {
167
+ return;
168
+ }
169
+ const ts = Number(message?.id);
170
+ if (!Number.isFinite(ts)) {
171
+ return;
172
+ }
173
+ if ((room.lastMessageTimestamp ?? 0) <= ts) {
174
+ room.lastMessageTimestamp = ts;
175
+ }
176
+ };
177
+ const upsertRoom = (state, roomData) => {
178
+ const existing = state.rooms[roomData.jid];
179
+ let lastViewed;
180
+ const serverMarker = state.privateStoreMarkers?.[roomData.jid] || 0;
181
+ if (roomData.lastViewedTimestamp != null && roomData.lastViewedTimestamp !== 0) {
182
+ lastViewed = roomData.lastViewedTimestamp;
183
+ } else if (existing?.lastViewedTimestamp != null && existing.lastViewedTimestamp > 0) {
184
+ lastViewed = existing.lastViewedTimestamp;
185
+ } else if (serverMarker > 0) {
186
+ lastViewed = serverMarker;
187
+ } else {
188
+ const msgs = roomData.messages || [];
189
+ let newest = 0;
190
+ for (const m of msgs) {
191
+ const t = m?.messageTimestampMs || (m?.date ? new Date(m.date).getTime() : 0);
192
+ if (t > newest) {
193
+ newest = t;
194
+ }
195
+ }
196
+ lastViewed = newest; // 0 if no messages → cold-start safe
197
+ }
198
+ const incomingMessages = Array.isArray(roomData.messages) ? roomData.messages : [];
199
+ const existingMessages = Array.isArray(existing?.messages) ? existing.messages : [];
200
+ state.rooms[roomData.jid] = {
201
+ ...roomData,
202
+ icon: roomData.icon !== undefined ? roomData.icon : existing?.icon,
203
+ roomBg: roomData.roomBg !== undefined ? roomData.roomBg : existing?.roomBg,
204
+ messages: existingMessages.length > 0 ? existingMessages : incomingMessages,
205
+ lastViewedTimestamp: lastViewed,
206
+ unreadMessages: roomData.unreadMessages ?? existing?.unreadMessages ?? 0,
207
+ unreadBaselineTimestamp: existing?.unreadBaselineTimestamp ?? existing?.lastViewedTimestamp ?? roomData.unreadBaselineTimestamp ?? 0
208
+ };
209
+ };
210
+
211
+ /** Order two numeric stanza ids (microsecond timestamps, too long for a
212
+ * double) without BigInt: by length, then lexicographically. */
213
+ const compareStanzaIds = (a, b) => a.length !== b.length ? a.length - b.length : a < b ? -1 : a > b ? 1 : 0;
214
+ exports.compareStanzaIds = compareStanzaIds;
215
+ const applyReactionToMessage = (message, from, reactions, data, ts) => {
216
+ const fromId = String(from || '').split('/')[0].split('@')[0];
217
+ if (!fromId) {
218
+ return;
219
+ }
220
+ const list = (reactions || []).filter(r => !!r);
221
+ const current = {
222
+ ...(message.reaction || {})
223
+ };
224
+ const prev = current[fromId];
225
+ // An older reaction (from a history page loaded after a newer one) never
226
+ // overwrites what is already known.
227
+ if (ts && prev?.ts && compareStanzaIds(ts, prev.ts) < 0) {
228
+ return;
229
+ }
230
+ if (list.length === 0) {
231
+ if (ts) {
232
+ // Keep a "removed" marker so an older reaction can't come back.
233
+ current[fromId] = {
234
+ emoji: [],
235
+ data: data || {},
236
+ ts
237
+ };
238
+ } else {
239
+ delete current[fromId];
240
+ }
241
+ } else {
242
+ current[fromId] = {
243
+ emoji: list,
244
+ data: data || {},
245
+ ...(ts ? {
246
+ ts
247
+ } : {})
248
+ };
249
+ }
250
+ const anyShown = Object.values(current).some(r => r?.emoji?.length);
251
+ message.reaction = anyShown || Object.keys(current).length ? current : undefined;
252
+ };
253
+ exports.applyReactionToMessage = applyReactionToMessage;
254
+ /** Reactions whose message is not loaded yet — applied when it arrives. */
255
+ const takePendingReactions = (state, roomJID, message) => {
256
+ const byMessage = state.pendingReactions?.[roomJID];
257
+ if (!byMessage) {
258
+ return;
259
+ }
260
+ const keys = [String(message.id), message.xmppId ? String(message.xmppId) : ''];
261
+ for (const key of keys) {
262
+ const list = key ? byMessage[key] : undefined;
263
+ if (!list) {
264
+ continue;
265
+ }
266
+ for (const r of list) {
267
+ applyReactionToMessage(message, r.from, r.reactions, r.data, r.ts);
268
+ }
269
+ delete byMessage[key];
270
+ }
271
+ };
272
+ const enforceMessageCap = (messages, limit = RUNTIME_MESSAGE_LIMIT) => {
111
273
  // Trim oldest until we're at/under the limit. Mutates in place
112
274
  // (immer-compatible inside reducers).
113
- while (messages.length > RUNTIME_MESSAGE_LIMIT) {
114
- messages.shift();
275
+ if (messages.length > limit) {
276
+ messages.splice(0, messages.length - limit);
115
277
  }
116
278
  };
117
279
 
@@ -190,10 +352,24 @@ function mergeHistoryIntoCache(existing, fetched) {
190
352
  // body). Preserve `isEdited` from the cached copy so a message edited
191
353
  // before reload keeps its marker instead of losing it on history sync.
192
354
  const prev = byId.get(String(m.id));
193
- byId.set(String(m.id), prev?.isEdited && !m.isEdited ? {
355
+ let next = prev?.isEdited && !m.isEdited ? {
194
356
  ...m,
195
357
  isEdited: true
196
- } : m);
358
+ } : m;
359
+ if (prev?.reaction && !next.reaction) {
360
+ next = {
361
+ ...next,
362
+ reaction: prev.reaction
363
+ };
364
+ }
365
+ // A history merge must not close a thread the user has open.
366
+ if (prev?.activeMessage && !next.activeMessage) {
367
+ next = {
368
+ ...next,
369
+ activeMessage: true
370
+ };
371
+ }
372
+ byId.set(String(m.id), next);
197
373
  }
198
374
  const merged = collapseCallLogDuplicates(Array.from(byId.values()).sort(byMs));
199
375
  return [...capTail(merged), ...pending];
@@ -212,7 +388,8 @@ const initialState = {
212
388
  },
213
389
  pendingNotificationJid: null,
214
390
  privateStoreMarkers: {},
215
- readBoundaries: {}
391
+ readBoundaries: {},
392
+ pendingReactions: {}
216
393
  };
217
394
  const isValidRoomJid = jid => {
218
395
  if (typeof jid !== 'string' || !jid) return false;
@@ -237,74 +414,33 @@ const addRoomViaApi = exports.addRoomViaApi = (0, _toolkit.createAsyncThunk)('ro
237
414
  // emitted .d.ts (TS4023). See chatSettingsSlice.ts for the same pattern.
238
415
  const reducers = {
239
416
  addRoom(state, action) {
240
- const {
241
- roomData
242
- } = action.payload;
243
- const existing = state.rooms[roomData.jid];
244
- // Default-marker resolution (cold-start unread bug):
245
- // 1. Explicit value on the payload wins.
246
- // 2. Existing redux value wins (preserves persisted/hydrated
247
- // markers when the privateStore pull lands before
248
- // /chats/my).
249
- // 3. Otherwise, anchor to the *newest known message* in the
250
- // payload — this marks everything currently in the room
251
- // as "seen" but lets any NEWER incoming message count as
252
- // unread. Previously this fell back to `Date.now()`, which
253
- // stamped a future-leaning marker that hid genuinely-new
254
- // messages received while the app was closed.
255
- // 4. If there are no messages at all yet, stamp `0` (=
256
- // "unknown — let the privateStore hydration set the real
257
- // marker before any future message arrives").
258
- let lastViewed;
259
- // Treat an incoming `0` as "unset". stanzaHandlers' addRoom passes
260
- // `lastViewedTimestamp: 0` as a placeholder; the old `!= null` check
261
- // let that 0 win and OVERWROTE the persisted/hydrated marker from
262
- // the previous session, so cold-start showed no unread badge for
263
- // messages received while the app was closed (bug #19/#20). A real
264
- // (non-zero) explicit value still wins; otherwise keep the existing
265
- // value; otherwise fall back to the server-side read marker fetched
266
- // from the private store (so a room the user has NEVER opened this
267
- // session still gets a real baseline — without it the unread
268
- // middleware's `lastViewedTimestamp > 0` gate skipped the room
269
- // forever and the badge never lit up); otherwise anchor to the
270
- // newest message in the payload.
271
- const serverMarker = state.privateStoreMarkers?.[roomData.jid] || 0;
272
- if (roomData.lastViewedTimestamp != null && roomData.lastViewedTimestamp !== 0) {
273
- lastViewed = roomData.lastViewedTimestamp;
274
- } else if (existing?.lastViewedTimestamp != null && existing.lastViewedTimestamp > 0) {
275
- lastViewed = existing.lastViewedTimestamp;
276
- } else if (serverMarker > 0) {
277
- lastViewed = serverMarker;
278
- } else {
279
- const msgs = roomData.messages || [];
280
- let newest = 0;
281
- for (const m of msgs) {
282
- const t = m?.messageTimestampMs || (m?.date ? new Date(m.date).getTime() : 0);
283
- if (t > newest) {
284
- newest = t;
285
- }
417
+ upsertRoom(state, action.payload.roomData);
418
+ },
419
+ setUnreadCounts(state, action) {
420
+ for (const [jid, count] of Object.entries(action.payload || {})) {
421
+ const room = state.rooms[jid];
422
+ if (!room) {
423
+ continue;
286
424
  }
287
- lastViewed = newest; // 0 if no messages → cold-start safe
288
- }
289
- // Preserve cached messages + unread when the incoming room carries
290
- // none. The /chats/my fetch (rooms.api) builds rooms with
291
- // `messages: []` and no unread; without this guard, re-entering the
292
- // app replaced every cached room with an empty one — wiping history
293
- // AND the unread badge before the history scheduler could re-merge
294
- // (the user's "it clears cache, unread and messages" bug). New rooms
295
- // (no existing) fall through to the incoming values. Mirrors
296
- // addRoomFromApi's preservation.
297
- const incomingMessages = Array.isArray(roomData.messages) ? roomData.messages : [];
298
- const existingMessages = Array.isArray(existing?.messages) ? existing.messages : [];
299
- state.rooms[roomData.jid] = {
300
- ...roomData,
301
- icon: roomData.icon !== undefined ? roomData.icon : existing?.icon,
302
- roomBg: roomData.roomBg !== undefined ? roomData.roomBg : existing?.roomBg,
303
- messages: existingMessages.length > 0 ? existingMessages : incomingMessages,
304
- lastViewedTimestamp: lastViewed,
305
- unreadMessages: roomData.unreadMessages ?? existing?.unreadMessages ?? 0,
306
- unreadBaselineTimestamp: existing?.unreadBaselineTimestamp ?? existing?.lastViewedTimestamp ?? roomData.unreadBaselineTimestamp ?? 0
307
- };
425
+ if (room.unreadMessages !== count) {
426
+ room.unreadMessages = count;
427
+ }
428
+ // "N+" only means "a whole page was unread"; an exact count below a
429
+ // page (or read to zero) settles it.
430
+ if (room.unreadCapped && count < UNREAD_CAP_PAGE) {
431
+ room.unreadCapped = false;
432
+ }
433
+ }
434
+ },
435
+ /** Several rooms in one action — the cold-start rehydrate of the whole
436
+ * cache used to be one `addRoom` per room, each running every
437
+ * middleware over every room already added (O(rooms²)). */
438
+ addRooms(state, action) {
439
+ for (const roomData of action.payload.rooms || []) {
440
+ if (roomData?.jid) {
441
+ upsertRoom(state, roomData);
442
+ }
443
+ }
308
444
  },
309
445
  deleteRoom(state, action) {
310
446
  const {
@@ -367,6 +503,7 @@ const reducers = {
367
503
  room.messages.map(message => {
368
504
  if (message.id === messageId) {
369
505
  message.isDeleted = true;
506
+ message.reaction = undefined;
370
507
  }
371
508
  });
372
509
  },
@@ -406,67 +543,50 @@ const reducers = {
406
543
  message,
407
544
  start
408
545
  } = action.payload;
409
-
410
- // Call signaling broadcasts ("call-token", "call-state", etc.)
411
- // sometimes slip past the live XMPP filter (MAM history, mucsub
412
- // catch-up), drop them here so they never land in the transcript
413
- // or the room-list "last message" preview.
414
- if (isCallSignalMessage(message)) {
415
- return;
546
+ const lengthBefore = state.rooms[roomJID]?.messages?.length || 0;
547
+ const outcome = insertRoomMessage(state, roomJID, message, start);
548
+ if (outcome.grew) {
549
+ capAfterGrowth(state.rooms[roomJID].messages, lengthBefore, outcome.atHead);
416
550
  }
417
-
418
- // Guard against the "stanza arrived before /chats/my completed"
419
- // race — without this, the optional-chain `?.messages` falls
420
- // back to undefined, and the assignment below tries to set
421
- // `.messages` on undefined → TypeError. Caller can safely
422
- // ignore the message; the room will get its messages array on
423
- // `addRoom` when the API response lands.
424
- if (!state.rooms[roomJID]) {
551
+ bumpLastMessageTimestamp(state, roomJID, message);
552
+ },
553
+ /**
554
+ * A whole page of messages (a MAM history page) in ONE action: the same
555
+ * per-message insert as `addRoomMessage`, but the cap, the middleware
556
+ * chain and every subscriber run once per page instead of once per
557
+ * message.
558
+ */
559
+ addRoomMessages(state, action) {
560
+ const {
561
+ roomJID,
562
+ messages,
563
+ start
564
+ } = action.payload;
565
+ if (!state.rooms[roomJID] || !Array.isArray(messages)) {
425
566
  return;
426
567
  }
427
- if (!state.rooms[roomJID].messages) {
428
- state.rooms[roomJID].messages = [];
429
- }
430
- const roomMessages = state.rooms[roomJID].messages;
431
-
432
- // Collapse multiple call-state events for the same call into a single
433
- // log entry. Sources: the client-side fallback written at hangup (id
434
- // "calllog-<callId>", exists only locally) and the server broadcast(s),
435
- // which can fire once per participant leaving (earlier ones carry a
436
- // partial durationMs). Rules:
437
- // - the SERVER copy is canonical for identity (id/date/xmppId): its
438
- // archive id is what MAM and the catch-up anchor return later, so
439
- // keeping a local "calllog-" id around breaks anchor matching and
440
- // duplicates the entry on the next history merge;
441
- // - the LARGEST duration wins for display, so a 2-minute call doesn't
442
- // render as "2 sec".
443
- const incomingCallLog = message.callLog;
444
- if (incomingCallLog?.callId) {
445
- const existingCallIdx = roomMessages.findIndex(msg => msg.callLog?.callId === incomingCallLog.callId);
446
- if (existingCallIdx !== -1) {
447
- const existing = roomMessages[existingCallIdx];
448
- const merged = mergeCallLogEntries(existing, message);
449
- if (merged !== existing) {
450
- roomMessages[existingCallIdx] = merged;
568
+ const lengthBefore = state.rooms[roomJID].messages?.length || 0;
569
+ let grew = false;
570
+ let anyAtTail = false;
571
+ let newest;
572
+ for (const message of messages) {
573
+ const outcome = insertRoomMessage(state, roomJID, message, start);
574
+ if (outcome.grew) {
575
+ grew = true;
576
+ if (!outcome.atHead) {
577
+ anyAtTail = true;
451
578
  }
452
- return;
579
+ }
580
+ if (!newest || Number(message?.id) > Number(newest.id)) {
581
+ newest = message;
453
582
  }
454
583
  }
455
- const lengthBefore = roomMessages.length;
456
- if (roomMessages.length === 0 || start) {
457
- roomMessages.unshift(message);
458
- } else {
459
- const lastViewedValue = state.rooms[roomJID].lastViewedTimestamp;
460
- const lastViewedTimestamp = state.visibleRoomJID === roomJID ? null : lastViewedValue ? lastViewedValue : null;
461
- (0, _insertMessageWithDelimiter.insertMessageWithDelimiter)(roomMessages, message, lastViewedTimestamp);
584
+ if (grew) {
585
+ // A page that only prepended older history is never trimmed.
586
+ capAfterGrowth(state.rooms[roomJID].messages, lengthBefore, !anyAtTail);
462
587
  }
463
-
464
- // Apply the in-memory cap only when the array actually GREW
465
- // (i.e. this wasn't a dedupe/merge that left length unchanged).
466
- // Otherwise repeated echoes of the same message would chip away
467
- // at the oldest history for no reason.
468
- if (roomMessages.length > lengthBefore) {
469
- enforceMessageCap(roomMessages);
588
+ if (newest) {
589
+ bumpLastMessageTimestamp(state, roomJID, newest);
470
590
  }
471
591
  },
472
592
  deleteAllRooms(state) {
@@ -685,21 +805,38 @@ const reducers = {
685
805
  const {
686
806
  roomJID,
687
807
  messageId,
688
- reactions
808
+ reactions,
809
+ from,
810
+ data,
811
+ latestReactionTimestamp
689
812
  } = action.payload;
813
+ if (!from) {
814
+ return;
815
+ }
690
816
  const room = state.rooms[roomJID];
691
- if (!room?.messages) {
817
+ const target = room?.messages?.find(msg => msg?.id === messageId || msg?.xmppId === messageId);
818
+ if (target) {
819
+ applyReactionToMessage(target, from, reactions, data, latestReactionTimestamp);
692
820
  return;
693
821
  }
694
- for (const msg of room.messages) {
695
- if (msg?.id === messageId) {
696
- msg.reactions = reactions;
697
- break;
698
- }
822
+ // The message is not loaded (yet): keep the reaction for it.
823
+ if (!state.pendingReactions) {
824
+ state.pendingReactions = {};
825
+ }
826
+ const byMessage = state.pendingReactions[roomJID] ||= {};
827
+ const list = byMessage[messageId] ||= [];
828
+ if (list.length < 50) {
829
+ list.push({
830
+ from,
831
+ reactions,
832
+ data,
833
+ ts: latestReactionTimestamp
834
+ });
699
835
  }
700
836
  },
701
837
  setLogoutState: state => {
702
838
  state.rooms = {};
839
+ state.pendingReactions = {};
703
840
  state.activeRoomJID = null;
704
841
  state.visibleRoomJID = null;
705
842
  state.isLoading = false;
@@ -783,6 +920,9 @@ const reducers = {
783
920
  room.historyComplete = patch.historyComplete;
784
921
  }
785
922
  if (Array.isArray(patch.messages)) {
923
+ for (const m of patch.messages) {
924
+ takePendingReactions(state, patch.jid, m);
925
+ }
786
926
  // Merge the fetched page into cache by message id rather than
787
927
  // replacing — preserves older history + unread on re-entry. Only
788
928
  // a true gap (no overlapping id) clears this chat's cache. See
@@ -914,6 +1054,9 @@ const {
914
1054
  deleteRoom,
915
1055
  updateRoom,
916
1056
  applyRoomsPreloadBatch,
1057
+ addRoomMessages,
1058
+ addRooms,
1059
+ setUnreadCounts,
917
1060
  setPendingNotificationJid,
918
1061
  clearPendingNotificationJid,
919
1062
  setReactions,
@@ -923,6 +1066,9 @@ exports.mergeUsersSet = mergeUsersSet;
923
1066
  exports.setReactions = setReactions;
924
1067
  exports.clearPendingNotificationJid = clearPendingNotificationJid;
925
1068
  exports.setPendingNotificationJid = setPendingNotificationJid;
1069
+ exports.setUnreadCounts = setUnreadCounts;
1070
+ exports.addRooms = addRooms;
1071
+ exports.addRoomMessages = addRoomMessages;
926
1072
  exports.applyRoomsPreloadBatch = applyRoomsPreloadBatch;
927
1073
  exports.updateRoom = updateRoom;
928
1074
  exports.deleteRoom = deleteRoom;