fix keyboard nav + mute state
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
import {createSinglePathSVG} from './TEMPLATE'
|
import {createSinglePathSVG} from './TEMPLATE'
|
||||||
|
|
||||||
export const Pause_Stroke2_Corner0_Rounded = createSinglePathSVG({
|
export const Pause_Stroke2_Corner2_Rounded = createSinglePathSVG({
|
||||||
path: 'M4 6a3 3 0 0 1 6 0v12a3 3 0 1 1-6 0V6Zm3-1a1 1 0 0 0-1 1v12a1 1 0 1 0 2 0V6a1 1 0 0 0-1-1Zm7 1a3 3 0 1 1 6 0v12a3 3 0 1 1-6 0V6Zm3-1a1 1 0 0 0-1 1v12a1 1 0 1 0 2 0V6a1 1 0 0 0-1-1Z',
|
path: 'M4 6a3 3 0 0 1 6 0v12a3 3 0 1 1-6 0V6Zm3-1a1 1 0 0 0-1 1v12a1 1 0 1 0 2 0V6a1 1 0 0 0-1-1Zm7 1a3 3 0 1 1 6 0v12a3 3 0 1 1-6 0V6Zm3-1a1 1 0 0 0-1 1v12a1 1 0 1 0 2 0V6a1 1 0 0 0-1-1Z',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const Pause_Filled_Corner0_Rounded = createSinglePathSVG({
|
export const Pause_Filled_Corner2_Rounded = createSinglePathSVG({
|
||||||
path: 'M4 6a3 3 0 0 1 6 0v12a3 3 0 1 1-6 0V6ZM14 6a3 3 0 1 1 6 0v12a3 3 0 1 1-6 0V6Z',
|
path: 'M4 6a3 3 0 0 1 6 0v12a3 3 0 1 1-6 0V6ZM14 6a3 3 0 1 1 6 0v12a3 3 0 1 1-6 0V6Z',
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import React, {useCallback, useEffect, useRef, useState} from 'react'
|
import React, {useCallback, useEffect, useRef, useState} from 'react'
|
||||||
import {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} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import Hls from 'hls.js'
|
import Hls from 'hls.js'
|
||||||
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Button, ButtonIcon} from '#/components/Button'
|
import {Button} from '#/components/Button'
|
||||||
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
||||||
import {ArrowsDiagonalOut_Stroke2_Corner2_Rounded as FullscreenIcon} from '#/components/icons/ArrowsDiagonal'
|
import {ArrowsDiagonalOut_Stroke2_Corner2_Rounded as FullscreenIcon} from '#/components/icons/ArrowsDiagonal'
|
||||||
import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute'
|
import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute'
|
||||||
import {Pause_Filled_Corner0_Rounded as PauseIcon} from '#/components/icons/Pause'
|
import {Pause_Filled_Corner2_Rounded as PauseIcon} from '#/components/icons/Pause'
|
||||||
import {Play_Filled_Corner2_Rounded as PlayIcon} from '#/components/icons/Play'
|
import {Play_Filled_Corner2_Rounded as PlayIcon} from '#/components/icons/Play'
|
||||||
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker'
|
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker'
|
||||||
|
|
||||||
@@ -202,6 +202,7 @@ function Controls({
|
|||||||
onIn: onMouseEnter,
|
onIn: onMouseEnter,
|
||||||
onOut: onMouseLeave,
|
onOut: onMouseLeave,
|
||||||
} = useInteractionState()
|
} = useInteractionState()
|
||||||
|
const {state: hasFocus, onIn: onFocus, onOut: onBlur} = useInteractionState()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (active) {
|
if (active) {
|
||||||
@@ -219,74 +220,102 @@ function Controls({
|
|||||||
}
|
}
|
||||||
}, [onScreen, pause])
|
}, [onScreen, pause])
|
||||||
|
|
||||||
|
const onPressPlayPause = useCallback(() => {
|
||||||
|
if (!focused) {
|
||||||
|
if (!active) {
|
||||||
|
setActive()
|
||||||
|
}
|
||||||
|
setFocused(true)
|
||||||
|
} else {
|
||||||
|
togglePlayPause()
|
||||||
|
}
|
||||||
|
}, [togglePlayPause, setActive, setFocused, active, focused])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
inset: 0,
|
inset: 0,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}}
|
display: 'flex',
|
||||||
onClick={evt => {
|
flexDirection: 'column',
|
||||||
evt.stopPropagation()
|
|
||||||
if (!focused) {
|
|
||||||
if (!active) {
|
|
||||||
setActive()
|
|
||||||
}
|
|
||||||
setFocused(true)
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
onMouseLeave={onMouseLeave}>
|
onMouseLeave={onMouseLeave}
|
||||||
{hovered && (
|
onFocus={onFocus}
|
||||||
<>
|
onBlur={onBlur}>
|
||||||
<View
|
<Pressable
|
||||||
style={[
|
accessibilityRole="button"
|
||||||
a.w_full,
|
accessibilityHint={_(
|
||||||
a.px_sm,
|
focused
|
||||||
a.pt_md,
|
? msg`Unmute video`
|
||||||
a.pb_lg,
|
: playing
|
||||||
a.absolute,
|
? msg`Pause video`
|
||||||
a.gap_xs,
|
: msg`Play video`,
|
||||||
a.flex_row,
|
)}
|
||||||
{bottom: 0},
|
style={[a.flex_1]}
|
||||||
{backgroundColor: 'rgba(0, 0, 0, 0.5)'},
|
onPress={onPressPlayPause}
|
||||||
]}>
|
/>
|
||||||
<Button
|
<View
|
||||||
label={_(playing ? msg`Pause` : msg`Play`)}
|
style={[
|
||||||
onPress={() => togglePlayPause()}
|
a.flex_shrink_0,
|
||||||
variant="ghost"
|
a.w_full,
|
||||||
shape="round"
|
a.px_sm,
|
||||||
size="medium">
|
a.pt_sm,
|
||||||
<ButtonIcon icon={playing ? PauseIcon : PlayIcon} />
|
a.pb_md,
|
||||||
</Button>
|
a.gap_sm,
|
||||||
<View style={a.flex_1} />
|
a.flex_row,
|
||||||
<Button
|
{backgroundColor: 'rgba(0, 0, 0, 0.5)'},
|
||||||
label={_(muted ? msg`Unmute` : msg`Mute`)}
|
hovered || hasFocus ? {opacity: 1} : {opacity: 0},
|
||||||
onPress={() => toggleMute()}
|
]}>
|
||||||
variant="ghost"
|
<Button
|
||||||
shape="round"
|
label={_(playing ? msg`Pause` : msg`Play`)}
|
||||||
size="medium">
|
onPress={onPressPlayPause}
|
||||||
<ButtonIcon icon={muted ? MuteIcon : UnmuteIcon} />
|
variant="ghost"
|
||||||
</Button>
|
shape="round"
|
||||||
{/* TODO: find workaround for iOS Safari */}
|
size="medium">
|
||||||
<Button
|
{playing ? (
|
||||||
label={_(muted ? msg`Unmute` : msg`Mute`)}
|
<PauseIcon fill={t.palette.white} width={20} />
|
||||||
onPress={() => {
|
) : (
|
||||||
if (document.fullscreenElement) {
|
<PlayIcon fill={t.palette.white} width={20} />
|
||||||
document.exitFullscreen()
|
)}
|
||||||
} else {
|
</Button>
|
||||||
enterFullscreen()
|
<View style={a.flex_1} />
|
||||||
}
|
<Button
|
||||||
}}
|
label={_(muted ? msg`Unmute` : msg`Mute`)}
|
||||||
variant="ghost"
|
onPress={() => {
|
||||||
shape="round"
|
if (!active) {
|
||||||
size="medium">
|
setActive()
|
||||||
<ButtonIcon icon={FullscreenIcon} />
|
}
|
||||||
</Button>
|
setFocused(true)
|
||||||
</View>
|
toggleMute()
|
||||||
</>
|
}}
|
||||||
)}
|
variant="ghost"
|
||||||
{(hovered || !focused) && (
|
shape="round"
|
||||||
|
size="medium">
|
||||||
|
{muted ? (
|
||||||
|
<MuteIcon fill={t.palette.white} width={20} />
|
||||||
|
) : (
|
||||||
|
<UnmuteIcon fill={t.palette.white} width={20} />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
{/* TODO: find workaround for iOS Safari */}
|
||||||
|
<Button
|
||||||
|
label={_(muted ? msg`Unmute` : msg`Mute`)}
|
||||||
|
onPress={() => {
|
||||||
|
if (document.fullscreenElement) {
|
||||||
|
document.exitFullscreen()
|
||||||
|
} else {
|
||||||
|
enterFullscreen()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
size="medium">
|
||||||
|
<FullscreenIcon fill={t.palette.white} width={20} />
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
{(hovered || hasFocus || !focused) && (
|
||||||
<Animated.View
|
<Animated.View
|
||||||
entering={FadeIn.duration(200)}
|
entering={FadeIn.duration(200)}
|
||||||
exiting={FadeOut.duration(200)}
|
exiting={FadeOut.duration(200)}
|
||||||
@@ -353,20 +382,16 @@ function useVideoUtils(ref: React.RefObject<HTMLVideoElement>) {
|
|||||||
setPlaying(false)
|
setPlaying(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleMute = () => {
|
const handleVolumeChange = () => {
|
||||||
setMuted(true)
|
if (!current) return
|
||||||
}
|
setMuted(current.muted)
|
||||||
|
|
||||||
const handleUnmute = () => {
|
|
||||||
setMuted(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ref.current.addEventListener('timeupdate', handleTimeUpdate)
|
ref.current.addEventListener('timeupdate', handleTimeUpdate)
|
||||||
ref.current.addEventListener('durationchange', handleDurationChange)
|
ref.current.addEventListener('durationchange', handleDurationChange)
|
||||||
ref.current.addEventListener('play', handlePlay)
|
ref.current.addEventListener('play', handlePlay)
|
||||||
ref.current.addEventListener('pause', handlePause)
|
ref.current.addEventListener('pause', handlePause)
|
||||||
ref.current.addEventListener('mute', handleMute)
|
ref.current.addEventListener('volumechange', handleVolumeChange)
|
||||||
ref.current.addEventListener('unmute', handleUnmute)
|
|
||||||
ref.current.addEventListener('ended', handlePause)
|
ref.current.addEventListener('ended', handlePause)
|
||||||
ref.current.addEventListener('error', handlePause)
|
ref.current.addEventListener('error', handlePause)
|
||||||
|
|
||||||
@@ -375,8 +400,7 @@ function useVideoUtils(ref: React.RefObject<HTMLVideoElement>) {
|
|||||||
current.removeEventListener('durationchange', handleDurationChange)
|
current.removeEventListener('durationchange', handleDurationChange)
|
||||||
current.removeEventListener('play', handlePlay)
|
current.removeEventListener('play', handlePlay)
|
||||||
current.removeEventListener('pause', handlePause)
|
current.removeEventListener('pause', handlePause)
|
||||||
current.removeEventListener('mute', handleMute)
|
current.removeEventListener('volumechange', handleVolumeChange)
|
||||||
current.removeEventListener('unmute', handleUnmute)
|
|
||||||
current.removeEventListener('ended', handlePause)
|
current.removeEventListener('ended', handlePause)
|
||||||
current.removeEventListener('error', handlePause)
|
current.removeEventListener('error', handlePause)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user