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