rework fullscreen API

This commit is contained in:
Samuel Newman
2024-08-05 12:01:32 +01:00
parent ada19e1e7f
commit bca7635ca4
3 changed files with 30 additions and 32 deletions
@@ -1,4 +1,4 @@
import React, {useCallback, useEffect, useRef, useState} from 'react' import React, {useEffect, useRef, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import Hls from 'hls.js' import Hls from 'hls.js'
@@ -49,12 +49,6 @@ export function VideoEmbedInner({
} }
}, [source]) }, [source])
const enterFullscreen = useCallback(() => {
if (containerRef.current) {
containerRef.current.requestFullscreen()
}
}, [])
return ( return (
<View <View
style={[ style={[
@@ -84,7 +78,7 @@ export function VideoEmbedInner({
focused={focused} focused={focused}
setFocused={setFocused} setFocused={setFocused}
onScreen={onScreen} onScreen={onScreen}
enterFullscreen={enterFullscreen} fullscreenRef={containerRef}
hasSubtitleTrack={hasSubtitleTrack} hasSubtitleTrack={hasSubtitleTrack}
/> />
</div> </div>
@@ -9,7 +9,7 @@ export function Controls({}: {
focused: boolean focused: boolean
setFocused: (focused: boolean) => void setFocused: (focused: boolean) => void
onScreen: boolean onScreen: boolean
enterFullscreen: () => void fullscreenRef: React.RefObject<HTMLDivElement>
hasSubtitleTrack: boolean hasSubtitleTrack: boolean
}): React.ReactElement { }): React.ReactElement {
throw new Error('Web-only component') throw new Error('Web-only component')
@@ -1,4 +1,10 @@
import React, {useCallback, useEffect, useRef, useState} from 'react' import React, {
useCallback,
useEffect,
useRef,
useState,
useSyncExternalStore,
} from 'react'
import {Pressable, View} from 'react-native' import {Pressable, View} from 'react-native'
import Animated, {FadeIn, FadeOut} from 'react-native-reanimated' import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
@@ -36,7 +42,7 @@ export function Controls({
focused, focused,
setFocused, setFocused,
onScreen, onScreen,
enterFullscreen, fullscreenRef,
hasSubtitleTrack, hasSubtitleTrack,
}: { }: {
videoRef: React.RefObject<HTMLVideoElement> videoRef: React.RefObject<HTMLVideoElement>
@@ -46,7 +52,7 @@ export function Controls({
focused: boolean focused: boolean
setFocused: (focused: boolean) => void setFocused: (focused: boolean) => void
onScreen: boolean onScreen: boolean
enterFullscreen: () => void fullscreenRef: React.RefObject<HTMLDivElement>
hasSubtitleTrack: boolean hasSubtitleTrack: boolean
}) { }) {
const { const {
@@ -71,7 +77,7 @@ export function Controls({
onIn: onMouseEnter, onIn: onMouseEnter,
onOut: onMouseLeave, onOut: onMouseLeave,
} = useInteractionState() } = useInteractionState()
const isFullscreen = useFullscreen() const [isFullscreen, toggleFullscreen] = useFullscreen(fullscreenRef)
const {state: hasFocus, onIn: onFocus, onOut: onBlur} = useInteractionState() const {state: hasFocus, onIn: onFocus, onOut: onBlur} = useInteractionState()
const [interactingViaKeypress, setInteractingViaKeypress] = useState(false) const [interactingViaKeypress, setInteractingViaKeypress] = useState(false)
@@ -163,12 +169,8 @@ export function Controls({
const onPressFullscreen = useCallback(() => { const onPressFullscreen = useCallback(() => {
drawFocus() drawFocus()
if (document.fullscreenElement) { toggleFullscreen()
document.exitFullscreen() }, [drawFocus, toggleFullscreen])
} else {
enterFullscreen()
}
}, [drawFocus, enterFullscreen])
const showControls = const showControls =
(focused && !playing) || (interactingViaKeypress ? hasFocus : hovered) (focused && !playing) || (interactingViaKeypress ? hasFocus : hovered)
@@ -536,22 +538,24 @@ function useVideoUtils(ref: React.RefObject<HTMLVideoElement>) {
} }
} }
function useFullscreen() { function fullscreenSubscribe(onChange: () => void) {
const [isFullscreen, setIsFullscreen] = useState( document.addEventListener('fullscreenchange', onChange)
return () => document.removeEventListener('fullscreenchange', onChange)
}
function useFullscreen(ref: React.RefObject<HTMLElement>) {
const isFullscreen = useSyncExternalStore(fullscreenSubscribe, () =>
Boolean(document.fullscreenElement), Boolean(document.fullscreenElement),
) )
useEffect(() => { const toggleFullscreen = useCallback(() => {
const handleFullscreenChange = () => { if (isFullscreen) {
setIsFullscreen(Boolean(document.fullscreenElement)) document.exitFullscreen()
} else {
if (!ref.current) return
ref.current.requestFullscreen()
} }
}, [isFullscreen, ref])
document.addEventListener('fullscreenchange', handleFullscreenChange) return [isFullscreen, toggleFullscreen] as const
return () => {
document.removeEventListener('fullscreenchange', handleFullscreenChange)
}
}, [])
return isFullscreen
} }