Factor props upwards

Also fix handling of missing aspectRatio
This commit is contained in:
Dan Abramov
2024-11-03 05:09:07 +00:00
parent f261484d4c
commit d8eaf8b06c
4 changed files with 34 additions and 52 deletions
@@ -20,7 +20,6 @@ import Animated, {
} from 'react-native-reanimated'
import {Image, ImageStyle} from 'expo-image'
import {useImageDimensions} from '#/lib/media/image-sizes'
import type {Dimensions as ImageDimensions, ImageSource} from '../../@types'
import {
applyRounding,
@@ -55,6 +54,8 @@ type Props = {
showControls: boolean
dismissSwipePan: PanGesture
imageStyle: StyleProp<ImageStyle>
imageAspect: number | undefined
dimensions: ImageDimensions | undefined
}
const ImageItem = ({
@@ -64,12 +65,10 @@ const ImageItem = ({
isPagingAndroid,
dismissSwipePan,
imageStyle,
imageAspect,
dimensions,
}: Props) => {
const [isScaled, setIsScaled] = useState(false)
const [imageAspect, imageDimensions] = useImageDimensions({
src: imageSrc.uri,
knownDimensions: imageSrc.dimensions,
})
const committedTransform = useSharedValue(initialTransform)
const panTranslation = useSharedValue({x: 0, y: 0})
const pinchOrigin = useSharedValue({x: 0, y: 0})
@@ -155,14 +154,14 @@ const ImageItem = ({
})
.onChange(e => {
'worklet'
if (!imageDimensions) {
if (!dimensions) {
return
}
// Don't let the picture zoom in so close that it gets blurry.
// Also, like in stock Android apps, don't let the user zoom out further than 1:1.
const [, , committedScale] = readTransform(committedTransform.value)
const maxCommittedScale =
(imageDimensions.width / SCREEN.width) * MAX_ORIGINAL_IMAGE_ZOOM
(dimensions.width / SCREEN.width) * MAX_ORIGINAL_IMAGE_ZOOM
const minPinchScale = 1 / committedScale
const maxPinchScale = maxCommittedScale / committedScale
const nextPinchScale = Math.min(
@@ -211,7 +210,7 @@ const ImageItem = ({
.minPointers(isScaled ? 1 : 2)
.onChange(e => {
'worklet'
if (!imageDimensions) {
if (!dimensions) {
return
}
const nextPanTranslation = {x: e.translationX, y: e.translationY}
@@ -259,7 +258,7 @@ const ImageItem = ({
.numberOfTaps(2)
.onEnd(e => {
'worklet'
if (!imageDimensions || !imageAspect) {
if (!dimensions || !imageAspect) {
return
}
const [, , committedScale] = readTransform(committedTransform.value)
@@ -279,7 +278,7 @@ const ImageItem = ({
)
// But don't zoom in so close that the picture gets blurry.
const maxScale =
(imageDimensions.width / SCREEN.width) * MAX_ORIGINAL_IMAGE_ZOOM
(dimensions.width / SCREEN.width) * MAX_ORIGINAL_IMAGE_ZOOM
const scale = Math.min(candidateScale, maxScale)
// Calculate where we would be if the user pinched into the double tapped point.
@@ -321,19 +320,7 @@ const ImageItem = ({
source={{uri: imageSrc.uri}}
placeholderContentFit="cover"
placeholder={{uri: imageSrc.thumbUri}}
style={[
{
width: SCREEN.width,
height: imageAspect ? SCREEN.width / imageAspect : undefined,
borderRadius:
imageSrc.type === 'circle-avi'
? SCREEN.width / 2
: imageSrc.type === 'rect-avi'
? 20
: 0,
},
imageStyle,
]}
style={imageStyle}
accessibilityLabel={imageSrc.alt}
accessibilityHint=""
accessibilityIgnoresInvertColors
@@ -22,8 +22,7 @@ import Animated, {runOnJS, useAnimatedRef} from 'react-native-reanimated'
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)
@@ -40,25 +39,24 @@ type Props = {
showControls: boolean
dismissSwipePan: PanGesture | null
imageStyle: StyleProp<ImageStyle>
imageAspect: number | undefined
dimensions: ImageDimensions | undefined
}
const ImageItem = ({
imageSrc,
dimensions,
onTap,
onZoom,
showControls,
dismissSwipePan,
imageStyle,
imageAspect,
}: Props) => {
const scrollViewRef = useAnimatedRef<Animated.ScrollView>()
const [scaled, setScaled] = useState(false)
const [imageAspect, imageDimensions] = useImageDimensions({
src: imageSrc.uri,
knownDimensions: imageSrc.dimensions,
})
const maxZoomScale = imageDimensions
? (imageDimensions.width / SCREEN.width) * MAX_ORIGINAL_IMAGE_ZOOM
const maxZoomScale = dimensions
? (dimensions.width / SCREEN.width) * MAX_ORIGINAL_IMAGE_ZOOM
: 1
const scrollHandler = useAnimatedScrollHandler({
@@ -158,19 +156,7 @@ const ImageItem = ({
source={{uri: imageSrc.uri}}
placeholderContentFit="cover"
placeholder={{uri: imageSrc.thumbUri}}
style={[
{
width: SCREEN.width,
height: imageAspect ? SCREEN.width / imageAspect : undefined,
borderRadius:
imageSrc.type === 'circle-avi'
? SCREEN.width / 2
: imageSrc.type === 'rect-avi'
? 20
: 0,
},
imageStyle,
]}
style={imageStyle}
accessibilityLabel={imageSrc.alt}
accessibilityHint=""
enableLiveTextInteraction={showControls && !scaled}
@@ -5,7 +5,7 @@ import {StyleProp, View} from 'react-native'
import {PanGesture} from 'react-native-gesture-handler'
import {ImageStyle} from 'expo-image'
import {ImageSource} from '../../@types'
import {Dimensions as ImageDimensions, ImageSource} from '../../@types'
type Props = {
imageSrc: ImageSource
@@ -16,6 +16,8 @@ type Props = {
showControls: boolean
dismissSwipePan: PanGesture | null
imageStyle: StyleProp<ImageStyle>
imageAspect: number | undefined
dimensions: ImageDimensions | undefined
}
const ImageItem = (_props: Props) => {
+13 -6
View File
@@ -38,6 +38,7 @@ import {Edge, SafeAreaView} from 'react-native-safe-area-context'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {Trans} from '@lingui/macro'
import {useImageDimensions} from '#/lib/media/image-sizes'
import {colors, s} from '#/lib/styles'
import {isAndroid, isIOS} from '#/platform/detection'
import {Lightbox} from '#/state/lightbox'
@@ -262,20 +263,22 @@ function LightboxPage({
dismissSwipeTranslateY: SharedValue<number>
dismissSwipePan: PanGesture
}) {
const {thumbRect, dimensions} = imageSrc
const imageAspect = dimensions
? dimensions.width / dimensions.height
: undefined
const {thumbRect, dimensions: knownDimensions, type} = imageSrc
const [imageAspect, dimensions] = useImageDimensions({
src: imageSrc.uri,
knownDimensions,
})
const finalWidth = SCREEN.width
const finalHeight = imageAspect ? SCREEN.width / imageAspect : undefined
const interpolation = useDerivedValue(() => {
if (isActive && thumbRect && dimensions && openProgress.value < 1) {
if (isActive && thumbRect && knownDimensions && openProgress.value < 1) {
return interpolateTransform(
openProgress.value,
thumbRect,
SCREEN,
dimensions,
knownDimensions,
)
}
const translateY = isActive ? dismissSwipeTranslateY.value : 0
@@ -299,6 +302,8 @@ function LightboxPage({
return {
width,
height,
borderRadius:
type === 'circle-avi' ? SCREEN.width / 2 : type === 'rect-avi' ? 20 : 0,
}
})
@@ -313,6 +318,8 @@ function LightboxPage({
showControls={showControls}
dismissSwipePan={isActive ? dismissSwipePan : null}
imageStyle={imageStyle}
imageAspect={imageAspect}
dimensions={dimensions}
/>
</Animated.View>
)