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
@@ -0,0 +1,215 @@
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
+ const View = require('react-native/Libraries/Components/View/View');
19
+
20
+ return {
21
+ isAudioPackageAvailable: jest.fn(() => true),
22
+ NetInfo: {
23
+ addEventListener: jest.fn(),
24
+ },
25
+ Sound: {
26
+ Player: View,
27
+ },
28
+ };
29
+ });
30
+
31
+ const getComponent = (props: Partial<AudioAttachmentUploadPreviewProps>) => (
32
+ <ThemeProvider theme={defaultTheme}>
33
+ <AudioAttachmentUploadPreview {...(props as unknown as AudioAttachmentUploadPreviewProps)} />,
34
+ </ThemeProvider>
35
+ );
36
+
37
+ describe('AudioAttachmentUploadPreview', () => {
38
+ it('handle play pause button when isPausedStatusAvailable unavailable and progress 1', () => {
39
+ const seekMock = jest.fn();
40
+ jest.spyOn(React, 'useRef').mockReturnValue({
41
+ current: {
42
+ seek: seekMock,
43
+ },
44
+ });
45
+
46
+ const onPlayPauseMock = jest.fn();
47
+ const { getByA11yLabel } = render(
48
+ getComponent({
49
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
50
+ item: { file: { name: 'audio.mp3' }, paused: true, progress: 1 } as unknown as FileUpload,
51
+ onPlayPause: onPlayPauseMock,
52
+ }),
53
+ );
54
+
55
+ const playPauseButton = getByA11yLabel('Play Pause Button');
56
+
57
+ act(() => {
58
+ fireEvent(playPauseButton, 'onPress');
59
+ });
60
+ expect(seekMock).toHaveBeenCalled();
61
+ });
62
+
63
+ it('handle play pause button when isPausedStatusAvailable unavailable and paused equals true', () => {
64
+ const playAsyncMock = jest.fn();
65
+ const onPlayPauseMock = jest.fn((id, status) => ({ id, status }));
66
+
67
+ jest.spyOn(React, 'useRef').mockReturnValue({
68
+ current: {
69
+ playAsync: playAsyncMock,
70
+ },
71
+ });
72
+
73
+ const { getByA11yLabel } = render(
74
+ getComponent({
75
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
76
+ item: { file: { name: 'audio.mp3' }, paused: true } as unknown as FileUpload,
77
+ onPlayPause: onPlayPauseMock,
78
+ }),
79
+ );
80
+
81
+ const playPauseButton = getByA11yLabel('Play Pause Button');
82
+
83
+ act(() => {
84
+ fireEvent(playPauseButton, 'onPress');
85
+ });
86
+
87
+ expect(playAsyncMock).toHaveBeenCalled();
88
+ });
89
+
90
+ it('handle play pause button when isPausedStatusAvailable unavailable and paused equals false', () => {
91
+ const pauseAsyncMock = jest.fn();
92
+ const onPlayPauseMock = jest.fn((id, status) => ({ id, status }));
93
+
94
+ jest.spyOn(React, 'useRef').mockReturnValue({
95
+ current: {
96
+ pauseAsync: pauseAsyncMock,
97
+ },
98
+ });
99
+
100
+ const { getByA11yLabel } = render(
101
+ getComponent({
102
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
103
+ item: { file: { name: 'audio.mp3' }, paused: false } as unknown as FileUpload,
104
+ onPlayPause: onPlayPauseMock,
105
+ }),
106
+ );
107
+
108
+ const playPauseButton = getByA11yLabel('Play Pause Button');
109
+
110
+ act(() => {
111
+ fireEvent(playPauseButton, 'onPress');
112
+ });
113
+
114
+ expect(pauseAsyncMock).toHaveBeenCalled();
115
+ });
116
+
117
+ it('handle onLoad event of sound player', () => {
118
+ const onLoadMock = jest.fn().mockImplementation((id, duration) => ({ duration, id }));
119
+
120
+ const { getByTestId } = render(
121
+ getComponent({
122
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
123
+ item: { file: { name: 'audio.mp3' }, paused: false } as unknown as FileUpload,
124
+ onLoad: onLoadMock,
125
+ }),
126
+ );
127
+
128
+ const soundPlayer = getByTestId('sound-player');
129
+
130
+ act(() => {
131
+ fireEvent(soundPlayer, 'onLoad', {
132
+ duration: 100,
133
+ });
134
+ });
135
+
136
+ expect(onLoadMock).toHaveBeenCalled();
137
+ });
138
+
139
+ it('handle onEnd event of sound player', () => {
140
+ const onProgressMock = jest.fn().mockImplementation((id, duration) => ({ duration, id }));
141
+ const onPlayPauseMock = jest.fn().mockImplementation((id, status) => ({ id, status }));
142
+
143
+ const { getByTestId } = render(
144
+ getComponent({
145
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
146
+ item: { file: { name: 'audio.mp3' }, paused: false } as unknown as FileUpload,
147
+ onPlayPause: onPlayPauseMock,
148
+ onProgress: onProgressMock,
149
+ }),
150
+ );
151
+
152
+ const soundPlayer = getByTestId('sound-player');
153
+
154
+ act(() => {
155
+ fireEvent(soundPlayer, 'onEnd');
156
+ });
157
+
158
+ expect(onPlayPauseMock).toHaveBeenCalled();
159
+ expect(onProgressMock).toHaveBeenCalled();
160
+ });
161
+
162
+ it('handle onProgress event of sound player', () => {
163
+ const onProgressMock = jest.fn().mockImplementation((id, duration) => ({ duration, id }));
164
+
165
+ const { getByTestId } = render(
166
+ getComponent({
167
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
168
+ item: { file: { name: 'audio.mp3' }, paused: false } as unknown as FileUpload,
169
+ onProgress: onProgressMock,
170
+ }),
171
+ );
172
+
173
+ const soundPlayer = getByTestId('sound-player');
174
+
175
+ act(() => {
176
+ fireEvent(soundPlayer, 'onProgress', {
177
+ currentTime: 10,
178
+ seekableDuration: 10,
179
+ });
180
+ });
181
+
182
+ expect(onProgressMock).toHaveBeenCalled();
183
+ });
184
+
185
+ it('handle onProgressDrag event of the progress control', () => {
186
+ const onProgressMock = jest.fn().mockImplementation((id, duration) => ({ duration, id }));
187
+ const seekMock = jest.fn();
188
+
189
+ jest.spyOn(React, 'useRef').mockReturnValue({
190
+ current: {
191
+ seek: seekMock,
192
+ },
193
+ });
194
+
195
+ const { getByTestId } = render(
196
+ getComponent({
197
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
198
+ item: { file: { name: 'audio.mp3' }, paused: false } as unknown as FileUpload,
199
+ onProgress: onProgressMock,
200
+ }),
201
+ );
202
+
203
+ const progressControl = getByTestId('progress-control');
204
+
205
+ act(() => {
206
+ fireEvent(progressControl, 'onProgressDrag', {
207
+ currentTime: 10,
208
+ seekableDuration: 10,
209
+ });
210
+ });
211
+
212
+ expect(onProgressMock).toHaveBeenCalled();
213
+ expect(seekMock).toHaveBeenCalled();
214
+ });
215
+ });
@@ -25,6 +25,21 @@ function MockedFlatList(props) {
25
25
  return <View testID={props.testID}>{items}</View>;
26
26
  }
27
27
 
28
+ jest.mock('../../../native.ts', () => {
29
+ // eslint-disable-next-line no-undef
30
+ const View = require('react-native/Libraries/Components/View/View');
31
+
32
+ return {
33
+ isAudioPackageAvailable: jest.fn(() => true),
34
+ NetInfo: {
35
+ addEventListener: jest.fn(),
36
+ },
37
+ Sound: {
38
+ Player: View,
39
+ },
40
+ };
41
+ });
42
+
28
43
  describe('FileUploadPreview', () => {
29
44
  it('should render FileUploadPreview with all uploading files', async () => {
30
45
  const fileUploads = [
@@ -298,4 +313,53 @@ describe('FileUploadPreview', () => {
298
313
  expect(uploadFile).toHaveBeenCalledTimes(0);
299
314
  });
300
315
  });
316
+
317
+ it('should render FileUploadPreview with all uploaded audios', async () => {
318
+ const fileUploads = [
319
+ generateFileUploadPreview({
320
+ id: 'file-upload-id-1',
321
+ state: FileState.UPLOADED,
322
+ type: 'audio/mp3',
323
+ }),
324
+ ];
325
+ const removeFile = jest.fn();
326
+ const uploadFile = jest.fn();
327
+
328
+ const user1 = generateUser();
329
+
330
+ const mockedChannel = generateChannelResponse({
331
+ members: [generateMember({ user: user1 })],
332
+ messages: [generateMessage({ user: user1 }), generateMessage({ user: user1 })],
333
+ });
334
+
335
+ const chatClient = await getTestClientWithUser({ id: 'testID' });
336
+ useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannel)]);
337
+ const channel = chatClient.channel('messaging', mockedChannel.id);
338
+ await channel.query();
339
+
340
+ const { getByTestId } = render(
341
+ <OverlayProvider>
342
+ <Chat client={chatClient}>
343
+ <Channel channel={channel} FlatList={MockedFlatList}>
344
+ <FileUploadPreview
345
+ fileUploads={fileUploads}
346
+ removeFile={removeFile}
347
+ uploadFile={uploadFile}
348
+ />
349
+ </Channel>
350
+ </Chat>
351
+ </OverlayProvider>,
352
+ );
353
+
354
+ const audioAttachmentUploadPreviewComponent = getByTestId('audio-attachment-upload-preview');
355
+
356
+ await waitFor(() => {
357
+ fireEvent(audioAttachmentUploadPreviewComponent, 'onLoad');
358
+ fireEvent(audioAttachmentUploadPreviewComponent, 'onProgress');
359
+ fireEvent(audioAttachmentUploadPreviewComponent, 'onPlayPause');
360
+ fireEvent(audioAttachmentUploadPreviewComponent, 'onPlayPause', {
361
+ status: false,
362
+ });
363
+ });
364
+ });
301
365
  });
@@ -9,43 +9,61 @@ import Animated, {
9
9
  useSharedValue,
10
10
  } from 'react-native-reanimated';
11
11
 
12
- import type { ImageGalleryFooterVideoControlProps } from './ImageGalleryFooter';
12
+ import { useTheme } from '../../contexts/themeContext/ThemeContext';
13
13
 
14
- import { useTheme } from '../../../contexts/themeContext/ThemeContext';
14
+ export type ProgressControlProps = {
15
+ duration: number;
16
+ filledColor: string;
17
+ onPlayPause: (status?: boolean) => void;
18
+ onProgressDrag: (progress: number) => void;
19
+ progress: number;
20
+ testID: string;
21
+ width: number;
22
+ };
15
23
 
16
- type ProgressControlProps = Pick<
17
- ImageGalleryFooterVideoControlProps,
18
- 'duration' | 'onPlayPause' | 'onProgressDrag' | 'progress'
19
- >;
20
-
21
- const width = 180;
22
24
  const height = 2;
23
25
  const styles = StyleSheet.create({
24
26
  containerStyle: {
25
27
  borderRadius: 50,
26
28
  height,
27
- width,
28
29
  },
29
30
  innerStyle: {
30
31
  height,
31
32
  },
32
33
  progressControlThumbStyle: {
33
- backgroundColor: '#fff',
34
34
  borderRadius: 5,
35
+ elevation: 6,
35
36
  height: 20,
37
+ shadowOffset: {
38
+ height: 3,
39
+ width: 0,
40
+ },
41
+ shadowOpacity: 0.27,
42
+ shadowRadius: 4.65,
36
43
  top: -11,
37
- width: 4,
44
+ width: 5,
38
45
  },
39
46
  });
40
47
 
41
- const ProgressControlThumb = () => <View style={styles.progressControlThumbStyle} />;
48
+ const ProgressControlThumb = () => {
49
+ const {
50
+ theme: {
51
+ colors: { black },
52
+ },
53
+ } = useTheme();
54
+ return (
55
+ <View
56
+ style={[styles.progressControlThumbStyle, { backgroundColor: '#ffffff', shadowColor: black }]}
57
+ />
58
+ );
59
+ };
42
60
 
43
61
  export const ProgressControl: React.FC<ProgressControlProps> = React.memo(
44
62
  (props) => {
45
- const { duration, onPlayPause, onProgressDrag, progress } = props;
63
+ const { duration, filledColor, onPlayPause, onProgressDrag, progress, testID, width } = props;
46
64
  const {
47
65
  theme: {
48
- colors: { grey_dark, white_snow },
66
+ colors: { grey_dark },
49
67
  },
50
68
  } = useTheme();
51
69
 
@@ -58,7 +76,7 @@ export const ProgressControl: React.FC<ProgressControlProps> = React.memo(
58
76
  }, [progress]);
59
77
 
60
78
  const animatedStyles = useAnimatedStyle(() => ({
61
- backgroundColor: white_snow,
79
+ backgroundColor: filledColor,
62
80
  width: state.value,
63
81
  }));
64
82
 
@@ -77,10 +95,10 @@ export const ProgressControl: React.FC<ProgressControlProps> = React.memo(
77
95
  translateX.value = state.value;
78
96
  const dragFinishLocationInSeconds = (state.value / width) * duration;
79
97
  runOnJS(onProgressDrag)(dragFinishLocationInSeconds);
80
- runOnJS(onPlayPause)();
98
+ runOnJS(onPlayPause)(false);
81
99
  },
82
100
  onStart: () => {
83
- runOnJS(onPlayPause)();
101
+ runOnJS(onPlayPause)(true);
84
102
  cancelAnimation(translateX);
85
103
  state.value = translateX.value;
86
104
  },
@@ -88,10 +106,10 @@ export const ProgressControl: React.FC<ProgressControlProps> = React.memo(
88
106
  [duration],
89
107
  );
90
108
  return (
91
- <View style={[styles.containerStyle, { backgroundColor: grey_dark }]}>
109
+ <View style={[styles.containerStyle, { backgroundColor: grey_dark, width }]}>
92
110
  <Animated.View style={[styles.innerStyle, animatedStyles]} />
93
111
 
94
- <PanGestureHandler maxPointers={1} onGestureEvent={onGestureEvent}>
112
+ <PanGestureHandler maxPointers={1} onGestureEvent={onGestureEvent} testID={testID}>
95
113
  <Animated.View style={[thumbStyles]}>
96
114
  <ProgressControlThumb />
97
115
  </Animated.View>
@@ -304,7 +304,7 @@ exports[`Thread should match thread snapshot 1`] = `
304
304
  }
305
305
  >
306
306
  <Image
307
- accessibilityLabel="avatar-image"
307
+ accessibilityLabel="Avatar Image"
308
308
  onError={[Function]}
309
309
  source={
310
310
  Object {
@@ -552,7 +552,7 @@ exports[`Thread should match thread snapshot 1`] = `
552
552
  }
553
553
  >
554
554
  <Image
555
- accessibilityLabel="avatar-image"
555
+ accessibilityLabel="Avatar Image"
556
556
  onError={[Function]}
557
557
  source={
558
558
  Object {
@@ -800,7 +800,7 @@ exports[`Thread should match thread snapshot 1`] = `
800
800
  }
801
801
  >
802
802
  <Image
803
- accessibilityLabel="avatar-image"
803
+ accessibilityLabel="Avatar Image"
804
804
  onError={[Function]}
805
805
  source={
806
806
  Object {
@@ -1091,7 +1091,7 @@ exports[`Thread should match thread snapshot 1`] = `
1091
1091
  }
1092
1092
  >
1093
1093
  <Image
1094
- accessibilityLabel="avatar-image"
1094
+ accessibilityLabel="Avatar Image"
1095
1095
  onError={[Function]}
1096
1096
  source={
1097
1097
  Object {
@@ -113,6 +113,7 @@ export * from './MessageInput/AttachButton';
113
113
  export * from './MessageInput/CommandsButton';
114
114
  export * from './MessageInput/CooldownTimer';
115
115
  export * from './MessageInput/FileUploadPreview';
116
+ export * from './MessageInput/AudioAttachmentUploadPreview';
116
117
  export * from './MessageInput/ImageUploadPreview';
117
118
  export * from './MessageInput/InputButtons';
118
119
  export * from './MessageInput/MessageInput';
@@ -149,6 +150,8 @@ export * from './MessageOverlay/OverlayReactions';
149
150
  export * from './MessageOverlay/OverlayReactionsAvatar';
150
151
  export * from './MessageOverlay/OverlayReactionList';
151
152
 
153
+ export * from './ProgressControl/ProgressControl';
154
+
152
155
  export * from './Reply/Reply';
153
156
 
154
157
  export * from './Spinner/Spinner';
@@ -22,6 +22,7 @@ import { useCreateMessageInputContext } from './hooks/useCreateMessageInputConte
22
22
  import { isEditingBoolean, useMessageDetailsForState } from './hooks/useMessageDetailsForState';
23
23
 
24
24
  import type { AttachButtonProps } from '../../components/MessageInput/AttachButton';
25
+ import type { AudioAttachmentUploadPreviewProps } from '../../components/MessageInput/AudioAttachmentUploadPreview';
25
26
  import type { CommandsButtonProps } from '../../components/MessageInput/CommandsButton';
26
27
  import type { InputEditingStateHeaderProps } from '../../components/MessageInput/components/InputEditingStateHeader';
27
28
  import type { InputGiphySearchProps } from '../../components/MessageInput/components/InputGiphySearch';
@@ -62,6 +63,9 @@ export type FileUpload = {
62
63
  file: File;
63
64
  id: string;
64
65
  state: FileStateValue;
66
+ duration?: number;
67
+ paused?: boolean;
68
+ progress?: number;
65
69
  thumb_url?: string;
66
70
  url?: string;
67
71
  };
@@ -220,6 +224,12 @@ export type InputMessageInputContextValue<
220
224
  * Defaults to and accepts same props as: [AttachButton](https://getstream.io/chat/docs/sdk/reactnative/ui-components/attach-button/)
221
225
  */
222
226
  AttachButton: React.ComponentType<AttachButtonProps<StreamChatGenerics>>;
227
+
228
+ /** Custom UI component for AudioAttachmentUploadPreview. */
229
+ AudioAttachmentUploadPreview: React.ComponentType<
230
+ AudioAttachmentUploadPreviewProps<StreamChatGenerics>
231
+ >;
232
+
223
233
  clearEditingState: () => void;
224
234
  clearQuotedMessageState: () => void;
225
235
  /**
@@ -1031,8 +1041,11 @@ export const MessageInputProvider = <
1031
1041
  : FileState.UPLOADING;
1032
1042
 
1033
1043
  const newFile: FileUpload = {
1044
+ duration: 0,
1034
1045
  file: { ...file, type: mimeType || file?.type },
1035
1046
  id,
1047
+ paused: true,
1048
+ progress: 0,
1036
1049
  state: fileState,
1037
1050
  };
1038
1051
 
@@ -12,6 +12,7 @@ export const useCreateMessageInputContext = <
12
12
  asyncIds,
13
13
  asyncUploads,
14
14
  AttachButton,
15
+ AudioAttachmentUploadPreview,
15
16
  autoCompleteSuggestionsLimit,
16
17
  clearEditingState,
17
18
  clearQuotedMessageState,
@@ -96,7 +97,9 @@ export const useCreateMessageInputContext = <
96
97
  }: MessageInputContextValue<StreamChatGenerics> &
97
98
  Pick<ThreadContextValue<StreamChatGenerics>, 'thread'>) => {
98
99
  const editingExists = !!editing;
99
- const fileUploadsValue = fileUploads.map(({ state }) => state).join();
100
+ const fileUploadsValue = fileUploads
101
+ .map(({ duration, paused, progress, state }) => `${state},${paused},${progress},${duration}`)
102
+ .join();
100
103
  const imageUploadsValue = imageUploads.map(({ state }) => state).join();
101
104
  const mentionedUsersLength = mentionedUsers.length;
102
105
  const quotedMessageId = quotedMessage
@@ -113,6 +116,7 @@ export const useCreateMessageInputContext = <
113
116
  asyncIds,
114
117
  asyncUploads,
115
118
  AttachButton,
119
+ AudioAttachmentUploadPreview,
116
120
  autoCompleteSuggestionsLimit,
117
121
  clearEditingState,
118
122
  clearQuotedMessageState,
@@ -21,9 +21,12 @@ export const Colors = {
21
21
  grey_whisper: '#ECEBEB',
22
22
  icon_background: '#FFFFFF',
23
23
  label_bg_transparent: '#00000033', // 33 = 20% opacity
24
+ light_gray: '#DBDDE1',
24
25
  modal_shadow: '#00000099', // 99 = 60% opacity; x=0, y= 1, radius=4
25
26
  overlay: '#000000CC', // CC = 80% opacity
26
27
  shadow_icon: '#00000040', // 40 = 25% opacity; x=0, y=0, radius=4
28
+ static_black: '#000000',
29
+ static_white: '#ffffff',
27
30
  targetedMessageBackground: '#FBF4DD', // dark mode = #302D22
28
31
  transparent: 'transparent',
29
32
  white: '#FFFFFF',
@@ -244,6 +247,12 @@ export type Theme = {
244
247
  editingBoxHeaderTitle: TextStyle;
245
248
  };
246
249
  fileUploadPreview: {
250
+ audioAttachmentFileContainer: ViewStyle;
251
+ audioAttachmentUploadPreview: {
252
+ progressControlView: ViewStyle;
253
+ progressDurationText: TextStyle;
254
+ roundedView: ViewStyle;
255
+ };
247
256
  dismiss: ViewStyle;
248
257
  fileContainer: ViewStyle;
249
258
  fileContentContainer: ViewStyle;
@@ -737,6 +746,12 @@ export const defaultTheme: Theme = {
737
746
  editingBoxHeaderTitle: {},
738
747
  },
739
748
  fileUploadPreview: {
749
+ audioAttachmentFileContainer: {},
750
+ audioAttachmentUploadPreview: {
751
+ progressControlView: {},
752
+ progressDurationText: {},
753
+ roundedView: {},
754
+ },
740
755
  dismiss: {},
741
756
  fileContainer: {},
742
757
  fileContentContainer: {},
@@ -7,8 +7,8 @@ export const Pause: React.FC<IconProps> = (props) => {
7
7
  const { height, width } = props;
8
8
  return (
9
9
  <RootSvg height={height} viewBox={`0 0 ${height} ${width}`} width={width} {...props}>
10
- <Rect fill={'black'} height={14} width={4} x={6} y={5} />
11
- <Rect fill={'black'} height={14} width={4} x={14} y={5} />
10
+ <Rect fill={props.pathFill} height={14} width={4} x={6} y={5} />
11
+ <Rect fill={props.pathFill} height={14} width={4} x={14} y={5} />
12
12
  </RootSvg>
13
13
  );
14
14
  };
@@ -176,6 +176,7 @@ const FORMATTED_MESSAGE: FormatMessageResponse<DefaultStreamChatGenerics> = {
176
176
  message: {} as unknown as MessageResponse<DefaultStreamChatGenerics>,
177
177
  pinned_at: new Date('2021-02-12T12:12:35.862282Z'),
178
178
  status: 'received',
179
+ type: 'regular',
179
180
  updated_at: new Date('2021-02-12T12:12:35.862282Z'),
180
181
  };
181
182