import analytics from '@components/analytics' import GracefullyImage from '@components/GracefullyImage' import { HeaderCenter, HeaderLeft, HeaderRight } from '@components/Header' import { useActionSheet } from '@expo/react-native-action-sheet' import { RootStackScreenProps } from '@utils/navigation/navigators' import { useTheme } from '@utils/styles/ThemeManager' import React, { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { Dimensions, FlatList, PixelRatio, Platform, Share, StatusBar, View, ViewToken } from 'react-native' import { Directions, Gesture, LongPressGestureHandler } from 'react-native-gesture-handler' import { LiveTextImageView } from 'react-native-live-text-image-view' import { runOnJS, useSharedValue } from 'react-native-reanimated' import { Zoom, createZoomListComponent } from 'react-native-reanimated-zoom' import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context' import saveImage from './ImageViewer/save' const ZoomFlatList = createZoomListComponent(FlatList) const ScreenImagesViewer = ({ route: { params: { imageUrls, id } }, navigation }: RootStackScreenProps<'Screen-ImagesViewer'>) => { if (imageUrls.length === 0) { navigation.goBack() return null } const SCREEN_WIDTH = Dimensions.get('screen').width const SCREEN_HEIGHT = Dimensions.get('screen').height const insets = useSafeAreaInsets() const { mode, theme } = useTheme() const { t } = useTranslation('screenImageViewer') const initialIndex = imageUrls.findIndex(image => image.id === id) const [currentIndex, setCurrentIndex] = useState(initialIndex) const { showActionSheetWithOptions } = useActionSheet() const onPress = useCallback(() => { analytics('imageviewer_more_press') showActionSheetWithOptions( { options: [ t('content.options.save'), t('content.options.share'), t('content.options.cancel') ], cancelButtonIndex: 2, userInterfaceStyle: mode }, async buttonIndex => { switch (buttonIndex) { case 0: analytics('imageviewer_more_save_press') saveImage({ theme, image: imageUrls[currentIndex] }) break case 1: analytics('imageviewer_more_share_press') switch (Platform.OS) { case 'ios': await Share.share({ url: imageUrls[currentIndex].url }) break case 'android': await Share.share({ message: imageUrls[currentIndex].url }) break } break } } ) }, [currentIndex]) const isZoomed = useSharedValue(false) const renderItem = React.useCallback( ({ item }: { item: RootStackScreenProps<'Screen-ImagesViewer'>['route']['params']['imageUrls'][0] }) => { const screenRatio = SCREEN_WIDTH / SCREEN_HEIGHT const imageRatio = item.width && item.height ? item.width / item.height : 1 const imageWidth = item.width || 100 const imageHeight = item.height || 100 const maxWidthScale = item.width ? (item.width / SCREEN_WIDTH / PixelRatio.get()) * 4 : 0 const maxHeightScale = item.height ? (item.height / SCREEN_WIDTH / PixelRatio.get()) * 4 : 0 const max = Math.max.apply(Math, [maxWidthScale, maxHeightScale, 4]) return ( (isZoomed.value = true)} onZoomEnd={() => (isZoomed.value = false)} maximumZoomScale={max > 8 ? 8 : max} simultaneousGesture={Gesture.Fling() .direction(Directions.DOWN) .onStart(() => { if (isZoomed.value === false) { runOnJS(navigation.goBack)() } })} children={ imageRatio ? (SCREEN_HEIGHT / imageHeight) * imageWidth : SCREEN_WIDTH, height: screenRatio > imageRatio ? SCREEN_HEIGHT : (SCREEN_WIDTH / imageWidth) * imageHeight }} /> } /> ) }, [isZoomed.value] ) const onViewableItemsChanged = useCallback( ({ viewableItems }: { viewableItems: ViewToken[] }) => { setCurrentIndex(viewableItems[0]?.index || 0) }, [] ) return ( ) } export default ScreenImagesViewer