stream-chat-react-native-core 5.2.0 → 5.3.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.
- package/lib/commonjs/components/Attachment/Card.js +29 -18
- package/lib/commonjs/components/Attachment/Card.js.map +1 -1
- package/lib/commonjs/components/Attachment/Gallery.js +16 -20
- package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
- package/lib/commonjs/components/Attachment/GalleryImage.js +34 -6
- package/lib/commonjs/components/Attachment/GalleryImage.js.map +1 -1
- package/lib/commonjs/components/Attachment/Giphy.js +37 -29
- package/lib/commonjs/components/Attachment/Giphy.js.map +1 -1
- package/lib/commonjs/components/Avatar/Avatar.js +10 -8
- package/lib/commonjs/components/Avatar/Avatar.js.map +1 -1
- package/lib/commonjs/components/Avatar/GroupAvatar.js +3 -1
- package/lib/commonjs/components/Avatar/GroupAvatar.js.map +1 -1
- package/lib/commonjs/components/ChannelList/ChannelList.js +4 -4
- package/lib/commonjs/components/ChannelList/ChannelList.js.map +1 -1
- package/lib/commonjs/components/ChannelList/ChannelListMessenger.js +4 -4
- package/lib/commonjs/components/ChannelList/ChannelListMessenger.js.map +1 -1
- package/lib/commonjs/components/ChannelList/hooks/useCreateChannelsContext.js +1 -1
- package/lib/commonjs/components/ChannelList/hooks/useCreateChannelsContext.js.map +1 -1
- package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js +6 -7
- package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/ChannelAvatar.js +30 -6
- package/lib/commonjs/components/ChannelPreview/ChannelAvatar.js.map +1 -1
- package/lib/commonjs/components/Chat/Chat.js +8 -5
- package/lib/commonjs/components/Chat/Chat.js.map +1 -1
- package/lib/commonjs/components/Chat/hooks/useCreateChatContext.js +2 -0
- package/lib/commonjs/components/Chat/hooks/useCreateChatContext.js.map +1 -1
- package/lib/commonjs/components/ImageBackground.js +64 -0
- package/lib/commonjs/components/ImageBackground.js.map +1 -0
- package/lib/commonjs/components/Message/Message.js +15 -16
- package/lib/commonjs/components/Message/Message.js.map +1 -1
- package/lib/commonjs/components/Message/MessageSimple/MessageAvatar.js +12 -4
- package/lib/commonjs/components/Message/MessageSimple/MessageAvatar.js.map +1 -1
- package/lib/commonjs/components/Message/MessageSimple/MessageRepliesAvatars.js +26 -5
- package/lib/commonjs/components/Message/MessageSimple/MessageRepliesAvatars.js.map +1 -1
- package/lib/commonjs/components/MessageOverlay/MessageOverlay.js +58 -47
- package/lib/commonjs/components/MessageOverlay/MessageOverlay.js.map +1 -1
- package/lib/commonjs/contexts/channelsContext/ChannelsContext.js.map +1 -1
- package/lib/commonjs/contexts/chatContext/ChatContext.js +2 -2
- package/lib/commonjs/contexts/chatContext/ChatContext.js.map +1 -1
- package/lib/commonjs/contexts/messageOverlayContext/MessageOverlayContext.js +2 -2
- package/lib/commonjs/contexts/messageOverlayContext/MessageOverlayContext.js.map +1 -1
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/version.json +1 -1
- package/lib/module/components/Attachment/Card.js +29 -18
- package/lib/module/components/Attachment/Card.js.map +1 -1
- package/lib/module/components/Attachment/Gallery.js +16 -20
- package/lib/module/components/Attachment/Gallery.js.map +1 -1
- package/lib/module/components/Attachment/GalleryImage.js +34 -6
- package/lib/module/components/Attachment/GalleryImage.js.map +1 -1
- package/lib/module/components/Attachment/Giphy.js +37 -29
- package/lib/module/components/Attachment/Giphy.js.map +1 -1
- package/lib/module/components/Avatar/Avatar.js +10 -8
- package/lib/module/components/Avatar/Avatar.js.map +1 -1
- package/lib/module/components/Avatar/GroupAvatar.js +3 -1
- package/lib/module/components/Avatar/GroupAvatar.js.map +1 -1
- package/lib/module/components/ChannelList/ChannelList.js +4 -4
- package/lib/module/components/ChannelList/ChannelList.js.map +1 -1
- package/lib/module/components/ChannelList/ChannelListMessenger.js +4 -4
- package/lib/module/components/ChannelList/ChannelListMessenger.js.map +1 -1
- package/lib/module/components/ChannelList/hooks/useCreateChannelsContext.js +1 -1
- package/lib/module/components/ChannelList/hooks/useCreateChannelsContext.js.map +1 -1
- package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js +6 -7
- package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
- package/lib/module/components/ChannelPreview/ChannelAvatar.js +30 -6
- package/lib/module/components/ChannelPreview/ChannelAvatar.js.map +1 -1
- package/lib/module/components/Chat/Chat.js +8 -5
- package/lib/module/components/Chat/Chat.js.map +1 -1
- package/lib/module/components/Chat/hooks/useCreateChatContext.js +2 -0
- package/lib/module/components/Chat/hooks/useCreateChatContext.js.map +1 -1
- package/lib/module/components/ImageBackground.js +64 -0
- package/lib/module/components/ImageBackground.js.map +1 -0
- package/lib/module/components/Message/Message.js +15 -16
- package/lib/module/components/Message/Message.js.map +1 -1
- package/lib/module/components/Message/MessageSimple/MessageAvatar.js +12 -4
- package/lib/module/components/Message/MessageSimple/MessageAvatar.js.map +1 -1
- package/lib/module/components/Message/MessageSimple/MessageRepliesAvatars.js +26 -5
- package/lib/module/components/Message/MessageSimple/MessageRepliesAvatars.js.map +1 -1
- package/lib/module/components/MessageOverlay/MessageOverlay.js +58 -47
- package/lib/module/components/MessageOverlay/MessageOverlay.js.map +1 -1
- package/lib/module/contexts/channelsContext/ChannelsContext.js.map +1 -1
- package/lib/module/contexts/chatContext/ChatContext.js +2 -2
- package/lib/module/contexts/chatContext/ChatContext.js.map +1 -1
- package/lib/module/contexts/messageOverlayContext/MessageOverlayContext.js +2 -2
- package/lib/module/contexts/messageOverlayContext/MessageOverlayContext.js.map +1 -1
- package/lib/module/native.js.map +1 -1
- package/lib/module/version.json +1 -1
- package/lib/typescript/components/Attachment/Card.d.ts +3 -2
- package/lib/typescript/components/Attachment/GalleryImage.d.ts +8 -2
- package/lib/typescript/components/Attachment/Giphy.d.ts +2 -1
- package/lib/typescript/components/Avatar/Avatar.d.ts +2 -1
- package/lib/typescript/components/Avatar/GroupAvatar.d.ts +2 -1
- package/lib/typescript/components/ChannelList/hooks/usePaginatedChannels.d.ts +1 -1
- package/lib/typescript/components/ChannelPreview/ChannelAvatar.d.ts +2 -0
- package/lib/typescript/components/Chat/Chat.d.ts +1 -1
- package/lib/typescript/components/Chat/hooks/useCreateChatContext.d.ts +1 -1
- package/lib/typescript/components/ImageBackground.d.ts +33 -0
- package/lib/typescript/components/Message/Message.d.ts +2 -1
- package/lib/typescript/components/Message/MessageSimple/MessageAvatar.d.ts +2 -1
- package/lib/typescript/components/Message/MessageSimple/MessageRepliesAvatars.d.ts +2 -0
- package/lib/typescript/contexts/channelsContext/ChannelsContext.d.ts +1 -1
- package/lib/typescript/contexts/chatContext/ChatContext.d.ts +3 -1
- package/lib/typescript/contexts/messageOverlayContext/MessageOverlayContext.d.ts +4 -0
- package/lib/typescript/native.d.ts +2 -2
- package/package.json +1 -1
- package/src/__tests__/offline-feature.test.js +3 -1
- package/src/components/Attachment/Card.tsx +11 -2
- package/src/components/Attachment/Gallery.tsx +1 -7
- package/src/components/Attachment/GalleryImage.tsx +31 -9
- package/src/components/Attachment/Giphy.tsx +8 -2
- package/src/components/Avatar/Avatar.tsx +12 -2
- package/src/components/Avatar/GroupAvatar.tsx +4 -4
- package/src/components/ChannelList/ChannelList.tsx +3 -2
- package/src/components/ChannelList/ChannelListMessenger.tsx +3 -3
- package/src/components/ChannelList/__tests__/ChannelList.test.js +1 -1
- package/src/components/ChannelList/hooks/listeners/__tests__/useChannelUpdated.test.tsx +2 -1
- package/src/components/ChannelList/hooks/useCreateChannelsContext.ts +1 -1
- package/src/components/ChannelList/hooks/usePaginatedChannels.ts +12 -11
- package/src/components/ChannelPreview/ChannelAvatar.tsx +23 -4
- package/src/components/Chat/Chat.tsx +98 -95
- package/src/components/Chat/hooks/useCreateChatContext.ts +2 -0
- package/src/components/ImageBackground.tsx +77 -0
- package/src/components/Message/Message.tsx +8 -8
- package/src/components/Message/MessageSimple/MessageAvatar.tsx +6 -2
- package/src/components/Message/MessageSimple/MessageRepliesAvatars.tsx +15 -3
- package/src/components/MessageOverlay/MessageOverlay.tsx +210 -205
- package/src/contexts/channelsContext/ChannelsContext.tsx +1 -1
- package/src/contexts/chatContext/ChatContext.tsx +3 -1
- package/src/contexts/messageOverlayContext/MessageOverlayContext.tsx +8 -1
- package/src/native.ts +2 -2
- package/src/version.json +1 -1
|
@@ -3,6 +3,8 @@ import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
|
|
3
3
|
|
|
4
4
|
import type { Attachment } from 'stream-chat';
|
|
5
5
|
|
|
6
|
+
import { ChatContextValue, useChatContext } from '../../contexts/chatContext/ChatContext';
|
|
7
|
+
|
|
6
8
|
import {
|
|
7
9
|
ImageGalleryContextValue,
|
|
8
10
|
useImageGalleryContext,
|
|
@@ -145,6 +147,7 @@ export type GiphyPropsWithContext<
|
|
|
145
147
|
| 'onPressIn'
|
|
146
148
|
| 'preventPress'
|
|
147
149
|
> &
|
|
150
|
+
Pick<ChatContextValue<StreamChatGenerics>, 'ImageComponent'> &
|
|
148
151
|
Pick<
|
|
149
152
|
MessagesContextValue<StreamChatGenerics>,
|
|
150
153
|
| 'giphyVersion'
|
|
@@ -165,6 +168,7 @@ const GiphyWithContext = <
|
|
|
165
168
|
attachment,
|
|
166
169
|
giphyVersion,
|
|
167
170
|
handleAction,
|
|
171
|
+
ImageComponent = Image,
|
|
168
172
|
ImageLoadingFailedIndicator,
|
|
169
173
|
ImageLoadingIndicator,
|
|
170
174
|
isMyMessage,
|
|
@@ -241,7 +245,7 @@ const GiphyWithContext = <
|
|
|
241
245
|
>{`/giphy ${title}`}</Text>
|
|
242
246
|
</View>
|
|
243
247
|
<View style={styles.selectionImageContainer}>
|
|
244
|
-
<
|
|
248
|
+
<ImageComponent
|
|
245
249
|
onError={(error) => {
|
|
246
250
|
console.warn(error);
|
|
247
251
|
setLoadingImage(false);
|
|
@@ -339,7 +343,7 @@ const GiphyWithContext = <
|
|
|
339
343
|
container,
|
|
340
344
|
]}
|
|
341
345
|
>
|
|
342
|
-
<
|
|
346
|
+
<ImageComponent
|
|
343
347
|
accessibilityLabel='Giphy Attachment Image'
|
|
344
348
|
onError={(error) => {
|
|
345
349
|
console.warn(error);
|
|
@@ -446,6 +450,7 @@ export const Giphy = <
|
|
|
446
450
|
) => {
|
|
447
451
|
const { handleAction, isMyMessage, message, onLongPress, onPress, onPressIn, preventPress } =
|
|
448
452
|
useMessageContext<StreamChatGenerics>();
|
|
453
|
+
const { ImageComponent } = useChatContext<StreamChatGenerics>();
|
|
449
454
|
const { additionalTouchableProps, giphyVersion } = useMessagesContext<StreamChatGenerics>();
|
|
450
455
|
const { setMessages, setSelectedMessage } = useImageGalleryContext<StreamChatGenerics>();
|
|
451
456
|
const { setOverlay } = useOverlayContext();
|
|
@@ -464,6 +469,7 @@ export const Giphy = <
|
|
|
464
469
|
additionalTouchableProps,
|
|
465
470
|
giphyVersion,
|
|
466
471
|
handleAction,
|
|
472
|
+
ImageComponent,
|
|
467
473
|
ImageLoadingFailedIndicator,
|
|
468
474
|
ImageLoadingIndicator,
|
|
469
475
|
isMyMessage,
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Image,
|
|
4
|
+
ImageProps,
|
|
5
|
+
ImageStyle,
|
|
6
|
+
StyleProp,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
View,
|
|
9
|
+
ViewStyle,
|
|
10
|
+
} from 'react-native';
|
|
3
11
|
import Svg, { Circle, CircleProps } from 'react-native-svg';
|
|
4
12
|
|
|
5
13
|
import { useTheme } from '../../contexts/themeContext/ThemeContext';
|
|
@@ -38,6 +46,7 @@ export type AvatarProps = {
|
|
|
38
46
|
containerStyle?: StyleProp<ViewStyle>;
|
|
39
47
|
/** image url */
|
|
40
48
|
image?: string;
|
|
49
|
+
ImageComponent?: React.ComponentType<ImageProps>;
|
|
41
50
|
/** name of the picture, used for fallback */
|
|
42
51
|
imageStyle?: StyleProp<ImageStyle>;
|
|
43
52
|
name?: string;
|
|
@@ -53,6 +62,7 @@ export type AvatarProps = {
|
|
|
53
62
|
export const Avatar: React.FC<AvatarProps> = (props) => {
|
|
54
63
|
const {
|
|
55
64
|
containerStyle,
|
|
65
|
+
ImageComponent = Image,
|
|
56
66
|
image: imageProp,
|
|
57
67
|
imageStyle,
|
|
58
68
|
name,
|
|
@@ -95,7 +105,7 @@ export const Avatar: React.FC<AvatarProps> = (props) => {
|
|
|
95
105
|
}}
|
|
96
106
|
/>
|
|
97
107
|
) : (
|
|
98
|
-
<
|
|
108
|
+
<ImageComponent
|
|
99
109
|
accessibilityLabel={testID || 'Avatar Image'}
|
|
100
110
|
onError={() => setLoadingImageError(true)}
|
|
101
111
|
source={{
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Image, StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
|
|
2
|
+
import { Image, ImageProps, StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import { useTheme } from '../../contexts/themeContext/ThemeContext';
|
|
5
5
|
import { useLoadingImage } from '../../hooks/useLoadingImage';
|
|
6
6
|
import { getResizedImageUrl } from '../../utils/getResizedImageUrl';
|
|
7
|
-
|
|
8
7
|
const randomImageBaseUrl = 'https://getstream.io/random_png/';
|
|
9
8
|
const randomSvgBaseUrl = 'https://getstream.io/random_svg/';
|
|
10
9
|
const streamCDN = 'stream-io-cdn.com';
|
|
@@ -27,6 +26,7 @@ export type GroupAvatarProps = {
|
|
|
27
26
|
/** total size in pixels */
|
|
28
27
|
size: number;
|
|
29
28
|
containerStyle?: StyleProp<ViewStyle>;
|
|
29
|
+
ImageComponent?: React.ComponentType<ImageProps>;
|
|
30
30
|
/** image urls */
|
|
31
31
|
images?: string[];
|
|
32
32
|
/** name of the users, used for fallback */
|
|
@@ -38,7 +38,7 @@ export type GroupAvatarProps = {
|
|
|
38
38
|
* GroupAvatar - A round group of avatar images with fallbacks to users' initials
|
|
39
39
|
*/
|
|
40
40
|
export const GroupAvatar: React.FC<GroupAvatarProps> = (props) => {
|
|
41
|
-
const { containerStyle, images, names, size, testID } = props;
|
|
41
|
+
const { containerStyle, ImageComponent = Image, images, names, size, testID } = props;
|
|
42
42
|
const {
|
|
43
43
|
theme: {
|
|
44
44
|
groupAvatar: { container, image },
|
|
@@ -136,7 +136,7 @@ export const GroupAvatar: React.FC<GroupAvatarProps> = (props) => {
|
|
|
136
136
|
]}
|
|
137
137
|
>
|
|
138
138
|
{column.map(({ height, name, url, width }, rowIndex) => (
|
|
139
|
-
<
|
|
139
|
+
<ImageComponent
|
|
140
140
|
accessibilityLabel={testID || 'Avatar Image'}
|
|
141
141
|
key={`avatar-${url}-${rowIndex}`}
|
|
142
142
|
onError={() => setLoadingImageError(true)}
|
|
@@ -314,12 +314,13 @@ export const ChannelList = <
|
|
|
314
314
|
setChannels,
|
|
315
315
|
});
|
|
316
316
|
|
|
317
|
-
const channelIdsStr = channels
|
|
317
|
+
const channelIdsStr = channels?.reduce((acc, channel) => `${acc}${channel.cid}`, '');
|
|
318
318
|
|
|
319
319
|
useEffect(() => {
|
|
320
|
-
if (staticChannelsActive || !enableOfflineSupport) {
|
|
320
|
+
if (channels === null || staticChannelsActive || !enableOfflineSupport) {
|
|
321
321
|
return;
|
|
322
322
|
}
|
|
323
|
+
|
|
323
324
|
upsertCidsForQuery({
|
|
324
325
|
cids: channels.map((c) => c.cid),
|
|
325
326
|
filters,
|
|
@@ -132,14 +132,14 @@ const ChannelListMessengerWithContext = <
|
|
|
132
132
|
if (debugRef.current.setSendEventParams)
|
|
133
133
|
debugRef.current.setSendEventParams({
|
|
134
134
|
action: 'Channels',
|
|
135
|
-
data: channels
|
|
135
|
+
data: channels?.map((channel) => ({
|
|
136
136
|
data: channel.data,
|
|
137
137
|
members: channel.state.members,
|
|
138
138
|
})),
|
|
139
139
|
});
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
if (error && !refreshing && !loadingChannels &&
|
|
142
|
+
if (error && !refreshing && !loadingChannels && channels === null) {
|
|
143
143
|
return (
|
|
144
144
|
<LoadingErrorIndicator
|
|
145
145
|
error={error}
|
|
@@ -157,7 +157,7 @@ const ChannelListMessengerWithContext = <
|
|
|
157
157
|
};
|
|
158
158
|
|
|
159
159
|
const ListFooterComponent = () =>
|
|
160
|
-
channels
|
|
160
|
+
channels?.length && ListHeaderComponent ? <ListHeaderComponent /> : null;
|
|
161
161
|
|
|
162
162
|
if (loadingChannels) {
|
|
163
163
|
return <LoadingIndicator listType='channel' />;
|
|
@@ -43,7 +43,7 @@ const ChannelListComponent = (props) => {
|
|
|
43
43
|
const { channels, onSelect } = useChannelsContext();
|
|
44
44
|
return (
|
|
45
45
|
<View testID='channel-list'>
|
|
46
|
-
{channels
|
|
46
|
+
{channels?.map((channel) => (
|
|
47
47
|
<ChannelPreviewComponent
|
|
48
48
|
{...props}
|
|
49
49
|
channel={channel}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { Text } from 'react-native';
|
|
2
|
+
import { Image, Text } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import { act } from 'react-test-renderer';
|
|
5
5
|
|
|
@@ -59,6 +59,7 @@ describe('useChannelUpdated', () => {
|
|
|
59
59
|
client: mockClient,
|
|
60
60
|
connectionRecovering: false,
|
|
61
61
|
enableOfflineSupport: false,
|
|
62
|
+
ImageComponent: Image,
|
|
62
63
|
isOnline: true,
|
|
63
64
|
mutedUsers: [],
|
|
64
65
|
setActiveChannel: () => null,
|
|
@@ -38,7 +38,7 @@ export const useCreateChannelsContext = <
|
|
|
38
38
|
Skeleton,
|
|
39
39
|
}: ChannelsContextValue<StreamChatGenerics>) => {
|
|
40
40
|
const channelValueString = channels
|
|
41
|
-
|
|
41
|
+
?.map(
|
|
42
42
|
(channel) =>
|
|
43
43
|
`${channel.data?.name ?? ''}${channel.id ?? ''}${Object.values(channel.state.members)
|
|
44
44
|
.map((member) => member.user?.online)
|
|
@@ -44,11 +44,8 @@ export const usePaginatedChannels = <
|
|
|
44
44
|
sort = {},
|
|
45
45
|
}: Parameters<StreamChatGenerics>) => {
|
|
46
46
|
const { client } = useChatContext<StreamChatGenerics>();
|
|
47
|
-
const
|
|
48
|
-
const [
|
|
49
|
-
initialChannelsStateRef.current,
|
|
50
|
-
);
|
|
51
|
-
const [staticChannelsActive, setStaticChannelsActive] = useState<boolean>(true);
|
|
47
|
+
const [channels, setChannels] = useState<Channel<StreamChatGenerics>[] | null>(null);
|
|
48
|
+
const [staticChannelsActive, setStaticChannelsActive] = useState<boolean>(false);
|
|
52
49
|
const activeChannels = useActiveChannelsRefContext();
|
|
53
50
|
|
|
54
51
|
const [error, setError] = useState<Error>();
|
|
@@ -95,7 +92,8 @@ export const usePaginatedChannels = <
|
|
|
95
92
|
|
|
96
93
|
const newOptions = {
|
|
97
94
|
limit: options?.limit ?? MAX_QUERY_CHANNELS_LIMIT,
|
|
98
|
-
offset:
|
|
95
|
+
offset:
|
|
96
|
+
queryType === 'loadChannels' && !staticChannelsActive && channels ? channels.length : 0,
|
|
99
97
|
...options,
|
|
100
98
|
};
|
|
101
99
|
|
|
@@ -108,7 +106,7 @@ export const usePaginatedChannels = <
|
|
|
108
106
|
return;
|
|
109
107
|
}
|
|
110
108
|
const newChannels =
|
|
111
|
-
queryType === 'loadChannels' && !staticChannelsActive
|
|
109
|
+
queryType === 'loadChannels' && !staticChannelsActive && channels
|
|
112
110
|
? [...channels, ...channelQueryResponse]
|
|
113
111
|
: channelQueryResponse;
|
|
114
112
|
|
|
@@ -195,6 +193,7 @@ export const usePaginatedChannels = <
|
|
|
195
193
|
offlineMode: true,
|
|
196
194
|
}),
|
|
197
195
|
);
|
|
196
|
+
setStaticChannelsActive(true);
|
|
198
197
|
}
|
|
199
198
|
} catch (e) {
|
|
200
199
|
console.warn('Failed to get channels from database: ', e);
|
|
@@ -212,15 +211,17 @@ export const usePaginatedChannels = <
|
|
|
212
211
|
error,
|
|
213
212
|
hasNextPage,
|
|
214
213
|
loadingChannels:
|
|
215
|
-
activeQueryType === 'queryLocalDB'
|
|
216
|
-
? true
|
|
217
|
-
: activeQueryType === 'reload' && channels === initialChannelsStateRef.current,
|
|
214
|
+
activeQueryType === 'queryLocalDB' ? true : activeQueryType === 'reload' && channels === null,
|
|
218
215
|
loadingNextPage: activeQueryType === 'loadChannels',
|
|
219
216
|
loadNextPage,
|
|
220
217
|
refreshing: activeQueryType === 'refresh',
|
|
221
218
|
refreshList,
|
|
222
219
|
reloadList,
|
|
223
|
-
|
|
220
|
+
// Although channels can be null, there is no practical case where channels will be null
|
|
221
|
+
// when setChannels is used. setChannels is only recommended to be used for overriding
|
|
222
|
+
// event handler. Thus instead of adding if check for channels === null, its better to
|
|
223
|
+
// simply reassign types here.
|
|
224
|
+
setChannels: setChannels as React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[]>>,
|
|
224
225
|
staticChannelsActive,
|
|
225
226
|
};
|
|
226
227
|
};
|
|
@@ -4,6 +4,7 @@ import type { ChannelPreviewProps } from './ChannelPreview';
|
|
|
4
4
|
import { useChannelPreviewDisplayAvatar } from './hooks/useChannelPreviewDisplayAvatar';
|
|
5
5
|
import { useChannelPreviewDisplayPresence } from './hooks/useChannelPreviewDisplayPresence';
|
|
6
6
|
|
|
7
|
+
import { ChatContextValue, useChatContext } from '../../contexts/chatContext/ChatContext';
|
|
7
8
|
import type { DefaultStreamChatGenerics } from '../../types/types';
|
|
8
9
|
import { Avatar } from '../Avatar/Avatar';
|
|
9
10
|
import { GroupAvatar } from '../Avatar/GroupAvatar';
|
|
@@ -15,26 +16,44 @@ export type ChannelAvatarProps<
|
|
|
15
16
|
/**
|
|
16
17
|
* This UI component displays an avatar for a particular channel.
|
|
17
18
|
*/
|
|
18
|
-
export const
|
|
19
|
+
export const ChannelAvatarWithContext = <
|
|
19
20
|
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
|
|
20
21
|
>(
|
|
21
|
-
props: ChannelAvatarProps<StreamChatGenerics>,
|
|
22
|
+
props: ChannelAvatarProps<StreamChatGenerics> & Pick<ChatContextValue, 'ImageComponent'>,
|
|
22
23
|
) => {
|
|
23
|
-
const { channel } = props;
|
|
24
|
+
const { channel, ImageComponent } = props;
|
|
24
25
|
|
|
25
26
|
const displayAvatar = useChannelPreviewDisplayAvatar(channel);
|
|
26
27
|
const displayPresence = useChannelPreviewDisplayPresence(channel);
|
|
27
28
|
|
|
28
29
|
if (displayAvatar.images) {
|
|
29
|
-
return
|
|
30
|
+
return (
|
|
31
|
+
<GroupAvatar
|
|
32
|
+
ImageComponent={ImageComponent}
|
|
33
|
+
images={displayAvatar.images}
|
|
34
|
+
names={displayAvatar.names}
|
|
35
|
+
size={40}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
30
38
|
}
|
|
31
39
|
|
|
32
40
|
return (
|
|
33
41
|
<Avatar
|
|
34
42
|
image={displayAvatar.image}
|
|
43
|
+
ImageComponent={ImageComponent}
|
|
35
44
|
name={displayAvatar.name}
|
|
36
45
|
online={displayPresence}
|
|
37
46
|
size={40}
|
|
38
47
|
/>
|
|
39
48
|
);
|
|
40
49
|
};
|
|
50
|
+
|
|
51
|
+
export const ChannelAvatar = <
|
|
52
|
+
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
|
|
53
|
+
>(
|
|
54
|
+
props: ChannelAvatarProps<StreamChatGenerics>,
|
|
55
|
+
) => {
|
|
56
|
+
const { ImageComponent } = useChatContext<StreamChatGenerics>();
|
|
57
|
+
|
|
58
|
+
return <ChannelAvatarWithContext {...props} ImageComponent={ImageComponent} />;
|
|
59
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { PropsWithChildren, useEffect, useState } from 'react';
|
|
2
|
-
import { Platform } from 'react-native';
|
|
2
|
+
import { Image, Platform } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import Dayjs from 'dayjs';
|
|
5
5
|
|
|
@@ -37,100 +37,101 @@ init();
|
|
|
37
37
|
|
|
38
38
|
export type ChatProps<
|
|
39
39
|
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
|
|
40
|
-
> = Pick<ChatContextValue<StreamChatGenerics>, 'client'> &
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
40
|
+
> = Pick<ChatContextValue<StreamChatGenerics>, 'client'> &
|
|
41
|
+
Partial<Pick<ChatContextValue<StreamChatGenerics>, 'ImageComponent'>> & {
|
|
42
|
+
/**
|
|
43
|
+
* When false, ws connection won't be disconnection upon backgrounding the app.
|
|
44
|
+
* To receive push notifications, its necessary that user doesn't have active
|
|
45
|
+
* websocket connection. So by default, we disconnect websocket connection when
|
|
46
|
+
* app goes to background, and reconnect when app comes to foreground.
|
|
47
|
+
*/
|
|
48
|
+
closeConnectionOnBackground?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Enables offline storage and loading for chat data.
|
|
51
|
+
*/
|
|
52
|
+
enableOfflineSupport?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Instance of Streami18n class should be provided to Chat component to enable internationalization.
|
|
55
|
+
*
|
|
56
|
+
* Stream provides following list of in-built translations:
|
|
57
|
+
* 1. English (en)
|
|
58
|
+
* 2. Dutch (nl)
|
|
59
|
+
* 3. ...
|
|
60
|
+
* 4. ...
|
|
61
|
+
*
|
|
62
|
+
* Simplest way to start using chat components in one of the in-built languages would be following:
|
|
63
|
+
*
|
|
64
|
+
* ```
|
|
65
|
+
* const i18n = new Streami18n('nl');
|
|
66
|
+
* <Chat client={chatClient} i18nInstance={i18n}>
|
|
67
|
+
* ...
|
|
68
|
+
* </Chat>
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* If you would like to override certain keys in in-built translation.
|
|
72
|
+
* UI will be automatically updated in this case.
|
|
73
|
+
*
|
|
74
|
+
* ```
|
|
75
|
+
* const i18n = new Streami18n('nl');
|
|
76
|
+
*
|
|
77
|
+
* i18n.registerTranslation('nl', {
|
|
78
|
+
* 'Nothing yet...': 'Nog Niet ...',
|
|
79
|
+
* '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} en {{ secondUser }} zijn aan het typen...',
|
|
80
|
+
* });
|
|
81
|
+
*
|
|
82
|
+
* <Chat client={chatClient} i18nInstance={i18n}>
|
|
83
|
+
* ...
|
|
84
|
+
* </Chat>
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* You can use the same function to add whole new language.
|
|
88
|
+
*
|
|
89
|
+
* ```
|
|
90
|
+
* const i18n = new Streami18n('it');
|
|
91
|
+
*
|
|
92
|
+
* i18n.registerTranslation('it', {
|
|
93
|
+
* 'Nothing yet...': 'Non ancora ...',
|
|
94
|
+
* '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} a {{ secondUser }} stanno scrivendo...',
|
|
95
|
+
* });
|
|
96
|
+
*
|
|
97
|
+
* // Make sure to call setLanguage to reflect new language in UI.
|
|
98
|
+
* i18n.setLanguage('it');
|
|
99
|
+
* <Chat client={chatClient} i18nInstance={i18n}>
|
|
100
|
+
* ...
|
|
101
|
+
* </Chat>
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
i18nInstance?: Streami18n;
|
|
105
|
+
/**
|
|
106
|
+
* 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)
|
|
107
|
+
*
|
|
108
|
+
* Please check section about [themes in cookbook](https://github.com/GetStream/stream-chat-react-native/wiki/Cookbook-v3.0#theme) for details.
|
|
109
|
+
*
|
|
110
|
+
* ```
|
|
111
|
+
* import type { DeepPartial, Theme } from 'stream-chat-react-native';
|
|
112
|
+
*
|
|
113
|
+
* const theme: DeepPartial<Theme> = {
|
|
114
|
+
* messageSimple: {
|
|
115
|
+
* file: {
|
|
116
|
+
* container: {
|
|
117
|
+
* backgroundColor: 'red',
|
|
118
|
+
* },
|
|
119
|
+
* icon: {
|
|
120
|
+
* height: 16,
|
|
121
|
+
* width: 16,
|
|
122
|
+
* },
|
|
123
|
+
* },
|
|
124
|
+
* },
|
|
125
|
+
* };
|
|
126
|
+
*
|
|
127
|
+
* <Chat style={theme}>
|
|
128
|
+
* </Chat>
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* @overrideType object
|
|
132
|
+
*/
|
|
133
|
+
style?: DeepPartial<Theme>;
|
|
134
|
+
};
|
|
134
135
|
|
|
135
136
|
const ChatWithContext = <
|
|
136
137
|
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
|
|
@@ -143,6 +144,7 @@ const ChatWithContext = <
|
|
|
143
144
|
closeConnectionOnBackground = true,
|
|
144
145
|
enableOfflineSupport = false,
|
|
145
146
|
i18nInstance,
|
|
147
|
+
ImageComponent = Image,
|
|
146
148
|
style,
|
|
147
149
|
} = props;
|
|
148
150
|
|
|
@@ -206,6 +208,7 @@ const ChatWithContext = <
|
|
|
206
208
|
client,
|
|
207
209
|
connectionRecovering,
|
|
208
210
|
enableOfflineSupport,
|
|
211
|
+
ImageComponent,
|
|
209
212
|
isOnline,
|
|
210
213
|
mutedUsers,
|
|
211
214
|
setActiveChannel,
|
|
@@ -11,6 +11,7 @@ export const useCreateChatContext = <
|
|
|
11
11
|
client,
|
|
12
12
|
connectionRecovering,
|
|
13
13
|
enableOfflineSupport,
|
|
14
|
+
ImageComponent,
|
|
14
15
|
isOnline,
|
|
15
16
|
mutedUsers,
|
|
16
17
|
setActiveChannel,
|
|
@@ -31,6 +32,7 @@ export const useCreateChatContext = <
|
|
|
31
32
|
client,
|
|
32
33
|
connectionRecovering,
|
|
33
34
|
enableOfflineSupport,
|
|
35
|
+
ImageComponent,
|
|
34
36
|
isOnline,
|
|
35
37
|
mutedUsers,
|
|
36
38
|
setActiveChannel,
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Image, ImageBackgroundProps, ImageProps, StyleSheet, View } from 'react-native';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* DISCLAIMER: This component has been pretty-much copied from react-native's source code
|
|
7
|
+
* https://github.com/facebook/react-native/blob/main/Libraries/Image/ImageBackground.js
|
|
8
|
+
* Few modifications have been done such as converting to functional component, removing ref related logic (since its not required).
|
|
9
|
+
* Also support for prop `ImageComponent` has been introduced to allow rendering custom
|
|
10
|
+
* component instead of `Image`.
|
|
11
|
+
*
|
|
12
|
+
*
|
|
13
|
+
* Very simple drop-in replacement for <Image> which supports nesting views.
|
|
14
|
+
*
|
|
15
|
+
* ```ReactNativeWebPlayer
|
|
16
|
+
* import React, { Component } from 'react';
|
|
17
|
+
* import { AppRegistry, View, ImageBackground, Text } from 'react-native';
|
|
18
|
+
*
|
|
19
|
+
* class DisplayAnImageBackground extends Component {
|
|
20
|
+
* render() {
|
|
21
|
+
* return (
|
|
22
|
+
* <ImageBackground
|
|
23
|
+
* style={{width: 50, height: 50}}
|
|
24
|
+
* source={{uri: 'https://reactnative.dev/img/opengraph.png'}}
|
|
25
|
+
* >
|
|
26
|
+
* <Text>React</Text>
|
|
27
|
+
* </ImageBackground>
|
|
28
|
+
* );
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
export const ImageBackground: React.ComponentType<
|
|
35
|
+
ImageBackgroundProps & {
|
|
36
|
+
ImageComponent?: React.ComponentType<ImageProps>;
|
|
37
|
+
}
|
|
38
|
+
> = (props) => {
|
|
39
|
+
const {
|
|
40
|
+
children,
|
|
41
|
+
ImageComponent = Image,
|
|
42
|
+
imageStyle,
|
|
43
|
+
importantForAccessibility,
|
|
44
|
+
style,
|
|
45
|
+
...rest
|
|
46
|
+
} = props;
|
|
47
|
+
|
|
48
|
+
const flattenedStyle = StyleSheet.flatten(style);
|
|
49
|
+
return (
|
|
50
|
+
<View
|
|
51
|
+
accessibilityIgnoresInvertColors={true}
|
|
52
|
+
importantForAccessibility={importantForAccessibility}
|
|
53
|
+
style={style}
|
|
54
|
+
>
|
|
55
|
+
<ImageComponent
|
|
56
|
+
{...rest}
|
|
57
|
+
importantForAccessibility={importantForAccessibility}
|
|
58
|
+
style={[
|
|
59
|
+
StyleSheet.absoluteFill,
|
|
60
|
+
{
|
|
61
|
+
// Temporary Workaround:
|
|
62
|
+
// Current (imperfect yet) implementation of <Image> overwrites width and height styles
|
|
63
|
+
// (which is not quite correct), and these styles conflict with explicitly set styles
|
|
64
|
+
// of <ImageBackground> and with our internal layout model here.
|
|
65
|
+
// So, we have to proxy/reapply these styles explicitly for actual <Image> component.
|
|
66
|
+
// This workaround should be removed after implementing proper support of
|
|
67
|
+
// intrinsic content size of the <Image>.
|
|
68
|
+
height: flattenedStyle?.height,
|
|
69
|
+
width: flattenedStyle?.width,
|
|
70
|
+
},
|
|
71
|
+
imageStyle,
|
|
72
|
+
]}
|
|
73
|
+
/>
|
|
74
|
+
{children}
|
|
75
|
+
</View>
|
|
76
|
+
);
|
|
77
|
+
};
|