stream-chat-react-native-core 4.5.1-beta.1 → 4.6.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 (83) hide show
  1. package/lib/commonjs/components/Attachment/FileIcon.js +9 -1
  2. package/lib/commonjs/components/Attachment/FileIcon.js.map +1 -1
  3. package/lib/commonjs/components/AttachmentPicker/AttachmentPicker.js +208 -31
  4. package/lib/commonjs/components/AttachmentPicker/AttachmentPicker.js.map +1 -1
  5. package/lib/commonjs/components/Message/MessageSimple/MessageContent.js +39 -21
  6. package/lib/commonjs/components/Message/MessageSimple/MessageContent.js.map +1 -1
  7. package/lib/commonjs/components/MessageInput/FileUploadPreview.js +1 -1
  8. package/lib/commonjs/components/MessageInput/FileUploadPreview.js.map +1 -1
  9. package/lib/commonjs/components/MessageInput/MessageInput.js +129 -44
  10. package/lib/commonjs/components/MessageInput/MessageInput.js.map +1 -1
  11. package/lib/commonjs/components/Reply/Reply.js +25 -9
  12. package/lib/commonjs/components/Reply/Reply.js.map +1 -1
  13. package/lib/commonjs/contexts/attachmentPickerContext/AttachmentPickerContext.js +15 -8
  14. package/lib/commonjs/contexts/attachmentPickerContext/AttachmentPickerContext.js.map +1 -1
  15. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +10 -7
  16. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  17. package/lib/commonjs/contexts/messageInputContext/hooks/useMessageDetailsForState.js +16 -1
  18. package/lib/commonjs/contexts/messageInputContext/hooks/useMessageDetailsForState.js.map +1 -1
  19. package/lib/commonjs/contexts/themeContext/utils/theme.js +1 -0
  20. package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
  21. package/lib/commonjs/icons/Recorder.js +47 -0
  22. package/lib/commonjs/icons/Recorder.js.map +1 -0
  23. package/lib/commonjs/icons/Video.js +82 -0
  24. package/lib/commonjs/icons/Video.js.map +1 -0
  25. package/lib/commonjs/icons/index.js +26 -0
  26. package/lib/commonjs/icons/index.js.map +1 -1
  27. package/lib/commonjs/native.js.map +1 -1
  28. package/lib/commonjs/version.json +1 -1
  29. package/lib/module/components/Attachment/FileIcon.js +9 -1
  30. package/lib/module/components/Attachment/FileIcon.js.map +1 -1
  31. package/lib/module/components/AttachmentPicker/AttachmentPicker.js +208 -31
  32. package/lib/module/components/AttachmentPicker/AttachmentPicker.js.map +1 -1
  33. package/lib/module/components/Message/MessageSimple/MessageContent.js +39 -21
  34. package/lib/module/components/Message/MessageSimple/MessageContent.js.map +1 -1
  35. package/lib/module/components/MessageInput/FileUploadPreview.js +1 -1
  36. package/lib/module/components/MessageInput/FileUploadPreview.js.map +1 -1
  37. package/lib/module/components/MessageInput/MessageInput.js +129 -44
  38. package/lib/module/components/MessageInput/MessageInput.js.map +1 -1
  39. package/lib/module/components/Reply/Reply.js +25 -9
  40. package/lib/module/components/Reply/Reply.js.map +1 -1
  41. package/lib/module/contexts/attachmentPickerContext/AttachmentPickerContext.js +15 -8
  42. package/lib/module/contexts/attachmentPickerContext/AttachmentPickerContext.js.map +1 -1
  43. package/lib/module/contexts/messageInputContext/MessageInputContext.js +10 -7
  44. package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  45. package/lib/module/contexts/messageInputContext/hooks/useMessageDetailsForState.js +16 -1
  46. package/lib/module/contexts/messageInputContext/hooks/useMessageDetailsForState.js.map +1 -1
  47. package/lib/module/contexts/themeContext/utils/theme.js +1 -0
  48. package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
  49. package/lib/module/icons/Recorder.js +47 -0
  50. package/lib/module/icons/Recorder.js.map +1 -0
  51. package/lib/module/icons/Video.js +82 -0
  52. package/lib/module/icons/Video.js.map +1 -0
  53. package/lib/module/icons/index.js +26 -0
  54. package/lib/module/icons/index.js.map +1 -1
  55. package/lib/module/native.js.map +1 -1
  56. package/lib/module/version.json +1 -1
  57. package/lib/typescript/components/MessageInput/MessageInput.d.ts +1 -1
  58. package/lib/typescript/contexts/attachmentPickerContext/AttachmentPickerContext.d.ts +3 -2
  59. package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts +4 -15
  60. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +1 -0
  61. package/lib/typescript/icons/Recorder.d.ts +3 -0
  62. package/lib/typescript/icons/Video.d.ts +3 -0
  63. package/lib/typescript/icons/index.d.ts +2 -0
  64. package/lib/typescript/native.d.ts +3 -14
  65. package/lib/typescript/types/types.d.ts +24 -0
  66. package/package.json +1 -1
  67. package/src/components/Attachment/FileIcon.tsx +45 -0
  68. package/src/components/AttachmentPicker/AttachmentPicker.tsx +172 -22
  69. package/src/components/Message/MessageSimple/MessageContent.tsx +23 -12
  70. package/src/components/MessageInput/FileUploadPreview.tsx +1 -1
  71. package/src/components/MessageInput/MessageInput.tsx +106 -19
  72. package/src/components/Reply/Reply.tsx +31 -14
  73. package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +12 -0
  74. package/src/contexts/attachmentPickerContext/AttachmentPickerContext.tsx +6 -2
  75. package/src/contexts/messageInputContext/MessageInputContext.tsx +17 -24
  76. package/src/contexts/messageInputContext/hooks/useMessageDetailsForState.ts +17 -1
  77. package/src/contexts/themeContext/utils/theme.ts +2 -0
  78. package/src/icons/Recorder.tsx +16 -0
  79. package/src/icons/Video.tsx +37 -0
  80. package/src/icons/index.ts +2 -0
  81. package/src/native.ts +4 -14
  82. package/src/types/types.ts +27 -0
  83. package/src/version.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { FlatList as DefaultFlatList } from 'react-native';
2
2
  import type { NetInfoSubscription } from '@react-native-community/netinfo';
3
+ import type { Asset, File } from './types/types';
3
4
  declare type CompressImage = ({ compressImageQuality, height, uri, width, }: {
4
5
  compressImageQuality: number;
5
6
  height: number;
@@ -11,15 +12,8 @@ declare type DeleteFile = ({ uri }: {
11
12
  uri: string;
12
13
  }) => Promise<boolean> | never;
13
14
  export declare let deleteFile: DeleteFile;
14
- declare type GetLocalAssetUri = (uriOrAssetId: string) => Promise<string> | never;
15
+ declare type GetLocalAssetUri = (uriOrAssetId: string) => never;
15
16
  export declare let getLocalAssetUri: GetLocalAssetUri;
16
- export declare type Asset = {
17
- height: number;
18
- source: 'camera' | 'picker';
19
- uri: string;
20
- width: number;
21
- id?: string;
22
- };
23
17
  declare type GetPhotos = ({ after, first }: {
24
18
  first: number;
25
19
  after?: string;
@@ -41,12 +35,7 @@ declare type PickDocument = ({ maxNumberOfFiles }: {
41
35
  maxNumberOfFiles?: number;
42
36
  }) => Promise<{
43
37
  cancelled: boolean;
44
- docs?: {
45
- name: string;
46
- size?: number | string;
47
- type?: string;
48
- uri?: string;
49
- }[];
38
+ docs?: File[];
50
39
  }> | never;
51
40
  export declare let pickDocument: PickDocument;
52
41
  declare type SaveFileOptions = {
@@ -1,4 +1,28 @@
1
1
  import type { ExtendableGenerics, LiteralStringForUnion } from 'stream-chat';
2
+ export declare type Asset = {
3
+ duration: number | null;
4
+ filename: string;
5
+ fileSize: string;
6
+ height: number;
7
+ playableDuration: number | null;
8
+ source: 'camera' | 'picker';
9
+ type: string;
10
+ uri: string;
11
+ width: number;
12
+ id?: string;
13
+ size?: number | string;
14
+ };
15
+ export declare type File = {
16
+ name: string;
17
+ duration?: string | null;
18
+ size?: number | string;
19
+ type?: string;
20
+ uri?: string;
21
+ };
22
+ export declare type DefaultAttachmentType = UnknownType & {
23
+ file_size?: number | string;
24
+ mime_type?: string;
25
+ };
2
26
  interface DefaultUserType extends UnknownType {
3
27
  image?: string;
4
28
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "stream-chat-react-native-core",
3
3
  "description": "The official React Native and Expo components for Stream Chat, a service for building chat applications",
4
- "version": "4.5.1-beta.1",
4
+ "version": "4.6.0-beta.1",
5
5
  "author": {
6
6
  "company": "Stream.io Inc",
7
7
  "name": "Stream.io Inc"
@@ -19,6 +19,7 @@ import { SEVEN_Z } from '../../icons/SEVEN_Z';
19
19
  import { TAR } from '../../icons/TAR';
20
20
  import { TXT } from '../../icons/TXT';
21
21
  import type { IconProps } from '../../icons/utils/base';
22
+ import { Video } from '../../icons/Video';
22
23
  import { XLS } from '../../icons/XLS';
23
24
  import { XLSX } from '../../icons/XLSX';
24
25
  import { ZIP } from '../../icons/ZIP';
@@ -320,6 +321,46 @@ const zipFileTypes = [
320
321
  'application/zip',
321
322
  ];
322
323
 
324
+ const videoFileTypes = [
325
+ 'video/3g2',
326
+ 'video/3gp',
327
+ 'video/aaf',
328
+ 'video/asf',
329
+ 'video/avchd',
330
+ 'video/avi',
331
+ 'video/drc',
332
+ 'video/flv',
333
+ 'video/m2v',
334
+ 'video/m3u8',
335
+ 'video/m4p',
336
+ 'video/m4v',
337
+ 'video/mkv',
338
+ 'video/mng',
339
+ 'video/mov',
340
+ 'video/mp2',
341
+ 'video/mp4',
342
+ 'video/mpe',
343
+ 'video/mpeg',
344
+ 'video/mpg',
345
+ 'video/mpv',
346
+ 'video/mxf',
347
+ 'video/nsv',
348
+ 'video/ogg',
349
+ 'video/ogv',
350
+ 'video/qt',
351
+ 'video/rm',
352
+ 'video/rmvb',
353
+ 'video/roq',
354
+ 'video/svi',
355
+ 'video/vob',
356
+ 'video/webm',
357
+ 'video/wmv',
358
+ 'video/yuv',
359
+ 'video/quicktime',
360
+ 'video/webm',
361
+ 'video/x-flv',
362
+ ];
363
+
323
364
  const mimeTypeToIconMap: Record<string, React.FC<IconProps>> = {
324
365
  'application/pdf': PDF, // .pdf
325
366
  'application/rtf': RTF, // .rtf
@@ -371,6 +412,10 @@ for (const type of zipFileTypes) {
371
412
  mimeTypeToIconMap[type] = ZIP;
372
413
  }
373
414
 
415
+ for (const type of videoFileTypes) {
416
+ mimeTypeToIconMap[type] = Video;
417
+ }
418
+
374
419
  function mimeTypeToIcon(mimeType?: string): React.FC<IconProps> {
375
420
  if (!mimeType) return GenericFile;
376
421
 
@@ -7,6 +7,7 @@ import {
7
7
  Platform,
8
8
  StatusBar,
9
9
  StyleSheet,
10
+ Text,
10
11
  View,
11
12
  } from 'react-native';
12
13
 
@@ -15,42 +16,161 @@ import BottomSheet, {
15
16
  BottomSheetHandleProps,
16
17
  TouchableOpacity,
17
18
  } from '@gorhom/bottom-sheet';
19
+ import dayjs from 'dayjs';
20
+ import duration from 'dayjs/plugin/duration';
21
+ import { lookup } from 'mime-types';
18
22
 
19
23
  import type { AttachmentPickerErrorProps } from './components/AttachmentPickerError';
20
24
 
21
25
  import { useAttachmentPickerContext } from '../../contexts/attachmentPickerContext/AttachmentPickerContext';
22
26
  import { useTheme } from '../../contexts/themeContext/ThemeContext';
23
- import { Asset, getPhotos } from '../../native';
27
+ import { Recorder } from '../../icons';
28
+ import { getPhotos } from '../../native';
29
+ import type { Asset, File } from '../../types/types';
24
30
  import { vh, vw } from '../../utils/utils';
25
31
 
32
+ dayjs.extend(duration);
33
+
26
34
  const styles = StyleSheet.create({
27
35
  container: {
28
36
  flexGrow: 1,
29
37
  },
38
+ durationText: {
39
+ fontWeight: 'bold',
40
+ },
30
41
  overlay: {
31
42
  alignItems: 'flex-end',
32
43
  flex: 1,
33
44
  },
45
+ videoView: {
46
+ bottom: 5,
47
+ display: 'flex',
48
+ flexDirection: 'row',
49
+ justifyContent: 'space-between',
50
+ paddingHorizontal: 5,
51
+ position: 'absolute',
52
+ width: '100%',
53
+ },
34
54
  });
35
55
 
36
56
  const screenHeight = vh(100);
37
57
  const fullScreenHeight = Dimensions.get('window').height;
38
58
 
39
59
  type AttachmentImageProps = {
60
+ asset: Asset;
61
+ ImageOverlaySelectedComponent: React.ComponentType;
62
+ maxNumberOfFiles: number;
63
+ selected: boolean;
64
+ setSelectedImages: React.Dispatch<React.SetStateAction<Asset[]>>;
65
+ numberOfAttachmentPickerImageColumns?: number;
66
+ };
67
+
68
+ type AttachmentVideoProps = {
69
+ asset: Asset;
40
70
  ImageOverlaySelectedComponent: React.ComponentType;
41
- onPress: () => void;
71
+ maxNumberOfFiles: number;
42
72
  selected: boolean;
43
- uri: string;
73
+ setSelectedFiles: React.Dispatch<React.SetStateAction<File[]>>;
44
74
  numberOfAttachmentPickerImageColumns?: number;
45
75
  };
46
76
 
77
+ const AttachmentVideo: React.FC<AttachmentVideoProps> = (props) => {
78
+ const {
79
+ asset,
80
+ ImageOverlaySelectedComponent,
81
+ maxNumberOfFiles,
82
+ numberOfAttachmentPickerImageColumns,
83
+ selected,
84
+ setSelectedFiles,
85
+ } = props;
86
+
87
+ const {
88
+ theme: {
89
+ attachmentPicker: { durationText, image, imageOverlay },
90
+ colors: { overlay, white },
91
+ },
92
+ } = useTheme();
93
+
94
+ const { duration, playableDuration, uri } = asset;
95
+
96
+ const videoDuration = duration ? duration : playableDuration;
97
+
98
+ const ONE_HOUR_IN_SECONDS = 3600;
99
+
100
+ let durationLabel = '00:00';
101
+
102
+ if (videoDuration) {
103
+ const isDurationLongerThanHour = videoDuration / ONE_HOUR_IN_SECONDS >= 1;
104
+ const formattedDurationParam = isDurationLongerThanHour ? 'HH:mm:ss' : 'mm:ss';
105
+ const formattedVideoDuration = dayjs
106
+ .duration(videoDuration, 'second')
107
+ .format(formattedDurationParam);
108
+ durationLabel = formattedVideoDuration;
109
+ }
110
+
111
+ const size = vw(100) / (numberOfAttachmentPickerImageColumns || 3) - 2;
112
+
113
+ const onPressVideo = () => {
114
+ if (selected) {
115
+ setSelectedFiles((files) => files.filter((file) => file.uri !== asset.uri));
116
+ } else {
117
+ setSelectedFiles((files) => {
118
+ if (files.length >= maxNumberOfFiles) {
119
+ return files;
120
+ }
121
+ return [
122
+ ...files,
123
+ {
124
+ duration: durationLabel,
125
+ name: asset.filename,
126
+ size: asset.fileSize,
127
+ type: 'video',
128
+ uri: asset.uri,
129
+ },
130
+ ];
131
+ });
132
+ }
133
+ };
134
+
135
+ return (
136
+ <TouchableOpacity onPress={onPressVideo}>
137
+ <ImageBackground
138
+ source={{ uri }}
139
+ style={[
140
+ {
141
+ height: size,
142
+ margin: 1,
143
+ width: size,
144
+ },
145
+ image,
146
+ ]}
147
+ >
148
+ {selected && (
149
+ <View style={[styles.overlay, { backgroundColor: overlay }, imageOverlay]}>
150
+ <ImageOverlaySelectedComponent />
151
+ </View>
152
+ )}
153
+ <View style={styles.videoView}>
154
+ <Recorder height={20} pathFill={white} width={25} />
155
+ {videoDuration ? (
156
+ <Text style={[styles.durationText, durationText, { color: white }]}>
157
+ {durationLabel}
158
+ </Text>
159
+ ) : null}
160
+ </View>
161
+ </ImageBackground>
162
+ </TouchableOpacity>
163
+ );
164
+ };
165
+
47
166
  const AttachmentImage: React.FC<AttachmentImageProps> = (props) => {
48
167
  const {
168
+ asset,
49
169
  ImageOverlaySelectedComponent,
170
+ maxNumberOfFiles,
50
171
  numberOfAttachmentPickerImageColumns,
51
- onPress,
52
172
  selected,
53
- uri,
173
+ setSelectedImages,
54
174
  } = props;
55
175
  const {
56
176
  theme: {
@@ -61,8 +181,23 @@ const AttachmentImage: React.FC<AttachmentImageProps> = (props) => {
61
181
 
62
182
  const size = vw(100) / (numberOfAttachmentPickerImageColumns || 3) - 2;
63
183
 
184
+ const { uri } = asset;
185
+
186
+ const onPressImage = () => {
187
+ if (selected) {
188
+ setSelectedImages((images) => images.filter((image) => image.uri !== asset.uri));
189
+ } else {
190
+ setSelectedImages((images) => {
191
+ if (images.length >= maxNumberOfFiles) {
192
+ return images;
193
+ }
194
+ return [...images, asset];
195
+ });
196
+ }
197
+ };
198
+
64
199
  return (
65
- <TouchableOpacity onPress={onPress}>
200
+ <TouchableOpacity onPress={onPressImage}>
66
201
  <ImageBackground
67
202
  source={{ uri }}
68
203
  style={[
@@ -92,6 +227,7 @@ const renderImage = ({
92
227
  ImageOverlaySelectedComponent: React.ComponentType;
93
228
  maxNumberOfFiles: number;
94
229
  selected: boolean;
230
+ setSelectedFiles: React.Dispatch<React.SetStateAction<File[]>>;
95
231
  setSelectedImages: React.Dispatch<React.SetStateAction<Asset[]>>;
96
232
  numberOfAttachmentPickerImageColumns?: number;
97
233
  };
@@ -102,28 +238,37 @@ const renderImage = ({
102
238
  maxNumberOfFiles,
103
239
  numberOfAttachmentPickerImageColumns,
104
240
  selected,
241
+ setSelectedFiles,
105
242
  setSelectedImages,
106
243
  } = item;
107
- const onPress = () => {
108
- if (selected) {
109
- setSelectedImages((images) => images.filter((image) => image.uri !== asset.uri));
110
- } else {
111
- setSelectedImages((images) => {
112
- if (images.length >= maxNumberOfFiles) {
113
- return images;
114
- }
115
- return [...images, asset];
116
- });
117
- }
118
- };
119
244
 
120
- return (
245
+ const contentType = lookup(asset.filename) || 'multipart/form-data';
246
+
247
+ const fileType = asset.filename
248
+ ? contentType.startsWith('image/')
249
+ ? 'image'
250
+ : 'video'
251
+ : asset.type === 'video'
252
+ ? 'video'
253
+ : 'image';
254
+
255
+ return fileType === 'image' ? (
121
256
  <AttachmentImage
257
+ asset={asset}
258
+ ImageOverlaySelectedComponent={ImageOverlaySelectedComponent}
259
+ maxNumberOfFiles={maxNumberOfFiles}
260
+ numberOfAttachmentPickerImageColumns={numberOfAttachmentPickerImageColumns}
261
+ selected={selected}
262
+ setSelectedImages={setSelectedImages}
263
+ />
264
+ ) : (
265
+ <AttachmentVideo
266
+ asset={asset}
122
267
  ImageOverlaySelectedComponent={ImageOverlaySelectedComponent}
268
+ maxNumberOfFiles={maxNumberOfFiles}
123
269
  numberOfAttachmentPickerImageColumns={numberOfAttachmentPickerImageColumns}
124
- onPress={onPress}
125
270
  selected={selected}
126
- uri={asset.uri}
271
+ setSelectedFiles={setSelectedFiles}
127
272
  />
128
273
  );
129
274
  };
@@ -187,8 +332,10 @@ export const AttachmentPicker = React.forwardRef(
187
332
  const {
188
333
  closePicker,
189
334
  maxNumberOfFiles,
335
+ selectedFiles,
190
336
  selectedImages,
191
337
  selectedPicker,
338
+ setSelectedFiles,
192
339
  setSelectedImages,
193
340
  setSelectedPicker,
194
341
  topInset,
@@ -306,7 +453,10 @@ export const AttachmentPicker = React.forwardRef(
306
453
  ImageOverlaySelectedComponent,
307
454
  maxNumberOfFiles,
308
455
  numberOfAttachmentPickerImageColumns,
309
- selected: selectedImages.some((image) => image.uri === asset.uri),
456
+ selected:
457
+ selectedImages.some((image) => image.uri === asset.uri) ||
458
+ selectedFiles.some((file) => file.uri === asset.uri),
459
+ setSelectedFiles,
310
460
  setSelectedImages,
311
461
  }));
312
462
 
@@ -143,7 +143,7 @@ const MessageContentWithContext = <
143
143
  colors: { accent_red, blue_alice, grey_gainsboro, grey_whisper, transparent, white },
144
144
  messageSimple: {
145
145
  content: {
146
- container: { borderRadiusL, borderRadiusS, ...container },
146
+ container: { borderRadius, borderRadiusL, borderRadiusS, ...container },
147
147
  containerInner,
148
148
  errorContainer,
149
149
  errorIcon,
@@ -223,6 +223,22 @@ const MessageContentWithContext = <
223
223
 
224
224
  const repliesCurveColor = isMyMessage && !error ? backgroundColor : grey_whisper;
225
225
 
226
+ const isBorderColor = isMyMessage && !error;
227
+
228
+ const shouldApplyBorderRadius = (firstGroupStyle: string, secondGroupStyle: string): boolean =>
229
+ (groupStyle === firstGroupStyle || groupStyle === secondGroupStyle) &&
230
+ (!hasThreadReplies || threadList);
231
+
232
+ const applyBorderRadius = (
233
+ firstGroupStyle: string,
234
+ secondGroupStyle: string,
235
+ ): number | undefined => {
236
+ if (shouldApplyBorderRadius(firstGroupStyle, secondGroupStyle)) {
237
+ return borderRadiusS;
238
+ }
239
+ return borderRadiusL;
240
+ };
241
+
226
242
  return (
227
243
  <TouchableOpacity
228
244
  activeOpacity={0.7}
@@ -297,17 +313,12 @@ const MessageContentWithContext = <
297
313
  styles.containerInner,
298
314
  {
299
315
  backgroundColor,
300
- borderBottomLeftRadius:
301
- (groupStyle === 'left_bottom' || groupStyle === 'left_single') &&
302
- (!hasThreadReplies || threadList)
303
- ? borderRadiusS
304
- : borderRadiusL,
305
- borderBottomRightRadius:
306
- (groupStyle === 'right_bottom' || groupStyle === 'right_single') &&
307
- (!hasThreadReplies || threadList)
308
- ? borderRadiusS
309
- : borderRadiusL,
310
- borderColor: isMyMessage && !error ? backgroundColor : grey_whisper,
316
+ borderBottomLeftRadius: applyBorderRadius('left_bottom', 'left_single'),
317
+ borderBottomRightRadius: applyBorderRadius('right_bottom', 'right_single'),
318
+ borderColor: isBorderColor ? backgroundColor : grey_whisper,
319
+ borderRadius,
320
+ borderTopLeftRadius: applyBorderRadius('left_top', 'right_single'),
321
+ borderTopRightRadius: applyBorderRadius('right_top', 'right_single'),
311
322
  },
312
323
  noBorder ? { borderWidth: 0 } : {},
313
324
  containerInner,
@@ -105,7 +105,7 @@ const UnsupportedFileTypeOrFileSizeIndicator = ({
105
105
  </View>
106
106
  ) : (
107
107
  <Text style={[styles.fileSizeText, { color: grey }, fileSizeText]}>
108
- {getFileSizeDisplayText(item.file.size)}
108
+ {item.file.duration ? item.file.duration : getFileSizeDisplayText(item.file.size)}
109
109
  </Text>
110
110
  );
111
111
  };