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

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 (206) hide show
  1. package/lib/commonjs/components/Attachment/AudioAttachment.js +541 -0
  2. package/lib/commonjs/components/Attachment/AudioAttachment.js.map +1 -0
  3. package/lib/commonjs/components/Attachment/FileAttachmentGroup.js +113 -10
  4. package/lib/commonjs/components/Attachment/FileAttachmentGroup.js.map +1 -1
  5. package/lib/commonjs/components/Attachment/Gallery.js +2 -2
  6. package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
  7. package/lib/commonjs/components/Attachment/{GallaryImage.js → GalleryImage.js} +3 -3
  8. package/lib/{module/components/Attachment/GallaryImage.js.map → commonjs/components/Attachment/GalleryImage.js.map} +1 -1
  9. package/lib/commonjs/components/Attachment/Giphy.js +1 -1
  10. package/lib/commonjs/components/Attachment/Giphy.js.map +1 -1
  11. package/lib/commonjs/components/Attachment/VideoThumbnail.js +10 -5
  12. package/lib/commonjs/components/Attachment/VideoThumbnail.js.map +1 -1
  13. package/lib/commonjs/components/Avatar/Avatar.js +1 -1
  14. package/lib/commonjs/components/Avatar/Avatar.js.map +1 -1
  15. package/lib/commonjs/components/Avatar/GroupAvatar.js +1 -1
  16. package/lib/commonjs/components/Avatar/GroupAvatar.js.map +1 -1
  17. package/lib/commonjs/components/Channel/Channel.js +18 -13
  18. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  19. package/lib/commonjs/components/Channel/hooks/useCreateInputMessageInputContext.js +2 -0
  20. package/lib/commonjs/components/Channel/hooks/useCreateInputMessageInputContext.js.map +1 -1
  21. package/lib/commonjs/components/ImageGallery/ImageGallery.js +37 -30
  22. package/lib/commonjs/components/ImageGallery/ImageGallery.js.map +1 -1
  23. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryImage.js +5 -3
  24. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryImage.js.map +1 -1
  25. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryVideo.js +10 -6
  26. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryVideo.js.map +1 -1
  27. package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js +17 -14
  28. package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
  29. package/lib/commonjs/components/ImageGallery/components/ImageGalleryHeader.js +1 -0
  30. package/lib/commonjs/components/ImageGallery/components/ImageGalleryHeader.js.map +1 -1
  31. package/lib/commonjs/components/ImageGallery/components/ImageGalleryOverlay.js +2 -1
  32. package/lib/commonjs/components/ImageGallery/components/ImageGalleryOverlay.js.map +1 -1
  33. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js +37 -18
  34. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  35. package/lib/commonjs/components/ImageGallery/components/ImageGrid.js +3 -1
  36. package/lib/commonjs/components/ImageGallery/components/ImageGrid.js.map +1 -1
  37. package/lib/commonjs/components/ImageGallery/components/ImageGridHandle.js +5 -4
  38. package/lib/commonjs/components/ImageGallery/components/ImageGridHandle.js.map +1 -1
  39. package/lib/commonjs/components/Message/Message.js +8 -6
  40. package/lib/commonjs/components/Message/Message.js.map +1 -1
  41. package/lib/commonjs/components/Message/MessageSimple/utils/parseLinks.js +1 -1
  42. package/lib/commonjs/components/Message/MessageSimple/utils/parseLinks.js.map +1 -1
  43. package/lib/commonjs/components/Message/MessageSimple/utils/parseLinks.test.js +1 -1
  44. package/lib/commonjs/components/Message/MessageSimple/utils/parseLinks.test.js.map +1 -1
  45. package/lib/commonjs/components/MessageInput/FileUploadPreview.js +125 -35
  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/AudioAttachment.js +541 -0
  65. package/lib/module/components/Attachment/AudioAttachment.js.map +1 -0
  66. package/lib/module/components/Attachment/FileAttachmentGroup.js +113 -10
  67. package/lib/module/components/Attachment/FileAttachmentGroup.js.map +1 -1
  68. package/lib/module/components/Attachment/Gallery.js +2 -2
  69. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  70. package/lib/module/components/Attachment/{GallaryImage.js → GalleryImage.js} +3 -3
  71. package/lib/{commonjs/components/Attachment/GallaryImage.js.map → module/components/Attachment/GalleryImage.js.map} +1 -1
  72. package/lib/module/components/Attachment/Giphy.js +1 -1
  73. package/lib/module/components/Attachment/Giphy.js.map +1 -1
  74. package/lib/module/components/Attachment/VideoThumbnail.js +10 -5
  75. package/lib/module/components/Attachment/VideoThumbnail.js.map +1 -1
  76. package/lib/module/components/Avatar/Avatar.js +1 -1
  77. package/lib/module/components/Avatar/Avatar.js.map +1 -1
  78. package/lib/module/components/Avatar/GroupAvatar.js +1 -1
  79. package/lib/module/components/Avatar/GroupAvatar.js.map +1 -1
  80. package/lib/module/components/Channel/Channel.js +18 -13
  81. package/lib/module/components/Channel/Channel.js.map +1 -1
  82. package/lib/module/components/Channel/hooks/useCreateInputMessageInputContext.js +2 -0
  83. package/lib/module/components/Channel/hooks/useCreateInputMessageInputContext.js.map +1 -1
  84. package/lib/module/components/ImageGallery/ImageGallery.js +37 -30
  85. package/lib/module/components/ImageGallery/ImageGallery.js.map +1 -1
  86. package/lib/module/components/ImageGallery/components/AnimatedGalleryImage.js +5 -3
  87. package/lib/module/components/ImageGallery/components/AnimatedGalleryImage.js.map +1 -1
  88. package/lib/module/components/ImageGallery/components/AnimatedGalleryVideo.js +10 -6
  89. package/lib/module/components/ImageGallery/components/AnimatedGalleryVideo.js.map +1 -1
  90. package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js +17 -14
  91. package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
  92. package/lib/module/components/ImageGallery/components/ImageGalleryHeader.js +1 -0
  93. package/lib/module/components/ImageGallery/components/ImageGalleryHeader.js.map +1 -1
  94. package/lib/module/components/ImageGallery/components/ImageGalleryOverlay.js +2 -1
  95. package/lib/module/components/ImageGallery/components/ImageGalleryOverlay.js.map +1 -1
  96. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js +37 -18
  97. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  98. package/lib/module/components/ImageGallery/components/ImageGrid.js +3 -1
  99. package/lib/module/components/ImageGallery/components/ImageGrid.js.map +1 -1
  100. package/lib/module/components/ImageGallery/components/ImageGridHandle.js +5 -4
  101. package/lib/module/components/ImageGallery/components/ImageGridHandle.js.map +1 -1
  102. package/lib/module/components/Message/Message.js +8 -6
  103. package/lib/module/components/Message/Message.js.map +1 -1
  104. package/lib/module/components/Message/MessageSimple/utils/parseLinks.js +1 -1
  105. package/lib/module/components/Message/MessageSimple/utils/parseLinks.js.map +1 -1
  106. package/lib/module/components/Message/MessageSimple/utils/parseLinks.test.js +1 -1
  107. package/lib/module/components/Message/MessageSimple/utils/parseLinks.test.js.map +1 -1
  108. package/lib/module/components/MessageInput/FileUploadPreview.js +125 -35
  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/AudioAttachment.d.ts +26 -0
  128. package/lib/typescript/components/Attachment/FileAttachmentGroup.d.ts +2 -1
  129. package/lib/typescript/components/Attachment/{GallaryImage.d.ts → GalleryImage.d.ts} +0 -0
  130. package/lib/typescript/components/Channel/hooks/useCreateInputMessageInputContext.d.ts +1 -1
  131. package/lib/typescript/components/ImageGallery/__tests__/AnimatedVideoGallery.test.d.ts +1 -0
  132. package/lib/typescript/components/ImageGallery/__tests__/ImageGallery.test.d.ts +1 -0
  133. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryFooter.test.d.ts +1 -0
  134. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryGrid.test.d.ts +1 -0
  135. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryGridHandle.test.d.ts +1 -0
  136. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryHeader.test.d.ts +1 -0
  137. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryOverlay.test.d.ts +1 -0
  138. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryVideoControl.test.d.ts +1 -0
  139. package/lib/typescript/components/ImageGallery/components/AnimatedGalleryImage.d.ts +1 -0
  140. package/lib/typescript/components/ImageGallery/components/AnimatedGalleryVideo.d.ts +2 -3
  141. package/lib/typescript/components/ImageGallery/components/ImageGalleryFooter.d.ts +2 -1
  142. package/lib/typescript/components/ImageGallery/components/ImageGrid.d.ts +2 -3
  143. package/lib/typescript/components/Message/hooks/useMessageActionHandlers.d.ts +1 -1
  144. package/lib/typescript/components/Message/hooks/useMessageActions.d.ts +1 -1
  145. package/lib/typescript/components/MessageInput/FileUploadPreview.d.ts +1 -1
  146. package/lib/typescript/components/MessageInput/__tests__/AudioAttachmentUploadPreviewExpo.test.d.ts +1 -0
  147. package/lib/typescript/components/MessageInput/__tests__/AudioAttachmentUploadPreviewNative.test.d.ts +1 -0
  148. package/lib/typescript/components/ProgressControl/ProgressControl.d.ts +11 -0
  149. package/lib/typescript/components/index.d.ts +2 -0
  150. package/lib/typescript/contexts/messageContext/MessageContext.d.ts +1 -1
  151. package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts +7 -1
  152. package/lib/typescript/contexts/messageInputContext/hooks/useCreateMessageInputContext.d.ts +1 -1
  153. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +9 -0
  154. package/lib/typescript/native.d.ts +59 -2
  155. package/package.json +1 -1
  156. package/src/components/Attachment/AudioAttachment.tsx +357 -0
  157. package/src/components/Attachment/FileAttachmentGroup.tsx +96 -7
  158. package/src/components/Attachment/Gallery.tsx +1 -1
  159. package/src/components/Attachment/{GallaryImage.tsx → GalleryImage.tsx} +1 -1
  160. package/src/components/Attachment/Giphy.tsx +1 -1
  161. package/src/components/Attachment/VideoThumbnail.tsx +4 -4
  162. package/src/components/Attachment/__tests__/Gallery.test.js +6 -6
  163. package/src/components/Attachment/__tests__/Giphy.test.js +4 -4
  164. package/src/components/Avatar/Avatar.tsx +1 -1
  165. package/src/components/Avatar/GroupAvatar.tsx +1 -1
  166. package/src/components/Channel/Channel.tsx +3 -0
  167. package/src/components/Channel/hooks/useCreateInputMessageInputContext.ts +2 -0
  168. package/src/components/ImageGallery/ImageGallery.tsx +21 -11
  169. package/src/components/ImageGallery/__tests__/AnimatedVideoGallery.test.tsx +241 -0
  170. package/src/components/ImageGallery/__tests__/ImageGallery.test.tsx +192 -0
  171. package/src/components/ImageGallery/__tests__/ImageGalleryFooter.test.tsx +190 -0
  172. package/src/components/ImageGallery/__tests__/ImageGalleryGrid.test.tsx +98 -0
  173. package/src/components/ImageGallery/__tests__/ImageGalleryGridHandle.test.tsx +79 -0
  174. package/src/components/ImageGallery/__tests__/ImageGalleryHeader.test.tsx +172 -0
  175. package/src/components/ImageGallery/__tests__/ImageGalleryOverlay.test.tsx +94 -0
  176. package/src/components/ImageGallery/__tests__/ImageGalleryVideoControl.test.tsx +84 -0
  177. package/src/components/ImageGallery/components/AnimatedGalleryImage.tsx +3 -0
  178. package/src/components/ImageGallery/components/AnimatedGalleryVideo.tsx +11 -3
  179. package/src/components/ImageGallery/components/ImageGalleryFooter.tsx +9 -2
  180. package/src/components/ImageGallery/components/ImageGalleryHeader.tsx +1 -1
  181. package/src/components/ImageGallery/components/ImageGalleryOverlay.tsx +6 -1
  182. package/src/components/ImageGallery/components/ImageGalleryVideoControl.tsx +27 -9
  183. package/src/components/ImageGallery/components/ImageGrid.tsx +19 -17
  184. package/src/components/ImageGallery/components/ImageGridHandle.tsx +4 -1
  185. package/src/components/Message/Message.tsx +2 -1
  186. package/src/components/Message/MessageSimple/__tests__/MessageContent.test.js +11 -3
  187. package/src/components/Message/MessageSimple/__tests__/__snapshots__/MessageAvatar.test.js.snap +1 -1
  188. package/src/components/Message/MessageSimple/utils/parseLinks.test.ts +4 -0
  189. package/src/components/Message/MessageSimple/utils/parseLinks.ts +1 -1
  190. package/src/components/MessageInput/FileUploadPreview.tsx +162 -66
  191. package/src/components/MessageInput/__tests__/AudioAttachmentUploadPreviewExpo.test.tsx +196 -0
  192. package/src/components/MessageInput/__tests__/AudioAttachmentUploadPreviewNative.test.tsx +212 -0
  193. package/src/components/MessageInput/__tests__/FileUploadPreview.test.js +64 -0
  194. package/src/components/{ImageGallery/components → ProgressControl}/ProgressControl.tsx +37 -19
  195. package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +4 -4
  196. package/src/components/index.ts +3 -0
  197. package/src/contexts/messageInputContext/MessageInputContext.tsx +11 -0
  198. package/src/contexts/messageInputContext/hooks/useCreateMessageInputContext.ts +5 -1
  199. package/src/contexts/themeContext/utils/theme.ts +15 -0
  200. package/src/icons/Pause.tsx +2 -2
  201. package/src/mock-builders/api/channelMocks.tsx +1 -0
  202. package/src/native.ts +67 -7
  203. package/src/version.json +1 -1
  204. package/lib/commonjs/components/ImageGallery/components/ProgressControl.js.map +0 -1
  205. package/lib/module/components/ImageGallery/components/ProgressControl.js.map +0 -1
  206. 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' | 'AudioAttachment'
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
+ AudioAttachment,
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, pausedStatus?: boolean) => {
176
+ if (pausedStatus === 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,62 +223,82 @@ 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
+ <AudioAttachment
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 pathFill={grey_dark} />
300
+ </TouchableOpacity>
207
301
  </UploadProgressIndicator>
208
- <TouchableOpacity
209
- onPress={() => {
210
- removeFile(item.id);
211
- }}
212
- style={[styles.dismiss, { backgroundColor: grey_gainsboro }, dismiss]}
213
- testID='remove-file-upload-preview'
214
- >
215
- <Close pathFill={grey_dark} />
216
- </TouchableOpacity>
217
302
  </>
218
303
  );
219
304
  };
@@ -234,7 +319,7 @@ const FileUploadPreviewWithContext = <
234
319
  length: FILE_PREVIEW_HEIGHT + 8,
235
320
  offset: (FILE_PREVIEW_HEIGHT + 8) * index,
236
321
  })}
237
- keyExtractor={(item) => item.id}
322
+ keyExtractor={(item) => `${item.id}`}
238
323
  onLayout={({
239
324
  nativeEvent: {
240
325
  layout: { width },
@@ -259,7 +344,11 @@ const areEqual = <StreamChatGenerics extends DefaultStreamChatGenerics = Default
259
344
  return (
260
345
  prevFileUploads.length === nextFileUploads.length &&
261
346
  prevFileUploads.every(
262
- (prevFileUpload, index) => prevFileUpload.state === nextFileUploads[index].state,
347
+ (prevFileUpload, index) =>
348
+ prevFileUpload.state === nextFileUploads[index].state &&
349
+ prevFileUpload.paused === nextFileUploads[index].paused &&
350
+ prevFileUpload.progress === nextFileUploads[index].progress &&
351
+ prevFileUpload.duration === nextFileUploads[index].duration,
263
352
  )
264
353
  );
265
354
  };
@@ -282,13 +371,20 @@ export const FileUploadPreview = <
282
371
  >(
283
372
  props: FileUploadPreviewProps<StreamChatGenerics>,
284
373
  ) => {
285
- const { fileUploads, removeFile, uploadFile } = useMessageInputContext<StreamChatGenerics>();
286
-
374
+ const { AudioAttachment, fileUploads, removeFile, setFileUploads, uploadFile } =
375
+ useMessageInputContext<StreamChatGenerics>();
287
376
  const { FileAttachmentIcon } = useMessagesContext<StreamChatGenerics>();
288
377
 
289
378
  return (
290
379
  <MemoizedFileUploadPreview
291
- {...{ FileAttachmentIcon, fileUploads, removeFile, uploadFile }}
380
+ {...{
381
+ AudioAttachment,
382
+ FileAttachmentIcon,
383
+ fileUploads,
384
+ removeFile,
385
+ setFileUploads,
386
+ uploadFile,
387
+ }}
292
388
  {...props}
293
389
  />
294
390
  );
@@ -0,0 +1,196 @@
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 { AudioAttachment, AudioAttachmentProps } from '../../Attachment/AudioAttachment';
13
+
14
+ jest.mock('../../../native.ts', () => ({
15
+ isAudioPackageAvailable: jest.fn(() => true),
16
+ NetInfo: {
17
+ addEventListener: jest.fn(),
18
+ },
19
+ Sound: {
20
+ initializeSound: jest.fn(),
21
+ Player: null,
22
+ },
23
+ }));
24
+
25
+ jest.mock('react-native/Libraries/ReactNative/I18nManager', () => ({
26
+ isRTL: true,
27
+ }));
28
+
29
+ const getComponent = (props: Partial<AudioAttachmentProps>) => (
30
+ <ThemeProvider theme={defaultTheme}>
31
+ <AudioAttachment {...(props as unknown as AudioAttachmentProps)} />,
32
+ </ThemeProvider>
33
+ );
34
+
35
+ describe('AudioAttachmentExpo', () => {
36
+ it('handle play pause button when isPausedStatusAvailable unavailable and progress 1', () => {
37
+ const setPositionAsyncMock = jest.fn();
38
+ jest.spyOn(React, 'useRef').mockReturnValue({
39
+ current: {
40
+ setPositionAsync: setPositionAsyncMock,
41
+ },
42
+ });
43
+
44
+ const onPlayPauseMock = jest.fn();
45
+ const { getByA11yLabel } = render(
46
+ getComponent({
47
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
48
+ item: {
49
+ file: { name: 'audio.mp3', uri: 'https://www.test.com/audio.mp3' },
50
+ paused: true,
51
+ progress: 1,
52
+ } as unknown as FileUpload,
53
+ onPlayPause: onPlayPauseMock,
54
+ }),
55
+ );
56
+
57
+ const playPauseButton = getByA11yLabel('Play Pause Button');
58
+
59
+ act(() => {
60
+ fireEvent(playPauseButton, 'onPress');
61
+ });
62
+ expect(setPositionAsyncMock).toHaveBeenCalled();
63
+ });
64
+
65
+ it('handle initial paused state', () => {
66
+ const pauseAsyncMock = jest.fn();
67
+ jest.spyOn(React, 'useRef').mockReturnValue({
68
+ current: {
69
+ pauseAsync: pauseAsyncMock,
70
+ },
71
+ });
72
+
73
+ const onPlayPauseMock = jest.fn();
74
+ const { getByA11yLabel } = render(
75
+ getComponent({
76
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
77
+ item: {
78
+ file: { name: 'audio.mp3', uri: 'https://www.test.com/audio.mp3' },
79
+ paused: true,
80
+ progress: 1,
81
+ } as unknown as FileUpload,
82
+ onPlayPause: onPlayPauseMock,
83
+ }),
84
+ );
85
+
86
+ const playPauseButton = getByA11yLabel('Play Pause Button');
87
+
88
+ act(() => {
89
+ fireEvent(playPauseButton, 'onPress');
90
+ });
91
+ expect(pauseAsyncMock).toHaveBeenCalled();
92
+ });
93
+
94
+ it('handle initial play state', () => {
95
+ const playAsyncMock = jest.fn();
96
+ jest.spyOn(React, 'useRef').mockReturnValue({
97
+ current: {
98
+ playAsync: playAsyncMock,
99
+ },
100
+ });
101
+
102
+ const onPlayPauseMock = jest.fn();
103
+ const { getByA11yLabel } = render(
104
+ getComponent({
105
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
106
+ item: {
107
+ file: { name: 'audio.mp3', uri: 'https://www.test.com/audio.mp3' },
108
+ paused: false,
109
+ progress: 1,
110
+ } as unknown as FileUpload,
111
+ onPlayPause: onPlayPauseMock,
112
+ }),
113
+ );
114
+
115
+ const playPauseButton = getByA11yLabel('Play Pause Button');
116
+
117
+ act(() => {
118
+ fireEvent(playPauseButton, 'onPress');
119
+ });
120
+
121
+ expect(playAsyncMock).toHaveBeenCalled();
122
+ });
123
+
124
+ it('handle unmount', () => {
125
+ const stopAsyncMock = jest.fn();
126
+ const unloadAsyncMock = jest.fn();
127
+ jest.spyOn(React, 'useRef').mockReturnValue({
128
+ current: {
129
+ stopAsync: stopAsyncMock,
130
+ unloadAsync: unloadAsyncMock,
131
+ },
132
+ });
133
+
134
+ const { unmount } = render(
135
+ getComponent({
136
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
137
+ item: {
138
+ file: { name: 'audio.mp3', uri: 'https://www.test.com/audio.mp3' },
139
+ paused: false,
140
+ progress: 1,
141
+ } as unknown as FileUpload,
142
+ }),
143
+ );
144
+
145
+ unmount();
146
+
147
+ expect(stopAsyncMock).toHaveBeenCalled();
148
+ expect(unloadAsyncMock).toHaveBeenCalled();
149
+ });
150
+
151
+ it('render text in rtl mode', () => {
152
+ const { getByA11yLabel } = render(
153
+ getComponent({
154
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
155
+ item: {
156
+ file: { name: 'audio.mp3', uri: 'https://www.test.com/audio.mp3' },
157
+ progress: 1,
158
+ } as unknown as FileUpload,
159
+ }),
160
+ );
161
+
162
+ const textComponent = getByA11yLabel('File Name');
163
+ expect(textComponent?.props.style[2].writingDirection).toBe('rtl');
164
+ });
165
+
166
+ it('handle onProgressDrag event of the progress control', () => {
167
+ const onProgressMock = jest.fn().mockImplementation((id, duration) => ({ duration, id }));
168
+ const setPositionAsyncMock = jest.fn();
169
+
170
+ jest.spyOn(React, 'useRef').mockReturnValue({
171
+ current: {
172
+ setPositionAsync: setPositionAsyncMock,
173
+ },
174
+ });
175
+
176
+ const { getByTestId } = render(
177
+ getComponent({
178
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
179
+ item: { file: { name: 'audio.mp3' }, paused: false } as unknown as FileUpload,
180
+ onProgress: onProgressMock,
181
+ }),
182
+ );
183
+
184
+ const progressControl = getByTestId('progress-control');
185
+
186
+ act(() => {
187
+ fireEvent(progressControl, 'onProgressDrag', {
188
+ currentTime: 10,
189
+ seekableDuration: 10,
190
+ });
191
+ });
192
+
193
+ expect(onProgressMock).toHaveBeenCalled();
194
+ expect(setPositionAsyncMock).toHaveBeenCalled();
195
+ });
196
+ });