fullscreen API

This commit is contained in:
Samuel Newman
2024-07-30 20:04:32 +02:00
parent 92664f57d5
commit e7d269e692
@@ -1,4 +1,4 @@
import React, {useEffect, useRef, useState} from 'react' import React, {useCallback, useEffect, useRef, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import Animated, {FadeIn, FadeOut} from 'react-native-reanimated' import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'
import {msg} from '@lingui/macro' import {msg} from '@lingui/macro'
@@ -86,6 +86,7 @@ export function VideoPlayer({
onScreen: boolean onScreen: boolean
}) { }) {
const [hls] = useState(() => new Hls()) const [hls] = useState(() => new Hls())
const containerRef = useRef<HTMLDivElement>(null)
const ref = useRef<HTMLVideoElement>(null) const ref = useRef<HTMLVideoElement>(null)
const [focused, setFocused] = useState(false) const [focused, setFocused] = useState(false)
@@ -115,6 +116,12 @@ export function VideoPlayer({
} }
}, [source, hls]) }, [source, hls])
const enterFullscreen = useCallback(() => {
if (containerRef.current) {
containerRef.current.requestFullscreen()
}
}, [])
return ( return (
<View <View
style={[ style={[
@@ -136,6 +143,7 @@ export function VideoPlayer({
pointerEvents: 'none', pointerEvents: 'none',
}} }}
/> />
<div ref={containerRef} style={{flex: 1}}>
<Controls <Controls
videoRef={ref} videoRef={ref}
active={active} active={active}
@@ -143,6 +151,7 @@ export function VideoPlayer({
focused={focused} focused={focused}
setFocused={setFocused} setFocused={setFocused}
onScreen={onScreen} onScreen={onScreen}
enterFullscreen={enterFullscreen}
/> />
<video <video
src={source} src={source}
@@ -153,6 +162,7 @@ export function VideoPlayer({
loop loop
muted={!focused} muted={!focused}
/> />
</div>
</View> </View>
) )
} }
@@ -164,6 +174,7 @@ function Controls({
focused, focused,
setFocused, setFocused,
onScreen, onScreen,
enterFullscreen,
}: { }: {
videoRef: React.RefObject<HTMLVideoElement> videoRef: React.RefObject<HTMLVideoElement>
active: boolean active: boolean
@@ -171,6 +182,7 @@ function Controls({
focused: boolean focused: boolean
setFocused: (focused: boolean) => void setFocused: (focused: boolean) => void
onScreen: boolean onScreen: boolean
enterFullscreen: () => void
}) { }) {
const {play, pause, playing, muted, togglePlayPause, currentTime, duration} = const {play, pause, playing, muted, togglePlayPause, currentTime, duration} =
useVideoUtils(videoRef) useVideoUtils(videoRef)
@@ -217,6 +229,7 @@ function Controls({
onMouseEnter={onMouseEnter} onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}> onMouseLeave={onMouseLeave}>
{hovered && ( {hovered && (
<>
<View <View
style={[ style={[
a.w_full, a.w_full,
@@ -237,6 +250,7 @@ function Controls({
size="medium"> size="medium">
<ButtonIcon icon={playing ? PauseIcon : PlayIcon} /> <ButtonIcon icon={playing ? PauseIcon : PlayIcon} />
</Button> </Button>
<View style={a.flex_1} />
<Button <Button
label={_(muted ? msg`Unmute` : msg`Mute`)} label={_(muted ? msg`Unmute` : msg`Mute`)}
onPress={() => { onPress={() => {
@@ -247,12 +261,15 @@ function Controls({
size="medium"> size="medium">
<ButtonIcon icon={muted ? MuteIcon : UnmuteIcon} /> <ButtonIcon icon={muted ? MuteIcon : UnmuteIcon} />
</Button> </Button>
<View style={a.flex_1} />
{/* TODO: find workaround for iOS Safari */} {/* TODO: find workaround for iOS Safari */}
<Button <Button
label={_(muted ? msg`Unmute` : msg`Mute`)} label={_(muted ? msg`Unmute` : msg`Mute`)}
onPress={() => { onPress={() => {
console.log('clicked fullscreen btn') if (document.fullscreenElement) {
document.exitFullscreen()
} else {
enterFullscreen()
}
}} }}
variant="ghost" variant="ghost"
shape="round" shape="round"
@@ -260,6 +277,7 @@ function Controls({
<ButtonIcon icon={FullscreenIcon} /> <ButtonIcon icon={FullscreenIcon} />
</Button> </Button>
</View> </View>
</>
)} )}
{(hovered || !focused) && ( {(hovered || !focused) && (
<Animated.View <Animated.View
@@ -305,6 +323,13 @@ function useVideoUtils(ref: React.RefObject<HTMLVideoElement>) {
if (!ref.current) return if (!ref.current) return
let current = ref.current let current = ref.current
// Initial values
setCurrentTime(current.currentTime || 0)
setDuration(current.duration || 0)
setCanPlay(current.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA)
setMuted(current.muted)
setPlaying(!current.paused)
const handleTimeUpdate = () => { const handleTimeUpdate = () => {
if (!current) return if (!current) return
setCurrentTime(current.currentTime || 0) setCurrentTime(current.currentTime || 0)
@@ -384,11 +409,7 @@ function useVideoUtils(ref: React.RefObject<HTMLVideoElement>) {
} }
const togglePlayPause = () => { const togglePlayPause = () => {
if (playing) { setPlaying(p => !p)
play()
} else {
pause()
}
} }
return {play, pause, togglePlayPause, duration, currentTime, playing, muted} return {play, pause, togglePlayPause, duration, currentTime, playing, muted}