/**
* 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, useMemo, useState} from 'react'
import {Animated, StyleSheet, View, ModalProps, Platform} from 'react-native'
import ImageItem from './components/ImageItem/ImageItem'
import ImageDefaultHeader from './components/ImageDefaultHeader'
import {ImageSource} from './@types'
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
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,
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 [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 onZoom = (nextIsScaled: boolean) => {
toggleBarsVisible(!nextIsScaled)
setIsScaled(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
}
const headerTransform = headerTranslate.getTranslateTransform()
const footerTransform = footerTranslate.getTranslateTransform()
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) => (
)
export default EnhancedImageViewing