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
@@ -0,0 +1,212 @@
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
+ const View = require('react-native/Libraries/Components/View/View');
16
+
17
+ return {
18
+ isAudioPackageAvailable: jest.fn(() => true),
19
+ NetInfo: {
20
+ addEventListener: jest.fn(),
21
+ },
22
+ Sound: {
23
+ Player: View,
24
+ },
25
+ };
26
+ });
27
+
28
+ const getComponent = (props: Partial<AudioAttachmentProps>) => (
29
+ <ThemeProvider theme={defaultTheme}>
30
+ <AudioAttachment {...(props as unknown as AudioAttachmentProps)} />,
31
+ </ThemeProvider>
32
+ );
33
+
34
+ describe('AudioAttachment', () => {
35
+ it('handle play pause button when isPausedStatusAvailable unavailable and progress 1', () => {
36
+ const seekMock = jest.fn();
37
+ jest.spyOn(React, 'useRef').mockReturnValue({
38
+ current: {
39
+ seek: seekMock,
40
+ },
41
+ });
42
+
43
+ const onPlayPauseMock = jest.fn();
44
+ const { getByA11yLabel } = render(
45
+ getComponent({
46
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
47
+ item: { file: { name: 'audio.mp3' }, paused: true, progress: 1 } as unknown as FileUpload,
48
+ onPlayPause: onPlayPauseMock,
49
+ }),
50
+ );
51
+
52
+ const playPauseButton = getByA11yLabel('Play Pause Button');
53
+
54
+ act(() => {
55
+ fireEvent(playPauseButton, 'onPress');
56
+ });
57
+ expect(seekMock).toHaveBeenCalled();
58
+ });
59
+
60
+ it('handle play pause button when isPausedStatusAvailable unavailable and paused equals true', () => {
61
+ const playAsyncMock = jest.fn();
62
+ const onPlayPauseMock = jest.fn((id, status) => ({ id, status }));
63
+
64
+ jest.spyOn(React, 'useRef').mockReturnValue({
65
+ current: {
66
+ playAsync: playAsyncMock,
67
+ },
68
+ });
69
+
70
+ const { getByA11yLabel } = render(
71
+ getComponent({
72
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
73
+ item: { file: { name: 'audio.mp3' }, paused: true } as unknown as FileUpload,
74
+ onPlayPause: onPlayPauseMock,
75
+ }),
76
+ );
77
+
78
+ const playPauseButton = getByA11yLabel('Play Pause Button');
79
+
80
+ act(() => {
81
+ fireEvent(playPauseButton, 'onPress');
82
+ });
83
+
84
+ expect(playAsyncMock).toHaveBeenCalled();
85
+ });
86
+
87
+ it('handle play pause button when isPausedStatusAvailable unavailable and paused equals false', () => {
88
+ const pauseAsyncMock = jest.fn();
89
+ const onPlayPauseMock = jest.fn((id, status) => ({ id, status }));
90
+
91
+ jest.spyOn(React, 'useRef').mockReturnValue({
92
+ current: {
93
+ pauseAsync: pauseAsyncMock,
94
+ },
95
+ });
96
+
97
+ const { getByA11yLabel } = render(
98
+ getComponent({
99
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
100
+ item: { file: { name: 'audio.mp3' }, paused: false } as unknown as FileUpload,
101
+ onPlayPause: onPlayPauseMock,
102
+ }),
103
+ );
104
+
105
+ const playPauseButton = getByA11yLabel('Play Pause Button');
106
+
107
+ act(() => {
108
+ fireEvent(playPauseButton, 'onPress');
109
+ });
110
+
111
+ expect(pauseAsyncMock).toHaveBeenCalled();
112
+ });
113
+
114
+ it('handle onLoad event of sound player', () => {
115
+ const onLoadMock = jest.fn().mockImplementation((id, duration) => ({ duration, id }));
116
+
117
+ const { getByTestId } = render(
118
+ getComponent({
119
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
120
+ item: { file: { name: 'audio.mp3' }, paused: false } as unknown as FileUpload,
121
+ onLoad: onLoadMock,
122
+ }),
123
+ );
124
+
125
+ const soundPlayer = getByTestId('sound-player');
126
+
127
+ act(() => {
128
+ fireEvent(soundPlayer, 'onLoad', {
129
+ duration: 100,
130
+ });
131
+ });
132
+
133
+ expect(onLoadMock).toHaveBeenCalled();
134
+ });
135
+
136
+ it('handle onEnd event of sound player', () => {
137
+ const onProgressMock = jest.fn().mockImplementation((id, duration) => ({ duration, id }));
138
+ const onPlayPauseMock = jest.fn().mockImplementation((id, status) => ({ id, status }));
139
+
140
+ const { getByTestId } = render(
141
+ getComponent({
142
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
143
+ item: { file: { name: 'audio.mp3' }, paused: false } as unknown as FileUpload,
144
+ onPlayPause: onPlayPauseMock,
145
+ onProgress: onProgressMock,
146
+ }),
147
+ );
148
+
149
+ const soundPlayer = getByTestId('sound-player');
150
+
151
+ act(() => {
152
+ fireEvent(soundPlayer, 'onEnd');
153
+ });
154
+
155
+ expect(onPlayPauseMock).toHaveBeenCalled();
156
+ expect(onProgressMock).toHaveBeenCalled();
157
+ });
158
+
159
+ it('handle onProgress event of sound player', () => {
160
+ const onProgressMock = jest.fn().mockImplementation((id, duration) => ({ duration, id }));
161
+
162
+ const { getByTestId } = render(
163
+ getComponent({
164
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
165
+ item: { file: { name: 'audio.mp3' }, paused: false } as unknown as FileUpload,
166
+ onProgress: onProgressMock,
167
+ }),
168
+ );
169
+
170
+ const soundPlayer = getByTestId('sound-player');
171
+
172
+ act(() => {
173
+ fireEvent(soundPlayer, 'onProgress', {
174
+ currentTime: 10,
175
+ seekableDuration: 10,
176
+ });
177
+ });
178
+
179
+ expect(onProgressMock).toHaveBeenCalled();
180
+ });
181
+
182
+ it('handle onProgressDrag event of the progress control', () => {
183
+ const onProgressMock = jest.fn().mockImplementation((id, duration) => ({ duration, id }));
184
+ const seekMock = jest.fn();
185
+
186
+ jest.spyOn(React, 'useRef').mockReturnValue({
187
+ current: {
188
+ seek: seekMock,
189
+ },
190
+ });
191
+
192
+ const { getByTestId } = render(
193
+ getComponent({
194
+ fileUploads: [generateFileUploadPreview({ type: 'audio/mp3' })],
195
+ item: { file: { name: 'audio.mp3' }, paused: false } as unknown as FileUpload,
196
+ onProgress: onProgressMock,
197
+ }),
198
+ );
199
+
200
+ const progressControl = getByTestId('progress-control');
201
+
202
+ act(() => {
203
+ fireEvent(progressControl, 'onProgressDrag', {
204
+ currentTime: 10,
205
+ seekableDuration: 10,
206
+ });
207
+ });
208
+
209
+ expect(onProgressMock).toHaveBeenCalled();
210
+ expect(seekMock).toHaveBeenCalled();
211
+ });
212
+ });
@@ -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 AudioAttachmentComponent = getByTestId('audio-attachment-upload-preview');
355
+
356
+ await waitFor(() => {
357
+ fireEvent(AudioAttachmentComponent, 'onLoad');
358
+ fireEvent(AudioAttachmentComponent, 'onProgress');
359
+ fireEvent(AudioAttachmentComponent, 'onPlayPause');
360
+ fireEvent(AudioAttachmentComponent, '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 {
@@ -1,5 +1,6 @@
1
1
  export * from './Attachment/Attachment';
2
2
  export * from './Attachment/AttachmentActions';
3
+ export * from './Attachment/AudioAttachment';
3
4
  export * from './Attachment/Card';
4
5
  export * from './Attachment/FileAttachment';
5
6
  export * from './Attachment/FileAttachmentGroup';
@@ -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';
@@ -21,6 +21,7 @@ import {
21
21
  import { useCreateMessageInputContext } from './hooks/useCreateMessageInputContext';
22
22
  import { isEditingBoolean, useMessageDetailsForState } from './hooks/useMessageDetailsForState';
23
23
 
24
+ import type { AudioAttachmentProps } from '../../components/Attachment/AudioAttachment';
24
25
  import type { AttachButtonProps } from '../../components/MessageInput/AttachButton';
25
26
  import type { CommandsButtonProps } from '../../components/MessageInput/CommandsButton';
26
27
  import type { InputEditingStateHeaderProps } from '../../components/MessageInput/components/InputEditingStateHeader';
@@ -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,10 @@ 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 AudioAttachment. */
229
+ AudioAttachment: React.ComponentType<AudioAttachmentProps<StreamChatGenerics>>;
230
+
223
231
  clearEditingState: () => void;
224
232
  clearQuotedMessageState: () => void;
225
233
  /**
@@ -1031,8 +1039,11 @@ export const MessageInputProvider = <
1031
1039
  : FileState.UPLOADING;
1032
1040
 
1033
1041
  const newFile: FileUpload = {
1042
+ duration: 0,
1034
1043
  file: { ...file, type: mimeType || file?.type },
1035
1044
  id,
1045
+ paused: true,
1046
+ progress: 0,
1036
1047
  state: fileState,
1037
1048
  };
1038
1049
 
@@ -12,6 +12,7 @@ export const useCreateMessageInputContext = <
12
12
  asyncIds,
13
13
  asyncUploads,
14
14
  AttachButton,
15
+ AudioAttachment,
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
+ AudioAttachment,
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
+ audioAttachment: {
251
+ progressControlView: ViewStyle;
252
+ progressDurationText: TextStyle;
253
+ roundedView: ViewStyle;
254
+ };
255
+ audioAttachmentFileContainer: ViewStyle;
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
+ audioAttachment: {
750
+ progressControlView: {},
751
+ progressDurationText: {},
752
+ roundedView: {},
753
+ },
754
+ audioAttachmentFileContainer: {},
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