@ethora/chat-component-rn 26.9.0 → 26.10.0

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 (761) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +19 -0
  3. package/lib/commonjs/assets/icons.js +2 -2
  4. package/lib/commonjs/assets/icons.js.map +1 -1
  5. package/lib/commonjs/components/Header/HeaderRoomList.js +22 -6
  6. package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
  7. package/lib/commonjs/components/InputComponents/Search.js +38 -1
  8. package/lib/commonjs/components/InputComponents/Search.js.map +1 -1
  9. package/lib/commonjs/components/MainComponents/ArchivedMessageCard.js +166 -0
  10. package/lib/commonjs/components/MainComponents/ArchivedMessageCard.js.map +1 -0
  11. package/lib/commonjs/components/MainComponents/ChatHeader.js +22 -5
  12. package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
  13. package/lib/commonjs/components/MainComponents/ChatRoom.js +56 -25
  14. package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
  15. package/lib/commonjs/components/MainComponents/ChatWrapper.js +53 -4
  16. package/lib/commonjs/components/MainComponents/ChatWrapper.js.map +1 -1
  17. package/lib/commonjs/components/MainComponents/MediaMessage.js +18 -3
  18. package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
  19. package/lib/commonjs/components/MainComponents/MessageList.js +739 -42
  20. package/lib/commonjs/components/MainComponents/MessageList.js.map +1 -1
  21. package/lib/commonjs/components/MainComponents/MessageSearchButton.js +58 -0
  22. package/lib/commonjs/components/MainComponents/MessageSearchButton.js.map +1 -0
  23. package/lib/commonjs/components/MainComponents/ReduxWrapper.js +15 -6
  24. package/lib/commonjs/components/MainComponents/ReduxWrapper.js.map +1 -1
  25. package/lib/commonjs/components/MainComponents/RoomList.js +110 -1
  26. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  27. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js +14 -3
  28. package/lib/commonjs/components/Menu/HeaderRoomListMenu.js.map +1 -1
  29. package/lib/commonjs/components/MessageBubble/BubbleHighlight.js +112 -0
  30. package/lib/commonjs/components/MessageBubble/BubbleHighlight.js.map +1 -0
  31. package/lib/commonjs/components/MessageBubble/Message.js +169 -125
  32. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  33. package/lib/commonjs/components/MessageBubble/MessageInteractions.js +98 -78
  34. package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
  35. package/lib/commonjs/components/MessageBubble/messageMenuLayout.js +50 -0
  36. package/lib/commonjs/components/MessageBubble/messageMenuLayout.js.map +1 -0
  37. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +73 -37
  38. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  39. package/lib/commonjs/components/Modals/MessageSearchModal/MessageHitResults.js +253 -0
  40. package/lib/commonjs/components/Modals/MessageSearchModal/MessageHitResults.js.map +1 -0
  41. package/lib/commonjs/components/Modals/MessageSearchModal/MessageSearchModal.js +488 -0
  42. package/lib/commonjs/components/Modals/MessageSearchModal/MessageSearchModal.js.map +1 -0
  43. package/lib/commonjs/components/Modals/MessageSearchModal/openHit.js +51 -0
  44. package/lib/commonjs/components/Modals/MessageSearchModal/openHit.js.map +1 -0
  45. package/lib/commonjs/components/Modals/MessageSearchModal/resolveSender.js +47 -0
  46. package/lib/commonjs/components/Modals/MessageSearchModal/resolveSender.js.map +1 -0
  47. package/lib/commonjs/components/Modals/MessageSearchModal/searchFilters.js +83 -0
  48. package/lib/commonjs/components/Modals/MessageSearchModal/searchFilters.js.map +1 -0
  49. package/lib/commonjs/components/Modals/MessageSearchModal/snippet.js +61 -0
  50. package/lib/commonjs/components/Modals/MessageSearchModal/snippet.js.map +1 -0
  51. package/lib/commonjs/components/Modals/MessageSearchModal/useMessageSearch.js +136 -0
  52. package/lib/commonjs/components/Modals/MessageSearchModal/useMessageSearch.js.map +1 -0
  53. package/lib/commonjs/components/Modals/PublicChatsModal/PublicChatsModal.js +306 -0
  54. package/lib/commonjs/components/Modals/PublicChatsModal/PublicChatsModal.js.map +1 -0
  55. package/lib/commonjs/components/Modals/PublicChatsModal/publicChatsLogic.js +36 -0
  56. package/lib/commonjs/components/Modals/PublicChatsModal/publicChatsLogic.js.map +1 -0
  57. package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js +8 -1
  58. package/lib/commonjs/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
  59. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +13 -2
  60. package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
  61. package/lib/commonjs/components/RoomComponents/SwipeableRoomRow.js +38 -6
  62. package/lib/commonjs/components/RoomComponents/SwipeableRoomRow.js.map +1 -1
  63. package/lib/commonjs/components/Thread/ThreadHeader.js +3 -1
  64. package/lib/commonjs/components/Thread/ThreadHeader.js.map +1 -1
  65. package/lib/commonjs/components/Thread/ThreadWrapper.js +90 -10
  66. package/lib/commonjs/components/Thread/ThreadWrapper.js.map +1 -1
  67. package/lib/commonjs/components/styled/AudioDecoderHost.js +338 -0
  68. package/lib/commonjs/components/styled/AudioDecoderHost.js.map +1 -0
  69. package/lib/commonjs/components/styled/AudioMessage.js +493 -420
  70. package/lib/commonjs/components/styled/AudioMessage.js.map +1 -1
  71. package/lib/commonjs/components/styled/SendInput.js +31 -5
  72. package/lib/commonjs/components/styled/SendInput.js.map +1 -1
  73. package/lib/commonjs/context/MessageNotificationContext.js +14 -4
  74. package/lib/commonjs/context/MessageNotificationContext.js.map +1 -1
  75. package/lib/commonjs/context/xmppProvider.js +54 -79
  76. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  77. package/lib/commonjs/helpers/audioWaveform.js +165 -0
  78. package/lib/commonjs/helpers/audioWaveform.js.map +1 -0
  79. package/lib/commonjs/helpers/backgroundJoinSweep.js +36 -0
  80. package/lib/commonjs/helpers/backgroundJoinSweep.js.map +1 -0
  81. package/lib/commonjs/helpers/bubbleHighlight.js +44 -0
  82. package/lib/commonjs/helpers/bubbleHighlight.js.map +1 -0
  83. package/lib/commonjs/helpers/checkUniqueUsers.js +14 -12
  84. package/lib/commonjs/helpers/checkUniqueUsers.js.map +1 -1
  85. package/lib/commonjs/helpers/constants/MODAL_COMPONENTS.js +5 -1
  86. package/lib/commonjs/helpers/constants/MODAL_COMPONENTS.js.map +1 -1
  87. package/lib/commonjs/helpers/constants/MODAL_TYPES.js +3 -1
  88. package/lib/commonjs/helpers/constants/MODAL_TYPES.js.map +1 -1
  89. package/lib/commonjs/helpers/createRoomFromApi.js +40 -3
  90. package/lib/commonjs/helpers/createRoomFromApi.js.map +1 -1
  91. package/lib/commonjs/helpers/dedupeMembers.js +34 -0
  92. package/lib/commonjs/helpers/dedupeMembers.js.map +1 -0
  93. package/lib/commonjs/helpers/ethoraLogger.js +56 -0
  94. package/lib/commonjs/helpers/ethoraLogger.js.map +1 -0
  95. package/lib/commonjs/helpers/getUnnamedUsers.js +9 -4
  96. package/lib/commonjs/helpers/getUnnamedUsers.js.map +1 -1
  97. package/lib/commonjs/helpers/historyPreloadConfig.js +44 -0
  98. package/lib/commonjs/helpers/historyPreloadConfig.js.map +1 -0
  99. package/lib/commonjs/helpers/historyPreloadScheduler.js +372 -137
  100. package/lib/commonjs/helpers/historyPreloadScheduler.js.map +1 -1
  101. package/lib/commonjs/helpers/initRoomsPresence.js +17 -5
  102. package/lib/commonjs/helpers/initRoomsPresence.js.map +1 -1
  103. package/lib/commonjs/helpers/insertMessageWithDelimiter.js +5 -0
  104. package/lib/commonjs/helpers/insertMessageWithDelimiter.js.map +1 -1
  105. package/lib/commonjs/helpers/isLikelyMucJid.js +67 -0
  106. package/lib/commonjs/helpers/isLikelyMucJid.js.map +1 -0
  107. package/lib/commonjs/helpers/isMessageSearchEnabled.js +18 -0
  108. package/lib/commonjs/helpers/isMessageSearchEnabled.js.map +1 -0
  109. package/lib/commonjs/helpers/joiningRoom.js +14 -0
  110. package/lib/commonjs/helpers/joiningRoom.js.map +1 -0
  111. package/lib/commonjs/helpers/jumpThread.js +100 -0
  112. package/lib/commonjs/helpers/jumpThread.js.map +1 -0
  113. package/lib/commonjs/helpers/jumpToMessage.js +58 -0
  114. package/lib/commonjs/helpers/jumpToMessage.js.map +1 -0
  115. package/lib/commonjs/helpers/jumpWindow.js +187 -0
  116. package/lib/commonjs/helpers/jumpWindow.js.map +1 -0
  117. package/lib/commonjs/helpers/loadRoomHistory.js +75 -0
  118. package/lib/commonjs/helpers/loadRoomHistory.js.map +1 -0
  119. package/lib/commonjs/helpers/notificationPolicy.js +77 -0
  120. package/lib/commonjs/helpers/notificationPolicy.js.map +1 -0
  121. package/lib/commonjs/helpers/openRoomAtMessage.js +47 -0
  122. package/lib/commonjs/helpers/openRoomAtMessage.js.map +1 -0
  123. package/lib/commonjs/helpers/openThreadForJump.js +72 -0
  124. package/lib/commonjs/helpers/openThreadForJump.js.map +1 -0
  125. package/lib/commonjs/helpers/parseMessageReference.js +27 -8
  126. package/lib/commonjs/helpers/parseMessageReference.js.map +1 -1
  127. package/lib/commonjs/helpers/publicChatsEntry.js +17 -0
  128. package/lib/commonjs/helpers/publicChatsEntry.js.map +1 -0
  129. package/lib/commonjs/helpers/roomActivityScore.js +37 -0
  130. package/lib/commonjs/helpers/roomActivityScore.js.map +1 -0
  131. package/lib/commonjs/helpers/roomUserCount.js +36 -0
  132. package/lib/commonjs/helpers/roomUserCount.js.map +1 -0
  133. package/lib/commonjs/helpers/runConfiguredHistoryPreload.js +68 -0
  134. package/lib/commonjs/helpers/runConfiguredHistoryPreload.js.map +1 -0
  135. package/lib/commonjs/helpers/sessionAppId.js +24 -0
  136. package/lib/commonjs/helpers/sessionAppId.js.map +1 -0
  137. package/lib/commonjs/helpers/timestamp.js +43 -0
  138. package/lib/commonjs/helpers/timestamp.js.map +1 -0
  139. package/lib/commonjs/helpers/userResolver.js +517 -0
  140. package/lib/commonjs/helpers/userResolver.js.map +1 -0
  141. package/lib/commonjs/helpers/xmppIdShape.js +52 -0
  142. package/lib/commonjs/helpers/xmppIdShape.js.map +1 -0
  143. package/lib/commonjs/hooks/useChatWrapperInit.js +27 -5
  144. package/lib/commonjs/hooks/useChatWrapperInit.js.map +1 -1
  145. package/lib/commonjs/hooks/useHeapSender.js +54 -3
  146. package/lib/commonjs/hooks/useHeapSender.js.map +1 -1
  147. package/lib/commonjs/hooks/useJumpToMessage.js +411 -0
  148. package/lib/commonjs/hooks/useJumpToMessage.js.map +1 -0
  149. package/lib/commonjs/hooks/useMessageLoaderQueue.js +32 -5
  150. package/lib/commonjs/hooks/useMessageLoaderQueue.js.map +1 -1
  151. package/lib/commonjs/hooks/useMessageQueue.js +13 -5
  152. package/lib/commonjs/hooks/useMessageQueue.js.map +1 -1
  153. package/lib/commonjs/hooks/useRoomDirectory.js +29 -0
  154. package/lib/commonjs/hooks/useRoomDirectory.js.map +1 -0
  155. package/lib/commonjs/hooks/useRoomInitialization.js +27 -5
  156. package/lib/commonjs/hooks/useRoomInitialization.js.map +1 -1
  157. package/lib/commonjs/hooks/useRoomMute.js +62 -0
  158. package/lib/commonjs/hooks/useRoomMute.js.map +1 -0
  159. package/lib/commonjs/hooks/useRoomState.js +3 -1
  160. package/lib/commonjs/hooks/useRoomState.js.map +1 -1
  161. package/lib/commonjs/hooks/useSendMessage.js +13 -3
  162. package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
  163. package/lib/commonjs/i18n/strings.js +318 -6
  164. package/lib/commonjs/i18n/strings.js.map +1 -1
  165. package/lib/commonjs/networking/api-requests/messageSearch.api.js +87 -0
  166. package/lib/commonjs/networking/api-requests/messageSearch.api.js.map +1 -0
  167. package/lib/commonjs/networking/api-requests/publicChats.api.js +48 -0
  168. package/lib/commonjs/networking/api-requests/publicChats.api.js.map +1 -0
  169. package/lib/commonjs/networking/api-requests/roomMembers.api.js +253 -4
  170. package/lib/commonjs/networking/api-requests/roomMembers.api.js.map +1 -1
  171. package/lib/commonjs/networking/api-requests/rooms.api.js +48 -12
  172. package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
  173. package/lib/commonjs/networking/api-requests/xmppToken.api.js +71 -0
  174. package/lib/commonjs/networking/api-requests/xmppToken.api.js.map +1 -0
  175. package/lib/commonjs/networking/ethoraEvents.js +227 -0
  176. package/lib/commonjs/networking/ethoraEvents.js.map +1 -0
  177. package/lib/commonjs/networking/stanzaHandlers.js +153 -16
  178. package/lib/commonjs/networking/stanzaHandlers.js.map +1 -1
  179. package/lib/commonjs/networking/xmpp/allRoomPresences.xmpp.js +124 -3
  180. package/lib/commonjs/networking/xmpp/allRoomPresences.xmpp.js.map +1 -1
  181. package/lib/commonjs/networking/xmpp/getHistory.xmpp.js +319 -35
  182. package/lib/commonjs/networking/xmpp/getHistory.xmpp.js.map +1 -1
  183. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js +7 -0
  184. package/lib/commonjs/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  185. package/lib/commonjs/networking/xmpp/historyCursor.js +101 -0
  186. package/lib/commonjs/networking/xmpp/historyCursor.js.map +1 -0
  187. package/lib/commonjs/networking/xmpp/mamQueryIds.js +17 -0
  188. package/lib/commonjs/networking/xmpp/mamQueryIds.js.map +1 -0
  189. package/lib/commonjs/networking/xmpp/mamRouter.js +24 -9
  190. package/lib/commonjs/networking/xmpp/mamRouter.js.map +1 -1
  191. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js +70 -65
  192. package/lib/commonjs/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  193. package/lib/commonjs/networking/xmpp/roomJoinSweep.js +389 -0
  194. package/lib/commonjs/networking/xmpp/roomJoinSweep.js.map +1 -0
  195. package/lib/commonjs/networking/xmpp/sendMediaMessage.xmpp.js +0 -1
  196. package/lib/commonjs/networking/xmpp/sendMediaMessage.xmpp.js.map +1 -1
  197. package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js +0 -1
  198. package/lib/commonjs/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
  199. package/lib/commonjs/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js +0 -1
  200. package/lib/commonjs/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js.map +1 -1
  201. package/lib/commonjs/networking/xmppClient.js +269 -41
  202. package/lib/commonjs/networking/xmppClient.js.map +1 -1
  203. package/lib/commonjs/networking/xmppCredentials.js +80 -0
  204. package/lib/commonjs/networking/xmppCredentials.js.map +1 -0
  205. package/lib/commonjs/roomStore/Middleware/jumpThreadMiddleware.js +158 -0
  206. package/lib/commonjs/roomStore/Middleware/jumpThreadMiddleware.js.map +1 -0
  207. package/lib/commonjs/roomStore/Middleware/reactionsMiddleware.js +6 -0
  208. package/lib/commonjs/roomStore/Middleware/reactionsMiddleware.js.map +1 -1
  209. package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js +45 -7
  210. package/lib/commonjs/roomStore/Middleware/unreadMidlleware.js.map +1 -1
  211. package/lib/commonjs/roomStore/chatSettingsSlice.js +15 -1
  212. package/lib/commonjs/roomStore/chatSettingsSlice.js.map +1 -1
  213. package/lib/commonjs/roomStore/index.js +13 -3
  214. package/lib/commonjs/roomStore/index.js.map +1 -1
  215. package/lib/commonjs/roomStore/persistence.js +48 -1
  216. package/lib/commonjs/roomStore/persistence.js.map +1 -1
  217. package/lib/commonjs/roomStore/roomsSlice.js +474 -60
  218. package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
  219. package/lib/commonjs/roomStore/safeKey.js +44 -0
  220. package/lib/commonjs/roomStore/safeKey.js.map +1 -0
  221. package/lib/commonjs/roomStore/usersSetCap.js +37 -0
  222. package/lib/commonjs/roomStore/usersSetCap.js.map +1 -0
  223. package/lib/commonjs/version.js +1 -1
  224. package/lib/commonjs/version.js.map +1 -1
  225. package/lib/module/assets/icons.js +1 -1
  226. package/lib/module/assets/icons.js.map +1 -1
  227. package/lib/module/components/Header/HeaderRoomList.js +23 -7
  228. package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
  229. package/lib/module/components/InputComponents/Search.js +39 -2
  230. package/lib/module/components/InputComponents/Search.js.map +1 -1
  231. package/lib/module/components/MainComponents/ArchivedMessageCard.js +161 -0
  232. package/lib/module/components/MainComponents/ArchivedMessageCard.js.map +1 -0
  233. package/lib/module/components/MainComponents/ChatHeader.js +22 -5
  234. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  235. package/lib/module/components/MainComponents/ChatRoom.js +57 -26
  236. package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
  237. package/lib/module/components/MainComponents/ChatWrapper.js +54 -5
  238. package/lib/module/components/MainComponents/ChatWrapper.js.map +1 -1
  239. package/lib/module/components/MainComponents/MediaMessage.js +18 -3
  240. package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
  241. package/lib/module/components/MainComponents/MessageList.js +740 -42
  242. package/lib/module/components/MainComponents/MessageList.js.map +1 -1
  243. package/lib/module/components/MainComponents/MessageSearchButton.js +48 -0
  244. package/lib/module/components/MainComponents/MessageSearchButton.js.map +1 -0
  245. package/lib/module/components/MainComponents/ReduxWrapper.js +15 -7
  246. package/lib/module/components/MainComponents/ReduxWrapper.js.map +1 -1
  247. package/lib/module/components/MainComponents/RoomList.js +111 -2
  248. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  249. package/lib/module/components/Menu/HeaderRoomListMenu.js +15 -4
  250. package/lib/module/components/Menu/HeaderRoomListMenu.js.map +1 -1
  251. package/lib/module/components/MessageBubble/BubbleHighlight.js +106 -0
  252. package/lib/module/components/MessageBubble/BubbleHighlight.js.map +1 -0
  253. package/lib/module/components/MessageBubble/Message.js +172 -127
  254. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  255. package/lib/module/components/MessageBubble/MessageInteractions.js +98 -78
  256. package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
  257. package/lib/module/components/MessageBubble/messageMenuLayout.js +45 -0
  258. package/lib/module/components/MessageBubble/messageMenuLayout.js.map +1 -0
  259. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +74 -38
  260. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  261. package/lib/module/components/Modals/MessageSearchModal/MessageHitResults.js +243 -0
  262. package/lib/module/components/Modals/MessageSearchModal/MessageHitResults.js.map +1 -0
  263. package/lib/module/components/Modals/MessageSearchModal/MessageSearchModal.js +482 -0
  264. package/lib/module/components/Modals/MessageSearchModal/MessageSearchModal.js.map +1 -0
  265. package/lib/module/components/Modals/MessageSearchModal/openHit.js +45 -0
  266. package/lib/module/components/Modals/MessageSearchModal/openHit.js.map +1 -0
  267. package/lib/module/components/Modals/MessageSearchModal/resolveSender.js +41 -0
  268. package/lib/module/components/Modals/MessageSearchModal/resolveSender.js.map +1 -0
  269. package/lib/module/components/Modals/MessageSearchModal/searchFilters.js +74 -0
  270. package/lib/module/components/Modals/MessageSearchModal/searchFilters.js.map +1 -0
  271. package/lib/module/components/Modals/MessageSearchModal/snippet.js +57 -0
  272. package/lib/module/components/Modals/MessageSearchModal/snippet.js.map +1 -0
  273. package/lib/module/components/Modals/MessageSearchModal/useMessageSearch.js +131 -0
  274. package/lib/module/components/Modals/MessageSearchModal/useMessageSearch.js.map +1 -0
  275. package/lib/module/components/Modals/PublicChatsModal/PublicChatsModal.js +300 -0
  276. package/lib/module/components/Modals/PublicChatsModal/PublicChatsModal.js.map +1 -0
  277. package/lib/module/components/Modals/PublicChatsModal/publicChatsLogic.js +30 -0
  278. package/lib/module/components/Modals/PublicChatsModal/publicChatsLogic.js.map +1 -0
  279. package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js +8 -1
  280. package/lib/module/components/Modals/SelectUsersModal/SelectUsersModal.js.map +1 -1
  281. package/lib/module/components/RoomComponents/ChatRoomItem.js +14 -3
  282. package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
  283. package/lib/module/components/RoomComponents/SwipeableRoomRow.js +39 -7
  284. package/lib/module/components/RoomComponents/SwipeableRoomRow.js.map +1 -1
  285. package/lib/module/components/Thread/ThreadHeader.js +3 -1
  286. package/lib/module/components/Thread/ThreadHeader.js.map +1 -1
  287. package/lib/module/components/Thread/ThreadWrapper.js +89 -9
  288. package/lib/module/components/Thread/ThreadWrapper.js.map +1 -1
  289. package/lib/module/components/styled/AudioDecoderHost.js +332 -0
  290. package/lib/module/components/styled/AudioDecoderHost.js.map +1 -0
  291. package/lib/module/components/styled/AudioMessage.js +495 -422
  292. package/lib/module/components/styled/AudioMessage.js.map +1 -1
  293. package/lib/module/components/styled/SendInput.js +32 -6
  294. package/lib/module/components/styled/SendInput.js.map +1 -1
  295. package/lib/module/context/MessageNotificationContext.js +15 -5
  296. package/lib/module/context/MessageNotificationContext.js.map +1 -1
  297. package/lib/module/context/xmppProvider.js +54 -79
  298. package/lib/module/context/xmppProvider.js.map +1 -1
  299. package/lib/module/helpers/audioWaveform.js +153 -0
  300. package/lib/module/helpers/audioWaveform.js.map +1 -0
  301. package/lib/module/helpers/backgroundJoinSweep.js +30 -0
  302. package/lib/module/helpers/backgroundJoinSweep.js.map +1 -0
  303. package/lib/module/helpers/bubbleHighlight.js +38 -0
  304. package/lib/module/helpers/bubbleHighlight.js.map +1 -0
  305. package/lib/module/helpers/checkUniqueUsers.js +15 -13
  306. package/lib/module/helpers/checkUniqueUsers.js.map +1 -1
  307. package/lib/module/helpers/constants/MODAL_COMPONENTS.js +5 -1
  308. package/lib/module/helpers/constants/MODAL_COMPONENTS.js.map +1 -1
  309. package/lib/module/helpers/constants/MODAL_TYPES.js +3 -1
  310. package/lib/module/helpers/constants/MODAL_TYPES.js.map +1 -1
  311. package/lib/module/helpers/createRoomFromApi.js +37 -3
  312. package/lib/module/helpers/createRoomFromApi.js.map +1 -1
  313. package/lib/module/helpers/dedupeMembers.js +28 -0
  314. package/lib/module/helpers/dedupeMembers.js.map +1 -0
  315. package/lib/module/helpers/ethoraLogger.js +52 -0
  316. package/lib/module/helpers/ethoraLogger.js.map +1 -0
  317. package/lib/module/helpers/getUnnamedUsers.js +9 -4
  318. package/lib/module/helpers/getUnnamedUsers.js.map +1 -1
  319. package/lib/module/helpers/historyPreloadConfig.js +39 -0
  320. package/lib/module/helpers/historyPreloadConfig.js.map +1 -0
  321. package/lib/module/helpers/historyPreloadScheduler.js +368 -134
  322. package/lib/module/helpers/historyPreloadScheduler.js.map +1 -1
  323. package/lib/module/helpers/initRoomsPresence.js +18 -5
  324. package/lib/module/helpers/initRoomsPresence.js.map +1 -1
  325. package/lib/module/helpers/insertMessageWithDelimiter.js +5 -0
  326. package/lib/module/helpers/insertMessageWithDelimiter.js.map +1 -1
  327. package/lib/module/helpers/isLikelyMucJid.js +60 -0
  328. package/lib/module/helpers/isLikelyMucJid.js.map +1 -0
  329. package/lib/module/helpers/isMessageSearchEnabled.js +13 -0
  330. package/lib/module/helpers/isMessageSearchEnabled.js.map +1 -0
  331. package/lib/module/helpers/joiningRoom.js +9 -0
  332. package/lib/module/helpers/joiningRoom.js.map +1 -0
  333. package/lib/module/helpers/jumpThread.js +83 -0
  334. package/lib/module/helpers/jumpThread.js.map +1 -0
  335. package/lib/module/helpers/jumpToMessage.js +52 -0
  336. package/lib/module/helpers/jumpToMessage.js.map +1 -0
  337. package/lib/module/helpers/jumpWindow.js +177 -0
  338. package/lib/module/helpers/jumpWindow.js.map +1 -0
  339. package/lib/module/helpers/loadRoomHistory.js +69 -0
  340. package/lib/module/helpers/loadRoomHistory.js.map +1 -0
  341. package/lib/module/helpers/notificationPolicy.js +70 -0
  342. package/lib/module/helpers/notificationPolicy.js.map +1 -0
  343. package/lib/module/helpers/openRoomAtMessage.js +41 -0
  344. package/lib/module/helpers/openRoomAtMessage.js.map +1 -0
  345. package/lib/module/helpers/openThreadForJump.js +68 -0
  346. package/lib/module/helpers/openThreadForJump.js.map +1 -0
  347. package/lib/module/helpers/parseMessageReference.js +26 -6
  348. package/lib/module/helpers/parseMessageReference.js.map +1 -1
  349. package/lib/module/helpers/publicChatsEntry.js +12 -0
  350. package/lib/module/helpers/publicChatsEntry.js.map +1 -0
  351. package/lib/module/helpers/roomActivityScore.js +30 -0
  352. package/lib/module/helpers/roomActivityScore.js.map +1 -0
  353. package/lib/module/helpers/roomUserCount.js +29 -0
  354. package/lib/module/helpers/roomUserCount.js.map +1 -0
  355. package/lib/module/helpers/runConfiguredHistoryPreload.js +63 -0
  356. package/lib/module/helpers/runConfiguredHistoryPreload.js.map +1 -0
  357. package/lib/module/helpers/sessionAppId.js +20 -0
  358. package/lib/module/helpers/sessionAppId.js.map +1 -0
  359. package/lib/module/helpers/timestamp.js +37 -0
  360. package/lib/module/helpers/timestamp.js.map +1 -0
  361. package/lib/module/helpers/userResolver.js +503 -0
  362. package/lib/module/helpers/userResolver.js.map +1 -0
  363. package/lib/module/helpers/xmppIdShape.js +46 -0
  364. package/lib/module/helpers/xmppIdShape.js.map +1 -0
  365. package/lib/module/hooks/useChatWrapperInit.js +16 -5
  366. package/lib/module/hooks/useChatWrapperInit.js.map +1 -1
  367. package/lib/module/hooks/useHeapSender.js +54 -3
  368. package/lib/module/hooks/useHeapSender.js.map +1 -1
  369. package/lib/module/hooks/useJumpToMessage.js +389 -0
  370. package/lib/module/hooks/useJumpToMessage.js.map +1 -0
  371. package/lib/module/hooks/useMessageLoaderQueue.js +32 -5
  372. package/lib/module/hooks/useMessageLoaderQueue.js.map +1 -1
  373. package/lib/module/hooks/useMessageQueue.js +13 -5
  374. package/lib/module/hooks/useMessageQueue.js.map +1 -1
  375. package/lib/module/hooks/useRoomDirectory.js +24 -0
  376. package/lib/module/hooks/useRoomDirectory.js.map +1 -0
  377. package/lib/module/hooks/useRoomInitialization.js +29 -7
  378. package/lib/module/hooks/useRoomInitialization.js.map +1 -1
  379. package/lib/module/hooks/useRoomMute.js +58 -0
  380. package/lib/module/hooks/useRoomMute.js.map +1 -0
  381. package/lib/module/hooks/useRoomState.js +3 -1
  382. package/lib/module/hooks/useRoomState.js.map +1 -1
  383. package/lib/module/hooks/useSendMessage.js +13 -3
  384. package/lib/module/hooks/useSendMessage.js.map +1 -1
  385. package/lib/module/i18n/strings.js +318 -6
  386. package/lib/module/i18n/strings.js.map +1 -1
  387. package/lib/module/networking/api-requests/messageSearch.api.js +81 -0
  388. package/lib/module/networking/api-requests/messageSearch.api.js.map +1 -0
  389. package/lib/module/networking/api-requests/publicChats.api.js +43 -0
  390. package/lib/module/networking/api-requests/publicChats.api.js.map +1 -0
  391. package/lib/module/networking/api-requests/roomMembers.api.js +248 -4
  392. package/lib/module/networking/api-requests/roomMembers.api.js.map +1 -1
  393. package/lib/module/networking/api-requests/rooms.api.js +48 -12
  394. package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
  395. package/lib/module/networking/api-requests/xmppToken.api.js +66 -0
  396. package/lib/module/networking/api-requests/xmppToken.api.js.map +1 -0
  397. package/lib/module/networking/ethoraEvents.js +220 -0
  398. package/lib/module/networking/ethoraEvents.js.map +1 -0
  399. package/lib/module/networking/stanzaHandlers.js +155 -18
  400. package/lib/module/networking/stanzaHandlers.js.map +1 -1
  401. package/lib/module/networking/xmpp/allRoomPresences.xmpp.js +125 -3
  402. package/lib/module/networking/xmpp/allRoomPresences.xmpp.js.map +1 -1
  403. package/lib/module/networking/xmpp/getHistory.xmpp.js +318 -35
  404. package/lib/module/networking/xmpp/getHistory.xmpp.js.map +1 -1
  405. package/lib/module/networking/xmpp/handleStanzas.xmpp.js +7 -0
  406. package/lib/module/networking/xmpp/handleStanzas.xmpp.js.map +1 -1
  407. package/lib/module/networking/xmpp/historyCursor.js +95 -0
  408. package/lib/module/networking/xmpp/historyCursor.js.map +1 -0
  409. package/lib/module/networking/xmpp/mamQueryIds.js +12 -0
  410. package/lib/module/networking/xmpp/mamQueryIds.js.map +1 -0
  411. package/lib/module/networking/xmpp/mamRouter.js +22 -8
  412. package/lib/module/networking/xmpp/mamRouter.js.map +1 -1
  413. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js +68 -62
  414. package/lib/module/networking/xmpp/presenceInRoom.xmpp.js.map +1 -1
  415. package/lib/module/networking/xmpp/roomJoinSweep.js +385 -0
  416. package/lib/module/networking/xmpp/roomJoinSweep.js.map +1 -0
  417. package/lib/module/networking/xmpp/sendMediaMessage.xmpp.js +0 -1
  418. package/lib/module/networking/xmpp/sendMediaMessage.xmpp.js.map +1 -1
  419. package/lib/module/networking/xmpp/sendTextMessage.xmpp.js +0 -1
  420. package/lib/module/networking/xmpp/sendTextMessage.xmpp.js.map +1 -1
  421. package/lib/module/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js +0 -1
  422. package/lib/module/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.js.map +1 -1
  423. package/lib/module/networking/xmppClient.js +269 -41
  424. package/lib/module/networking/xmppClient.js.map +1 -1
  425. package/lib/module/networking/xmppCredentials.js +76 -0
  426. package/lib/module/networking/xmppCredentials.js.map +1 -0
  427. package/lib/module/roomStore/Middleware/jumpThreadMiddleware.js +153 -0
  428. package/lib/module/roomStore/Middleware/jumpThreadMiddleware.js.map +1 -0
  429. package/lib/module/roomStore/Middleware/reactionsMiddleware.js +6 -0
  430. package/lib/module/roomStore/Middleware/reactionsMiddleware.js.map +1 -1
  431. package/lib/module/roomStore/Middleware/unreadMidlleware.js +46 -7
  432. package/lib/module/roomStore/Middleware/unreadMidlleware.js.map +1 -1
  433. package/lib/module/roomStore/chatSettingsSlice.js +13 -0
  434. package/lib/module/roomStore/chatSettingsSlice.js.map +1 -1
  435. package/lib/module/roomStore/index.js +7 -3
  436. package/lib/module/roomStore/index.js.map +1 -1
  437. package/lib/module/roomStore/persistence.js +46 -1
  438. package/lib/module/roomStore/persistence.js.map +1 -1
  439. package/lib/module/roomStore/roomsSlice.js +459 -58
  440. package/lib/module/roomStore/roomsSlice.js.map +1 -1
  441. package/lib/module/roomStore/safeKey.js +37 -0
  442. package/lib/module/roomStore/safeKey.js.map +1 -0
  443. package/lib/module/roomStore/usersSetCap.js +32 -0
  444. package/lib/module/roomStore/usersSetCap.js.map +1 -0
  445. package/lib/module/version.js +1 -1
  446. package/lib/module/version.js.map +1 -1
  447. package/lib/typescript/assets/icons.d.ts +4 -0
  448. package/lib/typescript/assets/icons.d.ts.map +1 -1
  449. package/lib/typescript/components/Header/HeaderRoomList.d.ts.map +1 -1
  450. package/lib/typescript/components/InputComponents/Search.d.ts.map +1 -1
  451. package/lib/typescript/components/MainComponents/ArchivedMessageCard.d.ts +12 -0
  452. package/lib/typescript/components/MainComponents/ArchivedMessageCard.d.ts.map +1 -0
  453. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  454. package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
  455. package/lib/typescript/components/MainComponents/ChatWrapper.d.ts.map +1 -1
  456. package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
  457. package/lib/typescript/components/MainComponents/MessageList.d.ts +22 -1
  458. package/lib/typescript/components/MainComponents/MessageList.d.ts.map +1 -1
  459. package/lib/typescript/components/MainComponents/MessageSearchButton.d.ts +7 -0
  460. package/lib/typescript/components/MainComponents/MessageSearchButton.d.ts.map +1 -0
  461. package/lib/typescript/components/MainComponents/ReduxWrapper.d.ts.map +1 -1
  462. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  463. package/lib/typescript/components/Menu/HeaderRoomListMenu.d.ts.map +1 -1
  464. package/lib/typescript/components/MessageBubble/BubbleHighlight.d.ts +12 -0
  465. package/lib/typescript/components/MessageBubble/BubbleHighlight.d.ts.map +1 -0
  466. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  467. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts +5 -0
  468. package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
  469. package/lib/typescript/components/MessageBubble/messageMenuLayout.d.ts +29 -0
  470. package/lib/typescript/components/MessageBubble/messageMenuLayout.d.ts.map +1 -0
  471. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts +2 -0
  472. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
  473. package/lib/typescript/components/Modals/MessageSearchModal/MessageHitResults.d.ts +44 -0
  474. package/lib/typescript/components/Modals/MessageSearchModal/MessageHitResults.d.ts.map +1 -0
  475. package/lib/typescript/components/Modals/MessageSearchModal/MessageSearchModal.d.ts +12 -0
  476. package/lib/typescript/components/Modals/MessageSearchModal/MessageSearchModal.d.ts.map +1 -0
  477. package/lib/typescript/components/Modals/MessageSearchModal/openHit.d.ts +15 -0
  478. package/lib/typescript/components/Modals/MessageSearchModal/openHit.d.ts.map +1 -0
  479. package/lib/typescript/components/Modals/MessageSearchModal/resolveSender.d.ts +34 -0
  480. package/lib/typescript/components/Modals/MessageSearchModal/resolveSender.d.ts.map +1 -0
  481. package/lib/typescript/components/Modals/MessageSearchModal/searchFilters.d.ts +41 -0
  482. package/lib/typescript/components/Modals/MessageSearchModal/searchFilters.d.ts.map +1 -0
  483. package/lib/typescript/components/Modals/MessageSearchModal/snippet.d.ts +15 -0
  484. package/lib/typescript/components/Modals/MessageSearchModal/snippet.d.ts.map +1 -0
  485. package/lib/typescript/components/Modals/MessageSearchModal/useMessageSearch.d.ts +23 -0
  486. package/lib/typescript/components/Modals/MessageSearchModal/useMessageSearch.d.ts.map +1 -0
  487. package/lib/typescript/components/Modals/PublicChatsModal/PublicChatsModal.d.ts +16 -0
  488. package/lib/typescript/components/Modals/PublicChatsModal/PublicChatsModal.d.ts.map +1 -0
  489. package/lib/typescript/components/Modals/PublicChatsModal/publicChatsLogic.d.ts +14 -0
  490. package/lib/typescript/components/Modals/PublicChatsModal/publicChatsLogic.d.ts.map +1 -0
  491. package/lib/typescript/components/Modals/SelectUsersModal/SelectUsersModal.d.ts.map +1 -1
  492. package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
  493. package/lib/typescript/components/RoomComponents/SwipeableRoomRow.d.ts +5 -1
  494. package/lib/typescript/components/RoomComponents/SwipeableRoomRow.d.ts.map +1 -1
  495. package/lib/typescript/components/Thread/ThreadHeader.d.ts.map +1 -1
  496. package/lib/typescript/components/Thread/ThreadWrapper.d.ts +1 -0
  497. package/lib/typescript/components/Thread/ThreadWrapper.d.ts.map +1 -1
  498. package/lib/typescript/components/styled/AudioDecoderHost.d.ts +39 -0
  499. package/lib/typescript/components/styled/AudioDecoderHost.d.ts.map +1 -0
  500. package/lib/typescript/components/styled/AudioMessage.d.ts +14 -1
  501. package/lib/typescript/components/styled/AudioMessage.d.ts.map +1 -1
  502. package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
  503. package/lib/typescript/context/MessageNotificationContext.d.ts.map +1 -1
  504. package/lib/typescript/context/xmppProvider.d.ts +2 -0
  505. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  506. package/lib/typescript/helpers/audioWaveform.d.ts +54 -0
  507. package/lib/typescript/helpers/audioWaveform.d.ts.map +1 -0
  508. package/lib/typescript/helpers/backgroundJoinSweep.d.ts +14 -0
  509. package/lib/typescript/helpers/backgroundJoinSweep.d.ts.map +1 -0
  510. package/lib/typescript/helpers/bubbleHighlight.d.ts +17 -0
  511. package/lib/typescript/helpers/bubbleHighlight.d.ts.map +1 -0
  512. package/lib/typescript/helpers/checkUniqueUsers.d.ts +2 -2
  513. package/lib/typescript/helpers/checkUniqueUsers.d.ts.map +1 -1
  514. package/lib/typescript/helpers/constants/MODAL_COMPONENTS.d.ts.map +1 -1
  515. package/lib/typescript/helpers/constants/MODAL_TYPES.d.ts +2 -0
  516. package/lib/typescript/helpers/constants/MODAL_TYPES.d.ts.map +1 -1
  517. package/lib/typescript/helpers/createRoomFromApi.d.ts +25 -0
  518. package/lib/typescript/helpers/createRoomFromApi.d.ts.map +1 -1
  519. package/lib/typescript/helpers/dedupeMembers.d.ts +11 -0
  520. package/lib/typescript/helpers/dedupeMembers.d.ts.map +1 -0
  521. package/lib/typescript/helpers/ethoraLogger.d.ts +13 -0
  522. package/lib/typescript/helpers/ethoraLogger.d.ts.map +1 -0
  523. package/lib/typescript/helpers/getUnnamedUsers.d.ts.map +1 -1
  524. package/lib/typescript/helpers/historyPreloadConfig.d.ts +26 -0
  525. package/lib/typescript/helpers/historyPreloadConfig.d.ts.map +1 -0
  526. package/lib/typescript/helpers/historyPreloadScheduler.d.ts +8 -4
  527. package/lib/typescript/helpers/historyPreloadScheduler.d.ts.map +1 -1
  528. package/lib/typescript/helpers/initRoomsPresence.d.ts +7 -0
  529. package/lib/typescript/helpers/initRoomsPresence.d.ts.map +1 -1
  530. package/lib/typescript/helpers/insertMessageWithDelimiter.d.ts.map +1 -1
  531. package/lib/typescript/helpers/isLikelyMucJid.d.ts +19 -0
  532. package/lib/typescript/helpers/isLikelyMucJid.d.ts.map +1 -0
  533. package/lib/typescript/helpers/isMessageSearchEnabled.d.ts +12 -0
  534. package/lib/typescript/helpers/isMessageSearchEnabled.d.ts.map +1 -0
  535. package/lib/typescript/helpers/joiningRoom.d.ts +7 -0
  536. package/lib/typescript/helpers/joiningRoom.d.ts.map +1 -0
  537. package/lib/typescript/helpers/jumpThread.d.ts +48 -0
  538. package/lib/typescript/helpers/jumpThread.d.ts.map +1 -0
  539. package/lib/typescript/helpers/jumpToMessage.d.ts +26 -0
  540. package/lib/typescript/helpers/jumpToMessage.d.ts.map +1 -0
  541. package/lib/typescript/helpers/jumpWindow.d.ts +74 -0
  542. package/lib/typescript/helpers/jumpWindow.d.ts.map +1 -0
  543. package/lib/typescript/helpers/loadRoomHistory.d.ts +34 -0
  544. package/lib/typescript/helpers/loadRoomHistory.d.ts.map +1 -0
  545. package/lib/typescript/helpers/notificationPolicy.d.ts +42 -0
  546. package/lib/typescript/helpers/notificationPolicy.d.ts.map +1 -0
  547. package/lib/typescript/helpers/openRoomAtMessage.d.ts +17 -0
  548. package/lib/typescript/helpers/openRoomAtMessage.d.ts.map +1 -0
  549. package/lib/typescript/helpers/openThreadForJump.d.ts +27 -0
  550. package/lib/typescript/helpers/openThreadForJump.d.ts.map +1 -0
  551. package/lib/typescript/helpers/parseMessageReference.d.ts +18 -5
  552. package/lib/typescript/helpers/parseMessageReference.d.ts.map +1 -1
  553. package/lib/typescript/helpers/publicChatsEntry.d.ts +11 -0
  554. package/lib/typescript/helpers/publicChatsEntry.d.ts.map +1 -0
  555. package/lib/typescript/helpers/roomActivityScore.d.ts +5 -0
  556. package/lib/typescript/helpers/roomActivityScore.d.ts.map +1 -0
  557. package/lib/typescript/helpers/roomUserCount.d.ts +20 -0
  558. package/lib/typescript/helpers/roomUserCount.d.ts.map +1 -0
  559. package/lib/typescript/helpers/runConfiguredHistoryPreload.d.ts +21 -0
  560. package/lib/typescript/helpers/runConfiguredHistoryPreload.d.ts.map +1 -0
  561. package/lib/typescript/helpers/sessionAppId.d.ts +8 -0
  562. package/lib/typescript/helpers/sessionAppId.d.ts.map +1 -0
  563. package/lib/typescript/helpers/timestamp.d.ts +3 -0
  564. package/lib/typescript/helpers/timestamp.d.ts.map +1 -0
  565. package/lib/typescript/helpers/userResolver.d.ts +58 -0
  566. package/lib/typescript/helpers/userResolver.d.ts.map +1 -0
  567. package/lib/typescript/helpers/xmppIdShape.d.ts +10 -0
  568. package/lib/typescript/helpers/xmppIdShape.d.ts.map +1 -0
  569. package/lib/typescript/hooks/useChatWrapperInit.d.ts +2 -0
  570. package/lib/typescript/hooks/useChatWrapperInit.d.ts.map +1 -1
  571. package/lib/typescript/hooks/useHeapSender.d.ts.map +1 -1
  572. package/lib/typescript/hooks/useJumpToMessage.d.ts +116 -0
  573. package/lib/typescript/hooks/useJumpToMessage.d.ts.map +1 -0
  574. package/lib/typescript/hooks/useMessageLoaderQueue.d.ts.map +1 -1
  575. package/lib/typescript/hooks/useMessageQueue.d.ts.map +1 -1
  576. package/lib/typescript/hooks/useRoomDirectory.d.ts +12 -0
  577. package/lib/typescript/hooks/useRoomDirectory.d.ts.map +1 -0
  578. package/lib/typescript/hooks/useRoomInitialization.d.ts.map +1 -1
  579. package/lib/typescript/hooks/useRoomMute.d.ts +8 -0
  580. package/lib/typescript/hooks/useRoomMute.d.ts.map +1 -0
  581. package/lib/typescript/hooks/useRoomState.d.ts +1 -0
  582. package/lib/typescript/hooks/useRoomState.d.ts.map +1 -1
  583. package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
  584. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  585. package/lib/typescript/networking/api-requests/messageSearch.api.d.ts +57 -0
  586. package/lib/typescript/networking/api-requests/messageSearch.api.d.ts.map +1 -0
  587. package/lib/typescript/networking/api-requests/publicChats.api.d.ts +24 -0
  588. package/lib/typescript/networking/api-requests/publicChats.api.d.ts.map +1 -0
  589. package/lib/typescript/networking/api-requests/roomMembers.api.d.ts +19 -1
  590. package/lib/typescript/networking/api-requests/roomMembers.api.d.ts.map +1 -1
  591. package/lib/typescript/networking/api-requests/rooms.api.d.ts.map +1 -1
  592. package/lib/typescript/networking/api-requests/xmppToken.api.d.ts +2 -0
  593. package/lib/typescript/networking/api-requests/xmppToken.api.d.ts.map +1 -0
  594. package/lib/typescript/networking/ethoraEvents.d.ts +45 -0
  595. package/lib/typescript/networking/ethoraEvents.d.ts.map +1 -0
  596. package/lib/typescript/networking/stanzaHandlers.d.ts +1 -1
  597. package/lib/typescript/networking/stanzaHandlers.d.ts.map +1 -1
  598. package/lib/typescript/networking/xmpp/allRoomPresences.xmpp.d.ts +32 -1
  599. package/lib/typescript/networking/xmpp/allRoomPresences.xmpp.d.ts.map +1 -1
  600. package/lib/typescript/networking/xmpp/getHistory.xmpp.d.ts +64 -0
  601. package/lib/typescript/networking/xmpp/getHistory.xmpp.d.ts.map +1 -1
  602. package/lib/typescript/networking/xmpp/handleStanzas.xmpp.d.ts.map +1 -1
  603. package/lib/typescript/networking/xmpp/historyCursor.d.ts +35 -0
  604. package/lib/typescript/networking/xmpp/historyCursor.d.ts.map +1 -0
  605. package/lib/typescript/networking/xmpp/mamQueryIds.d.ts +10 -0
  606. package/lib/typescript/networking/xmpp/mamQueryIds.d.ts.map +1 -0
  607. package/lib/typescript/networking/xmpp/mamRouter.d.ts +7 -0
  608. package/lib/typescript/networking/xmpp/mamRouter.d.ts.map +1 -1
  609. package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts +13 -2
  610. package/lib/typescript/networking/xmpp/presenceInRoom.xmpp.d.ts.map +1 -1
  611. package/lib/typescript/networking/xmpp/roomJoinSweep.d.ts +82 -0
  612. package/lib/typescript/networking/xmpp/roomJoinSweep.d.ts.map +1 -0
  613. package/lib/typescript/networking/xmpp/sendMediaMessage.xmpp.d.ts.map +1 -1
  614. package/lib/typescript/networking/xmpp/sendTextMessage.xmpp.d.ts.map +1 -1
  615. package/lib/typescript/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.d.ts.map +1 -1
  616. package/lib/typescript/networking/xmppClient.d.ts +90 -4
  617. package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
  618. package/lib/typescript/networking/xmppCredentials.d.ts +12 -0
  619. package/lib/typescript/networking/xmppCredentials.d.ts.map +1 -0
  620. package/lib/typescript/roomStore/Middleware/jumpThreadMiddleware.d.ts +3 -0
  621. package/lib/typescript/roomStore/Middleware/jumpThreadMiddleware.d.ts.map +1 -0
  622. package/lib/typescript/roomStore/Middleware/reactionsMiddleware.d.ts.map +1 -1
  623. package/lib/typescript/roomStore/Middleware/unreadMidlleware.d.ts.map +1 -1
  624. package/lib/typescript/roomStore/chatSettingsSlice.d.ts +8 -1
  625. package/lib/typescript/roomStore/chatSettingsSlice.d.ts.map +1 -1
  626. package/lib/typescript/roomStore/index.d.ts +2 -1
  627. package/lib/typescript/roomStore/index.d.ts.map +1 -1
  628. package/lib/typescript/roomStore/persistence.d.ts +8 -0
  629. package/lib/typescript/roomStore/persistence.d.ts.map +1 -1
  630. package/lib/typescript/roomStore/roomsSlice.d.ts +138 -2
  631. package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
  632. package/lib/typescript/roomStore/safeKey.d.ts +13 -0
  633. package/lib/typescript/roomStore/safeKey.d.ts.map +1 -0
  634. package/lib/typescript/roomStore/usersSetCap.d.ts +16 -0
  635. package/lib/typescript/roomStore/usersSetCap.d.ts.map +1 -0
  636. package/lib/typescript/types/models/media.model.d.ts +2 -0
  637. package/lib/typescript/types/models/media.model.d.ts.map +1 -1
  638. package/lib/typescript/types/models/room.model.d.ts +18 -5
  639. package/lib/typescript/types/models/room.model.d.ts.map +1 -1
  640. package/lib/typescript/types/models/xmpp.model.d.ts +8 -1
  641. package/lib/typescript/types/models/xmpp.model.d.ts.map +1 -1
  642. package/lib/typescript/types/types.d.ts +90 -5
  643. package/lib/typescript/types/types.d.ts.map +1 -1
  644. package/lib/typescript/version.d.ts +1 -1
  645. package/lib/typescript/version.d.ts.map +1 -1
  646. package/package.json +1 -1
  647. package/src/assets/icons.tsx +13 -0
  648. package/src/components/Header/HeaderRoomList.tsx +21 -4
  649. package/src/components/InputComponents/Search.tsx +33 -0
  650. package/src/components/MainComponents/ArchivedMessageCard.tsx +139 -0
  651. package/src/components/MainComponents/ChatHeader.tsx +19 -3
  652. package/src/components/MainComponents/ChatRoom.tsx +60 -23
  653. package/src/components/MainComponents/ChatWrapper.tsx +50 -9
  654. package/src/components/MainComponents/MediaMessage.tsx +17 -0
  655. package/src/components/MainComponents/MessageList.tsx +823 -84
  656. package/src/components/MainComponents/MessageSearchButton.tsx +48 -0
  657. package/src/components/MainComponents/ReduxWrapper.tsx +16 -5
  658. package/src/components/MainComponents/RoomList.tsx +125 -0
  659. package/src/components/Menu/HeaderRoomListMenu.tsx +26 -2
  660. package/src/components/MessageBubble/BubbleHighlight.tsx +106 -0
  661. package/src/components/MessageBubble/Message.tsx +265 -177
  662. package/src/components/MessageBubble/MessageInteractions.tsx +109 -86
  663. package/src/components/MessageBubble/messageMenuLayout.ts +59 -0
  664. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +92 -21
  665. package/src/components/Modals/MessageSearchModal/MessageHitResults.tsx +271 -0
  666. package/src/components/Modals/MessageSearchModal/MessageSearchModal.tsx +487 -0
  667. package/src/components/Modals/MessageSearchModal/openHit.ts +50 -0
  668. package/src/components/Modals/MessageSearchModal/resolveSender.ts +57 -0
  669. package/src/components/Modals/MessageSearchModal/searchFilters.ts +109 -0
  670. package/src/components/Modals/MessageSearchModal/snippet.ts +58 -0
  671. package/src/components/Modals/MessageSearchModal/useMessageSearch.ts +151 -0
  672. package/src/components/Modals/PublicChatsModal/PublicChatsModal.tsx +288 -0
  673. package/src/components/Modals/PublicChatsModal/publicChatsLogic.ts +36 -0
  674. package/src/components/Modals/SelectUsersModal/SelectUsersModal.tsx +8 -1
  675. package/src/components/RoomComponents/ChatRoomItem.tsx +16 -3
  676. package/src/components/RoomComponents/SwipeableRoomRow.tsx +39 -6
  677. package/src/components/Thread/ThreadHeader.tsx +3 -1
  678. package/src/components/Thread/ThreadWrapper.tsx +96 -10
  679. package/src/components/styled/AudioDecoderHost.tsx +351 -0
  680. package/src/components/styled/AudioMessage.tsx +482 -425
  681. package/src/components/styled/SendInput.tsx +42 -4
  682. package/src/context/MessageNotificationContext.tsx +19 -5
  683. package/src/context/xmppProvider.tsx +56 -91
  684. package/src/helpers/audioWaveform.ts +142 -0
  685. package/src/helpers/backgroundJoinSweep.ts +35 -0
  686. package/src/helpers/bubbleHighlight.ts +47 -0
  687. package/src/helpers/checkUniqueUsers.tsx +15 -17
  688. package/src/helpers/constants/MODAL_COMPONENTS.tsx +4 -0
  689. package/src/helpers/constants/MODAL_TYPES.ts +3 -0
  690. package/src/helpers/createRoomFromApi.tsx +45 -4
  691. package/src/helpers/dedupeMembers.ts +29 -0
  692. package/src/helpers/ethoraLogger.ts +50 -0
  693. package/src/helpers/getUnnamedUsers.ts +7 -4
  694. package/src/helpers/historyPreloadConfig.ts +68 -0
  695. package/src/helpers/historyPreloadScheduler.ts +437 -199
  696. package/src/helpers/initRoomsPresence.ts +20 -7
  697. package/src/helpers/insertMessageWithDelimiter.ts +3 -0
  698. package/src/helpers/isLikelyMucJid.ts +72 -0
  699. package/src/helpers/isMessageSearchEnabled.ts +18 -0
  700. package/src/helpers/joiningRoom.ts +13 -0
  701. package/src/helpers/jumpThread.ts +102 -0
  702. package/src/helpers/jumpToMessage.ts +57 -0
  703. package/src/helpers/jumpWindow.ts +212 -0
  704. package/src/helpers/loadRoomHistory.ts +83 -0
  705. package/src/helpers/notificationPolicy.ts +82 -0
  706. package/src/helpers/openRoomAtMessage.ts +38 -0
  707. package/src/helpers/openThreadForJump.ts +96 -0
  708. package/src/helpers/parseMessageReference.ts +37 -8
  709. package/src/helpers/publicChatsEntry.ts +15 -0
  710. package/src/helpers/roomActivityScore.ts +45 -0
  711. package/src/helpers/roomUserCount.ts +44 -0
  712. package/src/helpers/runConfiguredHistoryPreload.ts +76 -0
  713. package/src/helpers/sessionAppId.ts +17 -0
  714. package/src/helpers/timestamp.ts +44 -0
  715. package/src/helpers/userResolver.ts +542 -0
  716. package/src/helpers/xmppIdShape.ts +46 -0
  717. package/src/hooks/useChatWrapperInit.ts +22 -4
  718. package/src/hooks/useHeapSender.tsx +54 -3
  719. package/src/hooks/useJumpToMessage.ts +538 -0
  720. package/src/hooks/useMessageLoaderQueue.tsx +40 -4
  721. package/src/hooks/useMessageQueue.ts +9 -5
  722. package/src/hooks/useRoomDirectory.ts +39 -0
  723. package/src/hooks/useRoomInitialization.tsx +33 -7
  724. package/src/hooks/useRoomMute.ts +42 -0
  725. package/src/hooks/useRoomState.tsx +6 -0
  726. package/src/hooks/useSendMessage.tsx +14 -2
  727. package/src/i18n/strings.ts +312 -0
  728. package/src/networking/api-requests/messageSearch.api.ts +130 -0
  729. package/src/networking/api-requests/publicChats.api.ts +71 -0
  730. package/src/networking/api-requests/roomMembers.api.ts +263 -11
  731. package/src/networking/api-requests/rooms.api.ts +52 -12
  732. package/src/networking/api-requests/xmppToken.api.ts +62 -0
  733. package/src/networking/ethoraEvents.ts +262 -0
  734. package/src/networking/stanzaHandlers.ts +145 -19
  735. package/src/networking/xmpp/allRoomPresences.xmpp.ts +155 -5
  736. package/src/networking/xmpp/getHistory.xmpp.ts +433 -47
  737. package/src/networking/xmpp/handleStanzas.xmpp.ts +8 -0
  738. package/src/networking/xmpp/historyCursor.ts +124 -0
  739. package/src/networking/xmpp/mamQueryIds.ts +11 -0
  740. package/src/networking/xmpp/mamRouter.ts +24 -10
  741. package/src/networking/xmpp/presenceInRoom.xmpp.ts +91 -68
  742. package/src/networking/xmpp/roomJoinSweep.ts +412 -0
  743. package/src/networking/xmpp/sendMediaMessage.xmpp.ts +0 -1
  744. package/src/networking/xmpp/sendTextMessage.xmpp.ts +0 -1
  745. package/src/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.ts +0 -1
  746. package/src/networking/xmppClient.ts +323 -47
  747. package/src/networking/xmppCredentials.ts +87 -0
  748. package/src/roomStore/Middleware/jumpThreadMiddleware.ts +163 -0
  749. package/src/roomStore/Middleware/reactionsMiddleware.tsx +4 -0
  750. package/src/roomStore/Middleware/unreadMidlleware.tsx +59 -11
  751. package/src/roomStore/chatSettingsSlice.ts +11 -0
  752. package/src/roomStore/index.ts +10 -3
  753. package/src/roomStore/persistence.ts +54 -0
  754. package/src/roomStore/roomsSlice.ts +547 -65
  755. package/src/roomStore/safeKey.ts +49 -0
  756. package/src/roomStore/usersSetCap.ts +37 -0
  757. package/src/types/models/media.model.ts +4 -0
  758. package/src/types/models/room.model.ts +18 -5
  759. package/src/types/models/xmpp.model.ts +15 -1
  760. package/src/types/types.ts +95 -5
  761. package/src/version.ts +1 -1
@@ -9,25 +9,28 @@ var _secureFileUrl = require("../../helpers/secureFileUrl");
9
9
  var _reactNative = require("react-native");
10
10
  var _expoAudio = require("expo-audio");
11
11
  var FileSystem = _interopRequireWildcard(require("expo-file-system/legacy"));
12
- var _reactNativeWebview = require("react-native-webview");
13
- var _icons = require("../../assets/icons");
12
+ var _reactNativeSvg = _interopRequireWildcard(require("react-native-svg"));
14
13
  var _useTheme = require("../../hooks/useTheme");
14
+ var _useT = require("../../i18n/useT");
15
15
  var _mimeToExtension = require("../../helpers/mimeToExtension");
16
+ var _audioWaveform = require("../../helpers/audioWaveform");
16
17
  var _devLogger = require("../../utils/devLogger");
18
+ var _AudioDecoderHost = require("./AudioDecoderHost");
17
19
  var _jsxRuntime = require("react/jsx-runtime");
18
20
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
19
- const formatTime = millis => {
20
- const safe = Number.isFinite(millis) && millis > 0 ? millis : 0;
21
- const totalSec = Math.floor(safe / 1000);
22
- const min = Math.floor(totalSec / 60);
23
- const sec = totalSec % 60;
24
- return `${min}:${sec.toString().padStart(2, '0')}`;
25
- };
26
- // Largest payload we will pull into JS for decoding (input opus) and the
27
- // largest WAV we will ship back over the bridge (output PCM). Voice
28
- // messages are a few dozen KB / a couple hundred KB of WAV; these only
29
- // guard against a pathological multi-minute attachment.
30
- const MAX_DECODE_BYTES = 25 * 1024 * 1024;
21
+ const SPEEDS = [1, 1.5, 2];
22
+ const BAR_WIDTH = 3;
23
+ const BAR_GAP = 2;
24
+ const WAVE_HEIGHT = 24;
25
+
26
+ /** Waveforms already worked out this session, by source URL. */
27
+ const analysisCache = new Map();
28
+
29
+ /**
30
+ * Only one voice note plays at a time, as in the messengers: starting one
31
+ * pauses whichever was playing.
32
+ */
33
+ let pauseActive = null;
31
34
  const hashString = value => {
32
35
  let hash = 0;
33
36
  for (let i = 0; i < value.length; i += 1) {
@@ -136,142 +139,93 @@ const getContainerExtension = container => {
136
139
  // Everything else (mp3/m4a/aac/wav), and ALL of Android (ExoPlayer handles
137
140
  // Opus natively), plays straight through expo-audio.
138
141
  const requiresWebAudioDecode = container => _reactNative.Platform.OS === 'ios' && (container === 'webm' || container === 'ogg');
142
+ const PlayGlyph = ({
143
+ color
144
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.default, {
145
+ width: 26,
146
+ height: 26,
147
+ viewBox: "0 0 24 24",
148
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Path, {
149
+ d: "M7.5 5.2v13.6c0 .95 1.05 1.5 1.8.95l9.9-6.8c.65-.45.65-1.45 0-1.9L9.3 4.25c-.75-.55-1.8 0-1.8.95z",
150
+ fill: color
151
+ })
152
+ });
153
+ const PauseGlyph = ({
154
+ color
155
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeSvg.default, {
156
+ width: 24,
157
+ height: 24,
158
+ viewBox: "0 0 24 24",
159
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Rect, {
160
+ x: 6.5,
161
+ y: 5,
162
+ width: 4,
163
+ height: 14,
164
+ rx: 1.4,
165
+ fill: color
166
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Rect, {
167
+ x: 13.5,
168
+ y: 5,
169
+ width: 4,
170
+ height: 14,
171
+ rx: 1.4,
172
+ fill: color
173
+ })]
174
+ });
139
175
 
140
- // The WebView is used ONLY as a decoder, never as a player. Two iOS facts
141
- // force this shape:
142
- // • `decodeAudioData` is the only iOS API that understands WebM/Ogg Opus,
143
- // and it works on a suspended AudioContext (decoding needs no gesture).
144
- // • Playing audio OUT of a WebView — via AudioContext OR an <audio>
145
- // element — is gated behind an in-page user gesture that an RN-side tap
146
- // cannot supply, so both hang silently.
147
- // Therefore the page decodes Opus → PCM, re-encodes to a WAV blob, and ships
148
- // the bytes back to RN as base64. RN writes the WAV to cache and plays it
149
- // through expo-audio (native, no gesture limits, real play/pause/seek).
150
- const WEB_DECODER_HTML = `<!doctype html>
151
- <html>
152
- <head>
153
- <meta charset="utf-8" />
154
- <meta name="viewport" content="width=device-width, initial-scale=1" />
155
- <style>html,body{margin:0;padding:0;width:1px;height:1px;overflow:hidden;background:transparent}</style>
156
- </head>
157
- <body>
158
- <script>
159
- (function () {
160
- var MAX_WAV = ${MAX_DECODE_BYTES};
161
- var post = function (payload) {
162
- if (window.ReactNativeWebView) {
163
- window.ReactNativeWebView.postMessage(JSON.stringify(payload));
164
- }
165
- };
166
- var ctx = null;
167
- var encodeWav = function (buffer) {
168
- var numCh = buffer.numberOfChannels;
169
- var frames = buffer.length;
170
- var sr = buffer.sampleRate;
171
- var bytesLen = 44 + frames * numCh * 2;
172
- var ab = new ArrayBuffer(bytesLen);
173
- var view = new DataView(ab);
174
- var off = 0;
175
- var ws = function (s) { for (var i = 0; i < s.length; i += 1) { view.setUint8(off++, s.charCodeAt(i)); } };
176
- var u32 = function (d) { view.setUint32(off, d, true); off += 4; };
177
- var u16 = function (d) { view.setUint16(off, d, true); off += 2; };
178
- ws('RIFF'); u32(bytesLen - 8); ws('WAVE');
179
- ws('fmt '); u32(16); u16(1); u16(numCh); u32(sr); u32(sr * numCh * 2); u16(numCh * 2); u16(16);
180
- ws('data'); u32(frames * numCh * 2);
181
- var chans = [];
182
- for (var c = 0; c < numCh; c += 1) { chans.push(buffer.getChannelData(c)); }
183
- for (var f = 0; f < frames; f += 1) {
184
- for (var c2 = 0; c2 < numCh; c2 += 1) {
185
- var s = Math.max(-1, Math.min(1, chans[c2][f]));
186
- view.setInt16(off, s < 0 ? s * 0x8000 : s * 0x7fff, true);
187
- off += 2;
188
- }
189
- }
190
- return ab;
191
- };
192
- var abToBase64 = function (ab) {
193
- var bytes = new Uint8Array(ab);
194
- var binary = '';
195
- var chunk = 0x8000;
196
- for (var i = 0; i < bytes.length; i += chunk) {
197
- binary += String.fromCharCode.apply(null, bytes.subarray(i, i + chunk));
198
- }
199
- return window.btoa(binary);
200
- };
201
- window.__decodeAudio = function (base64) {
202
- try {
203
- if (!ctx) {
204
- var Ctx = window.AudioContext || window.webkitAudioContext;
205
- ctx = new Ctx();
206
- }
207
- var bin = window.atob(base64);
208
- var len = bin.length;
209
- var bytes = new Uint8Array(len);
210
- for (var i = 0; i < len; i += 1) { bytes[i] = bin.charCodeAt(i); }
211
- ctx.decodeAudioData(
212
- bytes.buffer,
213
- function (decoded) {
214
- try {
215
- var wav = encodeWav(decoded);
216
- if (wav.byteLength > MAX_WAV) {
217
- post({ type: 'error', message: 'audio_too_long' });
218
- return;
219
- }
220
- post({
221
- type: 'decoded',
222
- durationMillis: Math.floor(decoded.duration * 1000),
223
- wavBase64: abToBase64(wav),
224
- });
225
- } catch (e) {
226
- post({ type: 'error', message: 'encode_failed:' + (e && e.message ? e.message : e) });
227
- }
228
- },
229
- function (err) {
230
- post({ type: 'error', message: 'decode_failed:' + (err && err.message ? err.message : err) });
231
- }
232
- );
233
- } catch (e) {
234
- post({ type: 'error', message: 'load_failed:' + (e && e.message ? e.message : e) });
235
- }
236
- };
237
- post({ type: 'bridge_ready' });
238
- })();
239
- </script>
240
- </body>
241
- </html>`;
176
+ /**
177
+ * A voice message the way the messengers draw it: a round play button,
178
+ * the clip's waveform filling in as it plays (tap it to jump), and its
179
+ * length — elapsed while playing — under the bars.
180
+ *
181
+ * The bars come from the sender's `waveForm` when there is one, otherwise
182
+ * from decoding the file in the shared decoder (AudioDecoderHost), which
183
+ * is also what makes the web client's WebM/Opus playable on iOS.
184
+ */
242
185
  const AudioMessage = ({
243
186
  src,
244
187
  mimeType,
245
188
  fileName,
246
- originalName
189
+ originalName,
190
+ duration: durationProp,
191
+ waveForm,
192
+ isUser = false
247
193
  }) => {
248
194
  const theme = (0, _useTheme.useTheme)();
195
+ const t = (0, _useT.useT)();
249
196
  const soundRef = (0, _react.useRef)(null);
250
- // expo-audio delivers progress through an event subscription instead of
251
- // expo-av's `onPlaybackStatusUpdate` callback argument, so the handle has
252
- // to be held and removed alongside the player itself.
197
+ // expo-audio delivers progress through an event subscription, so the
198
+ // handle has to be held and removed alongside the player itself.
253
199
  const statusSubRef = (0, _react.useRef)(null);
254
- const webViewRef = (0, _react.useRef)(null);
255
200
  const preparedRef = (0, _react.useRef)(null);
256
- const bridgeReadyRef = (0, _react.useRef)(false);
257
- const injectedRef = (0, _react.useRef)(false);
201
+ const preparingRef = (0, _react.useRef)(null);
258
202
  const didFinishRef = (0, _react.useRef)(false);
259
203
  const unmountedRef = (0, _react.useRef)(false);
260
204
  const loadingTimerRef = (0, _react.useRef)(null);
205
+ // Where to start once the player is up (a tap on the bars before play).
206
+ const pendingSeekRef = (0, _react.useRef)(null);
207
+ const rateRef = (0, _react.useRef)(1);
208
+
209
+ // The file's identity without its (rotating) access token, so caches
210
+ // survive a token refresh.
211
+ const cacheKey = src.split(/[?#]/)[0] || src;
212
+ const metaPeaks = (0, _react.useMemo)(() => (0, _audioWaveform.parseWaveForm)(waveForm), [waveForm]);
213
+ const metaDuration = (0, _audioWaveform.parseDurationSeconds)(durationProp) * 1000;
261
214
  const [isPlaying, setIsPlaying] = (0, _react.useState)(false);
262
215
  const [isLoading, setIsLoading] = (0, _react.useState)(false);
263
216
  const [playbackError, setPlaybackError] = (0, _react.useState)(false);
264
217
  const [position, setPosition] = (0, _react.useState)(0);
265
- const [duration, setDuration] = (0, _react.useState)(0);
266
- const [webViewEnabled, setWebViewEnabled] = (0, _react.useState)(false);
267
- const primaryColor = theme.primary;
268
- const onPrimary = theme.textOnPrimary;
269
- const trackStyle = {
270
- backgroundColor: theme.border
271
- };
272
- const timeStyle = {
273
- color: theme.textSecondary
274
- };
218
+ const [duration, setDuration] = (0, _react.useState)(metaDuration);
219
+ const [peaks, setPeaks] = (0, _react.useState)(metaPeaks);
220
+ const [rate, setRate] = (0, _react.useState)(1);
221
+ const [waveWidth, setWaveWidth] = (0, _react.useState)(0);
222
+
223
+ // The brand colour from the config (the same tint as the composer's mic
224
+ // and send buttons), on own and others' bubbles alike.
225
+ const ink = theme.icon;
226
+ const buttonFill = ink;
227
+ const buttonGlyph = theme.textOnPrimary;
228
+ const metaColor = isUser ? theme.messageTextUser : theme.textSecondary;
275
229
  const clearLoadingGuard = () => {
276
230
  if (loadingTimerRef.current) {
277
231
  clearTimeout(loadingTimerRef.current);
@@ -281,8 +235,7 @@ const AudioMessage = ({
281
235
 
282
236
  // expo-audio players are native shared objects: they are NOT garbage
283
237
  // collected with the component, so every one we create has to be
284
- // explicitly `remove()`d (expo-av's `unloadAsync` equivalent) and its
285
- // status subscription torn down first.
238
+ // explicitly `remove()`d and its status subscription torn down first.
286
239
  const releasePlayer = () => {
287
240
  statusSubRef.current?.remove();
288
241
  statusSubRef.current = null;
@@ -301,6 +254,25 @@ const AudioMessage = ({
301
254
  }
302
255
  }
303
256
  };
257
+
258
+ // Stable for this bubble's lifetime: what another bubble calls to pause
259
+ // this one when it starts playing.
260
+ const pauseSelf = (0, _react.useRef)(() => {
261
+ try {
262
+ soundRef.current?.pause();
263
+ } catch {
264
+ /* released */
265
+ }
266
+ if (!unmountedRef.current) {
267
+ setIsPlaying(false);
268
+ }
269
+ }).current;
270
+ const claimPlayback = () => {
271
+ if (pauseActive && pauseActive !== pauseSelf) {
272
+ pauseActive();
273
+ }
274
+ pauseActive = pauseSelf;
275
+ };
304
276
  const fail = reason => {
305
277
  clearLoadingGuard();
306
278
  if (unmountedRef.current) {
@@ -323,74 +295,76 @@ const AudioMessage = ({
323
295
  };
324
296
 
325
297
  // Hard ceiling on the loading spinner — whatever stalls (a hung network
326
- // request, a WebView that never decodes, a player that never loads)
327
- // the control resolves to an error state instead of spinning forever
328
- // (the customer-reported "stuck spinner").
298
+ // request, a decode that never returns, a player that never loads) the
299
+ // control resolves to an error state instead of spinning forever.
329
300
  const armLoadingGuard = () => {
330
301
  clearLoadingGuard();
331
302
  loadingTimerRef.current = setTimeout(() => {
332
303
  if (!unmountedRef.current && !soundRef.current) {
333
304
  fail(new Error('audio_timeout'));
334
305
  }
335
- }, 15000);
306
+ }, 25000);
336
307
  };
337
- const prepareSource = async () => {
338
- if (preparedRef.current) {
339
- return preparedRef.current;
308
+ const cacheBase = () => FileSystem.cacheDirectory ? `${FileSystem.cacheDirectory}ethora-audio-${hashString(cacheKey)}` : null;
309
+ const sniff = async uri => {
310
+ try {
311
+ const head = await FileSystem.readAsStringAsync(uri, {
312
+ encoding: FileSystem.EncodingType.Base64,
313
+ position: 0,
314
+ length: 32
315
+ });
316
+ return detectContainer(decodeBase64Head(head, 16));
317
+ } catch {
318
+ return 'unknown';
340
319
  }
341
- if (!/^https?:\/\//i.test(src)) {
342
- const prepared = {
343
- localUri: src,
344
- container: 'unknown'
345
- };
346
- preparedRef.current = prepared;
347
- return prepared;
320
+ };
321
+
322
+ // Download once (shared by the waveform and playback), sniff the real
323
+ // container, and give the cached file a real extension so AVFoundation /
324
+ // ExoPlayer pick the right demuxer instead of choking on an opaque
325
+ // `.blob` (the original `audio_timeout` cause).
326
+ const prepareSource = () => {
327
+ if (preparedRef.current) {
328
+ return Promise.resolve(preparedRef.current);
348
329
  }
349
- const cacheDirectory = FileSystem.cacheDirectory;
350
- if (!cacheDirectory) {
351
- const prepared = {
352
- localUri: src,
353
- container: 'unknown'
354
- };
355
- preparedRef.current = prepared;
356
- return prepared;
330
+ if (preparingRef.current) {
331
+ return preparingRef.current;
357
332
  }
358
- const base = `${cacheDirectory}ethora-audio-${hashString(src)}`;
359
- const part = `${base}.part`;
360
- const partInfo = await FileSystem.getInfoAsync(part);
361
- if (!partInfo.exists) {
362
- const download = await withTimeout(FileSystem.downloadAsync((0, _secureFileUrl.withFileToken)(src), part), 12000, 'audio_download_timeout');
363
- logAudioDebug('audio downloaded', {
364
- src,
365
- uri: download.status === 200 ? download.uri : undefined,
366
- status: download.status
367
- });
368
- if (download.status !== 200) {
369
- throw new Error(`audio_download_status_${download.status}`);
333
+ const run = async () => {
334
+ const base = cacheBase();
335
+ if (!/^https?:\/\//i.test(src) || !base) {
336
+ // Local file (the sender's own clip while it uploads).
337
+ return {
338
+ localUri: src,
339
+ container: await sniff(src)
340
+ };
370
341
  }
371
- }
372
- const head = await FileSystem.readAsStringAsync(part, {
373
- encoding: FileSystem.EncodingType.Base64,
374
- position: 0,
375
- length: 32
376
- });
377
- const container = detectContainer(decodeBase64Head(head, 16));
378
- let base64;
379
- let localUri = part;
380
- if (requiresWebAudioDecode(container)) {
381
- // WebView-decode path: extension is irrelevant, we hand over the bytes.
382
- const info = await FileSystem.getInfoAsync(part);
383
- const size = 'size' in info ? info.size ?? 0 : 0;
384
- if (size > MAX_DECODE_BYTES) {
385
- throw new Error('audio_too_large_to_decode');
342
+ const wav = `${base}.wav`;
343
+ if ((await FileSystem.getInfoAsync(wav)).exists) {
344
+ return {
345
+ localUri: wav,
346
+ container: 'wav',
347
+ playable: true
348
+ };
349
+ }
350
+ const part = `${base}.part`;
351
+ if (!(await FileSystem.getInfoAsync(part)).exists) {
352
+ const download = await withTimeout(FileSystem.downloadAsync((0, _secureFileUrl.withFileToken)(src), part), 12000, 'audio_download_timeout');
353
+ if (download.status !== 200) {
354
+ await FileSystem.deleteAsync(part, {
355
+ idempotent: true
356
+ }).catch(() => {});
357
+ throw new Error(`audio_download_status_${download.status}`);
358
+ }
359
+ }
360
+ const container = await sniff(part);
361
+ if (requiresWebAudioDecode(container)) {
362
+ // Decoded to WAV before playing; the extension is irrelevant.
363
+ return {
364
+ localUri: part,
365
+ container
366
+ };
386
367
  }
387
- base64 = await FileSystem.readAsStringAsync(part, {
388
- encoding: FileSystem.EncodingType.Base64
389
- });
390
- } else {
391
- // Native path: give the cached file a real extension so AVFoundation
392
- // / ExoPlayer pick the right demuxer instead of choking on an opaque
393
- // `.blob` (the original `audio_timeout` cause).
394
368
  const ext = container !== 'unknown' ? getContainerExtension(container) : (0, _mimeToExtension.getIosAudioPlaybackCacheExtension)({
395
369
  mime: mimeType,
396
370
  fileName,
@@ -398,8 +372,7 @@ const AudioMessage = ({
398
372
  url: src
399
373
  });
400
374
  const finalUri = `${base}${ext}`;
401
- const finalInfo = await FileSystem.getInfoAsync(finalUri);
402
- if (finalInfo.exists) {
375
+ if ((await FileSystem.getInfoAsync(finalUri)).exists) {
403
376
  await FileSystem.deleteAsync(part, {
404
377
  idempotent: true
405
378
  }).catch(() => {});
@@ -409,42 +382,171 @@ const AudioMessage = ({
409
382
  to: finalUri
410
383
  });
411
384
  }
412
- localUri = finalUri;
413
- }
414
- const prepared = {
415
- localUri,
416
- container,
417
- base64
385
+ return {
386
+ localUri: finalUri,
387
+ container
388
+ };
418
389
  };
419
- preparedRef.current = prepared;
420
- logAudioDebug('audio prepared', {
421
- src,
422
- mimeType,
423
- fileName,
424
- originalName,
425
- container,
426
- platform: _reactNative.Platform.OS,
427
- decode: requiresWebAudioDecode(container) ? 'web-audio' : 'native'
390
+ const pending = run().then(prepared => {
391
+ preparedRef.current = prepared;
392
+ preparingRef.current = null;
393
+ logAudioDebug('audio prepared', {
394
+ src,
395
+ container: prepared.container,
396
+ platform: _reactNative.Platform.OS
397
+ });
398
+ return prepared;
399
+ }, error => {
400
+ preparingRef.current = null;
401
+ throw error;
402
+ });
403
+ preparingRef.current = pending;
404
+ return pending;
405
+ };
406
+ const readBase64 = async uri => {
407
+ const info = await FileSystem.getInfoAsync(uri);
408
+ const size = 'size' in info ? info.size ?? 0 : 0;
409
+ if (size > _AudioDecoderHost.MAX_DECODE_BYTES) {
410
+ throw new Error('audio_too_large_to_decode');
411
+ }
412
+ return FileSystem.readAsStringAsync(uri, {
413
+ encoding: FileSystem.EncodingType.Base64
428
414
  });
429
- return prepared;
430
415
  };
431
- const maybeInjectDecode = () => {
432
- const base64 = preparedRef.current?.base64;
433
- if (bridgeReadyRef.current && base64 && !injectedRef.current && webViewRef.current) {
434
- injectedRef.current = true;
435
- webViewRef.current.injectJavaScript(`window.__decodeAudio(${JSON.stringify(base64)}); true;`);
416
+ const remember = analysis => {
417
+ analysisCache.set(cacheKey, analysis);
418
+ const base = cacheBase();
419
+ if (base) {
420
+ FileSystem.writeAsStringAsync(`${base}.wave.json`, JSON.stringify(analysis)).catch(() => {});
421
+ }
422
+ };
423
+ const applyAnalysis = analysis => {
424
+ if (unmountedRef.current) {
425
+ return;
426
+ }
427
+ if (!metaPeaks && analysis.peaks.length) {
428
+ setPeaks(analysis.peaks);
429
+ }
430
+ if (analysis.durationMillis > 0) {
431
+ setDuration(current => current || analysis.durationMillis);
432
+ }
433
+ };
434
+
435
+ // Decode the clip once: its bars, its real length (MediaRecorder writes
436
+ // WebM without a duration header), and — where the native player cannot
437
+ // read it — a WAV copy to play.
438
+ const decodeClip = async prepared => {
439
+ const wantWav = requiresWebAudioDecode(prepared.container) && !prepared.playable;
440
+ const clip = await (0, _AudioDecoderHost.decodeAudioClip)(await readBase64(prepared.localUri), {
441
+ wantWav
442
+ });
443
+ const analysis = {
444
+ peaks: clip.peaks,
445
+ durationMillis: clip.durationMillis
446
+ };
447
+ remember(analysis);
448
+ applyAnalysis(analysis);
449
+ const base = cacheBase();
450
+ if (clip.wavBase64 && base) {
451
+ const wavUri = `${base}.wav`;
452
+ await FileSystem.writeAsStringAsync(wavUri, clip.wavBase64, {
453
+ encoding: FileSystem.EncodingType.Base64
454
+ });
455
+ await FileSystem.deleteAsync(prepared.localUri, {
456
+ idempotent: true
457
+ }).catch(() => {});
458
+ preparedRef.current = {
459
+ localUri: wavUri,
460
+ container: 'wav',
461
+ playable: true
462
+ };
436
463
  }
464
+ return preparedRef.current ?? prepared;
437
465
  };
438
466
 
439
- // expo-audio reports times in SECONDS (expo-av used milliseconds); the
440
- // whole UI below is millisecond-based, so convert at this boundary and
441
- // nowhere else.
467
+ // Full reset whenever the source changes (component reused for a new
468
+ // message / re-render with a different src).
469
+ const lastSrcRef = (0, _react.useRef)(src);
470
+ (0, _react.useEffect)(() => {
471
+ if (lastSrcRef.current === src) {
472
+ return;
473
+ }
474
+ lastSrcRef.current = src;
475
+ releasePlayer();
476
+ preparedRef.current = null;
477
+ preparingRef.current = null;
478
+ didFinishRef.current = false;
479
+ pendingSeekRef.current = null;
480
+ clearLoadingGuard();
481
+ setIsPlaying(false);
482
+ setIsLoading(false);
483
+ setPlaybackError(false);
484
+ setPosition(0);
485
+ setDuration(metaDuration);
486
+ setPeaks(metaPeaks);
487
+ // eslint-disable-next-line react-hooks/exhaustive-deps
488
+ }, [src]);
489
+
490
+ // The waveform, as soon as the bubble shows: from the message itself,
491
+ // from this session's cache, from the disk cache, or by decoding.
492
+ (0, _react.useEffect)(() => {
493
+ if (!src || metaPeaks && metaDuration > 0) {
494
+ return;
495
+ }
496
+ const cached = analysisCache.get(cacheKey);
497
+ if (cached) {
498
+ applyAnalysis(cached);
499
+ return;
500
+ }
501
+ let cancelled = false;
502
+ (async () => {
503
+ const base = cacheBase();
504
+ if (base) {
505
+ try {
506
+ const stored = await FileSystem.readAsStringAsync(`${base}.wave.json`);
507
+ const parsed = JSON.parse(stored);
508
+ if (Array.isArray(parsed?.peaks)) {
509
+ analysisCache.set(cacheKey, parsed);
510
+ if (!cancelled) {
511
+ applyAnalysis(parsed);
512
+ }
513
+ return;
514
+ }
515
+ } catch {
516
+ /* not analysed yet */
517
+ }
518
+ }
519
+ try {
520
+ const prepared = await prepareSource();
521
+ if (cancelled) {
522
+ return;
523
+ }
524
+ await decodeClip(prepared);
525
+ } catch (error) {
526
+ // Not fatal: the bubble keeps flat bars and still plays.
527
+ logAudioDebug('audio waveform unavailable', {
528
+ src,
529
+ error: error instanceof Error ? error.message : String(error)
530
+ });
531
+ }
532
+ })();
533
+ return () => {
534
+ cancelled = true;
535
+ };
536
+ // eslint-disable-next-line react-hooks/exhaustive-deps
537
+ }, [src]);
538
+
539
+ // expo-audio reports times in SECONDS; the UI is millisecond-based, so
540
+ // convert at this boundary and nowhere else.
442
541
  const onPlaybackStatusUpdate = status => {
443
- if (!status.isLoaded) {
542
+ if (!status.isLoaded || unmountedRef.current) {
444
543
  return;
445
544
  }
446
545
  setPosition(Math.max(0, status.currentTime * 1000));
447
- setDuration(status.duration > 0 ? status.duration * 1000 : 0);
546
+ // A WebM without a duration header reports 0 here: keep the decoded one.
547
+ if (status.duration > 0) {
548
+ setDuration(status.duration * 1000);
549
+ }
448
550
  setIsPlaying(status.playing);
449
551
  if (status.didJustFinish) {
450
552
  didFinishRef.current = true;
@@ -465,15 +567,13 @@ const AudioMessage = ({
465
567
  } catch {
466
568
  /* non-fatal — still plays through the ringer channel */
467
569
  }
468
- // expo-audio has no awaitable `createAsync`: the player is constructed
469
- // synchronously and loads in the background, reporting `isLoaded` via
470
- // the status event. Wait for that first loaded status (same 12s budget
471
- // expo-av's createAsync had) so the spinner still resolves to either
472
- // real playback or the error state, never to a silent dead button.
570
+ // expo-audio has no awaitable create: the player loads in the
571
+ // background and reports `isLoaded` via the status event. Wait for it
572
+ // so the spinner resolves to real playback or the error state.
473
573
  const player = (0, _expoAudio.createAudioPlayer)({
474
574
  uri: localUri
475
575
  }, {
476
- updateInterval: 250
576
+ updateInterval: 100
477
577
  });
478
578
  let settleLoaded = null;
479
579
  const loaded = new Promise(resolve => {
@@ -500,81 +600,33 @@ const AudioMessage = ({
500
600
  }
501
601
  soundRef.current = player;
502
602
  statusSubRef.current = subscription;
603
+ if (rateRef.current !== 1) {
604
+ player.shouldCorrectPitch = true;
605
+ player.setPlaybackRate(rateRef.current);
606
+ }
607
+ const seek = pendingSeekRef.current;
608
+ pendingSeekRef.current = null;
609
+ if (seek !== null && player.duration > 0) {
610
+ await player.seekTo(seek * player.duration);
611
+ }
612
+ claimPlayback();
503
613
  player.play();
504
614
  clearLoadingGuard();
505
615
  setIsLoading(false);
506
616
  setPlaybackError(false);
507
617
  setIsPlaying(true);
508
- logAudioDebug('native audio playback started', {
509
- src,
510
- container: preparedRef.current?.container,
511
- localUri
512
- });
513
- };
514
-
515
- // WebView finished decoding Opus → WAV: persist the WAV and play it
516
- // natively. From here it is indistinguishable from any other native clip.
517
- const onDecoded = async (durationMillis, wavBase64) => {
518
- try {
519
- const cacheDirectory = FileSystem.cacheDirectory || '';
520
- const wavUri = `${cacheDirectory}ethora-audio-${hashString(src)}.wav`;
521
- await FileSystem.writeAsStringAsync(wavUri, wavBase64, {
522
- encoding: FileSystem.EncodingType.Base64
523
- });
524
- if (unmountedRef.current) {
525
- return;
526
- }
527
- preparedRef.current = {
528
- localUri: wavUri,
529
- container: preparedRef.current?.container ?? 'webm'
530
- };
531
- if (durationMillis > 0) {
532
- setDuration(durationMillis);
533
- }
534
- setWebViewEnabled(false); // decoder no longer needed
535
- await startNativePlayback(wavUri);
536
- } catch (error) {
537
- fail(error);
538
- }
539
- };
540
- const handleWebMessage = event => {
541
- let payload;
542
- try {
543
- payload = JSON.parse(event.nativeEvent.data);
544
- } catch {
545
- return;
546
- }
547
- if (payload.type === 'bridge_ready') {
548
- bridgeReadyRef.current = true;
549
- maybeInjectDecode();
550
- return;
551
- }
552
- if (payload.type === 'decoded') {
553
- logAudioDebug('web audio decoded', {
554
- src,
555
- durationMillis: payload.durationMillis,
556
- wavBytes: payload.wavBase64 ? payload.wavBase64.length : 0
557
- });
558
- void onDecoded(payload.durationMillis, payload.wavBase64);
559
- return;
560
- }
561
- // type === 'error'
562
- fail(new Error(payload.message || 'web_audio_error'));
563
618
  };
564
619
  const togglePlayback = async () => {
565
620
  if (!src) {
566
621
  return;
567
622
  }
568
623
 
569
- // Already-loaded native sound (covers both native formats AND the
570
- // decoded-WAV from the WebView path) → plain toggle.
624
+ // Already-loaded player → plain toggle.
571
625
  if (soundRef.current) {
572
626
  try {
573
- // `play()` / `pause()` emit NO status event of their own (expo-av's
574
- // playAsync/pauseAsync resolved with one). Playing state only ever
575
- // reaches us through the periodic time observer, and that observer
576
- // stops while paused — so without setting this here the button
577
- // would latch on "pause" forever and never resume.
627
+ // `play()` / `pause()` emit no status event of their own, and the
628
+ // time observer stops while paused — so set the state here or the
629
+ // button latches on "pause" forever.
578
630
  if (isPlaying) {
579
631
  soundRef.current.pause();
580
632
  setIsPlaying(false);
@@ -583,6 +635,7 @@ const AudioMessage = ({
583
635
  await soundRef.current.seekTo(0);
584
636
  didFinishRef.current = false;
585
637
  }
638
+ claimPlayback();
586
639
  soundRef.current.play();
587
640
  setIsPlaying(true);
588
641
  }
@@ -592,22 +645,17 @@ const AudioMessage = ({
592
645
  return;
593
646
  }
594
647
 
595
- // First tap → prepare (download + sniff) then route to the right engine.
648
+ // First tap → download (unless the waveform already did), decode where
649
+ // the native player cannot, then play.
596
650
  setPlaybackError(false);
597
651
  setIsLoading(true);
598
652
  armLoadingGuard();
599
653
  try {
600
- const prepared = await withTimeout(prepareSource(), 14000, 'audio_prepare_timeout');
601
- if (unmountedRef.current) {
602
- return;
654
+ let prepared = await withTimeout(prepareSource(), 14000, 'audio_prepare_timeout');
655
+ if (requiresWebAudioDecode(prepared.container) && !prepared.playable) {
656
+ prepared = await decodeClip(prepared);
603
657
  }
604
- if (requiresWebAudioDecode(prepared.container)) {
605
- // Mount the decoder WebView; decoding + playback continue when the
606
- // 'decoded' message arrives (→ onDecoded → startNativePlayback).
607
- if (!webViewEnabled) {
608
- setWebViewEnabled(true);
609
- }
610
- maybeInjectDecode();
658
+ if (unmountedRef.current) {
611
659
  return;
612
660
  }
613
661
  await startNativePlayback(prepared.localUri);
@@ -615,166 +663,191 @@ const AudioMessage = ({
615
663
  fail(error);
616
664
  }
617
665
  };
666
+
667
+ // A tap on the bars jumps there (and starts playing, as in Telegram).
668
+ const seekFromTap = event => {
669
+ if (!waveWidth || playbackError) {
670
+ return;
671
+ }
672
+ const ratio = Math.max(0, Math.min(1, event.nativeEvent.locationX / waveWidth));
673
+ const player = soundRef.current;
674
+ if (player && player.duration > 0) {
675
+ didFinishRef.current = false;
676
+ void player.seekTo(ratio * player.duration);
677
+ setPosition(ratio * player.duration * 1000);
678
+ if (!isPlaying) {
679
+ claimPlayback();
680
+ player.play();
681
+ setIsPlaying(true);
682
+ }
683
+ return;
684
+ }
685
+ if (isLoading) {
686
+ return;
687
+ }
688
+ pendingSeekRef.current = ratio;
689
+ void togglePlayback();
690
+ };
691
+ const cycleSpeed = () => {
692
+ const next = SPEEDS[(SPEEDS.indexOf(rate) + 1) % SPEEDS.length];
693
+ rateRef.current = next;
694
+ setRate(next);
695
+ const player = soundRef.current;
696
+ if (player) {
697
+ player.shouldCorrectPitch = true;
698
+ player.setPlaybackRate(next);
699
+ }
700
+ };
618
701
  (0, _react.useEffect)(() => {
619
702
  unmountedRef.current = false;
620
703
  return () => {
621
704
  unmountedRef.current = true;
705
+ if (pauseActive === pauseSelf) {
706
+ pauseActive = null;
707
+ }
622
708
  clearLoadingGuard();
623
709
  releasePlayer();
624
710
  };
625
711
  // eslint-disable-next-line react-hooks/exhaustive-deps
626
712
  }, []);
627
-
628
- // Full reset whenever the source changes (component reused for a new
629
- // message / re-render with a different src).
630
- (0, _react.useEffect)(() => {
631
- releasePlayer();
632
- preparedRef.current = null;
633
- bridgeReadyRef.current = false;
634
- injectedRef.current = false;
635
- didFinishRef.current = false;
636
- clearLoadingGuard();
637
- setIsPlaying(false);
638
- setIsLoading(false);
639
- setPlaybackError(false);
640
- setPosition(0);
641
- setDuration(0);
642
- setWebViewEnabled(false);
643
- // eslint-disable-next-line react-hooks/exhaustive-deps
644
- }, [src]);
713
+ const onWaveLayout = event => {
714
+ const width = Math.floor(event.nativeEvent.layout.width);
715
+ if (width !== waveWidth) {
716
+ setWaveWidth(width);
717
+ }
718
+ };
719
+ const barCount = waveWidth ? Math.max(8, Math.floor((waveWidth + BAR_GAP) / (BAR_WIDTH + BAR_GAP))) : 0;
720
+ const bars = (0, _react.useMemo)(() => barCount ? (0, _audioWaveform.resamplePeaks)(peaks ?? new Array(barCount).fill(_audioWaveform.MIN_BAR), barCount) : [], [peaks, barCount]);
645
721
  const progress = duration > 0 ? Math.min(1, position / duration) : 0;
722
+ const playedBars = Math.round(progress * bars.length);
723
+ const started = isPlaying || position > 0;
724
+ const timeLabel = playbackError ? t('media.audioUnavailable') : started ? (0, _audioWaveform.formatClipTime)(position) : duration > 0 ? (0, _audioWaveform.formatClipTime)(duration) : '';
646
725
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
647
- style: styles.root,
648
- children: [webViewEnabled ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
649
- style: styles.decoderHost,
650
- pointerEvents: "none",
651
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeWebview.WebView, {
652
- ref: webViewRef,
653
- source: {
654
- html: WEB_DECODER_HTML
655
- },
656
- originWhitelist: ['*'],
657
- onMessage: handleWebMessage,
658
- javaScriptEnabled: true,
659
- domStorageEnabled: false,
660
- scrollEnabled: false,
661
- pointerEvents: "none",
662
- showsHorizontalScrollIndicator: false,
663
- showsVerticalScrollIndicator: false,
664
- style: styles.hiddenWebView
726
+ style: styles.container,
727
+ testID: "audio-message",
728
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
729
+ testID: "audio-play-button",
730
+ accessibilityRole: "button",
731
+ accessibilityLabel: t(isPlaying ? 'media.audioPause' : 'media.audioPlay'),
732
+ style: ({
733
+ pressed
734
+ }) => [styles.playButton, {
735
+ backgroundColor: buttonFill,
736
+ opacity: pressed ? 0.85 : 1
737
+ }],
738
+ onPress: togglePlayback,
739
+ disabled: isLoading,
740
+ hitSlop: 6,
741
+ children: isLoading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
742
+ size: "small",
743
+ color: buttonGlyph
744
+ }) : isPlaying ? /*#__PURE__*/(0, _jsxRuntime.jsx)(PauseGlyph, {
745
+ color: buttonGlyph
746
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(PlayGlyph, {
747
+ color: buttonGlyph
665
748
  })
666
- }) : null, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
667
- style: styles.container,
668
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
669
- testID: "audio-play-button",
670
- accessibilityLabel: "audio-play-button",
671
- style: [styles.playButton, {
672
- backgroundColor: primaryColor
673
- }],
674
- onPress: togglePlayback,
675
- disabled: isLoading,
676
- activeOpacity: 0.85,
677
- children: isLoading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
678
- size: "small",
679
- color: onPrimary
680
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
681
- style: styles.iconWrap,
682
- children: isPlaying ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_icons.PauseIcon, {
683
- width: 18,
684
- height: 18,
685
- color: onPrimary
686
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_icons.PlayIcon, {
687
- width: 18,
688
- height: 18,
689
- color: onPrimary
690
- })
691
- })
749
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
750
+ style: styles.track,
751
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
752
+ testID: "audio-waveform",
753
+ accessibilityElementsHidden: true,
754
+ importantForAccessibility: "no-hide-descendants",
755
+ onPress: seekFromTap,
756
+ onLayout: onWaveLayout,
757
+ style: styles.wave,
758
+ children: bars.map((value, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
759
+ style: [styles.bar, {
760
+ height: Math.max(BAR_WIDTH, Math.round(value * WAVE_HEIGHT)),
761
+ backgroundColor: ink,
762
+ opacity: index < playedBars ? 1 : 0.35
763
+ }]
764
+ }, index))
692
765
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
693
- style: styles.progressContainer,
694
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
695
- style: [styles.progressTrack, trackStyle],
696
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
697
- style: [styles.progressFill, {
698
- width: `${progress * 100}%`,
699
- backgroundColor: primaryColor
700
- }]
766
+ style: styles.metaRow,
767
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
768
+ style: [styles.time, {
769
+ color: metaColor
770
+ }],
771
+ numberOfLines: 1,
772
+ children: timeLabel
773
+ }), started && !playbackError ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
774
+ testID: "audio-speed",
775
+ accessibilityRole: "button",
776
+ accessibilityLabel: t('media.audioSpeed'),
777
+ onPress: cycleSpeed,
778
+ hitSlop: 8,
779
+ style: [styles.speed, {
780
+ backgroundColor: ink
781
+ }],
782
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
783
+ style: [styles.speedText, {
784
+ color: buttonGlyph
785
+ }],
786
+ children: `${rate}×`
701
787
  })
702
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
703
- style: styles.progressRow,
704
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
705
- style: [styles.time, timeStyle],
706
- children: playbackError ? 'Audio unavailable' : formatTime(position)
707
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
708
- style: [styles.time, timeStyle],
709
- children: !playbackError && duration > 0 ? formatTime(duration) : ''
710
- })]
711
- })]
788
+ }) : null]
712
789
  })]
713
790
  })]
714
791
  });
715
792
  };
716
793
  var _default = exports.default = AudioMessage;
717
794
  const styles = _reactNative.StyleSheet.create({
718
- root: {
719
- position: 'relative'
720
- },
721
- decoderHost: {
722
- position: 'absolute',
723
- top: 0,
724
- left: 0,
725
- width: 0,
726
- height: 0,
727
- overflow: 'hidden',
728
- opacity: 0
729
- },
730
795
  container: {
731
796
  flexDirection: 'row',
732
797
  alignItems: 'center',
733
- gap: 12,
734
- paddingHorizontal: 12,
735
- paddingVertical: 10,
736
- width: 260,
798
+ gap: 10,
799
+ // Media bubbles carry no padding of their own (images run edge to
800
+ // edge), so the player brings the text bubble's inset with it.
801
+ paddingTop: 10,
802
+ paddingLeft: 10,
803
+ paddingRight: 12,
804
+ width: 250,
737
805
  maxWidth: '100%'
738
806
  },
739
807
  playButton: {
740
- width: 44,
741
- height: 44,
742
- borderRadius: 22,
808
+ width: 46,
809
+ height: 46,
810
+ borderRadius: 23,
743
811
  alignItems: 'center',
744
812
  justifyContent: 'center'
745
813
  },
746
- iconWrap: {
747
- marginLeft: 1
748
- },
749
- progressContainer: {
814
+ track: {
750
815
  flex: 1,
751
- gap: 6
816
+ gap: 4
752
817
  },
753
- progressRow: {
818
+ wave: {
819
+ height: WAVE_HEIGHT,
754
820
  flexDirection: 'row',
755
- justifyContent: 'space-between',
756
- alignItems: 'center'
757
- },
758
- progressTrack: {
759
- height: 6,
760
- backgroundColor: '#D0D7E6',
761
- borderRadius: 999,
821
+ alignItems: 'flex-end',
822
+ gap: BAR_GAP,
762
823
  overflow: 'hidden'
763
824
  },
764
- hiddenWebView: {
765
- position: 'absolute',
766
- width: 1,
767
- height: 1,
768
- opacity: 0
825
+ bar: {
826
+ width: BAR_WIDTH,
827
+ borderRadius: BAR_WIDTH / 2
769
828
  },
770
- progressFill: {
771
- height: '100%',
772
- borderRadius: 999
829
+ metaRow: {
830
+ flexDirection: 'row',
831
+ alignItems: 'center',
832
+ gap: 6,
833
+ minHeight: 16
773
834
  },
774
835
  time: {
775
836
  fontSize: 12,
776
- color: '#667085',
777
- fontWeight: '500'
837
+ lineHeight: 16,
838
+ fontVariant: ['tabular-nums'],
839
+ opacity: 0.85
840
+ },
841
+ speed: {
842
+ borderRadius: 8,
843
+ paddingHorizontal: 5,
844
+ paddingVertical: 1,
845
+ opacity: 0.85
846
+ },
847
+ speedText: {
848
+ fontSize: 11,
849
+ lineHeight: 14,
850
+ fontWeight: '700'
778
851
  }
779
852
  });
780
853
  //# sourceMappingURL=AudioMessage.js.map