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

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 (190) 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/ImageGallery/ImageGallery.js +37 -30
  18. package/lib/commonjs/components/ImageGallery/ImageGallery.js.map +1 -1
  19. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryImage.js +5 -3
  20. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryImage.js.map +1 -1
  21. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryVideo.js +10 -6
  22. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryVideo.js.map +1 -1
  23. package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js +17 -14
  24. package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
  25. package/lib/commonjs/components/ImageGallery/components/ImageGalleryHeader.js +1 -0
  26. package/lib/commonjs/components/ImageGallery/components/ImageGalleryHeader.js.map +1 -1
  27. package/lib/commonjs/components/ImageGallery/components/ImageGalleryOverlay.js +2 -1
  28. package/lib/commonjs/components/ImageGallery/components/ImageGalleryOverlay.js.map +1 -1
  29. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js +36 -18
  30. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  31. package/lib/commonjs/components/ImageGallery/components/ImageGrid.js +3 -1
  32. package/lib/commonjs/components/ImageGallery/components/ImageGrid.js.map +1 -1
  33. package/lib/commonjs/components/ImageGallery/components/ImageGridHandle.js +5 -4
  34. package/lib/commonjs/components/ImageGallery/components/ImageGridHandle.js.map +1 -1
  35. package/lib/commonjs/components/Message/Message.js +8 -6
  36. package/lib/commonjs/components/Message/Message.js.map +1 -1
  37. package/lib/commonjs/components/MessageInput/AudioAttachmentUploadPreview.js +538 -0
  38. package/lib/commonjs/components/MessageInput/AudioAttachmentUploadPreview.js.map +1 -0
  39. package/lib/commonjs/components/MessageInput/FileUploadPreview.js +143 -32
  40. package/lib/commonjs/components/MessageInput/FileUploadPreview.js.map +1 -1
  41. package/lib/{module/components/ImageGallery/components → commonjs/components/ProgressControl}/ProgressControl.js +37 -24
  42. package/lib/commonjs/components/ProgressControl/ProgressControl.js.map +1 -0
  43. package/lib/commonjs/components/index.js +26 -0
  44. package/lib/commonjs/components/index.js.map +1 -1
  45. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +5 -2
  46. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  47. package/lib/commonjs/contexts/messageInputContext/hooks/useCreateMessageInputContext.js +7 -2
  48. package/lib/commonjs/contexts/messageInputContext/hooks/useCreateMessageInputContext.js.map +1 -1
  49. package/lib/commonjs/contexts/themeContext/utils/theme.js +9 -0
  50. package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
  51. package/lib/commonjs/icons/Pause.js +2 -2
  52. package/lib/commonjs/icons/Pause.js.map +1 -1
  53. package/lib/commonjs/mock-builders/api/channelMocks.js +1 -0
  54. package/lib/commonjs/mock-builders/api/channelMocks.js.map +1 -1
  55. package/lib/commonjs/native.js +13 -5
  56. package/lib/commonjs/native.js.map +1 -1
  57. package/lib/commonjs/version.json +1 -1
  58. package/lib/module/components/Attachment/Gallery.js +2 -2
  59. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  60. package/lib/module/components/Attachment/{GallaryImage.js → GalleryImage.js} +3 -3
  61. package/lib/{commonjs/components/Attachment/GallaryImage.js.map → module/components/Attachment/GalleryImage.js.map} +1 -1
  62. package/lib/module/components/Attachment/Giphy.js +1 -1
  63. package/lib/module/components/Attachment/Giphy.js.map +1 -1
  64. package/lib/module/components/Attachment/VideoThumbnail.js +4 -5
  65. package/lib/module/components/Attachment/VideoThumbnail.js.map +1 -1
  66. package/lib/module/components/Avatar/Avatar.js +1 -1
  67. package/lib/module/components/Avatar/Avatar.js.map +1 -1
  68. package/lib/module/components/Avatar/GroupAvatar.js +1 -1
  69. package/lib/module/components/Avatar/GroupAvatar.js.map +1 -1
  70. package/lib/module/components/Channel/Channel.js +18 -13
  71. package/lib/module/components/Channel/Channel.js.map +1 -1
  72. package/lib/module/components/Channel/hooks/useCreateInputMessageInputContext.js +2 -0
  73. package/lib/module/components/Channel/hooks/useCreateInputMessageInputContext.js.map +1 -1
  74. package/lib/module/components/ImageGallery/ImageGallery.js +37 -30
  75. package/lib/module/components/ImageGallery/ImageGallery.js.map +1 -1
  76. package/lib/module/components/ImageGallery/components/AnimatedGalleryImage.js +5 -3
  77. package/lib/module/components/ImageGallery/components/AnimatedGalleryImage.js.map +1 -1
  78. package/lib/module/components/ImageGallery/components/AnimatedGalleryVideo.js +10 -6
  79. package/lib/module/components/ImageGallery/components/AnimatedGalleryVideo.js.map +1 -1
  80. package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js +17 -14
  81. package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
  82. package/lib/module/components/ImageGallery/components/ImageGalleryHeader.js +1 -0
  83. package/lib/module/components/ImageGallery/components/ImageGalleryHeader.js.map +1 -1
  84. package/lib/module/components/ImageGallery/components/ImageGalleryOverlay.js +2 -1
  85. package/lib/module/components/ImageGallery/components/ImageGalleryOverlay.js.map +1 -1
  86. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js +36 -18
  87. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  88. package/lib/module/components/ImageGallery/components/ImageGrid.js +3 -1
  89. package/lib/module/components/ImageGallery/components/ImageGrid.js.map +1 -1
  90. package/lib/module/components/ImageGallery/components/ImageGridHandle.js +5 -4
  91. package/lib/module/components/ImageGallery/components/ImageGridHandle.js.map +1 -1
  92. package/lib/module/components/Message/Message.js +8 -6
  93. package/lib/module/components/Message/Message.js.map +1 -1
  94. package/lib/module/components/MessageInput/AudioAttachmentUploadPreview.js +538 -0
  95. package/lib/module/components/MessageInput/AudioAttachmentUploadPreview.js.map +1 -0
  96. package/lib/module/components/MessageInput/FileUploadPreview.js +143 -32
  97. package/lib/module/components/MessageInput/FileUploadPreview.js.map +1 -1
  98. package/lib/{commonjs/components/ImageGallery/components → module/components/ProgressControl}/ProgressControl.js +37 -24
  99. package/lib/module/components/ProgressControl/ProgressControl.js.map +1 -0
  100. package/lib/module/components/index.js +26 -0
  101. package/lib/module/components/index.js.map +1 -1
  102. package/lib/module/contexts/messageInputContext/MessageInputContext.js +5 -2
  103. package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  104. package/lib/module/contexts/messageInputContext/hooks/useCreateMessageInputContext.js +7 -2
  105. package/lib/module/contexts/messageInputContext/hooks/useCreateMessageInputContext.js.map +1 -1
  106. package/lib/module/contexts/themeContext/utils/theme.js +9 -0
  107. package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
  108. package/lib/module/icons/Pause.js +2 -2
  109. package/lib/module/icons/Pause.js.map +1 -1
  110. package/lib/module/mock-builders/api/channelMocks.js +1 -0
  111. package/lib/module/mock-builders/api/channelMocks.js.map +1 -1
  112. package/lib/module/native.js +13 -5
  113. package/lib/module/native.js.map +1 -1
  114. package/lib/module/version.json +1 -1
  115. package/lib/typescript/components/Attachment/{GallaryImage.d.ts → GalleryImage.d.ts} +0 -0
  116. package/lib/typescript/components/Channel/hooks/useCreateInputMessageInputContext.d.ts +1 -1
  117. package/lib/typescript/components/ImageGallery/__tests__/AnimatedVideoGallery.test.d.ts +1 -0
  118. package/lib/typescript/components/ImageGallery/__tests__/ImageGallery.test.d.ts +1 -0
  119. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryFooter.test.d.ts +1 -0
  120. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryGrid.test.d.ts +1 -0
  121. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryGridHandle.test.d.ts +1 -0
  122. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryHeader.test.d.ts +1 -0
  123. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryOverlay.test.d.ts +1 -0
  124. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryVideoControl.test.d.ts +1 -0
  125. package/lib/typescript/components/ImageGallery/components/AnimatedGalleryImage.d.ts +1 -0
  126. package/lib/typescript/components/ImageGallery/components/AnimatedGalleryVideo.d.ts +2 -3
  127. package/lib/typescript/components/ImageGallery/components/ImageGalleryFooter.d.ts +2 -1
  128. package/lib/typescript/components/ImageGallery/components/ImageGrid.d.ts +2 -3
  129. package/lib/typescript/components/Message/hooks/useMessageActionHandlers.d.ts +1 -1
  130. package/lib/typescript/components/Message/hooks/useMessageActions.d.ts +1 -1
  131. package/lib/typescript/components/MessageInput/AudioAttachmentUploadPreview.d.ts +26 -0
  132. package/lib/typescript/components/MessageInput/FileUploadPreview.d.ts +1 -1
  133. package/lib/typescript/components/MessageInput/__tests__/AudioAttachmentUploadPreviewExpo.test.d.ts +1 -0
  134. package/lib/typescript/components/MessageInput/__tests__/AudioAttachmentUploadPreviewNative.test.d.ts +1 -0
  135. package/lib/typescript/components/ProgressControl/ProgressControl.d.ts +11 -0
  136. package/lib/typescript/components/index.d.ts +2 -0
  137. package/lib/typescript/contexts/messageContext/MessageContext.d.ts +1 -1
  138. package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts +7 -1
  139. package/lib/typescript/contexts/messageInputContext/hooks/useCreateMessageInputContext.d.ts +1 -1
  140. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +9 -0
  141. package/lib/typescript/native.d.ts +59 -2
  142. package/package.json +1 -1
  143. package/src/components/Attachment/Gallery.tsx +1 -1
  144. package/src/components/Attachment/{GallaryImage.tsx → GalleryImage.tsx} +1 -1
  145. package/src/components/Attachment/Giphy.tsx +1 -1
  146. package/src/components/Attachment/VideoThumbnail.tsx +1 -2
  147. package/src/components/Attachment/__tests__/Gallery.test.js +6 -6
  148. package/src/components/Attachment/__tests__/Giphy.test.js +4 -4
  149. package/src/components/Avatar/Avatar.tsx +1 -1
  150. package/src/components/Avatar/GroupAvatar.tsx +1 -1
  151. package/src/components/Channel/Channel.tsx +3 -0
  152. package/src/components/Channel/hooks/useCreateInputMessageInputContext.ts +2 -0
  153. package/src/components/ImageGallery/ImageGallery.tsx +21 -11
  154. package/src/components/ImageGallery/__tests__/AnimatedVideoGallery.test.tsx +241 -0
  155. package/src/components/ImageGallery/__tests__/ImageGallery.test.tsx +192 -0
  156. package/src/components/ImageGallery/__tests__/ImageGalleryFooter.test.tsx +190 -0
  157. package/src/components/ImageGallery/__tests__/ImageGalleryGrid.test.tsx +98 -0
  158. package/src/components/ImageGallery/__tests__/ImageGalleryGridHandle.test.tsx +79 -0
  159. package/src/components/ImageGallery/__tests__/ImageGalleryHeader.test.tsx +172 -0
  160. package/src/components/ImageGallery/__tests__/ImageGalleryOverlay.test.tsx +94 -0
  161. package/src/components/ImageGallery/__tests__/ImageGalleryVideoControl.test.tsx +84 -0
  162. package/src/components/ImageGallery/components/AnimatedGalleryImage.tsx +3 -0
  163. package/src/components/ImageGallery/components/AnimatedGalleryVideo.tsx +11 -3
  164. package/src/components/ImageGallery/components/ImageGalleryFooter.tsx +9 -2
  165. package/src/components/ImageGallery/components/ImageGalleryHeader.tsx +1 -1
  166. package/src/components/ImageGallery/components/ImageGalleryOverlay.tsx +6 -1
  167. package/src/components/ImageGallery/components/ImageGalleryVideoControl.tsx +22 -9
  168. package/src/components/ImageGallery/components/ImageGrid.tsx +19 -17
  169. package/src/components/ImageGallery/components/ImageGridHandle.tsx +4 -1
  170. package/src/components/Message/Message.tsx +2 -1
  171. package/src/components/Message/MessageSimple/__tests__/MessageContent.test.js +9 -3
  172. package/src/components/Message/MessageSimple/__tests__/__snapshots__/MessageAvatar.test.js.snap +1 -1
  173. package/src/components/MessageInput/AudioAttachmentUploadPreview.tsx +362 -0
  174. package/src/components/MessageInput/FileUploadPreview.tsx +162 -57
  175. package/src/components/MessageInput/__tests__/AudioAttachmentUploadPreviewExpo.test.tsx +199 -0
  176. package/src/components/MessageInput/__tests__/AudioAttachmentUploadPreviewNative.test.tsx +215 -0
  177. package/src/components/MessageInput/__tests__/FileUploadPreview.test.js +64 -0
  178. package/src/components/{ImageGallery/components → ProgressControl}/ProgressControl.tsx +37 -19
  179. package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +4 -4
  180. package/src/components/index.ts +3 -0
  181. package/src/contexts/messageInputContext/MessageInputContext.tsx +13 -0
  182. package/src/contexts/messageInputContext/hooks/useCreateMessageInputContext.ts +5 -1
  183. package/src/contexts/themeContext/utils/theme.ts +15 -0
  184. package/src/icons/Pause.tsx +2 -2
  185. package/src/mock-builders/api/channelMocks.tsx +1 -0
  186. package/src/native.ts +67 -7
  187. package/src/version.json +1 -1
  188. package/lib/commonjs/components/ImageGallery/components/ProgressControl.js.map +0 -1
  189. package/lib/module/components/ImageGallery/components/ProgressControl.js.map +0 -1
  190. package/lib/typescript/components/ImageGallery/components/ProgressControl.d.ts +0 -5
@@ -4,20 +4,18 @@ import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
4
4
  import dayjs from 'dayjs';
5
5
 
6
6
  import type { ImageGalleryFooterVideoControlProps } from './ImageGalleryFooter';
7
- import { ProgressControl } from './ProgressControl';
8
7
 
9
8
  import { useTheme } from '../../../contexts/themeContext/ThemeContext';
10
9
 
11
10
  import { Pause, Play } from '../../../icons';
11
+ import { ProgressControl } from '../../ProgressControl/ProgressControl';
12
12
 
13
13
  const styles = StyleSheet.create({
14
14
  durationTextStyle: {
15
- color: '#fff',
16
15
  fontWeight: 'bold',
17
16
  },
18
17
  roundedView: {
19
18
  alignItems: 'center',
20
- backgroundColor: '#fff',
21
19
  borderRadius: 50,
22
20
  display: 'flex',
23
21
  elevation: 2,
@@ -55,6 +53,7 @@ export const ImageGalleryVideoControl: React.FC<ImageGalleryFooterVideoControlPr
55
53
 
56
54
  const {
57
55
  theme: {
56
+ colors: { black, white_snow },
58
57
  imageGallery: {
59
58
  videoControl: { durationTextStyle, roundedView, videoContainer },
60
59
  },
@@ -63,25 +62,39 @@ export const ImageGalleryVideoControl: React.FC<ImageGalleryFooterVideoControlPr
63
62
 
64
63
  return (
65
64
  <View style={[styles.videoContainer, videoContainer]}>
66
- <TouchableOpacity onPress={onPlayPause}>
67
- <View style={[styles.roundedView, roundedView]}>
65
+ <TouchableOpacity
66
+ accessibilityLabel='Play Pause Button'
67
+ onPress={() => {
68
+ onPlayPause();
69
+ }}
70
+ >
71
+ <View style={[styles.roundedView, roundedView, { backgroundColor: white_snow }]}>
68
72
  {paused ? (
69
- <Play height={24} pathFill={'#000'} width={24} />
73
+ <Play accessibilityLabel='Play Icon' height={24} pathFill={black} width={24} />
70
74
  ) : (
71
- <Pause height={24} width={24} />
75
+ <Pause accessibilityLabel='Pause Icon' height={24} width={24} />
72
76
  )}
73
77
  </View>
74
78
  </TouchableOpacity>
75
- <Text style={[styles.durationTextStyle, durationTextStyle]}>
79
+ <Text
80
+ accessibilityLabel='Progress Duration'
81
+ style={[styles.durationTextStyle, durationTextStyle, { color: white_snow }]}
82
+ >
76
83
  {progressDuration ? progressDuration : '00:00'}
77
84
  </Text>
78
85
  <ProgressControl
79
86
  duration={duration}
87
+ filledColor={white_snow}
80
88
  onPlayPause={onPlayPause}
81
89
  onProgressDrag={onProgressDrag}
82
90
  progress={progress}
91
+ testID={'progress-control'}
92
+ width={180}
83
93
  />
84
- <Text style={[styles.durationTextStyle, durationTextStyle]}>
94
+ <Text
95
+ accessibilityLabel='Video Duration'
96
+ style={[styles.durationTextStyle, durationTextStyle, { color: white_snow }]}
97
+ >
85
98
  {videoDuration ? videoDuration : '00:00'}
86
99
  </Text>
87
100
  </View>
@@ -82,7 +82,7 @@ const GridImage = <
82
82
  }
83
83
 
84
84
  return (
85
- <TouchableOpacity onPress={selectAndClose}>
85
+ <TouchableOpacity accessibilityLabel='Grid Image' onPress={selectAndClose}>
86
86
  {type === 'video' ? (
87
87
  <View style={[styles.image, { height: size, width: size }, gridImage]}>
88
88
  <VideoThumbnail />
@@ -102,26 +102,27 @@ const renderItem = <
102
102
  item: GridImageItem<StreamChatGenerics>;
103
103
  }) => <GridImage item={item} />;
104
104
 
105
- type Props<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> =
106
- ImageGalleryGridImageComponents<StreamChatGenerics> & {
107
- closeGridView: () => void;
108
- photos: Photo<StreamChatGenerics>[];
109
- setImage: React.Dispatch<
110
- React.SetStateAction<
111
- | {
112
- messageId?: string | undefined;
113
- url?: string | undefined;
114
- }
115
- | undefined
116
- >
117
- >;
118
- numberOfImageGalleryGridColumns?: number;
119
- };
105
+ export type ImageGridType<
106
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
107
+ > = ImageGalleryGridImageComponents<StreamChatGenerics> & {
108
+ closeGridView: () => void;
109
+ photos: Photo<StreamChatGenerics>[];
110
+ setImage: React.Dispatch<
111
+ React.SetStateAction<
112
+ | {
113
+ messageId?: string | undefined;
114
+ url?: string | undefined;
115
+ }
116
+ | undefined
117
+ >
118
+ >;
119
+ numberOfImageGalleryGridColumns?: number;
120
+ };
120
121
 
121
122
  export const ImageGrid = <
122
123
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
123
124
  >(
124
- props: Props<StreamChatGenerics>,
125
+ props: ImageGridType<StreamChatGenerics>,
125
126
  ) => {
126
127
  const {
127
128
  avatarComponent,
@@ -154,6 +155,7 @@ export const ImageGrid = <
154
155
 
155
156
  return (
156
157
  <BottomSheetFlatList<GridImageItem<StreamChatGenerics>>
158
+ accessibilityLabel='Image Grid'
157
159
  contentContainerStyle={[
158
160
  styles.contentContainer,
159
161
  { backgroundColor: white },
@@ -60,7 +60,10 @@ export const ImageGridHandle: React.FC<Props> = (props) => {
60
60
  const { t } = useTranslationContext();
61
61
 
62
62
  return (
63
- <View style={[styles.handle, { backgroundColor: white }, handle]}>
63
+ <View
64
+ accessibilityLabel='Image Grid Handle'
65
+ style={[styles.handle, { backgroundColor: white }, handle]}
66
+ >
64
67
  {leftComponent ? leftComponent({ closeGridView }) : <View style={styles.leftContainer} />}
65
68
  {centerComponent ? (
66
69
  centerComponent({ closeGridView })
@@ -342,6 +342,8 @@ const MessageWithContext = <
342
342
  } else if (cur.type === 'video' && !cur.og_scrape_url) {
343
343
  acc.files.push(cur);
344
344
  acc.other = []; // remove other attachments if a file exists
345
+ } else if (cur.type === 'audio') {
346
+ acc.files.push(cur);
345
347
  } else if (cur.type === 'image' && !cur.title_link && !cur.og_scrape_url) {
346
348
  /**
347
349
  * this next if is not combined with the above one for cases where we have
@@ -371,7 +373,6 @@ const MessageWithContext = <
371
373
  other: [] as Attachment<StreamChatGenerics>[],
372
374
  videos: [] as Attachment<StreamChatGenerics>[],
373
375
  };
374
-
375
376
  /**
376
377
  * Check if any actions to prevent long press
377
378
  */
@@ -188,15 +188,21 @@ describe('MessageContent', () => {
188
188
  it('renders the FileAttachment component when a file attachment exists', async () => {
189
189
  const user = generateUser();
190
190
  const message = generateMessage({
191
- attachments: [{ title: 'file', type: 'file' }],
191
+ attachments: [
192
+ { title: 'file', type: 'file' },
193
+ { title: 'audio', type: 'audio' },
194
+ { title: 'video', type: 'video' },
195
+ ],
192
196
  user,
193
197
  });
194
198
 
195
- const { getByTestId } = renderMessage({ message });
199
+ const { getByTestId, queryAllByTestId } = renderMessage({ message });
200
+
201
+ const fileAttachments = queryAllByTestId('file-attachment');
196
202
 
197
203
  await waitFor(() => {
198
204
  expect(getByTestId('message-content-wrapper')).toBeTruthy();
199
- expect(getByTestId('file-attachment')).toBeTruthy();
205
+ expect(fileAttachments).toHaveLength(2);
200
206
  });
201
207
  });
202
208
 
@@ -32,7 +32,7 @@ exports[`MessageAvatar should render message avatar 1`] = `
32
32
  }
33
33
  >
34
34
  <Image
35
- accessibilityLabel="avatar-image"
35
+ accessibilityLabel="Avatar Image"
36
36
  onError={[Function]}
37
37
  source={
38
38
  Object {
@@ -0,0 +1,362 @@
1
+ import React, { useEffect } from 'react';
2
+ import { I18nManager, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
3
+
4
+ import dayjs from 'dayjs';
5
+ import duration from 'dayjs/plugin/duration';
6
+
7
+ import {
8
+ FileUpload,
9
+ MessageInputContextValue,
10
+ useMessageInputContext,
11
+ useTheme,
12
+ } from '../../contexts';
13
+ import { Pause, Play } from '../../icons';
14
+ import {
15
+ PlaybackStatus,
16
+ Sound,
17
+ SoundReturnType,
18
+ VideoPayloadData,
19
+ VideoProgressData,
20
+ } from '../../native';
21
+ import type { DefaultStreamChatGenerics } from '../../types/types';
22
+ import { ProgressControl } from '../ProgressControl/ProgressControl';
23
+
24
+ dayjs.extend(duration);
25
+
26
+ const FILE_PREVIEW_HEIGHT = 70;
27
+
28
+ const styles = StyleSheet.create({
29
+ fileContainer: {
30
+ borderRadius: 12,
31
+ borderWidth: 1,
32
+ flexDirection: 'row',
33
+ height: FILE_PREVIEW_HEIGHT,
34
+ paddingLeft: 8,
35
+ paddingRight: 8,
36
+ },
37
+ fileContentContainer: { flexDirection: 'row' },
38
+ filenameText: {
39
+ fontSize: 14,
40
+ fontWeight: 'bold',
41
+ paddingLeft: 10,
42
+ },
43
+ fileTextContainer: {
44
+ justifyContent: 'space-around',
45
+ },
46
+ flatList: { marginBottom: 12, maxHeight: FILE_PREVIEW_HEIGHT * 2.5 + 16 },
47
+ overlay: {
48
+ borderRadius: 12,
49
+ marginLeft: 8,
50
+ marginRight: 8,
51
+ },
52
+ progressControlView: {
53
+ flex: 8,
54
+ },
55
+ progressDurationText: {
56
+ flex: 4,
57
+ fontSize: 12,
58
+ paddingLeft: 10,
59
+ paddingRight: 8,
60
+ },
61
+ roundedView: {
62
+ alignItems: 'center',
63
+ alignSelf: 'center',
64
+ borderRadius: 50,
65
+ display: 'flex',
66
+ elevation: 4,
67
+ height: 36,
68
+ justifyContent: 'center',
69
+ shadowOffset: {
70
+ height: 2,
71
+ width: 0,
72
+ },
73
+ shadowOpacity: 0.23,
74
+ shadowRadius: 2.62,
75
+ width: 36,
76
+ },
77
+ });
78
+
79
+ export type AudioAttachmentUploadPreviewPropsWithContext<
80
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
81
+ > = Pick<
82
+ MessageInputContextValue<StreamChatGenerics>,
83
+ 'fileUploads' | 'removeFile' | 'uploadFile'
84
+ > & {
85
+ index: number;
86
+ item: FileUpload;
87
+ onLoad: (index: string, duration: number) => void;
88
+ onPlayPause: (index: string, status?: boolean) => void;
89
+ onProgress: (index: string, currentTime?: number, hasEnd?: boolean) => void;
90
+ testID: string;
91
+ };
92
+
93
+ const AudioAttachmentUploadPreviewWithContext = <
94
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
95
+ >(
96
+ props: AudioAttachmentUploadPreviewPropsWithContext<StreamChatGenerics>,
97
+ ) => {
98
+ const soundRef = React.useRef<SoundReturnType | null>(null);
99
+ const { fileUploads, index, item, onLoad, onPlayPause, onProgress } = props;
100
+
101
+ const handleLoad = (payload: VideoPayloadData) => {
102
+ onLoad(item.id, payload.duration);
103
+ };
104
+
105
+ const handleProgress = (data: VideoProgressData) => {
106
+ if (data.currentTime && data.seekableDuration) {
107
+ onProgress(item.id, data.currentTime);
108
+ }
109
+ };
110
+
111
+ const handlePlayPause = async (isPausedStatusAvailable?: boolean) => {
112
+ if (soundRef.current) {
113
+ if (isPausedStatusAvailable === undefined) {
114
+ if (item.progress === 1) {
115
+ // For native CLI
116
+ if (soundRef.current.seek) soundRef.current.seek(0);
117
+ // For expo CLI
118
+ if (soundRef.current.setPositionAsync) soundRef.current.setPositionAsync(0);
119
+ }
120
+ if (item.paused) {
121
+ if (soundRef.current.playAsync) await soundRef.current.playAsync();
122
+ onPlayPause(item.id, false);
123
+ } else {
124
+ if (soundRef.current.pauseAsync) await soundRef.current.pauseAsync();
125
+ onPlayPause(item.id, true);
126
+ }
127
+ } else {
128
+ onPlayPause(item.id, isPausedStatusAvailable);
129
+ }
130
+ }
131
+ };
132
+
133
+ const handleProgressDrag = async (position: number) => {
134
+ onProgress(item.id, position);
135
+ if (soundRef.current?.seek) soundRef.current.seek(position);
136
+ if (soundRef.current?.setPositionAsync) {
137
+ await soundRef.current.setPositionAsync(position * 1000);
138
+ }
139
+ };
140
+
141
+ const handleEnd = () => {
142
+ onPlayPause(item.id, true);
143
+ onProgress(item.id, item.duration, true);
144
+ };
145
+
146
+ const onPlaybackStatusUpdate = (playbackStatus: PlaybackStatus) => {
147
+ if (!playbackStatus.isLoaded) {
148
+ // Update your UI for the unloaded state
149
+ if (playbackStatus.error) {
150
+ console.log(`Encountered a fatal error during playback: ${playbackStatus.error}`);
151
+ }
152
+ } else {
153
+ const { durationMillis, positionMillis } = playbackStatus;
154
+ onLoad(item.id, durationMillis / 1000);
155
+ // Update your UI for the loaded state
156
+ if (playbackStatus.isPlaying) {
157
+ // Update your UI for the playing state
158
+ onProgress(item.id, positionMillis / 1000);
159
+ } else {
160
+ // Update your UI for the paused state
161
+ }
162
+
163
+ if (playbackStatus.isBuffering) {
164
+ // Update your UI for the buffering state
165
+ }
166
+
167
+ if (playbackStatus.didJustFinish && !playbackStatus.isLooping) {
168
+ // The player has just finished playing and will stop. Maybe you want to play something else?
169
+ // status: opposite of pause,says i am playing
170
+ handleEnd();
171
+ }
172
+ }
173
+ };
174
+
175
+ useEffect(() => {
176
+ if (Sound.Player === null) {
177
+ const initiateSound = async () => {
178
+ if (item && item.file && item.file.uri) {
179
+ soundRef.current = await Sound.initializeSound(
180
+ { uri: item.file.uri },
181
+ {},
182
+ onPlaybackStatusUpdate,
183
+ );
184
+ }
185
+ };
186
+ initiateSound();
187
+ }
188
+
189
+ return () => {
190
+ if (soundRef.current?.stopAsync && soundRef.current.unloadAsync) {
191
+ soundRef.current.stopAsync();
192
+ soundRef.current.unloadAsync();
193
+ }
194
+ };
195
+ }, []);
196
+
197
+ // This is needed for expo applications where the rerender doesn't occur on time thefore you need to update the state of the sound.
198
+ useEffect(() => {
199
+ const initalPlayPause = async () => {
200
+ if (soundRef.current) {
201
+ if (item.paused) {
202
+ if (soundRef.current.pauseAsync) await soundRef.current.pauseAsync();
203
+ } else {
204
+ if (soundRef.current.playAsync) await soundRef.current.playAsync();
205
+ }
206
+ }
207
+ };
208
+ if (!Sound.Player) {
209
+ initalPlayPause();
210
+ }
211
+ }, [item.paused]);
212
+
213
+ const {
214
+ theme: {
215
+ colors: { accent_blue, black, grey_dark, grey_whisper, static_black, static_white },
216
+ messageInput: {
217
+ fileUploadPreview: {
218
+ audioAttachmentUploadPreview: { progressControlView, progressDurationText, roundedView },
219
+ fileContainer,
220
+ fileContentContainer,
221
+ filenameText,
222
+ fileTextContainer,
223
+ },
224
+ },
225
+ },
226
+ } = useTheme();
227
+
228
+ const progressValueInSeconds = (item.duration as number) * (item.progress as number);
229
+
230
+ const progressDuration = progressValueInSeconds
231
+ ? progressValueInSeconds / 3600 >= 1
232
+ ? dayjs.duration(progressValueInSeconds, 'second').format('HH:mm:ss')
233
+ : dayjs.duration(progressValueInSeconds, 'second').format('mm:ss')
234
+ : '00:00';
235
+
236
+ const lastIndexOfDot = item.file.name.lastIndexOf('.');
237
+
238
+ return (
239
+ <View
240
+ style={[
241
+ styles.fileContainer,
242
+ index === fileUploads.length - 1
243
+ ? {
244
+ marginBottom: 0,
245
+ }
246
+ : {},
247
+ {
248
+ borderColor: grey_whisper,
249
+ width: -16,
250
+ },
251
+ fileContainer,
252
+ ]}
253
+ testID='audio-attachment-upload-preview'
254
+ >
255
+ <View style={[styles.fileContentContainer, fileContentContainer]}>
256
+ <TouchableOpacity
257
+ accessibilityLabel='Play Pause Button'
258
+ onPress={() => handlePlayPause()}
259
+ style={[
260
+ styles.roundedView,
261
+ roundedView,
262
+ { backgroundColor: static_white, shadowColor: black },
263
+ ]}
264
+ >
265
+ {item.paused ? (
266
+ <Play height={24} pathFill={static_black} width={24} />
267
+ ) : (
268
+ <Pause height={24} pathFill={static_black} width={24} />
269
+ )}
270
+ </TouchableOpacity>
271
+ <View style={[styles.fileTextContainer, fileTextContainer]}>
272
+ <Text
273
+ accessibilityLabel='File Name'
274
+ numberOfLines={1}
275
+ style={[
276
+ styles.filenameText,
277
+ {
278
+ color: black,
279
+ width:
280
+ 16 - // 16 = horizontal padding
281
+ 40 - // 40 = file icon size
282
+ 24 - // 24 = close icon size
283
+ 24, // 24 = internal padding
284
+ },
285
+ I18nManager.isRTL ? { writingDirection: 'rtl' } : { writingDirection: 'ltr' },
286
+ filenameText,
287
+ ]}
288
+ >
289
+ {item.file.name.slice(0, 12) + '...' + item.file.name.slice(lastIndexOfDot)}
290
+ </Text>
291
+ <View
292
+ style={{
293
+ alignItems: 'center',
294
+ display: 'flex',
295
+ flexDirection: 'row',
296
+ }}
297
+ >
298
+ {/* <ExpoSoundPlayer filePaused={!!item.paused} soundRef={soundRef} /> */}
299
+ {Sound.Player && (
300
+ <Sound.Player
301
+ onEnd={handleEnd}
302
+ onLoad={handleLoad}
303
+ onProgress={handleProgress}
304
+ paused={item.paused as boolean}
305
+ soundRef={soundRef}
306
+ testID='sound-player'
307
+ uri={item.file.uri}
308
+ />
309
+ )}
310
+ <Text style={[styles.progressDurationText, { color: grey_dark }, progressDurationText]}>
311
+ {progressDuration}
312
+ </Text>
313
+ <View style={[styles.progressControlView, progressControlView]}>
314
+ <ProgressControl
315
+ duration={item.duration as number}
316
+ filledColor={accent_blue}
317
+ onPlayPause={handlePlayPause}
318
+ onProgressDrag={handleProgressDrag}
319
+ progress={item.progress as number}
320
+ testID='progress-control'
321
+ width={110}
322
+ />
323
+ </View>
324
+ </View>
325
+ </View>
326
+ </View>
327
+ </View>
328
+ );
329
+ };
330
+
331
+ export type AudioAttachmentUploadPreviewProps<
332
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
333
+ > = Partial<AudioAttachmentUploadPreviewPropsWithContext<StreamChatGenerics>> & {
334
+ index: number;
335
+ item: FileUpload;
336
+ onLoad: (index: string, duration: number) => void;
337
+ onPlayPause: (index: string, status?: boolean) => void;
338
+ onProgress: (index: string, currentTime?: number, hasEnd?: boolean) => void;
339
+ testID: string;
340
+ };
341
+
342
+ /**
343
+ * AudioAttachmentUploadPreview
344
+ * UI Component to preview the audio files set for upload
345
+ */
346
+ export const AudioAttachmentUploadPreview = <
347
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
348
+ >(
349
+ props: AudioAttachmentUploadPreviewProps<StreamChatGenerics>,
350
+ ) => {
351
+ const { fileUploads, removeFile, uploadFile } = useMessageInputContext<StreamChatGenerics>();
352
+
353
+ return (
354
+ <AudioAttachmentUploadPreviewWithContext
355
+ {...{ fileUploads, removeFile, uploadFile }}
356
+ {...props}
357
+ />
358
+ );
359
+ };
360
+
361
+ AudioAttachmentUploadPreview.displayName =
362
+ 'AudioAttachmentUploadPreview{messageInput{autoAttachmentUploadPreview}}';