From eb33c3fa812cc087db14a6b6ba743e982b26c462 Mon Sep 17 00:00:00 2001 From: Aryan Goharzad Date: Wed, 25 Jan 2023 18:25:34 -0500 Subject: Saves image on long press (#83) * Saves image on long press * Adds save on long press * Forking lightbox * move to wrapper only to the bottom sheet to reduce impact of this change * lint * lint * lint * Use official `share` API * Clean up cache after download * comment * comment * Reduce swipe close velocity * Updates per feedback * lint * bugfix * Adds delayed press-in for TouchableOpacity --- .../components/ImageItem/ImageItem.ios.tsx | 152 +++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx (limited to 'src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx') diff --git a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx new file mode 100644 index 000000000..12d37e283 --- /dev/null +++ b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx @@ -0,0 +1,152 @@ +/** + * 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 React, {useCallback, useRef, useState} from 'react' + +import { + Animated, + Dimensions, + ScrollView, + StyleSheet, + View, + NativeScrollEvent, + NativeSyntheticEvent, + TouchableWithoutFeedback, +} from 'react-native' + +import useDoubleTapToZoom from '../../hooks/useDoubleTapToZoom' +import useImageDimensions from '../../hooks/useImageDimensions' + +import {getImageStyles, getImageTransform} from '../../utils' +import {ImageSource} from '../../@types' +import {ImageLoading} from './ImageLoading' + +const SWIPE_CLOSE_OFFSET = 75 +const SWIPE_CLOSE_VELOCITY = 1 +const SCREEN = Dimensions.get('screen') +const SCREEN_WIDTH = SCREEN.width +const SCREEN_HEIGHT = SCREEN.height + +type Props = { + imageSrc: ImageSource + onRequestClose: () => void + onZoom: (scaled: boolean) => void + onLongPress: (image: ImageSource) => void + delayLongPress: number + swipeToCloseEnabled?: boolean + doubleTapToZoomEnabled?: boolean +} + +const ImageItem = ({ + imageSrc, + onZoom, + onRequestClose, + onLongPress, + delayLongPress, + swipeToCloseEnabled = true, + doubleTapToZoomEnabled = true, +}: Props) => { + const scrollViewRef = useRef(null) + const [loaded, setLoaded] = useState(false) + const [scaled, setScaled] = useState(false) + const imageDimensions = useImageDimensions(imageSrc) + const handleDoubleTap = useDoubleTapToZoom(scrollViewRef, scaled, SCREEN) + + const [translate, scale] = getImageTransform(imageDimensions, SCREEN) + const scrollValueY = new Animated.Value(0) + const scaleValue = new Animated.Value(scale || 1) + const translateValue = new Animated.ValueXY(translate) + const maxScale = scale && scale > 0 ? Math.max(1 / scale, 1) : 1 + + const imageOpacity = scrollValueY.interpolate({ + inputRange: [-SWIPE_CLOSE_OFFSET, 0, SWIPE_CLOSE_OFFSET], + outputRange: [0.5, 1, 0.5], + }) + const imagesStyles = getImageStyles( + imageDimensions, + translateValue, + scaleValue, + ) + const imageStylesWithOpacity = {...imagesStyles, opacity: imageOpacity} + + const onScrollEndDrag = useCallback( + ({nativeEvent}: NativeSyntheticEvent) => { + const velocityY = nativeEvent?.velocity?.y ?? 0 + const currentScaled = nativeEvent?.zoomScale > 1 + + onZoom(currentScaled) + setScaled(currentScaled) + + if ( + !currentScaled && + swipeToCloseEnabled && + Math.abs(velocityY) > SWIPE_CLOSE_VELOCITY + ) { + onRequestClose() + } + }, + [onRequestClose, onZoom, swipeToCloseEnabled], + ) + + const onScroll = ({nativeEvent}: NativeSyntheticEvent) => { + const offsetY = nativeEvent?.contentOffset?.y ?? 0 + + if (nativeEvent?.zoomScale > 1) { + return + } + + scrollValueY.setValue(offsetY) + } + + const onLongPressHandler = useCallback(() => { + onLongPress(imageSrc) + }, [imageSrc, onLongPress]) + + return ( + + + {(!loaded || !imageDimensions) && } + + setLoaded(true)} + /> + + + + ) +} + +const styles = StyleSheet.create({ + listItem: { + width: SCREEN_WIDTH, + height: SCREEN_HEIGHT, + }, + imageScrollContainer: { + height: SCREEN_HEIGHT, + }, +}) + +export default React.memo(ImageItem) -- cgit 1.4.1