stream-chat-react-native-core 4.11.1-beta.3 → 4.12.0-beta.2

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 (205) hide show
  1. package/lib/commonjs/components/Attachment/Gallery.js +2 -2
  2. package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
  3. package/lib/commonjs/components/Attachment/{GallaryImage.js → GalleryImage.js} +3 -3
  4. package/lib/{module/components/Attachment/GallaryImage.js.map → commonjs/components/Attachment/GalleryImage.js.map} +1 -1
  5. package/lib/commonjs/components/Attachment/Giphy.js +1 -1
  6. package/lib/commonjs/components/Attachment/Giphy.js.map +1 -1
  7. package/lib/commonjs/components/Attachment/VideoThumbnail.js +4 -5
  8. package/lib/commonjs/components/Attachment/VideoThumbnail.js.map +1 -1
  9. package/lib/commonjs/components/Avatar/Avatar.js +1 -1
  10. package/lib/commonjs/components/Avatar/Avatar.js.map +1 -1
  11. package/lib/commonjs/components/Avatar/GroupAvatar.js +1 -1
  12. package/lib/commonjs/components/Avatar/GroupAvatar.js.map +1 -1
  13. package/lib/commonjs/components/Channel/Channel.js +18 -13
  14. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  15. package/lib/commonjs/components/Channel/hooks/useCreateInputMessageInputContext.js +2 -0
  16. package/lib/commonjs/components/Channel/hooks/useCreateInputMessageInputContext.js.map +1 -1
  17. package/lib/commonjs/components/ChannelPreview/ChannelPreview.js +17 -12
  18. package/lib/commonjs/components/ChannelPreview/ChannelPreview.js.map +1 -1
  19. package/lib/commonjs/components/ImageGallery/ImageGallery.js +37 -30
  20. package/lib/commonjs/components/ImageGallery/ImageGallery.js.map +1 -1
  21. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryImage.js +5 -3
  22. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryImage.js.map +1 -1
  23. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryVideo.js +10 -6
  24. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryVideo.js.map +1 -1
  25. package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js +17 -14
  26. package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
  27. package/lib/commonjs/components/ImageGallery/components/ImageGalleryHeader.js +1 -0
  28. package/lib/commonjs/components/ImageGallery/components/ImageGalleryHeader.js.map +1 -1
  29. package/lib/commonjs/components/ImageGallery/components/ImageGalleryOverlay.js +2 -1
  30. package/lib/commonjs/components/ImageGallery/components/ImageGalleryOverlay.js.map +1 -1
  31. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js +36 -18
  32. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  33. package/lib/commonjs/components/ImageGallery/components/ImageGrid.js +3 -1
  34. package/lib/commonjs/components/ImageGallery/components/ImageGrid.js.map +1 -1
  35. package/lib/commonjs/components/ImageGallery/components/ImageGridHandle.js +5 -4
  36. package/lib/commonjs/components/ImageGallery/components/ImageGridHandle.js.map +1 -1
  37. package/lib/commonjs/components/Message/Message.js +8 -6
  38. package/lib/commonjs/components/Message/Message.js.map +1 -1
  39. package/lib/commonjs/components/Message/MessageSimple/utils/parseLinks.js +1 -1
  40. package/lib/commonjs/components/Message/MessageSimple/utils/parseLinks.js.map +1 -1
  41. package/lib/commonjs/components/Message/MessageSimple/utils/parseLinks.test.js +1 -1
  42. package/lib/commonjs/components/Message/MessageSimple/utils/parseLinks.test.js.map +1 -1
  43. package/lib/commonjs/components/MessageInput/AudioAttachmentUploadPreview.js +538 -0
  44. package/lib/commonjs/components/MessageInput/AudioAttachmentUploadPreview.js.map +1 -0
  45. package/lib/commonjs/components/MessageInput/FileUploadPreview.js +143 -32
  46. package/lib/commonjs/components/MessageInput/FileUploadPreview.js.map +1 -1
  47. package/lib/{module/components/ImageGallery/components → commonjs/components/ProgressControl}/ProgressControl.js +37 -24
  48. package/lib/commonjs/components/ProgressControl/ProgressControl.js.map +1 -0
  49. package/lib/commonjs/components/index.js +26 -0
  50. package/lib/commonjs/components/index.js.map +1 -1
  51. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +5 -2
  52. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  53. package/lib/commonjs/contexts/messageInputContext/hooks/useCreateMessageInputContext.js +7 -2
  54. package/lib/commonjs/contexts/messageInputContext/hooks/useCreateMessageInputContext.js.map +1 -1
  55. package/lib/commonjs/contexts/themeContext/utils/theme.js +9 -0
  56. package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
  57. package/lib/commonjs/icons/Pause.js +2 -2
  58. package/lib/commonjs/icons/Pause.js.map +1 -1
  59. package/lib/commonjs/mock-builders/api/channelMocks.js +1 -0
  60. package/lib/commonjs/mock-builders/api/channelMocks.js.map +1 -1
  61. package/lib/commonjs/native.js +13 -5
  62. package/lib/commonjs/native.js.map +1 -1
  63. package/lib/commonjs/version.json +1 -1
  64. package/lib/module/components/Attachment/Gallery.js +2 -2
  65. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  66. package/lib/module/components/Attachment/{GallaryImage.js → GalleryImage.js} +3 -3
  67. package/lib/{commonjs/components/Attachment/GallaryImage.js.map → module/components/Attachment/GalleryImage.js.map} +1 -1
  68. package/lib/module/components/Attachment/Giphy.js +1 -1
  69. package/lib/module/components/Attachment/Giphy.js.map +1 -1
  70. package/lib/module/components/Attachment/VideoThumbnail.js +4 -5
  71. package/lib/module/components/Attachment/VideoThumbnail.js.map +1 -1
  72. package/lib/module/components/Avatar/Avatar.js +1 -1
  73. package/lib/module/components/Avatar/Avatar.js.map +1 -1
  74. package/lib/module/components/Avatar/GroupAvatar.js +1 -1
  75. package/lib/module/components/Avatar/GroupAvatar.js.map +1 -1
  76. package/lib/module/components/Channel/Channel.js +18 -13
  77. package/lib/module/components/Channel/Channel.js.map +1 -1
  78. package/lib/module/components/Channel/hooks/useCreateInputMessageInputContext.js +2 -0
  79. package/lib/module/components/Channel/hooks/useCreateInputMessageInputContext.js.map +1 -1
  80. package/lib/module/components/ChannelPreview/ChannelPreview.js +17 -12
  81. package/lib/module/components/ChannelPreview/ChannelPreview.js.map +1 -1
  82. package/lib/module/components/ImageGallery/ImageGallery.js +37 -30
  83. package/lib/module/components/ImageGallery/ImageGallery.js.map +1 -1
  84. package/lib/module/components/ImageGallery/components/AnimatedGalleryImage.js +5 -3
  85. package/lib/module/components/ImageGallery/components/AnimatedGalleryImage.js.map +1 -1
  86. package/lib/module/components/ImageGallery/components/AnimatedGalleryVideo.js +10 -6
  87. package/lib/module/components/ImageGallery/components/AnimatedGalleryVideo.js.map +1 -1
  88. package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js +17 -14
  89. package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
  90. package/lib/module/components/ImageGallery/components/ImageGalleryHeader.js +1 -0
  91. package/lib/module/components/ImageGallery/components/ImageGalleryHeader.js.map +1 -1
  92. package/lib/module/components/ImageGallery/components/ImageGalleryOverlay.js +2 -1
  93. package/lib/module/components/ImageGallery/components/ImageGalleryOverlay.js.map +1 -1
  94. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js +36 -18
  95. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  96. package/lib/module/components/ImageGallery/components/ImageGrid.js +3 -1
  97. package/lib/module/components/ImageGallery/components/ImageGrid.js.map +1 -1
  98. package/lib/module/components/ImageGallery/components/ImageGridHandle.js +5 -4
  99. package/lib/module/components/ImageGallery/components/ImageGridHandle.js.map +1 -1
  100. package/lib/module/components/Message/Message.js +8 -6
  101. package/lib/module/components/Message/Message.js.map +1 -1
  102. package/lib/module/components/Message/MessageSimple/utils/parseLinks.js +1 -1
  103. package/lib/module/components/Message/MessageSimple/utils/parseLinks.js.map +1 -1
  104. package/lib/module/components/Message/MessageSimple/utils/parseLinks.test.js +1 -1
  105. package/lib/module/components/Message/MessageSimple/utils/parseLinks.test.js.map +1 -1
  106. package/lib/module/components/MessageInput/AudioAttachmentUploadPreview.js +538 -0
  107. package/lib/module/components/MessageInput/AudioAttachmentUploadPreview.js.map +1 -0
  108. package/lib/module/components/MessageInput/FileUploadPreview.js +143 -32
  109. package/lib/module/components/MessageInput/FileUploadPreview.js.map +1 -1
  110. package/lib/{commonjs/components/ImageGallery/components → module/components/ProgressControl}/ProgressControl.js +37 -24
  111. package/lib/module/components/ProgressControl/ProgressControl.js.map +1 -0
  112. package/lib/module/components/index.js +26 -0
  113. package/lib/module/components/index.js.map +1 -1
  114. package/lib/module/contexts/messageInputContext/MessageInputContext.js +5 -2
  115. package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  116. package/lib/module/contexts/messageInputContext/hooks/useCreateMessageInputContext.js +7 -2
  117. package/lib/module/contexts/messageInputContext/hooks/useCreateMessageInputContext.js.map +1 -1
  118. package/lib/module/contexts/themeContext/utils/theme.js +9 -0
  119. package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
  120. package/lib/module/icons/Pause.js +2 -2
  121. package/lib/module/icons/Pause.js.map +1 -1
  122. package/lib/module/mock-builders/api/channelMocks.js +1 -0
  123. package/lib/module/mock-builders/api/channelMocks.js.map +1 -1
  124. package/lib/module/native.js +13 -5
  125. package/lib/module/native.js.map +1 -1
  126. package/lib/module/version.json +1 -1
  127. package/lib/typescript/components/Attachment/{GallaryImage.d.ts → GalleryImage.d.ts} +0 -0
  128. package/lib/typescript/components/Channel/hooks/useCreateInputMessageInputContext.d.ts +1 -1
  129. package/lib/typescript/components/ImageGallery/__tests__/AnimatedVideoGallery.test.d.ts +1 -0
  130. package/lib/typescript/components/ImageGallery/__tests__/ImageGallery.test.d.ts +1 -0
  131. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryFooter.test.d.ts +1 -0
  132. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryGrid.test.d.ts +1 -0
  133. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryGridHandle.test.d.ts +1 -0
  134. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryHeader.test.d.ts +1 -0
  135. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryOverlay.test.d.ts +1 -0
  136. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryVideoControl.test.d.ts +1 -0
  137. package/lib/typescript/components/ImageGallery/components/AnimatedGalleryImage.d.ts +1 -0
  138. package/lib/typescript/components/ImageGallery/components/AnimatedGalleryVideo.d.ts +2 -3
  139. package/lib/typescript/components/ImageGallery/components/ImageGalleryFooter.d.ts +2 -1
  140. package/lib/typescript/components/ImageGallery/components/ImageGrid.d.ts +2 -3
  141. package/lib/typescript/components/Message/hooks/useMessageActionHandlers.d.ts +1 -1
  142. package/lib/typescript/components/Message/hooks/useMessageActions.d.ts +1 -1
  143. package/lib/typescript/components/MessageInput/AudioAttachmentUploadPreview.d.ts +26 -0
  144. package/lib/typescript/components/MessageInput/FileUploadPreview.d.ts +1 -1
  145. package/lib/typescript/components/MessageInput/__tests__/AudioAttachmentUploadPreviewExpo.test.d.ts +1 -0
  146. package/lib/typescript/components/MessageInput/__tests__/AudioAttachmentUploadPreviewNative.test.d.ts +1 -0
  147. package/lib/typescript/components/ProgressControl/ProgressControl.d.ts +11 -0
  148. package/lib/typescript/components/index.d.ts +2 -0
  149. package/lib/typescript/contexts/messageContext/MessageContext.d.ts +1 -1
  150. package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts +7 -1
  151. package/lib/typescript/contexts/messageInputContext/hooks/useCreateMessageInputContext.d.ts +1 -1
  152. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +9 -0
  153. package/lib/typescript/native.d.ts +59 -2
  154. package/package.json +1 -1
  155. package/src/components/Attachment/Gallery.tsx +1 -1
  156. package/src/components/Attachment/{GallaryImage.tsx → GalleryImage.tsx} +1 -1
  157. package/src/components/Attachment/Giphy.tsx +1 -1
  158. package/src/components/Attachment/VideoThumbnail.tsx +1 -2
  159. package/src/components/Attachment/__tests__/Gallery.test.js +6 -6
  160. package/src/components/Attachment/__tests__/Giphy.test.js +4 -4
  161. package/src/components/Avatar/Avatar.tsx +1 -1
  162. package/src/components/Avatar/GroupAvatar.tsx +1 -1
  163. package/src/components/Channel/Channel.tsx +3 -0
  164. package/src/components/Channel/hooks/useCreateInputMessageInputContext.ts +2 -0
  165. package/src/components/ChannelPreview/ChannelPreview.tsx +14 -12
  166. package/src/components/ImageGallery/ImageGallery.tsx +21 -11
  167. package/src/components/ImageGallery/__tests__/AnimatedVideoGallery.test.tsx +241 -0
  168. package/src/components/ImageGallery/__tests__/ImageGallery.test.tsx +192 -0
  169. package/src/components/ImageGallery/__tests__/ImageGalleryFooter.test.tsx +190 -0
  170. package/src/components/ImageGallery/__tests__/ImageGalleryGrid.test.tsx +98 -0
  171. package/src/components/ImageGallery/__tests__/ImageGalleryGridHandle.test.tsx +79 -0
  172. package/src/components/ImageGallery/__tests__/ImageGalleryHeader.test.tsx +172 -0
  173. package/src/components/ImageGallery/__tests__/ImageGalleryOverlay.test.tsx +94 -0
  174. package/src/components/ImageGallery/__tests__/ImageGalleryVideoControl.test.tsx +84 -0
  175. package/src/components/ImageGallery/components/AnimatedGalleryImage.tsx +3 -0
  176. package/src/components/ImageGallery/components/AnimatedGalleryVideo.tsx +11 -3
  177. package/src/components/ImageGallery/components/ImageGalleryFooter.tsx +9 -2
  178. package/src/components/ImageGallery/components/ImageGalleryHeader.tsx +1 -1
  179. package/src/components/ImageGallery/components/ImageGalleryOverlay.tsx +6 -1
  180. package/src/components/ImageGallery/components/ImageGalleryVideoControl.tsx +22 -9
  181. package/src/components/ImageGallery/components/ImageGrid.tsx +19 -17
  182. package/src/components/ImageGallery/components/ImageGridHandle.tsx +4 -1
  183. package/src/components/Message/Message.tsx +2 -1
  184. package/src/components/Message/MessageSimple/__tests__/MessageContent.test.js +9 -3
  185. package/src/components/Message/MessageSimple/__tests__/__snapshots__/MessageAvatar.test.js.snap +1 -1
  186. package/src/components/Message/MessageSimple/utils/parseLinks.test.ts +4 -0
  187. package/src/components/Message/MessageSimple/utils/parseLinks.ts +1 -1
  188. package/src/components/MessageInput/AudioAttachmentUploadPreview.tsx +362 -0
  189. package/src/components/MessageInput/FileUploadPreview.tsx +162 -57
  190. package/src/components/MessageInput/__tests__/AudioAttachmentUploadPreviewExpo.test.tsx +199 -0
  191. package/src/components/MessageInput/__tests__/AudioAttachmentUploadPreviewNative.test.tsx +215 -0
  192. package/src/components/MessageInput/__tests__/FileUploadPreview.test.js +64 -0
  193. package/src/components/{ImageGallery/components → ProgressControl}/ProgressControl.tsx +37 -19
  194. package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +4 -4
  195. package/src/components/index.ts +3 -0
  196. package/src/contexts/messageInputContext/MessageInputContext.tsx +13 -0
  197. package/src/contexts/messageInputContext/hooks/useCreateMessageInputContext.ts +5 -1
  198. package/src/contexts/themeContext/utils/theme.ts +15 -0
  199. package/src/icons/Pause.tsx +2 -2
  200. package/src/mock-builders/api/channelMocks.tsx +1 -0
  201. package/src/native.ts +67 -7
  202. package/src/version.json +1 -1
  203. package/lib/commonjs/components/ImageGallery/components/ProgressControl.js.map +0 -1
  204. package/lib/module/components/ImageGallery/components/ProgressControl.js.map +0 -1
  205. package/lib/typescript/components/ImageGallery/components/ProgressControl.d.ts +0 -5
@@ -16,8 +16,9 @@ import { useTheme } from '../../contexts/themeContext/ThemeContext';
16
16
  import { useTranslationContext } from '../../contexts/translationContext/TranslationContext';
17
17
  import { Close } from '../../icons/Close';
18
18
  import { Warning } from '../../icons/Warning';
19
+ import { isAudioPackageAvailable } from '../../native';
19
20
  import type { DefaultStreamChatGenerics } from '../../types/types';
20
- import { getIndicatorTypeForFileState, ProgressIndicatorTypes } from '../../utils/utils';
21
+ import { FileState, getIndicatorTypeForFileState, ProgressIndicatorTypes } from '../../utils/utils';
21
22
  import { getFileSizeDisplayText } from '../Attachment/FileAttachment';
22
23
  import { WritingDirectionAwareText } from '../RTLComponents/WritingDirectionAwareText';
23
24
 
@@ -29,8 +30,8 @@ const styles = StyleSheet.create({
29
30
  borderRadius: 24,
30
31
  height: 24,
31
32
  position: 'absolute',
32
- right: 14,
33
- top: 4,
33
+ right: 8,
34
+ top: 8,
34
35
  width: 24,
35
36
  },
36
37
  fileContainer: {
@@ -40,9 +41,15 @@ const styles = StyleSheet.create({
40
41
  height: FILE_PREVIEW_HEIGHT,
41
42
  justifyContent: 'space-between',
42
43
  marginBottom: 8,
43
- padding: 8,
44
+ paddingLeft: 8,
45
+ paddingRight: 8,
44
46
  },
45
47
  fileContentContainer: { flexDirection: 'row' },
48
+ fileIcon: {
49
+ alignItems: 'center',
50
+ alignSelf: 'center',
51
+ justifyContent: 'center',
52
+ },
46
53
  filenameText: {
47
54
  fontSize: 14,
48
55
  fontWeight: 'bold',
@@ -85,7 +92,7 @@ const UnsupportedFileTypeOrFileSizeIndicator = ({
85
92
  }) => {
86
93
  const {
87
94
  theme: {
88
- colors: { accent_red, grey },
95
+ colors: { accent_red, grey, grey_dark },
89
96
  messageInput: {
90
97
  fileUploadPreview: { fileSizeText },
91
98
  },
@@ -101,7 +108,7 @@ const UnsupportedFileTypeOrFileSizeIndicator = ({
101
108
  style={styles.warningIconStyle}
102
109
  width={WARNING_ICON_SIZE}
103
110
  />
104
- <Text style={[styles.unsupportedFileText, { color: grey }]}>
111
+ <Text style={[styles.unsupportedFileText, { color: grey_dark }]}>
105
112
  {t('File type not supported')}
106
113
  </Text>
107
114
  </View>
@@ -116,7 +123,7 @@ type FileUploadPreviewPropsWithContext<
116
123
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
117
124
  > = Pick<
118
125
  MessageInputContextValue<StreamChatGenerics>,
119
- 'fileUploads' | 'removeFile' | 'uploadFile'
126
+ 'fileUploads' | 'removeFile' | 'uploadFile' | 'setFileUploads' | 'AudioAttachmentUploadPreview'
120
127
  > &
121
128
  Pick<MessagesContextValue<StreamChatGenerics>, 'FileAttachmentIcon'>;
122
129
 
@@ -125,16 +132,72 @@ const FileUploadPreviewWithContext = <
125
132
  >(
126
133
  props: FileUploadPreviewPropsWithContext<StreamChatGenerics>,
127
134
  ) => {
128
- const { FileAttachmentIcon, fileUploads, removeFile, uploadFile } = props;
135
+ const {
136
+ AudioAttachmentUploadPreview,
137
+ FileAttachmentIcon,
138
+ fileUploads,
139
+ removeFile,
140
+ setFileUploads,
141
+ uploadFile,
142
+ } = props;
129
143
 
130
144
  const flatListRef = useRef<FlatList<FileUpload> | null>(null);
131
145
  const [flatListWidth, setFlatListWidth] = useState(0);
132
146
 
147
+ // Handler triggered when an audio is loaded in the message input. The initial state is defined for the audio here and the duration is set.
148
+ const onLoad = (index: string, duration: number) => {
149
+ setFileUploads((prevFileUploads) =>
150
+ prevFileUploads.map((fileUpload) => ({
151
+ ...fileUpload,
152
+ duration: fileUpload.id === index ? duration : fileUpload.duration,
153
+ })),
154
+ );
155
+ };
156
+
157
+ // The handler which is triggered when the audio progresses/ the thumb is dragged in the progress control. The progressed duration is set here.
158
+ const onProgress = (index: string, currentTime?: number, hasEnd?: boolean) => {
159
+ setFileUploads((prevFileUploads) =>
160
+ prevFileUploads.map((fileUpload) => ({
161
+ ...fileUpload,
162
+ progress:
163
+ fileUpload.id === index
164
+ ? hasEnd
165
+ ? 1
166
+ : currentTime
167
+ ? currentTime / (fileUpload.duration as number)
168
+ : 0
169
+ : fileUpload.progress,
170
+ })),
171
+ );
172
+ };
173
+
174
+ // The handler which controls or sets the paused/played state of the audio.
175
+ const onPlayPause = (index: string, status?: boolean) => {
176
+ if (status === false) {
177
+ // If the status is false we set the audio with the index as playing and the others as paused.
178
+ setFileUploads((prevFileUploads) =>
179
+ prevFileUploads.map((fileUpload) => ({
180
+ ...fileUpload,
181
+ paused: fileUpload.id === index ? false : true,
182
+ })),
183
+ );
184
+ } else {
185
+ // If the status is true we simply set all the audio's paused state as true.
186
+ setFileUploads((prevFileUploads) =>
187
+ prevFileUploads.map((fileUpload) => ({
188
+ ...fileUpload,
189
+ paused: true,
190
+ })),
191
+ );
192
+ }
193
+ };
194
+
133
195
  const {
134
196
  theme: {
135
197
  colors: { black, grey_dark, grey_gainsboro, grey_whisper },
136
198
  messageInput: {
137
199
  fileUploadPreview: {
200
+ audioAttachmentFileContainer,
138
201
  dismiss,
139
202
  fileContainer,
140
203
  fileContentContainer,
@@ -149,6 +212,8 @@ const FileUploadPreviewWithContext = <
149
212
  const renderItem = ({ index, item }: { index: number; item: FileUpload }) => {
150
213
  const indicatorType = getIndicatorTypeForFileState(item.state);
151
214
 
215
+ const lastIndexOfDot = item.file.name.lastIndexOf('.');
216
+
152
217
  return (
153
218
  <>
154
219
  <UploadProgressIndicator
@@ -158,52 +223,81 @@ const FileUploadPreviewWithContext = <
158
223
  style={styles.overlay}
159
224
  type={indicatorType}
160
225
  >
161
- <View
162
- style={[
163
- styles.fileContainer,
164
- index === fileUploads.length - 1
165
- ? {
166
- marginBottom: 0,
167
- }
168
- : {},
169
- {
170
- borderColor: grey_whisper,
171
- width: flatListWidth - 16,
172
- },
173
- fileContainer,
174
- ]}
175
- >
176
- <View style={[styles.fileContentContainer, fileContentContainer]}>
177
- <FileAttachmentIcon mimeType={item.file.type} />
178
- <View style={[styles.fileTextContainer, fileTextContainer]}>
179
- <Text
180
- numberOfLines={1}
181
- style={[
182
- styles.filenameText,
183
- {
184
- color: black,
185
- width:
186
- flatListWidth -
187
- 16 - // 16 = horizontal padding
188
- 40 - // 40 = file icon size
189
- 24 - // 24 = close icon size
190
- 24, // 24 = internal padding
191
- },
192
- I18nManager.isRTL ? { writingDirection: 'rtl' } : { writingDirection: 'ltr' },
193
- filenameText,
194
- ]}
195
- >
196
- {item.file.name || ''}
197
- </Text>
198
- {indicatorType !== null && (
199
- <UnsupportedFileTypeOrFileSizeIndicator
200
- indicatorType={indicatorType}
201
- item={item}
202
- />
203
- )}
226
+ {item.file.type?.startsWith('audio/') && isAudioPackageAvailable() ? (
227
+ <View
228
+ style={[
229
+ { marginBottom: item.state === FileState.UPLOADED ? 8 : 0 },
230
+ audioAttachmentFileContainer,
231
+ ]}
232
+ >
233
+ <AudioAttachmentUploadPreview
234
+ index={index}
235
+ item={item}
236
+ onLoad={onLoad}
237
+ onPlayPause={onPlayPause}
238
+ onProgress={onProgress}
239
+ testID='audio-attachment-upload-preview'
240
+ />
241
+ </View>
242
+ ) : (
243
+ <View
244
+ style={[
245
+ styles.fileContainer,
246
+ index === fileUploads.length - 1
247
+ ? {
248
+ marginBottom: 0,
249
+ }
250
+ : {},
251
+ {
252
+ borderColor: grey_whisper,
253
+ width: flatListWidth - 16,
254
+ },
255
+ fileContainer,
256
+ ]}
257
+ >
258
+ <View style={[styles.fileContentContainer, fileContentContainer]}>
259
+ <View style={styles.fileIcon}>
260
+ <FileAttachmentIcon mimeType={item.file.type} />
261
+ </View>
262
+ <View style={[styles.fileTextContainer, fileTextContainer]}>
263
+ <Text
264
+ numberOfLines={1}
265
+ style={[
266
+ styles.filenameText,
267
+ {
268
+ color: black,
269
+ width:
270
+ flatListWidth -
271
+ 16 - // 16 = horizontal padding
272
+ 40 - // 40 = file icon size
273
+ 24 - // 24 = close icon size
274
+ 24, // 24 = internal padding
275
+ },
276
+ I18nManager.isRTL ? { writingDirection: 'rtl' } : { writingDirection: 'ltr' },
277
+ filenameText,
278
+ ]}
279
+ >
280
+ {item.file.name.slice(0, 12) + '...' + item.file.name.slice(lastIndexOfDot)}
281
+ </Text>
282
+ {indicatorType !== null && (
283
+ <UnsupportedFileTypeOrFileSizeIndicator
284
+ indicatorType={indicatorType}
285
+ item={item}
286
+ />
287
+ )}
288
+ </View>
204
289
  </View>
205
290
  </View>
206
- </View>
291
+ )}
292
+ <TouchableOpacity
293
+ onPress={() => {
294
+ removeFile(item.id);
295
+ }}
296
+ style={[styles.dismiss, { backgroundColor: grey_gainsboro }, dismiss]}
297
+ testID='remove-file-upload-preview'
298
+ >
299
+ <Close />
300
+ </TouchableOpacity>
207
301
  </UploadProgressIndicator>
208
302
  <TouchableOpacity
209
303
  onPress={() => {
@@ -234,7 +328,7 @@ const FileUploadPreviewWithContext = <
234
328
  length: FILE_PREVIEW_HEIGHT + 8,
235
329
  offset: (FILE_PREVIEW_HEIGHT + 8) * index,
236
330
  })}
237
- keyExtractor={(item) => item.id}
331
+ keyExtractor={(item) => `${item.id}`}
238
332
  onLayout={({
239
333
  nativeEvent: {
240
334
  layout: { width },
@@ -259,7 +353,11 @@ const areEqual = <StreamChatGenerics extends DefaultStreamChatGenerics = Default
259
353
  return (
260
354
  prevFileUploads.length === nextFileUploads.length &&
261
355
  prevFileUploads.every(
262
- (prevFileUpload, index) => prevFileUpload.state === nextFileUploads[index].state,
356
+ (prevFileUpload, index) =>
357
+ prevFileUpload.state === nextFileUploads[index].state &&
358
+ prevFileUpload.paused === nextFileUploads[index].paused &&
359
+ prevFileUpload.progress === nextFileUploads[index].progress &&
360
+ prevFileUpload.duration === nextFileUploads[index].duration,
263
361
  )
264
362
  );
265
363
  };
@@ -282,13 +380,20 @@ export const FileUploadPreview = <
282
380
  >(
283
381
  props: FileUploadPreviewProps<StreamChatGenerics>,
284
382
  ) => {
285
- const { fileUploads, removeFile, uploadFile } = useMessageInputContext<StreamChatGenerics>();
286
-
383
+ const { AudioAttachmentUploadPreview, fileUploads, removeFile, setFileUploads, uploadFile } =
384
+ useMessageInputContext<StreamChatGenerics>();
287
385
  const { FileAttachmentIcon } = useMessagesContext<StreamChatGenerics>();
288
386
 
289
387
  return (
290
388
  <MemoizedFileUploadPreview
291
- {...{ FileAttachmentIcon, fileUploads, removeFile, uploadFile }}
389
+ {...{
390
+ AudioAttachmentUploadPreview,
391
+ FileAttachmentIcon,
392
+ fileUploads,
393
+ removeFile,
394
+ setFileUploads,
395
+ uploadFile,
396
+ }}
292
397
  {...props}
293
398
  />
294
399
  );
@@ -0,0 +1,199 @@
1
+ import React from 'react';
2
+
3
+ import { act } from 'react-test-renderer';
4
+
5
+ import { fireEvent, render } from '@testing-library/react-native';
6
+
7
+ import type { FileUpload } from '../../../contexts/messageInputContext/MessageInputContext';
8
+ import { ThemeProvider } from '../../../contexts/themeContext/ThemeContext';
9
+ import { defaultTheme } from '../../../contexts/themeContext/utils/theme';
10
+
11
+ import { generateFileUploadPreview } from '../../../mock-builders/generator/attachment';
12
+ import {
13
+ AudioAttachmentUploadPreview,
14
+ AudioAttachmentUploadPreviewProps,
15
+ } from '../AudioAttachmentUploadPreview';
16
+
17
+ jest.mock('../../../native.ts', () => ({
18
+ isAudioPackageAvailable: jest.fn(() => true),
19
+ NetInfo: {
20
+ addEventListener: jest.fn(),
21
+ },
22
+ Sound: {
23
+ initializeSound: jest.fn(),
24
+ Player: null,
25
+ },
26
+ }));
27
+
28
+ jest.mock('react-native/Libraries/ReactNative/I18nManager', () => ({
29
+ isRTL: true,
30
+ }));
31
+
32
+ const getComponent = (props: Partial<AudioAttachmentUploadPreviewProps>) => (
33
+ <ThemeProvider theme={defaultTheme}>
34
+ <AudioAttachmentUploadPreview {...(props as unknown as AudioAttachmentUploadPreviewProps)} />,
35
+ </ThemeProvider>
36
+ );
37
+
38
+ describe('AudioAttachmentUploadPreviewExpo', () => {
39
+ it('handle play pause button when isPausedStatusAvailable unavailable and progress 1', () => {
40
+ const setPositionAsyncMock = jest.fn();
41
+ jest.spyOn(React, 'useRef').mockReturnValue({
42
+ current: {
43
+ setPositionAsync: setPositionAsyncMock,
44
+ },
45
+ });
46
+
47
+ const onPlayPauseMock = jest.fn();
48
+ const { getByA11yLabel } = render(
49
+ getComponent({
50
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
51
+ item: {
52
+ file: { name: 'audio.mp3', uri: 'https://www.test.com/audio.mp3' },
53
+ paused: true,
54
+ progress: 1,
55
+ } as unknown as FileUpload,
56
+ onPlayPause: onPlayPauseMock,
57
+ }),
58
+ );
59
+
60
+ const playPauseButton = getByA11yLabel('Play Pause Button');
61
+
62
+ act(() => {
63
+ fireEvent(playPauseButton, 'onPress');
64
+ });
65
+ expect(setPositionAsyncMock).toHaveBeenCalled();
66
+ });
67
+
68
+ it('handle initial paused state', () => {
69
+ const pauseAsyncMock = jest.fn();
70
+ jest.spyOn(React, 'useRef').mockReturnValue({
71
+ current: {
72
+ pauseAsync: pauseAsyncMock,
73
+ },
74
+ });
75
+
76
+ const onPlayPauseMock = jest.fn();
77
+ const { getByA11yLabel } = render(
78
+ getComponent({
79
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
80
+ item: {
81
+ file: { name: 'audio.mp3', uri: 'https://www.test.com/audio.mp3' },
82
+ paused: true,
83
+ progress: 1,
84
+ } as unknown as FileUpload,
85
+ onPlayPause: onPlayPauseMock,
86
+ }),
87
+ );
88
+
89
+ const playPauseButton = getByA11yLabel('Play Pause Button');
90
+
91
+ act(() => {
92
+ fireEvent(playPauseButton, 'onPress');
93
+ });
94
+ expect(pauseAsyncMock).toHaveBeenCalled();
95
+ });
96
+
97
+ it('handle initial play state', () => {
98
+ const playAsyncMock = jest.fn();
99
+ jest.spyOn(React, 'useRef').mockReturnValue({
100
+ current: {
101
+ playAsync: playAsyncMock,
102
+ },
103
+ });
104
+
105
+ const onPlayPauseMock = jest.fn();
106
+ const { getByA11yLabel } = render(
107
+ getComponent({
108
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
109
+ item: {
110
+ file: { name: 'audio.mp3', uri: 'https://www.test.com/audio.mp3' },
111
+ paused: false,
112
+ progress: 1,
113
+ } as unknown as FileUpload,
114
+ onPlayPause: onPlayPauseMock,
115
+ }),
116
+ );
117
+
118
+ const playPauseButton = getByA11yLabel('Play Pause Button');
119
+
120
+ act(() => {
121
+ fireEvent(playPauseButton, 'onPress');
122
+ });
123
+
124
+ expect(playAsyncMock).toHaveBeenCalled();
125
+ });
126
+
127
+ it('handle unmount', () => {
128
+ const stopAsyncMock = jest.fn();
129
+ const unloadAsyncMock = jest.fn();
130
+ jest.spyOn(React, 'useRef').mockReturnValue({
131
+ current: {
132
+ stopAsync: stopAsyncMock,
133
+ unloadAsync: unloadAsyncMock,
134
+ },
135
+ });
136
+
137
+ const { unmount } = render(
138
+ getComponent({
139
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
140
+ item: {
141
+ file: { name: 'audio.mp3', uri: 'https://www.test.com/audio.mp3' },
142
+ paused: false,
143
+ progress: 1,
144
+ } as unknown as FileUpload,
145
+ }),
146
+ );
147
+
148
+ unmount();
149
+
150
+ expect(stopAsyncMock).toHaveBeenCalled();
151
+ expect(unloadAsyncMock).toHaveBeenCalled();
152
+ });
153
+
154
+ it('render text in rtl mode', () => {
155
+ const { getByA11yLabel } = render(
156
+ getComponent({
157
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
158
+ item: {
159
+ file: { name: 'audio.mp3', uri: 'https://www.test.com/audio.mp3' },
160
+ progress: 1,
161
+ } as unknown as FileUpload,
162
+ }),
163
+ );
164
+
165
+ const textComponent = getByA11yLabel('File Name');
166
+ expect(textComponent?.props.style[2].writingDirection).toBe('rtl');
167
+ });
168
+
169
+ it('handle onProgressDrag event of the progress control', () => {
170
+ const onProgressMock = jest.fn().mockImplementation((id, duration) => ({ duration, id }));
171
+ const setPositionAsyncMock = jest.fn();
172
+
173
+ jest.spyOn(React, 'useRef').mockReturnValue({
174
+ current: {
175
+ setPositionAsync: setPositionAsyncMock,
176
+ },
177
+ });
178
+
179
+ const { getByTestId } = render(
180
+ getComponent({
181
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
182
+ item: { file: { name: 'audio.mp3' }, paused: false } as unknown as FileUpload,
183
+ onProgress: onProgressMock,
184
+ }),
185
+ );
186
+
187
+ const progressControl = getByTestId('progress-control');
188
+
189
+ act(() => {
190
+ fireEvent(progressControl, 'onProgressDrag', {
191
+ currentTime: 10,
192
+ seekableDuration: 10,
193
+ });
194
+ });
195
+
196
+ expect(onProgressMock).toHaveBeenCalled();
197
+ expect(setPositionAsyncMock).toHaveBeenCalled();
198
+ });
199
+ });