@ethora/chat-component-rn 26.10.9 → 26.10.11

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 (608) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +126 -1
  3. package/lib/commonjs/booking/index.js +44 -0
  4. package/lib/commonjs/booking/index.js.map +1 -0
  5. package/lib/commonjs/booking/pendingScheduledCall.js +275 -0
  6. package/lib/commonjs/booking/pendingScheduledCall.js.map +1 -0
  7. package/lib/commonjs/booking/scheduleForm.js +91 -0
  8. package/lib/commonjs/booking/scheduleForm.js.map +1 -0
  9. package/lib/commonjs/booking/scheduledCall.js +141 -0
  10. package/lib/commonjs/booking/scheduledCall.js.map +1 -0
  11. package/lib/commonjs/booking/scheduledCallActions.js +128 -0
  12. package/lib/commonjs/booking/scheduledCallActions.js.map +1 -0
  13. package/lib/commonjs/booking/scheduledCallLink.js +143 -0
  14. package/lib/commonjs/booking/scheduledCallLink.js.map +1 -0
  15. package/lib/commonjs/booking/scheduledCallStore.js +64 -0
  16. package/lib/commonjs/booking/scheduledCallStore.js.map +1 -0
  17. package/lib/commonjs/booking/startRoomCall.js +84 -0
  18. package/lib/commonjs/booking/startRoomCall.js.map +1 -0
  19. package/lib/commonjs/calls/callBusy.js +18 -0
  20. package/lib/commonjs/calls/callBusy.js.map +1 -0
  21. package/lib/commonjs/calls/callDisplay.js +73 -0
  22. package/lib/commonjs/calls/callDisplay.js.map +1 -0
  23. package/lib/commonjs/calls/callMode.js +175 -0
  24. package/lib/commonjs/calls/callMode.js.map +1 -0
  25. package/lib/commonjs/calls/declineReport.js +20 -0
  26. package/lib/commonjs/calls/declineReport.js.map +1 -0
  27. package/lib/commonjs/calls/p2p/P2PCallController.js +724 -0
  28. package/lib/commonjs/calls/p2p/P2PCallController.js.map +1 -0
  29. package/lib/commonjs/calls/p2p/icePolicy.js +107 -0
  30. package/lib/commonjs/calls/p2p/icePolicy.js.map +1 -0
  31. package/lib/commonjs/calls/p2p/negotiator.js +202 -0
  32. package/lib/commonjs/calls/p2p/negotiator.js.map +1 -0
  33. package/lib/commonjs/calls/p2p/p2pRuntime.js +147 -0
  34. package/lib/commonjs/calls/p2p/p2pRuntime.js.map +1 -0
  35. package/lib/commonjs/calls/p2p/signalInbox.js +98 -0
  36. package/lib/commonjs/calls/p2p/signalInbox.js.map +1 -0
  37. package/lib/commonjs/calls/p2p/signalStanza.js +141 -0
  38. package/lib/commonjs/calls/p2p/signalStanza.js.map +1 -0
  39. package/lib/commonjs/calls/p2p/webrtcRuntime.js +53 -0
  40. package/lib/commonjs/calls/p2p/webrtcRuntime.js.map +1 -0
  41. package/lib/commonjs/calls/senderTrust.js +43 -0
  42. package/lib/commonjs/calls/senderTrust.js.map +1 -0
  43. package/lib/commonjs/calls/startCall.js +51 -0
  44. package/lib/commonjs/calls/startCall.js.map +1 -0
  45. package/lib/commonjs/components/Booking/BookingIcons.js +55 -0
  46. package/lib/commonjs/components/Booking/BookingIcons.js.map +1 -0
  47. package/lib/commonjs/components/Booking/ScheduleCallButton.js +64 -0
  48. package/lib/commonjs/components/Booking/ScheduleCallButton.js.map +1 -0
  49. package/lib/commonjs/components/Booking/ScheduleCallSheet.js +351 -0
  50. package/lib/commonjs/components/Booking/ScheduleCallSheet.js.map +1 -0
  51. package/lib/commonjs/components/Booking/ScheduledCallCard.js +203 -0
  52. package/lib/commonjs/components/Booking/ScheduledCallCard.js.map +1 -0
  53. package/lib/commonjs/components/Booking/ScheduledCallHost.js +23 -0
  54. package/lib/commonjs/components/Booking/ScheduledCallHost.js.map +1 -0
  55. package/lib/commonjs/components/Booking/ScheduledCallMessage.js +55 -0
  56. package/lib/commonjs/components/Booking/ScheduledCallMessage.js.map +1 -0
  57. package/lib/commonjs/components/Booking/ScheduledCallPreJoin.js +235 -0
  58. package/lib/commonjs/components/Booking/ScheduledCallPreJoin.js.map +1 -0
  59. package/lib/commonjs/components/Booking/bookingShared.js +305 -0
  60. package/lib/commonjs/components/Booking/bookingShared.js.map +1 -0
  61. package/lib/commonjs/components/MainComponents/AlbumGrid.js +6 -2
  62. package/lib/commonjs/components/MainComponents/AlbumGrid.js.map +1 -1
  63. package/lib/commonjs/components/MainComponents/ChatHeader.js +18 -12
  64. package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
  65. package/lib/commonjs/components/MainComponents/LanguageSelectorButton.js +5 -2
  66. package/lib/commonjs/components/MainComponents/LanguageSelectorButton.js.map +1 -1
  67. package/lib/commonjs/components/MainComponents/LanguageSelectorModal.js +6 -3
  68. package/lib/commonjs/components/MainComponents/LanguageSelectorModal.js.map +1 -1
  69. package/lib/commonjs/components/MainComponents/MediaMessage.js +13 -0
  70. package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
  71. package/lib/commonjs/components/MainComponents/MessageContainer.js +13 -0
  72. package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
  73. package/lib/commonjs/components/MainComponents/ReduxWrapper.js +10 -0
  74. package/lib/commonjs/components/MainComponents/ReduxWrapper.js.map +1 -1
  75. package/lib/commonjs/components/MainComponents/RoomList.js +7 -16
  76. package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
  77. package/lib/commonjs/components/MessageBubble/Message.js +27 -1
  78. package/lib/commonjs/components/MessageBubble/Message.js.map +1 -1
  79. package/lib/commonjs/components/Modals/ChatProfileModal/ChatMediaGrid.js +159 -0
  80. package/lib/commonjs/components/Modals/ChatProfileModal/ChatMediaGrid.js.map +1 -0
  81. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +203 -134
  82. package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  83. package/lib/commonjs/components/Modals/ChatProfileModal/LeaveChatModal.js +180 -0
  84. package/lib/commonjs/components/Modals/ChatProfileModal/LeaveChatModal.js.map +1 -0
  85. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js +19 -15
  86. package/lib/commonjs/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -1
  87. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +100 -162
  88. package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  89. package/lib/commonjs/components/Modals/FilePreviewModal/MediaViewer.js +824 -0
  90. package/lib/commonjs/components/Modals/FilePreviewModal/MediaViewer.js.map +1 -0
  91. package/lib/commonjs/components/Modals/FilePreviewModal/useSaveFile.js +179 -0
  92. package/lib/commonjs/components/Modals/FilePreviewModal/useSaveFile.js.map +1 -0
  93. package/lib/commonjs/components/Modals/MessageSearchModal/MessageSearchModal.js +22 -5
  94. package/lib/commonjs/components/Modals/MessageSearchModal/MessageSearchModal.js.map +1 -1
  95. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +15 -8
  96. package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  97. package/lib/commonjs/components/Modals/UserSettingsModal/LanguageCard.js +1 -1
  98. package/lib/commonjs/components/Modals/UserSettingsModal/LanguageCard.js.map +1 -1
  99. package/lib/commonjs/components/VideoCalls/ActiveCallBar.js +3 -2
  100. package/lib/commonjs/components/VideoCalls/ActiveCallBar.js.map +1 -1
  101. package/lib/commonjs/components/VideoCalls/CallButtons.js +19 -11
  102. package/lib/commonjs/components/VideoCalls/CallButtons.js.map +1 -1
  103. package/lib/commonjs/components/VideoCalls/CallControlBar.js +119 -0
  104. package/lib/commonjs/components/VideoCalls/CallControlBar.js.map +1 -0
  105. package/lib/commonjs/components/VideoCalls/CallVideo.js +49 -0
  106. package/lib/commonjs/components/VideoCalls/CallVideo.js.map +1 -0
  107. package/lib/commonjs/components/VideoCalls/GroupCallView.js +281 -0
  108. package/lib/commonjs/components/VideoCalls/GroupCallView.js.map +1 -0
  109. package/lib/commonjs/components/VideoCalls/P2PCallRunner.js +151 -0
  110. package/lib/commonjs/components/VideoCalls/P2PCallRunner.js.map +1 -0
  111. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js +38 -14
  112. package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js.map +1 -1
  113. package/lib/commonjs/components/VideoCalls/VideoCallSession.js +57 -128
  114. package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -1
  115. package/lib/commonjs/components/VideoCalls/callActions.js +3 -0
  116. package/lib/commonjs/components/VideoCalls/callActions.js.map +1 -1
  117. package/lib/commonjs/components/VideoCalls/callElapsed.js +38 -0
  118. package/lib/commonjs/components/VideoCalls/callElapsed.js.map +1 -0
  119. package/lib/commonjs/components/VideoCalls/callLive.js +15 -0
  120. package/lib/commonjs/components/VideoCalls/callLive.js.map +1 -0
  121. package/lib/commonjs/components/VideoCalls/callSessionController.js +81 -24
  122. package/lib/commonjs/components/VideoCalls/callSessionController.js.map +1 -1
  123. package/lib/commonjs/components/VideoCalls/callSessionTypes.js +41 -0
  124. package/lib/commonjs/components/VideoCalls/callSessionTypes.js.map +1 -0
  125. package/lib/commonjs/components/VideoCalls/groupLayout.js +43 -0
  126. package/lib/commonjs/components/VideoCalls/groupLayout.js.map +1 -0
  127. package/lib/commonjs/components/VideoCalls/p2pCallSession.js +272 -0
  128. package/lib/commonjs/components/VideoCalls/p2pCallSession.js.map +1 -0
  129. package/lib/commonjs/components/VideoCalls/useCallKeep.js +7 -2
  130. package/lib/commonjs/components/VideoCalls/useCallKeep.js.map +1 -1
  131. package/lib/commonjs/components/VideoCalls/useOngoingCallNotification.js +2 -1
  132. package/lib/commonjs/components/VideoCalls/useOngoingCallNotification.js.map +1 -1
  133. package/lib/commonjs/components/styled/MessageImage.js +4 -1
  134. package/lib/commonjs/components/styled/MessageImage.js.map +1 -1
  135. package/lib/commonjs/components/styled/VideoMessage.js +5 -1
  136. package/lib/commonjs/components/styled/VideoMessage.js.map +1 -1
  137. package/lib/commonjs/context/MediaSourceContext.js +18 -0
  138. package/lib/commonjs/context/MediaSourceContext.js.map +1 -0
  139. package/lib/commonjs/context/xmppProvider.js +2 -1
  140. package/lib/commonjs/context/xmppProvider.js.map +1 -1
  141. package/lib/commonjs/helpers/callPush.js +3 -1
  142. package/lib/commonjs/helpers/callPush.js.map +1 -1
  143. package/lib/commonjs/helpers/constants/MODAL_COMPONENTS.js +3 -1
  144. package/lib/commonjs/helpers/constants/MODAL_COMPONENTS.js.map +1 -1
  145. package/lib/commonjs/helpers/constants/MODAL_TYPES.js +2 -0
  146. package/lib/commonjs/helpers/constants/MODAL_TYPES.js.map +1 -1
  147. package/lib/commonjs/helpers/incomingCallFromPush.js +63 -7
  148. package/lib/commonjs/helpers/incomingCallFromPush.js.map +1 -1
  149. package/lib/commonjs/helpers/publicChatsEntry.js +8 -6
  150. package/lib/commonjs/helpers/publicChatsEntry.js.map +1 -1
  151. package/lib/commonjs/helpers/pushPayload.js +5 -0
  152. package/lib/commonjs/helpers/pushPayload.js.map +1 -1
  153. package/lib/commonjs/helpers/reportRoom.js +76 -0
  154. package/lib/commonjs/helpers/reportRoom.js.map +1 -0
  155. package/lib/commonjs/helpers/roomMedia.js +118 -0
  156. package/lib/commonjs/helpers/roomMedia.js.map +1 -0
  157. package/lib/commonjs/i18n/strings.js +480 -0
  158. package/lib/commonjs/i18n/strings.js.map +1 -1
  159. package/lib/commonjs/main.js +93 -0
  160. package/lib/commonjs/main.js.map +1 -1
  161. package/lib/commonjs/networking/api-requests/callState.api.js +75 -0
  162. package/lib/commonjs/networking/api-requests/callState.api.js.map +1 -0
  163. package/lib/commonjs/networking/api-requests/push.api.js +29 -6
  164. package/lib/commonjs/networking/api-requests/push.api.js.map +1 -1
  165. package/lib/commonjs/networking/api-requests/rooms.api.js +17 -15
  166. package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
  167. package/lib/commonjs/networking/api-requests/scheduledCalls.api.js +141 -0
  168. package/lib/commonjs/networking/api-requests/scheduledCalls.api.js.map +1 -0
  169. package/lib/commonjs/networking/callTokenStanza.js +210 -50
  170. package/lib/commonjs/networking/callTokenStanza.js.map +1 -1
  171. package/lib/commonjs/roomStore/callSlice.js +59 -4
  172. package/lib/commonjs/roomStore/callSlice.js.map +1 -1
  173. package/lib/commonjs/services/appBadge.js +80 -0
  174. package/lib/commonjs/services/appBadge.js.map +1 -0
  175. package/lib/commonjs/services/languageSettings.js +47 -15
  176. package/lib/commonjs/services/languageSettings.js.map +1 -1
  177. package/lib/commonjs/services/pushRegistration.js +21 -5
  178. package/lib/commonjs/services/pushRegistration.js.map +1 -1
  179. package/lib/commonjs/version.js +1 -1
  180. package/lib/commonjs/version.js.map +1 -1
  181. package/lib/module/booking/index.js +5 -0
  182. package/lib/module/booking/index.js.map +1 -0
  183. package/lib/module/booking/pendingScheduledCall.js +261 -0
  184. package/lib/module/booking/pendingScheduledCall.js.map +1 -0
  185. package/lib/module/booking/scheduleForm.js +79 -0
  186. package/lib/module/booking/scheduleForm.js.map +1 -0
  187. package/lib/module/booking/scheduledCall.js +129 -0
  188. package/lib/module/booking/scheduledCall.js.map +1 -0
  189. package/lib/module/booking/scheduledCallActions.js +118 -0
  190. package/lib/module/booking/scheduledCallActions.js.map +1 -0
  191. package/lib/module/booking/scheduledCallLink.js +136 -0
  192. package/lib/module/booking/scheduledCallLink.js.map +1 -0
  193. package/lib/module/booking/scheduledCallStore.js +60 -0
  194. package/lib/module/booking/scheduledCallStore.js.map +1 -0
  195. package/lib/module/booking/startRoomCall.js +80 -0
  196. package/lib/module/booking/startRoomCall.js.map +1 -0
  197. package/lib/module/calls/callBusy.js +13 -0
  198. package/lib/module/calls/callBusy.js.map +1 -0
  199. package/lib/module/calls/callDisplay.js +65 -0
  200. package/lib/module/calls/callDisplay.js.map +1 -0
  201. package/lib/module/calls/callMode.js +168 -0
  202. package/lib/module/calls/callMode.js.map +1 -0
  203. package/lib/module/calls/declineReport.js +16 -0
  204. package/lib/module/calls/declineReport.js.map +1 -0
  205. package/lib/module/calls/p2p/P2PCallController.js +718 -0
  206. package/lib/module/calls/p2p/P2PCallController.js.map +1 -0
  207. package/lib/module/calls/p2p/icePolicy.js +102 -0
  208. package/lib/module/calls/p2p/icePolicy.js.map +1 -0
  209. package/lib/module/calls/p2p/negotiator.js +197 -0
  210. package/lib/module/calls/p2p/negotiator.js.map +1 -0
  211. package/lib/module/calls/p2p/p2pRuntime.js +137 -0
  212. package/lib/module/calls/p2p/p2pRuntime.js.map +1 -0
  213. package/lib/module/calls/p2p/signalInbox.js +93 -0
  214. package/lib/module/calls/p2p/signalInbox.js.map +1 -0
  215. package/lib/module/calls/p2p/signalStanza.js +135 -0
  216. package/lib/module/calls/p2p/signalStanza.js.map +1 -0
  217. package/lib/module/calls/p2p/webrtcRuntime.js +46 -0
  218. package/lib/module/calls/p2p/webrtcRuntime.js.map +1 -0
  219. package/lib/module/calls/senderTrust.js +38 -0
  220. package/lib/module/calls/senderTrust.js.map +1 -0
  221. package/lib/module/calls/startCall.js +47 -0
  222. package/lib/module/calls/startCall.js.map +1 -0
  223. package/lib/module/components/Booking/BookingIcons.js +48 -0
  224. package/lib/module/components/Booking/BookingIcons.js.map +1 -0
  225. package/lib/module/components/Booking/ScheduleCallButton.js +59 -0
  226. package/lib/module/components/Booking/ScheduleCallButton.js.map +1 -0
  227. package/lib/module/components/Booking/ScheduleCallSheet.js +345 -0
  228. package/lib/module/components/Booking/ScheduleCallSheet.js.map +1 -0
  229. package/lib/module/components/Booking/ScheduledCallCard.js +197 -0
  230. package/lib/module/components/Booking/ScheduledCallCard.js.map +1 -0
  231. package/lib/module/components/Booking/ScheduledCallHost.js +18 -0
  232. package/lib/module/components/Booking/ScheduledCallHost.js.map +1 -0
  233. package/lib/module/components/Booking/ScheduledCallMessage.js +48 -0
  234. package/lib/module/components/Booking/ScheduledCallMessage.js.map +1 -0
  235. package/lib/module/components/Booking/ScheduledCallPreJoin.js +229 -0
  236. package/lib/module/components/Booking/ScheduledCallPreJoin.js.map +1 -0
  237. package/lib/module/components/Booking/bookingShared.js +291 -0
  238. package/lib/module/components/Booking/bookingShared.js.map +1 -0
  239. package/lib/module/components/MainComponents/AlbumGrid.js +6 -2
  240. package/lib/module/components/MainComponents/AlbumGrid.js.map +1 -1
  241. package/lib/module/components/MainComponents/ChatHeader.js +20 -14
  242. package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
  243. package/lib/module/components/MainComponents/LanguageSelectorButton.js +5 -2
  244. package/lib/module/components/MainComponents/LanguageSelectorButton.js.map +1 -1
  245. package/lib/module/components/MainComponents/LanguageSelectorModal.js +7 -4
  246. package/lib/module/components/MainComponents/LanguageSelectorModal.js.map +1 -1
  247. package/lib/module/components/MainComponents/MediaMessage.js +13 -0
  248. package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
  249. package/lib/module/components/MainComponents/MessageContainer.js +13 -0
  250. package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
  251. package/lib/module/components/MainComponents/ReduxWrapper.js +10 -0
  252. package/lib/module/components/MainComponents/ReduxWrapper.js.map +1 -1
  253. package/lib/module/components/MainComponents/RoomList.js +7 -16
  254. package/lib/module/components/MainComponents/RoomList.js.map +1 -1
  255. package/lib/module/components/MessageBubble/Message.js +27 -1
  256. package/lib/module/components/MessageBubble/Message.js.map +1 -1
  257. package/lib/module/components/Modals/ChatProfileModal/ChatMediaGrid.js +154 -0
  258. package/lib/module/components/Modals/ChatProfileModal/ChatMediaGrid.js.map +1 -0
  259. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +204 -136
  260. package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
  261. package/lib/module/components/Modals/ChatProfileModal/LeaveChatModal.js +175 -0
  262. package/lib/module/components/Modals/ChatProfileModal/LeaveChatModal.js.map +1 -0
  263. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js +21 -15
  264. package/lib/module/components/Modals/ChatProfileModal/ReportChatModal.js.map +1 -1
  265. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +100 -163
  266. package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
  267. package/lib/module/components/Modals/FilePreviewModal/MediaViewer.js +819 -0
  268. package/lib/module/components/Modals/FilePreviewModal/MediaViewer.js.map +1 -0
  269. package/lib/module/components/Modals/FilePreviewModal/useSaveFile.js +172 -0
  270. package/lib/module/components/Modals/FilePreviewModal/useSaveFile.js.map +1 -0
  271. package/lib/module/components/Modals/MessageSearchModal/MessageSearchModal.js +20 -4
  272. package/lib/module/components/Modals/MessageSearchModal/MessageSearchModal.js.map +1 -1
  273. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +17 -10
  274. package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
  275. package/lib/module/components/Modals/UserSettingsModal/LanguageCard.js +1 -1
  276. package/lib/module/components/Modals/UserSettingsModal/LanguageCard.js.map +1 -1
  277. package/lib/module/components/VideoCalls/ActiveCallBar.js +3 -2
  278. package/lib/module/components/VideoCalls/ActiveCallBar.js.map +1 -1
  279. package/lib/module/components/VideoCalls/CallButtons.js +19 -11
  280. package/lib/module/components/VideoCalls/CallButtons.js.map +1 -1
  281. package/lib/module/components/VideoCalls/CallControlBar.js +113 -0
  282. package/lib/module/components/VideoCalls/CallControlBar.js.map +1 -0
  283. package/lib/module/components/VideoCalls/CallVideo.js +43 -0
  284. package/lib/module/components/VideoCalls/CallVideo.js.map +1 -0
  285. package/lib/module/components/VideoCalls/GroupCallView.js +275 -0
  286. package/lib/module/components/VideoCalls/GroupCallView.js.map +1 -0
  287. package/lib/module/components/VideoCalls/P2PCallRunner.js +147 -0
  288. package/lib/module/components/VideoCalls/P2PCallRunner.js.map +1 -0
  289. package/lib/module/components/VideoCalls/VideoCallOverlay.js +38 -14
  290. package/lib/module/components/VideoCalls/VideoCallOverlay.js.map +1 -1
  291. package/lib/module/components/VideoCalls/VideoCallSession.js +46 -127
  292. package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -1
  293. package/lib/module/components/VideoCalls/callActions.js +3 -0
  294. package/lib/module/components/VideoCalls/callActions.js.map +1 -1
  295. package/lib/module/components/VideoCalls/callElapsed.js +33 -0
  296. package/lib/module/components/VideoCalls/callElapsed.js.map +1 -0
  297. package/lib/module/components/VideoCalls/callLive.js +10 -0
  298. package/lib/module/components/VideoCalls/callLive.js.map +1 -0
  299. package/lib/module/components/VideoCalls/callSessionController.js +80 -24
  300. package/lib/module/components/VideoCalls/callSessionController.js.map +1 -1
  301. package/lib/module/components/VideoCalls/callSessionTypes.js +37 -0
  302. package/lib/module/components/VideoCalls/callSessionTypes.js.map +1 -0
  303. package/lib/module/components/VideoCalls/groupLayout.js +36 -0
  304. package/lib/module/components/VideoCalls/groupLayout.js.map +1 -0
  305. package/lib/module/components/VideoCalls/p2pCallSession.js +256 -0
  306. package/lib/module/components/VideoCalls/p2pCallSession.js.map +1 -0
  307. package/lib/module/components/VideoCalls/useCallKeep.js +8 -2
  308. package/lib/module/components/VideoCalls/useCallKeep.js.map +1 -1
  309. package/lib/module/components/VideoCalls/useOngoingCallNotification.js +2 -1
  310. package/lib/module/components/VideoCalls/useOngoingCallNotification.js.map +1 -1
  311. package/lib/module/components/styled/MessageImage.js +4 -1
  312. package/lib/module/components/styled/MessageImage.js.map +1 -1
  313. package/lib/module/components/styled/VideoMessage.js +5 -1
  314. package/lib/module/components/styled/VideoMessage.js.map +1 -1
  315. package/lib/module/context/MediaSourceContext.js +13 -0
  316. package/lib/module/context/MediaSourceContext.js.map +1 -0
  317. package/lib/module/context/xmppProvider.js +2 -1
  318. package/lib/module/context/xmppProvider.js.map +1 -1
  319. package/lib/module/helpers/callPush.js +3 -1
  320. package/lib/module/helpers/callPush.js.map +1 -1
  321. package/lib/module/helpers/constants/MODAL_COMPONENTS.js +2 -1
  322. package/lib/module/helpers/constants/MODAL_COMPONENTS.js.map +1 -1
  323. package/lib/module/helpers/constants/MODAL_TYPES.js +2 -0
  324. package/lib/module/helpers/constants/MODAL_TYPES.js.map +1 -1
  325. package/lib/module/helpers/incomingCallFromPush.js +63 -7
  326. package/lib/module/helpers/incomingCallFromPush.js.map +1 -1
  327. package/lib/module/helpers/publicChatsEntry.js +8 -6
  328. package/lib/module/helpers/publicChatsEntry.js.map +1 -1
  329. package/lib/module/helpers/pushPayload.js +5 -0
  330. package/lib/module/helpers/pushPayload.js.map +1 -1
  331. package/lib/module/helpers/reportRoom.js +70 -0
  332. package/lib/module/helpers/reportRoom.js.map +1 -0
  333. package/lib/module/helpers/roomMedia.js +112 -0
  334. package/lib/module/helpers/roomMedia.js.map +1 -0
  335. package/lib/module/i18n/strings.js +480 -0
  336. package/lib/module/i18n/strings.js.map +1 -1
  337. package/lib/module/main.js +5 -0
  338. package/lib/module/main.js.map +1 -1
  339. package/lib/module/networking/api-requests/callState.api.js +66 -0
  340. package/lib/module/networking/api-requests/callState.api.js.map +1 -0
  341. package/lib/module/networking/api-requests/push.api.js +29 -6
  342. package/lib/module/networking/api-requests/push.api.js.map +1 -1
  343. package/lib/module/networking/api-requests/rooms.api.js +17 -15
  344. package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
  345. package/lib/module/networking/api-requests/scheduledCalls.api.js +130 -0
  346. package/lib/module/networking/api-requests/scheduledCalls.api.js.map +1 -0
  347. package/lib/module/networking/callTokenStanza.js +210 -50
  348. package/lib/module/networking/callTokenStanza.js.map +1 -1
  349. package/lib/module/roomStore/callSlice.js +57 -3
  350. package/lib/module/roomStore/callSlice.js.map +1 -1
  351. package/lib/module/services/appBadge.js +74 -0
  352. package/lib/module/services/appBadge.js.map +1 -0
  353. package/lib/module/services/languageSettings.js +44 -13
  354. package/lib/module/services/languageSettings.js.map +1 -1
  355. package/lib/module/services/pushRegistration.js +21 -5
  356. package/lib/module/services/pushRegistration.js.map +1 -1
  357. package/lib/module/version.js +1 -1
  358. package/lib/module/version.js.map +1 -1
  359. package/lib/typescript/booking/index.d.ts +3 -0
  360. package/lib/typescript/booking/index.d.ts.map +1 -0
  361. package/lib/typescript/booking/pendingScheduledCall.d.ts +80 -0
  362. package/lib/typescript/booking/pendingScheduledCall.d.ts.map +1 -0
  363. package/lib/typescript/booking/scheduleForm.d.ts +28 -0
  364. package/lib/typescript/booking/scheduleForm.d.ts.map +1 -0
  365. package/lib/typescript/booking/scheduledCall.d.ts +52 -0
  366. package/lib/typescript/booking/scheduledCall.d.ts.map +1 -0
  367. package/lib/typescript/booking/scheduledCallActions.d.ts +22 -0
  368. package/lib/typescript/booking/scheduledCallActions.d.ts.map +1 -0
  369. package/lib/typescript/booking/scheduledCallLink.d.ts +37 -0
  370. package/lib/typescript/booking/scheduledCallLink.d.ts.map +1 -0
  371. package/lib/typescript/booking/scheduledCallStore.d.ts +47 -0
  372. package/lib/typescript/booking/scheduledCallStore.d.ts.map +1 -0
  373. package/lib/typescript/booking/startRoomCall.d.ts +12 -0
  374. package/lib/typescript/booking/startRoomCall.d.ts.map +1 -0
  375. package/lib/typescript/calls/callBusy.d.ts +9 -0
  376. package/lib/typescript/calls/callBusy.d.ts.map +1 -0
  377. package/lib/typescript/calls/callDisplay.d.ts +23 -0
  378. package/lib/typescript/calls/callDisplay.d.ts.map +1 -0
  379. package/lib/typescript/calls/callMode.d.ts +106 -0
  380. package/lib/typescript/calls/callMode.d.ts.map +1 -0
  381. package/lib/typescript/calls/declineReport.d.ts +11 -0
  382. package/lib/typescript/calls/declineReport.d.ts.map +1 -0
  383. package/lib/typescript/calls/p2p/P2PCallController.d.ts +150 -0
  384. package/lib/typescript/calls/p2p/P2PCallController.d.ts.map +1 -0
  385. package/lib/typescript/calls/p2p/icePolicy.d.ts +37 -0
  386. package/lib/typescript/calls/p2p/icePolicy.d.ts.map +1 -0
  387. package/lib/typescript/calls/p2p/negotiator.d.ts +57 -0
  388. package/lib/typescript/calls/p2p/negotiator.d.ts.map +1 -0
  389. package/lib/typescript/calls/p2p/p2pRuntime.d.ts +41 -0
  390. package/lib/typescript/calls/p2p/p2pRuntime.d.ts.map +1 -0
  391. package/lib/typescript/calls/p2p/signalInbox.d.ts +35 -0
  392. package/lib/typescript/calls/p2p/signalInbox.d.ts.map +1 -0
  393. package/lib/typescript/calls/p2p/signalStanza.d.ts +52 -0
  394. package/lib/typescript/calls/p2p/signalStanza.d.ts.map +1 -0
  395. package/lib/typescript/calls/p2p/webrtcRuntime.d.ts +32 -0
  396. package/lib/typescript/calls/p2p/webrtcRuntime.d.ts.map +1 -0
  397. package/lib/typescript/calls/senderTrust.d.ts +8 -0
  398. package/lib/typescript/calls/senderTrust.d.ts.map +1 -0
  399. package/lib/typescript/calls/startCall.d.ts +17 -0
  400. package/lib/typescript/calls/startCall.d.ts.map +1 -0
  401. package/lib/typescript/components/Booking/BookingIcons.d.ts +9 -0
  402. package/lib/typescript/components/Booking/BookingIcons.d.ts.map +1 -0
  403. package/lib/typescript/components/Booking/ScheduleCallButton.d.ts +11 -0
  404. package/lib/typescript/components/Booking/ScheduleCallButton.d.ts.map +1 -0
  405. package/lib/typescript/components/Booking/ScheduleCallSheet.d.ts +4 -0
  406. package/lib/typescript/components/Booking/ScheduleCallSheet.d.ts.map +1 -0
  407. package/lib/typescript/components/Booking/ScheduledCallCard.d.ts +14 -0
  408. package/lib/typescript/components/Booking/ScheduledCallCard.d.ts.map +1 -0
  409. package/lib/typescript/components/Booking/ScheduledCallHost.d.ts +10 -0
  410. package/lib/typescript/components/Booking/ScheduledCallHost.d.ts.map +1 -0
  411. package/lib/typescript/components/Booking/ScheduledCallMessage.d.ts +20 -0
  412. package/lib/typescript/components/Booking/ScheduledCallMessage.d.ts.map +1 -0
  413. package/lib/typescript/components/Booking/ScheduledCallPreJoin.d.ts +8 -0
  414. package/lib/typescript/components/Booking/ScheduledCallPreJoin.d.ts.map +1 -0
  415. package/lib/typescript/components/Booking/bookingShared.d.ts +199 -0
  416. package/lib/typescript/components/Booking/bookingShared.d.ts.map +1 -0
  417. package/lib/typescript/components/MainComponents/AlbumGrid.d.ts.map +1 -1
  418. package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
  419. package/lib/typescript/components/MainComponents/LanguageSelectorButton.d.ts +3 -1
  420. package/lib/typescript/components/MainComponents/LanguageSelectorButton.d.ts.map +1 -1
  421. package/lib/typescript/components/MainComponents/LanguageSelectorModal.d.ts.map +1 -1
  422. package/lib/typescript/components/MainComponents/MediaMessage.d.ts +3 -1
  423. package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
  424. package/lib/typescript/components/MainComponents/MessageContainer.d.ts.map +1 -1
  425. package/lib/typescript/components/MainComponents/ReduxWrapper.d.ts.map +1 -1
  426. package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
  427. package/lib/typescript/components/MessageBubble/Message.d.ts.map +1 -1
  428. package/lib/typescript/components/Modals/ChatProfileModal/ChatMediaGrid.d.ts +16 -0
  429. package/lib/typescript/components/Modals/ChatProfileModal/ChatMediaGrid.d.ts.map +1 -0
  430. package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
  431. package/lib/typescript/components/Modals/ChatProfileModal/LeaveChatModal.d.ts +18 -0
  432. package/lib/typescript/components/Modals/ChatProfileModal/LeaveChatModal.d.ts.map +1 -0
  433. package/lib/typescript/components/Modals/ChatProfileModal/ReportChatModal.d.ts.map +1 -1
  434. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts +16 -0
  435. package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
  436. package/lib/typescript/components/Modals/FilePreviewModal/MediaViewer.d.ts +27 -0
  437. package/lib/typescript/components/Modals/FilePreviewModal/MediaViewer.d.ts.map +1 -0
  438. package/lib/typescript/components/Modals/FilePreviewModal/useSaveFile.d.ts +9 -0
  439. package/lib/typescript/components/Modals/FilePreviewModal/useSaveFile.d.ts.map +1 -0
  440. package/lib/typescript/components/Modals/MessageSearchModal/MessageSearchModal.d.ts +8 -0
  441. package/lib/typescript/components/Modals/MessageSearchModal/MessageSearchModal.d.ts.map +1 -1
  442. package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
  443. package/lib/typescript/components/Modals/UserSettingsModal/LanguageCard.d.ts.map +1 -1
  444. package/lib/typescript/components/VideoCalls/ActiveCallBar.d.ts.map +1 -1
  445. package/lib/typescript/components/VideoCalls/CallButtons.d.ts +2 -1
  446. package/lib/typescript/components/VideoCalls/CallButtons.d.ts.map +1 -1
  447. package/lib/typescript/components/VideoCalls/CallControlBar.d.ts +17 -0
  448. package/lib/typescript/components/VideoCalls/CallControlBar.d.ts.map +1 -0
  449. package/lib/typescript/components/VideoCalls/CallVideo.d.ts +23 -0
  450. package/lib/typescript/components/VideoCalls/CallVideo.d.ts.map +1 -0
  451. package/lib/typescript/components/VideoCalls/GroupCallView.d.ts +22 -0
  452. package/lib/typescript/components/VideoCalls/GroupCallView.d.ts.map +1 -0
  453. package/lib/typescript/components/VideoCalls/P2PCallRunner.d.ts +2 -0
  454. package/lib/typescript/components/VideoCalls/P2PCallRunner.d.ts.map +1 -0
  455. package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts.map +1 -1
  456. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts +10 -12
  457. package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -1
  458. package/lib/typescript/components/VideoCalls/callActions.d.ts.map +1 -1
  459. package/lib/typescript/components/VideoCalls/callElapsed.d.ts +8 -0
  460. package/lib/typescript/components/VideoCalls/callElapsed.d.ts.map +1 -0
  461. package/lib/typescript/components/VideoCalls/callLive.d.ts +9 -0
  462. package/lib/typescript/components/VideoCalls/callLive.d.ts.map +1 -0
  463. package/lib/typescript/components/VideoCalls/callSessionController.d.ts +10 -31
  464. package/lib/typescript/components/VideoCalls/callSessionController.d.ts.map +1 -1
  465. package/lib/typescript/components/VideoCalls/callSessionTypes.d.ts +60 -0
  466. package/lib/typescript/components/VideoCalls/callSessionTypes.d.ts.map +1 -0
  467. package/lib/typescript/components/VideoCalls/groupLayout.d.ts +23 -0
  468. package/lib/typescript/components/VideoCalls/groupLayout.d.ts.map +1 -0
  469. package/lib/typescript/components/VideoCalls/p2pCallSession.d.ts +31 -0
  470. package/lib/typescript/components/VideoCalls/p2pCallSession.d.ts.map +1 -0
  471. package/lib/typescript/components/VideoCalls/useCallKeep.d.ts.map +1 -1
  472. package/lib/typescript/components/VideoCalls/useOngoingCallNotification.d.ts.map +1 -1
  473. package/lib/typescript/components/styled/MessageImage.d.ts.map +1 -1
  474. package/lib/typescript/components/styled/VideoMessage.d.ts.map +1 -1
  475. package/lib/typescript/context/MediaSourceContext.d.ts +4 -0
  476. package/lib/typescript/context/MediaSourceContext.d.ts.map +1 -0
  477. package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
  478. package/lib/typescript/helpers/callPush.d.ts +11 -1
  479. package/lib/typescript/helpers/callPush.d.ts.map +1 -1
  480. package/lib/typescript/helpers/constants/MODAL_COMPONENTS.d.ts.map +1 -1
  481. package/lib/typescript/helpers/constants/MODAL_TYPES.d.ts +2 -0
  482. package/lib/typescript/helpers/constants/MODAL_TYPES.d.ts.map +1 -1
  483. package/lib/typescript/helpers/incomingCallFromPush.d.ts.map +1 -1
  484. package/lib/typescript/helpers/publicChatsEntry.d.ts +7 -5
  485. package/lib/typescript/helpers/publicChatsEntry.d.ts.map +1 -1
  486. package/lib/typescript/helpers/pushPayload.d.ts +1 -1
  487. package/lib/typescript/helpers/pushPayload.d.ts.map +1 -1
  488. package/lib/typescript/helpers/reportRoom.d.ts +19 -0
  489. package/lib/typescript/helpers/reportRoom.d.ts.map +1 -0
  490. package/lib/typescript/helpers/roomMedia.d.ts +26 -0
  491. package/lib/typescript/helpers/roomMedia.d.ts.map +1 -0
  492. package/lib/typescript/i18n/strings.d.ts.map +1 -1
  493. package/lib/typescript/main.d.ts +6 -1
  494. package/lib/typescript/main.d.ts.map +1 -1
  495. package/lib/typescript/networking/api-requests/callState.api.d.ts +25 -0
  496. package/lib/typescript/networking/api-requests/callState.api.d.ts.map +1 -0
  497. package/lib/typescript/networking/api-requests/push.api.d.ts +9 -2
  498. package/lib/typescript/networking/api-requests/push.api.d.ts.map +1 -1
  499. package/lib/typescript/networking/api-requests/rooms.api.d.ts +8 -6
  500. package/lib/typescript/networking/api-requests/rooms.api.d.ts.map +1 -1
  501. package/lib/typescript/networking/api-requests/scheduledCalls.api.d.ts +86 -0
  502. package/lib/typescript/networking/api-requests/scheduledCalls.api.d.ts.map +1 -0
  503. package/lib/typescript/networking/callTokenStanza.d.ts.map +1 -1
  504. package/lib/typescript/roomStore/callSlice.d.ts +23 -1
  505. package/lib/typescript/roomStore/callSlice.d.ts.map +1 -1
  506. package/lib/typescript/services/appBadge.d.ts +3 -0
  507. package/lib/typescript/services/appBadge.d.ts.map +1 -0
  508. package/lib/typescript/services/languageSettings.d.ts +7 -0
  509. package/lib/typescript/services/languageSettings.d.ts.map +1 -1
  510. package/lib/typescript/services/pushRegistration.d.ts.map +1 -1
  511. package/lib/typescript/types/models/modal.model.d.ts +18 -0
  512. package/lib/typescript/types/models/modal.model.d.ts.map +1 -1
  513. package/lib/typescript/types/types.d.ts +85 -4
  514. package/lib/typescript/types/types.d.ts.map +1 -1
  515. package/lib/typescript/version.d.ts +1 -1
  516. package/lib/typescript/version.d.ts.map +1 -1
  517. package/package.json +9 -2
  518. package/src/booking/index.ts +10 -0
  519. package/src/booking/pendingScheduledCall.ts +272 -0
  520. package/src/booking/scheduleForm.ts +84 -0
  521. package/src/booking/scheduledCall.ts +163 -0
  522. package/src/booking/scheduledCallActions.ts +141 -0
  523. package/src/booking/scheduledCallLink.ts +145 -0
  524. package/src/booking/scheduledCallStore.ts +69 -0
  525. package/src/booking/startRoomCall.ts +103 -0
  526. package/src/calls/callBusy.ts +10 -0
  527. package/src/calls/callDisplay.ts +74 -0
  528. package/src/calls/callMode.ts +286 -0
  529. package/src/calls/declineReport.ts +16 -0
  530. package/src/calls/p2p/P2PCallController.ts +813 -0
  531. package/src/calls/p2p/icePolicy.ts +99 -0
  532. package/src/calls/p2p/negotiator.ts +186 -0
  533. package/src/calls/p2p/p2pRuntime.ts +164 -0
  534. package/src/calls/p2p/signalInbox.ts +117 -0
  535. package/src/calls/p2p/signalStanza.ts +205 -0
  536. package/src/calls/p2p/webrtcRuntime.ts +60 -0
  537. package/src/calls/senderTrust.ts +40 -0
  538. package/src/calls/startCall.ts +56 -0
  539. package/src/components/Booking/BookingIcons.tsx +44 -0
  540. package/src/components/Booking/ScheduleCallButton.tsx +66 -0
  541. package/src/components/Booking/ScheduleCallSheet.tsx +380 -0
  542. package/src/components/Booking/ScheduledCallCard.tsx +216 -0
  543. package/src/components/Booking/ScheduledCallHost.tsx +18 -0
  544. package/src/components/Booking/ScheduledCallMessage.tsx +62 -0
  545. package/src/components/Booking/ScheduledCallPreJoin.tsx +230 -0
  546. package/src/components/Booking/bookingShared.tsx +295 -0
  547. package/src/components/MainComponents/AlbumGrid.tsx +5 -1
  548. package/src/components/MainComponents/ChatHeader.tsx +18 -11
  549. package/src/components/MainComponents/LanguageSelectorButton.tsx +9 -2
  550. package/src/components/MainComponents/LanguageSelectorModal.tsx +10 -6
  551. package/src/components/MainComponents/MediaMessage.tsx +13 -2
  552. package/src/components/MainComponents/MessageContainer.tsx +15 -0
  553. package/src/components/MainComponents/ReduxWrapper.tsx +10 -0
  554. package/src/components/MainComponents/RoomList.tsx +8 -19
  555. package/src/components/MessageBubble/Message.tsx +24 -1
  556. package/src/components/Modals/ChatProfileModal/ChatMediaGrid.tsx +174 -0
  557. package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +119 -48
  558. package/src/components/Modals/ChatProfileModal/LeaveChatModal.tsx +191 -0
  559. package/src/components/Modals/ChatProfileModal/ReportChatModal.tsx +22 -22
  560. package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +115 -185
  561. package/src/components/Modals/FilePreviewModal/MediaViewer.tsx +880 -0
  562. package/src/components/Modals/FilePreviewModal/useSaveFile.ts +207 -0
  563. package/src/components/Modals/MessageSearchModal/MessageSearchModal.tsx +56 -30
  564. package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +28 -9
  565. package/src/components/Modals/UserSettingsModal/LanguageCard.tsx +9 -7
  566. package/src/components/VideoCalls/ActiveCallBar.tsx +6 -5
  567. package/src/components/VideoCalls/CallButtons.tsx +23 -12
  568. package/src/components/VideoCalls/CallControlBar.tsx +131 -0
  569. package/src/components/VideoCalls/CallVideo.tsx +59 -0
  570. package/src/components/VideoCalls/GroupCallView.tsx +324 -0
  571. package/src/components/VideoCalls/P2PCallRunner.tsx +192 -0
  572. package/src/components/VideoCalls/VideoCallOverlay.tsx +62 -17
  573. package/src/components/VideoCalls/VideoCallSession.tsx +55 -133
  574. package/src/components/VideoCalls/callActions.ts +3 -0
  575. package/src/components/VideoCalls/callElapsed.ts +27 -0
  576. package/src/components/VideoCalls/callLive.ts +13 -0
  577. package/src/components/VideoCalls/callSessionController.ts +130 -55
  578. package/src/components/VideoCalls/callSessionTypes.ts +80 -0
  579. package/src/components/VideoCalls/groupLayout.ts +48 -0
  580. package/src/components/VideoCalls/p2pCallSession.ts +291 -0
  581. package/src/components/VideoCalls/useCallKeep.ts +9 -2
  582. package/src/components/VideoCalls/useOngoingCallNotification.ts +2 -2
  583. package/src/components/styled/MessageImage.tsx +3 -1
  584. package/src/components/styled/VideoMessage.tsx +5 -1
  585. package/src/context/MediaSourceContext.tsx +14 -0
  586. package/src/context/xmppProvider.tsx +3 -0
  587. package/src/helpers/callPush.ts +13 -1
  588. package/src/helpers/constants/MODAL_COMPONENTS.tsx +4 -1
  589. package/src/helpers/constants/MODAL_TYPES.ts +2 -0
  590. package/src/helpers/incomingCallFromPush.ts +65 -7
  591. package/src/helpers/publicChatsEntry.ts +8 -7
  592. package/src/helpers/pushPayload.ts +9 -1
  593. package/src/helpers/reportRoom.ts +93 -0
  594. package/src/helpers/roomMedia.ts +126 -0
  595. package/src/i18n/strings.ts +480 -0
  596. package/src/main.ts +33 -0
  597. package/src/networking/api-requests/callState.api.ts +83 -0
  598. package/src/networking/api-requests/push.api.ts +28 -3
  599. package/src/networking/api-requests/rooms.api.ts +25 -15
  600. package/src/networking/api-requests/scheduledCalls.api.ts +232 -0
  601. package/src/networking/callTokenStanza.ts +247 -50
  602. package/src/roomStore/callSlice.ts +86 -2
  603. package/src/services/appBadge.ts +85 -0
  604. package/src/services/languageSettings.ts +43 -8
  605. package/src/services/pushRegistration.ts +34 -3
  606. package/src/types/models/modal.model.ts +16 -0
  607. package/src/types/types.ts +86 -4
  608. package/src/version.ts +1 -1
@@ -0,0 +1,880 @@
1
+ /** @format */
2
+
3
+ import React, {
4
+ useCallback,
5
+ useEffect,
6
+ useMemo,
7
+ useRef,
8
+ useState,
9
+ } from 'react';
10
+ import {
11
+ ActivityIndicator,
12
+ Animated,
13
+ BackHandler,
14
+ Image,
15
+ LayoutChangeEvent,
16
+ Pressable,
17
+ StatusBar,
18
+ StyleSheet,
19
+ Text,
20
+ TouchableOpacity,
21
+ useWindowDimensions,
22
+ View,
23
+ } from 'react-native';
24
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
25
+ import {
26
+ Gesture,
27
+ GestureDetector,
28
+ type GestureType,
29
+ } from 'react-native-gesture-handler';
30
+ import { useVideoPlayer, VideoView } from 'expo-video';
31
+ import { useDispatch } from 'react-redux';
32
+ import type { ModalFile } from '../../../types/types';
33
+ import {
34
+ BackIcon,
35
+ DeleteIcon,
36
+ PauseIcon,
37
+ PlayIcon,
38
+ ReplyIcon,
39
+ SaveIcon,
40
+ } from '../../../assets/icons';
41
+ import { withFileToken } from '../../../helpers/secureFileUrl';
42
+ import {
43
+ downloadVideoToCache,
44
+ findCachedVideo,
45
+ isRemoteUrl,
46
+ isStreamingUnsupported,
47
+ markStreamingUnsupported,
48
+ } from '../../../helpers/videoCache';
49
+ import { setDeleteModal } from '../../../roomStore/chatSettingsSlice';
50
+ import { setActiveMessage, setEditAction } from '../../../roomStore/roomsSlice';
51
+ import { useT, useUiLocale } from '../../../i18n/useT';
52
+
53
+ const WHITE = '#FFFFFF';
54
+ const BAR_BACKGROUND = 'rgba(0, 0, 0, 0.45)';
55
+ /** Drag (fraction of the height) or fling speed that closes the viewer. */
56
+ const CLOSE_DISTANCE = 0.15;
57
+ const CLOSE_VELOCITY = 900;
58
+ /** Swipe (fraction of the width) or fling speed that turns the page. */
59
+ const PAGE_DISTANCE = 0.25;
60
+ const PAGE_VELOCITY = 700;
61
+ /** A playing video takes the chrome away after this long without a touch. */
62
+ const AUTO_HIDE_MS = 3000;
63
+
64
+ const formatTime = (seconds: number) => {
65
+ const total = Math.max(0, Math.floor(seconds || 0));
66
+ const m = Math.floor(total / 60);
67
+ const s = total % 60;
68
+ return `${m}:${s < 10 ? '0' : ''}${s}`;
69
+ };
70
+
71
+ interface MediaViewerProps {
72
+ /** A picture or a video. */
73
+ file: ModalFile;
74
+ /** Called once the viewer has animated out. */
75
+ onClose: () => void;
76
+ /** Turn to another file of the album (an index into `file.siblings`). */
77
+ onPage?: (index: number) => void;
78
+ onSave: () => void;
79
+ /** After Reply opened the thread, for a host that has more to close. */
80
+ onReplyOpened?: () => void;
81
+ }
82
+
83
+ /**
84
+ * Full-screen photo / video viewer that behaves like Telegram's. A tap shows
85
+ * or hides everything but the media (a fade both ways); a drag up or down
86
+ * pulls the media off with the backdrop fading behind it, and a long enough
87
+ * drag or a fling closes the viewer; a sideways swipe turns the page in an
88
+ * album. The bottom bar carries Reply (where replies are on) and Delete (on
89
+ * one's own message). A video has its own controls in the chrome: tapping
90
+ * them works the player instead of hiding the chrome, and while it plays the
91
+ * chrome goes away by itself after a few seconds.
92
+ */
93
+ const MediaViewer: React.FC<MediaViewerProps> = ({
94
+ file,
95
+ onClose,
96
+ onPage,
97
+ onSave,
98
+ onReplyOpened,
99
+ }) => {
100
+ const t = useT();
101
+ const locale = useUiLocale();
102
+ const dispatch = useDispatch();
103
+ const insets = useSafeAreaInsets();
104
+ const { width, height } = useWindowDimensions();
105
+
106
+ const appear = useRef(new Animated.Value(0)).current;
107
+ const dragX = useRef(new Animated.Value(0)).current;
108
+ const dragY = useRef(new Animated.Value(0)).current;
109
+ const chrome = useRef(new Animated.Value(1)).current;
110
+ const [chromeVisible, setChromeVisible] = useState(true);
111
+ const [bottomBarHeight, setBottomBarHeight] = useState(0);
112
+
113
+ const closing = useRef(false);
114
+ const axis = useRef<'x' | 'y' | null>(null);
115
+ const pendingSlide = useRef<number>(0);
116
+ const playing = useRef(false);
117
+ const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
118
+
119
+ const siblings = file.siblings ?? [];
120
+ const index = file.index ?? 0;
121
+ const hasPrev = siblings.length > 1 && index > 0;
122
+ const hasNext = siblings.length > 1 && index < siblings.length - 1;
123
+ const isVideo = (file.mimetype || '').startsWith('video/');
124
+ const source = file.source;
125
+ const canReply = !!source?.replyTo;
126
+ const canDelete = !!source?.own;
127
+
128
+ useEffect(() => {
129
+ Animated.timing(appear, {
130
+ toValue: 1,
131
+ duration: 220,
132
+ useNativeDriver: true,
133
+ }).start();
134
+ }, [appear]);
135
+
136
+ // ---- chrome ------------------------------------------------------------
137
+
138
+ const cancelAutoHide = useCallback(() => {
139
+ if (hideTimer.current) {clearTimeout(hideTimer.current);}
140
+ hideTimer.current = null;
141
+ }, []);
142
+
143
+ const showChrome = useCallback(
144
+ (visible: boolean) => {
145
+ setChromeVisible(visible);
146
+ Animated.timing(chrome, {
147
+ toValue: visible ? 1 : 0,
148
+ duration: 180,
149
+ useNativeDriver: true,
150
+ }).start();
151
+ },
152
+ [chrome]
153
+ );
154
+
155
+ const scheduleAutoHide = useCallback(() => {
156
+ cancelAutoHide();
157
+ if (!playing.current) {return;}
158
+ hideTimer.current = setTimeout(() => showChrome(false), AUTO_HIDE_MS);
159
+ }, [cancelAutoHide, showChrome]);
160
+
161
+ useEffect(() => cancelAutoHide, [cancelAutoHide]);
162
+
163
+ const toggleChrome = () => {
164
+ const next = !chromeVisible;
165
+ showChrome(next);
166
+ if (next) {scheduleAutoHide();} else {cancelAutoHide();}
167
+ };
168
+
169
+ const handlePlayback = useCallback(
170
+ (isPlaying: boolean) => {
171
+ playing.current = isPlaying;
172
+ if (isPlaying) {scheduleAutoHide();} else {cancelAutoHide();}
173
+ },
174
+ [cancelAutoHide, scheduleAutoHide]
175
+ );
176
+
177
+ // ---- close / page --------------------------------------------------------
178
+
179
+ const close = useCallback(
180
+ (direction = 0) => {
181
+ if (closing.current) {return;}
182
+ closing.current = true;
183
+ cancelAutoHide();
184
+ const animations = [
185
+ Animated.timing(appear, { toValue: 0, duration: 200, useNativeDriver: true }),
186
+ ];
187
+ if (direction !== 0) {
188
+ animations.push(
189
+ Animated.timing(dragY, {
190
+ toValue: direction * height,
191
+ duration: 200,
192
+ useNativeDriver: true,
193
+ })
194
+ );
195
+ }
196
+ Animated.parallel(animations).start(() => onClose());
197
+ },
198
+ [appear, cancelAutoHide, dragY, height, onClose]
199
+ );
200
+
201
+ useEffect(() => {
202
+ const sub = BackHandler.addEventListener('hardwareBackPress', () => {
203
+ close();
204
+ return true;
205
+ });
206
+ return () => sub.remove();
207
+ }, [close]);
208
+
209
+ const springBack = (value: Animated.Value) =>
210
+ Animated.spring(value, {
211
+ toValue: 0,
212
+ useNativeDriver: true,
213
+ bounciness: 4,
214
+ }).start();
215
+
216
+ const turnPage = useCallback(
217
+ (direction: 1 | -1) => {
218
+ Animated.timing(dragX, {
219
+ toValue: -direction * width,
220
+ duration: 160,
221
+ useNativeDriver: true,
222
+ }).start(() => {
223
+ pendingSlide.current = direction;
224
+ onPage?.(index + direction);
225
+ });
226
+ },
227
+ [dragX, index, onPage, width]
228
+ );
229
+
230
+ // The new file mounts off-screen on the side it comes from, then slides in.
231
+ useEffect(() => {
232
+ const direction = pendingSlide.current;
233
+ if (!direction) {return;}
234
+ pendingSlide.current = 0;
235
+ playing.current = false;
236
+ dragX.setValue(direction * width);
237
+ Animated.timing(dragX, {
238
+ toValue: 0,
239
+ duration: 180,
240
+ useNativeDriver: true,
241
+ }).start();
242
+ }, [dragX, file.fileURL, width]);
243
+
244
+ // ---- gestures ------------------------------------------------------------
245
+
246
+ const latest = useRef({ hasPrev, hasNext, width, height, close, turnPage });
247
+ latest.current = { hasPrev, hasNext, width, height, close, turnPage };
248
+ const pageable = siblings.length > 1;
249
+
250
+ const pan = useMemo(
251
+ () =>
252
+ Gesture.Pan()
253
+ .runOnJS(true)
254
+ .activeOffsetY([-12, 12])
255
+ .activeOffsetX(pageable ? [-12, 12] : [-10000, 10000])
256
+ .onStart((e) => {
257
+ axis.current =
258
+ pageable && Math.abs(e.translationX) > Math.abs(e.translationY)
259
+ ? 'x'
260
+ : 'y';
261
+ })
262
+ .onUpdate((e) => {
263
+ const l = latest.current;
264
+ if (axis.current === 'x') {
265
+ // Past the first or last file the page only gives a little.
266
+ const edge =
267
+ (e.translationX > 0 && !l.hasPrev) || (e.translationX < 0 && !l.hasNext);
268
+ dragX.setValue(edge ? e.translationX * 0.3 : e.translationX);
269
+ } else {
270
+ dragY.setValue(e.translationY);
271
+ }
272
+ })
273
+ .onEnd((e) => {
274
+ const l = latest.current;
275
+ if (axis.current === 'x') {
276
+ if ((e.translationX < -l.width * PAGE_DISTANCE || e.velocityX < -PAGE_VELOCITY) && l.hasNext) {
277
+ l.turnPage(1);
278
+ } else if ((e.translationX > l.width * PAGE_DISTANCE || e.velocityX > PAGE_VELOCITY) && l.hasPrev) {
279
+ l.turnPage(-1);
280
+ } else {
281
+ springBack(dragX);
282
+ }
283
+ } else if (
284
+ Math.abs(e.translationY) > l.height * CLOSE_DISTANCE ||
285
+ Math.abs(e.velocityY) > CLOSE_VELOCITY
286
+ ) {
287
+ l.close(Math.sign(e.translationY || e.velocityY) || 1);
288
+ } else {
289
+ springBack(dragY);
290
+ }
291
+ axis.current = null;
292
+ }),
293
+ // eslint-disable-next-line react-hooks/exhaustive-deps
294
+ [pageable]
295
+ );
296
+
297
+ // ---- actions -------------------------------------------------------------
298
+
299
+ const handleReply = () => {
300
+ if (!source?.replyTo) {return;}
301
+ const target = source.replyTo;
302
+ close();
303
+ dispatch(setEditAction({ isEdit: false }));
304
+ dispatch(setActiveMessage({ id: target.id, chatJID: target.chatJID }));
305
+ onReplyOpened?.();
306
+ };
307
+
308
+ const handleDelete = () => {
309
+ if (!source?.own) {return;}
310
+ const { roomJid, messageId } = source;
311
+ close();
312
+ dispatch(setDeleteModal({ isDeleteModal: true, roomJid, messageId }));
313
+ };
314
+
315
+ // ---- styles from the animated values -------------------------------------
316
+
317
+ const dragFade = dragY.interpolate({
318
+ inputRange: [-height / 2, 0, height / 2],
319
+ outputRange: [0.15, 1, 0.15],
320
+ extrapolate: 'clamp',
321
+ });
322
+ const dragShrink = dragY.interpolate({
323
+ inputRange: [-height, 0, height],
324
+ outputRange: [0.85, 1, 0.85],
325
+ extrapolate: 'clamp',
326
+ });
327
+ const backdropOpacity = Animated.multiply(appear, dragFade);
328
+ const mediaStyle = {
329
+ transform: [
330
+ { translateX: dragX },
331
+ { translateY: dragY },
332
+ {
333
+ scale: Animated.multiply(
334
+ appear.interpolate({ inputRange: [0, 1], outputRange: [0.92, 1] }),
335
+ dragShrink
336
+ ),
337
+ },
338
+ ],
339
+ opacity: appear,
340
+ };
341
+ // The chrome steps aside while the media is being dragged.
342
+ const chromeOpacity = Animated.multiply(
343
+ Animated.multiply(chrome, appear),
344
+ dragY.interpolate({
345
+ inputRange: [-60, 0, 60],
346
+ outputRange: [0, 1, 0],
347
+ extrapolate: 'clamp',
348
+ })
349
+ );
350
+ const chromePointerEvents = chromeVisible ? 'box-none' : 'none';
351
+
352
+ const subtitle = [
353
+ source?.timestamp
354
+ ? new Date(source.timestamp).toLocaleString(locale, {
355
+ day: 'numeric',
356
+ month: 'short',
357
+ hour: '2-digit',
358
+ minute: '2-digit',
359
+ })
360
+ : null,
361
+ siblings.length > 1
362
+ ? t('attachment.position', { index: index + 1, total: siblings.length })
363
+ : null,
364
+ ]
365
+ .filter(Boolean)
366
+ .join(' · ');
367
+
368
+ const showBottomBar = canReply || canDelete;
369
+
370
+ return (
371
+ <View style={StyleSheet.absoluteFill} testID="media-viewer">
372
+ {/* Light text on the black backdrop; it leaves with the chrome. The
373
+ previous bar style comes back when the viewer unmounts. */}
374
+ <StatusBar barStyle="light-content" hidden={!chromeVisible} animated />
375
+ <Animated.View
376
+ style={[StyleSheet.absoluteFill, styles.backdrop, { opacity: backdropOpacity }]}
377
+ />
378
+ <GestureDetector gesture={pan}>
379
+ <View style={StyleSheet.absoluteFill}>
380
+ <Pressable
381
+ testID="media-viewer-surface"
382
+ style={StyleSheet.absoluteFill}
383
+ onPress={toggleChrome}
384
+ >
385
+ <Animated.View style={[StyleSheet.absoluteFill, mediaStyle]} pointerEvents="none">
386
+ {isVideo ? null : <ViewerImage key={file.fileURL} uri={file.fileURL} />}
387
+ </Animated.View>
388
+ </Pressable>
389
+
390
+ {isVideo && (
391
+ <ViewerVideo
392
+ key={file.fileURL}
393
+ uri={withFileToken(file.fileURL)}
394
+ mimetype={file.mimetype}
395
+ mediaStyle={mediaStyle}
396
+ chromeOpacity={chromeOpacity}
397
+ chromePointerEvents={chromePointerEvents}
398
+ bottomOffset={(showBottomBar ? bottomBarHeight : insets.bottom) + 8}
399
+ outerGesture={pan}
400
+ onPlayback={handlePlayback}
401
+ onActivity={scheduleAutoHide}
402
+ />
403
+ )}
404
+
405
+ <Animated.View
406
+ pointerEvents={chromePointerEvents}
407
+ style={[styles.topBar, { paddingTop: insets.top + 6, opacity: chromeOpacity }]}
408
+ >
409
+ <TouchableOpacity
410
+ testID="media-viewer-back"
411
+ accessibilityRole="button"
412
+ accessibilityLabel={t('action.close')}
413
+ hitSlop={12}
414
+ style={styles.iconButton}
415
+ onPress={() => close()}
416
+ >
417
+ <BackIcon color={WHITE} />
418
+ </TouchableOpacity>
419
+ <View style={styles.titleBlock}>
420
+ <Text numberOfLines={1} style={styles.title}>
421
+ {source?.senderName || t('modal.filePreview.title')}
422
+ </Text>
423
+ {!!subtitle && (
424
+ <Text numberOfLines={1} style={styles.subtitle}>
425
+ {subtitle}
426
+ </Text>
427
+ )}
428
+ </View>
429
+ <TouchableOpacity
430
+ testID="media-viewer-save"
431
+ accessibilityRole="button"
432
+ accessibilityLabel={t('action.save')}
433
+ hitSlop={12}
434
+ style={styles.iconButton}
435
+ onPress={onSave}
436
+ >
437
+ <SaveIcon color={WHITE} />
438
+ </TouchableOpacity>
439
+ </Animated.View>
440
+
441
+ {showBottomBar && (
442
+ <Animated.View
443
+ pointerEvents={chromePointerEvents}
444
+ onLayout={(e: LayoutChangeEvent) =>
445
+ setBottomBarHeight(e.nativeEvent.layout.height)
446
+ }
447
+ style={[
448
+ styles.bottomBar,
449
+ { paddingBottom: insets.bottom + 8, opacity: chromeOpacity },
450
+ ]}
451
+ >
452
+ {canReply ? (
453
+ <TouchableOpacity
454
+ testID="media-viewer-reply"
455
+ accessibilityRole="button"
456
+ accessibilityLabel={t('action.reply')}
457
+ hitSlop={12}
458
+ style={styles.iconButton}
459
+ onPress={handleReply}
460
+ >
461
+ <ReplyIcon color={WHITE} />
462
+ </TouchableOpacity>
463
+ ) : (
464
+ <View style={styles.iconButton} />
465
+ )}
466
+ {canDelete && (
467
+ <TouchableOpacity
468
+ testID="media-viewer-delete"
469
+ accessibilityRole="button"
470
+ accessibilityLabel={t('action.delete')}
471
+ hitSlop={12}
472
+ style={styles.iconButton}
473
+ onPress={handleDelete}
474
+ >
475
+ <DeleteIcon fill={WHITE} />
476
+ </TouchableOpacity>
477
+ )}
478
+ </Animated.View>
479
+ )}
480
+ </View>
481
+ </GestureDetector>
482
+ </View>
483
+ );
484
+ };
485
+
486
+ const ViewerImage: React.FC<{ uri: string }> = ({ uri }) => {
487
+ const [loaded, setLoaded] = useState(false);
488
+ return (
489
+ <>
490
+ <Image
491
+ source={{ uri: withFileToken(uri) }}
492
+ style={StyleSheet.absoluteFill}
493
+ resizeMode="contain"
494
+ onLoad={() => setLoaded(true)}
495
+ onError={() => setLoaded(true)}
496
+ />
497
+ {!loaded && (
498
+ <View style={styles.center}>
499
+ <ActivityIndicator color={WHITE} />
500
+ </View>
501
+ )}
502
+ </>
503
+ );
504
+ };
505
+
506
+ interface ViewerVideoProps {
507
+ uri: string;
508
+ mimetype?: string;
509
+ mediaStyle: any;
510
+ chromeOpacity: Animated.AnimatedInterpolation<number> | Animated.AnimatedMultiplication<number>;
511
+ chromePointerEvents: 'box-none' | 'none';
512
+ /** Distance of the scrubber from the bottom edge (above the action bar). */
513
+ bottomOffset: number;
514
+ /** The viewer's pan, which waits for the scrubber's own drag to fail. */
515
+ outerGesture: GestureType;
516
+ onPlayback: (playing: boolean) => void;
517
+ /** Any touch on the controls: restarts the chrome's auto-hide. */
518
+ onActivity: () => void;
519
+ }
520
+
521
+ /**
522
+ * The video page: the surface in the media layer, the play / pause button
523
+ * and the scrubber in the chrome layer. Streams when the server allows it
524
+ * and falls back to a downloaded copy (AVPlayer refuses servers that ignore
525
+ * byte ranges), which is also what a reopened video plays from.
526
+ */
527
+ const ViewerVideo: React.FC<ViewerVideoProps> = ({
528
+ uri,
529
+ mimetype,
530
+ mediaStyle,
531
+ chromeOpacity,
532
+ chromePointerEvents,
533
+ bottomOffset,
534
+ outerGesture,
535
+ onPlayback,
536
+ onActivity,
537
+ }) => {
538
+ const t = useT();
539
+ const remote = isRemoteUrl(uri);
540
+ // What the player is given; null until we know where to play from.
541
+ const [source, setSource] = useState<string | null>(remote ? null : uri);
542
+ // null = not downloading, otherwise 0..1 (0 while the size is unknown).
543
+ const [progress, setProgress] = useState<number | null>(null);
544
+ const [failed, setFailed] = useState(false);
545
+ const [isPlaying, setIsPlaying] = useState(false);
546
+ const [time, setTime] = useState(0);
547
+ const [duration, setDuration] = useState(0);
548
+ const [scrubTime, setScrubTime] = useState<number | null>(null);
549
+ const [trackWidth, setTrackWidth] = useState(0);
550
+ const ended = useRef(false);
551
+ // Opens playing, like Telegram; a pause sticks across a fallback copy.
552
+ const wantsPlay = useRef(true);
553
+ const downloadStarted = useRef(false);
554
+ const mounted = useRef(true);
555
+ useEffect(
556
+ () => () => {
557
+ mounted.current = false;
558
+ },
559
+ []
560
+ );
561
+
562
+ const download = useCallback(() => {
563
+ if (downloadStarted.current) {return;}
564
+ downloadStarted.current = true;
565
+ setProgress(0);
566
+ downloadVideoToCache(uri, mimetype, (fraction) => {
567
+ if (mounted.current) {setProgress(fraction);}
568
+ })
569
+ .then((localUri) => {
570
+ if (!mounted.current) {return;}
571
+ setProgress(null);
572
+ setSource(localUri);
573
+ })
574
+ .catch((err) => {
575
+ console.warn('video download failed', err);
576
+ if (!mounted.current) {return;}
577
+ setProgress(null);
578
+ setFailed(true);
579
+ });
580
+ }, [mimetype, uri]);
581
+
582
+ useEffect(() => {
583
+ if (!remote) {return;}
584
+ let active = true;
585
+ findCachedVideo(uri, mimetype).then((cached) => {
586
+ if (!active) {return;}
587
+ if (cached) {
588
+ setSource(cached);
589
+ } else if (isStreamingUnsupported(uri)) {
590
+ download();
591
+ } else {
592
+ setSource(uri);
593
+ }
594
+ });
595
+ return () => {
596
+ active = false;
597
+ };
598
+ }, [download, mimetype, remote, uri]);
599
+
600
+ const player = useVideoPlayer(source, (p) => {
601
+ p.muted = false;
602
+ p.timeUpdateEventInterval = 0.25;
603
+ if (wantsPlay.current) {p.play();}
604
+ });
605
+
606
+ useEffect(() => {
607
+ const subs = [
608
+ player.addListener('playingChange', ({ isPlaying: next }) => {
609
+ setIsPlaying(next);
610
+ onPlayback(next);
611
+ }),
612
+ player.addListener('timeUpdate', ({ currentTime }) => setTime(currentTime)),
613
+ player.addListener('playToEnd', () => {
614
+ ended.current = true;
615
+ }),
616
+ player.addListener('statusChange', (event) => {
617
+ if (event.status === 'readyToPlay') {
618
+ setDuration(player.duration || 0);
619
+ return;
620
+ }
621
+ if (event.status !== 'error') {return;}
622
+ if (source === uri && remote) {
623
+ markStreamingUnsupported(uri);
624
+ download();
625
+ } else {
626
+ setFailed(true);
627
+ }
628
+ }),
629
+ ];
630
+ return () => subs.forEach((sub) => sub.remove());
631
+ }, [download, onPlayback, player, remote, source, uri]);
632
+
633
+ useEffect(() => () => onPlayback(false), [onPlayback]);
634
+
635
+ const togglePlay = () => {
636
+ onActivity();
637
+ if (isPlaying) {
638
+ wantsPlay.current = false;
639
+ player.pause();
640
+ return;
641
+ }
642
+ if (ended.current) {
643
+ ended.current = false;
644
+ player.currentTime = 0;
645
+ }
646
+ wantsPlay.current = true;
647
+ player.play();
648
+ };
649
+
650
+ const latest = useRef({ trackWidth, duration, player, onActivity });
651
+ latest.current = { trackWidth, duration, player, onActivity };
652
+ const timeAt = (x: number) => {
653
+ const l = latest.current;
654
+ if (l.trackWidth <= 0 || l.duration <= 0) {return 0;}
655
+ return Math.min(1, Math.max(0, x / l.trackWidth)) * l.duration;
656
+ };
657
+ const seek = (seconds: number) => {
658
+ const l = latest.current;
659
+ ended.current = false;
660
+ l.player.currentTime = seconds;
661
+ setTime(seconds);
662
+ l.onActivity();
663
+ };
664
+
665
+ const scrub = useMemo(() => {
666
+ const drag = Gesture.Pan()
667
+ .runOnJS(true)
668
+ .activeOffsetX([-2, 2])
669
+ .onUpdate((e) => setScrubTime(timeAt(e.x)))
670
+ .onEnd((e) => seek(timeAt(e.x)))
671
+ .onFinalize(() => setScrubTime(null))
672
+ .blocksExternalGesture(outerGesture);
673
+ const tap = Gesture.Tap()
674
+ .runOnJS(true)
675
+ .onEnd((e) => seek(timeAt(e.x)))
676
+ .blocksExternalGesture(outerGesture);
677
+ return Gesture.Exclusive(drag, tap);
678
+ }, [outerGesture]);
679
+
680
+ const loading = progress !== null || source === null;
681
+ const shown = scrubTime ?? time;
682
+ const fraction = duration > 0 ? Math.min(1, shown / duration) : 0;
683
+
684
+ return (
685
+ <>
686
+ <Animated.View
687
+ style={[StyleSheet.absoluteFill, mediaStyle]}
688
+ pointerEvents="none"
689
+ >
690
+ {/* No surface while the copy downloads: the failed stream would
691
+ show the system's "can't play" glyph under the spinner. */}
692
+ {!loading && !failed && (
693
+ <VideoView
694
+ player={player}
695
+ style={StyleSheet.absoluteFill}
696
+ contentFit="contain"
697
+ nativeControls={false}
698
+ surfaceType="textureView"
699
+ />
700
+ )}
701
+ </Animated.View>
702
+
703
+ {failed ? (
704
+ <View style={styles.center} pointerEvents="none">
705
+ <Text style={styles.failedTitle}>{t('video.cantPlay')}</Text>
706
+ <Text style={styles.failedHint}>{t('video.cantPlayHint')}</Text>
707
+ </View>
708
+ ) : loading ? (
709
+ <View style={styles.center} pointerEvents="none">
710
+ <View style={styles.playButton}>
711
+ <ActivityIndicator color={WHITE} />
712
+ </View>
713
+ {!!progress && (
714
+ <Text style={styles.progress}>{Math.round(progress * 100)}%</Text>
715
+ )}
716
+ </View>
717
+ ) : (
718
+ <>
719
+ <Animated.View
720
+ pointerEvents={chromePointerEvents}
721
+ style={[styles.center, { opacity: chromeOpacity }]}
722
+ >
723
+ <TouchableOpacity
724
+ testID="media-viewer-play"
725
+ accessibilityRole="button"
726
+ activeOpacity={0.8}
727
+ style={styles.playButton}
728
+ onPress={togglePlay}
729
+ >
730
+ {isPlaying ? (
731
+ <PauseIcon width={30} height={30} color={WHITE} />
732
+ ) : (
733
+ <PlayIcon width={30} height={30} color={WHITE} />
734
+ )}
735
+ </TouchableOpacity>
736
+ </Animated.View>
737
+
738
+ <Animated.View
739
+ pointerEvents={chromePointerEvents}
740
+ style={[styles.scrubberRow, { bottom: bottomOffset, opacity: chromeOpacity }]}
741
+ >
742
+ <Text style={styles.time}>{formatTime(shown)}</Text>
743
+ <GestureDetector gesture={scrub}>
744
+ <View
745
+ testID="media-viewer-scrubber"
746
+ style={styles.track}
747
+ onLayout={(e) => setTrackWidth(e.nativeEvent.layout.width)}
748
+ >
749
+ <View style={styles.trackLine}>
750
+ <View style={[styles.trackFill, { width: `${fraction * 100}%` }]} />
751
+ </View>
752
+ <View style={[styles.thumb, { left: fraction * trackWidth - 7 }]} />
753
+ </View>
754
+ </GestureDetector>
755
+ <Text style={styles.time}>{formatTime(duration)}</Text>
756
+ </Animated.View>
757
+ </>
758
+ )}
759
+ </>
760
+ );
761
+ };
762
+
763
+ const styles = StyleSheet.create({
764
+ backdrop: {
765
+ backgroundColor: '#000000',
766
+ },
767
+ center: {
768
+ ...StyleSheet.absoluteFill,
769
+ alignItems: 'center',
770
+ justifyContent: 'center',
771
+ },
772
+ topBar: {
773
+ position: 'absolute',
774
+ top: 0,
775
+ left: 0,
776
+ right: 0,
777
+ flexDirection: 'row',
778
+ alignItems: 'center',
779
+ paddingHorizontal: 8,
780
+ paddingBottom: 10,
781
+ backgroundColor: BAR_BACKGROUND,
782
+ },
783
+ bottomBar: {
784
+ position: 'absolute',
785
+ left: 0,
786
+ right: 0,
787
+ bottom: 0,
788
+ flexDirection: 'row',
789
+ alignItems: 'center',
790
+ justifyContent: 'space-between',
791
+ paddingHorizontal: 8,
792
+ paddingTop: 10,
793
+ backgroundColor: BAR_BACKGROUND,
794
+ },
795
+ iconButton: {
796
+ width: 44,
797
+ height: 44,
798
+ alignItems: 'center',
799
+ justifyContent: 'center',
800
+ },
801
+ titleBlock: {
802
+ flex: 1,
803
+ alignItems: 'center',
804
+ paddingHorizontal: 8,
805
+ },
806
+ title: {
807
+ color: WHITE,
808
+ fontSize: 16,
809
+ fontWeight: '600',
810
+ },
811
+ subtitle: {
812
+ color: 'rgba(255, 255, 255, 0.7)',
813
+ fontSize: 13,
814
+ marginTop: 2,
815
+ },
816
+ playButton: {
817
+ width: 64,
818
+ height: 64,
819
+ borderRadius: 32,
820
+ backgroundColor: 'rgba(0, 0, 0, 0.55)',
821
+ alignItems: 'center',
822
+ justifyContent: 'center',
823
+ },
824
+ progress: {
825
+ marginTop: 10,
826
+ color: WHITE,
827
+ fontSize: 13,
828
+ fontWeight: '600',
829
+ },
830
+ failedTitle: {
831
+ color: WHITE,
832
+ fontSize: 16,
833
+ fontWeight: '600',
834
+ },
835
+ failedHint: {
836
+ marginTop: 8,
837
+ color: 'rgba(255, 255, 255, 0.7)',
838
+ textAlign: 'center',
839
+ paddingHorizontal: 32,
840
+ },
841
+ scrubberRow: {
842
+ position: 'absolute',
843
+ left: 12,
844
+ right: 12,
845
+ flexDirection: 'row',
846
+ alignItems: 'center',
847
+ gap: 10,
848
+ },
849
+ time: {
850
+ color: WHITE,
851
+ fontSize: 12,
852
+ fontVariant: ['tabular-nums'],
853
+ minWidth: 36,
854
+ textAlign: 'center',
855
+ },
856
+ track: {
857
+ flex: 1,
858
+ height: 32,
859
+ justifyContent: 'center',
860
+ },
861
+ trackLine: {
862
+ height: 3,
863
+ borderRadius: 1.5,
864
+ backgroundColor: 'rgba(255, 255, 255, 0.35)',
865
+ overflow: 'hidden',
866
+ },
867
+ trackFill: {
868
+ height: '100%',
869
+ backgroundColor: WHITE,
870
+ },
871
+ thumb: {
872
+ position: 'absolute',
873
+ width: 14,
874
+ height: 14,
875
+ borderRadius: 7,
876
+ backgroundColor: WHITE,
877
+ },
878
+ });
879
+
880
+ export default MediaViewer;