diff options
author | dan <dan.abramov@gmail.com> | 2024-11-08 02:49:32 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-08 02:49:32 +0000 |
commit | 5d0610d419906be0ef2c7c7ab0d1f66c366f3aed (patch) | |
tree | d120b486b15a3720691530264509cd2d11e51b87 /src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx | |
parent | 6570f56d8e22b22d099338c24731f525b860583a (diff) | |
download | voidsky-5d0610d419906be0ef2c7c7ab0d1f66c366f3aed.tar.zst |
[Lightbox] New dismiss gesture (#6135)
* Make iOS scrollview bounded to the image I've had to remove the dismiss handling because the scroll view no longer scrolls at rest. * Fix double-tap not working right after a vertical swipe It seems like for some reason the vertical swipe is still being handled by the scroll view, so double tap gets eaten while it's "coming back". But you don't really see it moving. Weird. * Add an intermediate LightboxImage component * Hoist useImageDimensions up * Implement xplat dismiss gesture This is now shared between platforms, letting us animate the backdrop and add a consistent "fly away" behavior. * Optimize Android compositing perf * Fix supertall images For example, https://bsky.app/profile/schlagteslinks.bsky.social/post/3l7y4l6yur72e * Fix oopsie
Diffstat (limited to 'src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx')
-rw-r--r-- | src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx | 95 |
1 files changed, 44 insertions, 51 deletions
diff --git a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx index a17d4fe66..b4bbfb4d5 100644 --- a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx +++ b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx @@ -7,26 +7,27 @@ */ import React, {useState} from 'react' -import {ActivityIndicator, StyleSheet, View} from 'react-native' -import {Gesture, GestureDetector} from 'react-native-gesture-handler' +import {ActivityIndicator, StyleProp, StyleSheet, View} from 'react-native' +import { + Gesture, + GestureDetector, + PanGesture, +} from 'react-native-gesture-handler' import Animated, { AnimatedRef, - interpolate, measure, runOnJS, useAnimatedRef, useAnimatedStyle, - useSharedValue, } from 'react-native-reanimated' import {useSafeAreaFrame} from 'react-native-safe-area-context' -import {Image} from 'expo-image' +import {Image, ImageStyle} from 'expo-image' import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED' -import {useImageDimensions} from '#/lib/media/image-sizes' -import {ImageSource} from '../../@types' +import {Dimensions as ImageDimensions, ImageSource} from '../../@types' + +const AnimatedImage = Animated.createAnimatedComponent(Image) -const SWIPE_CLOSE_OFFSET = 75 -const SWIPE_CLOSE_VELOCITY = 1 const MAX_ORIGINAL_IMAGE_ZOOM = 2 const MIN_SCREEN_ZOOM = 2 @@ -38,24 +39,26 @@ type Props = { isScrollViewBeingDragged: boolean showControls: boolean safeAreaRef: AnimatedRef<View> + imageAspect: number | undefined + imageDimensions: ImageDimensions | undefined + imageStyle: StyleProp<ImageStyle> + dismissSwipePan: PanGesture } const ImageItem = ({ imageSrc, onTap, onZoom, - onRequestClose, showControls, safeAreaRef, + imageAspect, + imageDimensions, + imageStyle, + dismissSwipePan, }: Props) => { const scrollViewRef = useAnimatedRef<Animated.ScrollView>() - const translationY = useSharedValue(0) const [scaled, setScaled] = useState(false) const screenSizeDelayedForJSThreadOnly = useSafeAreaFrame() - const [imageAspect, imageDimensions] = useImageDimensions({ - src: imageSrc.uri, - knownDimensions: imageSrc.dimensions, - }) const maxZoomScale = Math.max( MIN_SCREEN_ZOOM, imageDimensions @@ -65,33 +68,21 @@ const ImageItem = ({ ) const animatedStyle = useAnimatedStyle(() => { + const screenSize = measure(safeAreaRef) ?? screenSizeDelayedForJSThreadOnly return { - flex: 1, - opacity: interpolate( - translationY.value, - [-SWIPE_CLOSE_OFFSET, 0, SWIPE_CLOSE_OFFSET], - [0.5, 1, 0.5], - ), + width: screenSize.width, + maxHeight: screenSize.height, + alignSelf: 'center', + aspectRatio: imageAspect, } }) const scrollHandler = useAnimatedScrollHandler({ onScroll(e) { const nextIsScaled = e.zoomScale > 1 - translationY.value = nextIsScaled ? 0 : e.contentOffset.y - if (scaled !== nextIsScaled) { - runOnJS(handleZoom)(nextIsScaled) - } - }, - onEndDrag(e) { - const velocityY = e.velocity?.y ?? 0 - const nextIsScaled = e.zoomScale > 1 if (scaled !== nextIsScaled) { runOnJS(handleZoom)(nextIsScaled) } - if (!nextIsScaled && Math.abs(velocityY) > SWIPE_CLOSE_VELOCITY) { - runOnJS(onRequestClose)() - } }, }) @@ -146,7 +137,11 @@ const ImageItem = ({ runOnJS(zoomTo)(nextZoomRect) }) - const composedGesture = Gesture.Exclusive(doubleTap, singleTap) + const composedGesture = Gesture.Exclusive( + dismissSwipePan, + doubleTap, + singleTap, + ) return ( <GestureDetector gesture={composedGesture}> @@ -158,21 +153,22 @@ const ImageItem = ({ showsVerticalScrollIndicator={false} maximumZoomScale={maxZoomScale} onScroll={scrollHandler} - contentContainerStyle={styles.scrollContainer}> - <Animated.View style={animatedStyle}> - <ActivityIndicator size="small" color="#FFF" style={styles.loading} /> - <Image - contentFit="contain" - source={{uri: imageSrc.uri}} - placeholderContentFit="contain" - placeholder={{uri: imageSrc.thumbUri}} - style={styles.image} - accessibilityLabel={imageSrc.alt} - accessibilityHint="" - enableLiveTextInteraction={showControls && !scaled} - accessibilityIgnoresInvertColors - /> - </Animated.View> + bounces={scaled} + bouncesZoom={true} + style={imageStyle} + centerContent> + <ActivityIndicator size="small" color="#FFF" style={styles.loading} /> + <AnimatedImage + contentFit="contain" + source={{uri: imageSrc.uri}} + placeholderContentFit="contain" + placeholder={{uri: imageSrc.thumbUri}} + style={animatedStyle} + accessibilityLabel={imageSrc.alt} + accessibilityHint="" + enableLiveTextInteraction={showControls && !scaled} + accessibilityIgnoresInvertColors + /> </Animated.ScrollView> </GestureDetector> ) @@ -186,9 +182,6 @@ const styles = StyleSheet.create({ right: 0, bottom: 0, }, - scrollContainer: { - flex: 1, - }, image: { flex: 1, }, |