about summary refs log tree commit diff
path: root/src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts')
-rw-r--r--src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts423
1 files changed, 0 insertions, 423 deletions
diff --git a/src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts b/src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts
deleted file mode 100644
index 85454e37e..000000000
--- a/src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts
+++ /dev/null
@@ -1,423 +0,0 @@
-/**
- * Copyright (c) JOB TODAY S.A. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- */
-
-import {useEffect} from 'react'
-import {
-  Animated,
-  Dimensions,
-  GestureResponderEvent,
-  GestureResponderHandlers,
-  NativeTouchEvent,
-  PanResponder,
-  PanResponderGestureState,
-} from 'react-native'
-
-import {Position} from '../@types'
-import {getImageTranslate} from '../utils'
-
-const SCREEN = Dimensions.get('window')
-const SCREEN_WIDTH = SCREEN.width
-const SCREEN_HEIGHT = SCREEN.height
-const ANDROID_BAR_HEIGHT = 24
-
-const MIN_ZOOM = 2
-const MAX_SCALE = 2
-const DOUBLE_TAP_DELAY = 300
-const OUT_BOUND_MULTIPLIER = 0.75
-
-type Props = {
-  initialScale: number
-  initialTranslate: Position
-  onZoom: (isZoomed: boolean) => void
-}
-
-const usePanResponder = ({
-  initialScale,
-  initialTranslate,
-  onZoom,
-}: Props): Readonly<
-  [GestureResponderHandlers, Animated.Value, Animated.ValueXY]
-> => {
-  let numberInitialTouches = 1
-  let initialTouches: NativeTouchEvent[] = []
-  let currentScale = initialScale
-  let currentTranslate = initialTranslate
-  let tmpScale = 0
-  let tmpTranslate: Position | null = null
-  let isDoubleTapPerformed = false
-  let lastTapTS: number | null = null
-
-  // TODO: It's not valid to reinitialize Animated values during render.
-  // This is a bug.
-  const scaleValue = new Animated.Value(initialScale)
-  const translateValue = new Animated.ValueXY(initialTranslate)
-
-  const imageDimensions = getImageDimensionsByTranslate(
-    initialTranslate,
-    SCREEN,
-  )
-
-  const getBounds = (scale: number) => {
-    const scaledImageDimensions = {
-      width: imageDimensions.width * scale,
-      height: imageDimensions.height * scale,
-    }
-    const translateDelta = getImageTranslate(scaledImageDimensions, SCREEN)
-
-    const left = initialTranslate.x - translateDelta.x
-    const right = left - (scaledImageDimensions.width - SCREEN.width)
-    const top = initialTranslate.y - translateDelta.y
-    const bottom = top - (scaledImageDimensions.height - SCREEN.height)
-
-    return [top, left, bottom, right]
-  }
-
-  const getTransformAfterDoubleTap = (
-    touchX: number,
-    touchY: number,
-  ): [number, Position] => {
-    let nextScale = initialScale
-    let nextTranslateX = initialTranslate.x
-    let nextTranslateY = initialTranslate.y
-
-    // First, let's figure out how much we want to zoom in.
-    // We want to try to zoom in at least close enough to get rid of black bars.
-    const imageAspect = imageDimensions.width / imageDimensions.height
-    const screenAspect = SCREEN.width / SCREEN.height
-    let zoom = Math.max(
-      imageAspect / screenAspect,
-      screenAspect / imageAspect,
-      MIN_ZOOM,
-    )
-    // Don't zoom so hard that the original image's pixels become blurry.
-    zoom = Math.min(zoom, MAX_SCALE / initialScale)
-    nextScale = initialScale * zoom
-
-    // Next, let's see if we need to adjust the scaled image translation.
-    // Ideally, we want the tapped point to stay under the finger after the scaling.
-    const dx = SCREEN.width / 2 - touchX
-    const dy = SCREEN.height / 2 - (touchY - ANDROID_BAR_HEIGHT)
-    // Before we try to adjust the translation, check how much wiggle room we have.
-    // We don't want to introduce new black bars or make existing black bars unbalanced.
-    const [topBound, leftBound, bottomBound, rightBound] = getBounds(nextScale)
-    if (leftBound > rightBound) {
-      // Content fills the screen horizontally so we have horizontal wiggle room.
-      // Try to keep the tapped point under the finger after zoom.
-      nextTranslateX += dx * zoom - dx
-      nextTranslateX = Math.min(nextTranslateX, leftBound)
-      nextTranslateX = Math.max(nextTranslateX, rightBound)
-    }
-    if (topBound > bottomBound) {
-      // Content fills the screen vertically so we have vertical wiggle room.
-      // Try to keep the tapped point under the finger after zoom.
-      nextTranslateY += dy * zoom - dy
-      nextTranslateY = Math.min(nextTranslateY, topBound)
-      nextTranslateY = Math.max(nextTranslateY, bottomBound)
-    }
-
-    return [
-      nextScale,
-      {
-        x: nextTranslateX,
-        y: nextTranslateY,
-      },
-    ]
-  }
-
-  const fitsScreenByWidth = () =>
-    imageDimensions.width * currentScale < SCREEN_WIDTH
-  const fitsScreenByHeight = () =>
-    imageDimensions.height * currentScale < SCREEN_HEIGHT
-
-  useEffect(() => {
-    scaleValue.addListener(({value}) => {
-      if (typeof onZoom === 'function') {
-        onZoom(value !== initialScale)
-      }
-    })
-
-    return () => scaleValue.removeAllListeners()
-  })
-
-  const panResponder = PanResponder.create({
-    onStartShouldSetPanResponder: () => true,
-    onStartShouldSetPanResponderCapture: () => true,
-    onMoveShouldSetPanResponder: () => true,
-    onMoveShouldSetPanResponderCapture: () => true,
-    onPanResponderGrant: (
-      _: GestureResponderEvent,
-      gestureState: PanResponderGestureState,
-    ) => {
-      numberInitialTouches = gestureState.numberActiveTouches
-
-      if (gestureState.numberActiveTouches > 1) {
-        return
-      }
-    },
-    onPanResponderStart: (
-      event: GestureResponderEvent,
-      gestureState: PanResponderGestureState,
-    ) => {
-      initialTouches = event.nativeEvent.touches
-      numberInitialTouches = gestureState.numberActiveTouches
-
-      if (gestureState.numberActiveTouches > 1) {
-        return
-      }
-
-      const tapTS = Date.now()
-      // Handle double tap event by calculating diff between first and second taps timestamps
-
-      isDoubleTapPerformed = Boolean(
-        lastTapTS && tapTS - lastTapTS < DOUBLE_TAP_DELAY,
-      )
-
-      if (isDoubleTapPerformed) {
-        let nextScale = initialScale
-        let nextTranslate = initialTranslate
-
-        const willZoom = currentScale === initialScale
-        if (willZoom) {
-          const {pageX: touchX, pageY: touchY} = event.nativeEvent.touches[0]
-          ;[nextScale, nextTranslate] = getTransformAfterDoubleTap(
-            touchX,
-            touchY,
-          )
-        }
-        onZoom(willZoom)
-
-        Animated.parallel(
-          [
-            Animated.timing(translateValue.x, {
-              toValue: nextTranslate.x,
-              duration: 300,
-              useNativeDriver: true,
-            }),
-            Animated.timing(translateValue.y, {
-              toValue: nextTranslate.y,
-              duration: 300,
-              useNativeDriver: true,
-            }),
-            Animated.timing(scaleValue, {
-              toValue: nextScale,
-              duration: 300,
-              useNativeDriver: true,
-            }),
-          ],
-          {stopTogether: false},
-        ).start(() => {
-          currentScale = nextScale
-          currentTranslate = nextTranslate
-        })
-
-        lastTapTS = null
-      } else {
-        lastTapTS = Date.now()
-      }
-    },
-    onPanResponderMove: (
-      event: GestureResponderEvent,
-      gestureState: PanResponderGestureState,
-    ) => {
-      // Don't need to handle move because double tap in progress (was handled in onStart)
-      if (isDoubleTapPerformed) {
-        return
-      }
-
-      if (
-        numberInitialTouches === 1 &&
-        gestureState.numberActiveTouches === 2
-      ) {
-        numberInitialTouches = 2
-        initialTouches = event.nativeEvent.touches
-      }
-
-      const isTapGesture =
-        numberInitialTouches === 1 && gestureState.numberActiveTouches === 1
-      const isPinchGesture =
-        numberInitialTouches === 2 && gestureState.numberActiveTouches === 2
-
-      if (isPinchGesture) {
-        const initialDistance = getDistanceBetweenTouches(initialTouches)
-        const currentDistance = getDistanceBetweenTouches(
-          event.nativeEvent.touches,
-        )
-
-        let nextScale = (currentDistance / initialDistance) * currentScale
-
-        /**
-         * In case image is scaling smaller than initial size ->
-         * slow down this transition by applying OUT_BOUND_MULTIPLIER
-         */
-        if (nextScale < initialScale) {
-          nextScale =
-            nextScale + (initialScale - nextScale) * OUT_BOUND_MULTIPLIER
-        }
-
-        /**
-         * In case image is scaling down -> move it in direction of initial position
-         */
-        if (currentScale > initialScale && currentScale > nextScale) {
-          const k = (currentScale - initialScale) / (currentScale - nextScale)
-
-          const nextTranslateX =
-            nextScale < initialScale
-              ? initialTranslate.x
-              : currentTranslate.x -
-                (currentTranslate.x - initialTranslate.x) / k
-
-          const nextTranslateY =
-            nextScale < initialScale
-              ? initialTranslate.y
-              : currentTranslate.y -
-                (currentTranslate.y - initialTranslate.y) / k
-
-          translateValue.x.setValue(nextTranslateX)
-          translateValue.y.setValue(nextTranslateY)
-
-          tmpTranslate = {x: nextTranslateX, y: nextTranslateY}
-        }
-
-        scaleValue.setValue(nextScale)
-        tmpScale = nextScale
-      }
-
-      if (isTapGesture && currentScale > initialScale) {
-        const {x, y} = currentTranslate
-
-        const {dx, dy} = gestureState
-        const [topBound, leftBound, bottomBound, rightBound] =
-          getBounds(currentScale)
-
-        let nextTranslateX = x + dx
-        let nextTranslateY = y + dy
-
-        if (nextTranslateX > leftBound) {
-          nextTranslateX =
-            nextTranslateX - (nextTranslateX - leftBound) * OUT_BOUND_MULTIPLIER
-        }
-
-        if (nextTranslateX < rightBound) {
-          nextTranslateX =
-            nextTranslateX -
-            (nextTranslateX - rightBound) * OUT_BOUND_MULTIPLIER
-        }
-
-        if (nextTranslateY > topBound) {
-          nextTranslateY =
-            nextTranslateY - (nextTranslateY - topBound) * OUT_BOUND_MULTIPLIER
-        }
-
-        if (nextTranslateY < bottomBound) {
-          nextTranslateY =
-            nextTranslateY -
-            (nextTranslateY - bottomBound) * OUT_BOUND_MULTIPLIER
-        }
-
-        if (fitsScreenByWidth()) {
-          nextTranslateX = x
-        }
-
-        if (fitsScreenByHeight()) {
-          nextTranslateY = y
-        }
-
-        translateValue.x.setValue(nextTranslateX)
-        translateValue.y.setValue(nextTranslateY)
-
-        tmpTranslate = {x: nextTranslateX, y: nextTranslateY}
-      }
-    },
-    onPanResponderRelease: () => {
-      if (isDoubleTapPerformed) {
-        isDoubleTapPerformed = false
-      }
-
-      if (tmpScale > 0) {
-        if (tmpScale < initialScale || tmpScale > MAX_SCALE) {
-          tmpScale = tmpScale < initialScale ? initialScale : MAX_SCALE
-          Animated.timing(scaleValue, {
-            toValue: tmpScale,
-            duration: 100,
-            useNativeDriver: true,
-          }).start()
-        }
-
-        currentScale = tmpScale
-        tmpScale = 0
-      }
-
-      if (tmpTranslate) {
-        const {x, y} = tmpTranslate
-        const [topBound, leftBound, bottomBound, rightBound] =
-          getBounds(currentScale)
-
-        let nextTranslateX = x
-        let nextTranslateY = y
-
-        if (!fitsScreenByWidth()) {
-          if (nextTranslateX > leftBound) {
-            nextTranslateX = leftBound
-          } else if (nextTranslateX < rightBound) {
-            nextTranslateX = rightBound
-          }
-        }
-
-        if (!fitsScreenByHeight()) {
-          if (nextTranslateY > topBound) {
-            nextTranslateY = topBound
-          } else if (nextTranslateY < bottomBound) {
-            nextTranslateY = bottomBound
-          }
-        }
-
-        Animated.parallel([
-          Animated.timing(translateValue.x, {
-            toValue: nextTranslateX,
-            duration: 100,
-            useNativeDriver: true,
-          }),
-          Animated.timing(translateValue.y, {
-            toValue: nextTranslateY,
-            duration: 100,
-            useNativeDriver: true,
-          }),
-        ]).start()
-
-        currentTranslate = {x: nextTranslateX, y: nextTranslateY}
-        tmpTranslate = null
-      }
-    },
-    onPanResponderTerminationRequest: () => false,
-    onShouldBlockNativeResponder: () => false,
-  })
-
-  return [panResponder.panHandlers, scaleValue, translateValue]
-}
-
-const getImageDimensionsByTranslate = (
-  translate: Position,
-  screen: {width: number; height: number},
-): {width: number; height: number} => ({
-  width: screen.width - translate.x * 2,
-  height: screen.height - translate.y * 2,
-})
-
-const getDistanceBetweenTouches = (touches: NativeTouchEvent[]): number => {
-  const [a, b] = touches
-
-  if (a == null || b == null) {
-    return 0
-  }
-
-  return Math.sqrt(
-    Math.pow(a.pageX - b.pageX, 2) + Math.pow(a.pageY - b.pageY, 2),
-  )
-}
-
-export default usePanResponder