From a48c213af585f43a1e6414ed0bf6c8d1552565d8 Mon Sep 17 00:00:00 2001
From: dan <dan.abramov@gmail.com>
Date: Tue, 10 Oct 2023 23:48:31 +0100
Subject: Port remaining lightbox code to Reanimated (#1669)

* Port remaining lightbox code to Reanimated

* Fix  memoization
---
 src/view/com/lightbox/ImageViewing/index.tsx | 69 +++++++++++-----------------
 1 file changed, 27 insertions(+), 42 deletions(-)

(limited to 'src/view/com/lightbox/ImageViewing/index.tsx')

diff --git a/src/view/com/lightbox/ImageViewing/index.tsx b/src/view/com/lightbox/ImageViewing/index.tsx
index 631a6ca0c..78d16f8a6 100644
--- a/src/view/com/lightbox/ImageViewing/index.tsx
+++ b/src/view/com/lightbox/ImageViewing/index.tsx
@@ -8,13 +8,14 @@
 // Original code copied and simplified from the link below as the codebase is currently not maintained:
 // https://github.com/jobtoday/react-native-image-viewing
 
-import React, {ComponentType, useMemo, useState} from 'react'
-import {Animated, StyleSheet, View, ModalProps, Platform} from 'react-native'
+import React, {ComponentType, useCallback, useMemo, useState} from 'react'
+import {StyleSheet, View, Platform} from 'react-native'
 
 import ImageItem from './components/ImageItem/ImageItem'
 import ImageDefaultHeader from './components/ImageDefaultHeader'
 
 import {ImageSource} from './@types'
+import Animated, {useAnimatedStyle, withSpring} from 'react-native-reanimated'
 import {Edge, SafeAreaView} from 'react-native-safe-area-context'
 import PagerView from 'react-native-pager-view'
 
@@ -23,19 +24,12 @@ type Props = {
   initialImageIndex: number
   visible: boolean
   onRequestClose: () => void
-  presentationStyle?: ModalProps['presentationStyle']
-  animationType?: ModalProps['animationType']
   backgroundColor?: string
   HeaderComponent?: ComponentType<{imageIndex: number}>
   FooterComponent?: ComponentType<{imageIndex: number}>
 }
 
 const DEFAULT_BG_COLOR = '#000'
-const INITIAL_POSITION = {x: 0, y: 0}
-const ANIMATION_CONFIG = {
-  duration: 200,
-  useNativeDriver: true,
-}
 
 function ImageViewing({
   images,
@@ -49,37 +43,25 @@ function ImageViewing({
   const [isScaled, setIsScaled] = useState(false)
   const [isDragging, setIsDragging] = useState(false)
   const [imageIndex, setImageIndex] = useState(initialImageIndex)
-  const [headerTranslate] = useState(
-    () => new Animated.ValueXY(INITIAL_POSITION),
-  )
-  const [footerTranslate] = useState(
-    () => new Animated.ValueXY(INITIAL_POSITION),
-  )
 
-  const toggleBarsVisible = (isVisible: boolean) => {
-    if (isVisible) {
-      Animated.parallel([
-        Animated.timing(headerTranslate.y, {...ANIMATION_CONFIG, toValue: 0}),
-        Animated.timing(footerTranslate.y, {...ANIMATION_CONFIG, toValue: 0}),
-      ]).start()
-    } else {
-      Animated.parallel([
-        Animated.timing(headerTranslate.y, {
-          ...ANIMATION_CONFIG,
-          toValue: -300,
-        }),
-        Animated.timing(footerTranslate.y, {
-          ...ANIMATION_CONFIG,
-          toValue: 300,
-        }),
-      ]).start()
-    }
-  }
+  const animatedHeaderStyle = useAnimatedStyle(() => ({
+    transform: [
+      {
+        translateY: withClampedSpring(isScaled ? -300 : 0),
+      },
+    ],
+  }))
+  const animatedFooterStyle = useAnimatedStyle(() => ({
+    transform: [
+      {
+        translateY: withClampedSpring(isScaled ? 300 : 0),
+      },
+    ],
+  }))
 
-  const onZoom = (nextIsScaled: boolean) => {
-    toggleBarsVisible(!nextIsScaled)
-    setIsScaled(false)
-  }
+  const onZoom = useCallback((nextIsScaled: boolean) => {
+    setIsScaled(nextIsScaled)
+  }, [])
 
   const edges = useMemo(() => {
     if (Platform.OS === 'android') {
@@ -92,8 +74,6 @@ function ImageViewing({
     return null
   }
 
-  const headerTransform = headerTranslate.getTranslateTransform()
-  const footerTransform = footerTranslate.getTranslateTransform()
   return (
     <SafeAreaView
       style={styles.screen}
@@ -101,7 +81,7 @@ function ImageViewing({
       aria-modal
       accessibilityViewIsModal>
       <View style={[styles.container, {backgroundColor}]}>
-        <Animated.View style={[styles.header, {transform: headerTransform}]}>
+        <Animated.View style={[styles.header, animatedHeaderStyle]}>
           {typeof HeaderComponent !== 'undefined' ? (
             React.createElement(HeaderComponent, {
               imageIndex,
@@ -134,7 +114,7 @@ function ImageViewing({
           ))}
         </PagerView>
         {typeof FooterComponent !== 'undefined' && (
-          <Animated.View style={[styles.footer, {transform: footerTransform}]}>
+          <Animated.View style={[styles.footer, animatedFooterStyle]}>
             {React.createElement(FooterComponent, {
               imageIndex,
             })}
@@ -179,4 +159,9 @@ const EnhancedImageViewing = (props: Props) => (
   <ImageViewing key={props.initialImageIndex} {...props} />
 )
 
+function withClampedSpring(value: any) {
+  'worklet'
+  return withSpring(value, {overshootClamping: true})
+}
+
 export default EnhancedImageViewing
-- 
cgit 1.4.1

