stream-chat-react-native-core 4.6.1 → 4.7.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/Attachment.js +22 -13
- package/lib/commonjs/components/Attachment/Attachment.js.map +1 -1
- package/lib/commonjs/components/Attachment/Card.js +23 -14
- package/lib/commonjs/components/Attachment/Card.js.map +1 -1
- package/lib/commonjs/components/Attachment/Gallery.js +72 -37
- package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
- package/lib/commonjs/components/Attachment/VideoThumbnail.js +83 -0
- package/lib/commonjs/components/Attachment/VideoThumbnail.js.map +1 -0
- package/lib/commonjs/components/Attachment/hooks/useGoToURL.js +1 -1
- package/lib/commonjs/components/Attachment/hooks/useGoToURL.js.map +1 -1
- package/lib/commonjs/components/Attachment/utils/buildGallery/buildThumbnail.js +1 -0
- package/lib/commonjs/components/Attachment/utils/buildGallery/buildThumbnail.js.map +1 -1
- package/lib/commonjs/components/Attachment/utils/getAspectRatio.js +5 -5
- package/lib/commonjs/components/Attachment/utils/getAspectRatio.js.map +1 -1
- package/lib/commonjs/components/Channel/Channel.js +19 -14
- package/lib/commonjs/components/Channel/Channel.js.map +1 -1
- package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js +4 -2
- package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
- package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js +43 -28
- package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js.map +1 -1
- package/lib/commonjs/components/Chat/hooks/useIsOnline.js +6 -6
- package/lib/commonjs/components/Chat/hooks/useIsOnline.js.map +1 -1
- package/lib/commonjs/components/ImageGallery/ImageGallery.js +167 -345
- package/lib/commonjs/components/ImageGallery/ImageGallery.js.map +1 -1
- package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryImage.js +4 -4
- package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryImage.js.map +1 -1
- package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryVideo.js +225 -0
- package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryVideo.js.map +1 -0
- package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js +102 -40
- package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
- package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js +145 -0
- package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -0
- package/lib/commonjs/components/ImageGallery/components/ImageGrid.js +31 -34
- package/lib/commonjs/components/ImageGallery/components/ImageGrid.js.map +1 -1
- package/lib/commonjs/components/ImageGallery/components/ProgressControl.js +153 -0
- package/lib/commonjs/components/ImageGallery/components/ProgressControl.js.map +1 -0
- package/lib/commonjs/components/ImageGallery/hooks/useImageGalleryGestures.js +373 -0
- package/lib/commonjs/components/ImageGallery/hooks/useImageGalleryGestures.js.map +1 -0
- package/lib/commonjs/components/Message/Message.js +23 -13
- package/lib/commonjs/components/Message/Message.js.map +1 -1
- package/lib/commonjs/components/Message/MessageSimple/utils/renderText.js +22 -15
- package/lib/commonjs/components/Message/MessageSimple/utils/renderText.js.map +1 -1
- package/lib/commonjs/components/Message/hooks/useCreateMessageContext.js +4 -2
- package/lib/commonjs/components/Message/hooks/useCreateMessageContext.js.map +1 -1
- package/lib/commonjs/components/MessageOverlay/MessageOverlay.js +25 -23
- package/lib/commonjs/components/MessageOverlay/MessageOverlay.js.map +1 -1
- package/lib/commonjs/components/Reply/Reply.js +32 -12
- package/lib/commonjs/components/Reply/Reply.js.map +1 -1
- package/lib/commonjs/components/Spinner/Spinner.js +12 -4
- package/lib/commonjs/components/Spinner/Spinner.js.map +1 -1
- package/lib/commonjs/components/index.js +26 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/contexts/messageContext/MessageContext.js +2 -2
- package/lib/commonjs/contexts/messageContext/MessageContext.js.map +1 -1
- package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +15 -4
- package/lib/commonjs/contexts/messageInputContext/MessageInputContext.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/contexts/messagesContext/MessagesContext.js +2 -2
- package/lib/commonjs/contexts/messagesContext/MessagesContext.js.map +1 -1
- package/lib/commonjs/contexts/themeContext/utils/theme.js +10 -1
- package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
- package/lib/commonjs/icons/Pause.js +61 -0
- package/lib/commonjs/icons/Pause.js.map +1 -0
- package/lib/commonjs/icons/Play.js +42 -0
- package/lib/commonjs/icons/Play.js.map +1 -0
- package/lib/commonjs/icons/index.js +26 -0
- package/lib/commonjs/icons/index.js.map +1 -1
- package/lib/commonjs/mock-builders/api/queryMembers.js +98 -1
- package/lib/commonjs/mock-builders/api/queryMembers.js.map +1 -1
- package/lib/commonjs/native.js +7 -1
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/utils/getUrlOfImageAttachment.js +1 -1
- package/lib/commonjs/utils/getUrlOfImageAttachment.js.map +1 -1
- package/lib/commonjs/version.json +1 -1
- package/lib/module/components/Attachment/Attachment.js +22 -13
- package/lib/module/components/Attachment/Attachment.js.map +1 -1
- package/lib/module/components/Attachment/Card.js +23 -14
- package/lib/module/components/Attachment/Card.js.map +1 -1
- package/lib/module/components/Attachment/Gallery.js +72 -37
- package/lib/module/components/Attachment/Gallery.js.map +1 -1
- package/lib/module/components/Attachment/VideoThumbnail.js +83 -0
- package/lib/module/components/Attachment/VideoThumbnail.js.map +1 -0
- package/lib/module/components/Attachment/hooks/useGoToURL.js +1 -1
- package/lib/module/components/Attachment/hooks/useGoToURL.js.map +1 -1
- package/lib/module/components/Attachment/utils/buildGallery/buildThumbnail.js +1 -0
- package/lib/module/components/Attachment/utils/buildGallery/buildThumbnail.js.map +1 -1
- package/lib/module/components/Attachment/utils/getAspectRatio.js +5 -5
- package/lib/module/components/Attachment/utils/getAspectRatio.js.map +1 -1
- package/lib/module/components/Channel/Channel.js +19 -14
- package/lib/module/components/Channel/Channel.js.map +1 -1
- package/lib/module/components/Channel/hooks/useCreateMessagesContext.js +4 -2
- package/lib/module/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
- package/lib/module/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js +43 -28
- package/lib/module/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js.map +1 -1
- package/lib/module/components/Chat/hooks/useIsOnline.js +6 -6
- package/lib/module/components/Chat/hooks/useIsOnline.js.map +1 -1
- package/lib/module/components/ImageGallery/ImageGallery.js +167 -345
- package/lib/module/components/ImageGallery/ImageGallery.js.map +1 -1
- package/lib/module/components/ImageGallery/components/AnimatedGalleryImage.js +4 -4
- package/lib/module/components/ImageGallery/components/AnimatedGalleryImage.js.map +1 -1
- package/lib/module/components/ImageGallery/components/AnimatedGalleryVideo.js +225 -0
- package/lib/module/components/ImageGallery/components/AnimatedGalleryVideo.js.map +1 -0
- package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js +102 -40
- package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
- package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js +145 -0
- package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -0
- package/lib/module/components/ImageGallery/components/ImageGrid.js +31 -34
- package/lib/module/components/ImageGallery/components/ImageGrid.js.map +1 -1
- package/lib/module/components/ImageGallery/components/ProgressControl.js +153 -0
- package/lib/module/components/ImageGallery/components/ProgressControl.js.map +1 -0
- package/lib/module/components/ImageGallery/hooks/useImageGalleryGestures.js +373 -0
- package/lib/module/components/ImageGallery/hooks/useImageGalleryGestures.js.map +1 -0
- package/lib/module/components/Message/Message.js +23 -13
- package/lib/module/components/Message/Message.js.map +1 -1
- package/lib/module/components/Message/MessageSimple/utils/renderText.js +22 -15
- package/lib/module/components/Message/MessageSimple/utils/renderText.js.map +1 -1
- package/lib/module/components/Message/hooks/useCreateMessageContext.js +4 -2
- package/lib/module/components/Message/hooks/useCreateMessageContext.js.map +1 -1
- package/lib/module/components/MessageOverlay/MessageOverlay.js +25 -23
- package/lib/module/components/MessageOverlay/MessageOverlay.js.map +1 -1
- package/lib/module/components/Reply/Reply.js +32 -12
- package/lib/module/components/Reply/Reply.js.map +1 -1
- package/lib/module/components/Spinner/Spinner.js +12 -4
- package/lib/module/components/Spinner/Spinner.js.map +1 -1
- package/lib/module/components/index.js +26 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/contexts/messageContext/MessageContext.js +2 -2
- package/lib/module/contexts/messageContext/MessageContext.js.map +1 -1
- package/lib/module/contexts/messageInputContext/MessageInputContext.js +15 -4
- package/lib/module/contexts/messageInputContext/MessageInputContext.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/contexts/messagesContext/MessagesContext.js +2 -2
- package/lib/module/contexts/messagesContext/MessagesContext.js.map +1 -1
- package/lib/module/contexts/themeContext/utils/theme.js +10 -1
- package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
- package/lib/module/icons/Pause.js +61 -0
- package/lib/module/icons/Pause.js.map +1 -0
- package/lib/module/icons/Play.js +42 -0
- package/lib/module/icons/Play.js.map +1 -0
- package/lib/module/icons/index.js +26 -0
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/mock-builders/api/queryMembers.js +98 -1
- package/lib/module/mock-builders/api/queryMembers.js.map +1 -1
- package/lib/module/native.js +7 -1
- package/lib/module/native.js.map +1 -1
- package/lib/module/utils/getUrlOfImageAttachment.js +1 -1
- package/lib/module/utils/getUrlOfImageAttachment.js.map +1 -1
- package/lib/module/version.json +1 -1
- package/lib/typescript/components/Attachment/Gallery.d.ts +1 -1
- package/lib/typescript/components/Attachment/VideoThumbnail.d.ts +4 -0
- package/lib/typescript/components/Attachment/utils/buildGallery/types.d.ts +1 -0
- package/lib/typescript/components/Attachment/utils/getAspectRatio.d.ts +1 -1
- 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__/useChannelPreviewDisplayName.test.d.ts +1 -0
- package/lib/typescript/components/ChannelPreview/hooks/useChannelPreviewDisplayName.d.ts +4 -4
- package/lib/typescript/components/Chat/hooks/useIsOnline.d.ts +1 -1
- package/lib/typescript/components/ImageGallery/ImageGallery.d.ts +2 -0
- package/lib/typescript/components/ImageGallery/components/AnimatedGalleryVideo.d.ts +27 -0
- package/lib/typescript/components/ImageGallery/components/ImageGalleryFooter.d.ts +18 -2
- package/lib/typescript/components/ImageGallery/components/ImageGalleryVideoControl.d.ts +3 -0
- package/lib/typescript/components/ImageGallery/components/ProgressControl.d.ts +5 -0
- package/lib/typescript/components/ImageGallery/hooks/useImageGalleryGestures.d.ts +36 -0
- package/lib/typescript/components/Message/Message.d.ts +9 -3
- package/lib/typescript/components/Message/hooks/useCreateMessageContext.d.ts +1 -1
- package/lib/typescript/components/Spinner/Spinner.d.ts +7 -1
- package/lib/typescript/components/index.d.ts +2 -0
- package/lib/typescript/contexts/messageContext/MessageContext.d.ts +3 -1
- package/lib/typescript/contexts/messageOverlayContext/MessageOverlayContext.d.ts +1 -0
- package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts +2 -0
- package/lib/typescript/contexts/themeContext/utils/theme.d.ts +9 -0
- package/lib/typescript/icons/Pause.d.ts +3 -0
- package/lib/typescript/icons/Play.d.ts +3 -0
- package/lib/typescript/icons/index.d.ts +2 -0
- package/lib/typescript/mock-builders/api/queryMembers.d.ts +161 -0
- package/lib/typescript/mock-builders/api/utils.d.ts +7 -0
- package/lib/typescript/mock-builders/generator/user.d.ts +30 -0
- package/lib/typescript/mock-builders/mock.d.ts +3 -0
- package/lib/typescript/native.d.ts +66 -1
- package/package.json +1 -1
- package/src/components/Attachment/Attachment.tsx +11 -7
- package/src/components/Attachment/Card.tsx +3 -0
- package/src/components/Attachment/Gallery.tsx +75 -36
- package/src/components/Attachment/VideoThumbnail.tsx +45 -0
- package/src/components/Attachment/hooks/useGoToURL.ts +1 -1
- package/src/components/Attachment/utils/buildGallery/buildThumbnail.ts +1 -0
- package/src/components/Attachment/utils/buildGallery/types.ts +1 -0
- package/src/components/Attachment/utils/getAspectRatio.ts +7 -5
- package/src/components/Channel/Channel.tsx +4 -0
- package/src/components/Channel/hooks/useCreateMessagesContext.ts +2 -0
- package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewDisplayName.test.tsx +83 -0
- package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayName.ts +43 -26
- package/src/components/Chat/hooks/useIsOnline.ts +7 -7
- package/src/components/ImageGallery/ImageGallery.tsx +145 -667
- package/src/components/ImageGallery/components/AnimatedGalleryImage.tsx +4 -4
- package/src/components/ImageGallery/components/AnimatedGalleryVideo.tsx +224 -0
- package/src/components/ImageGallery/components/ImageGalleryFooter.tsx +114 -19
- package/src/components/ImageGallery/components/ImageGalleryVideoControl.tsx +103 -0
- package/src/components/ImageGallery/components/ImageGrid.tsx +12 -25
- package/src/components/ImageGallery/components/ProgressControl.tsx +107 -0
- package/src/components/ImageGallery/hooks/useImageGalleryGestures.tsx +722 -0
- package/src/components/Message/Message.tsx +18 -7
- package/src/components/Message/MessageSimple/utils/renderText.tsx +6 -1
- package/src/components/Message/hooks/useCreateMessageContext.ts +2 -0
- package/src/components/MessageOverlay/MessageOverlay.tsx +2 -0
- package/src/components/Reply/Reply.tsx +36 -23
- package/src/components/Spinner/Spinner.tsx +11 -4
- package/src/components/index.ts +2 -0
- package/src/contexts/messageContext/MessageContext.tsx +2 -0
- package/src/contexts/messageInputContext/MessageInputContext.tsx +11 -0
- package/src/contexts/messageOverlayContext/MessageOverlayContext.tsx +1 -0
- package/src/contexts/messagesContext/MessagesContext.tsx +2 -0
- package/src/contexts/themeContext/utils/theme.ts +18 -0
- package/src/icons/Pause.tsx +14 -0
- package/src/icons/Play.tsx +17 -0
- package/src/icons/index.ts +2 -0
- package/src/mock-builders/api/queryMembers.js +98 -0
- package/src/native.ts +59 -1
- package/src/utils/getUrlOfImageAttachment.ts +1 -1
- package/src/version.json +1 -1
|
@@ -12,23 +12,17 @@ import {
|
|
|
12
12
|
|
|
13
13
|
import {
|
|
14
14
|
PanGestureHandler,
|
|
15
|
-
PanGestureHandlerGestureEvent,
|
|
16
15
|
PinchGestureHandler,
|
|
17
|
-
PinchGestureHandlerGestureEvent,
|
|
18
16
|
TapGestureHandler,
|
|
19
|
-
TapGestureHandlerGestureEvent,
|
|
20
17
|
} from 'react-native-gesture-handler';
|
|
21
18
|
|
|
22
19
|
import Animated, {
|
|
23
|
-
cancelAnimation,
|
|
24
20
|
Easing,
|
|
25
21
|
runOnJS,
|
|
26
22
|
runOnUI,
|
|
27
|
-
useAnimatedGestureHandler,
|
|
28
23
|
useAnimatedStyle,
|
|
29
24
|
useDerivedValue,
|
|
30
25
|
useSharedValue,
|
|
31
|
-
withDecay,
|
|
32
26
|
withTiming,
|
|
33
27
|
} from 'react-native-reanimated';
|
|
34
28
|
|
|
@@ -37,6 +31,7 @@ import { BottomSheetModal, BottomSheetModalProvider } from '@gorhom/bottom-sheet
|
|
|
37
31
|
import type { UserResponse } from 'stream-chat';
|
|
38
32
|
|
|
39
33
|
import { AnimatedGalleryImage } from './components/AnimatedGalleryImage';
|
|
34
|
+
import { AnimatedGalleryVideo } from './components/AnimatedGalleryVideo';
|
|
40
35
|
import {
|
|
41
36
|
ImageGalleryFooter,
|
|
42
37
|
ImageGalleryFooterCustomComponentProps,
|
|
@@ -52,13 +47,15 @@ import {
|
|
|
52
47
|
ImageGridHandle,
|
|
53
48
|
} from './components/ImageGridHandle';
|
|
54
49
|
|
|
50
|
+
import { useImageGalleryGestures } from './hooks/useImageGalleryGestures';
|
|
51
|
+
|
|
55
52
|
import { useImageGalleryContext } from '../../contexts/imageGalleryContext/ImageGalleryContext';
|
|
56
53
|
import {
|
|
57
54
|
OverlayProviderProps,
|
|
58
55
|
useOverlayContext,
|
|
59
56
|
} from '../../contexts/overlayContext/OverlayContext';
|
|
60
57
|
import { useTheme } from '../../contexts/themeContext/ThemeContext';
|
|
61
|
-
import {
|
|
58
|
+
import type { VideoPayloadData, VideoProgressData, VideoType } from '../../native';
|
|
62
59
|
import type { DefaultStreamChatGenerics } from '../../types/types';
|
|
63
60
|
import { getResizedImageUrl } from '../../utils/getResizedImageUrl';
|
|
64
61
|
import { getUrlOfImageAttachment } from '../../utils/getUrlOfImageAttachment';
|
|
@@ -148,6 +145,9 @@ export const ImageGallery = <
|
|
|
148
145
|
numberOfImageGalleryGridColumns,
|
|
149
146
|
overlayOpacity,
|
|
150
147
|
} = props;
|
|
148
|
+
const [paused, setPaused] = useState<boolean>(false);
|
|
149
|
+
const [progress, setProgress] = useState<number>(0);
|
|
150
|
+
const [duration, setDuration] = useState<number>(0);
|
|
151
151
|
const {
|
|
152
152
|
theme: {
|
|
153
153
|
colors: { white_snow },
|
|
@@ -155,7 +155,7 @@ export const ImageGallery = <
|
|
|
155
155
|
},
|
|
156
156
|
} = useTheme();
|
|
157
157
|
const [gridPhotos, setGridPhotos] = useState<Photo<StreamChatGenerics>[]>([]);
|
|
158
|
-
const { overlay,
|
|
158
|
+
const { overlay, translucentStatusBar } = useOverlayContext();
|
|
159
159
|
const { image, images, setImage } = useImageGalleryContext<StreamChatGenerics>();
|
|
160
160
|
|
|
161
161
|
/**
|
|
@@ -175,7 +175,10 @@ export const ImageGallery = <
|
|
|
175
175
|
: vh(100);
|
|
176
176
|
const halfScreenHeight = screenHeight / 2;
|
|
177
177
|
const quarterScreenHeight = screenHeight / 4;
|
|
178
|
-
const snapPoints = React.useMemo(
|
|
178
|
+
const snapPoints = React.useMemo(
|
|
179
|
+
() => [(screenHeight * 3) / 4, screenHeight - (imageGalleryGridHandleHeight ?? 40)],
|
|
180
|
+
[],
|
|
181
|
+
);
|
|
179
182
|
|
|
180
183
|
/**
|
|
181
184
|
* BottomSheetModal ref
|
|
@@ -226,12 +229,6 @@ export const ImageGallery = <
|
|
|
226
229
|
*/
|
|
227
230
|
const headerFooterVisible = useSharedValue(1);
|
|
228
231
|
|
|
229
|
-
/**
|
|
230
|
-
* Values to track scale for haptic feedback firing
|
|
231
|
-
*/
|
|
232
|
-
const hasHitBottomScale = useSharedValue(1);
|
|
233
|
-
const hasHitTopScale = useSharedValue(0);
|
|
234
|
-
|
|
235
232
|
/**
|
|
236
233
|
* Gesture handler refs
|
|
237
234
|
*/
|
|
@@ -243,73 +240,19 @@ export const ImageGallery = <
|
|
|
243
240
|
/**
|
|
244
241
|
* Shared values for movement
|
|
245
242
|
*/
|
|
246
|
-
const offsetX = useSharedValue(0);
|
|
247
|
-
const offsetY = useSharedValue(0);
|
|
248
243
|
const translateX = useSharedValue(0);
|
|
249
244
|
const translateY = useSharedValue(0);
|
|
250
245
|
const offsetScale = useSharedValue(1);
|
|
251
246
|
const scale = useSharedValue(1);
|
|
252
247
|
const translationX = useSharedValue(0);
|
|
253
248
|
|
|
254
|
-
/**
|
|
255
|
-
* Shared values for touch tracking
|
|
256
|
-
*/
|
|
257
|
-
const originX = useSharedValue(0);
|
|
258
|
-
const originY = useSharedValue(0);
|
|
259
|
-
const focalX = useSharedValue(0);
|
|
260
|
-
const focalY = useSharedValue(0);
|
|
261
|
-
const oldFocalX = useSharedValue(0);
|
|
262
|
-
const oldFocalY = useSharedValue(0);
|
|
263
|
-
const focalOffsetX = useSharedValue(0);
|
|
264
|
-
const focalOffsetY = useSharedValue(0);
|
|
265
|
-
const adjustedFocalX = useSharedValue(0);
|
|
266
|
-
const adjustedFocalY = useSharedValue(0);
|
|
267
|
-
const tapX = useSharedValue(0);
|
|
268
|
-
const tapY = useSharedValue(0);
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Shared values for gesture tracking
|
|
272
|
-
*/
|
|
273
|
-
const numberOfPinchFingers = useSharedValue(0);
|
|
274
|
-
const isSwiping = useSharedValue(0);
|
|
275
|
-
const isPinch = useSharedValue(false);
|
|
276
|
-
const hasPinched = useSharedValue(0);
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* Reset gesture values for use on touch release
|
|
280
|
-
*/
|
|
281
|
-
const resetTouchValues = () => {
|
|
282
|
-
'worklet';
|
|
283
|
-
focalX.value = 0;
|
|
284
|
-
focalY.value = 0;
|
|
285
|
-
oldFocalX.value = 0;
|
|
286
|
-
oldFocalY.value = 0;
|
|
287
|
-
originX.value = 0;
|
|
288
|
-
originY.value = 0;
|
|
289
|
-
focalOffsetX.value = 0;
|
|
290
|
-
focalOffsetY.value = 0;
|
|
291
|
-
numberOfPinchFingers.value = 0;
|
|
292
|
-
isPinch.value = false;
|
|
293
|
-
isSwiping.value = IsSwiping.UNDETERMINED;
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Reset movement values for use on selected photo change
|
|
298
|
-
*/
|
|
299
|
-
const resetMovementValues = () => {
|
|
300
|
-
'worklet';
|
|
301
|
-
translateX.value = 0;
|
|
302
|
-
translateY.value = 0;
|
|
303
|
-
scale.value = 1;
|
|
304
|
-
offsetScale.value = 1;
|
|
305
|
-
};
|
|
306
|
-
|
|
307
249
|
/**
|
|
308
250
|
* Photos array created from all currently available
|
|
309
251
|
* photo attachments
|
|
310
252
|
*/
|
|
311
253
|
|
|
312
254
|
const photos = images.reduce((acc: Photo<StreamChatGenerics>[], cur) => {
|
|
255
|
+
console.log(cur);
|
|
313
256
|
const attachmentImages =
|
|
314
257
|
cur.attachments?.filter(
|
|
315
258
|
(attachment) =>
|
|
@@ -320,7 +263,8 @@ export const ImageGallery = <
|
|
|
320
263
|
(attachment.type === 'image' &&
|
|
321
264
|
!attachment.title_link &&
|
|
322
265
|
!attachment.og_scrape_url &&
|
|
323
|
-
getUrlOfImageAttachment(attachment))
|
|
266
|
+
getUrlOfImageAttachment(attachment)) ||
|
|
267
|
+
attachment.type === 'video',
|
|
324
268
|
) || [];
|
|
325
269
|
|
|
326
270
|
const attachmentPhotos = attachmentImages.map((a) => {
|
|
@@ -331,8 +275,10 @@ export const ImageGallery = <
|
|
|
331
275
|
created_at: cur.created_at,
|
|
332
276
|
id: `photoId-${cur.id}-${imageUrl}`,
|
|
333
277
|
messageId: cur.id,
|
|
278
|
+
mime_type: a.mime_type,
|
|
334
279
|
original_height: a.original_height,
|
|
335
280
|
original_width: a.original_width,
|
|
281
|
+
type: a.type,
|
|
336
282
|
uri: getResizedImageUrl({
|
|
337
283
|
height: screenHeight,
|
|
338
284
|
url: imageUrl,
|
|
@@ -372,6 +318,10 @@ export const ImageGallery = <
|
|
|
372
318
|
(photo) => photo.messageId === image?.messageId && photo.uri === image?.url,
|
|
373
319
|
);
|
|
374
320
|
|
|
321
|
+
if (photoLength > 1) {
|
|
322
|
+
setPaused(true);
|
|
323
|
+
}
|
|
324
|
+
|
|
375
325
|
runOnUI(updatePosition)(newIndex);
|
|
376
326
|
}, [image, photoLength]);
|
|
377
327
|
|
|
@@ -392,582 +342,30 @@ export const ImageGallery = <
|
|
|
392
342
|
const imageHeight = Math.floor(height * (screenWidth / width));
|
|
393
343
|
setCurrentImageHeight(imageHeight > screenHeight ? screenHeight : imageHeight);
|
|
394
344
|
} else if (photo?.uri) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
345
|
+
if (photo.type === 'image') {
|
|
346
|
+
Image.getSize(photo.uri, (width, height) => {
|
|
347
|
+
const imageHeight = Math.floor(height * (screenWidth / width));
|
|
348
|
+
setCurrentImageHeight(imageHeight > screenHeight ? screenHeight : imageHeight);
|
|
349
|
+
});
|
|
350
|
+
}
|
|
399
351
|
}
|
|
400
352
|
}, [uriForCurrentImage]);
|
|
401
353
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
if (isAndroid && hasPinched.value === HasPinched.TRUE) {
|
|
418
|
-
hasPinched.value = HasPinched.FALSE;
|
|
419
|
-
isSwiping.value = IsSwiping.FALSE;
|
|
420
|
-
offsetX.value = translateX.value + evt.translationX;
|
|
421
|
-
offsetY.value = translateY.value - evt.translationY;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* isSwiping is used to prevent Y movement if a clear swipe to next
|
|
426
|
-
* or previous is begun when at the edge of a photo. The value is
|
|
427
|
-
* either 0, 1, or 2, via the IsSwiping enum designating undetermined,
|
|
428
|
-
* true, or false and is reset on releasing the touch
|
|
429
|
-
*/
|
|
430
|
-
if (isSwiping.value === IsSwiping.UNDETERMINED) {
|
|
431
|
-
const maxXYRatio = isAndroid ? 1 : 0.25;
|
|
432
|
-
if (
|
|
433
|
-
Math.abs(evt.translationX / evt.translationY) > maxXYRatio &&
|
|
434
|
-
(Math.abs(-halfScreenWidth * (scale.value - 1) - offsetX.value) < 3 ||
|
|
435
|
-
Math.abs(halfScreenWidth * (scale.value - 1) - offsetX.value) < 3)
|
|
436
|
-
) {
|
|
437
|
-
isSwiping.value = IsSwiping.TRUE;
|
|
438
|
-
}
|
|
439
|
-
if (Math.abs(evt.translationY) > 25) {
|
|
440
|
-
isSwiping.value = IsSwiping.FALSE;
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
/**
|
|
445
|
-
* localEvtScale is used for swipe away
|
|
446
|
-
*/
|
|
447
|
-
const localEvtScale = scale.value / offsetScale.value;
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* If not swiping translate the image in X and Y to the event
|
|
451
|
-
* translation plus offset. If swiping only translate X, if
|
|
452
|
-
* swiping down when at top of screen or centered balance scale
|
|
453
|
-
* using offset to a degree (this needs improvement the calculation
|
|
454
|
-
* is incorrect but likely needs origin use to be 100%)
|
|
455
|
-
*/
|
|
456
|
-
translateX.value =
|
|
457
|
-
scale.value !== offsetScale.value
|
|
458
|
-
? offsetX.value * localEvtScale - evt.translationX
|
|
459
|
-
: offsetX.value - evt.translationX;
|
|
460
|
-
translateY.value =
|
|
461
|
-
isSwiping.value !== IsSwiping.TRUE
|
|
462
|
-
? scale.value !== offsetScale.value
|
|
463
|
-
? offsetY.value * localEvtScale + evt.translationY
|
|
464
|
-
: offsetY.value + evt.translationY
|
|
465
|
-
: translateY.value;
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* If swiping down start scaling down the image for swipe
|
|
469
|
-
* away effect
|
|
470
|
-
*/
|
|
471
|
-
scale.value =
|
|
472
|
-
currentImageHeight * offsetScale.value < screenHeight && translateY.value > 0
|
|
473
|
-
? offsetScale.value * (1 - (1 / 3) * (translateY.value / screenHeight))
|
|
474
|
-
: currentImageHeight * offsetScale.value > screenHeight &&
|
|
475
|
-
translateY.value > (currentImageHeight / 2) * offsetScale.value - halfScreenHeight
|
|
476
|
-
? offsetScale.value *
|
|
477
|
-
(1 -
|
|
478
|
-
(1 / 3) *
|
|
479
|
-
((translateY.value -
|
|
480
|
-
((currentImageHeight / 2) * offsetScale.value - halfScreenHeight)) /
|
|
481
|
-
screenHeight))
|
|
482
|
-
: scale.value;
|
|
483
|
-
|
|
484
|
-
overlayOpacity.value = localEvtScale;
|
|
485
|
-
}
|
|
486
|
-
},
|
|
487
|
-
onFinish: (evt) => {
|
|
488
|
-
if (!isPinch.value && evt.numberOfPointers < 2) {
|
|
489
|
-
/**
|
|
490
|
-
* To determine if the fling should page to the next image we
|
|
491
|
-
* calculate a final position based on the current position and
|
|
492
|
-
* event velocity
|
|
493
|
-
*/
|
|
494
|
-
const finalXPosition = evt.translationX - evt.velocityX * 0.3;
|
|
495
|
-
const finalYPosition = evt.translationY + evt.velocityY * 0.1;
|
|
496
|
-
|
|
497
|
-
/**
|
|
498
|
-
* If there is a next photo, the image is lined up to the right
|
|
499
|
-
* edge, the swipe is to the left, and the final position is more
|
|
500
|
-
* than half the screen width, move to the next image
|
|
501
|
-
*/
|
|
502
|
-
if (
|
|
503
|
-
index.value < photoLength - 1 &&
|
|
504
|
-
Math.abs(halfScreenWidth * (scale.value - 1) + offsetX.value) < 3 &&
|
|
505
|
-
translateX.value < 0 &&
|
|
506
|
-
finalXPosition < -halfScreenWidth &&
|
|
507
|
-
isSwiping.value === IsSwiping.TRUE
|
|
508
|
-
) {
|
|
509
|
-
cancelAnimation(translationX);
|
|
510
|
-
translationX.value = withTiming(
|
|
511
|
-
-(screenWidth + MARGIN) * (index.value + 1),
|
|
512
|
-
{
|
|
513
|
-
duration: 200,
|
|
514
|
-
easing: Easing.out(Easing.ease),
|
|
515
|
-
},
|
|
516
|
-
() => {
|
|
517
|
-
resetMovementValues();
|
|
518
|
-
index.value = index.value + 1;
|
|
519
|
-
runOnJS(setSelectedIndex)(index.value);
|
|
520
|
-
},
|
|
521
|
-
);
|
|
522
|
-
|
|
523
|
-
/**
|
|
524
|
-
* If there is a previous photo, the image is lined up to the left
|
|
525
|
-
* edge, the swipe is to the right, and the final position is more
|
|
526
|
-
* than half the screen width, move to the previous image
|
|
527
|
-
*/
|
|
528
|
-
} else if (
|
|
529
|
-
index.value > 0 &&
|
|
530
|
-
Math.abs(-halfScreenWidth * (scale.value - 1) + offsetX.value) < 3 &&
|
|
531
|
-
translateX.value > 0 &&
|
|
532
|
-
finalXPosition > halfScreenWidth &&
|
|
533
|
-
isSwiping.value === IsSwiping.TRUE
|
|
534
|
-
) {
|
|
535
|
-
cancelAnimation(translationX);
|
|
536
|
-
translationX.value = withTiming(
|
|
537
|
-
-(screenWidth + MARGIN) * (index.value - 1),
|
|
538
|
-
{
|
|
539
|
-
duration: 200,
|
|
540
|
-
easing: Easing.out(Easing.ease),
|
|
541
|
-
},
|
|
542
|
-
() => {
|
|
543
|
-
resetMovementValues();
|
|
544
|
-
index.value = index.value - 1;
|
|
545
|
-
runOnJS(setSelectedIndex)(index.value);
|
|
546
|
-
},
|
|
547
|
-
);
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* When the pan is finished if the scale is less than 1 return the
|
|
552
|
-
* photo to center, if the photo is inside the edges of the screen
|
|
553
|
-
* return the photo to line up with the edges, otherwise use decay
|
|
554
|
-
* with a clamping at the edges to give the effect the image is
|
|
555
|
-
* sliding along using velocity and friction
|
|
556
|
-
*/
|
|
557
|
-
translateX.value =
|
|
558
|
-
scale.value < 1
|
|
559
|
-
? withTiming(0)
|
|
560
|
-
: translateX.value > halfScreenWidth * (scale.value - 1)
|
|
561
|
-
? withTiming(halfScreenWidth * (scale.value - 1), {
|
|
562
|
-
duration: 200,
|
|
563
|
-
})
|
|
564
|
-
: translateX.value < -halfScreenWidth * (scale.value - 1)
|
|
565
|
-
? withTiming(-halfScreenWidth * (scale.value - 1), {
|
|
566
|
-
duration: 200,
|
|
567
|
-
})
|
|
568
|
-
: withDecay({
|
|
569
|
-
clamp: [
|
|
570
|
-
-halfScreenWidth * (scale.value - 1),
|
|
571
|
-
halfScreenWidth * (scale.value - 1),
|
|
572
|
-
],
|
|
573
|
-
deceleration: 0.99,
|
|
574
|
-
velocity: -evt.velocityX,
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
/**
|
|
578
|
-
* When the pan is finished if the height is less than the screen
|
|
579
|
-
* height return the photo to center, if the photo is inside the
|
|
580
|
-
* edges of the screen return the photo to line up with the edges,
|
|
581
|
-
* otherwise use decay with a clamping at the edges to give the effect
|
|
582
|
-
* the image is sliding along using velocity and friction
|
|
583
|
-
*/
|
|
584
|
-
translateY.value =
|
|
585
|
-
currentImageHeight * scale.value < screenHeight
|
|
586
|
-
? withTiming(0)
|
|
587
|
-
: translateY.value > (currentImageHeight / 2) * scale.value - halfScreenHeight
|
|
588
|
-
? withTiming((currentImageHeight / 2) * scale.value - halfScreenHeight)
|
|
589
|
-
: translateY.value < (-currentImageHeight / 2) * scale.value + halfScreenHeight
|
|
590
|
-
? withTiming((-currentImageHeight / 2) * scale.value + halfScreenHeight)
|
|
591
|
-
: withDecay({
|
|
592
|
-
clamp: [
|
|
593
|
-
(-currentImageHeight / 2) * scale.value + halfScreenHeight,
|
|
594
|
-
(currentImageHeight / 2) * scale.value - halfScreenHeight,
|
|
595
|
-
],
|
|
596
|
-
deceleration: 0.99,
|
|
597
|
-
velocity: evt.velocityY,
|
|
598
|
-
});
|
|
599
|
-
|
|
600
|
-
resetTouchValues();
|
|
601
|
-
|
|
602
|
-
/**
|
|
603
|
-
* If the scale has been reduced below one, i.e. zoomed out, translate
|
|
604
|
-
* the zoom back to one
|
|
605
|
-
*/
|
|
606
|
-
scale.value =
|
|
607
|
-
scale.value !== offsetScale.value ? withTiming(offsetScale.value) : offsetScale.value;
|
|
608
|
-
|
|
609
|
-
/**
|
|
610
|
-
* If the photo is centered or at the top of the screen if scaled larger
|
|
611
|
-
* than the screen, and not paging left or right, and the final Y position
|
|
612
|
-
* is greater than half the screen using swipe velocity and position, close
|
|
613
|
-
* the overlay
|
|
614
|
-
*/
|
|
615
|
-
if (
|
|
616
|
-
finalYPosition > halfScreenHeight &&
|
|
617
|
-
offsetY.value + 8 >= (currentImageHeight / 2) * scale.value - halfScreenHeight &&
|
|
618
|
-
isSwiping.value !== IsSwiping.TRUE &&
|
|
619
|
-
translateY.value !== 0 &&
|
|
620
|
-
!(
|
|
621
|
-
Math.abs(halfScreenWidth * (scale.value - 1) + offsetX.value) < 3 &&
|
|
622
|
-
translateX.value < 0 &&
|
|
623
|
-
finalXPosition < -halfScreenWidth
|
|
624
|
-
) &&
|
|
625
|
-
!(
|
|
626
|
-
Math.abs(-halfScreenWidth * (scale.value - 1) + offsetX.value) < 3 &&
|
|
627
|
-
translateX.value > 0 &&
|
|
628
|
-
finalXPosition > halfScreenWidth
|
|
629
|
-
)
|
|
630
|
-
) {
|
|
631
|
-
cancelAnimation(translateX);
|
|
632
|
-
cancelAnimation(translateY);
|
|
633
|
-
cancelAnimation(scale);
|
|
634
|
-
overlayOpacity.value = withTiming(
|
|
635
|
-
0,
|
|
636
|
-
{
|
|
637
|
-
duration: 200,
|
|
638
|
-
easing: Easing.out(Easing.ease),
|
|
639
|
-
},
|
|
640
|
-
() => {
|
|
641
|
-
runOnJS(setOverlay)('none');
|
|
642
|
-
},
|
|
643
|
-
);
|
|
644
|
-
scale.value = withTiming(0.6, {
|
|
645
|
-
duration: 200,
|
|
646
|
-
easing: Easing.out(Easing.ease),
|
|
647
|
-
});
|
|
648
|
-
translateY.value =
|
|
649
|
-
evt.velocityY > 1000
|
|
650
|
-
? withDecay({
|
|
651
|
-
velocity: evt.velocityY,
|
|
652
|
-
})
|
|
653
|
-
: withTiming(halfScreenHeight + (currentImageHeight / 2) * scale.value, {
|
|
654
|
-
duration: 200,
|
|
655
|
-
easing: Easing.out(Easing.ease),
|
|
656
|
-
});
|
|
657
|
-
translateX.value = withDecay({
|
|
658
|
-
velocity: -evt.velocityX,
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
},
|
|
663
|
-
|
|
664
|
-
onStart: () => {
|
|
665
|
-
if (!isPinch.value) {
|
|
666
|
-
/**
|
|
667
|
-
* Cancel any previous motion animation on translations when a touch
|
|
668
|
-
* begins to interrupt the animation and take over the position handling
|
|
669
|
-
*/
|
|
670
|
-
cancelAnimation(translateX);
|
|
671
|
-
cancelAnimation(translateY);
|
|
672
|
-
cancelAnimation(scale);
|
|
673
|
-
offsetX.value = translateX.value;
|
|
674
|
-
offsetY.value = translateY.value;
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
/**
|
|
678
|
-
* Reset hasPinched for Android single finger offset
|
|
679
|
-
*/
|
|
680
|
-
hasPinched.value = HasPinched.FALSE;
|
|
681
|
-
},
|
|
682
|
-
},
|
|
683
|
-
[currentImageHeight, photoLength],
|
|
684
|
-
);
|
|
685
|
-
|
|
686
|
-
/**
|
|
687
|
-
* On pinch is run when two or more fingers touch the screen, it then takes over
|
|
688
|
-
* all touch handling even if the number of fingers is reduced to one until the
|
|
689
|
-
* touch is complete
|
|
690
|
-
*/
|
|
691
|
-
const onPinch = useAnimatedGestureHandler<PinchGestureHandlerGestureEvent>(
|
|
692
|
-
{
|
|
693
|
-
onActive: (evt) => {
|
|
694
|
-
/**
|
|
695
|
-
* Android starts with a zero event with 1 touch instead of two
|
|
696
|
-
* we therefore must wait to capture starting info until the double
|
|
697
|
-
* touch begins
|
|
698
|
-
*/
|
|
699
|
-
if (!isPinch.value && isAndroid) {
|
|
700
|
-
/**
|
|
701
|
-
* Set hasPinched to true so when removing one finger the pan active
|
|
702
|
-
* state adjusts the offset
|
|
703
|
-
*/
|
|
704
|
-
hasPinched.value = HasPinched.TRUE;
|
|
705
|
-
|
|
706
|
-
/**
|
|
707
|
-
* Cancel any previous motion animation on translations when a touch
|
|
708
|
-
* begins to interrupt the animation and take over the position handling
|
|
709
|
-
*/
|
|
710
|
-
cancelAnimation(translateX);
|
|
711
|
-
cancelAnimation(translateY);
|
|
712
|
-
cancelAnimation(scale);
|
|
713
|
-
|
|
714
|
-
/**
|
|
715
|
-
* Reset isSwiping as now the pan gesture handler is no longer running
|
|
716
|
-
*/
|
|
717
|
-
isSwiping.value = IsSwiping.UNDETERMINED;
|
|
718
|
-
|
|
719
|
-
/**
|
|
720
|
-
* Set initial values for pinch gesture interaction handler
|
|
721
|
-
*/
|
|
722
|
-
numberOfPinchFingers.value = evt.numberOfPointers;
|
|
723
|
-
offsetX.value = translateX.value;
|
|
724
|
-
offsetY.value = translateY.value;
|
|
725
|
-
adjustedFocalX.value = evt.focalX - (halfScreenWidth - offsetX.value);
|
|
726
|
-
adjustedFocalY.value = evt.focalY - (halfScreenHeight + offsetY.value);
|
|
727
|
-
originX.value = adjustedFocalX.value;
|
|
728
|
-
originY.value = adjustedFocalY.value;
|
|
729
|
-
offsetScale.value = scale.value;
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
/**
|
|
733
|
-
* Set pinch to true to stop all pan gesture interactions, we do this
|
|
734
|
-
* again here for Android outside the check that creates type
|
|
735
|
-
*/
|
|
736
|
-
isPinch.value = true;
|
|
737
|
-
|
|
738
|
-
/**
|
|
739
|
-
* The scale is clamped to a minimum of 1 and maximum of 8 for aesthetics.
|
|
740
|
-
* We use the clamped value to determine a local event scale so the focal
|
|
741
|
-
* point does not become out of sync with the actual photo scaling, e.g.
|
|
742
|
-
* evt.scale is 20 but scale is 8, using evt.scale for offset will put the
|
|
743
|
-
* photo and calculations out of sync
|
|
744
|
-
*/
|
|
745
|
-
scale.value = clamp(offsetScale.value * evt.scale, 1, 8);
|
|
746
|
-
const localEvtScale = scale.value / offsetScale.value;
|
|
747
|
-
|
|
748
|
-
/**
|
|
749
|
-
* When we hit the top or bottom of the scale clamping we run a haptic
|
|
750
|
-
* trigger, we track if it has been run to not spam the trigger
|
|
751
|
-
*/
|
|
752
|
-
if (scale.value !== 8 && scale.value !== 1) {
|
|
753
|
-
hasHitTopScale.value = 0;
|
|
754
|
-
hasHitBottomScale.value = 0;
|
|
755
|
-
} else if (scale.value === 8 && hasHitTopScale.value === 0) {
|
|
756
|
-
hasHitTopScale.value = 1;
|
|
757
|
-
runOnJS(triggerHaptic)('impactLight');
|
|
758
|
-
} else if (scale.value === 1 && hasHitBottomScale.value === 0) {
|
|
759
|
-
hasHitBottomScale.value = 1;
|
|
760
|
-
runOnJS(triggerHaptic)('impactLight');
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
/**
|
|
764
|
-
* We calculate the adjusted focal point on the photo using the events
|
|
765
|
-
* focal position on the screen, screen size, and current photo offset
|
|
766
|
-
*/
|
|
767
|
-
adjustedFocalX.value = evt.focalX - (halfScreenWidth - offsetX.value);
|
|
768
|
-
adjustedFocalY.value = evt.focalY - (halfScreenHeight + offsetY.value);
|
|
769
|
-
|
|
770
|
-
/**
|
|
771
|
-
* If the number of fingers on the screen changes, the position of the
|
|
772
|
-
* focal point will change and this needs to be accounted for, e.g. if
|
|
773
|
-
* two fingers are on the screen the focal is between them, but if one is
|
|
774
|
-
* then removed the focal is now at the remaining fingers touch position.
|
|
775
|
-
* If this happens without accounting for the change the image will jump
|
|
776
|
-
* around, we keep track of the previous two finger focal to adjust for this
|
|
777
|
-
* change in a reduction from two fingers to one, then if another finger
|
|
778
|
-
* is added again we adjust the origin to account for the difference between
|
|
779
|
-
* the original two finger touch and the new two finger touch position.
|
|
780
|
-
*/
|
|
781
|
-
if (numberOfPinchFingers.value !== evt.numberOfPointers) {
|
|
782
|
-
numberOfPinchFingers.value = evt.numberOfPointers;
|
|
783
|
-
if (evt.numberOfPointers === 1) {
|
|
784
|
-
focalOffsetX.value = oldFocalX.value - adjustedFocalX.value;
|
|
785
|
-
focalOffsetY.value = oldFocalY.value - adjustedFocalY.value;
|
|
786
|
-
} else if (numberOfPinchFingers.value > 1) {
|
|
787
|
-
originX.value =
|
|
788
|
-
originX.value -
|
|
789
|
-
(oldFocalX.value / localEvtScale - adjustedFocalX.value / localEvtScale);
|
|
790
|
-
originY.value =
|
|
791
|
-
originY.value -
|
|
792
|
-
(oldFocalY.value / localEvtScale - adjustedFocalY.value / localEvtScale);
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
/**
|
|
797
|
-
* If pinch handler has been activated via two fingers then the fingers
|
|
798
|
-
* reduced to one we keep track of the old focal using the focal offset
|
|
799
|
-
* from when the number of fingers was two. We then translate the photo
|
|
800
|
-
* taking into account the offset, focal, focal offset, origin, and scale.
|
|
801
|
-
*/
|
|
802
|
-
if (numberOfPinchFingers.value === 1) {
|
|
803
|
-
oldFocalX.value = adjustedFocalX.value + focalOffsetX.value;
|
|
804
|
-
oldFocalY.value = adjustedFocalY.value + focalOffsetY.value;
|
|
805
|
-
translateX.value = offsetX.value - oldFocalX.value + localEvtScale * originX.value;
|
|
806
|
-
translateY.value = offsetY.value + oldFocalY.value - localEvtScale * originY.value;
|
|
807
|
-
|
|
808
|
-
/**
|
|
809
|
-
* If the number of fingers in the gesture is greater than one the
|
|
810
|
-
* adjusted focal point is saved as the old focal and the photo is
|
|
811
|
-
* translated taking into account the offset, focal, origin, and scale.
|
|
812
|
-
*/
|
|
813
|
-
} else if (numberOfPinchFingers.value > 1) {
|
|
814
|
-
oldFocalX.value = adjustedFocalX.value;
|
|
815
|
-
oldFocalY.value = adjustedFocalY.value;
|
|
816
|
-
translateX.value = offsetX.value - adjustedFocalX.value + localEvtScale * originX.value;
|
|
817
|
-
translateY.value = offsetY.value + adjustedFocalY.value - localEvtScale * originY.value;
|
|
818
|
-
}
|
|
819
|
-
},
|
|
820
|
-
onFinish: () => {
|
|
821
|
-
if (isPinch.value) {
|
|
822
|
-
/**
|
|
823
|
-
* When the pinch is finished if the scale is less than 1 return the
|
|
824
|
-
* photo to center, if the photo is inside the edges of the screen
|
|
825
|
-
* return the photo to line up with the edges, otherwise leave the
|
|
826
|
-
* photo in its current position
|
|
827
|
-
*/
|
|
828
|
-
translateX.value =
|
|
829
|
-
scale.value < 1
|
|
830
|
-
? withTiming(0)
|
|
831
|
-
: translateX.value > halfScreenWidth * (scale.value - 1)
|
|
832
|
-
? withTiming(halfScreenWidth * (scale.value - 1))
|
|
833
|
-
: translateX.value < -halfScreenWidth * (scale.value - 1)
|
|
834
|
-
? withTiming(-halfScreenWidth * (scale.value - 1))
|
|
835
|
-
: translateX.value;
|
|
836
|
-
|
|
837
|
-
/**
|
|
838
|
-
* When the pinch is finished if the height is less than the screen
|
|
839
|
-
* height return the photo to center, if the photo is inside the
|
|
840
|
-
* edges of the screen return the photo to line up with the edges,
|
|
841
|
-
* otherwise leave the photo in its current position
|
|
842
|
-
*/
|
|
843
|
-
translateY.value =
|
|
844
|
-
currentImageHeight * scale.value < screenHeight
|
|
845
|
-
? withTiming(0)
|
|
846
|
-
: translateY.value > (currentImageHeight / 2) * scale.value - screenHeight / 2
|
|
847
|
-
? withTiming((currentImageHeight / 2) * scale.value - screenHeight / 2)
|
|
848
|
-
: translateY.value < (-currentImageHeight / 2) * scale.value + screenHeight / 2
|
|
849
|
-
? withTiming((-currentImageHeight / 2) * scale.value + screenHeight / 2)
|
|
850
|
-
: translateY.value;
|
|
851
|
-
|
|
852
|
-
/**
|
|
853
|
-
* If the scale has been reduced below one, i.e. zoomed out, translate
|
|
854
|
-
* the zoom back to one
|
|
855
|
-
*/
|
|
856
|
-
offsetScale.value = scale.value < 1 ? 1 : scale.value;
|
|
857
|
-
scale.value = scale.value < 1 ? withTiming(1) : scale.value;
|
|
858
|
-
resetTouchValues();
|
|
859
|
-
}
|
|
860
|
-
},
|
|
861
|
-
onStart: (evt) => {
|
|
862
|
-
/**
|
|
863
|
-
* Android starts with a zero event with 1 touch instead of two
|
|
864
|
-
* we therefore must wait to capture starting info until the double
|
|
865
|
-
* touch begins
|
|
866
|
-
*/
|
|
867
|
-
if (!isAndroid) {
|
|
868
|
-
/**
|
|
869
|
-
* Cancel any previous motion animation on translations when a touch
|
|
870
|
-
* begins to interrupt the animation and take over the position handling
|
|
871
|
-
*/
|
|
872
|
-
cancelAnimation(translateX);
|
|
873
|
-
cancelAnimation(translateY);
|
|
874
|
-
cancelAnimation(scale);
|
|
875
|
-
|
|
876
|
-
/**
|
|
877
|
-
* Set pinch to true to stop all pan gesture interactions
|
|
878
|
-
*/
|
|
879
|
-
isPinch.value = true;
|
|
880
|
-
|
|
881
|
-
/**
|
|
882
|
-
* Reset isSwiping as now the pan gesture handler is no longer running
|
|
883
|
-
*/
|
|
884
|
-
isSwiping.value = IsSwiping.UNDETERMINED;
|
|
885
|
-
|
|
886
|
-
/**
|
|
887
|
-
* Set initial values for pinch gesture interaction handler
|
|
888
|
-
*/
|
|
889
|
-
numberOfPinchFingers.value = evt.numberOfPointers;
|
|
890
|
-
offsetX.value = translateX.value;
|
|
891
|
-
offsetY.value = translateY.value;
|
|
892
|
-
adjustedFocalX.value = evt.focalX - (halfScreenWidth - offsetX.value);
|
|
893
|
-
adjustedFocalY.value = evt.focalY - (halfScreenHeight + offsetY.value);
|
|
894
|
-
originX.value = adjustedFocalX.value;
|
|
895
|
-
originY.value = adjustedFocalY.value;
|
|
896
|
-
offsetScale.value = scale.value;
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
/**
|
|
900
|
-
* Reset hasPinched for Android single finger offset
|
|
901
|
-
*/
|
|
902
|
-
hasPinched.value = HasPinched.FALSE;
|
|
903
|
-
},
|
|
904
|
-
},
|
|
905
|
-
[currentImageHeight],
|
|
906
|
-
);
|
|
907
|
-
|
|
908
|
-
/**
|
|
909
|
-
* Single tap handler for header hiding and showing
|
|
910
|
-
*/
|
|
911
|
-
const onSingleTap = useAnimatedGestureHandler<TapGestureHandlerGestureEvent>({
|
|
912
|
-
onActive: () => {
|
|
913
|
-
cancelAnimation(headerFooterVisible);
|
|
914
|
-
headerFooterVisible.value = headerFooterVisible.value > 0 ? withTiming(0) : withTiming(1);
|
|
915
|
-
},
|
|
916
|
-
});
|
|
917
|
-
|
|
918
|
-
/**
|
|
919
|
-
* Double tap handler to zoom back out and hide header and footer
|
|
920
|
-
*/
|
|
921
|
-
const onDoubleTap = useAnimatedGestureHandler<TapGestureHandlerGestureEvent>({
|
|
922
|
-
onActive: (evt) => {
|
|
923
|
-
if (Math.abs(tapX.value - evt.absoluteX) < 64 && Math.abs(tapY.value - evt.absoluteY) < 64) {
|
|
924
|
-
if (offsetScale.value === 1 && offsetX.value === 0 && offsetY.value === 0) {
|
|
925
|
-
offsetScale.value = 2;
|
|
926
|
-
scale.value = withTiming(2, {
|
|
927
|
-
duration: 200,
|
|
928
|
-
easing: Easing.out(Easing.ease),
|
|
929
|
-
});
|
|
930
|
-
translateX.value = withTiming(evt.absoluteX - halfScreenWidth, {
|
|
931
|
-
duration: 200,
|
|
932
|
-
easing: Easing.out(Easing.ease),
|
|
933
|
-
});
|
|
934
|
-
if (currentImageHeight * 2 > screenHeight) {
|
|
935
|
-
const translateYTopBottom =
|
|
936
|
-
evt.absoluteY > halfScreenHeight
|
|
937
|
-
? -(currentImageHeight * 2 - screenHeight) / 2
|
|
938
|
-
: (currentImageHeight * 2 - screenHeight) / 2;
|
|
939
|
-
translateY.value = withTiming(translateYTopBottom, {
|
|
940
|
-
duration: 200,
|
|
941
|
-
easing: Easing.out(Easing.ease),
|
|
942
|
-
});
|
|
943
|
-
}
|
|
944
|
-
} else {
|
|
945
|
-
offsetScale.value = 1;
|
|
946
|
-
scale.value = withTiming(1, {
|
|
947
|
-
duration: 200,
|
|
948
|
-
easing: Easing.out(Easing.ease),
|
|
949
|
-
});
|
|
950
|
-
offsetX.value = 0;
|
|
951
|
-
offsetY.value = 0;
|
|
952
|
-
translateX.value = withTiming(0, {
|
|
953
|
-
duration: 200,
|
|
954
|
-
easing: Easing.out(Easing.ease),
|
|
955
|
-
});
|
|
956
|
-
translateY.value = withTiming(0, {
|
|
957
|
-
duration: 200,
|
|
958
|
-
easing: Easing.out(Easing.ease),
|
|
959
|
-
});
|
|
960
|
-
if (headerFooterVisible.value !== 0) {
|
|
961
|
-
cancelAnimation(headerFooterVisible);
|
|
962
|
-
headerFooterVisible.value = withTiming(0);
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
},
|
|
967
|
-
onStart: (evt) => {
|
|
968
|
-
tapX.value = evt.absoluteX;
|
|
969
|
-
tapY.value = evt.absoluteY;
|
|
970
|
-
},
|
|
354
|
+
const { onDoubleTap, onPan, onPinch, onSingleTap } = useImageGalleryGestures({
|
|
355
|
+
currentImageHeight,
|
|
356
|
+
halfScreenHeight,
|
|
357
|
+
halfScreenWidth,
|
|
358
|
+
headerFooterVisible,
|
|
359
|
+
offsetScale,
|
|
360
|
+
overlayOpacity,
|
|
361
|
+
photoLength,
|
|
362
|
+
scale,
|
|
363
|
+
screenHeight,
|
|
364
|
+
screenWidth,
|
|
365
|
+
setSelectedIndex,
|
|
366
|
+
translateX,
|
|
367
|
+
translateY,
|
|
368
|
+
translationX,
|
|
971
369
|
});
|
|
972
370
|
|
|
973
371
|
/**
|
|
@@ -1047,6 +445,49 @@ export const ImageGallery = <
|
|
|
1047
445
|
setGridPhotos(photos);
|
|
1048
446
|
}
|
|
1049
447
|
};
|
|
448
|
+
|
|
449
|
+
const videoRef = useRef<VideoType>(null);
|
|
450
|
+
|
|
451
|
+
const handleEnd = () => {
|
|
452
|
+
setPaused(true);
|
|
453
|
+
setProgress(1);
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
const handleLoad = (payload: VideoPayloadData) => {
|
|
457
|
+
if (payload.duration) setDuration(payload.duration);
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
const handleProgress = (data: VideoProgressData) => {
|
|
461
|
+
if (data.currentTime && data.seekableDuration) {
|
|
462
|
+
setProgress(data.currentTime / data.seekableDuration);
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
const handlePlayPause = () => {
|
|
467
|
+
// React Native Video for RN CLI has seek as an API to move to a particular location in the video
|
|
468
|
+
if (progress === 1 && videoRef.current && videoRef.current.seek) {
|
|
469
|
+
videoRef.current.seek(0);
|
|
470
|
+
}
|
|
471
|
+
// Expo AV for Expo has replayAsync as an API to move to a starting of the video
|
|
472
|
+
if (progress === 1 && videoRef.current && videoRef.current.replayAsync) {
|
|
473
|
+
videoRef.current.replayAsync();
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
setPaused((state) => !state);
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
const onProgressDrag = (progress: number) => {
|
|
480
|
+
// React Native Video for RN CLI has seek as an API to move to a particular location in the video
|
|
481
|
+
if (videoRef.current && videoRef.current.seek) {
|
|
482
|
+
videoRef.current.seek(progress);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Expo AV for Expo has setPositionAsync as an API to move to a particular location of the video
|
|
486
|
+
if (videoRef.current && videoRef.current.setPositionAsync) {
|
|
487
|
+
videoRef.current.setPositionAsync(progress * 1000);
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
|
|
1050
491
|
return (
|
|
1051
492
|
<Animated.View pointerEvents={'auto'} style={[StyleSheet.absoluteFillObject, showScreenStyle]}>
|
|
1052
493
|
<Animated.View style={[StyleSheet.absoluteFillObject, containerBackground]} />
|
|
@@ -1098,29 +539,58 @@ export const ImageGallery = <
|
|
|
1098
539
|
},
|
|
1099
540
|
]}
|
|
1100
541
|
>
|
|
1101
|
-
{photos.map((photo, i) =>
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
{
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
542
|
+
{photos.map((photo, i) =>
|
|
543
|
+
photo.type === 'video' ? (
|
|
544
|
+
<AnimatedGalleryVideo
|
|
545
|
+
handleEnd={handleEnd}
|
|
546
|
+
handleLoad={handleLoad}
|
|
547
|
+
handleProgress={handleProgress}
|
|
548
|
+
index={i}
|
|
549
|
+
key={`${photo.uri}-${i}`}
|
|
550
|
+
offsetScale={offsetScale}
|
|
551
|
+
paused={paused}
|
|
552
|
+
previous={selectedIndex > i}
|
|
553
|
+
scale={scale}
|
|
554
|
+
screenHeight={screenHeight}
|
|
555
|
+
selected={selectedIndex === i}
|
|
556
|
+
shouldRender={Math.abs(selectedIndex - i) < 4}
|
|
557
|
+
source={{ uri: photo.uri }}
|
|
558
|
+
style={[
|
|
559
|
+
{
|
|
560
|
+
height: screenHeight * 8,
|
|
561
|
+
marginRight: MARGIN,
|
|
562
|
+
width: screenWidth * 8,
|
|
563
|
+
},
|
|
564
|
+
slide,
|
|
565
|
+
]}
|
|
566
|
+
translateX={translateX}
|
|
567
|
+
translateY={translateY}
|
|
568
|
+
videoRef={videoRef}
|
|
569
|
+
/>
|
|
570
|
+
) : (
|
|
571
|
+
<AnimatedGalleryImage
|
|
572
|
+
index={i}
|
|
573
|
+
key={`${photo.uri}-${i}`}
|
|
574
|
+
offsetScale={offsetScale}
|
|
575
|
+
photo={photo}
|
|
576
|
+
previous={selectedIndex > i}
|
|
577
|
+
scale={scale}
|
|
578
|
+
screenHeight={screenHeight}
|
|
579
|
+
selected={selectedIndex === i}
|
|
580
|
+
shouldRender={Math.abs(selectedIndex - i) < 4}
|
|
581
|
+
style={[
|
|
582
|
+
{
|
|
583
|
+
height: screenHeight * 8,
|
|
584
|
+
marginRight: MARGIN,
|
|
585
|
+
width: screenWidth * 8,
|
|
586
|
+
},
|
|
587
|
+
slide,
|
|
588
|
+
]}
|
|
589
|
+
translateX={translateX}
|
|
590
|
+
translateY={translateY}
|
|
591
|
+
/>
|
|
592
|
+
),
|
|
593
|
+
)}
|
|
1124
594
|
</Animated.View>
|
|
1125
595
|
</Animated.View>
|
|
1126
596
|
</PanGestureHandler>
|
|
@@ -1137,14 +607,20 @@ export const ImageGallery = <
|
|
|
1137
607
|
{...imageGalleryCustomComponents?.header}
|
|
1138
608
|
/>
|
|
1139
609
|
<ImageGalleryFooter<StreamChatGenerics>
|
|
610
|
+
duration={duration}
|
|
611
|
+
onPlayPause={handlePlayPause}
|
|
612
|
+
onProgressDrag={onProgressDrag}
|
|
1140
613
|
opacity={headerFooterOpacity}
|
|
1141
614
|
openGridView={openGridView}
|
|
615
|
+
paused={paused}
|
|
1142
616
|
photo={photos[selectedIndex]}
|
|
1143
617
|
photoLength={photoLength}
|
|
618
|
+
progress={progress}
|
|
1144
619
|
selectedIndex={selectedIndex}
|
|
1145
620
|
visible={headerFooterVisible}
|
|
1146
621
|
{...imageGalleryCustomComponents?.footer}
|
|
1147
622
|
/>
|
|
623
|
+
|
|
1148
624
|
<ImageGalleryOverlay
|
|
1149
625
|
animatedBottomSheetIndex={animatedBottomSheetIndex}
|
|
1150
626
|
closeGridView={closeGridView}
|
|
@@ -1202,8 +678,10 @@ export type Photo<
|
|
|
1202
678
|
channelId?: string;
|
|
1203
679
|
created_at?: string | Date;
|
|
1204
680
|
messageId?: string;
|
|
681
|
+
mime_type?: string;
|
|
1205
682
|
original_height?: number;
|
|
1206
683
|
original_width?: number;
|
|
684
|
+
type?: string;
|
|
1207
685
|
user?: UserResponse<StreamChatGenerics> | null;
|
|
1208
686
|
user_id?: string;
|
|
1209
687
|
};
|