diff options
author | dan <dan.abramov@gmail.com> | 2024-11-28 23:29:45 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-28 23:29:45 +0000 |
commit | 5f4a0f2881b9420f3a3f3fb6527352f58a99d9ea (patch) | |
tree | 646756fc73e3f16f06f22c623e8e2c48e30c8834 | |
parent | d08ce0d473374c0720d018e8fc8ed550ed32544a (diff) | |
download | voidsky-5f4a0f2881b9420f3a3f3fb6527352f58a99d9ea.tar.zst |
"Contain" images with missing dimensions instead of cropping them (#6828)
* Show unknown aspect as "contain" for autosize * Fix a flash of wrong position when opening in lightbox * Fix last frame flash on Android
3 files changed, 35 insertions, 20 deletions
diff --git a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx index 8e046e5ba..925158773 100644 --- a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx +++ b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx @@ -392,9 +392,9 @@ const ImageItem = ({ <Animated.View style={imageCropStyle}> <Animated.View style={imageStyle}> <Image - contentFit="cover" + contentFit="contain" source={{uri: imageSrc.uri}} - placeholderContentFit="cover" + placeholderContentFit="contain" placeholder={{uri: imageSrc.thumbUri}} accessibilityLabel={imageSrc.alt} onLoad={ diff --git a/src/view/com/lightbox/ImageViewing/index.tsx b/src/view/com/lightbox/ImageViewing/index.tsx index ce59b4b9d..f91acc12a 100644 --- a/src/view/com/lightbox/ImageViewing/index.tsx +++ b/src/view/com/lightbox/ImageViewing/index.tsx @@ -8,7 +8,7 @@ // 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, {useCallback, useEffect, useState} from 'react' +import React, {useCallback, useEffect, useMemo, useState} from 'react' import { LayoutAnimation, PixelRatio, @@ -79,6 +79,15 @@ const FAST_SPRING: WithSpringConfig = { restDisplacementThreshold: 0.01, } +function canAnimate(lightbox: Lightbox): boolean { + return ( + !PlatformInfo.getIsReducedMotionEnabled() && + lightbox.images.every( + img => img.thumbRect && (img.dimensions || img.thumbDimensions), + ) + ) +} + export default function ImageViewRoot({ lightbox: nextLightbox, onRequestClose, @@ -104,23 +113,19 @@ export default function ImageViewRoot({ return } - const canAnimate = - !PlatformInfo.getIsReducedMotionEnabled() && - nextLightbox.images.every( - img => img.thumbRect && (img.dimensions || img.thumbDimensions), - ) + const isAnimated = canAnimate(nextLightbox) // https://github.com/software-mansion/react-native-reanimated/issues/6677 rAF_FIXED(() => { openProgress.set(() => - canAnimate ? withClampedSpring(1, SLOW_SPRING) : 1, + isAnimated ? withClampedSpring(1, SLOW_SPRING) : 1, ) }) return () => { // https://github.com/software-mansion/react-native-reanimated/issues/6677 rAF_FIXED(() => { openProgress.set(() => - canAnimate ? withClampedSpring(0, SLOW_SPRING) : 0, + isAnimated ? withClampedSpring(0, SLOW_SPRING) : 0, ) }) } @@ -185,6 +190,7 @@ function ImageView({ openProgress: SharedValue<number> }) { const {images, index: initialImageIndex} = lightbox + const isAnimated = useMemo(() => canAnimate(lightbox), [lightbox]) const [isScaled, setIsScaled] = useState(false) const [isDragging, setIsDragging] = useState(false) const [imageIndex, setImageIndex] = useState(initialImageIndex) @@ -194,10 +200,19 @@ function ImageView({ const isFlyingAway = useSharedValue(false) const containerStyle = useAnimatedStyle(() => { - if (openProgress.get() < 1 || isFlyingAway.get()) { - return {pointerEvents: 'none'} + if (openProgress.get() < 1) { + return { + pointerEvents: 'none', + opacity: isAnimated ? 1 : 0, + } + } + if (isFlyingAway.get()) { + return { + pointerEvents: 'none', + opacity: 1, + } } - return {pointerEvents: 'auto'} + return {pointerEvents: 'auto', opacity: 1} }) const backdropStyle = useAnimatedStyle(() => { diff --git a/src/view/com/util/images/AutoSizedImage.tsx b/src/view/com/util/images/AutoSizedImage.tsx index 617b9bec4..a411b24bb 100644 --- a/src/view/com/util/images/AutoSizedImage.tsx +++ b/src/view/com/util/images/AutoSizedImage.tsx @@ -85,10 +85,6 @@ export function AutoSizedImage({ if (Number.isNaN(aspectRatio)) { aspectRatio = undefined } - } else { - // If we don't know it synchronously, treat it like a square. - // We won't use fetched dimensions to avoid a layout shift. - aspectRatio = 1 } let constrained: number | undefined @@ -103,11 +99,13 @@ export function AutoSizedImage({ const cropDisabled = crop === 'none' const isCropped = rawIsCropped && !cropDisabled + const isContain = aspectRatio === undefined const hasAlt = !!image.alt const contents = ( <View ref={containerRef} collapsable={false} style={{flex: 1}}> <Image + contentFit={isContain ? 'contain' : 'cover'} style={[a.w_full, a.h_full]} source={image.thumb} accessible={true} // Must set for `accessibilityLabel` to work @@ -115,9 +113,11 @@ export function AutoSizedImage({ accessibilityLabel={image.alt} accessibilityHint="" onLoad={e => { - fetchedDimsRef.current = { - width: e.source.width, - height: e.source.height, + if (!isContain) { + fetchedDimsRef.current = { + width: e.source.width, + height: e.source.height, + } } }} /> |