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.
Files changed (222) hide show
  1. package/lib/commonjs/components/Attachment/Attachment.js +22 -13
  2. package/lib/commonjs/components/Attachment/Attachment.js.map +1 -1
  3. package/lib/commonjs/components/Attachment/Card.js +23 -14
  4. package/lib/commonjs/components/Attachment/Card.js.map +1 -1
  5. package/lib/commonjs/components/Attachment/Gallery.js +72 -37
  6. package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
  7. package/lib/commonjs/components/Attachment/VideoThumbnail.js +83 -0
  8. package/lib/commonjs/components/Attachment/VideoThumbnail.js.map +1 -0
  9. package/lib/commonjs/components/Attachment/hooks/useGoToURL.js +1 -1
  10. package/lib/commonjs/components/Attachment/hooks/useGoToURL.js.map +1 -1
  11. package/lib/commonjs/components/Attachment/utils/buildGallery/buildThumbnail.js +1 -0
  12. package/lib/commonjs/components/Attachment/utils/buildGallery/buildThumbnail.js.map +1 -1
  13. package/lib/commonjs/components/Attachment/utils/getAspectRatio.js +5 -5
  14. package/lib/commonjs/components/Attachment/utils/getAspectRatio.js.map +1 -1
  15. package/lib/commonjs/components/Channel/Channel.js +19 -14
  16. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  17. package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js +4 -2
  18. package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
  19. package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js +43 -28
  20. package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js.map +1 -1
  21. package/lib/commonjs/components/Chat/hooks/useIsOnline.js +6 -6
  22. package/lib/commonjs/components/Chat/hooks/useIsOnline.js.map +1 -1
  23. package/lib/commonjs/components/ImageGallery/ImageGallery.js +167 -345
  24. package/lib/commonjs/components/ImageGallery/ImageGallery.js.map +1 -1
  25. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryImage.js +4 -4
  26. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryImage.js.map +1 -1
  27. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryVideo.js +225 -0
  28. package/lib/commonjs/components/ImageGallery/components/AnimatedGalleryVideo.js.map +1 -0
  29. package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js +102 -40
  30. package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
  31. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js +145 -0
  32. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -0
  33. package/lib/commonjs/components/ImageGallery/components/ImageGrid.js +31 -34
  34. package/lib/commonjs/components/ImageGallery/components/ImageGrid.js.map +1 -1
  35. package/lib/commonjs/components/ImageGallery/components/ProgressControl.js +153 -0
  36. package/lib/commonjs/components/ImageGallery/components/ProgressControl.js.map +1 -0
  37. package/lib/commonjs/components/ImageGallery/hooks/useImageGalleryGestures.js +373 -0
  38. package/lib/commonjs/components/ImageGallery/hooks/useImageGalleryGestures.js.map +1 -0
  39. package/lib/commonjs/components/Message/Message.js +23 -13
  40. package/lib/commonjs/components/Message/Message.js.map +1 -1
  41. package/lib/commonjs/components/Message/MessageSimple/utils/renderText.js +22 -15
  42. package/lib/commonjs/components/Message/MessageSimple/utils/renderText.js.map +1 -1
  43. package/lib/commonjs/components/Message/hooks/useCreateMessageContext.js +4 -2
  44. package/lib/commonjs/components/Message/hooks/useCreateMessageContext.js.map +1 -1
  45. package/lib/commonjs/components/MessageOverlay/MessageOverlay.js +25 -23
  46. package/lib/commonjs/components/MessageOverlay/MessageOverlay.js.map +1 -1
  47. package/lib/commonjs/components/Reply/Reply.js +32 -12
  48. package/lib/commonjs/components/Reply/Reply.js.map +1 -1
  49. package/lib/commonjs/components/Spinner/Spinner.js +12 -4
  50. package/lib/commonjs/components/Spinner/Spinner.js.map +1 -1
  51. package/lib/commonjs/components/index.js +26 -0
  52. package/lib/commonjs/components/index.js.map +1 -1
  53. package/lib/commonjs/contexts/messageContext/MessageContext.js +2 -2
  54. package/lib/commonjs/contexts/messageContext/MessageContext.js.map +1 -1
  55. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +15 -4
  56. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  57. package/lib/commonjs/contexts/messageOverlayContext/MessageOverlayContext.js +2 -2
  58. package/lib/commonjs/contexts/messageOverlayContext/MessageOverlayContext.js.map +1 -1
  59. package/lib/commonjs/contexts/messagesContext/MessagesContext.js +2 -2
  60. package/lib/commonjs/contexts/messagesContext/MessagesContext.js.map +1 -1
  61. package/lib/commonjs/contexts/themeContext/utils/theme.js +10 -1
  62. package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
  63. package/lib/commonjs/icons/Pause.js +61 -0
  64. package/lib/commonjs/icons/Pause.js.map +1 -0
  65. package/lib/commonjs/icons/Play.js +42 -0
  66. package/lib/commonjs/icons/Play.js.map +1 -0
  67. package/lib/commonjs/icons/index.js +26 -0
  68. package/lib/commonjs/icons/index.js.map +1 -1
  69. package/lib/commonjs/mock-builders/api/queryMembers.js +98 -1
  70. package/lib/commonjs/mock-builders/api/queryMembers.js.map +1 -1
  71. package/lib/commonjs/native.js +7 -1
  72. package/lib/commonjs/native.js.map +1 -1
  73. package/lib/commonjs/utils/getUrlOfImageAttachment.js +1 -1
  74. package/lib/commonjs/utils/getUrlOfImageAttachment.js.map +1 -1
  75. package/lib/commonjs/version.json +1 -1
  76. package/lib/module/components/Attachment/Attachment.js +22 -13
  77. package/lib/module/components/Attachment/Attachment.js.map +1 -1
  78. package/lib/module/components/Attachment/Card.js +23 -14
  79. package/lib/module/components/Attachment/Card.js.map +1 -1
  80. package/lib/module/components/Attachment/Gallery.js +72 -37
  81. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  82. package/lib/module/components/Attachment/VideoThumbnail.js +83 -0
  83. package/lib/module/components/Attachment/VideoThumbnail.js.map +1 -0
  84. package/lib/module/components/Attachment/hooks/useGoToURL.js +1 -1
  85. package/lib/module/components/Attachment/hooks/useGoToURL.js.map +1 -1
  86. package/lib/module/components/Attachment/utils/buildGallery/buildThumbnail.js +1 -0
  87. package/lib/module/components/Attachment/utils/buildGallery/buildThumbnail.js.map +1 -1
  88. package/lib/module/components/Attachment/utils/getAspectRatio.js +5 -5
  89. package/lib/module/components/Attachment/utils/getAspectRatio.js.map +1 -1
  90. package/lib/module/components/Channel/Channel.js +19 -14
  91. package/lib/module/components/Channel/Channel.js.map +1 -1
  92. package/lib/module/components/Channel/hooks/useCreateMessagesContext.js +4 -2
  93. package/lib/module/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
  94. package/lib/module/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js +43 -28
  95. package/lib/module/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js.map +1 -1
  96. package/lib/module/components/Chat/hooks/useIsOnline.js +6 -6
  97. package/lib/module/components/Chat/hooks/useIsOnline.js.map +1 -1
  98. package/lib/module/components/ImageGallery/ImageGallery.js +167 -345
  99. package/lib/module/components/ImageGallery/ImageGallery.js.map +1 -1
  100. package/lib/module/components/ImageGallery/components/AnimatedGalleryImage.js +4 -4
  101. package/lib/module/components/ImageGallery/components/AnimatedGalleryImage.js.map +1 -1
  102. package/lib/module/components/ImageGallery/components/AnimatedGalleryVideo.js +225 -0
  103. package/lib/module/components/ImageGallery/components/AnimatedGalleryVideo.js.map +1 -0
  104. package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js +102 -40
  105. package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
  106. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js +145 -0
  107. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -0
  108. package/lib/module/components/ImageGallery/components/ImageGrid.js +31 -34
  109. package/lib/module/components/ImageGallery/components/ImageGrid.js.map +1 -1
  110. package/lib/module/components/ImageGallery/components/ProgressControl.js +153 -0
  111. package/lib/module/components/ImageGallery/components/ProgressControl.js.map +1 -0
  112. package/lib/module/components/ImageGallery/hooks/useImageGalleryGestures.js +373 -0
  113. package/lib/module/components/ImageGallery/hooks/useImageGalleryGestures.js.map +1 -0
  114. package/lib/module/components/Message/Message.js +23 -13
  115. package/lib/module/components/Message/Message.js.map +1 -1
  116. package/lib/module/components/Message/MessageSimple/utils/renderText.js +22 -15
  117. package/lib/module/components/Message/MessageSimple/utils/renderText.js.map +1 -1
  118. package/lib/module/components/Message/hooks/useCreateMessageContext.js +4 -2
  119. package/lib/module/components/Message/hooks/useCreateMessageContext.js.map +1 -1
  120. package/lib/module/components/MessageOverlay/MessageOverlay.js +25 -23
  121. package/lib/module/components/MessageOverlay/MessageOverlay.js.map +1 -1
  122. package/lib/module/components/Reply/Reply.js +32 -12
  123. package/lib/module/components/Reply/Reply.js.map +1 -1
  124. package/lib/module/components/Spinner/Spinner.js +12 -4
  125. package/lib/module/components/Spinner/Spinner.js.map +1 -1
  126. package/lib/module/components/index.js +26 -0
  127. package/lib/module/components/index.js.map +1 -1
  128. package/lib/module/contexts/messageContext/MessageContext.js +2 -2
  129. package/lib/module/contexts/messageContext/MessageContext.js.map +1 -1
  130. package/lib/module/contexts/messageInputContext/MessageInputContext.js +15 -4
  131. package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  132. package/lib/module/contexts/messageOverlayContext/MessageOverlayContext.js +2 -2
  133. package/lib/module/contexts/messageOverlayContext/MessageOverlayContext.js.map +1 -1
  134. package/lib/module/contexts/messagesContext/MessagesContext.js +2 -2
  135. package/lib/module/contexts/messagesContext/MessagesContext.js.map +1 -1
  136. package/lib/module/contexts/themeContext/utils/theme.js +10 -1
  137. package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
  138. package/lib/module/icons/Pause.js +61 -0
  139. package/lib/module/icons/Pause.js.map +1 -0
  140. package/lib/module/icons/Play.js +42 -0
  141. package/lib/module/icons/Play.js.map +1 -0
  142. package/lib/module/icons/index.js +26 -0
  143. package/lib/module/icons/index.js.map +1 -1
  144. package/lib/module/mock-builders/api/queryMembers.js +98 -1
  145. package/lib/module/mock-builders/api/queryMembers.js.map +1 -1
  146. package/lib/module/native.js +7 -1
  147. package/lib/module/native.js.map +1 -1
  148. package/lib/module/utils/getUrlOfImageAttachment.js +1 -1
  149. package/lib/module/utils/getUrlOfImageAttachment.js.map +1 -1
  150. package/lib/module/version.json +1 -1
  151. package/lib/typescript/components/Attachment/Gallery.d.ts +1 -1
  152. package/lib/typescript/components/Attachment/VideoThumbnail.d.ts +4 -0
  153. package/lib/typescript/components/Attachment/utils/buildGallery/types.d.ts +1 -0
  154. package/lib/typescript/components/Attachment/utils/getAspectRatio.d.ts +1 -1
  155. package/lib/typescript/components/Channel/Channel.d.ts +1 -1
  156. package/lib/typescript/components/Channel/hooks/useCreateMessagesContext.d.ts +1 -1
  157. package/lib/typescript/components/ChannelPreview/hooks/__tests__/useChannelPreviewDisplayName.test.d.ts +1 -0
  158. package/lib/typescript/components/ChannelPreview/hooks/useChannelPreviewDisplayName.d.ts +4 -4
  159. package/lib/typescript/components/Chat/hooks/useIsOnline.d.ts +1 -1
  160. package/lib/typescript/components/ImageGallery/ImageGallery.d.ts +2 -0
  161. package/lib/typescript/components/ImageGallery/components/AnimatedGalleryVideo.d.ts +27 -0
  162. package/lib/typescript/components/ImageGallery/components/ImageGalleryFooter.d.ts +18 -2
  163. package/lib/typescript/components/ImageGallery/components/ImageGalleryVideoControl.d.ts +3 -0
  164. package/lib/typescript/components/ImageGallery/components/ProgressControl.d.ts +5 -0
  165. package/lib/typescript/components/ImageGallery/hooks/useImageGalleryGestures.d.ts +36 -0
  166. package/lib/typescript/components/Message/Message.d.ts +9 -3
  167. package/lib/typescript/components/Message/hooks/useCreateMessageContext.d.ts +1 -1
  168. package/lib/typescript/components/Spinner/Spinner.d.ts +7 -1
  169. package/lib/typescript/components/index.d.ts +2 -0
  170. package/lib/typescript/contexts/messageContext/MessageContext.d.ts +3 -1
  171. package/lib/typescript/contexts/messageOverlayContext/MessageOverlayContext.d.ts +1 -0
  172. package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts +2 -0
  173. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +9 -0
  174. package/lib/typescript/icons/Pause.d.ts +3 -0
  175. package/lib/typescript/icons/Play.d.ts +3 -0
  176. package/lib/typescript/icons/index.d.ts +2 -0
  177. package/lib/typescript/mock-builders/api/queryMembers.d.ts +161 -0
  178. package/lib/typescript/mock-builders/api/utils.d.ts +7 -0
  179. package/lib/typescript/mock-builders/generator/user.d.ts +30 -0
  180. package/lib/typescript/mock-builders/mock.d.ts +3 -0
  181. package/lib/typescript/native.d.ts +66 -1
  182. package/package.json +1 -1
  183. package/src/components/Attachment/Attachment.tsx +11 -7
  184. package/src/components/Attachment/Card.tsx +3 -0
  185. package/src/components/Attachment/Gallery.tsx +75 -36
  186. package/src/components/Attachment/VideoThumbnail.tsx +45 -0
  187. package/src/components/Attachment/hooks/useGoToURL.ts +1 -1
  188. package/src/components/Attachment/utils/buildGallery/buildThumbnail.ts +1 -0
  189. package/src/components/Attachment/utils/buildGallery/types.ts +1 -0
  190. package/src/components/Attachment/utils/getAspectRatio.ts +7 -5
  191. package/src/components/Channel/Channel.tsx +4 -0
  192. package/src/components/Channel/hooks/useCreateMessagesContext.ts +2 -0
  193. package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewDisplayName.test.tsx +83 -0
  194. package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayName.ts +43 -26
  195. package/src/components/Chat/hooks/useIsOnline.ts +7 -7
  196. package/src/components/ImageGallery/ImageGallery.tsx +145 -667
  197. package/src/components/ImageGallery/components/AnimatedGalleryImage.tsx +4 -4
  198. package/src/components/ImageGallery/components/AnimatedGalleryVideo.tsx +224 -0
  199. package/src/components/ImageGallery/components/ImageGalleryFooter.tsx +114 -19
  200. package/src/components/ImageGallery/components/ImageGalleryVideoControl.tsx +103 -0
  201. package/src/components/ImageGallery/components/ImageGrid.tsx +12 -25
  202. package/src/components/ImageGallery/components/ProgressControl.tsx +107 -0
  203. package/src/components/ImageGallery/hooks/useImageGalleryGestures.tsx +722 -0
  204. package/src/components/Message/Message.tsx +18 -7
  205. package/src/components/Message/MessageSimple/utils/renderText.tsx +6 -1
  206. package/src/components/Message/hooks/useCreateMessageContext.ts +2 -0
  207. package/src/components/MessageOverlay/MessageOverlay.tsx +2 -0
  208. package/src/components/Reply/Reply.tsx +36 -23
  209. package/src/components/Spinner/Spinner.tsx +11 -4
  210. package/src/components/index.ts +2 -0
  211. package/src/contexts/messageContext/MessageContext.tsx +2 -0
  212. package/src/contexts/messageInputContext/MessageInputContext.tsx +11 -0
  213. package/src/contexts/messageOverlayContext/MessageOverlayContext.tsx +1 -0
  214. package/src/contexts/messagesContext/MessagesContext.tsx +2 -0
  215. package/src/contexts/themeContext/utils/theme.ts +18 -0
  216. package/src/icons/Pause.tsx +14 -0
  217. package/src/icons/Play.tsx +17 -0
  218. package/src/icons/index.ts +2 -0
  219. package/src/mock-builders/api/queryMembers.js +98 -0
  220. package/src/native.ts +59 -1
  221. package/src/utils/getUrlOfImageAttachment.ts +1 -1
  222. 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 { triggerHaptic } from '../../native';
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, setOverlay, translucentStatusBar } = useOverlayContext();
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(() => [(screenHeight * 9) / 10], []);
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
- Image.getSize(photo.uri, (width, height) => {
396
- const imageHeight = Math.floor(height * (screenWidth / width));
397
- setCurrentImageHeight(imageHeight > screenHeight ? screenHeight : imageHeight);
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
- * We use simultaneousHandlers to allow pan and pinch gesture handlers
404
- * depending on the gesture. The touch is fully handled by the pinch
405
- * gesture handler once it has began so all interactions by the pan
406
- * handler are blocked if isPinch.value is true
407
- */
408
- const onPan = useAnimatedGestureHandler<PanGestureHandlerGestureEvent>(
409
- {
410
- onActive: (evt) => {
411
- if (evt.numberOfPointers === 1 && !isPinch.value) {
412
- /**
413
- * If Android where a second finger cannot be added back and
414
- * removing one finger returns to Pan Handler then adjust origin
415
- * on finger remove and set swiping false
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
- <AnimatedGalleryImage
1103
- index={i}
1104
- key={`${photo.uri}-${i}`}
1105
- offsetScale={offsetScale}
1106
- photo={photo}
1107
- previous={selectedIndex > i}
1108
- scale={scale}
1109
- screenHeight={screenHeight}
1110
- selected={selectedIndex === i}
1111
- shouldRender={Math.abs(selectedIndex - i) < 4}
1112
- style={[
1113
- {
1114
- height: screenHeight * 8,
1115
- marginRight: MARGIN,
1116
- width: screenWidth * 8,
1117
- },
1118
- slide,
1119
- ]}
1120
- translateX={translateX}
1121
- translateY={translateY}
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
  };