@sendbird/uikit-react-native 3.1.2 → 3.3.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 (337) hide show
  1. package/README.md +67 -42
  2. package/lib/commonjs/components/ChannelInput/EditInput.js +2 -11
  3. package/lib/commonjs/components/ChannelInput/EditInput.js.map +1 -1
  4. package/lib/commonjs/components/ChannelInput/MessageToReplyPreview.js +145 -0
  5. package/lib/commonjs/components/ChannelInput/MessageToReplyPreview.js.map +1 -0
  6. package/lib/commonjs/components/ChannelInput/SendInput.js +149 -323
  7. package/lib/commonjs/components/ChannelInput/SendInput.js.map +1 -1
  8. package/lib/commonjs/components/ChannelInput/VoiceMessageInput.js +238 -0
  9. package/lib/commonjs/components/ChannelInput/VoiceMessageInput.js.map +1 -0
  10. package/lib/commonjs/components/ChannelInput/index.js +34 -3
  11. package/lib/commonjs/components/ChannelInput/index.js.map +1 -1
  12. package/lib/commonjs/components/ChannelMessageList/index.js +148 -116
  13. package/lib/commonjs/components/ChannelMessageList/index.js.map +1 -1
  14. package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js +24 -13
  15. package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js.map +1 -1
  16. package/lib/commonjs/components/GroupChannelMessageRenderer/index.js +134 -6
  17. package/lib/commonjs/components/GroupChannelMessageRenderer/index.js.map +1 -1
  18. package/lib/commonjs/components/MessageSearchResultItem.js +1 -0
  19. package/lib/commonjs/components/MessageSearchResultItem.js.map +1 -1
  20. package/lib/commonjs/components/OpenChannelMessageRenderer/index.js +1 -0
  21. package/lib/commonjs/components/OpenChannelMessageRenderer/index.js.map +1 -1
  22. package/lib/commonjs/components/ReactionBottomSheets/ReactionUserListBottomSheet.js +2 -2
  23. package/lib/commonjs/components/ReactionBottomSheets/ReactionUserListBottomSheet.js.map +1 -1
  24. package/lib/commonjs/components/ReactionBottomSheets/index.js.map +1 -1
  25. package/lib/commonjs/components/StatusComposition.js.map +1 -1
  26. package/lib/commonjs/constants.js +5 -1
  27. package/lib/commonjs/constants.js.map +1 -1
  28. package/lib/commonjs/containers/GroupChannelPreviewContainer.js +1 -0
  29. package/lib/commonjs/containers/GroupChannelPreviewContainer.js.map +1 -1
  30. package/lib/commonjs/containers/InternalErrorBoundaryContainer.js.map +1 -1
  31. package/lib/commonjs/containers/SendbirdUIKitContainer.js +72 -34
  32. package/lib/commonjs/containers/SendbirdUIKitContainer.js.map +1 -1
  33. package/lib/commonjs/contexts/PlatformServiceCtx.js +16 -12
  34. package/lib/commonjs/contexts/PlatformServiceCtx.js.map +1 -1
  35. package/lib/commonjs/contexts/ReactionCtx.js +3 -2
  36. package/lib/commonjs/contexts/ReactionCtx.js.map +1 -1
  37. package/lib/commonjs/contexts/SendbirdChatCtx.js +2 -0
  38. package/lib/commonjs/contexts/SendbirdChatCtx.js.map +1 -1
  39. package/lib/commonjs/domain/groupChannel/component/GroupChannelHeader.js +14 -4
  40. package/lib/commonjs/domain/groupChannel/component/GroupChannelHeader.js.map +1 -1
  41. package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js +28 -42
  42. package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
  43. package/lib/commonjs/domain/groupChannel/module/moduleContext.js +109 -5
  44. package/lib/commonjs/domain/groupChannel/module/moduleContext.js.map +1 -1
  45. package/lib/commonjs/domain/groupChannel/types.js.map +1 -1
  46. package/lib/commonjs/domain/userList/types.js.map +1 -1
  47. package/lib/commonjs/fragments/createGroupChannelFragment.js +34 -7
  48. package/lib/commonjs/fragments/createGroupChannelFragment.js.map +1 -1
  49. package/lib/commonjs/fragments/createMessageSearchFragment.js +1 -1
  50. package/lib/commonjs/fragments/createMessageSearchFragment.js.map +1 -1
  51. package/lib/commonjs/hooks/useChannelInputItems.js +211 -0
  52. package/lib/commonjs/hooks/useChannelInputItems.js.map +1 -0
  53. package/lib/commonjs/hooks/useConnection.js +1 -1
  54. package/lib/commonjs/hooks/useConnection.js.map +1 -1
  55. package/lib/commonjs/hooks/useVoiceMessageInput.js +207 -0
  56. package/lib/commonjs/hooks/useVoiceMessageInput.js.map +1 -0
  57. package/lib/commonjs/index.js +36 -0
  58. package/lib/commonjs/index.js.map +1 -1
  59. package/lib/commonjs/libs/MentionManager.js.map +1 -1
  60. package/lib/commonjs/libs/SBUUtils.js +4 -0
  61. package/lib/commonjs/libs/SBUUtils.js.map +1 -1
  62. package/lib/commonjs/libs/VoiceMessageConfig.js +30 -0
  63. package/lib/commonjs/libs/VoiceMessageConfig.js.map +1 -0
  64. package/lib/commonjs/localization/StringSet.type.js.map +1 -1
  65. package/lib/commonjs/localization/createBaseStringSet.js +24 -9
  66. package/lib/commonjs/localization/createBaseStringSet.js.map +1 -1
  67. package/lib/commonjs/platform/createFileService.expo.js +10 -0
  68. package/lib/commonjs/platform/createFileService.expo.js.map +1 -1
  69. package/lib/commonjs/platform/createFileService.native.js +19 -0
  70. package/lib/commonjs/platform/createFileService.native.js.map +1 -1
  71. package/lib/commonjs/platform/createPlayerService.expo.js +137 -0
  72. package/lib/commonjs/platform/createPlayerService.expo.js.map +1 -0
  73. package/lib/commonjs/platform/createPlayerService.native.js +139 -0
  74. package/lib/commonjs/platform/createPlayerService.native.js.map +1 -0
  75. package/lib/commonjs/platform/createRecorderService.expo.js +158 -0
  76. package/lib/commonjs/platform/createRecorderService.expo.js.map +1 -0
  77. package/lib/commonjs/platform/createRecorderService.native.js +157 -0
  78. package/lib/commonjs/platform/createRecorderService.native.js.map +1 -0
  79. package/lib/commonjs/platform/types.js.map +1 -1
  80. package/lib/commonjs/types.js +7 -0
  81. package/lib/commonjs/types.js.map +1 -1
  82. package/lib/commonjs/utils/promise.js +138 -0
  83. package/lib/commonjs/utils/promise.js.map +1 -0
  84. package/lib/commonjs/version.js +1 -1
  85. package/lib/commonjs/version.js.map +1 -1
  86. package/lib/module/components/ChannelInput/EditInput.js +3 -12
  87. package/lib/module/components/ChannelInput/EditInput.js.map +1 -1
  88. package/lib/module/components/ChannelInput/MessageToReplyPreview.js +137 -0
  89. package/lib/module/components/ChannelInput/MessageToReplyPreview.js.map +1 -0
  90. package/lib/module/components/ChannelInput/SendInput.js +152 -326
  91. package/lib/module/components/ChannelInput/SendInput.js.map +1 -1
  92. package/lib/module/components/ChannelInput/VoiceMessageInput.js +228 -0
  93. package/lib/module/components/ChannelInput/VoiceMessageInput.js.map +1 -0
  94. package/lib/module/components/ChannelInput/index.js +36 -5
  95. package/lib/module/components/ChannelInput/index.js.map +1 -1
  96. package/lib/module/components/ChannelMessageList/index.js +149 -117
  97. package/lib/module/components/ChannelMessageList/index.js.map +1 -1
  98. package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js +24 -13
  99. package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js.map +1 -1
  100. package/lib/module/components/GroupChannelMessageRenderer/index.js +132 -7
  101. package/lib/module/components/GroupChannelMessageRenderer/index.js.map +1 -1
  102. package/lib/module/components/MessageSearchResultItem.js +2 -1
  103. package/lib/module/components/MessageSearchResultItem.js.map +1 -1
  104. package/lib/module/components/OpenChannelMessageRenderer/index.js +1 -0
  105. package/lib/module/components/OpenChannelMessageRenderer/index.js.map +1 -1
  106. package/lib/module/components/ReactionBottomSheets/ReactionUserListBottomSheet.js +2 -2
  107. package/lib/module/components/ReactionBottomSheets/ReactionUserListBottomSheet.js.map +1 -1
  108. package/lib/module/components/ReactionBottomSheets/index.js.map +1 -1
  109. package/lib/module/components/StatusComposition.js.map +1 -1
  110. package/lib/module/constants.js +2 -0
  111. package/lib/module/constants.js.map +1 -1
  112. package/lib/module/containers/GroupChannelPreviewContainer.js +2 -1
  113. package/lib/module/containers/GroupChannelPreviewContainer.js.map +1 -1
  114. package/lib/module/containers/InternalErrorBoundaryContainer.js.map +1 -1
  115. package/lib/module/containers/SendbirdUIKitContainer.js +74 -36
  116. package/lib/module/containers/SendbirdUIKitContainer.js.map +1 -1
  117. package/lib/module/contexts/PlatformServiceCtx.js +14 -11
  118. package/lib/module/contexts/PlatformServiceCtx.js.map +1 -1
  119. package/lib/module/contexts/ReactionCtx.js +3 -2
  120. package/lib/module/contexts/ReactionCtx.js.map +1 -1
  121. package/lib/module/contexts/SendbirdChatCtx.js +2 -0
  122. package/lib/module/contexts/SendbirdChatCtx.js.map +1 -1
  123. package/lib/module/domain/groupChannel/component/GroupChannelHeader.js +15 -5
  124. package/lib/module/domain/groupChannel/component/GroupChannelHeader.js.map +1 -1
  125. package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js +29 -43
  126. package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
  127. package/lib/module/domain/groupChannel/module/moduleContext.js +111 -7
  128. package/lib/module/domain/groupChannel/module/moduleContext.js.map +1 -1
  129. package/lib/module/domain/groupChannel/types.js.map +1 -1
  130. package/lib/module/domain/userList/types.js.map +1 -1
  131. package/lib/module/fragments/createGroupChannelFragment.js +36 -9
  132. package/lib/module/fragments/createGroupChannelFragment.js.map +1 -1
  133. package/lib/module/fragments/createMessageSearchFragment.js +1 -1
  134. package/lib/module/fragments/createMessageSearchFragment.js.map +1 -1
  135. package/lib/module/hooks/useChannelInputItems.js +203 -0
  136. package/lib/module/hooks/useChannelInputItems.js.map +1 -0
  137. package/lib/module/hooks/useConnection.js +1 -1
  138. package/lib/module/hooks/useConnection.js.map +1 -1
  139. package/lib/module/hooks/useVoiceMessageInput.js +199 -0
  140. package/lib/module/hooks/useVoiceMessageInput.js.map +1 -0
  141. package/lib/module/index.js +8 -0
  142. package/lib/module/index.js.map +1 -1
  143. package/lib/module/libs/MentionManager.js.map +1 -1
  144. package/lib/module/libs/SBUUtils.js +4 -0
  145. package/lib/module/libs/SBUUtils.js.map +1 -1
  146. package/lib/module/libs/VoiceMessageConfig.js +23 -0
  147. package/lib/module/libs/VoiceMessageConfig.js.map +1 -0
  148. package/lib/module/localization/StringSet.type.js.map +1 -1
  149. package/lib/module/localization/createBaseStringSet.js +25 -10
  150. package/lib/module/localization/createBaseStringSet.js.map +1 -1
  151. package/lib/module/platform/createFileService.expo.js +10 -0
  152. package/lib/module/platform/createFileService.expo.js.map +1 -1
  153. package/lib/module/platform/createFileService.native.js +19 -0
  154. package/lib/module/platform/createFileService.native.js.map +1 -1
  155. package/lib/module/platform/createPlayerService.expo.js +129 -0
  156. package/lib/module/platform/createPlayerService.expo.js.map +1 -0
  157. package/lib/module/platform/createPlayerService.native.js +132 -0
  158. package/lib/module/platform/createPlayerService.native.js.map +1 -0
  159. package/lib/module/platform/createRecorderService.expo.js +150 -0
  160. package/lib/module/platform/createRecorderService.expo.js.map +1 -0
  161. package/lib/module/platform/createRecorderService.native.js +149 -0
  162. package/lib/module/platform/createRecorderService.native.js.map +1 -0
  163. package/lib/module/platform/types.js.map +1 -1
  164. package/lib/module/types.js +5 -1
  165. package/lib/module/types.js.map +1 -1
  166. package/lib/module/utils/promise.js +132 -0
  167. package/lib/module/utils/promise.js.map +1 -0
  168. package/lib/module/version.js +1 -1
  169. package/lib/module/version.js.map +1 -1
  170. package/lib/typescript/src/components/ChannelCover.d.ts +2 -1
  171. package/lib/typescript/src/components/ChannelInput/AttachmentsButton.d.ts +2 -1
  172. package/lib/typescript/src/components/ChannelInput/MessageToReplyPreview.d.ts +7 -0
  173. package/lib/typescript/src/components/ChannelInput/VoiceMessageInput.d.ts +11 -0
  174. package/lib/typescript/src/components/ChannelInput/index.d.ts +9 -3
  175. package/lib/typescript/src/components/ChannelMessageList/index.d.ts +4 -1
  176. package/lib/typescript/src/components/FileViewer.d.ts +2 -1
  177. package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageDateSeparator.d.ts +2 -1
  178. package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.d.ts +1 -1
  179. package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageOutgoingStatus.d.ts +1 -1
  180. package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.d.ts +4 -2
  181. package/lib/typescript/src/components/GroupChannelMessageRenderer/index.d.ts +3 -0
  182. package/lib/typescript/src/components/NewMessagesButton.d.ts +1 -1
  183. package/lib/typescript/src/components/OpenChannelMessageRenderer/OpenChannelMessageDateSeparator.d.ts +2 -1
  184. package/lib/typescript/src/components/OpenChannelMessageRenderer/index.d.ts +2 -0
  185. package/lib/typescript/src/components/ProviderLayout.d.ts +1 -1
  186. package/lib/typescript/src/components/ReactionAddons/BottomSheetReactionAddon.d.ts +2 -1
  187. package/lib/typescript/src/components/ReactionAddons/MessageReactionAddon.d.ts +2 -1
  188. package/lib/typescript/src/components/ReactionAddons/ReactionRoundedButton.d.ts +3 -2
  189. package/lib/typescript/src/components/ReactionAddons/index.d.ts +3 -2
  190. package/lib/typescript/src/components/ReactionBottomSheets/ReactionListBottomSheet.d.ts +2 -1
  191. package/lib/typescript/src/components/ReactionBottomSheets/ReactionUserListBottomSheet.d.ts +2 -1
  192. package/lib/typescript/src/components/ReactionBottomSheets/index.d.ts +4 -4
  193. package/lib/typescript/src/components/ScrollToBottomButton.d.ts +1 -1
  194. package/lib/typescript/src/components/StatusComposition.d.ts +4 -4
  195. package/lib/typescript/src/components/TypedPlaceholder.d.ts +2 -1
  196. package/lib/typescript/src/components/UserActionBar.d.ts +2 -1
  197. package/lib/typescript/src/components/UserSelectableBar.d.ts +2 -1
  198. package/lib/typescript/src/constants.d.ts +2 -0
  199. package/lib/typescript/src/containers/GroupChannelPreviewContainer.d.ts +2 -1
  200. package/lib/typescript/src/containers/InternalErrorBoundaryContainer.d.ts +3 -3
  201. package/lib/typescript/src/containers/SendbirdUIKitContainer.d.ts +19 -8
  202. package/lib/typescript/src/contexts/LocalizationCtx.d.ts +1 -1
  203. package/lib/typescript/src/contexts/PlatformServiceCtx.d.ts +8 -8
  204. package/lib/typescript/src/contexts/ReactionCtx.d.ts +5 -2
  205. package/lib/typescript/src/contexts/SendbirdChatCtx.d.ts +6 -3
  206. package/lib/typescript/src/contexts/UserProfileCtx.d.ts +1 -1
  207. package/lib/typescript/src/domain/groupChannel/component/GroupChannelHeader.d.ts +2 -1
  208. package/lib/typescript/src/domain/groupChannel/component/GroupChannelInput.d.ts +1 -1
  209. package/lib/typescript/src/domain/groupChannel/component/GroupChannelMessageList.d.ts +1 -1
  210. package/lib/typescript/src/domain/groupChannel/component/GroupChannelStatusEmpty.d.ts +2 -1
  211. package/lib/typescript/src/domain/groupChannel/component/GroupChannelStatusLoading.d.ts +2 -1
  212. package/lib/typescript/src/domain/groupChannel/component/GroupChannelSuggestedMentionList.d.ts +2 -1
  213. package/lib/typescript/src/domain/groupChannel/types.d.ts +48 -0
  214. package/lib/typescript/src/domain/groupChannelBannedUsers/component/GroupChannelBannedUsersHeader.d.ts +2 -1
  215. package/lib/typescript/src/domain/groupChannelBannedUsers/component/GroupChannelBannedUsersList.d.ts +2 -1
  216. package/lib/typescript/src/domain/groupChannelBannedUsers/component/GroupChannelBannedUsersStatusEmpty.d.ts +2 -1
  217. package/lib/typescript/src/domain/groupChannelBannedUsers/component/GroupChannelBannedUsersStatusLoading.d.ts +2 -1
  218. package/lib/typescript/src/domain/groupChannelList/component/GroupChannelListHeader.d.ts +2 -1
  219. package/lib/typescript/src/domain/groupChannelList/component/GroupChannelListList.d.ts +2 -1
  220. package/lib/typescript/src/domain/groupChannelList/component/GroupChannelListStatusEmpty.d.ts +2 -1
  221. package/lib/typescript/src/domain/groupChannelList/component/GroupChannelListStatusLoading.d.ts +2 -1
  222. package/lib/typescript/src/domain/groupChannelList/component/GroupChannelListTypeSelector.d.ts +2 -1
  223. package/lib/typescript/src/domain/groupChannelModeration/component/GroupChannelModerationHeader.d.ts +2 -1
  224. package/lib/typescript/src/domain/groupChannelModeration/component/GroupChannelModerationMenu.d.ts +2 -1
  225. package/lib/typescript/src/domain/groupChannelMutedMembers/component/GroupChannelMutedMembersHeader.d.ts +2 -1
  226. package/lib/typescript/src/domain/groupChannelMutedMembers/component/GroupChannelMutedMembersList.d.ts +2 -1
  227. package/lib/typescript/src/domain/groupChannelMutedMembers/component/GroupChannelMutedMembersStatusEmpty.d.ts +2 -1
  228. package/lib/typescript/src/domain/groupChannelMutedMembers/component/GroupChannelMutedMembersStatusLoading.d.ts +2 -1
  229. package/lib/typescript/src/domain/groupChannelNotifications/component/GroupChannelNotificationsHeader.d.ts +2 -1
  230. package/lib/typescript/src/domain/groupChannelNotifications/component/GroupChannelNotificationsView.d.ts +2 -1
  231. package/lib/typescript/src/domain/groupChannelOperators/component/GroupChannelOperatorsHeader.d.ts +2 -1
  232. package/lib/typescript/src/domain/groupChannelOperators/component/GroupChannelOperatorsList.d.ts +2 -1
  233. package/lib/typescript/src/domain/groupChannelOperators/component/GroupChannelOperatorsStatusEmpty.d.ts +2 -1
  234. package/lib/typescript/src/domain/groupChannelOperators/component/GroupChannelOperatorsStatusLoading.d.ts +2 -1
  235. package/lib/typescript/src/domain/groupChannelSettings/component/GroupChannelSettingsHeader.d.ts +2 -1
  236. package/lib/typescript/src/domain/groupChannelSettings/component/GroupChannelSettingsInfo.d.ts +2 -1
  237. package/lib/typescript/src/domain/groupChannelSettings/component/GroupChannelSettingsMenu.d.ts +2 -1
  238. package/lib/typescript/src/domain/messageSearch/component/MessageSearchHeader.d.ts +2 -1
  239. package/lib/typescript/src/domain/messageSearch/component/MessageSearchList.d.ts +2 -1
  240. package/lib/typescript/src/domain/messageSearch/component/MessageSearchStatusEmpty.d.ts +2 -1
  241. package/lib/typescript/src/domain/messageSearch/component/MessageSearchStatusLoading.d.ts +2 -1
  242. package/lib/typescript/src/domain/openChannel/component/OpenChannelHeader.d.ts +2 -2
  243. package/lib/typescript/src/domain/openChannel/component/OpenChannelInput.d.ts +1 -1
  244. package/lib/typescript/src/domain/openChannel/component/OpenChannelMessageList.d.ts +1 -1
  245. package/lib/typescript/src/domain/openChannel/component/OpenChannelStatusEmpty.d.ts +2 -1
  246. package/lib/typescript/src/domain/openChannel/component/OpenChannelStatusLoading.d.ts +2 -1
  247. package/lib/typescript/src/domain/openChannelBannedUsers/component/OpenChannelBannedUsersHeader.d.ts +2 -1
  248. package/lib/typescript/src/domain/openChannelBannedUsers/component/OpenChannelBannedUsersList.d.ts +2 -1
  249. package/lib/typescript/src/domain/openChannelBannedUsers/component/OpenChannelBannedUsersStatusEmpty.d.ts +2 -1
  250. package/lib/typescript/src/domain/openChannelBannedUsers/component/OpenChannelBannedUsersStatusLoading.d.ts +2 -1
  251. package/lib/typescript/src/domain/openChannelCreate/component/OpenChannelCreateHeader.d.ts +2 -1
  252. package/lib/typescript/src/domain/openChannelCreate/component/OpenChannelCreateProfileInput.d.ts +2 -1
  253. package/lib/typescript/src/domain/openChannelCreate/component/OpenChannelCreateStatusLoading.d.ts +2 -1
  254. package/lib/typescript/src/domain/openChannelList/component/OpenChannelListHeader.d.ts +2 -1
  255. package/lib/typescript/src/domain/openChannelList/component/OpenChannelListList.d.ts +2 -1
  256. package/lib/typescript/src/domain/openChannelList/component/OpenChannelListStatusEmpty.d.ts +2 -1
  257. package/lib/typescript/src/domain/openChannelList/component/OpenChannelListStatusLoading.d.ts +2 -1
  258. package/lib/typescript/src/domain/openChannelModeration/component/OpenChannelModerationHeader.d.ts +2 -1
  259. package/lib/typescript/src/domain/openChannelModeration/component/OpenChannelModerationMenu.d.ts +2 -1
  260. package/lib/typescript/src/domain/openChannelMutedParticipants/component/OpenChannelMutedParticipantsHeader.d.ts +2 -1
  261. package/lib/typescript/src/domain/openChannelMutedParticipants/component/OpenChannelMutedParticipantsList.d.ts +2 -1
  262. package/lib/typescript/src/domain/openChannelMutedParticipants/component/OpenChannelMutedParticipantsStatusEmpty.d.ts +2 -1
  263. package/lib/typescript/src/domain/openChannelMutedParticipants/component/OpenChannelMutedParticipantsStatusLoading.d.ts +2 -1
  264. package/lib/typescript/src/domain/openChannelOperators/component/OpenChannelOperatorsHeader.d.ts +2 -1
  265. package/lib/typescript/src/domain/openChannelOperators/component/OpenChannelOperatorsList.d.ts +2 -1
  266. package/lib/typescript/src/domain/openChannelOperators/component/OpenChannelOperatorsStatusEmpty.d.ts +2 -1
  267. package/lib/typescript/src/domain/openChannelOperators/component/OpenChannelOperatorsStatusLoading.d.ts +2 -1
  268. package/lib/typescript/src/domain/openChannelSettings/component/OpenChannelSettingsHeader.d.ts +2 -1
  269. package/lib/typescript/src/domain/openChannelSettings/component/OpenChannelSettingsInfo.d.ts +2 -1
  270. package/lib/typescript/src/domain/openChannelSettings/component/OpenChannelSettingsMenu.d.ts +2 -1
  271. package/lib/typescript/src/domain/userList/component/UserListHeader.d.ts +3 -3
  272. package/lib/typescript/src/domain/userList/component/UserListList.d.ts +1 -1
  273. package/lib/typescript/src/domain/userList/component/UserListStatusEmpty.d.ts +2 -1
  274. package/lib/typescript/src/domain/userList/component/UserListStatusLoading.d.ts +2 -1
  275. package/lib/typescript/src/domain/userList/types.d.ts +2 -2
  276. package/lib/typescript/src/hooks/useChannelInputItems.d.ts +10 -0
  277. package/lib/typescript/src/hooks/useVoiceMessageInput.d.ts +53 -0
  278. package/lib/typescript/src/index.d.ts +4 -0
  279. package/lib/typescript/src/libs/MentionManager.d.ts +2 -1
  280. package/lib/typescript/src/libs/SBUUtils.d.ts +1 -0
  281. package/lib/typescript/src/libs/VoiceMessageConfig.d.ts +25 -0
  282. package/lib/typescript/src/localization/StringSet.type.d.ts +7 -0
  283. package/lib/typescript/src/platform/createPlayerService.expo.d.ts +7 -0
  284. package/lib/typescript/src/platform/createPlayerService.native.d.ts +9 -0
  285. package/lib/typescript/src/platform/createRecorderService.expo.d.ts +7 -0
  286. package/lib/typescript/src/platform/createRecorderService.native.d.ts +9 -0
  287. package/lib/typescript/src/platform/types.d.ts +100 -1
  288. package/lib/typescript/src/types.d.ts +5 -1
  289. package/lib/typescript/src/utils/promise.d.ts +7 -0
  290. package/lib/typescript/src/version.d.ts +1 -1
  291. package/package.json +10 -12
  292. package/src/components/ChannelInput/EditInput.tsx +3 -15
  293. package/src/components/ChannelInput/MessageToReplyPreview.tsx +133 -0
  294. package/src/components/ChannelInput/SendInput.tsx +131 -329
  295. package/src/components/ChannelInput/VoiceMessageInput.tsx +206 -0
  296. package/src/components/ChannelInput/index.tsx +37 -6
  297. package/src/components/ChannelMessageList/index.tsx +145 -113
  298. package/src/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.tsx +24 -11
  299. package/src/components/GroupChannelMessageRenderer/index.tsx +113 -4
  300. package/src/components/MessageSearchResultItem.tsx +2 -1
  301. package/src/components/OpenChannelMessageRenderer/index.tsx +1 -0
  302. package/src/components/ReactionBottomSheets/ReactionUserListBottomSheet.tsx +2 -2
  303. package/src/components/ReactionBottomSheets/index.tsx +3 -2
  304. package/src/components/StatusComposition.tsx +3 -3
  305. package/src/constants.ts +2 -0
  306. package/src/containers/GroupChannelPreviewContainer.tsx +2 -0
  307. package/src/containers/InternalErrorBoundaryContainer.tsx +1 -1
  308. package/src/containers/SendbirdUIKitContainer.tsx +103 -59
  309. package/src/contexts/PlatformServiceCtx.tsx +22 -20
  310. package/src/contexts/ReactionCtx.tsx +7 -5
  311. package/src/contexts/SendbirdChatCtx.tsx +10 -2
  312. package/src/domain/groupChannel/component/GroupChannelHeader.tsx +14 -3
  313. package/src/domain/groupChannel/component/GroupChannelMessageList.tsx +30 -43
  314. package/src/domain/groupChannel/module/moduleContext.tsx +119 -7
  315. package/src/domain/groupChannel/types.ts +45 -0
  316. package/src/domain/userList/types.ts +2 -2
  317. package/src/fragments/createGroupChannelFragment.tsx +43 -8
  318. package/src/fragments/createMessageSearchFragment.tsx +1 -1
  319. package/src/hooks/useChannelInputItems.ts +215 -0
  320. package/src/hooks/useConnection.ts +1 -1
  321. package/src/hooks/useVoiceMessageInput.ts +237 -0
  322. package/src/index.ts +9 -1
  323. package/src/libs/MentionManager.tsx +1 -1
  324. package/src/libs/SBUUtils.ts +5 -0
  325. package/src/libs/VoiceMessageConfig.ts +28 -0
  326. package/src/localization/StringSet.type.ts +8 -0
  327. package/src/localization/createBaseStringSet.ts +27 -11
  328. package/src/platform/createFileService.expo.ts +10 -0
  329. package/src/platform/createFileService.native.ts +19 -0
  330. package/src/platform/createPlayerService.expo.tsx +142 -0
  331. package/src/platform/createPlayerService.native.tsx +148 -0
  332. package/src/platform/createRecorderService.expo.tsx +160 -0
  333. package/src/platform/createRecorderService.native.tsx +170 -0
  334. package/src/platform/types.ts +114 -1
  335. package/src/types.ts +6 -1
  336. package/src/utils/promise.ts +139 -0
  337. package/src/version.ts +1 -1
@@ -0,0 +1,206 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { Animated } from 'react-native';
3
+
4
+ import {
5
+ Box,
6
+ Icon,
7
+ PressBox,
8
+ ProgressBar,
9
+ Text,
10
+ createStyleSheet,
11
+ useUIKitTheme,
12
+ } from '@sendbird/uikit-react-native-foundation';
13
+ import { conditionChaining, millsToMMSS } from '@sendbird/uikit-utils';
14
+
15
+ import { useLocalization } from '../../hooks/useContext';
16
+ import useVoiceMessageInput from '../../hooks/useVoiceMessageInput';
17
+ import type { FileType } from '../../platform/types';
18
+
19
+ export type VoiceMessageInputProps = {
20
+ onClose: () => Promise<void>;
21
+ onSend: (params: { file: FileType; duration: number }) => void;
22
+ };
23
+
24
+ const VoiceMessageInput = ({ onClose, onSend }: VoiceMessageInputProps) => {
25
+ const { STRINGS } = useLocalization();
26
+ const { colors } = useUIKitTheme();
27
+ const { actions, state } = useVoiceMessageInput({
28
+ onSend: (file, duration) => onSend({ file, duration }),
29
+ onClose,
30
+ });
31
+
32
+ const uiColors = colors.ui.voiceMessageInput.default[state.status !== 'idle' ? 'active' : 'inactive'];
33
+
34
+ const onPressCancel = async () => {
35
+ actions.cancel();
36
+ onClose();
37
+ };
38
+
39
+ const onPressSend = async () => {
40
+ actions.send();
41
+ onClose();
42
+ };
43
+
44
+ const onPressVoiceMessageAction = () => {
45
+ switch (state.status) {
46
+ case 'idle':
47
+ actions.startRecording();
48
+ break;
49
+ case 'recording':
50
+ if (lessThanMinimumDuration) {
51
+ actions.cancel();
52
+ } else {
53
+ actions.stopRecording();
54
+ }
55
+ break;
56
+ case 'recording_completed':
57
+ case 'playing_paused':
58
+ actions.playPlayer();
59
+ break;
60
+ case 'playing':
61
+ actions.pausePlayer();
62
+ break;
63
+ }
64
+ };
65
+ const renderActionIcon = () => {
66
+ switch (state.status) {
67
+ case 'idle':
68
+ return <Icon icon={'recording'} size={20} color={uiColors.recording} />;
69
+ case 'recording':
70
+ return <Icon icon={'stop'} size={20} color={uiColors.actionIcon} />;
71
+ case 'recording_completed':
72
+ case 'playing_paused':
73
+ return <Icon icon={'play'} size={20} color={uiColors.actionIcon} />;
74
+ case 'playing':
75
+ return <Icon icon={'pause'} size={20} color={uiColors.actionIcon} />;
76
+ }
77
+ };
78
+
79
+ const isRecorderState = state.status === 'recording' || state.status === 'recording_completed';
80
+ const lessThanMinimumDuration = state.recordingTime.currentTime < state.recordingTime.minDuration;
81
+ const remainingTime = state.playingTime.duration - state.playingTime.currentTime;
82
+
83
+ return (
84
+ <Box backgroundColor={uiColors.background} paddingVertical={24} paddingHorizontal={16} style={styles.container}>
85
+ {/** Progress bar **/}
86
+ <ProgressBar
87
+ style={styles.progressBar}
88
+ current={conditionChaining(
89
+ [state.status === 'recording', state.status === 'recording_completed'],
90
+ [state.recordingTime.currentTime, 0, state.playingTime.currentTime],
91
+ )}
92
+ total={(isRecorderState ? state.recordingTime.maxDuration : state.playingTime.duration) || 1}
93
+ trackColor={uiColors.progressTrack}
94
+ overlay={
95
+ <Box flex={1} flexDirection={'row'} alignItems={'center'} justifyContent={'flex-end'} paddingRight={16}>
96
+ <RecordingLight visible={state.status === 'recording'} />
97
+ <Text caption1 style={{ lineHeight: undefined, marginLeft: 6 }} color={uiColors.textTime}>
98
+ {millsToMMSS(isRecorderState ? state.recordingTime.currentTime : remainingTime)}
99
+ </Text>
100
+ </Box>
101
+ }
102
+ />
103
+
104
+ <Box height={34} alignItems={'center'} justifyContent={'center'}>
105
+ {/** Cancel / Send **/}
106
+ <Box flexDirection={'row'}>
107
+ <CancelButton label={STRINGS.LABELS.VOICE_MESSAGE_INPUT_CANCEL} onPress={onPressCancel} />
108
+ <Box flex={1} />
109
+ <SendButton disabled={state.status === 'idle' || lessThanMinimumDuration} onPress={onPressSend} />
110
+ </Box>
111
+
112
+ {/** Record / Stop / Play / Pause **/}
113
+ <Box style={{ position: 'absolute' }} alignItems={'center'} justifyContent={'center'}>
114
+ <PressBox activeOpacity={0.5} onPress={onPressVoiceMessageAction}>
115
+ <Box
116
+ width={34}
117
+ height={34}
118
+ borderRadius={17}
119
+ alignItems={'center'}
120
+ justifyContent={'center'}
121
+ backgroundColor={uiColors.actionIconBackground}
122
+ >
123
+ {renderActionIcon()}
124
+ </Box>
125
+ </PressBox>
126
+ </Box>
127
+ </Box>
128
+ </Box>
129
+ );
130
+ };
131
+
132
+ const RecordingLight = (props: { visible: boolean }) => {
133
+ const { colors } = useUIKitTheme();
134
+
135
+ const value = useRef(new Animated.Value(0)).current;
136
+ const animation = useRef(
137
+ Animated.loop(
138
+ Animated.sequence([
139
+ Animated.timing(value, { toValue: 1, duration: 500, useNativeDriver: true }),
140
+ Animated.timing(value, { toValue: 0, duration: 500, useNativeDriver: true }),
141
+ ]),
142
+ ),
143
+ ).current;
144
+
145
+ useEffect(() => {
146
+ if (props.visible) animation.start();
147
+ return () => {
148
+ animation.reset();
149
+ };
150
+ }, [props.visible]);
151
+
152
+ if (!props.visible) return null;
153
+ return (
154
+ <Animated.View
155
+ style={{
156
+ width: 12,
157
+ height: 12,
158
+ borderRadius: 6,
159
+ opacity: value,
160
+ backgroundColor: colors.ui.voiceMessageInput.default.active.recording,
161
+ }}
162
+ />
163
+ );
164
+ };
165
+
166
+ const CancelButton = (props: { onPress: () => void; label: string }) => {
167
+ const { colors } = useUIKitTheme();
168
+
169
+ return (
170
+ <PressBox activeOpacity={0.8} onPress={props.onPress}>
171
+ <Box paddingHorizontal={12} height={'100%'} alignItems={'center'} justifyContent={'center'}>
172
+ <Text button color={colors.ui.voiceMessageInput.default.active.textCancel} numberOfLines={1}>
173
+ {props.label}
174
+ </Text>
175
+ </Box>
176
+ </PressBox>
177
+ );
178
+ };
179
+
180
+ const SendButton = (props: { onPress: () => void; disabled: boolean }) => {
181
+ const { colors } = useUIKitTheme();
182
+
183
+ const uiColors = colors.ui.voiceMessageInput.default[props.disabled ? 'inactive' : 'active'];
184
+
185
+ return (
186
+ <PressBox disabled={props.disabled} activeOpacity={0.8} onPress={props.onPress}>
187
+ <Box backgroundColor={uiColors.sendIconBackground} padding={7} borderRadius={40}>
188
+ <Icon icon={'send'} size={20} color={uiColors.sendIcon} />
189
+ </Box>
190
+ </PressBox>
191
+ );
192
+ };
193
+
194
+ const styles = createStyleSheet({
195
+ container: {
196
+ borderTopLeftRadius: 8,
197
+ borderTopRightRadius: 8,
198
+ },
199
+ progressBar: {
200
+ height: 36,
201
+ marginBottom: 16,
202
+ borderRadius: 18,
203
+ },
204
+ });
205
+
206
+ export default VoiceMessageInput;
@@ -1,5 +1,5 @@
1
- import React, { MutableRefObject, useEffect, useState } from 'react';
2
- import { KeyboardAvoidingView, Platform, TextInput, View } from 'react-native';
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+ import { KeyboardAvoidingView, Platform, StyleProp, StyleSheet, TextInput, TextStyle, View } from 'react-native';
3
3
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
4
4
 
5
5
  import { createStyleSheet, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
@@ -23,7 +23,10 @@ import type { MentionedUser, Range } from '../../types';
23
23
  import type { AttachmentsButtonProps } from './AttachmentsButton';
24
24
  import AttachmentsButton from './AttachmentsButton';
25
25
  import EditInput from './EditInput';
26
+ import type { MessageToReplyPreviewProps } from './MessageToReplyPreview';
27
+ import { MessageToReplyPreview } from './MessageToReplyPreview';
26
28
  import SendInput from './SendInput';
29
+ import VoiceMessageInput, { VoiceMessageInputProps } from './VoiceMessageInput';
27
30
 
28
31
  export type SuggestedMentionListProps = {
29
32
  text: string;
@@ -36,6 +39,9 @@ export type SuggestedMentionListProps = {
36
39
  };
37
40
 
38
41
  export type ChannelInputProps = {
42
+ // style
43
+ style?: StyleProp<TextStyle>;
44
+
39
45
  // default
40
46
  channel: SendbirdBaseChannel;
41
47
  shouldRenderInput: boolean;
@@ -61,10 +67,12 @@ export type ChannelInputProps = {
61
67
  setMessageToReply?: (message?: undefined | SendbirdUserMessage | SendbirdFileMessage) => void;
62
68
 
63
69
  // mention
64
- SuggestedMentionList?: (props: SuggestedMentionListProps) => JSX.Element | null;
70
+ SuggestedMentionList?: (props: SuggestedMentionListProps) => React.ReactNode | null;
65
71
 
66
72
  // sub-components
67
- AttachmentsButton?: (props: AttachmentsButtonProps) => JSX.Element | null;
73
+ AttachmentsButton?: (props: AttachmentsButtonProps) => React.ReactNode | null;
74
+ MessageToReplyPreview?: (props: MessageToReplyPreviewProps) => React.ReactNode | null;
75
+ VoiceMessageInput?: (props: VoiceMessageInputProps) => React.ReactNode | null;
68
76
  };
69
77
 
70
78
  const AUTO_FOCUS = Platform.select({ ios: false, android: true, default: false });
@@ -80,7 +88,7 @@ const ChannelInput = (props: ChannelInputProps) => {
80
88
  const { channel, keyboardAvoidOffset, messageToEdit, setMessageToEdit } = props;
81
89
 
82
90
  const { top, left, right, bottom } = useSafeAreaInsets();
83
- const { colors } = useUIKitTheme();
91
+ const { colors, typography } = useUIKitTheme();
84
92
  const { sbOptions, mentionManager } = useSendbirdChat();
85
93
 
86
94
  const { selection, onSelectionChange, textInputRef, text, onChangeText, mentionedUsers } = useMentionTextInput({
@@ -97,6 +105,14 @@ const ChannelInput = (props: ChannelInputProps) => {
97
105
 
98
106
  const [inputHeight, setInputHeight] = useState(styles.inputDefault.height);
99
107
 
108
+ const fontStyle = useMemo(() => {
109
+ if (!typography.body3.fontSize) return typography.body3;
110
+ // NOTE: iOS does not support textAlignVertical, so we should adjust lineHeight to center the text in multiline TextInput.
111
+ return { ...typography.body3, lineHeight: typography.body3.fontSize * 1.275, textAlignVertical: 'center' };
112
+ }, [typography.body3.fontSize]);
113
+
114
+ const textInputStyle = StyleSheet.flatten([styles.input, fontStyle, props.style]);
115
+
100
116
  useTypingTrigger(text, channel);
101
117
  useTextClearOnDisabled(onChangeText, props.inputDisabled);
102
118
  useAutoFocusOnEditMode(textInputRef, messageToEdit);
@@ -129,7 +145,10 @@ const ChannelInput = (props: ChannelInputProps) => {
129
145
  onChangeText={onChangeText}
130
146
  onSelectionChange={onSelectionChange}
131
147
  mentionedUsers={mentionedUsers}
148
+ VoiceMessageInput={props.VoiceMessageInput ?? VoiceMessageInput}
132
149
  AttachmentsButton={props.AttachmentsButton ?? AttachmentsButton}
150
+ MessageToReplyPreview={props.MessageToReplyPreview ?? MessageToReplyPreview}
151
+ style={textInputStyle}
133
152
  />
134
153
  )}
135
154
  {inputMode === 'edit' && messageToEdit && (
@@ -144,6 +163,7 @@ const ChannelInput = (props: ChannelInputProps) => {
144
163
  mentionedUsers={mentionedUsers}
145
164
  messageToEdit={messageToEdit}
146
165
  setMessageToEdit={setMessageToEdit}
166
+ style={textInputStyle}
147
167
  />
148
168
  )}
149
169
  </View>
@@ -181,7 +201,7 @@ const useTextClearOnDisabled = (setText: (val: string) => void, chatDisabled: bo
181
201
  };
182
202
 
183
203
  const useAutoFocusOnEditMode = (
184
- textInputRef: MutableRefObject<TextInput | undefined>,
204
+ textInputRef: React.MutableRefObject<TextInput | undefined>,
185
205
  messageToEdit?: SendbirdBaseMessage,
186
206
  ) => {
187
207
  useEffect(() => {
@@ -203,6 +223,17 @@ const styles = createStyleSheet({
203
223
  inputDefault: {
204
224
  height: 56,
205
225
  },
226
+ input: {
227
+ flex: 1,
228
+ marginRight: 4,
229
+ borderRadius: 20,
230
+ paddingTop: 8,
231
+ paddingBottom: 8,
232
+ minHeight: 36,
233
+ // Android - padding area is hidden
234
+ // iOS - padding area is visible
235
+ maxHeight: Platform.select({ ios: 36 * 2 + 16, android: 36 * 2 }),
236
+ },
206
237
  });
207
238
 
208
239
  export default React.memo(ChannelInput);
@@ -22,6 +22,7 @@ import {
22
22
  getFileExtension,
23
23
  getFileType,
24
24
  isMyMessage,
25
+ isVoiceMessage,
25
26
  messageKeyExtractor,
26
27
  shouldRenderReaction,
27
28
  toMegabyte,
@@ -35,8 +36,9 @@ import type { CommonComponent } from '../../types';
35
36
  import ChatFlatList from '../ChatFlatList';
36
37
  import { ReactionAddons } from '../ReactionAddons';
37
38
 
38
- type PressActions = { onPress?: () => void; onLongPress?: () => void };
39
+ type PressActions = { onPress?: () => void; onLongPress?: () => void; bottomSheetItem?: BottomSheetItem };
39
40
  type HandleableMessage = SendbirdUserMessage | SendbirdFileMessage;
41
+ type CreateMessagePressActions = (params: { message: SendbirdMessage }) => PressActions;
40
42
  export type ChannelMessageListProps<T extends SendbirdGroupChannel | SendbirdOpenChannel> = {
41
43
  enableMessageGrouping: boolean;
42
44
  currentUserId?: string;
@@ -73,6 +75,8 @@ export type ChannelMessageListProps<T extends SendbirdGroupChannel | SendbirdOpe
73
75
  channel: T;
74
76
  currentUserId?: ChannelMessageListProps<T>['currentUserId'];
75
77
  enableMessageGrouping: ChannelMessageListProps<T>['enableMessageGrouping'];
78
+ bottomSheetItem?: BottomSheetItem;
79
+ isFirstItem: boolean;
76
80
  }) => React.ReactElement | null;
77
81
  renderNewMessagesButton: null | CommonComponent<{
78
82
  visible: boolean;
@@ -120,7 +124,7 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
120
124
  const { colors } = useUIKitTheme();
121
125
  const { show } = useUserProfile();
122
126
  const { left, right } = useSafeAreaInsets();
123
- const getMessagePressActions = useGetMessagePressActions({
127
+ const createMessagePressActions = useCreateMessagePressActions({
124
128
  channel,
125
129
  currentUserId,
126
130
  onEditMessage,
@@ -133,7 +137,7 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
133
137
  const safeAreaLayout = { paddingLeft: left, paddingRight: right };
134
138
 
135
139
  const renderItem: ListRenderItem<SendbirdMessage> = useFreshCallback(({ item, index }) => {
136
- const { onPress, onLongPress } = getMessagePressActions(item);
140
+ const { onPress, onLongPress, bottomSheetItem } = createMessagePressActions({ message: item });
137
141
  return renderMessage({
138
142
  message: item,
139
143
  prevMessage: messages[index + 1],
@@ -146,6 +150,8 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
146
150
  channel,
147
151
  currentUserId,
148
152
  focused: (searchItem?.startingPoint ?? -1) === item.createdAt,
153
+ bottomSheetItem,
154
+ isFirstItem: index === 0,
149
155
  });
150
156
  });
151
157
 
@@ -190,7 +196,7 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
190
196
  );
191
197
  };
192
198
 
193
- const useGetMessagePressActions = <T extends SendbirdGroupChannel | SendbirdOpenChannel>({
199
+ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdOpenChannel>({
194
200
  channel,
195
201
  currentUserId,
196
202
  onResendFailedMessage,
@@ -207,7 +213,7 @@ const useGetMessagePressActions = <T extends SendbirdGroupChannel | SendbirdOpen
207
213
  | 'onDeleteMessage'
208
214
  | 'onResendFailedMessage'
209
215
  | 'onPressMediaMessage'
210
- >) => {
216
+ >): CreateMessagePressActions => {
211
217
  const { colors } = useUIKitTheme();
212
218
  const { STRINGS } = useLocalization();
213
219
  const toast = useToast();
@@ -216,160 +222,186 @@ const useGetMessagePressActions = <T extends SendbirdGroupChannel | SendbirdOpen
216
222
  const { clipboardService, fileService } = usePlatformService();
217
223
  const { sbOptions } = useSendbirdChat();
218
224
 
219
- const onFailureToReSend = (error: Error) => {
225
+ const onResendFailure = (error: Error) => {
220
226
  toast.show(STRINGS.TOAST.RESEND_MSG_ERROR, 'error');
221
227
  Logger.error(STRINGS.TOAST.RESEND_MSG_ERROR, error);
222
228
  };
223
229
 
224
- const handleFailedMessage = (message: HandleableMessage) => {
230
+ const onDeleteFailure = (error: Error) => {
231
+ toast.show(STRINGS.TOAST.DELETE_MSG_ERROR, 'error');
232
+ Logger.error(STRINGS.TOAST.DELETE_MSG_ERROR, error);
233
+ };
234
+
235
+ const onCopyText = (message: HandleableMessage) => {
236
+ if (message.isUserMessage()) {
237
+ clipboardService.setString(message.message || '');
238
+ toast.show(STRINGS.TOAST.COPY_OK, 'success');
239
+ }
240
+ };
241
+
242
+ const onDownloadFile = (message: HandleableMessage) => {
243
+ if (message.isFileMessage()) {
244
+ if (toMegabyte(message.size) > 4) {
245
+ toast.show(STRINGS.TOAST.DOWNLOAD_START, 'success');
246
+ }
247
+
248
+ fileService
249
+ .save({ fileUrl: message.url, fileName: message.name, fileType: message.type })
250
+ .then((response) => {
251
+ toast.show(STRINGS.TOAST.DOWNLOAD_OK, 'success');
252
+ Logger.log('File saved to', response);
253
+ })
254
+ .catch((err) => {
255
+ toast.show(STRINGS.TOAST.DOWNLOAD_ERROR, 'error');
256
+ Logger.log('File save failure', err);
257
+ });
258
+ }
259
+ };
260
+
261
+ const onOpenFile = (message: HandleableMessage) => {
262
+ if (message.isFileMessage()) {
263
+ const fileType = getFileType(message.type || getFileExtension(message.name));
264
+ if (['image', 'video', 'audio'].includes(fileType)) {
265
+ onPressMediaMessage?.(message, () => onDeleteMessage(message), getAvailableUriFromFileMessage(message));
266
+ } else {
267
+ SBUUtils.openURL(message.url);
268
+ }
269
+ }
270
+ };
271
+
272
+ const openSheetForFailedMessage = (message: HandleableMessage) => {
225
273
  openSheet({
226
274
  sheetItems: [
227
275
  {
228
276
  title: STRINGS.LABELS.CHANNEL_MESSAGE_FAILED_RETRY,
229
- onPress: () => {
230
- onResendFailedMessage(message).catch(onFailureToReSend);
231
- },
277
+ onPress: () => onResendFailedMessage(message).catch(onResendFailure),
232
278
  },
233
279
  {
234
280
  title: STRINGS.LABELS.CHANNEL_MESSAGE_FAILED_REMOVE,
235
281
  titleColor: colors.ui.dialog.default.none.destructive,
236
- onPress: () => confirmDelete(message),
282
+ onPress: () => alertForMessageDelete(message),
237
283
  },
238
284
  ],
239
285
  });
240
286
  };
241
- const confirmDelete = (message: HandleableMessage) => {
287
+
288
+ const alertForMessageDelete = (message: HandleableMessage) => {
242
289
  alert({
243
290
  title: STRINGS.LABELS.CHANNEL_MESSAGE_DELETE_CONFIRM_TITLE,
244
291
  buttons: [
245
- {
246
- text: STRINGS.LABELS.CHANNEL_MESSAGE_DELETE_CONFIRM_CANCEL,
247
- },
292
+ { text: STRINGS.LABELS.CHANNEL_MESSAGE_DELETE_CONFIRM_CANCEL },
248
293
  {
249
294
  text: STRINGS.LABELS.CHANNEL_MESSAGE_DELETE_CONFIRM_OK,
250
295
  style: 'destructive',
251
296
  onPress: () => {
252
- onDeleteMessage(message).catch(() => toast.show(STRINGS.TOAST.DELETE_MSG_ERROR, 'error'));
297
+ onDeleteMessage(message).catch(onDeleteFailure);
253
298
  },
254
299
  },
255
300
  ],
256
301
  });
257
302
  };
258
303
 
259
- return (msg: SendbirdMessage) => {
260
- if (!msg.isUserMessage() && !msg.isFileMessage()) {
261
- return { onPress: undefined, onLongPress: undefined };
262
- }
304
+ return ({ message }) => {
305
+ if (!message.isUserMessage() && !message.isFileMessage()) return {};
263
306
 
264
307
  const sheetItems: BottomSheetItem['sheetItems'] = [];
265
- const response: PressActions = {
266
- onPress: undefined,
267
- onLongPress: undefined,
268
- };
269
-
270
- if (msg.isUserMessage()) {
271
- sheetItems.push({
272
- icon: 'copy',
308
+ const menu = {
309
+ copy: (message: HandleableMessage) => ({
310
+ icon: 'copy' as const,
273
311
  title: STRINGS.LABELS.CHANNEL_MESSAGE_COPY,
274
- onPress: () => {
275
- clipboardService.setString(msg.message || '');
276
- toast.show(STRINGS.TOAST.COPY_OK, 'success');
277
- },
278
- });
279
- }
280
- if (msg.isFileMessage()) {
281
- sheetItems.push({
282
- icon: 'download',
312
+ onPress: () => onCopyText(message),
313
+ }),
314
+ edit: (message: HandleableMessage) => ({
315
+ icon: 'edit' as const,
316
+ title: STRINGS.LABELS.CHANNEL_MESSAGE_EDIT,
317
+ onPress: () => onEditMessage(message),
318
+ }),
319
+ delete: (message: HandleableMessage) => ({
320
+ disabled: message.threadInfo ? message.threadInfo.replyCount > 0 : undefined,
321
+ icon: 'delete' as const,
322
+ title: STRINGS.LABELS.CHANNEL_MESSAGE_DELETE,
323
+ onPress: () => alertForMessageDelete(message),
324
+ }),
325
+ reply: (message: HandleableMessage) => ({
326
+ disabled: Boolean(message.parentMessageId),
327
+ icon: 'reply' as const,
328
+ title: STRINGS.LABELS.CHANNEL_MESSAGE_REPLY,
329
+ onPress: () => onReplyMessage?.(message),
330
+ }),
331
+ download: (message: HandleableMessage) => ({
332
+ icon: 'download' as const,
283
333
  title: STRINGS.LABELS.CHANNEL_MESSAGE_SAVE,
284
- onPress: async () => {
285
- if (toMegabyte(msg.size) > 4) {
286
- toast.show(STRINGS.TOAST.DOWNLOAD_START, 'success');
287
- }
334
+ onPress: () => onDownloadFile(message),
335
+ }),
336
+ };
288
337
 
289
- fileService
290
- .save({ fileUrl: msg.url, fileName: msg.name, fileType: msg.type })
291
- .then((response) => {
292
- toast.show(STRINGS.TOAST.DOWNLOAD_OK, 'success');
293
- Logger.log('File saved to', response);
294
- })
295
- .catch((err) => {
296
- toast.show(STRINGS.TOAST.DOWNLOAD_ERROR, 'error');
297
- Logger.log('File save failure', err);
298
- });
299
- },
300
- });
301
- }
302
- if (!channel.isEphemeral) {
303
- if (isMyMessage(msg, currentUserId) && msg.sendingStatus === 'succeeded') {
304
- if (msg.isUserMessage()) {
305
- sheetItems.push({
306
- icon: 'edit',
307
- title: STRINGS.LABELS.CHANNEL_MESSAGE_EDIT,
308
- onPress: () => onEditMessage(msg),
309
- });
338
+ if (message.isUserMessage()) {
339
+ sheetItems.push(menu.copy(message));
340
+ if (!channel.isEphemeral) {
341
+ if (isMyMessage(message, currentUserId) && message.sendingStatus === 'succeeded') {
342
+ sheetItems.push(menu.edit(message));
343
+ sheetItems.push(menu.delete(message));
344
+ }
345
+ if (channel.isGroupChannel() && sbOptions.uikit.groupChannel.channel.replyType === 'quote_reply') {
346
+ sheetItems.push(menu.reply(message));
310
347
  }
311
- sheetItems.push({
312
- disabled: msg.threadInfo ? msg.threadInfo.replyCount > 0 : undefined,
313
- icon: 'delete',
314
- title: STRINGS.LABELS.CHANNEL_MESSAGE_DELETE,
315
- onPress: () => confirmDelete(msg),
316
- });
317
- }
318
- if (channel.isGroupChannel() && sbOptions.uikit.groupChannel.channel.replyType === 'quote_reply') {
319
- sheetItems.push({
320
- disabled: Boolean(msg.parentMessageId),
321
- icon: 'reply',
322
- title: STRINGS.LABELS.CHANNEL_MESSAGE_REPLY,
323
- onPress: () => onReplyMessage?.(msg),
324
- });
325
348
  }
326
349
  }
327
350
 
328
- if (msg.isFileMessage()) {
329
- const fileType = getFileType(msg.type || getFileExtension(msg.name));
330
- switch (fileType) {
331
- case 'image':
332
- case 'video':
333
- case 'audio': {
334
- response.onPress = () => {
335
- onPressMediaMessage?.(msg, () => onDeleteMessage(msg), getAvailableUriFromFileMessage(msg));
336
- };
337
- break;
351
+ if (message.isFileMessage()) {
352
+ if (!isVoiceMessage(message)) {
353
+ sheetItems.push(menu.download(message));
354
+ }
355
+ if (!channel.isEphemeral) {
356
+ if (isMyMessage(message, currentUserId) && message.sendingStatus === 'succeeded') {
357
+ sheetItems.push(menu.delete(message));
338
358
  }
339
- default: {
340
- response.onPress = () => SBUUtils.openURL(msg.url);
341
- break;
359
+ if (channel.isGroupChannel() && sbOptions.uikit.groupChannel.channel.replyType === 'quote_reply') {
360
+ sheetItems.push(menu.reply(message));
342
361
  }
343
362
  }
344
363
  }
345
364
 
346
- if (sheetItems.length > 0) {
347
- response.onLongPress = () => {
348
- openSheet({
349
- sheetItems,
350
- HeaderComponent: shouldRenderReaction(
351
- channel,
352
- sbOptions.uikitWithAppInfo.groupChannel.channel.enableReactions,
353
- )
354
- ? ({ onClose }) => <ReactionAddons.BottomSheet message={msg} channel={channel} onClose={onClose} />
355
- : undefined,
356
- });
357
- };
358
- }
365
+ const bottomSheetItem: BottomSheetItem = {
366
+ sheetItems,
367
+ HeaderComponent: shouldRenderReaction(channel, sbOptions.uikitWithAppInfo.groupChannel.channel.enableReactions)
368
+ ? ({ onClose }) => <ReactionAddons.BottomSheet message={message} channel={channel} onClose={onClose} />
369
+ : undefined,
370
+ };
359
371
 
360
- if (msg.sendingStatus === 'failed') {
361
- response.onLongPress = () => handleFailedMessage(msg);
362
- response.onPress = () => {
363
- onResendFailedMessage(msg).catch(onFailureToReSend);
364
- };
365
- }
372
+ switch (true) {
373
+ case message.sendingStatus === 'pending': {
374
+ return {
375
+ onPress: undefined,
376
+ onLongPress: undefined,
377
+ bottomSheetItem: undefined,
378
+ };
379
+ }
366
380
 
367
- if (msg.sendingStatus === 'pending') {
368
- response.onLongPress = undefined;
369
- response.onPress = undefined;
370
- }
381
+ case message.sendingStatus === 'failed': {
382
+ return {
383
+ onPress: () => onResendFailedMessage(message).catch(onResendFailure),
384
+ onLongPress: () => openSheetForFailedMessage(message),
385
+ bottomSheetItem,
386
+ };
387
+ }
388
+
389
+ case message.isFileMessage(): {
390
+ return {
391
+ onPress: () => onOpenFile(message),
392
+ onLongPress: () => openSheet(bottomSheetItem),
393
+ bottomSheetItem,
394
+ };
395
+ }
371
396
 
372
- return response;
397
+ default: {
398
+ return {
399
+ onPress: undefined,
400
+ onLongPress: () => openSheet(bottomSheetItem),
401
+ bottomSheetItem,
402
+ };
403
+ }
404
+ }
373
405
  };
374
406
  };
375
407