@sendbird/uikit-react-native 3.5.4 → 3.7.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 (251) hide show
  1. package/README.md +11 -27
  2. package/lib/commonjs/components/ChannelInput/SendInput.js +23 -6
  3. package/lib/commonjs/components/ChannelInput/SendInput.js.map +1 -1
  4. package/lib/commonjs/components/ChannelInput/index.js.map +1 -1
  5. package/lib/commonjs/components/ChannelMessageList/index.js +22 -4
  6. package/lib/commonjs/components/ChannelMessageList/index.js.map +1 -1
  7. package/lib/commonjs/components/ChannelThreadMessageList/index.js +349 -0
  8. package/lib/commonjs/components/ChannelThreadMessageList/index.js.map +1 -0
  9. package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js +2 -2
  10. package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js.map +1 -1
  11. package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageReplyInfo.js +100 -0
  12. package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageReplyInfo.js.map +1 -0
  13. package/lib/commonjs/components/GroupChannelMessageRenderer/index.js +24 -6
  14. package/lib/commonjs/components/GroupChannelMessageRenderer/index.js.map +1 -1
  15. package/lib/commonjs/components/ReactionAddons/MessageReactionAddon.js +23 -6
  16. package/lib/commonjs/components/ReactionAddons/MessageReactionAddon.js.map +1 -1
  17. package/lib/commonjs/components/ThreadChatFlatList/index.js +76 -0
  18. package/lib/commonjs/components/ThreadChatFlatList/index.js.map +1 -0
  19. package/lib/commonjs/components/ThreadParentMessageRenderer/ThreadParentMessage.file.image.js +41 -0
  20. package/lib/commonjs/components/ThreadParentMessageRenderer/ThreadParentMessage.file.image.js.map +1 -0
  21. package/lib/commonjs/components/ThreadParentMessageRenderer/ThreadParentMessage.file.js +74 -0
  22. package/lib/commonjs/components/ThreadParentMessageRenderer/ThreadParentMessage.file.js.map +1 -0
  23. package/lib/commonjs/components/ThreadParentMessageRenderer/ThreadParentMessage.file.video.js +42 -0
  24. package/lib/commonjs/components/ThreadParentMessageRenderer/ThreadParentMessage.file.video.js.map +1 -0
  25. package/lib/commonjs/components/ThreadParentMessageRenderer/ThreadParentMessage.file.voice.js +94 -0
  26. package/lib/commonjs/components/ThreadParentMessageRenderer/ThreadParentMessage.file.voice.js.map +1 -0
  27. package/lib/commonjs/components/ThreadParentMessageRenderer/ThreadParentMessage.user.js +61 -0
  28. package/lib/commonjs/components/ThreadParentMessageRenderer/ThreadParentMessage.user.js.map +1 -0
  29. package/lib/commonjs/components/ThreadParentMessageRenderer/ThreadParentMessage.user.og.js +127 -0
  30. package/lib/commonjs/components/ThreadParentMessageRenderer/ThreadParentMessage.user.og.js.map +1 -0
  31. package/lib/commonjs/components/ThreadParentMessageRenderer/index.js +206 -0
  32. package/lib/commonjs/components/ThreadParentMessageRenderer/index.js.map +1 -0
  33. package/lib/commonjs/containers/SendbirdUIKitContainer.js +12 -11
  34. package/lib/commonjs/containers/SendbirdUIKitContainer.js.map +1 -1
  35. package/lib/commonjs/contexts/SendbirdChatCtx.js +7 -0
  36. package/lib/commonjs/contexts/SendbirdChatCtx.js.map +1 -1
  37. package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js +28 -5
  38. package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
  39. package/lib/commonjs/domain/groupChannel/module/moduleContext.js +14 -4
  40. package/lib/commonjs/domain/groupChannel/module/moduleContext.js.map +1 -1
  41. package/lib/commonjs/domain/groupChannel/types.js.map +1 -1
  42. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadHeader.js +82 -0
  43. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadHeader.js.map +1 -0
  44. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadInput.js +44 -0
  45. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadInput.js.map +1 -0
  46. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadMessageList.js +127 -0
  47. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadMessageList.js.map +1 -0
  48. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadParentMessageInfo.js +315 -0
  49. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadParentMessageInfo.js.map +1 -0
  50. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadStatusEmpty.js +27 -0
  51. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadStatusEmpty.js.map +1 -0
  52. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadStatusLoading.js +27 -0
  53. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadStatusLoading.js.map +1 -0
  54. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadSuggestedMentionList.js +195 -0
  55. package/lib/commonjs/domain/groupChannelThread/component/GroupChannelThreadSuggestedMentionList.js.map +1 -0
  56. package/lib/commonjs/domain/groupChannelThread/index.js +69 -0
  57. package/lib/commonjs/domain/groupChannelThread/index.js.map +1 -0
  58. package/lib/commonjs/domain/groupChannelThread/module/createGroupChannelThreadModule.js +42 -0
  59. package/lib/commonjs/domain/groupChannelThread/module/createGroupChannelThreadModule.js.map +1 -0
  60. package/lib/commonjs/domain/groupChannelThread/module/moduleContext.js +148 -0
  61. package/lib/commonjs/domain/groupChannelThread/module/moduleContext.js.map +1 -0
  62. package/lib/commonjs/domain/groupChannelThread/types.js +6 -0
  63. package/lib/commonjs/domain/groupChannelThread/types.js.map +1 -0
  64. package/lib/commonjs/fragments/createGroupChannelFragment.js +30 -5
  65. package/lib/commonjs/fragments/createGroupChannelFragment.js.map +1 -1
  66. package/lib/commonjs/fragments/createGroupChannelThreadFragment.js +267 -0
  67. package/lib/commonjs/fragments/createGroupChannelThreadFragment.js.map +1 -0
  68. package/lib/commonjs/hooks/useMentionSuggestion.js +5 -2
  69. package/lib/commonjs/hooks/useMentionSuggestion.js.map +1 -1
  70. package/lib/commonjs/index.js +72 -40
  71. package/lib/commonjs/index.js.map +1 -1
  72. package/lib/commonjs/libs/EmojiManager.js.map +1 -1
  73. package/lib/commonjs/libs/InternalLocalCacheStorage.js +65 -19
  74. package/lib/commonjs/libs/InternalLocalCacheStorage.js.map +1 -1
  75. package/lib/commonjs/libs/VoiceMessageStatusManager.js +66 -0
  76. package/lib/commonjs/libs/VoiceMessageStatusManager.js.map +1 -0
  77. package/lib/commonjs/localization/StringSet.type.js.map +1 -1
  78. package/lib/commonjs/localization/createBaseStringSet.js +25 -3
  79. package/lib/commonjs/localization/createBaseStringSet.js.map +1 -1
  80. package/lib/commonjs/platform/createMediaService.native.js.map +1 -1
  81. package/lib/commonjs/types.js.map +1 -1
  82. package/lib/commonjs/version.js +1 -1
  83. package/lib/commonjs/version.js.map +1 -1
  84. package/lib/module/components/ChannelInput/SendInput.js +23 -6
  85. package/lib/module/components/ChannelInput/SendInput.js.map +1 -1
  86. package/lib/module/components/ChannelInput/index.js.map +1 -1
  87. package/lib/module/components/ChannelMessageList/index.js +22 -4
  88. package/lib/module/components/ChannelMessageList/index.js.map +1 -1
  89. package/lib/module/components/ChannelThreadMessageList/index.js +341 -0
  90. package/lib/module/components/ChannelThreadMessageList/index.js.map +1 -0
  91. package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js +2 -2
  92. package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js.map +1 -1
  93. package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageReplyInfo.js +92 -0
  94. package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageReplyInfo.js.map +1 -0
  95. package/lib/module/components/GroupChannelMessageRenderer/index.js +24 -6
  96. package/lib/module/components/GroupChannelMessageRenderer/index.js.map +1 -1
  97. package/lib/module/components/ReactionAddons/MessageReactionAddon.js +23 -6
  98. package/lib/module/components/ReactionAddons/MessageReactionAddon.js.map +1 -1
  99. package/lib/module/components/ThreadChatFlatList/index.js +66 -0
  100. package/lib/module/components/ThreadChatFlatList/index.js.map +1 -0
  101. package/lib/module/components/ThreadParentMessageRenderer/ThreadParentMessage.file.image.js +34 -0
  102. package/lib/module/components/ThreadParentMessageRenderer/ThreadParentMessage.file.image.js.map +1 -0
  103. package/lib/module/components/ThreadParentMessageRenderer/ThreadParentMessage.file.js +67 -0
  104. package/lib/module/components/ThreadParentMessageRenderer/ThreadParentMessage.file.js.map +1 -0
  105. package/lib/module/components/ThreadParentMessageRenderer/ThreadParentMessage.file.video.js +34 -0
  106. package/lib/module/components/ThreadParentMessageRenderer/ThreadParentMessage.file.video.js.map +1 -0
  107. package/lib/module/components/ThreadParentMessageRenderer/ThreadParentMessage.file.voice.js +87 -0
  108. package/lib/module/components/ThreadParentMessageRenderer/ThreadParentMessage.file.voice.js.map +1 -0
  109. package/lib/module/components/ThreadParentMessageRenderer/ThreadParentMessage.user.js +54 -0
  110. package/lib/module/components/ThreadParentMessageRenderer/ThreadParentMessage.user.js.map +1 -0
  111. package/lib/module/components/ThreadParentMessageRenderer/ThreadParentMessage.user.og.js +119 -0
  112. package/lib/module/components/ThreadParentMessageRenderer/ThreadParentMessage.user.og.js.map +1 -0
  113. package/lib/module/components/ThreadParentMessageRenderer/index.js +196 -0
  114. package/lib/module/components/ThreadParentMessageRenderer/index.js.map +1 -0
  115. package/lib/module/containers/SendbirdUIKitContainer.js +13 -12
  116. package/lib/module/containers/SendbirdUIKitContainer.js.map +1 -1
  117. package/lib/module/contexts/SendbirdChatCtx.js +6 -0
  118. package/lib/module/contexts/SendbirdChatCtx.js.map +1 -1
  119. package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js +30 -6
  120. package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
  121. package/lib/module/domain/groupChannel/module/moduleContext.js +14 -4
  122. package/lib/module/domain/groupChannel/module/moduleContext.js.map +1 -1
  123. package/lib/module/domain/groupChannel/types.js.map +1 -1
  124. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadHeader.js +73 -0
  125. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadHeader.js.map +1 -0
  126. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadInput.js +34 -0
  127. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadInput.js.map +1 -0
  128. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadMessageList.js +117 -0
  129. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadMessageList.js.map +1 -0
  130. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadParentMessageInfo.js +305 -0
  131. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadParentMessageInfo.js.map +1 -0
  132. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadStatusEmpty.js +19 -0
  133. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadStatusEmpty.js.map +1 -0
  134. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadStatusLoading.js +19 -0
  135. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadStatusLoading.js.map +1 -0
  136. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadSuggestedMentionList.js +185 -0
  137. package/lib/module/domain/groupChannelThread/component/GroupChannelThreadSuggestedMentionList.js.map +1 -0
  138. package/lib/module/domain/groupChannelThread/index.js +9 -0
  139. package/lib/module/domain/groupChannelThread/index.js.map +1 -0
  140. package/lib/module/domain/groupChannelThread/module/createGroupChannelThreadModule.js +34 -0
  141. package/lib/module/domain/groupChannelThread/module/createGroupChannelThreadModule.js.map +1 -0
  142. package/lib/module/domain/groupChannelThread/module/moduleContext.js +137 -0
  143. package/lib/module/domain/groupChannelThread/module/moduleContext.js.map +1 -0
  144. package/lib/module/domain/groupChannelThread/types.js +2 -0
  145. package/lib/module/domain/groupChannelThread/types.js.map +1 -0
  146. package/lib/module/fragments/createGroupChannelFragment.js +33 -7
  147. package/lib/module/fragments/createGroupChannelFragment.js.map +1 -1
  148. package/lib/module/fragments/createGroupChannelThreadFragment.js +257 -0
  149. package/lib/module/fragments/createGroupChannelThreadFragment.js.map +1 -0
  150. package/lib/module/hooks/useMentionSuggestion.js +5 -2
  151. package/lib/module/hooks/useMentionSuggestion.js.map +1 -1
  152. package/lib/module/index.js +3 -0
  153. package/lib/module/index.js.map +1 -1
  154. package/lib/module/libs/EmojiManager.js.map +1 -1
  155. package/lib/module/libs/InternalLocalCacheStorage.js +65 -19
  156. package/lib/module/libs/InternalLocalCacheStorage.js.map +1 -1
  157. package/lib/module/libs/VoiceMessageStatusManager.js +59 -0
  158. package/lib/module/libs/VoiceMessageStatusManager.js.map +1 -0
  159. package/lib/module/localization/StringSet.type.js.map +1 -1
  160. package/lib/module/localization/createBaseStringSet.js +27 -4
  161. package/lib/module/localization/createBaseStringSet.js.map +1 -1
  162. package/lib/module/platform/createMediaService.native.js.map +1 -1
  163. package/lib/module/types.js.map +1 -1
  164. package/lib/module/version.js +1 -1
  165. package/lib/module/version.js.map +1 -1
  166. package/lib/typescript/src/components/ChannelInput/index.d.ts +1 -0
  167. package/lib/typescript/src/components/ChannelMessageList/index.d.ts +5 -2
  168. package/lib/typescript/src/components/ChannelThreadMessageList/index.d.ts +55 -0
  169. package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.d.ts +1 -1
  170. package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageReplyInfo.d.ts +9 -0
  171. package/lib/typescript/src/components/GroupChannelMessageRenderer/index.d.ts +3 -1
  172. package/lib/typescript/src/components/OpenChannelMessageRenderer/index.d.ts +3 -1
  173. package/lib/typescript/src/components/ReactionAddons/MessageReactionAddon.d.ts +3 -1
  174. package/lib/typescript/src/components/ReactionAddons/index.d.ts +2 -1
  175. package/lib/typescript/src/components/ThreadChatFlatList/index.d.ts +9 -0
  176. package/lib/typescript/src/components/ThreadParentMessageRenderer/ThreadParentMessage.file.d.ts +4 -0
  177. package/lib/typescript/src/components/ThreadParentMessageRenderer/ThreadParentMessage.file.image.d.ts +4 -0
  178. package/lib/typescript/src/components/ThreadParentMessageRenderer/ThreadParentMessage.file.video.d.ts +9 -0
  179. package/lib/typescript/src/components/ThreadParentMessageRenderer/ThreadParentMessage.file.voice.d.ts +13 -0
  180. package/lib/typescript/src/components/ThreadParentMessageRenderer/ThreadParentMessage.user.d.ts +10 -0
  181. package/lib/typescript/src/components/ThreadParentMessageRenderer/ThreadParentMessage.user.og.d.ts +10 -0
  182. package/lib/typescript/src/components/ThreadParentMessageRenderer/index.d.ts +20 -0
  183. package/lib/typescript/src/containers/SendbirdUIKitContainer.d.ts +8 -10
  184. package/lib/typescript/src/contexts/SendbirdChatCtx.d.ts +15 -1
  185. package/lib/typescript/src/domain/groupChannel/types.d.ts +4 -1
  186. package/lib/typescript/src/domain/groupChannelThread/component/GroupChannelThreadHeader.d.ts +4 -0
  187. package/lib/typescript/src/domain/groupChannelThread/component/GroupChannelThreadInput.d.ts +3 -0
  188. package/lib/typescript/src/domain/groupChannelThread/component/GroupChannelThreadMessageList.d.ts +7 -0
  189. package/lib/typescript/src/domain/groupChannelThread/component/GroupChannelThreadParentMessageInfo.d.ts +8 -0
  190. package/lib/typescript/src/domain/groupChannelThread/component/GroupChannelThreadStatusEmpty.d.ts +3 -0
  191. package/lib/typescript/src/domain/groupChannelThread/component/GroupChannelThreadStatusLoading.d.ts +3 -0
  192. package/lib/typescript/src/domain/groupChannelThread/component/GroupChannelThreadSuggestedMentionList.d.ts +4 -0
  193. package/lib/typescript/src/domain/groupChannelThread/index.d.ts +8 -0
  194. package/lib/typescript/src/domain/groupChannelThread/module/createGroupChannelThreadModule.d.ts +3 -0
  195. package/lib/typescript/src/domain/groupChannelThread/module/moduleContext.d.ts +3 -0
  196. package/lib/typescript/src/domain/groupChannelThread/types.d.ts +136 -0
  197. package/lib/typescript/src/domain/openChannel/component/OpenChannelHeader.d.ts +1 -1
  198. package/lib/typescript/src/fragments/createGroupChannelThreadFragment.d.ts +5 -0
  199. package/lib/typescript/src/hooks/useChannelInputItems.d.ts +1 -1
  200. package/lib/typescript/src/index.d.ts +3 -0
  201. package/lib/typescript/src/libs/InternalLocalCacheStorage.d.ts +5 -4
  202. package/lib/typescript/src/libs/VoiceMessageStatusManager.d.ts +11 -0
  203. package/lib/typescript/src/localization/StringSet.type.d.ts +23 -0
  204. package/lib/typescript/src/localization/createBaseStringSet.d.ts +1 -1
  205. package/lib/typescript/src/types.d.ts +4 -1
  206. package/lib/typescript/src/version.d.ts +1 -1
  207. package/package.json +27 -22
  208. package/src/components/ChannelInput/SendInput.tsx +24 -5
  209. package/src/components/ChannelInput/index.tsx +1 -0
  210. package/src/components/ChannelMessageList/index.tsx +27 -5
  211. package/src/components/ChannelThreadMessageList/index.tsx +406 -0
  212. package/src/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.tsx +3 -3
  213. package/src/components/GroupChannelMessageRenderer/GroupChannelMessageReplyInfo.tsx +96 -0
  214. package/src/components/GroupChannelMessageRenderer/index.tsx +21 -5
  215. package/src/components/ReactionAddons/MessageReactionAddon.tsx +38 -5
  216. package/src/components/ThreadChatFlatList/index.tsx +63 -0
  217. package/src/components/ThreadParentMessageRenderer/ThreadParentMessage.file.image.tsx +36 -0
  218. package/src/components/ThreadParentMessageRenderer/ThreadParentMessage.file.tsx +61 -0
  219. package/src/components/ThreadParentMessageRenderer/ThreadParentMessage.file.video.tsx +45 -0
  220. package/src/components/ThreadParentMessageRenderer/ThreadParentMessage.file.voice.tsx +107 -0
  221. package/src/components/ThreadParentMessageRenderer/ThreadParentMessage.user.og.tsx +133 -0
  222. package/src/components/ThreadParentMessageRenderer/ThreadParentMessage.user.tsx +65 -0
  223. package/src/components/ThreadParentMessageRenderer/index.tsx +194 -0
  224. package/src/containers/SendbirdUIKitContainer.tsx +28 -17
  225. package/src/contexts/SendbirdChatCtx.tsx +20 -0
  226. package/src/domain/groupChannel/component/GroupChannelMessageList.tsx +37 -8
  227. package/src/domain/groupChannel/module/moduleContext.tsx +12 -2
  228. package/src/domain/groupChannel/types.ts +5 -0
  229. package/src/domain/groupChannelThread/component/GroupChannelThreadHeader.tsx +63 -0
  230. package/src/domain/groupChannelThread/component/GroupChannelThreadInput.tsx +38 -0
  231. package/src/domain/groupChannelThread/component/GroupChannelThreadMessageList.tsx +105 -0
  232. package/src/domain/groupChannelThread/component/GroupChannelThreadParentMessageInfo.tsx +326 -0
  233. package/src/domain/groupChannelThread/component/GroupChannelThreadStatusEmpty.tsx +18 -0
  234. package/src/domain/groupChannelThread/component/GroupChannelThreadStatusLoading.tsx +18 -0
  235. package/src/domain/groupChannelThread/component/GroupChannelThreadSuggestedMentionList.tsx +174 -0
  236. package/src/domain/groupChannelThread/index.ts +8 -0
  237. package/src/domain/groupChannelThread/module/createGroupChannelThreadModule.tsx +35 -0
  238. package/src/domain/groupChannelThread/module/moduleContext.tsx +165 -0
  239. package/src/domain/groupChannelThread/types.ts +184 -0
  240. package/src/fragments/createGroupChannelFragment.tsx +38 -8
  241. package/src/fragments/createGroupChannelThreadFragment.tsx +280 -0
  242. package/src/hooks/useMentionSuggestion.ts +13 -9
  243. package/src/index.ts +4 -0
  244. package/src/libs/EmojiManager.ts +2 -2
  245. package/src/libs/InternalLocalCacheStorage.ts +70 -21
  246. package/src/libs/VoiceMessageStatusManager.ts +56 -0
  247. package/src/localization/StringSet.type.ts +27 -0
  248. package/src/localization/createBaseStringSet.ts +33 -4
  249. package/src/platform/createMediaService.native.tsx +9 -1
  250. package/src/types.ts +6 -1
  251. package/src/version.ts +1 -1
@@ -0,0 +1,194 @@
1
+ import React, { useRef } from 'react';
2
+
3
+ import { RegexTextPattern, Text, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
4
+ import {
5
+ SendbirdFileMessage,
6
+ type SendbirdUser,
7
+ SendbirdUserMessage,
8
+ getMessageType,
9
+ isMyMessage,
10
+ isVoiceMessage,
11
+ } from '@sendbird/uikit-utils';
12
+
13
+ import { VOICE_MESSAGE_META_ARRAY_DURATION_KEY } from '../../constants';
14
+ import SBUUtils from '../../libs/SBUUtils';
15
+ import { usePlatformService, useSendbirdChat } from './../../hooks/useContext';
16
+ import ThreadParentMessageFile from './ThreadParentMessage.file';
17
+ import ThreadParentMessageFileImage from './ThreadParentMessage.file.image';
18
+ import ThreadParentMessageFileVideo from './ThreadParentMessage.file.video';
19
+ import ThreadParentMessageFileVoice, { VoiceFileMessageState } from './ThreadParentMessage.file.voice';
20
+ import ThreadParentMessageUser from './ThreadParentMessage.user';
21
+ import ThreadParentMessageUserOg from './ThreadParentMessage.user.og';
22
+
23
+ export type ThreadParentMessageRendererProps<AdditionalProps = unknown> = {
24
+ parentMessage: SendbirdUserMessage | SendbirdFileMessage;
25
+ onPress?: () => void;
26
+ onLongPress?: () => void;
27
+ onPressURL?: (url: string) => void;
28
+ onPressMentionedUser?: (mentionedUser?: SendbirdUser) => void;
29
+ onToggleVoiceMessage?: (
30
+ state: VoiceFileMessageState,
31
+ setState: React.Dispatch<React.SetStateAction<VoiceFileMessageState>>,
32
+ ) => Promise<void>;
33
+ } & AdditionalProps;
34
+
35
+ const ThreadParentMessageRenderer = (props: ThreadParentMessageRendererProps) => {
36
+ const playerUnsubscribes = useRef<(() => void)[]>([]);
37
+ const { sbOptions, currentUser, mentionManager } = useSendbirdChat();
38
+ const { palette } = useUIKitTheme();
39
+ const { mediaService, playerService } = usePlatformService();
40
+ const parentMessage = props.parentMessage;
41
+
42
+ const resetPlayer = async () => {
43
+ playerUnsubscribes.current.forEach((unsubscribe) => {
44
+ try {
45
+ unsubscribe();
46
+ } catch {}
47
+ });
48
+ playerUnsubscribes.current.length = 0;
49
+ await playerService.reset();
50
+ };
51
+
52
+ const messageProps: ThreadParentMessageRendererProps = {
53
+ onPressURL: (url) => SBUUtils.openURL(url),
54
+ onToggleVoiceMessage: async (state, setState) => {
55
+ if (isVoiceMessage(parentMessage) && parentMessage.sendingStatus === 'succeeded') {
56
+ if (playerService.uri === parentMessage.url) {
57
+ if (playerService.state === 'playing') {
58
+ await playerService.pause();
59
+ } else {
60
+ await playerService.play(parentMessage.url);
61
+ }
62
+ } else {
63
+ if (playerService.state !== 'idle') {
64
+ await resetPlayer();
65
+ }
66
+
67
+ const shouldSeekToTime = state.duration > state.currentTime && state.currentTime > 0;
68
+ let seekFinished = !shouldSeekToTime;
69
+
70
+ const forPlayback = playerService.addPlaybackListener(({ stopped, currentTime, duration }) => {
71
+ if (seekFinished) {
72
+ setState((prevState) => ({ ...prevState, currentTime: stopped ? 0 : currentTime, duration }));
73
+ }
74
+ });
75
+ const forState = playerService.addStateListener((state) => {
76
+ switch (state) {
77
+ case 'preparing':
78
+ setState((prevState) => ({ ...prevState, status: 'preparing' }));
79
+ break;
80
+ case 'playing':
81
+ setState((prevState) => ({ ...prevState, status: 'playing' }));
82
+ break;
83
+ case 'idle':
84
+ case 'paused': {
85
+ setState((prevState) => ({ ...prevState, status: 'paused' }));
86
+ break;
87
+ }
88
+ case 'stopped':
89
+ setState((prevState) => ({ ...prevState, status: 'paused' }));
90
+ break;
91
+ }
92
+ });
93
+ playerUnsubscribes.current.push(forPlayback, forState);
94
+
95
+ await playerService.play(parentMessage.url);
96
+ if (shouldSeekToTime) {
97
+ await playerService.seek(state.currentTime);
98
+ seekFinished = true;
99
+ }
100
+ }
101
+ }
102
+ },
103
+ ...props,
104
+ };
105
+
106
+ const userMessageProps: {
107
+ renderRegexTextChildren: (message: SendbirdUserMessage) => string;
108
+ regexTextPatterns: RegexTextPattern[];
109
+ } = {
110
+ renderRegexTextChildren: (message) => {
111
+ if (
112
+ mentionManager.shouldUseMentionedMessageTemplate(message, sbOptions.uikit.groupChannel.channel.enableMention)
113
+ ) {
114
+ return message.mentionedMessageTemplate;
115
+ } else {
116
+ return message.message;
117
+ }
118
+ },
119
+ regexTextPatterns: [
120
+ {
121
+ regex: mentionManager.templateRegex,
122
+ replacer({ match, groups, parentProps, index, keyPrefix }) {
123
+ const user = parentMessage.mentionedUsers?.find((it) => it.userId === groups[2]);
124
+ if (user) {
125
+ const mentionColor =
126
+ !isMyMessage(parentMessage, currentUser?.userId) && user.userId === currentUser?.userId
127
+ ? palette.onBackgroundLight01
128
+ : parentProps?.color;
129
+
130
+ return (
131
+ <Text
132
+ {...parentProps}
133
+ key={`${keyPrefix}-${index}`}
134
+ color={mentionColor}
135
+ onPress={() => messageProps.onPressMentionedUser?.(user)}
136
+ onLongPress={messageProps.onLongPress}
137
+ style={[
138
+ parentProps?.style,
139
+ { fontWeight: '700' },
140
+ user.userId === currentUser?.userId && { backgroundColor: palette.highlight },
141
+ ]}
142
+ >
143
+ {`${mentionManager.asMentionedMessageText(user)}`}
144
+ </Text>
145
+ );
146
+ }
147
+ return match;
148
+ },
149
+ },
150
+ ],
151
+ };
152
+
153
+ switch (getMessageType(props.parentMessage)) {
154
+ case 'user': {
155
+ return <ThreadParentMessageUser {...userMessageProps} {...messageProps} />;
156
+ }
157
+ case 'user.opengraph': {
158
+ return <ThreadParentMessageUserOg {...userMessageProps} {...messageProps} />;
159
+ }
160
+ case 'file':
161
+ case 'file.audio': {
162
+ return <ThreadParentMessageFile {...messageProps} />;
163
+ }
164
+ case 'file.video': {
165
+ return (
166
+ <ThreadParentMessageFileVideo
167
+ fetchThumbnailFromVideoSource={(uri) => mediaService.getVideoThumbnail({ url: uri, timeMills: 1000 })}
168
+ {...messageProps}
169
+ />
170
+ );
171
+ }
172
+ case 'file.image': {
173
+ return <ThreadParentMessageFileImage {...messageProps} />;
174
+ }
175
+ case 'file.voice': {
176
+ return (
177
+ <ThreadParentMessageFileVoice
178
+ durationMetaArrayKey={VOICE_MESSAGE_META_ARRAY_DURATION_KEY}
179
+ onUnmount={() => {
180
+ if (isVoiceMessage(parentMessage) && playerService.uri === parentMessage.url) {
181
+ resetPlayer();
182
+ }
183
+ }}
184
+ {...messageProps}
185
+ />
186
+ );
187
+ }
188
+ default: {
189
+ return null;
190
+ }
191
+ }
192
+ };
193
+
194
+ export default React.memo(ThreadParentMessageRenderer);
@@ -1,5 +1,7 @@
1
+ import type { AsyncStorageStatic } from '@react-native-async-storage/async-storage';
1
2
  import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
2
3
  import { Platform } from 'react-native';
4
+ import type { MMKV } from 'react-native-mmkv';
3
5
  import { SafeAreaProvider } from 'react-native-safe-area-context';
4
6
 
5
7
  import SendbirdChat, { DeviceOsPlatform, SendbirdChatParams, SendbirdPlatform, SendbirdProduct } from '@sendbird/chat';
@@ -15,15 +17,17 @@ import {
15
17
  UIKitThemeProvider,
16
18
  } from '@sendbird/uikit-react-native-foundation';
17
19
  import { SBUConfig, UIKitConfigProvider } from '@sendbird/uikit-tools';
18
- import type {
20
+ import {
21
+ Logger,
22
+ NOOP,
19
23
  PartialDeep,
20
24
  SendbirdChatSDK,
21
25
  SendbirdGroupChannel,
22
26
  SendbirdGroupChannelCreateParams,
23
27
  SendbirdMember,
24
28
  SendbirdUser,
29
+ useIsFirstMount,
25
30
  } from '@sendbird/uikit-utils';
26
- import { NOOP, useIsFirstMount } from '@sendbird/uikit-utils';
27
31
 
28
32
  import { LocalizationContext, LocalizationProvider } from '../contexts/LocalizationCtx';
29
33
  import { PlatformServiceProvider } from '../contexts/PlatformServiceCtx';
@@ -38,6 +42,7 @@ import InternalLocalCacheStorage from '../libs/InternalLocalCacheStorage';
38
42
  import MentionConfig, { MentionConfigInterface } from '../libs/MentionConfig';
39
43
  import MentionManager from '../libs/MentionManager';
40
44
  import VoiceMessageConfig, { VoiceMessageConfigInterface } from '../libs/VoiceMessageConfig';
45
+ import VoiceMessageStatusManager from '../libs/VoiceMessageStatusManager';
41
46
  import StringSetEn from '../localization/StringSet.en';
42
47
  import type { StringSet } from '../localization/StringSet.type';
43
48
  import SBUDynamicModule from '../platform/dynamicModule';
@@ -49,7 +54,7 @@ import type {
49
54
  PlayerServiceInterface,
50
55
  RecorderServiceInterface,
51
56
  } from '../platform/types';
52
- import type { ErrorBoundaryProps, LocalCacheStorage } from '../types';
57
+ import { ErrorBoundaryProps, LocalCacheStorage } from '../types';
53
58
  import VERSION from '../version';
54
59
  import InternalErrorBoundaryContainer from './InternalErrorBoundaryContainer';
55
60
 
@@ -64,7 +69,6 @@ export const SendbirdUIKit = Object.freeze({
64
69
  },
65
70
  });
66
71
 
67
- type UnimplementedFeatures = 'threadReplySelectType' | 'replyType' | 'enableReactionsSupergroup';
68
72
  export type ChatOmittedInitParams = Omit<
69
73
  SendbirdChatParams<[GroupChannelModule, OpenChannelModule]>,
70
74
  (typeof chatOmitKeys)[number]
@@ -78,13 +82,13 @@ const chatOmitKeys = [
78
82
  'appVersion',
79
83
  'localCacheEnabled',
80
84
  'useAsyncStorageStore',
85
+ 'useMMKVStorageStore',
81
86
  ] as const;
82
87
  function sanitizeChatOptions<T extends Record<string, unknown>>(chatOptions: T): T {
83
88
  const opts = { ...chatOptions };
84
89
  chatOmitKeys.forEach((key) => delete opts[key]);
85
90
  return opts;
86
91
  }
87
-
88
92
  export type SendbirdUIKitContainerProps = React.PropsWithChildren<{
89
93
  appId: string;
90
94
  platformServices: {
@@ -95,15 +99,14 @@ export type SendbirdUIKitContainerProps = React.PropsWithChildren<{
95
99
  player: PlayerServiceInterface;
96
100
  recorder: RecorderServiceInterface;
97
101
  };
98
- chatOptions: {
99
- localCacheStorage: LocalCacheStorage;
100
- onInitialized?: (sdkInstance: SendbirdChatSDK) => SendbirdChatSDK;
101
- } & Partial<ChatOmittedInitParams> &
102
- Partial<ChatRelatedFeaturesInUIKit>;
102
+ chatOptions: Partial<ChatOmittedInitParams> &
103
+ Partial<ChatRelatedFeaturesInUIKit> & {
104
+ onInitialized?: (sdkInstance: SendbirdChatSDK) => SendbirdChatSDK;
105
+ localCacheStorage: LocalCacheStorage;
106
+ };
103
107
  uikitOptions?: PartialDeep<{
104
108
  common: SBUConfig['common'];
105
- groupChannel: Omit<SBUConfig['groupChannel']['channel'], UnimplementedFeatures> & {
106
- replyType: Extract<SBUConfig['groupChannel']['channel']['replyType'], 'none' | 'quote_reply'>;
109
+ groupChannel: Omit<SBUConfig['groupChannel']['channel'], 'enableReactionsSupergroup'> & {
107
110
  /**
108
111
  * @deprecated Currently, this feature is turned off by default. If you wish to use this feature, contact us: {@link https://dashboard.sendbird.com/settings/contact_us?category=feedback_and_feature_requests&product=UIKit}
109
112
  */
@@ -163,6 +166,10 @@ const SendbirdUIKitContainer = (props: SendbirdUIKitContainerProps) => {
163
166
 
164
167
  if (!chatOptions.localCacheStorage) {
165
168
  throw new Error('SendbirdUIKitContainer: chatOptions.localCacheStorage is required');
169
+ } else if ('getItem' in chatOptions.localCacheStorage) {
170
+ Logger.warn(
171
+ 'SendbirdUIKitContainer: localCacheStorage for `AsyncStorage` is deprecated. Please use `MMKV` instead.',
172
+ );
166
173
  }
167
174
 
168
175
  const defaultStringSet = localization?.stringSet ?? StringSetEn;
@@ -172,7 +179,7 @@ const SendbirdUIKitContainer = (props: SendbirdUIKitContainerProps) => {
172
179
 
173
180
  const [internalStorage] = useState(() => new InternalLocalCacheStorage(chatOptions.localCacheStorage));
174
181
  const [sdkInstance, setSdkInstance] = useState<SendbirdChatSDK>(() => {
175
- const sendbird = initializeSendbird(appId, { internalStorage, ...sanitizeChatOptions(chatOptions) });
182
+ const sendbird = initializeSendbird(appId, sanitizeChatOptions(chatOptions));
176
183
  unsubscribes.current = sendbird.unsubscribes;
177
184
  return sendbird.chatSDK;
178
185
  });
@@ -180,10 +187,11 @@ const SendbirdUIKitContainer = (props: SendbirdUIKitContainerProps) => {
180
187
  const { imageCompressionConfig, voiceMessageConfig, mentionConfig } = useConfigInstance(props);
181
188
  const emojiManager = useMemo(() => new EmojiManager(internalStorage), [internalStorage]);
182
189
  const mentionManager = useMemo(() => new MentionManager(mentionConfig), [mentionConfig]);
190
+ const voiceMessageStatusManager = useMemo(() => new VoiceMessageStatusManager(), []);
183
191
 
184
192
  useLayoutEffect(() => {
185
193
  if (!isFirstMount) {
186
- const sendbird = initializeSendbird(appId, { internalStorage, ...sanitizeChatOptions(chatOptions) });
194
+ const sendbird = initializeSendbird(appId, sanitizeChatOptions(chatOptions));
187
195
  setSdkInstance(sendbird.chatSDK);
188
196
  unsubscribes.current = sendbird.unsubscribes;
189
197
  }
@@ -227,6 +235,7 @@ const SendbirdUIKitContainer = (props: SendbirdUIKitContainerProps) => {
227
235
  mentionManager={mentionManager}
228
236
  imageCompressionConfig={imageCompressionConfig}
229
237
  voiceMessageConfig={voiceMessageConfig}
238
+ voiceMessageStatusManager={voiceMessageStatusManager}
230
239
  enableAutoPushTokenRegistration={
231
240
  chatOptions.enableAutoPushTokenRegistration ?? SendbirdUIKit.DEFAULT.AUTO_PUSH_TOKEN_REGISTRATION
232
241
  }
@@ -287,21 +296,23 @@ const SendbirdUIKitContainer = (props: SendbirdUIKitContainerProps) => {
287
296
  };
288
297
 
289
298
  interface InitOptions extends ChatOmittedInitParams {
290
- internalStorage: InternalLocalCacheStorage;
299
+ localCacheStorage: LocalCacheStorage;
291
300
  onInitialized?: (sdk: SendbirdChatSDK) => SendbirdChatSDK;
292
301
  }
293
302
  const initializeSendbird = (appId: string, options: InitOptions) => {
294
303
  let chatSDK: SendbirdChatSDK;
295
304
  const unsubscribes: Array<() => void> = [];
296
- const { internalStorage, onInitialized, ...chatInitParams } = options;
305
+ const { localCacheStorage, onInitialized, ...chatInitParams } = options;
297
306
 
307
+ const isMMKVStorage = 'getString' in localCacheStorage;
298
308
  chatSDK = SendbirdChat.init({
299
309
  ...chatInitParams,
300
310
  appId,
301
311
  newInstance: true,
302
312
  modules: [new GroupChannelModule(), new OpenChannelModule()],
303
313
  localCacheEnabled: true,
304
- useAsyncStorageStore: internalStorage as never,
314
+ useMMKVStorageStore: isMMKVStorage ? (localCacheStorage as MMKV) : undefined,
315
+ useAsyncStorageStore: !isMMKVStorage ? (localCacheStorage as AsyncStorageStatic) : undefined,
305
316
  });
306
317
 
307
318
  if (onInitialized) {
@@ -14,7 +14,9 @@ import type EmojiManager from '../libs/EmojiManager';
14
14
  import type ImageCompressionConfig from '../libs/ImageCompressionConfig';
15
15
  import type MentionManager from '../libs/MentionManager';
16
16
  import type VoiceMessageConfig from '../libs/VoiceMessageConfig';
17
+ import VoiceMessageStatusManager from '../libs/VoiceMessageStatusManager';
17
18
  import type { FileType } from '../platform/types';
19
+ import pubsub, { type PubSub } from '../utils/pubsub';
18
20
 
19
21
  export interface ChatRelatedFeaturesInUIKit {
20
22
  enableAutoPushTokenRegistration: boolean;
@@ -27,10 +29,18 @@ interface Props extends ChatRelatedFeaturesInUIKit, React.PropsWithChildren {
27
29
 
28
30
  emojiManager: EmojiManager;
29
31
  mentionManager: MentionManager;
32
+ voiceMessageStatusManager: VoiceMessageStatusManager;
30
33
  imageCompressionConfig: ImageCompressionConfig;
31
34
  voiceMessageConfig: VoiceMessageConfig;
32
35
  }
33
36
 
37
+ export type GroupChannelFragmentOptionsPubSubContextPayload = {
38
+ type: 'OVERRIDE_SEARCH_ITEM_STARTING_POINT';
39
+ data: {
40
+ startingPoint: number;
41
+ };
42
+ };
43
+
34
44
  export type SendbirdChatContextType = {
35
45
  sdk: SendbirdChatSDK;
36
46
  currentUser?: SendbirdUser;
@@ -39,6 +49,7 @@ export type SendbirdChatContextType = {
39
49
  // feature related instances
40
50
  emojiManager: EmojiManager;
41
51
  mentionManager: MentionManager;
52
+ voiceMessageStatusManager: VoiceMessageStatusManager;
42
53
  imageCompressionConfig: ImageCompressionConfig;
43
54
  voiceMessageConfig: VoiceMessageConfig;
44
55
 
@@ -46,6 +57,9 @@ export type SendbirdChatContextType = {
46
57
  updateCurrentUserInfo: (nickname?: string, profile?: string | FileType) => Promise<SendbirdUser>;
47
58
  markAsDeliveredWithChannel: (channel: SendbirdGroupChannel) => void;
48
59
 
60
+ groupChannelFragmentOptions: {
61
+ pubsub: PubSub<GroupChannelFragmentOptionsPubSubContextPayload>;
62
+ };
49
63
  sbOptions: {
50
64
  // UIKit options
51
65
  uikit: SBUConfig;
@@ -80,6 +94,7 @@ export type SendbirdChatContextType = {
80
94
  broadcastChannelEnabled: boolean;
81
95
  superGroupChannelEnabled: boolean;
82
96
  reactionEnabled: boolean;
97
+ uploadSizeLimit: number | undefined;
83
98
  };
84
99
  };
85
100
  };
@@ -90,6 +105,7 @@ export const SendbirdChatProvider = ({
90
105
  sdkInstance,
91
106
  emojiManager,
92
107
  mentionManager,
108
+ voiceMessageStatusManager,
93
109
  imageCompressionConfig,
94
110
  voiceMessageConfig,
95
111
  enableAutoPushTokenRegistration,
@@ -164,11 +180,15 @@ export const SendbirdChatProvider = ({
164
180
  mentionManager,
165
181
  imageCompressionConfig,
166
182
  voiceMessageConfig,
183
+ voiceMessageStatusManager,
167
184
  currentUser,
168
185
  setCurrentUser,
169
186
 
170
187
  updateCurrentUserInfo,
171
188
  markAsDeliveredWithChannel,
189
+ groupChannelFragmentOptions: {
190
+ pubsub: pubsub<GroupChannelFragmentOptionsPubSubContextPayload>(),
191
+ },
172
192
 
173
193
  // TODO: Options should be moved to the common area at the higher level to be passed to the context of each product.
174
194
  // For example, common -> chat context, common -> calls context
@@ -2,11 +2,12 @@ import React, { useContext, useEffect } from 'react';
2
2
 
3
3
  import { useChannelHandler } from '@sendbird/uikit-chat-hooks';
4
4
  import { useToast } from '@sendbird/uikit-react-native-foundation';
5
- import type { SendbirdMessage } from '@sendbird/uikit-utils';
6
- import { isDifferentChannel, useFreshCallback, useIsFirstMount, useUniqHandlerId } from '@sendbird/uikit-utils';
5
+ import { SendbirdMessage, SendbirdSendableMessage, useIsFirstMount } from '@sendbird/uikit-utils';
6
+ import { isDifferentChannel, useFreshCallback, useUniqHandlerId } from '@sendbird/uikit-utils';
7
7
 
8
8
  import ChannelMessageList from '../../../components/ChannelMessageList';
9
9
  import { MESSAGE_FOCUS_ANIMATION_DELAY, MESSAGE_SEARCH_SAFE_SCROLL_DELAY } from '../../../constants';
10
+ import { GroupChannelFragmentOptionsPubSubContextPayload } from '../../../contexts/SendbirdChatCtx';
10
11
  import { useLocalization, useSendbirdChat } from '../../../hooks/useContext';
11
12
  import { GroupChannelContexts } from '../module/moduleContext';
12
13
  import type { GroupChannelProps } from '../types';
@@ -14,10 +15,12 @@ import type { GroupChannelProps } from '../types';
14
15
  const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
15
16
  const toast = useToast();
16
17
  const { STRINGS } = useLocalization();
17
- const { sdk } = useSendbirdChat();
18
+ const { sdk, sbOptions, groupChannelFragmentOptions } = useSendbirdChat();
18
19
  const { setMessageToEdit, setMessageToReply } = useContext(GroupChannelContexts.Fragment);
19
20
  const { subscribe } = useContext(GroupChannelContexts.PubSub);
20
- const { flatListRef, lazyScrollToBottom, lazyScrollToIndex } = useContext(GroupChannelContexts.MessageList);
21
+ const { flatListRef, lazyScrollToBottom, lazyScrollToIndex, onPressReplyMessageInThread } = useContext(
22
+ GroupChannelContexts.MessageList,
23
+ );
21
24
 
22
25
  const id = useUniqHandlerId('GroupChannelMessageList');
23
26
  const isFirstMount = useIsFirstMount();
@@ -90,6 +93,17 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
90
93
  });
91
94
  }, [props.scrolledAwayFromBottom]);
92
95
 
96
+ useEffect(() => {
97
+ return groupChannelFragmentOptions.pubsub.subscribe((payload: GroupChannelFragmentOptionsPubSubContextPayload) => {
98
+ switch (payload.type) {
99
+ case 'OVERRIDE_SEARCH_ITEM_STARTING_POINT': {
100
+ scrollToMessageWithCreatedAt(payload.data.startingPoint, false, MESSAGE_SEARCH_SAFE_SCROLL_DELAY);
101
+ break;
102
+ }
103
+ }
104
+ });
105
+ }, []);
106
+
93
107
  useEffect(() => {
94
108
  // Only trigger once when message list mount with initial props.searchItem
95
109
  // - Search screen + searchItem > mount message list
@@ -99,16 +113,31 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
99
113
  }
100
114
  }, [isFirstMount]);
101
115
 
102
- const onPressParentMessage = useFreshCallback((message: SendbirdMessage) => {
103
- const canScrollToParent = scrollToMessageWithCreatedAt(message.createdAt, true, 0);
104
- if (!canScrollToParent) toast.show(STRINGS.TOAST.FIND_PARENT_MSG_ERROR, 'error');
105
- });
116
+ const onPressParentMessage = useFreshCallback(
117
+ (parentMessage: SendbirdMessage, childMessage: SendbirdSendableMessage) => {
118
+ if (
119
+ onPressReplyMessageInThread &&
120
+ sbOptions.uikit.groupChannel.channel.replyType === 'thread' &&
121
+ sbOptions.uikit.groupChannel.channel.threadReplySelectType === 'thread'
122
+ ) {
123
+ if (parentMessage.createdAt >= props.channel.messageOffsetTimestamp) {
124
+ onPressReplyMessageInThread(parentMessage as SendbirdSendableMessage, childMessage.createdAt);
125
+ } else {
126
+ toast.show(STRINGS.TOAST.FIND_PARENT_MSG_ERROR, 'error');
127
+ }
128
+ } else {
129
+ const canScrollToParent = scrollToMessageWithCreatedAt(parentMessage.createdAt, true, 0);
130
+ if (!canScrollToParent) toast.show(STRINGS.TOAST.FIND_PARENT_MSG_ERROR, 'error');
131
+ }
132
+ },
133
+ );
106
134
 
107
135
  return (
108
136
  <ChannelMessageList
109
137
  {...props}
110
138
  ref={flatListRef}
111
139
  onReplyMessage={setMessageToReply}
140
+ onReplyInThreadMessage={setMessageToReply}
112
141
  onEditMessage={setMessageToEdit}
113
142
  onPressParentMessage={onPressParentMessage}
114
143
  onPressNewMessagesButton={scrollToBottom}
@@ -58,12 +58,13 @@ export const GroupChannelContextsProvider: GroupChannelModule['Provider'] = ({
58
58
  groupChannelPubSub,
59
59
  messages,
60
60
  onUpdateSearchItem,
61
+ onPressReplyMessageInThread,
61
62
  }) => {
62
63
  if (!channel) throw new Error('GroupChannel is not provided to GroupChannelModule');
63
64
 
64
65
  const handlerId = useUniqHandlerId('GroupChannelContextsProvider');
65
66
  const { STRINGS } = useLocalization();
66
- const { currentUser, sdk } = useSendbirdChat();
67
+ const { currentUser, sdk, sbOptions } = useSendbirdChat();
67
68
 
68
69
  const [typingUsers, setTypingUsers] = useState<SendbirdUser[]>([]);
69
70
  const [messageToEdit, setMessageToEdit] = useState<SendbirdUserMessage | SendbirdFileMessage>();
@@ -90,6 +91,14 @@ export const GroupChannelContextsProvider: GroupChannelModule['Provider'] = ({
90
91
  }
91
92
  };
92
93
 
94
+ const onPressMessageToReply = (parentMessage?: SendbirdUserMessage | SendbirdFileMessage) => {
95
+ if (sbOptions.uikit.groupChannel.channel.replyType === 'thread' && parentMessage) {
96
+ onPressReplyMessageInThread?.(parentMessage, Number.MAX_SAFE_INTEGER);
97
+ } else if (sbOptions.uikit.groupChannel.channel.replyType === 'quote_reply') {
98
+ updateInputMode('reply', parentMessage);
99
+ }
100
+ };
101
+
93
102
  useChannelHandler(sdk, handlerId, {
94
103
  onMessageDeleted(_, messageId) {
95
104
  if (messageToReply?.messageId === messageId) {
@@ -125,7 +134,7 @@ export const GroupChannelContextsProvider: GroupChannelModule['Provider'] = ({
125
134
  messageToEdit,
126
135
  setMessageToEdit: useCallback((message) => updateInputMode('edit', message), []),
127
136
  messageToReply,
128
- setMessageToReply: useCallback((message) => updateInputMode('reply', message), []),
137
+ setMessageToReply: useCallback((message) => onPressMessageToReply(message), []),
129
138
  }}
130
139
  >
131
140
  <GroupChannelContexts.PubSub.Provider value={groupChannelPubSub}>
@@ -136,6 +145,7 @@ export const GroupChannelContextsProvider: GroupChannelModule['Provider'] = ({
136
145
  scrollToMessage,
137
146
  lazyScrollToIndex,
138
147
  lazyScrollToBottom,
148
+ onPressReplyMessageInThread,
139
149
  }}
140
150
  >
141
151
  {children}
@@ -11,6 +11,7 @@ import type {
11
11
  SendbirdFileMessageUpdateParams,
12
12
  SendbirdGroupChannel,
13
13
  SendbirdMessage,
14
+ SendbirdSendableMessage,
14
15
  SendbirdUser,
15
16
  SendbirdUserMessage,
16
17
  SendbirdUserMessageCreateParams,
@@ -30,6 +31,7 @@ export interface GroupChannelProps {
30
31
  onPressHeaderLeft: GroupChannelProps['Header']['onPressHeaderLeft'];
31
32
  onPressHeaderRight: GroupChannelProps['Header']['onPressHeaderRight'];
32
33
  onPressMediaMessage?: GroupChannelProps['MessageList']['onPressMediaMessage'];
34
+ onPressReplyMessageInThread?: GroupChannelProps['Provider']['onPressReplyMessageInThread'];
33
35
 
34
36
  onBeforeSendUserMessage?: OnBeforeHandler<SendbirdUserMessageCreateParams>;
35
37
  onBeforeSendFileMessage?: OnBeforeHandler<SendbirdFileMessageCreateParams>;
@@ -114,6 +116,7 @@ export interface GroupChannelProps {
114
116
  messages: SendbirdMessage[];
115
117
  // Changing the search item will trigger the focus animation on messages.
116
118
  onUpdateSearchItem: (searchItem?: GroupChannelProps['MessageList']['searchItem']) => void;
119
+ onPressReplyMessageInThread: (parentMessage: SendbirdSendableMessage, startingPoint?: number) => void;
117
120
  };
118
121
  }
119
122
 
@@ -171,6 +174,8 @@ export interface GroupChannelContextsType {
171
174
  timeout?: number;
172
175
  viewPosition?: number;
173
176
  }) => void;
177
+
178
+ onPressReplyMessageInThread?: (parentMessage: SendbirdSendableMessage, startingPoint?: number) => void;
174
179
  }>;
175
180
  }
176
181
  export interface GroupChannelModule {
@@ -0,0 +1,63 @@
1
+ import React, { useContext } from 'react';
2
+ import { View } from 'react-native';
3
+
4
+ import { Icon, Text, createStyleSheet, useHeaderStyle, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
5
+
6
+ import { useLocalization, useSendbirdChat } from '../../../hooks/useContext';
7
+ import { GroupChannelThreadContexts } from '../module/moduleContext';
8
+ import type { GroupChannelThreadProps } from '../types';
9
+
10
+ const GroupChannelThreadHeader = ({ onPressLeft, onPressSubtitle }: GroupChannelThreadProps['Header']) => {
11
+ const { headerTitle, channel } = useContext(GroupChannelThreadContexts.Fragment);
12
+ const { HeaderComponent } = useHeaderStyle();
13
+ const { STRINGS } = useLocalization();
14
+ const { select, colors, palette } = useUIKitTheme();
15
+ const { currentUser } = useSendbirdChat();
16
+
17
+ const renderSubtitle = () => {
18
+ if (!currentUser) return null;
19
+
20
+ return (
21
+ <Text
22
+ onPress={onPressSubtitle}
23
+ caption2
24
+ style={styles.subtitle}
25
+ color={select({ light: palette.primary300, dark: palette.primary200 })}
26
+ numberOfLines={1}
27
+ >
28
+ {STRINGS.GROUP_CHANNEL_THREAD.HEADER_SUBTITLE(currentUser.userId, channel)}
29
+ </Text>
30
+ );
31
+ };
32
+
33
+ return (
34
+ <HeaderComponent
35
+ clearTitleMargin
36
+ title={
37
+ <View style={styles.titleContainer}>
38
+ <View style={{ flexShrink: 1 }}>
39
+ <Text h2 color={colors.onBackground01} numberOfLines={1}>
40
+ {headerTitle}
41
+ </Text>
42
+ {renderSubtitle()}
43
+ </View>
44
+ </View>
45
+ }
46
+ left={<Icon icon={'arrow-left'} size={24} />}
47
+ onPressLeft={onPressLeft}
48
+ />
49
+ );
50
+ };
51
+
52
+ const styles = createStyleSheet({
53
+ titleContainer: {
54
+ maxWidth: '100%',
55
+ flexDirection: 'row',
56
+ width: '100%',
57
+ },
58
+ subtitle: {
59
+ marginTop: 2,
60
+ },
61
+ });
62
+
63
+ export default GroupChannelThreadHeader;