@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
@@ -1,52 +1,44 @@
1
- /* eslint-disable react-hooks/rules-of-hooks -- pre-existing port artifacts; hooks called conditionally / inside helpers. TODO: refactor */
2
- import React, { FC, useMemo, useState } from 'react';
3
- import { View, Text, TouchableOpacity, Animated } from 'react-native';
4
- import styled from 'styled-components/native';
1
+ import React, { FC, useMemo, useRef, useState } from 'react';
2
+ import { View, Text, TouchableOpacity, Animated, StyleSheet } from 'react-native';
5
3
  import { ReactionMessage } from '../../types/types';
6
4
  import { useTheme } from '../../hooks/useTheme';
7
-
8
- const ReactionContainer = styled.View`
9
- flex-direction: row;
10
- align-items: center;
11
- gap: 8px;
12
- `;
13
-
14
- const ReactionBox = styled(TouchableOpacity)<{ active: boolean; color: string }>`
15
- padding: 4px 8px;
16
- border-radius: 20px;
17
- background-color: ${({ active, color, theme }) =>
18
- active ? color : theme.surface};
19
- flex-direction: row;
20
- align-items: center;
21
- justify-content: center;
22
- elevation: 3;
23
- `;
5
+ import { getEmojiNativeById } from '../../helpers/emoji';
24
6
 
25
7
  interface MessageReactionProps {
26
8
  color: string;
27
9
  reaction: Record<string, ReactionMessage>;
28
10
  changeReaction: (reaction: string) => void;
29
11
  userName?: string;
30
- }
31
12
 
32
- const emojiMap: Record<string, string> = {
33
- joy: '😂',
34
- heart: '❤️',
35
- fire: '🔥',
36
- '+1': '👍',
37
- smile: '😄',
38
- scream: '😱',
39
- };
13
+ interactive?: boolean;
14
+ }
40
15
 
41
16
  export const MessageReaction: FC<MessageReactionProps> = ({
42
17
  reaction,
43
18
  color,
44
19
  changeReaction,
45
20
  userName,
21
+ interactive = true,
46
22
  }) => {
47
23
  const theme = useTheme();
48
24
  const [tooltipEmoji, setTooltipEmoji] = useState<string | null>(null);
49
- const fadeAnim = new Animated.Value(0);
25
+ const fadeAnim = useRef(new Animated.Value(0)).current;
26
+
27
+ const reactionDetails = useMemo(() => {
28
+ const result: Record<string, { count: number; users: string[] }> = {};
29
+ Object.values(reaction || {}).forEach(({ emoji, data }) => {
30
+ (emoji || []).forEach((em) => {
31
+ if (!result[em]) {result[em] = { count: 0, users: [] };}
32
+ result[em].count += 1;
33
+ result[em].users.push(
34
+ `${data?.senderFirstName || ''} ${data?.senderLastName || ''}`.trim()
35
+ );
36
+ });
37
+ });
38
+ return result;
39
+ }, [reaction]);
40
+
41
+ if (!reaction || Object.keys(reactionDetails).length === 0) {return null;}
50
42
 
51
43
  const showTooltip = (emoji: string) => {
52
44
  setTooltipEmoji(emoji);
@@ -65,90 +57,122 @@ export const MessageReaction: FC<MessageReactionProps> = ({
65
57
  }).start(() => setTooltipEmoji(null));
66
58
  };
67
59
 
68
- if (!reaction) {return null;}
69
-
70
- const reactionDetails = useMemo(() => {
71
- const result: Record<string, { count: number; users: string[] }> = {};
72
-
73
- Object.values(reaction).forEach(({ emoji, data }) => {
74
- if (emoji && emoji.length > 0)
75
- {emoji.forEach((em) => {
76
- if (!result[em]) {
77
- result[em] = { count: 0, users: [] };
78
- }
79
- result[em].count += 1;
80
- result[em].users.push(`${data?.senderFirstName} ${data?.senderLastName}`);
81
- });}
82
- });
83
-
84
- return result;
85
- }, [reaction]);
86
-
87
60
  return (
88
- <ReactionContainer>
61
+ <View style={styles.row}>
89
62
  {Object.entries(reactionDetails).map(([emoji, details]) => {
90
- const isUserReacted = userName
91
- ? details.users.includes(userName)
92
- : false;
93
-
63
+ const isUserReacted = !!userName && details.users.includes(userName);
94
64
  return (
95
- <View key={emoji} style={{ position: 'relative' }}>
96
- <ReactionBox
97
- active={isUserReacted}
98
- color={color}
65
+ <View key={emoji} style={styles.chipWrap}>
66
+ <TouchableOpacity
67
+ testID={`reaction-chip-${emoji}`}
68
+ activeOpacity={0.7}
69
+ disabled={!interactive}
99
70
  onPress={() => changeReaction(emoji)}
100
71
  onLongPress={() => showTooltip(emoji)}
101
72
  onPressOut={hideTooltip}
73
+ style={[
74
+ styles.chip,
75
+ {
76
+ backgroundColor: theme.surface,
77
+ borderColor: isUserReacted ? color : theme.border,
78
+ shadowColor: theme.shadow,
79
+ },
80
+ ]}
102
81
  >
103
- <Text style={{ fontSize: 18, marginRight: 4 }}>
104
- {emojiMap[emoji] || emoji}
105
- </Text>
82
+ {isUserReacted && (
83
+ <View
84
+ pointerEvents="none"
85
+ style={[styles.tint, { backgroundColor: `${color}26` }]}
86
+ />
87
+ )}
88
+ <Text style={styles.glyph}>{getEmojiNativeById(emoji)}</Text>
106
89
  <Text
107
- style={{
108
- fontSize: 14,
109
- fontWeight: '600',
110
- color: isUserReacted ? theme.textOnPrimary : color,
111
- }}
90
+ style={[
91
+ styles.count,
92
+ { color: isUserReacted ? color : theme.textSecondary },
93
+ ]}
112
94
  >
113
95
  {details.count}
114
96
  </Text>
115
- </ReactionBox>
97
+ </TouchableOpacity>
116
98
 
117
- {/* Tooltip */}
118
99
  {tooltipEmoji === emoji && (
119
100
  <Animated.View
120
- style={{
121
- position: 'absolute',
122
- bottom: 36,
123
- left: '50%',
124
- transform: [
125
- { translateX: -50 },
126
- {
127
- translateY: fadeAnim.interpolate({
128
- inputRange: [0, 1],
129
- outputRange: [4, 0],
130
- }),
131
- },
132
- ],
133
- opacity: fadeAnim,
134
- // Inverted pill: text colour as ground, surface as ink,
135
- // so it stays high-contrast on both palettes.
136
- backgroundColor: theme.text,
137
- borderRadius: 6,
138
- paddingHorizontal: 10,
139
- paddingVertical: 6,
140
- maxWidth: 220,
141
- zIndex: 999,
142
- }}
101
+ pointerEvents="none"
102
+ style={[
103
+ styles.tooltip,
104
+ {
105
+ opacity: fadeAnim,
106
+ transform: [
107
+ {
108
+ translateY: fadeAnim.interpolate({
109
+ inputRange: [0, 1],
110
+ outputRange: [4, 0],
111
+ }),
112
+ },
113
+ ],
114
+ // Inverted pill: text colour as ground, surface as ink,
115
+ // so it stays high-contrast on both palettes.
116
+ backgroundColor: theme.text,
117
+ },
118
+ ]}
143
119
  >
144
- <Text style={{ color: theme.surface, fontSize: 12 }}>
145
- {details.users.join(', ')}
120
+ <Text style={[styles.tooltipText, { color: theme.surface }]}>
121
+ {details.users.filter(Boolean).join(', ')}
146
122
  </Text>
147
123
  </Animated.View>
148
124
  )}
149
125
  </View>
150
126
  );
151
127
  })}
152
- </ReactionContainer>
128
+ </View>
153
129
  );
154
- };
130
+ };
131
+
132
+ const styles = StyleSheet.create({
133
+ row: {
134
+ flexDirection: 'row',
135
+ flexWrap: 'wrap',
136
+ alignItems: 'center',
137
+ gap: 6,
138
+ },
139
+ chipWrap: {
140
+ position: 'relative',
141
+ },
142
+ chip: {
143
+ flexDirection: 'row',
144
+ alignItems: 'center',
145
+ paddingVertical: 3,
146
+ paddingHorizontal: 8,
147
+ borderRadius: 14,
148
+ borderWidth: StyleSheet.hairlineWidth,
149
+ shadowOpacity: 0.08,
150
+ shadowOffset: { width: 0, height: 1 },
151
+ shadowRadius: 2,
152
+ elevation: 1,
153
+ },
154
+ tint: {
155
+ position: "absolute", top: 0, right: 0, bottom: 0, left: 0,
156
+ borderRadius: 14,
157
+ },
158
+ glyph: {
159
+ fontSize: 16,
160
+ marginRight: 4,
161
+ },
162
+ count: {
163
+ fontSize: 13,
164
+ fontWeight: '600',
165
+ },
166
+ tooltip: {
167
+ position: 'absolute',
168
+ bottom: 34,
169
+ left: 0,
170
+ borderRadius: 6,
171
+ paddingHorizontal: 10,
172
+ paddingVertical: 6,
173
+ maxWidth: 220,
174
+ },
175
+ tooltipText: {
176
+ fontSize: 12,
177
+ },
178
+ });
@@ -1,50 +1,83 @@
1
- import { FC } from 'react';
2
- import { IMessage } from '../../types/types';
3
- import { styled } from 'styled-components/native';
4
- import { Text } from 'react-native';
5
-
6
- export const StyledMessageReply = styled.TouchableOpacity<{
7
- isUser: boolean;
8
- configColor: string;
9
- }>`
10
- background-color: ${(props) => (props.isUser ? '#ffffff' : '#E7EDF9')};
11
- padding: 8px 16px;
12
- margin-bottom: 8px;
13
- border-radius: 4px;
14
- border-style: solid;
15
- border-start-width: ${(props) => (props.isUser ? 4 : 0)}px;
16
- border-start-color: ${(props) =>
17
- props.isUser ? props.configColor : 'transparent'};
18
- border-end-width: ${(props) => (!props.isUser ? 4 : 0)}px;
19
- border-end-color: ${(props) =>
20
- !props.isUser ? props.configColor : 'transparent'};
21
- `;
22
-
23
- const StyledText = styled.Text`
24
- font-size: 14px;
25
- overflow: hidden;
26
- `;
1
+ import React, { FC } from 'react';
2
+ import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
3
+ import { useTheme } from '../../hooks/useTheme';
27
4
 
28
5
  interface MessageReplyProps {
29
6
  isUser: boolean;
30
7
  text: string;
8
+ /** The parent's author, when the reply carries it. */
9
+ userName?: string;
31
10
  color?: string;
32
11
  handleReplyMessage: () => void;
33
12
  }
34
13
 
14
+ /**
15
+ * Quote of the parent at the top of a reply that was also sent to the
16
+ * channel (WhatsApp-style): accent bar, author, up to two lines of text.
17
+ * Tapping opens the parent's thread.
18
+ */
35
19
  export const MessageReply: FC<MessageReplyProps> = ({
36
20
  isUser,
37
21
  text,
38
- color = '#0052CD',
22
+ userName,
23
+ color,
39
24
  handleReplyMessage,
40
25
  }) => {
26
+ const theme = useTheme();
27
+ const accent = color || theme.primary;
41
28
  return (
42
- <StyledMessageReply
29
+ <TouchableOpacity
30
+ testID="message-reply-quote"
31
+ activeOpacity={0.7}
43
32
  onPress={handleReplyMessage}
44
- isUser={isUser}
45
- configColor={color}
33
+ style={[
34
+ styles.quote,
35
+ {
36
+ // A tint of the bubble's own ground, so it reads on both sides
37
+ // and in both themes.
38
+ backgroundColor: isUser ? 'rgba(0,0,0,0.12)' : theme.surfaceSecondary,
39
+ },
40
+ ]}
46
41
  >
47
- <StyledText>{text}</StyledText>
48
- </StyledMessageReply>
42
+ <View style={[styles.bar, { backgroundColor: accent }]} />
43
+ <View style={styles.body}>
44
+ {!!userName && (
45
+ <Text numberOfLines={1} style={[styles.author, { color: accent }]}>
46
+ {userName}
47
+ </Text>
48
+ )}
49
+ <Text
50
+ numberOfLines={2}
51
+ style={[styles.text, { color: isUser ? theme.messageTextUser : theme.text }]}
52
+ >
53
+ {text}
54
+ </Text>
55
+ </View>
56
+ </TouchableOpacity>
49
57
  );
50
58
  };
59
+
60
+ const styles = StyleSheet.create({
61
+ quote: {
62
+ flexDirection: 'row',
63
+ borderRadius: 8,
64
+ overflow: 'hidden',
65
+ marginBottom: 8,
66
+ },
67
+ bar: {
68
+ width: 4,
69
+ },
70
+ body: {
71
+ flexShrink: 1,
72
+ paddingVertical: 6,
73
+ paddingHorizontal: 10,
74
+ },
75
+ author: {
76
+ fontSize: 13,
77
+ fontWeight: '600',
78
+ marginBottom: 2,
79
+ },
80
+ text: {
81
+ fontSize: 14,
82
+ },
83
+ });
@@ -510,6 +510,10 @@ const ChatProfileModal: React.FC<ChatProfileModalProps> = ({
510
510
  ]}
511
511
  onLayout={(e) => setViewportHeight(e.nativeEvent.layout.height)}
512
512
  showsVerticalScrollIndicator={false}
513
+ // Magnet: a header released part-way settles fully open or fully
514
+ // collapsed; past the collapsed point the content scrolls freely.
515
+ snapToOffsets={[0, collapseDistance]}
516
+ snapToEnd={false}
513
517
  keyboardShouldPersistTaps="handled"
514
518
  scrollEventThrottle={16}
515
519
  onScroll={Animated.event(
@@ -2,9 +2,13 @@ import React from 'react';
2
2
  import { ModalBackground } from '../styledModalComponents';
3
3
  import { ModalType } from '../../../types/types';
4
4
  import { useDispatch } from 'react-redux';
5
- import { setActiveModal } from '../../../roomStore/chatSettingsSlice';
5
+ import {
6
+ setActiveModal,
7
+ setSelectedUser,
8
+ } from '../../../roomStore/chatSettingsSlice';
6
9
  import { MODAL_TYPES } from '../../../helpers/constants/MODAL_TYPES';
7
10
  import { MODAL_COMPONENTS } from '../../../helpers/constants/MODAL_COMPONENTS';
11
+ import { SwipeBackLayer } from './SwipeBackLayer';
8
12
 
9
13
  interface ModalProps {
10
14
  children?: React.ReactNode;
@@ -44,6 +48,33 @@ const Modal: React.FC<ModalProps> = ({ children, modal, setOpenModal }) => {
44
48
  return <>{renderModalContent()}{children}</>;
45
49
  }
46
50
 
51
+ // The profile screens are full-screen pages rather than dialogs: they
52
+ // slide in and can be swiped back from the left edge, like a room. One
53
+ // layer serves both, so going chat profile → member profile swaps the
54
+ // page in place instead of replaying the entrance.
55
+ if (modal === MODAL_TYPES.PROFILE || modal === MODAL_TYPES.CHAT_PROFILE) {
56
+ const ProfileComponent = MODAL_COMPONENTS[modal];
57
+ if (ProfileComponent) {
58
+ return (
59
+ <SwipeBackLayer
60
+ onClose={() => {
61
+ // The viewed member is cleared only once the page is gone, so
62
+ // it doesn't flip to the user's own profile mid-slide.
63
+ dispatch(setSelectedUser(undefined));
64
+ setOpenModal();
65
+ }}
66
+ >
67
+ {(close) => (
68
+ <>
69
+ <ProfileComponent handleCloseModal={close} />
70
+ {children}
71
+ </>
72
+ )}
73
+ </SwipeBackLayer>
74
+ );
75
+ }
76
+ }
77
+
47
78
  return (
48
79
  modal && (
49
80
  <ModalBackground
@@ -0,0 +1,221 @@
1
+ import React, {
2
+ ReactNode,
3
+ useCallback,
4
+ useEffect,
5
+ useMemo,
6
+ useRef,
7
+ useState,
8
+ } from 'react';
9
+ import {
10
+ Animated,
11
+ BackHandler,
12
+ Keyboard,
13
+ StyleSheet,
14
+ useWindowDimensions,
15
+ View,
16
+ } from 'react-native';
17
+ import { Gesture, GestureDetector } from 'react-native-gesture-handler';
18
+ import {
19
+ COMPLETE_DISTANCE,
20
+ COMPLETE_VELOCITY,
21
+ EDGE_WIDTH,
22
+ LIST_DIM,
23
+ POP,
24
+ PUSH,
25
+ } from '../../MainComponents/RoomStack';
26
+
27
+ interface SwipeBackLayerProps {
28
+ /** Called once the screen has left (swipe, back button, hardware back). */
29
+ onClose: () => void;
30
+ /** Receives the animated close, to hand to the screen's own back button. */
31
+ children: (close: () => void) => ReactNode;
32
+ }
33
+
34
+ /**
35
+ * Full-screen modal layer with the same navigation feel as RoomStack: it
36
+ * slides in from the right, and a swipe from the left edge drags it back
37
+ * out over whatever is underneath (the room or the list). Like RoomStack it
38
+ * runs on RN's own `Animated`, one value driving every layer.
39
+ */
40
+ export const SwipeBackLayer: React.FC<SwipeBackLayerProps> = ({
41
+ onClose,
42
+ children,
43
+ }) => {
44
+ const { width: windowWidth } = useWindowDimensions();
45
+ const [width, setWidth] = useState(windowWidth);
46
+ const widthRef = useRef(width);
47
+ widthRef.current = width;
48
+ const x = useRef(new Animated.Value(windowWidth)).current;
49
+ const closing = useRef(false);
50
+
51
+ const slideTo = useCallback(
52
+ (
53
+ toValue: number,
54
+ config: typeof PUSH,
55
+ done?: (finished: boolean) => void
56
+ ) => {
57
+ Animated.timing(x, {
58
+ toValue,
59
+ ...config,
60
+ useNativeDriver: true,
61
+ }).start(({ finished }) => done?.(finished));
62
+ },
63
+ [x]
64
+ );
65
+
66
+ useEffect(() => {
67
+ slideTo(0, PUSH);
68
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
69
+
70
+ const onCloseRef = useRef(onClose);
71
+ onCloseRef.current = onClose;
72
+ const [closeCount, setCloseCount] = useState(0);
73
+ const finish = useCallback(() => {
74
+ onCloseRef.current();
75
+ setCloseCount(count => count + 1);
76
+ }, []);
77
+
78
+ // `onClose` normally unmounts this layer. If it is still here afterwards
79
+ // (the modal did not close), slide the screen back rather than leave it
80
+ // parked off-screen.
81
+ useEffect(() => {
82
+ if (closeCount === 0) {
83
+ return;
84
+ }
85
+ closing.current = false;
86
+ slideTo(0, POP);
87
+ }, [closeCount]); // eslint-disable-line react-hooks/exhaustive-deps
88
+
89
+ const slideOut = useCallback(() => {
90
+ closing.current = true;
91
+ slideTo(widthRef.current, POP, finished => {
92
+ if (finished) {
93
+ finish();
94
+ } else {
95
+ closing.current = false;
96
+ }
97
+ });
98
+ }, [finish, slideTo]);
99
+
100
+ const close = useCallback(() => {
101
+ if (closing.current) {
102
+ return;
103
+ }
104
+ Keyboard.dismiss();
105
+ slideOut();
106
+ }, [slideOut]);
107
+
108
+ useEffect(() => {
109
+ const sub = BackHandler.addEventListener('hardwareBackPress', () => {
110
+ close();
111
+ return true;
112
+ });
113
+ return () => sub.remove();
114
+ }, [close]);
115
+
116
+ const swipeBack = useMemo(
117
+ () =>
118
+ Gesture.Pan()
119
+ .runOnJS(true)
120
+ .hitSlop({ left: 0, width: EDGE_WIDTH })
121
+ .activeOffsetX(12)
122
+ .failOffsetY([-16, 16])
123
+ .onStart(() => {
124
+ if (closing.current) {
125
+ return;
126
+ }
127
+ Keyboard.dismiss();
128
+ x.stopAnimation();
129
+ })
130
+ .onUpdate(e => {
131
+ if (closing.current) {
132
+ return;
133
+ }
134
+ x.setValue(Math.min(Math.max(e.translationX, 0), widthRef.current));
135
+ })
136
+ .onEnd(e => {
137
+ if (closing.current) {
138
+ return;
139
+ }
140
+ const complete =
141
+ e.translationX > widthRef.current * COMPLETE_DISTANCE ||
142
+ e.velocityX > COMPLETE_VELOCITY;
143
+ if (complete) {
144
+ slideOut();
145
+ } else {
146
+ slideTo(0, POP);
147
+ }
148
+ }),
149
+ [slideOut, slideTo, x]
150
+ );
151
+
152
+ const dimOpacity = useMemo(
153
+ () =>
154
+ x.interpolate({
155
+ inputRange: [0, width],
156
+ outputRange: [LIST_DIM, 0],
157
+ extrapolate: 'clamp',
158
+ }),
159
+ [x, width]
160
+ );
161
+
162
+ return (
163
+ <View
164
+ pointerEvents="box-none"
165
+ style={styles.host}
166
+ onLayout={e => {
167
+ const next = e.nativeEvent.layout.width;
168
+ if (next > 0 && next !== widthRef.current) {
169
+ setWidth(next);
170
+ }
171
+ }}
172
+ >
173
+ <Animated.View
174
+ pointerEvents="none"
175
+ style={[styles.fill, styles.dim, { opacity: dimOpacity }]}
176
+ />
177
+ <GestureDetector gesture={swipeBack}>
178
+ <Animated.View
179
+ style={[
180
+ styles.fill,
181
+ styles.screen,
182
+ { transform: [{ translateX: x }] },
183
+ ]}
184
+ >
185
+ {children(close)}
186
+ </Animated.View>
187
+ </GestureDetector>
188
+ </View>
189
+ );
190
+ };
191
+
192
+ const styles = StyleSheet.create({
193
+ host: {
194
+ position: 'absolute',
195
+ top: 0,
196
+ right: 0,
197
+ bottom: 0,
198
+ left: 0,
199
+ zIndex: 1000,
200
+ overflow: 'hidden',
201
+ },
202
+ fill: {
203
+ position: 'absolute',
204
+ top: 0,
205
+ right: 0,
206
+ bottom: 0,
207
+ left: 0,
208
+ },
209
+ dim: {
210
+ backgroundColor: '#000',
211
+ },
212
+ // Same box the shared ModalBackground gives its content.
213
+ screen: {
214
+ justifyContent: 'center',
215
+ alignItems: 'center',
216
+ shadowColor: '#000',
217
+ shadowOffset: { width: -4, height: 0 },
218
+ shadowOpacity: 0.18,
219
+ shadowRadius: 12,
220
+ },
221
+ });