stream-chat-react-native-core 4.5.0 → 4.6.0
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.
- package/README.md +3 -3
- package/lib/commonjs/components/Attachment/FileIcon.js +9 -1
- package/lib/commonjs/components/Attachment/FileIcon.js.map +1 -1
- package/lib/commonjs/components/AttachmentPicker/AttachmentPicker.js +232 -48
- package/lib/commonjs/components/AttachmentPicker/AttachmentPicker.js.map +1 -1
- package/lib/commonjs/components/Channel/Channel.js.map +1 -1
- package/lib/commonjs/components/Chat/Chat.js.map +1 -1
- package/lib/commonjs/components/Message/Message.js.map +1 -1
- package/lib/commonjs/components/Message/MessageSimple/MessageContent.js +39 -21
- package/lib/commonjs/components/Message/MessageSimple/MessageContent.js.map +1 -1
- package/lib/commonjs/components/Message/MessageSimple/utils/renderText.md +1 -1
- package/lib/commonjs/components/MessageInput/FileUploadPreview.js +1 -1
- package/lib/commonjs/components/MessageInput/FileUploadPreview.js.map +1 -1
- package/lib/commonjs/components/MessageInput/MessageInput.js +129 -44
- package/lib/commonjs/components/MessageInput/MessageInput.js.map +1 -1
- package/lib/commonjs/components/Reply/Reply.js +25 -9
- package/lib/commonjs/components/Reply/Reply.js.map +1 -1
- package/lib/commonjs/contexts/attachmentPickerContext/AttachmentPickerContext.js +15 -8
- package/lib/commonjs/contexts/attachmentPickerContext/AttachmentPickerContext.js.map +1 -1
- package/lib/commonjs/contexts/channelContext/ChannelContext.js.map +1 -1
- package/lib/commonjs/contexts/channelContext/ChannelContext.md +1 -1
- package/lib/commonjs/contexts/channelsContext/ChannelsContext.js.map +1 -1
- package/lib/commonjs/contexts/channelsContext/ChannelsContext.md +1 -1
- package/lib/commonjs/contexts/chatContext/ChatContext.md +1 -1
- package/lib/commonjs/contexts/imageGalleryContext/ImageGalleryContext.md +1 -1
- package/lib/commonjs/contexts/keyboardContext/KeyboardContext.md +1 -1
- package/lib/commonjs/contexts/messageContext/MessageContext.js.map +1 -1
- package/lib/commonjs/contexts/messageContext/MessageContext.md +1 -1
- package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +10 -7
- package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
- package/lib/commonjs/contexts/messageInputContext/MessageInputContext.md +1 -1
- package/lib/commonjs/contexts/messageInputContext/hooks/useMessageDetailsForState.js +16 -1
- package/lib/commonjs/contexts/messageInputContext/hooks/useMessageDetailsForState.js.map +1 -1
- package/lib/commonjs/contexts/messageOverlayContext/MessageOverlayContext.js.map +1 -1
- package/lib/commonjs/contexts/messagesContext/MessagesContext.js.map +1 -1
- package/lib/commonjs/contexts/messagesContext/MessagesContext.md +1 -1
- package/lib/commonjs/contexts/overlayContext/OverlayContext.md +1 -1
- package/lib/commonjs/contexts/paginatedMessageListContext/PaginatedMessageListContext.md +1 -1
- package/lib/commonjs/contexts/suggestionsContext/SuggestionsContext.md +1 -1
- package/lib/commonjs/contexts/themeContext/utils/theme.js +1 -0
- package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
- package/lib/commonjs/contexts/typingContext/TypingContext.md +1 -1
- package/lib/commonjs/icons/Recorder.js +47 -0
- package/lib/commonjs/icons/Recorder.js.map +1 -0
- package/lib/commonjs/icons/Video.js +82 -0
- package/lib/commonjs/icons/Video.js.map +1 -0
- package/lib/commonjs/icons/index.js +26 -0
- package/lib/commonjs/icons/index.js.map +1 -1
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/version.json +1 -1
- package/lib/module/components/Attachment/FileIcon.js +9 -1
- package/lib/module/components/Attachment/FileIcon.js.map +1 -1
- package/lib/module/components/AttachmentPicker/AttachmentPicker.js +232 -48
- package/lib/module/components/AttachmentPicker/AttachmentPicker.js.map +1 -1
- package/lib/module/components/Channel/Channel.js.map +1 -1
- package/lib/module/components/Chat/Chat.js.map +1 -1
- package/lib/module/components/Message/Message.js.map +1 -1
- package/lib/module/components/Message/MessageSimple/MessageContent.js +39 -21
- package/lib/module/components/Message/MessageSimple/MessageContent.js.map +1 -1
- package/lib/module/components/Message/MessageSimple/utils/renderText.md +1 -1
- package/lib/module/components/MessageInput/FileUploadPreview.js +1 -1
- package/lib/module/components/MessageInput/FileUploadPreview.js.map +1 -1
- package/lib/module/components/MessageInput/MessageInput.js +129 -44
- package/lib/module/components/MessageInput/MessageInput.js.map +1 -1
- package/lib/module/components/Reply/Reply.js +25 -9
- package/lib/module/components/Reply/Reply.js.map +1 -1
- package/lib/module/contexts/attachmentPickerContext/AttachmentPickerContext.js +15 -8
- package/lib/module/contexts/attachmentPickerContext/AttachmentPickerContext.js.map +1 -1
- package/lib/module/contexts/channelContext/ChannelContext.js.map +1 -1
- package/lib/module/contexts/channelContext/ChannelContext.md +1 -1
- package/lib/module/contexts/channelsContext/ChannelsContext.js.map +1 -1
- package/lib/module/contexts/channelsContext/ChannelsContext.md +1 -1
- package/lib/module/contexts/chatContext/ChatContext.md +1 -1
- package/lib/module/contexts/imageGalleryContext/ImageGalleryContext.md +1 -1
- package/lib/module/contexts/keyboardContext/KeyboardContext.md +1 -1
- package/lib/module/contexts/messageContext/MessageContext.js.map +1 -1
- package/lib/module/contexts/messageContext/MessageContext.md +1 -1
- package/lib/module/contexts/messageInputContext/MessageInputContext.js +10 -7
- package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
- package/lib/module/contexts/messageInputContext/MessageInputContext.md +1 -1
- package/lib/module/contexts/messageInputContext/hooks/useMessageDetailsForState.js +16 -1
- package/lib/module/contexts/messageInputContext/hooks/useMessageDetailsForState.js.map +1 -1
- package/lib/module/contexts/messageOverlayContext/MessageOverlayContext.js.map +1 -1
- package/lib/module/contexts/messagesContext/MessagesContext.js.map +1 -1
- package/lib/module/contexts/messagesContext/MessagesContext.md +1 -1
- package/lib/module/contexts/overlayContext/OverlayContext.md +1 -1
- package/lib/module/contexts/paginatedMessageListContext/PaginatedMessageListContext.md +1 -1
- package/lib/module/contexts/suggestionsContext/SuggestionsContext.md +1 -1
- package/lib/module/contexts/themeContext/utils/theme.js +1 -0
- package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
- package/lib/module/contexts/typingContext/TypingContext.md +1 -1
- package/lib/module/icons/Recorder.js +47 -0
- package/lib/module/icons/Recorder.js.map +1 -0
- package/lib/module/icons/Video.js +82 -0
- package/lib/module/icons/Video.js.map +1 -0
- package/lib/module/icons/index.js +26 -0
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/native.js.map +1 -1
- package/lib/module/version.json +1 -1
- package/lib/typescript/components/AttachmentPicker/AttachmentPicker.d.ts +6 -6
- package/lib/typescript/components/Channel/Channel.d.ts +2 -2
- package/lib/typescript/components/Chat/Chat.d.ts +1 -1
- package/lib/typescript/components/Message/Message.d.ts +2 -2
- package/lib/typescript/components/MessageInput/MessageInput.d.ts +1 -1
- package/lib/typescript/contexts/attachmentPickerContext/AttachmentPickerContext.d.ts +9 -8
- package/lib/typescript/contexts/channelContext/ChannelContext.d.ts +2 -2
- package/lib/typescript/contexts/channelsContext/ChannelsContext.d.ts +6 -6
- package/lib/typescript/contexts/messageContext/MessageContext.d.ts +2 -2
- package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts +10 -21
- package/lib/typescript/contexts/messageOverlayContext/MessageOverlayContext.d.ts +6 -6
- package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts +20 -20
- package/lib/typescript/contexts/themeContext/utils/theme.d.ts +2 -1
- package/lib/typescript/icons/Recorder.d.ts +3 -0
- package/lib/typescript/icons/Video.d.ts +3 -0
- package/lib/typescript/icons/index.d.ts +2 -0
- package/lib/typescript/native.d.ts +3 -14
- package/lib/typescript/types/types.d.ts +24 -0
- package/package.json +1 -1
- package/src/components/Attachment/FileIcon.tsx +45 -0
- package/src/components/AttachmentPicker/AttachmentPicker.tsx +210 -60
- package/src/components/Channel/Channel.tsx +2 -2
- package/src/components/Chat/Chat.tsx +1 -1
- package/src/components/Message/Message.tsx +2 -2
- package/src/components/Message/MessageSimple/MessageContent.tsx +23 -12
- package/src/components/Message/MessageSimple/utils/renderText.md +1 -1
- package/src/components/MessageInput/FileUploadPreview.tsx +1 -1
- package/src/components/MessageInput/MessageInput.tsx +106 -19
- package/src/components/Reply/Reply.tsx +31 -14
- package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +12 -0
- package/src/contexts/attachmentPickerContext/AttachmentPickerContext.tsx +12 -8
- package/src/contexts/channelContext/ChannelContext.md +1 -1
- package/src/contexts/channelContext/ChannelContext.tsx +2 -2
- package/src/contexts/channelsContext/ChannelsContext.md +1 -1
- package/src/contexts/channelsContext/ChannelsContext.tsx +6 -6
- package/src/contexts/chatContext/ChatContext.md +1 -1
- package/src/contexts/imageGalleryContext/ImageGalleryContext.md +1 -1
- package/src/contexts/keyboardContext/KeyboardContext.md +1 -1
- package/src/contexts/messageContext/MessageContext.md +1 -1
- package/src/contexts/messageContext/MessageContext.tsx +2 -2
- package/src/contexts/messageInputContext/MessageInputContext.md +1 -1
- package/src/contexts/messageInputContext/MessageInputContext.tsx +23 -30
- package/src/contexts/messageInputContext/hooks/useMessageDetailsForState.ts +17 -1
- package/src/contexts/messageOverlayContext/MessageOverlayContext.tsx +6 -6
- package/src/contexts/messagesContext/MessagesContext.md +1 -1
- package/src/contexts/messagesContext/MessagesContext.tsx +20 -20
- package/src/contexts/overlayContext/OverlayContext.md +1 -1
- package/src/contexts/paginatedMessageListContext/PaginatedMessageListContext.md +1 -1
- package/src/contexts/suggestionsContext/SuggestionsContext.md +1 -1
- package/src/contexts/themeContext/utils/theme.ts +3 -1
- package/src/contexts/typingContext/TypingContext.md +1 -1
- package/src/icons/Recorder.tsx +16 -0
- package/src/icons/Video.tsx +37 -0
- package/src/icons/index.ts +2 -0
- package/src/native.ts +4 -14
- package/src/types/types.ts +27 -0
- package/src/version.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useMemo, useState } from 'react';
|
|
1
|
+
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
BackHandler,
|
|
4
4
|
Dimensions,
|
|
@@ -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 {
|
|
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;
|
|
40
61
|
ImageOverlaySelectedComponent: React.ComponentType;
|
|
41
|
-
|
|
62
|
+
maxNumberOfFiles: number;
|
|
42
63
|
selected: boolean;
|
|
43
|
-
|
|
64
|
+
setSelectedImages: React.Dispatch<React.SetStateAction<Asset[]>>;
|
|
44
65
|
numberOfAttachmentPickerImageColumns?: number;
|
|
45
66
|
};
|
|
46
67
|
|
|
68
|
+
type AttachmentVideoProps = {
|
|
69
|
+
asset: Asset;
|
|
70
|
+
ImageOverlaySelectedComponent: React.ComponentType;
|
|
71
|
+
maxNumberOfFiles: number;
|
|
72
|
+
selected: boolean;
|
|
73
|
+
setSelectedFiles: React.Dispatch<React.SetStateAction<File[]>>;
|
|
74
|
+
numberOfAttachmentPickerImageColumns?: number;
|
|
75
|
+
};
|
|
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
|
-
|
|
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={
|
|
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,55 +238,64 @@ 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
|
-
|
|
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
|
-
|
|
271
|
+
setSelectedFiles={setSelectedFiles}
|
|
127
272
|
/>
|
|
128
273
|
);
|
|
129
274
|
};
|
|
130
275
|
|
|
131
276
|
export type AttachmentPickerProps = {
|
|
132
277
|
/**
|
|
133
|
-
* Custom UI component to render [draggable handle](https://github.com/GetStream/stream-chat-react-native/blob/
|
|
278
|
+
* Custom UI component to render [draggable handle](https://github.com/GetStream/stream-chat-react-native/blob/main/screenshots/docs/1.png) of attachment picker.
|
|
134
279
|
*
|
|
135
|
-
* **Default** [AttachmentPickerBottomSheetHandle](https://github.com/GetStream/stream-chat-react-native/blob/
|
|
280
|
+
* **Default** [AttachmentPickerBottomSheetHandle](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/AttachmentPicker/components/AttachmentPickerBottomSheetHandle.tsx)
|
|
136
281
|
*/
|
|
137
282
|
AttachmentPickerBottomSheetHandle: React.FC<BottomSheetHandleProps>;
|
|
138
283
|
/**
|
|
139
284
|
* Custom UI component to render error component while opening attachment picker.
|
|
140
285
|
*
|
|
141
|
-
* **Default** [AttachmentPickerError](https://github.com/GetStream/stream-chat-react-native/blob/
|
|
286
|
+
* **Default** [AttachmentPickerError](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/AttachmentPicker/components/AttachmentPickerError.tsx)
|
|
142
287
|
*/
|
|
143
288
|
AttachmentPickerError: React.ComponentType<AttachmentPickerErrorProps>;
|
|
144
289
|
/**
|
|
145
290
|
* Custom UI component to render error image for attachment picker
|
|
146
291
|
*
|
|
147
|
-
* **Default** [AttachmentPickerErrorImage](https://github.com/GetStream/stream-chat-react-native/blob/
|
|
292
|
+
* **Default** [AttachmentPickerErrorImage](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/AttachmentPicker/components/AttachmentPickerErrorImage.tsx)
|
|
148
293
|
*/
|
|
149
294
|
AttachmentPickerErrorImage: React.ComponentType;
|
|
150
295
|
/**
|
|
151
|
-
* Custom UI component to render overlay component, that shows up on top of [selected image](https://github.com/GetStream/stream-chat-react-native/blob/
|
|
296
|
+
* Custom UI component to render overlay component, that shows up on top of [selected image](https://github.com/GetStream/stream-chat-react-native/blob/main/screenshots/docs/1.png) (with tick mark)
|
|
152
297
|
*
|
|
153
|
-
* **Default** [ImageOverlaySelectedComponent](https://github.com/GetStream/stream-chat-react-native/blob/
|
|
298
|
+
* **Default** [ImageOverlaySelectedComponent](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/AttachmentPicker/components/ImageOverlaySelectedComponent.tsx)
|
|
154
299
|
*/
|
|
155
300
|
ImageOverlaySelectedComponent: React.ComponentType;
|
|
156
301
|
attachmentPickerBottomSheetHandleHeight?: number;
|
|
@@ -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,
|
|
@@ -200,13 +347,7 @@ export const AttachmentPicker = React.forwardRef(
|
|
|
200
347
|
const [hasNextPage, setHasNextPage] = useState(true);
|
|
201
348
|
const [loadingPhotos, setLoadingPhotos] = useState(false);
|
|
202
349
|
const [photos, setPhotos] = useState<Asset[]>([]);
|
|
203
|
-
|
|
204
|
-
const hideAttachmentPicker = () => {
|
|
205
|
-
setSelectedPicker(undefined);
|
|
206
|
-
if ((ref as React.MutableRefObject<BottomSheet>)?.current) {
|
|
207
|
-
(ref as React.MutableRefObject<BottomSheet>).current.close();
|
|
208
|
-
}
|
|
209
|
-
};
|
|
350
|
+
const bottomSheetCloseOnKeyboardShowTimeout = useRef<NodeJS.Timeout>();
|
|
210
351
|
|
|
211
352
|
const getMorePhotos = async () => {
|
|
212
353
|
if (hasNextPage && !loadingPhotos && currentIndex > -1 && selectedPicker === 'images') {
|
|
@@ -248,6 +389,20 @@ export const AttachmentPicker = React.forwardRef(
|
|
|
248
389
|
}, [selectedPicker]);
|
|
249
390
|
|
|
250
391
|
useEffect(() => {
|
|
392
|
+
const hideAttachmentPicker = () => {
|
|
393
|
+
if (bottomSheetCloseOnKeyboardShowTimeout.current) {
|
|
394
|
+
clearTimeout(bottomSheetCloseOnKeyboardShowTimeout.current);
|
|
395
|
+
}
|
|
396
|
+
setSelectedPicker(undefined);
|
|
397
|
+
// This short timeout is to prevent a race condition
|
|
398
|
+
// where the close function is called during the point when a internal container layout happens within the bottomsheet due to keyboard affecting the layout
|
|
399
|
+
// If the container layout measures a shorter height than previous but if the close snapped to the previous height's position, the bottom sheet will show up
|
|
400
|
+
// this short delay ensures that close function is always called after a container layout due to keyboard change
|
|
401
|
+
bottomSheetCloseOnKeyboardShowTimeout.current = setTimeout(
|
|
402
|
+
() => (ref as React.MutableRefObject<BottomSheet | undefined>).current?.close(),
|
|
403
|
+
150,
|
|
404
|
+
);
|
|
405
|
+
};
|
|
251
406
|
const keyboardSubscription =
|
|
252
407
|
Platform.OS === 'ios'
|
|
253
408
|
? Keyboard.addListener('keyboardWillShow', hideAttachmentPicker)
|
|
@@ -265,6 +420,9 @@ export const AttachmentPicker = React.forwardRef(
|
|
|
265
420
|
} else {
|
|
266
421
|
Keyboard.removeListener('keyboardDidShow', hideAttachmentPicker);
|
|
267
422
|
}
|
|
423
|
+
if (bottomSheetCloseOnKeyboardShowTimeout.current) {
|
|
424
|
+
clearTimeout(bottomSheetCloseOnKeyboardShowTimeout.current);
|
|
425
|
+
}
|
|
268
426
|
};
|
|
269
427
|
}, []);
|
|
270
428
|
|
|
@@ -295,7 +453,10 @@ export const AttachmentPicker = React.forwardRef(
|
|
|
295
453
|
ImageOverlaySelectedComponent,
|
|
296
454
|
maxNumberOfFiles,
|
|
297
455
|
numberOfAttachmentPickerImageColumns,
|
|
298
|
-
selected:
|
|
456
|
+
selected:
|
|
457
|
+
selectedImages.some((image) => image.uri === asset.uri) ||
|
|
458
|
+
selectedFiles.some((file) => file.uri === asset.uri),
|
|
459
|
+
setSelectedFiles,
|
|
299
460
|
setSelectedImages,
|
|
300
461
|
}));
|
|
301
462
|
|
|
@@ -326,35 +487,24 @@ export const AttachmentPicker = React.forwardRef(
|
|
|
326
487
|
: statusBarHeight
|
|
327
488
|
: 0;
|
|
328
489
|
|
|
329
|
-
const initialSnapPoint =
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
(fullScreenHeight - screenHeight + androidBottomBarHeightAdjustment) -
|
|
334
|
-
handleHeight
|
|
335
|
-
: 308 + (fullScreenHeight - screenHeight + androidBottomBarHeightAdjustment),
|
|
336
|
-
[
|
|
337
|
-
attachmentPickerBottomSheetHeight,
|
|
338
|
-
androidBottomBarHeightAdjustment,
|
|
339
|
-
fullScreenHeight,
|
|
340
|
-
handleHeight,
|
|
341
|
-
screenHeight,
|
|
342
|
-
],
|
|
343
|
-
);
|
|
490
|
+
const initialSnapPoint =
|
|
491
|
+
attachmentPickerBottomSheetHeight ?? Platform.OS === 'android'
|
|
492
|
+
? 308 + (fullScreenHeight - screenHeight + androidBottomBarHeightAdjustment) - handleHeight
|
|
493
|
+
: 308 + (fullScreenHeight - screenHeight + androidBottomBarHeightAdjustment);
|
|
344
494
|
|
|
345
|
-
const finalSnapPoint =
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
: fullScreenHeight - topInset,
|
|
350
|
-
[fullScreenHeight, handleHeight, topInset],
|
|
351
|
-
);
|
|
495
|
+
const finalSnapPoint =
|
|
496
|
+
Platform.OS === 'android'
|
|
497
|
+
? fullScreenHeight - topInset - handleHeight
|
|
498
|
+
: fullScreenHeight - topInset;
|
|
352
499
|
|
|
353
500
|
/**
|
|
354
501
|
* Snap points changing cause a rerender of the position,
|
|
355
502
|
* this is an issue if you are calling close on the bottom sheet.
|
|
356
503
|
*/
|
|
357
|
-
const snapPoints =
|
|
504
|
+
const snapPoints = useMemo(
|
|
505
|
+
() => [initialSnapPoint, finalSnapPoint],
|
|
506
|
+
[initialSnapPoint, finalSnapPoint],
|
|
507
|
+
);
|
|
358
508
|
|
|
359
509
|
return (
|
|
360
510
|
<>
|
|
@@ -370,7 +520,7 @@ export const AttachmentPicker = React.forwardRef(
|
|
|
370
520
|
}
|
|
371
521
|
handleHeight={handleHeight}
|
|
372
522
|
index={-1}
|
|
373
|
-
onChange={
|
|
523
|
+
onChange={setCurrentIndex}
|
|
374
524
|
ref={ref}
|
|
375
525
|
snapPoints={snapPoints}
|
|
376
526
|
>
|
|
@@ -304,7 +304,7 @@ export type ChannelPropsWithContext<
|
|
|
304
304
|
/**
|
|
305
305
|
* When true, disables the KeyboardCompatibleView wrapper
|
|
306
306
|
*
|
|
307
|
-
* Channel internally uses the [KeyboardCompatibleView](https://github.com/GetStream/stream-chat-react-native/blob/
|
|
307
|
+
* Channel internally uses the [KeyboardCompatibleView](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/KeyboardCompatibleView/KeyboardCompatibleView.tsx)
|
|
308
308
|
* component to adjust the height of Channel when the keyboard is opened or dismissed. This prop provides the ability to disable this functionality in case you
|
|
309
309
|
* want to use [KeyboardAvoidingView](https://facebook.github.io/react-native/docs/keyboardavoidingview) or handle dismissal yourself.
|
|
310
310
|
* KeyboardAvoidingView works well when your component occupies 100% of screen height, otherwise it may raise some issues.
|
|
@@ -345,7 +345,7 @@ export type ChannelPropsWithContext<
|
|
|
345
345
|
keyboardBehavior?: KeyboardAvoidingViewProps['behavior'];
|
|
346
346
|
/**
|
|
347
347
|
* Custom wrapper component that handles height adjustment of Channel component when keyboard is opened or dismissed
|
|
348
|
-
* Default component (accepts the same props): [KeyboardCompatibleView](https://github.com/GetStream/stream-chat-react-native/blob/
|
|
348
|
+
* Default component (accepts the same props): [KeyboardCompatibleView](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/KeyboardCompatibleView/KeyboardCompatibleView.tsx)
|
|
349
349
|
*
|
|
350
350
|
* **Example:**
|
|
351
351
|
*
|
|
@@ -91,7 +91,7 @@ export type ChatProps<
|
|
|
91
91
|
*/
|
|
92
92
|
i18nInstance?: Streami18n;
|
|
93
93
|
/**
|
|
94
|
-
* You can pass the theme object to customize the styles of Chat components. You can check the default theme in [theme.ts](https://github.com/GetStream/stream-chat-react-native/blob/
|
|
94
|
+
* You can pass the theme object to customize the styles of Chat components. You can check the default theme in [theme.ts](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/contexts/themeContext/utils/theme.ts)
|
|
95
95
|
*
|
|
96
96
|
* Please check section about [themes in cookbook](https://github.com/GetStream/stream-chat-react-native/wiki/Cookbook-v3.0#theme) for details.
|
|
97
97
|
*
|
|
@@ -160,7 +160,7 @@ export type MessagePropsWithContext<
|
|
|
160
160
|
* You can call methods available on the Message
|
|
161
161
|
* component such as handleEdit, handleDelete, handleAction etc.
|
|
162
162
|
*
|
|
163
|
-
* Source - [Message](https://github.com/GetStream/stream-chat-react-native/blob/
|
|
163
|
+
* Source - [Message](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/Message/Message.tsx)
|
|
164
164
|
*
|
|
165
165
|
* By default, we show the overlay with all the message actions on long press.
|
|
166
166
|
*
|
|
@@ -173,7 +173,7 @@ export type MessagePropsWithContext<
|
|
|
173
173
|
* You can call methods available on the Message
|
|
174
174
|
* component such as handleEdit, handleDelete, handleAction etc.
|
|
175
175
|
*
|
|
176
|
-
* Source - [Message](https://github.com/GetStream/stream-chat-react-native/blob/
|
|
176
|
+
* Source - [Message](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/Message/Message.tsx)
|
|
177
177
|
*
|
|
178
178
|
* By default, we will dismiss the keyboard on press.
|
|
179
179
|
*
|
|
@@ -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
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
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,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[src/components/Message/MessageSimple/utils/renderText.ts](https://github.com/GetStream/stream-chat-react-native/blob/
|
|
1
|
+
[src/components/Message/MessageSimple/utils/renderText.ts](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/Message/MessageSimple/utils/renderText.ts)
|
|
2
2
|
|
|
3
3
|
Function that handles markdown and parsing for the text of message.
|
|
4
4
|
|
|
@@ -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
|
};
|