/**
* 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.
*
*/
// 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, 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'
type Props = {
images: ImageSource[]
initialImageIndex: number
visible: boolean
onRequestClose: () => void
backgroundColor?: string
HeaderComponent?: ComponentType<{imageIndex: number}>
FooterComponent?: ComponentType<{imageIndex: number}>
}
const DEFAULT_BG_COLOR = '#000'
function ImageViewing({
images,
initialImageIndex,
visible,
onRequestClose,
backgroundColor = DEFAULT_BG_COLOR,
HeaderComponent,
FooterComponent,
}: Props) {
const [isScaled, setIsScaled] = useState(false)
const [isDragging, setIsDragging] = useState(false)
const [imageIndex, setImageIndex] = useState(initialImageIndex)
const [showControls, setShowControls] = useState(true)
const animatedHeaderStyle = useAnimatedStyle(() => ({
pointerEvents: showControls ? 'auto' : 'none',
opacity: withClampedSpring(showControls ? 1 : 0),
transform: [
{
translateY: withClampedSpring(showControls ? 0 : -30),
},
],
}))
const animatedFooterStyle = useAnimatedStyle(() => ({
pointerEvents: showControls ? 'auto' : 'none',
opacity: withClampedSpring(showControls ? 1 : 0),
transform: [
{
translateY: withClampedSpring(showControls ? 0 : 30),
},
],
}))
const onTap = useCallback(() => {
setShowControls(show => !show)
}, [])
const onZoom = useCallback((nextIsScaled: boolean) => {
setIsScaled(nextIsScaled)
if (nextIsScaled) {
setShowControls(false)
}
}, [])
const edges = useMemo(() => {
if (Platform.OS === 'android') {
return ['top', 'bottom', 'left', 'right'] satisfies Edge[]
}
return ['left', 'right'] satisfies Edge[] // iOS, so no top/bottom safe area
}, [])
if (!visible) {
return null
}
return (
{typeof HeaderComponent !== 'undefined' ? (
React.createElement(HeaderComponent, {
imageIndex,
})
) : (
)}
{
setImageIndex(e.nativeEvent.position)
setIsScaled(false)
}}
onPageScrollStateChanged={e => {
setIsDragging(e.nativeEvent.pageScrollState !== 'idle')
}}
overdrag={true}
style={styles.pager}>
{images.map(imageSrc => (
))}
{typeof FooterComponent !== 'undefined' && (
{React.createElement(FooterComponent, {
imageIndex,
})}
)}
)
}
const styles = StyleSheet.create({
screen: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
container: {
flex: 1,
backgroundColor: '#000',
},
pager: {
flex: 1,
},
header: {
position: 'absolute',
width: '100%',
zIndex: 1,
top: 0,
pointerEvents: 'box-none',
},
footer: {
position: 'absolute',
width: '100%',
zIndex: 1,
bottom: 0,
},
})
const EnhancedImageViewing = (props: Props) => (
)
function withClampedSpring(value: any) {
'worklet'
return withSpring(value, {overshootClamping: true, stiffness: 300})
}
export default EnhancedImageViewing