Add <DeferReveal> to defer expensive views
This commit is contained in:
@@ -0,0 +1,23 @@
|
|||||||
|
import {ReactNode, useEffect, useState} from 'react'
|
||||||
|
|
||||||
|
export function DeferReveal({
|
||||||
|
children,
|
||||||
|
defer,
|
||||||
|
// To verify, toggle `forceReveal` between `true` and `false`.
|
||||||
|
iVerifiedThereAreNoLayoutJumps: _unused,
|
||||||
|
forceReveal,
|
||||||
|
}: {
|
||||||
|
children: ReactNode
|
||||||
|
defer: boolean
|
||||||
|
iVerifiedThereAreNoLayoutJumps: true
|
||||||
|
forceReveal?: never // DEV-only
|
||||||
|
}) {
|
||||||
|
const [isReady, setIsReady] = useState(!defer)
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isReady) {
|
||||||
|
setIsReady(true)
|
||||||
|
}
|
||||||
|
}, [isReady])
|
||||||
|
const finalIsReady = forceReveal ?? isReady
|
||||||
|
return finalIsReady ? children : null
|
||||||
|
}
|
||||||
@@ -8,8 +8,10 @@ import {useLingui} from '@lingui/react'
|
|||||||
import {HandleRef, useHandleRef} from '#/lib/hooks/useHandleRef'
|
import {HandleRef, useHandleRef} from '#/lib/hooks/useHandleRef'
|
||||||
import type {Dimensions} from '#/lib/media/types'
|
import type {Dimensions} from '#/lib/media/types'
|
||||||
import {isNative} from '#/platform/detection'
|
import {isNative} from '#/platform/detection'
|
||||||
|
import {isAndroid} from '#/platform/detection'
|
||||||
import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge'
|
import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge'
|
||||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||||
|
import {DeferReveal} from '#/components/DeferReveal'
|
||||||
import {ArrowsDiagonalOut_Stroke2_Corner0_Rounded as Fullscreen} from '#/components/icons/ArrowsDiagonal'
|
import {ArrowsDiagonalOut_Stroke2_Corner0_Rounded as Fullscreen} from '#/components/icons/ArrowsDiagonal'
|
||||||
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
@@ -107,6 +109,7 @@ export function AutoSizedImage({
|
|||||||
|
|
||||||
const contents = (
|
const contents = (
|
||||||
<View ref={containerRef} collapsable={false} style={{flex: 1}}>
|
<View ref={containerRef} collapsable={false} style={{flex: 1}}>
|
||||||
|
<DeferReveal defer={isAndroid} iVerifiedThereAreNoLayoutJumps>
|
||||||
<Image
|
<Image
|
||||||
style={[a.w_full, a.h_full]}
|
style={[a.w_full, a.h_full]}
|
||||||
source={image.thumb}
|
source={image.thumb}
|
||||||
@@ -185,6 +188,7 @@ export function AutoSizedImage({
|
|||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
|
</DeferReveal>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ import {useLingui} from '@lingui/react'
|
|||||||
|
|
||||||
import {HandleRef} from '#/lib/hooks/useHandleRef'
|
import {HandleRef} from '#/lib/hooks/useHandleRef'
|
||||||
import {Dimensions} from '#/lib/media/types'
|
import {Dimensions} from '#/lib/media/types'
|
||||||
|
import {isAndroid} from '#/platform/detection'
|
||||||
import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge'
|
import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge'
|
||||||
import {PostEmbedViewContext} from '#/view/com/util/post-embeds/types'
|
import {PostEmbedViewContext} from '#/view/com/util/post-embeds/types'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
import {DeferReveal} from '#/components/DeferReveal'
|
||||||
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
@@ -70,6 +72,7 @@ export function GalleryItem({
|
|||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityLabel={image.alt || _(msg`Image`)}
|
accessibilityLabel={image.alt || _(msg`Image`)}
|
||||||
accessibilityHint="">
|
accessibilityHint="">
|
||||||
|
<DeferReveal defer={isAndroid} iVerifiedThereAreNoLayoutJumps>
|
||||||
<Image
|
<Image
|
||||||
source={{uri: image.thumb}}
|
source={{uri: image.thumb}}
|
||||||
style={[a.flex_1]}
|
style={[a.flex_1]}
|
||||||
@@ -84,6 +87,7 @@ export function GalleryItem({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</DeferReveal>
|
||||||
<MediaInsetBorder style={insetBorderStyle} />
|
<MediaInsetBorder style={insetBorderStyle} />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
{hasAlt && !hideBadges ? (
|
{hasAlt && !hideBadges ? (
|
||||||
|
|||||||
@@ -9,12 +9,13 @@ import {parseAltFromGIFDescription} from '#/lib/gif-alt-text'
|
|||||||
import {shareUrl} from '#/lib/sharing'
|
import {shareUrl} from '#/lib/sharing'
|
||||||
import {parseEmbedPlayerFromUrl} from '#/lib/strings/embed-player'
|
import {parseEmbedPlayerFromUrl} from '#/lib/strings/embed-player'
|
||||||
import {toNiceDomain} from '#/lib/strings/url-helpers'
|
import {toNiceDomain} from '#/lib/strings/url-helpers'
|
||||||
import {isNative} from '#/platform/detection'
|
import {isAndroid, isNative} from '#/platform/detection'
|
||||||
import {useExternalEmbedsPrefs} from '#/state/preferences'
|
import {useExternalEmbedsPrefs} from '#/state/preferences'
|
||||||
import {ExternalGifEmbed} from '#/view/com/util/post-embeds/ExternalGifEmbed'
|
import {ExternalGifEmbed} from '#/view/com/util/post-embeds/ExternalGifEmbed'
|
||||||
import {ExternalPlayer} from '#/view/com/util/post-embeds/ExternalPlayerEmbed'
|
import {ExternalPlayer} from '#/view/com/util/post-embeds/ExternalPlayerEmbed'
|
||||||
import {GifEmbed} from '#/view/com/util/post-embeds/GifEmbed'
|
import {GifEmbed} from '#/view/com/util/post-embeds/GifEmbed'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
import {DeferReveal} from '#/components/DeferReveal'
|
||||||
import {Divider} from '#/components/Divider'
|
import {Divider} from '#/components/Divider'
|
||||||
import {Earth_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
|
import {Earth_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
|
||||||
import {Link} from '#/components/Link'
|
import {Link} from '#/components/Link'
|
||||||
@@ -87,13 +88,18 @@ export const ExternalLinkEmbed = ({
|
|||||||
: t.atoms.border_contrast_low,
|
: t.atoms.border_contrast_low,
|
||||||
]}>
|
]}>
|
||||||
{imageUri && !embedPlayerParams ? (
|
{imageUri && !embedPlayerParams ? (
|
||||||
<Image
|
<View
|
||||||
style={{
|
style={{
|
||||||
aspectRatio: 1.91,
|
aspectRatio: 1.91,
|
||||||
}}
|
}}>
|
||||||
|
<DeferReveal defer={isAndroid} iVerifiedThereAreNoLayoutJumps>
|
||||||
|
<Image
|
||||||
|
style={{flex: 1}}
|
||||||
source={{uri: imageUri}}
|
source={{uri: imageUri}}
|
||||||
accessibilityIgnoresInvertColors
|
accessibilityIgnoresInvertColors
|
||||||
/>
|
/>
|
||||||
|
</DeferReveal>
|
||||||
|
</View>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
|
|
||||||
{embedPlayerParams?.isGif ? (
|
{embedPlayerParams?.isGif ? (
|
||||||
|
|||||||
@@ -23,9 +23,10 @@ import {useNavigation} from '@react-navigation/native'
|
|||||||
|
|
||||||
import {NavigationProp} from '#/lib/routes/types'
|
import {NavigationProp} from '#/lib/routes/types'
|
||||||
import {EmbedPlayerParams, getPlayerAspect} from '#/lib/strings/embed-player'
|
import {EmbedPlayerParams, getPlayerAspect} from '#/lib/strings/embed-player'
|
||||||
import {isNative} from '#/platform/detection'
|
import {isAndroid, isNative} from '#/platform/detection'
|
||||||
import {useExternalEmbedsPrefs} from '#/state/preferences'
|
import {useExternalEmbedsPrefs} from '#/state/preferences'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
import {DeferReveal} from '#/components/DeferReveal'
|
||||||
import {useDialogControl} from '#/components/Dialog'
|
import {useDialogControl} from '#/components/Dialog'
|
||||||
import {EmbedConsentDialog} from '#/components/dialogs/EmbedConsent'
|
import {EmbedConsentDialog} from '#/components/dialogs/EmbedConsent'
|
||||||
import {Fill} from '#/components/Fill'
|
import {Fill} from '#/components/Fill'
|
||||||
@@ -217,6 +218,7 @@ export function ExternalPlayer({
|
|||||||
ref={viewRef}
|
ref={viewRef}
|
||||||
collapsable={false}
|
collapsable={false}
|
||||||
style={[aspect, a.overflow_hidden]}>
|
style={[aspect, a.overflow_hidden]}>
|
||||||
|
<DeferReveal defer={isAndroid} iVerifiedThereAreNoLayoutJumps>
|
||||||
{link.thumb && (!isPlayerActive || isLoading) ? (
|
{link.thumb && (!isPlayerActive || isLoading) ? (
|
||||||
<>
|
<>
|
||||||
<Image
|
<Image
|
||||||
@@ -254,6 +256,7 @@ export function ExternalPlayer({
|
|||||||
params={params}
|
params={params}
|
||||||
onLoad={onLoad}
|
onLoad={onLoad}
|
||||||
/>
|
/>
|
||||||
|
</DeferReveal>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,10 +12,11 @@ import {useLingui} from '@lingui/react'
|
|||||||
|
|
||||||
import {HITSLOP_20} from '#/lib/constants'
|
import {HITSLOP_20} from '#/lib/constants'
|
||||||
import {EmbedPlayerParams} from '#/lib/strings/embed-player'
|
import {EmbedPlayerParams} from '#/lib/strings/embed-player'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isAndroid, isWeb} from '#/platform/detection'
|
||||||
import {useAutoplayDisabled} from '#/state/preferences'
|
import {useAutoplayDisabled} from '#/state/preferences'
|
||||||
import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge'
|
import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
import {DeferReveal} from '#/components/DeferReveal'
|
||||||
import {Fill} from '#/components/Fill'
|
import {Fill} from '#/components/Fill'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import * as Prompt from '#/components/Prompt'
|
import * as Prompt from '#/components/Prompt'
|
||||||
@@ -121,6 +122,7 @@ export function GifEmbed({
|
|||||||
{aspectRatio: params.dimensions!.width / params.dimensions!.height},
|
{aspectRatio: params.dimensions!.width / params.dimensions!.height},
|
||||||
style,
|
style,
|
||||||
]}>
|
]}>
|
||||||
|
<DeferReveal defer={isAndroid} iVerifiedThereAreNoLayoutJumps>
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
a.absolute,
|
a.absolute,
|
||||||
@@ -161,6 +163,7 @@ export function GifEmbed({
|
|||||||
)}
|
)}
|
||||||
{!hideAlt && isPreferredAltText && <AltText text={altText} />}
|
{!hideAlt && isPreferredAltText && <AltText text={altText} />}
|
||||||
</View>
|
</View>
|
||||||
|
</DeferReveal>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user