Remove async resizing from external embed player (#2936)

* remove debug

adjust youtube shorts height

fix webview style

simplify styles

fix resizing

make it more clear

remove async resizes from external player

* remove comment

* ts

* reverse aspect
zio/stable
Hailey 2024-02-20 11:38:56 -08:00 committed by GitHub
parent 09eee05f8b
commit fab6c286f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 48 additions and 84 deletions

View File

@ -343,45 +343,45 @@ export function parseEmbedPlayerFromUrl(
} }
} }
export function getPlayerHeight({ export function getPlayerAspect({
type, type,
width,
hasThumb, hasThumb,
width,
}: { }: {
type: EmbedPlayerParams['type'] type: EmbedPlayerParams['type']
width: number
hasThumb: boolean hasThumb: boolean
}) { width: number
if (!hasThumb) return (width / 16) * 9 }): {aspectRatio?: number; height?: number} {
if (!hasThumb) return {aspectRatio: 16 / 9}
switch (type) { switch (type) {
case 'youtube_video': case 'youtube_video':
case 'twitch_video': case 'twitch_video':
case 'vimeo_video': case 'vimeo_video':
return (width / 16) * 9 return {aspectRatio: 16 / 9}
case 'youtube_short': case 'youtube_short':
if (SCREEN_HEIGHT < 600) { if (SCREEN_HEIGHT < 600) {
return ((width / 9) * 16) / 1.75 return {aspectRatio: (9 / 16) * 1.75}
} else { } else {
return ((width / 9) * 16) / 1.5 return {aspectRatio: (9 / 16) * 1.5}
} }
case 'spotify_album': case 'spotify_album':
case 'apple_music_album': case 'apple_music_album':
case 'apple_music_playlist': case 'apple_music_playlist':
case 'spotify_playlist': case 'spotify_playlist':
case 'soundcloud_set': case 'soundcloud_set':
return 380 return {height: 380}
case 'spotify_song': case 'spotify_song':
if (width <= 300) { if (width <= 300) {
return 155 return {height: 155}
} }
return 232 return {height: 232}
case 'soundcloud_track': case 'soundcloud_track':
return 165 return {height: 165}
case 'apple_music_song': case 'apple_music_song':
return 150 return {height: 150}
default: default:
return width return {aspectRatio: 16 / 9}
} }
} }

View File

@ -1,11 +1,14 @@
import React from 'react' import React from 'react'
import {View} from 'react-native' import {View, ViewStyle} from 'react-native'
/** /**
* This utility function captures events and stops * This utility function captures events and stops
* them from propagating upwards. * them from propagating upwards.
*/ */
export function EventStopper({children}: React.PropsWithChildren<{}>) { export function EventStopper({
children,
style,
}: React.PropsWithChildren<{style?: ViewStyle | ViewStyle[]}>) {
const stop = (e: any) => { const stop = (e: any) => {
e.stopPropagation() e.stopPropagation()
} }
@ -15,7 +18,8 @@ export function EventStopper({children}: React.PropsWithChildren<{}>) {
onTouchEnd={stop} onTouchEnd={stop}
// @ts-ignore web only -prf // @ts-ignore web only -prf
onClick={stop} onClick={stop}
onKeyDown={stop}> onKeyDown={stop}
style={style}>
{children} {children}
</View> </View>
) )

View File

@ -21,7 +21,7 @@ import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
import {AppBskyEmbedExternal} from '@atproto/api' import {AppBskyEmbedExternal} from '@atproto/api'
import {EmbedPlayerParams, getPlayerHeight} from 'lib/strings/embed-player' import {EmbedPlayerParams, getPlayerAspect} from 'lib/strings/embed-player'
import {EventStopper} from '../EventStopper' import {EventStopper} from '../EventStopper'
import {isNative} from 'platform/detection' import {isNative} from 'platform/detection'
import {NavigationProp} from 'lib/routes/types' import {NavigationProp} from 'lib/routes/types'
@ -67,14 +67,12 @@ function PlaceholderOverlay({
// This renders the webview/youtube player as a separate layer // This renders the webview/youtube player as a separate layer
function Player({ function Player({
height,
params, params,
onLoad, onLoad,
isPlayerActive, isPlayerActive,
}: { }: {
isPlayerActive: boolean isPlayerActive: boolean
params: EmbedPlayerParams params: EmbedPlayerParams
height: number
onLoad: () => void onLoad: () => void
}) { }) {
// ensures we only load what's requested // ensures we only load what's requested
@ -91,25 +89,21 @@ function Player({
if (!isPlayerActive) return null if (!isPlayerActive) return null
return ( return (
<View style={[styles.layer, styles.playerLayer]}> <EventStopper style={[styles.layer, styles.playerLayer]}>
<EventStopper> <WebView
<View style={{height, width: '100%'}}> javaScriptEnabled={true}
<WebView onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
javaScriptEnabled={true} mediaPlaybackRequiresUserAction={false}
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} allowsInlineMediaPlayback
mediaPlaybackRequiresUserAction={false} bounces={false}
allowsInlineMediaPlayback allowsFullscreenVideo
bounces={false} nestedScrollEnabled
allowsFullscreenVideo source={{uri: params.playerUri}}
nestedScrollEnabled onLoad={onLoad}
source={{uri: params.playerUri}} style={styles.webview}
onLoad={onLoad} setSupportMultipleWindows={false} // Prevent any redirects from opening a new window (ads)
setSupportMultipleWindows={false} // Prevent any redirects from opening a new window (ads) />
style={[styles.webview, styles.topRadius]} </EventStopper>
/>
</View>
</EventStopper>
</View>
) )
} }
@ -129,13 +123,16 @@ export function ExternalPlayer({
const [isPlayerActive, setPlayerActive] = React.useState(false) const [isPlayerActive, setPlayerActive] = React.useState(false)
const [isLoading, setIsLoading] = React.useState(true) const [isLoading, setIsLoading] = React.useState(true)
const [dim, setDim] = React.useState({
width: 0, const aspect = React.useMemo(() => {
height: 0, return getPlayerAspect({
}) type: params.type,
width: windowDims.width,
hasThumb: !!link.thumb,
})
}, [params.type, windowDims.width, link.thumb])
const viewRef = useAnimatedRef() const viewRef = useAnimatedRef()
const frameCallback = useFrameCallback(() => { const frameCallback = useFrameCallback(() => {
const measurement = measure(viewRef) const measurement = measure(viewRef)
if (!measurement) return if (!measurement) return
@ -180,17 +177,6 @@ export function ExternalPlayer({
} }
}, [navigation, isPlayerActive, frameCallback]) }, [navigation, isPlayerActive, frameCallback])
// calculate height for the player and the screen size
const height = React.useMemo(
() =>
getPlayerHeight({
type: params.type,
width: dim.width,
hasThumb: !!link.thumb,
}),
[params.type, dim.width, link.thumb],
)
const onLoad = React.useCallback(() => { const onLoad = React.useCallback(() => {
setIsLoading(false) setIsLoading(false)
}, []) }, [])
@ -216,32 +202,11 @@ export function ExternalPlayer({
[externalEmbedsPrefs, openModal, params.source], [externalEmbedsPrefs, openModal, params.source],
) )
// measure the layout to set sizing
const onLayout = React.useCallback(
(event: {nativeEvent: {layout: {width: any; height: any}}}) => {
setDim({
width: event.nativeEvent.layout.width,
height: event.nativeEvent.layout.height,
})
},
[],
)
return ( return (
<Animated.View <Animated.View ref={viewRef} collapsable={false} style={[aspect]}>
ref={viewRef}
style={{height}}
collapsable={false}
onLayout={onLayout}>
{link.thumb && (!isPlayerActive || isLoading) && ( {link.thumb && (!isPlayerActive || isLoading) && (
<Image <Image
style={[ style={[{flex: 1}, styles.topRadius]}
{
width: dim.width,
height,
},
styles.topRadius,
]}
source={{uri: link.thumb}} source={{uri: link.thumb}}
accessibilityIgnoresInvertColors accessibilityIgnoresInvertColors
/> />
@ -251,12 +216,7 @@ export function ExternalPlayer({
isPlayerActive={isPlayerActive} isPlayerActive={isPlayerActive}
onPress={onPlayPress} onPress={onPlayPress}
/> />
<Player <Player isPlayerActive={isPlayerActive} params={params} onLoad={onLoad} />
isPlayerActive={isPlayerActive}
params={params}
height={height}
onLoad={onLoad}
/>
</Animated.View> </Animated.View>
) )
} }