stream-chat-react-native-core 4.8.0 → 4.9.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.
- package/lib/commonjs/components/Attachment/GallaryImage.js +41 -0
- package/lib/commonjs/components/Attachment/GallaryImage.js.map +1 -0
- package/lib/commonjs/components/Attachment/Gallery.js +101 -36
- package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
- package/lib/commonjs/components/Attachment/Giphy.js +118 -25
- package/lib/commonjs/components/Attachment/Giphy.js.map +1 -1
- package/lib/commonjs/components/Attachment/ImageLoadingFailedIndicator.js +105 -0
- package/lib/commonjs/components/Attachment/ImageLoadingFailedIndicator.js.map +1 -0
- package/lib/commonjs/components/Attachment/ImageLoadingIndicator.js +58 -0
- package/lib/commonjs/components/Attachment/ImageLoadingIndicator.js.map +1 -0
- package/lib/commonjs/components/Attachment/hooks/useLoadingImage.js +32 -0
- package/lib/commonjs/components/Attachment/hooks/useLoadingImage.js.map +1 -0
- package/lib/commonjs/components/Channel/Channel.js +23 -13
- package/lib/commonjs/components/Channel/Channel.js.map +1 -1
- package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js +4 -0
- package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/hooks/useLatestMessagePreview.js +43 -19
- package/lib/commonjs/components/ChannelPreview/hooks/useLatestMessagePreview.js.map +1 -1
- package/lib/commonjs/components/MessageInput/FileUploadPreview.js +20 -19
- package/lib/commonjs/components/MessageInput/FileUploadPreview.js.map +1 -1
- package/lib/commonjs/components/MessageInput/ImageUploadPreview.js +14 -15
- package/lib/commonjs/components/MessageInput/ImageUploadPreview.js.map +1 -1
- package/lib/commonjs/contexts/messagesContext/MessagesContext.js +2 -2
- package/lib/commonjs/contexts/messagesContext/MessagesContext.js.map +1 -1
- package/lib/commonjs/contexts/themeContext/utils/theme.js +4 -0
- package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
- package/lib/commonjs/mock-builders/api/channelMocks.js +299 -0
- package/lib/commonjs/mock-builders/api/channelMocks.js.map +1 -0
- package/lib/commonjs/version.json +1 -1
- package/lib/module/components/Attachment/GallaryImage.js +41 -0
- package/lib/module/components/Attachment/GallaryImage.js.map +1 -0
- package/lib/module/components/Attachment/Gallery.js +101 -36
- package/lib/module/components/Attachment/Gallery.js.map +1 -1
- package/lib/module/components/Attachment/Giphy.js +118 -25
- package/lib/module/components/Attachment/Giphy.js.map +1 -1
- package/lib/module/components/Attachment/ImageLoadingFailedIndicator.js +105 -0
- package/lib/module/components/Attachment/ImageLoadingFailedIndicator.js.map +1 -0
- package/lib/module/components/Attachment/ImageLoadingIndicator.js +58 -0
- package/lib/module/components/Attachment/ImageLoadingIndicator.js.map +1 -0
- package/lib/module/components/Attachment/hooks/useLoadingImage.js +32 -0
- package/lib/module/components/Attachment/hooks/useLoadingImage.js.map +1 -0
- package/lib/module/components/Channel/Channel.js +23 -13
- package/lib/module/components/Channel/Channel.js.map +1 -1
- package/lib/module/components/Channel/hooks/useCreateMessagesContext.js +4 -0
- package/lib/module/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
- package/lib/module/components/ChannelPreview/hooks/useLatestMessagePreview.js +43 -19
- package/lib/module/components/ChannelPreview/hooks/useLatestMessagePreview.js.map +1 -1
- package/lib/module/components/MessageInput/FileUploadPreview.js +20 -19
- package/lib/module/components/MessageInput/FileUploadPreview.js.map +1 -1
- package/lib/module/components/MessageInput/ImageUploadPreview.js +14 -15
- package/lib/module/components/MessageInput/ImageUploadPreview.js.map +1 -1
- package/lib/module/contexts/messagesContext/MessagesContext.js +2 -2
- package/lib/module/contexts/messagesContext/MessagesContext.js.map +1 -1
- package/lib/module/contexts/themeContext/utils/theme.js +4 -0
- package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
- package/lib/module/mock-builders/api/channelMocks.js +299 -0
- package/lib/module/mock-builders/api/channelMocks.js.map +1 -0
- package/lib/module/version.json +1 -1
- package/lib/typescript/components/Attachment/GallaryImage.d.ts +5 -0
- package/lib/typescript/components/Attachment/Gallery.d.ts +1 -1
- package/lib/typescript/components/Attachment/Giphy.d.ts +1 -1
- package/lib/typescript/components/Attachment/ImageLoadingFailedIndicator.d.ts +3 -0
- package/lib/typescript/components/Attachment/ImageLoadingIndicator.d.ts +3 -0
- package/lib/typescript/components/Attachment/hooks/useLoadingImage.d.ts +7 -0
- package/lib/typescript/components/Channel/Channel.d.ts +1 -1
- package/lib/typescript/components/Channel/hooks/useCreateMessagesContext.d.ts +1 -1
- package/lib/typescript/components/ChannelPreview/hooks/__tests__/useLatestMessagePreview.test.d.ts +1 -0
- package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts +10 -0
- package/lib/typescript/contexts/themeContext/utils/theme.d.ts +4 -0
- package/lib/typescript/mock-builders/api/channelMocks.d.ts +14 -0
- package/package.json +1 -1
- package/src/components/Attachment/GallaryImage.tsx +22 -0
- package/src/components/Attachment/Gallery.tsx +68 -35
- package/src/components/Attachment/Giphy.tsx +68 -1
- package/src/components/Attachment/ImageLoadingFailedIndicator.tsx +56 -0
- package/src/components/Attachment/ImageLoadingIndicator.tsx +31 -0
- package/src/components/Attachment/__tests__/Attachment.test.js +9 -3
- package/src/components/Attachment/__tests__/Gallery.test.js +36 -1
- package/src/components/Attachment/__tests__/Giphy.test.js +110 -90
- package/src/components/Attachment/hooks/useLoadingImage.tsx +8 -0
- package/src/components/Channel/Channel.tsx +8 -0
- package/src/components/Channel/hooks/useCreateMessagesContext.ts +4 -0
- package/src/components/ChannelPreview/__tests__/ChannelPreviewMessenger.test.js +0 -1
- package/src/components/ChannelPreview/hooks/__tests__/useLatestMessagePreview.test.tsx +145 -0
- package/src/components/ChannelPreview/hooks/useLatestMessagePreview.ts +50 -24
- package/src/components/MessageInput/FileUploadPreview.tsx +5 -4
- package/src/components/MessageInput/ImageUploadPreview.tsx +2 -3
- package/src/contexts/messagesContext/MessagesContext.tsx +15 -0
- package/src/contexts/themeContext/utils/theme.ts +8 -0
- package/src/mock-builders/api/channelMocks.tsx +272 -0
- package/src/version.json +1 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
|
3
3
|
|
|
4
|
+
import { GalleryImage } from './GallaryImage';
|
|
5
|
+
import { useLoadingImage } from './hooks/useLoadingImage';
|
|
4
6
|
import { buildGallery } from './utils/buildGallery/buildGallery';
|
|
5
7
|
|
|
6
8
|
import { getGalleryImageBorderRadius } from './utils/getGalleryImageBorderRadius';
|
|
@@ -27,25 +29,7 @@ import {
|
|
|
27
29
|
import { useTheme } from '../../contexts/themeContext/ThemeContext';
|
|
28
30
|
import { isVideoPackageAvailable } from '../../native';
|
|
29
31
|
import type { DefaultStreamChatGenerics } from '../../types/types';
|
|
30
|
-
import { getUrlWithoutParams
|
|
31
|
-
|
|
32
|
-
const GalleryImage: React.FC<
|
|
33
|
-
Omit<ImageProps, 'height' | 'source'> & {
|
|
34
|
-
uri: string;
|
|
35
|
-
}
|
|
36
|
-
> = (props) => {
|
|
37
|
-
const { uri, ...rest } = props;
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<Image
|
|
41
|
-
{...rest}
|
|
42
|
-
source={{
|
|
43
|
-
uri: makeImageCompatibleUrl(uri),
|
|
44
|
-
}}
|
|
45
|
-
testID='image-attachment-single'
|
|
46
|
-
/>
|
|
47
|
-
);
|
|
48
|
-
};
|
|
32
|
+
import { getUrlWithoutParams } from '../../utils/utils';
|
|
49
33
|
|
|
50
34
|
const MemoizedGalleryImage = React.memo(
|
|
51
35
|
GalleryImage,
|
|
@@ -54,7 +38,7 @@ const MemoizedGalleryImage = React.memo(
|
|
|
54
38
|
) as typeof GalleryImage;
|
|
55
39
|
|
|
56
40
|
const styles = StyleSheet.create({
|
|
57
|
-
|
|
41
|
+
errorTextSize: { fontSize: 10 },
|
|
58
42
|
galleryContainer: {
|
|
59
43
|
borderTopLeftRadius: 13,
|
|
60
44
|
borderTopRightRadius: 13,
|
|
@@ -62,7 +46,19 @@ const styles = StyleSheet.create({
|
|
|
62
46
|
flexWrap: 'wrap',
|
|
63
47
|
overflow: 'hidden',
|
|
64
48
|
},
|
|
65
|
-
imageContainer: {
|
|
49
|
+
imageContainer: {
|
|
50
|
+
alignItems: 'center',
|
|
51
|
+
display: 'flex',
|
|
52
|
+
flexDirection: 'row',
|
|
53
|
+
justifyContent: 'center',
|
|
54
|
+
padding: 1,
|
|
55
|
+
},
|
|
56
|
+
imageContainerStyle: { alignItems: 'center', flex: 1, justifyContent: 'center' },
|
|
57
|
+
imageLoadingIndicatorStyle: {
|
|
58
|
+
alignItems: 'center',
|
|
59
|
+
justifyContent: 'center',
|
|
60
|
+
position: 'absolute',
|
|
61
|
+
},
|
|
66
62
|
moreImagesContainer: {
|
|
67
63
|
alignItems: 'center',
|
|
68
64
|
justifyContent: 'center',
|
|
@@ -88,7 +84,11 @@ export type GalleryPropsWithContext<
|
|
|
88
84
|
> &
|
|
89
85
|
Pick<
|
|
90
86
|
MessagesContextValue<StreamChatGenerics>,
|
|
91
|
-
|
|
87
|
+
| 'additionalTouchableProps'
|
|
88
|
+
| 'legacyImageViewerSwipeBehaviour'
|
|
89
|
+
| 'VideoThumbnail'
|
|
90
|
+
| 'ImageLoadingIndicator'
|
|
91
|
+
| 'ImageLoadingFailedIndicator'
|
|
92
92
|
> &
|
|
93
93
|
Pick<OverlayContextValue, 'setOverlay'> & {
|
|
94
94
|
channelId: string | undefined;
|
|
@@ -118,6 +118,8 @@ const GalleryWithContext = <
|
|
|
118
118
|
alignment,
|
|
119
119
|
groupStyles,
|
|
120
120
|
hasThreadReplies,
|
|
121
|
+
ImageLoadingFailedIndicator,
|
|
122
|
+
ImageLoadingIndicator,
|
|
121
123
|
images,
|
|
122
124
|
legacyImageViewerSwipeBehaviour,
|
|
123
125
|
message,
|
|
@@ -133,6 +135,9 @@ const GalleryWithContext = <
|
|
|
133
135
|
VideoThumbnail,
|
|
134
136
|
} = props;
|
|
135
137
|
|
|
138
|
+
const { isLoadingImage, isLoadingImageError, setLoadingImage, setLoadingImageError } =
|
|
139
|
+
useLoadingImage();
|
|
140
|
+
|
|
136
141
|
const {
|
|
137
142
|
theme: {
|
|
138
143
|
colors: { overlay },
|
|
@@ -304,18 +309,37 @@ const GalleryWithContext = <
|
|
|
304
309
|
]}
|
|
305
310
|
/>
|
|
306
311
|
) : (
|
|
307
|
-
<
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
312
|
+
<View style={styles.imageContainerStyle}>
|
|
313
|
+
<MemoizedGalleryImage
|
|
314
|
+
onError={(error) => {
|
|
315
|
+
console.warn(error);
|
|
316
|
+
setLoadingImage(false);
|
|
317
|
+
setLoadingImageError(true);
|
|
318
|
+
}}
|
|
319
|
+
onLoadEnd={() => setLoadingImage(false)}
|
|
320
|
+
onLoadStart={() => setLoadingImage(true)}
|
|
321
|
+
resizeMode={resizeMode}
|
|
322
|
+
style={[
|
|
323
|
+
borderRadius,
|
|
324
|
+
image,
|
|
325
|
+
{
|
|
326
|
+
height: height - 1,
|
|
327
|
+
width: width - 1,
|
|
328
|
+
},
|
|
329
|
+
]}
|
|
330
|
+
uri={url}
|
|
331
|
+
/>
|
|
332
|
+
{isLoadingImage && (
|
|
333
|
+
<View style={{ position: 'absolute' }}>
|
|
334
|
+
<ImageLoadingIndicator style={styles.imageLoadingIndicatorStyle} />
|
|
335
|
+
</View>
|
|
336
|
+
)}
|
|
337
|
+
{isLoadingImageError && (
|
|
338
|
+
<View style={{ position: 'absolute' }}>
|
|
339
|
+
<ImageLoadingFailedIndicator style={styles.imageLoadingIndicatorStyle} />
|
|
340
|
+
</View>
|
|
341
|
+
)}
|
|
342
|
+
</View>
|
|
319
343
|
)}
|
|
320
344
|
{colIndex === numOfColumns - 1 &&
|
|
321
345
|
rowIndex === numOfRows - 1 &&
|
|
@@ -412,6 +436,8 @@ export const Gallery = <
|
|
|
412
436
|
alignment: propAlignment,
|
|
413
437
|
groupStyles: propGroupStyles,
|
|
414
438
|
hasThreadReplies,
|
|
439
|
+
ImageLoadingFailedIndicator: PropImageLoadingFailedIndicator,
|
|
440
|
+
ImageLoadingIndicator: PropImageLoadingIndicator,
|
|
415
441
|
images: propImages,
|
|
416
442
|
onLongPress: propOnLongPress,
|
|
417
443
|
onPress: propOnPress,
|
|
@@ -439,6 +465,8 @@ export const Gallery = <
|
|
|
439
465
|
} = useMessageContext<StreamChatGenerics>();
|
|
440
466
|
const {
|
|
441
467
|
additionalTouchableProps: contextAdditionalTouchableProps,
|
|
468
|
+
ImageLoadingFailedIndicator: ContextImageLoadingFailedIndicator,
|
|
469
|
+
ImageLoadingIndicator: ContextImageLoadingIndicator,
|
|
442
470
|
legacyImageViewerSwipeBehaviour,
|
|
443
471
|
VideoThumbnail: ContextVideoThumnbnail,
|
|
444
472
|
} = useMessagesContext<StreamChatGenerics>();
|
|
@@ -461,6 +489,9 @@ export const Gallery = <
|
|
|
461
489
|
const setOverlay = propSetOverlay || contextSetOverlay;
|
|
462
490
|
const threadList = propThreadList || contextThreadList;
|
|
463
491
|
const VideoThumbnail = PropVideoThumbnail || ContextVideoThumnbnail;
|
|
492
|
+
const ImageLoadingFailedIndicator =
|
|
493
|
+
PropImageLoadingFailedIndicator || ContextImageLoadingFailedIndicator;
|
|
494
|
+
const ImageLoadingIndicator = PropImageLoadingIndicator || ContextImageLoadingIndicator;
|
|
464
495
|
|
|
465
496
|
return (
|
|
466
497
|
<MemoizedGallery
|
|
@@ -470,6 +501,8 @@ export const Gallery = <
|
|
|
470
501
|
channelId: message?.cid,
|
|
471
502
|
groupStyles,
|
|
472
503
|
hasThreadReplies: hasThreadReplies || !!message?.reply_count,
|
|
504
|
+
ImageLoadingFailedIndicator,
|
|
505
|
+
ImageLoadingIndicator,
|
|
473
506
|
images,
|
|
474
507
|
legacyImageViewerSwipeBehaviour,
|
|
475
508
|
message,
|
|
@@ -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 { useLoadingImage } from './hooks/useLoadingImage';
|
|
7
|
+
|
|
6
8
|
import {
|
|
7
9
|
ImageGalleryContextValue,
|
|
8
10
|
useImageGalleryContext,
|
|
@@ -40,6 +42,11 @@ const styles = StyleSheet.create({
|
|
|
40
42
|
fontWeight: '600',
|
|
41
43
|
paddingVertical: 16,
|
|
42
44
|
},
|
|
45
|
+
centerChild: {
|
|
46
|
+
alignItems: 'center',
|
|
47
|
+
display: 'flex',
|
|
48
|
+
justifyContent: 'center',
|
|
49
|
+
},
|
|
43
50
|
container: {
|
|
44
51
|
overflow: 'hidden',
|
|
45
52
|
width: 270,
|
|
@@ -84,6 +91,17 @@ const styles = StyleSheet.create({
|
|
|
84
91
|
padding: 8,
|
|
85
92
|
width: '60%',
|
|
86
93
|
},
|
|
94
|
+
imageErrorIndicatorStyle: {
|
|
95
|
+
alignItems: 'center',
|
|
96
|
+
flex: 1,
|
|
97
|
+
justifyContent: 'center',
|
|
98
|
+
},
|
|
99
|
+
imageLoadingIndicatorStyle: {
|
|
100
|
+
alignItems: 'center',
|
|
101
|
+
flex: 1,
|
|
102
|
+
justifyContent: 'center',
|
|
103
|
+
position: 'absolute',
|
|
104
|
+
},
|
|
87
105
|
selectionContainer: {
|
|
88
106
|
borderBottomRightRadius: 0,
|
|
89
107
|
borderRadius: 16,
|
|
@@ -128,7 +146,13 @@ export type GiphyPropsWithContext<
|
|
|
128
146
|
| 'onPressIn'
|
|
129
147
|
| 'preventPress'
|
|
130
148
|
> &
|
|
131
|
-
Pick<
|
|
149
|
+
Pick<
|
|
150
|
+
MessagesContextValue<StreamChatGenerics>,
|
|
151
|
+
| 'giphyVersion'
|
|
152
|
+
| 'additionalTouchableProps'
|
|
153
|
+
| 'ImageLoadingIndicator'
|
|
154
|
+
| 'ImageLoadingFailedIndicator'
|
|
155
|
+
> & {
|
|
132
156
|
attachment: Attachment<StreamChatGenerics>;
|
|
133
157
|
} & Pick<OverlayContextValue, 'setOverlay'>;
|
|
134
158
|
|
|
@@ -142,6 +166,8 @@ const GiphyWithContext = <
|
|
|
142
166
|
attachment,
|
|
143
167
|
giphyVersion,
|
|
144
168
|
handleAction,
|
|
169
|
+
ImageLoadingFailedIndicator,
|
|
170
|
+
ImageLoadingIndicator,
|
|
145
171
|
isMyMessage,
|
|
146
172
|
message,
|
|
147
173
|
onLongPress,
|
|
@@ -155,6 +181,9 @@ const GiphyWithContext = <
|
|
|
155
181
|
|
|
156
182
|
const { actions, giphy: giphyData, image_url, thumb_url, title, type } = attachment;
|
|
157
183
|
|
|
184
|
+
const { isLoadingImage, isLoadingImageError, setLoadingImage, setLoadingImageError } =
|
|
185
|
+
useLoadingImage();
|
|
186
|
+
|
|
158
187
|
const {
|
|
159
188
|
theme: {
|
|
160
189
|
colors: { accent_blue, black, grey, grey_dark, grey_gainsboro, label_bg_transparent, white },
|
|
@@ -214,6 +243,13 @@ const GiphyWithContext = <
|
|
|
214
243
|
</View>
|
|
215
244
|
<View style={styles.selectionImageContainer}>
|
|
216
245
|
<Image
|
|
246
|
+
onError={(error) => {
|
|
247
|
+
console.warn(error);
|
|
248
|
+
setLoadingImage(false);
|
|
249
|
+
setLoadingImageError(true);
|
|
250
|
+
}}
|
|
251
|
+
onLoadEnd={() => setLoadingImage(false)}
|
|
252
|
+
onLoadStart={() => setLoadingImage(true)}
|
|
217
253
|
resizeMode='contain'
|
|
218
254
|
source={{ uri: makeImageCompatibleUrl(uri) }}
|
|
219
255
|
style={[styles.giphy, giphyDimensions, giphy]}
|
|
@@ -299,16 +335,36 @@ const GiphyWithContext = <
|
|
|
299
335
|
<View
|
|
300
336
|
style={[
|
|
301
337
|
styles.container,
|
|
338
|
+
styles.centerChild,
|
|
302
339
|
{ backgroundColor: isMyMessage ? grey_gainsboro : white },
|
|
303
340
|
container,
|
|
304
341
|
]}
|
|
305
342
|
>
|
|
306
343
|
<Image
|
|
344
|
+
accessibilityLabel='giphy-attachment-image'
|
|
345
|
+
onError={(error) => {
|
|
346
|
+
console.warn(error);
|
|
347
|
+
setLoadingImage(false);
|
|
348
|
+
setLoadingImageError(true);
|
|
349
|
+
}}
|
|
350
|
+
onLoadEnd={() => setLoadingImage(false)}
|
|
351
|
+
onLoadStart={() => setLoadingImage(true)}
|
|
307
352
|
resizeMode='contain'
|
|
308
353
|
source={{ uri: makeImageCompatibleUrl(uri) }}
|
|
309
354
|
style={[styles.giphy, giphyDimensions, giphy]}
|
|
310
355
|
testID='giphy-attachment-image'
|
|
311
356
|
/>
|
|
357
|
+
|
|
358
|
+
{isLoadingImageError && (
|
|
359
|
+
<View style={{ position: 'absolute' }}>
|
|
360
|
+
<ImageLoadingFailedIndicator style={styles.imageErrorIndicatorStyle} />
|
|
361
|
+
</View>
|
|
362
|
+
)}
|
|
363
|
+
{isLoadingImage && (
|
|
364
|
+
<View style={{ position: 'absolute' }}>
|
|
365
|
+
<ImageLoadingIndicator style={styles.imageLoadingIndicatorStyle} />
|
|
366
|
+
</View>
|
|
367
|
+
)}
|
|
312
368
|
<View style={[styles.giphyMask, giphyMask]}>
|
|
313
369
|
<View
|
|
314
370
|
style={[
|
|
@@ -387,12 +443,23 @@ export const Giphy = <
|
|
|
387
443
|
const { additionalTouchableProps, giphyVersion } = useMessagesContext<StreamChatGenerics>();
|
|
388
444
|
const { setImage, setImages } = useImageGalleryContext<StreamChatGenerics>();
|
|
389
445
|
const { setOverlay } = useOverlayContext();
|
|
446
|
+
|
|
447
|
+
const {
|
|
448
|
+
ImageLoadingFailedIndicator: ContextImageLoadingFailedIndicator,
|
|
449
|
+
ImageLoadingIndicator: ContextImageLoadingIndicator,
|
|
450
|
+
} = useMessagesContext<StreamChatGenerics>();
|
|
451
|
+
const ImageLoadingFailedIndicator =
|
|
452
|
+
ContextImageLoadingFailedIndicator || props.ImageLoadingFailedIndicator;
|
|
453
|
+
const ImageLoadingIndicator = ContextImageLoadingIndicator || props.ImageLoadingIndicator;
|
|
454
|
+
|
|
390
455
|
return (
|
|
391
456
|
<MemoizedGiphy
|
|
392
457
|
{...{
|
|
393
458
|
additionalTouchableProps,
|
|
394
459
|
giphyVersion,
|
|
395
460
|
handleAction,
|
|
461
|
+
ImageLoadingFailedIndicator,
|
|
462
|
+
ImageLoadingIndicator,
|
|
396
463
|
isMyMessage,
|
|
397
464
|
message,
|
|
398
465
|
onLongPress,
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StyleSheet, Text, View, ViewProps } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { useTheme } from '../../contexts/themeContext/ThemeContext';
|
|
5
|
+
import { useTranslationContext } from '../../contexts/translationContext/TranslationContext';
|
|
6
|
+
|
|
7
|
+
import { Warning } from '../../icons';
|
|
8
|
+
|
|
9
|
+
const WARNING_ICON_SIZE = 14;
|
|
10
|
+
|
|
11
|
+
const styles = StyleSheet.create({
|
|
12
|
+
container: {
|
|
13
|
+
alignContent: 'center',
|
|
14
|
+
alignItems: 'center',
|
|
15
|
+
borderRadius: 20,
|
|
16
|
+
flexDirection: 'row',
|
|
17
|
+
justifyContent: 'center',
|
|
18
|
+
},
|
|
19
|
+
errorText: {
|
|
20
|
+
fontSize: 8,
|
|
21
|
+
justifyContent: 'center',
|
|
22
|
+
paddingHorizontal: 8,
|
|
23
|
+
},
|
|
24
|
+
warningIconStyle: {
|
|
25
|
+
borderRadius: 24,
|
|
26
|
+
marginLeft: 4,
|
|
27
|
+
marginTop: 6,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export type ImageLoadingFailedIndicatorProps = ViewProps;
|
|
32
|
+
|
|
33
|
+
export const ImageLoadingFailedIndicator = (props: ImageLoadingFailedIndicatorProps) => {
|
|
34
|
+
const {
|
|
35
|
+
theme: {
|
|
36
|
+
colors: { accent_red, overlay, white },
|
|
37
|
+
},
|
|
38
|
+
} = useTheme();
|
|
39
|
+
|
|
40
|
+
const { t } = useTranslationContext();
|
|
41
|
+
|
|
42
|
+
const { style, ...rest } = props;
|
|
43
|
+
return (
|
|
44
|
+
<View {...rest} accessibilityHint='image-loading-error' style={[style]}>
|
|
45
|
+
<View style={[styles.container, { backgroundColor: overlay }]}>
|
|
46
|
+
<Warning
|
|
47
|
+
height={WARNING_ICON_SIZE}
|
|
48
|
+
pathFill={accent_red}
|
|
49
|
+
style={styles.warningIconStyle}
|
|
50
|
+
width={WARNING_ICON_SIZE}
|
|
51
|
+
/>
|
|
52
|
+
<Text style={[styles.errorText, { color: white }]}>{t('Error loading')}</Text>
|
|
53
|
+
</View>
|
|
54
|
+
</View>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ActivityIndicator, StyleSheet, View, ViewProps } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { useTheme } from '../../contexts/themeContext/ThemeContext';
|
|
5
|
+
|
|
6
|
+
const styles = StyleSheet.create({
|
|
7
|
+
container: {
|
|
8
|
+
alignItems: 'center',
|
|
9
|
+
display: 'flex',
|
|
10
|
+
justifyContent: 'center',
|
|
11
|
+
width: '100%',
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export type ImageLoadingIndicatorProps = ViewProps;
|
|
16
|
+
|
|
17
|
+
export const ImageLoadingIndicator = (props: ImageLoadingIndicatorProps) => {
|
|
18
|
+
const {
|
|
19
|
+
theme: {
|
|
20
|
+
messageSimple: {
|
|
21
|
+
loadingIndicator: { container },
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
} = useTheme();
|
|
25
|
+
const { style, ...rest } = props;
|
|
26
|
+
return (
|
|
27
|
+
<View {...rest} accessibilityHint='image-loading' style={[styles.container, container, style]}>
|
|
28
|
+
<ActivityIndicator />
|
|
29
|
+
</View>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
@@ -4,6 +4,7 @@ import { fireEvent, render, waitFor } from '@testing-library/react-native';
|
|
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
5
5
|
|
|
6
6
|
import { MessageProvider } from '../../../contexts/messageContext/MessageContext';
|
|
7
|
+
import { MessagesProvider } from '../../../contexts/messagesContext/MessagesContext';
|
|
7
8
|
import { ThemeProvider } from '../../../contexts/themeContext/ThemeContext';
|
|
8
9
|
import {
|
|
9
10
|
generateAttachmentAction,
|
|
@@ -12,6 +13,9 @@ import {
|
|
|
12
13
|
generateImageAttachment,
|
|
13
14
|
} from '../../../mock-builders/generator/attachment';
|
|
14
15
|
import { generateMessage } from '../../../mock-builders/generator/message';
|
|
16
|
+
|
|
17
|
+
import { ImageLoadingFailedIndicator } from '../../Attachment/ImageLoadingFailedIndicator';
|
|
18
|
+
import { ImageLoadingIndicator } from '../../Attachment/ImageLoadingIndicator';
|
|
15
19
|
import { Attachment } from '../Attachment';
|
|
16
20
|
import { AttachmentActions } from '../AttachmentActions';
|
|
17
21
|
|
|
@@ -19,9 +23,11 @@ const getAttachmentComponent = (props) => {
|
|
|
19
23
|
const message = generateMessage();
|
|
20
24
|
return (
|
|
21
25
|
<ThemeProvider>
|
|
22
|
-
<
|
|
23
|
-
<
|
|
24
|
-
|
|
26
|
+
<MessagesProvider value={{ ImageLoadingFailedIndicator, ImageLoadingIndicator }}>
|
|
27
|
+
<MessageProvider value={{ message }}>
|
|
28
|
+
<Attachment {...props} />
|
|
29
|
+
</MessageProvider>
|
|
30
|
+
</MessagesProvider>
|
|
25
31
|
</ThemeProvider>
|
|
26
32
|
);
|
|
27
33
|
};
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
fireEvent,
|
|
5
|
+
render,
|
|
6
|
+
waitFor,
|
|
7
|
+
waitForElementToBeRemoved,
|
|
8
|
+
} from '@testing-library/react-native';
|
|
4
9
|
|
|
5
10
|
import { OverlayProvider } from '../../../contexts/overlayContext/OverlayProvider';
|
|
6
11
|
|
|
@@ -230,4 +235,34 @@ describe('Gallery', () => {
|
|
|
230
235
|
expect(queryAllByTestId('gallery-column-1-item-1').length).toBe(1);
|
|
231
236
|
});
|
|
232
237
|
});
|
|
238
|
+
|
|
239
|
+
it('should render an error indicator', async () => {
|
|
240
|
+
const image1 = generateImageAttachment({
|
|
241
|
+
original_height: 300,
|
|
242
|
+
original_width: 600,
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
const component = await getComponent([image1]);
|
|
246
|
+
const { getByA11yLabel, getByAccessibilityHint } = render(component);
|
|
247
|
+
|
|
248
|
+
fireEvent(getByA11yLabel('gallery-image'), 'error');
|
|
249
|
+
expect(getByAccessibilityHint('image-loading-error')).toBeTruthy();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('should render a loading indicator and when successful render the image', async () => {
|
|
253
|
+
const image1 = generateImageAttachment({
|
|
254
|
+
original_height: 300,
|
|
255
|
+
original_width: 600,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
const component = await getComponent([image1]);
|
|
259
|
+
const { getByA11yLabel, getByAccessibilityHint } = render(component);
|
|
260
|
+
|
|
261
|
+
fireEvent(getByA11yLabel('gallery-image'), 'onLoadStart');
|
|
262
|
+
expect(getByAccessibilityHint('image-loading')).toBeTruthy();
|
|
263
|
+
|
|
264
|
+
fireEvent(getByA11yLabel('gallery-image'), 'onLoadFinish');
|
|
265
|
+
waitForElementToBeRemoved(() => getByAccessibilityHint('image-loading'));
|
|
266
|
+
expect(getByA11yLabel('gallery-image')).toBeTruthy();
|
|
267
|
+
});
|
|
233
268
|
});
|