Additional embed sources and external-media consent controls (#2424)
* add apple music embed * add vimeo embed * add logic for tenor and giphy embeds * keep it simple, use playerUri for images too * add gif embed player * lint, fix tests * remove links that can't produce a thumb * Revert "remove links that can't produce a thumb" This reverts commit 985b92b4e622db936bb0c79fdf324099b9c8fcd8. * Revert "Revert "remove links that can't produce a thumb"" This reverts commit 4895ded8b5120c4fc52b43ae85c9a01ea0b1a733. * Revert "Revert "Revert "remove links that can't produce a thumb""" This reverts commit 36d04b517ba5139e1639f2eda28d7f9aaa2dbfb6. * properly obtain giphy metadata regardless of used url * test fixes * adjust gif player * add all twitch embed types * support m.youtube links * few logic adjustments * adjust spotify player height * prefetch gif before showing * use memory-disk cache policy on gifs * use `disk` cachePolicy on ios - can't start/stop animation * support pause/play on web * onLoad fix * remove extra pressable, add accessibility, fix scale issues * improve size of embed * add settings * fix(?) settings * add source to embed player params * update tests * better naming and settings options * consent modal * fix test id * why is webstorm adding .tsx * web modal * simplify types * adjust snap points * remove unnecessary yt embed library. just use the webview always * remove now useless WebGifStill 😭 * more type cleanup * more type cleanup * combine parse and prefs check in one memo * improve dimensions of youtube shorts * oops didn't commit the test 🫥 * add shorts as separate embed type * fix up schema * shorts modal * hide gif details * support localized spotify embeds * more cleanup * improve look and accessibility of gif embeds * Update routing for the external embeds settings page * Update and simplify the external embed preferences screen * Update copy in embedconsent modal and add 'allow all' button --------- Co-authored-by: Hailey <me@haileyok.com>
This commit is contained in:
parent
db62f27241
commit
0dae24e78f
24 changed files with 1240 additions and 131 deletions
|
|
@ -16,14 +16,17 @@ import Animated, {
|
|||
import {Image} from 'expo-image'
|
||||
import {WebView} from 'react-native-webview'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import YoutubePlayer from 'react-native-youtube-iframe'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {AppBskyEmbedExternal} from '@atproto/api'
|
||||
import {EmbedPlayerParams, getPlayerHeight} from 'lib/strings/embed-player'
|
||||
import {EventStopper} from '../EventStopper'
|
||||
import {AppBskyEmbedExternal} from '@atproto/api'
|
||||
import {isNative} from 'platform/detection'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {useExternalEmbedsPrefs} from 'state/preferences'
|
||||
import {useModalControls} from 'state/modals'
|
||||
|
||||
interface ShouldStartLoadRequest {
|
||||
url: string
|
||||
|
|
@ -39,6 +42,8 @@ function PlaceholderOverlay({
|
|||
isPlayerActive: boolean
|
||||
onPress: (event: GestureResponderEvent) => void
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
|
||||
// If the player is active and not loading, we don't want to show the overlay.
|
||||
if (isPlayerActive && !isLoading) return null
|
||||
|
||||
|
|
@ -46,8 +51,8 @@ function PlaceholderOverlay({
|
|||
<View style={[styles.layer, styles.overlayLayer]}>
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Play Video"
|
||||
accessibilityHint=""
|
||||
accessibilityLabel={_(msg`Play Video`)}
|
||||
accessibilityHint={_(msg`Play Video`)}
|
||||
onPress={onPress}
|
||||
style={[styles.overlayContainer, styles.topRadius]}>
|
||||
{!isPlayerActive ? (
|
||||
|
|
@ -84,31 +89,21 @@ function Player({
|
|||
return (
|
||||
<View style={[styles.layer, styles.playerLayer]}>
|
||||
<EventStopper>
|
||||
{isNative && params.type === 'youtube_video' ? (
|
||||
<YoutubePlayer
|
||||
videoId={params.videoId}
|
||||
play
|
||||
height={height}
|
||||
onReady={onLoad}
|
||||
webViewStyle={[styles.webview, styles.topRadius]}
|
||||
<View style={{height, width: '100%'}}>
|
||||
<WebView
|
||||
javaScriptEnabled={true}
|
||||
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
|
||||
mediaPlaybackRequiresUserAction={false}
|
||||
allowsInlineMediaPlayback
|
||||
bounces={false}
|
||||
allowsFullscreenVideo
|
||||
nestedScrollEnabled
|
||||
source={{uri: params.playerUri}}
|
||||
onLoad={onLoad}
|
||||
setSupportMultipleWindows={false} // Prevent any redirects from opening a new window (ads)
|
||||
style={[styles.webview, styles.topRadius]}
|
||||
/>
|
||||
) : (
|
||||
<View style={{height, width: '100%'}}>
|
||||
<WebView
|
||||
javaScriptEnabled={true}
|
||||
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
|
||||
mediaPlaybackRequiresUserAction={false}
|
||||
allowsInlineMediaPlayback
|
||||
bounces={false}
|
||||
allowsFullscreenVideo
|
||||
nestedScrollEnabled
|
||||
source={{uri: params.playerUri}}
|
||||
onLoad={onLoad}
|
||||
setSupportMultipleWindows={false} // Prevent any redirects from opening a new window (ads)
|
||||
style={[styles.webview, styles.topRadius]}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</EventStopper>
|
||||
</View>
|
||||
)
|
||||
|
|
@ -125,6 +120,8 @@ export function ExternalPlayer({
|
|||
const navigation = useNavigation<NavigationProp>()
|
||||
const insets = useSafeAreaInsets()
|
||||
const windowDims = useWindowDimensions()
|
||||
const externalEmbedsPrefs = useExternalEmbedsPrefs()
|
||||
const {openModal} = useModalControls()
|
||||
|
||||
const [isPlayerActive, setPlayerActive] = React.useState(false)
|
||||
const [isLoading, setIsLoading] = React.useState(true)
|
||||
|
|
@ -194,12 +191,26 @@ export function ExternalPlayer({
|
|||
setIsLoading(false)
|
||||
}, [])
|
||||
|
||||
const onPlayPress = React.useCallback((event: GestureResponderEvent) => {
|
||||
// Prevent this from propagating upward on web
|
||||
event.preventDefault()
|
||||
const onPlayPress = React.useCallback(
|
||||
(event: GestureResponderEvent) => {
|
||||
// Prevent this from propagating upward on web
|
||||
event.preventDefault()
|
||||
|
||||
setPlayerActive(true)
|
||||
}, [])
|
||||
if (externalEmbedsPrefs?.[params.source] === undefined) {
|
||||
openModal({
|
||||
name: 'embed-consent',
|
||||
source: params.source,
|
||||
onAccept: () => {
|
||||
setPlayerActive(true)
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
setPlayerActive(true)
|
||||
},
|
||||
[externalEmbedsPrefs, openModal, params.source],
|
||||
)
|
||||
|
||||
// measure the layout to set sizing
|
||||
const onLayout = React.useCallback(
|
||||
|
|
@ -231,7 +242,6 @@ export function ExternalPlayer({
|
|||
accessibilityIgnoresInvertColors
|
||||
/>
|
||||
)}
|
||||
|
||||
<PlaceholderOverlay
|
||||
isLoading={isLoading}
|
||||
isPlayerActive={isPlayerActive}
|
||||
|
|
@ -274,4 +284,8 @@ const styles = StyleSheet.create({
|
|||
webview: {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
gifContainer: {
|
||||
width: '100%',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue