mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at samuel/exp-cli 111 lines 3.4 kB view raw
1import {useCallback} from 'react' 2import {View} from 'react-native' 3import Animated, {FadeIn, FadeOut} from 'react-native-reanimated' 4import {msg} from '@lingui/macro' 5import {useLingui} from '@lingui/react' 6import type React from 'react' 7 8import {isSafari, isTouchDevice} from '#/lib/browser' 9import {atoms as a} from '#/alf' 10import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute' 11import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker' 12import {useVideoVolumeState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext' 13import {ControlButton} from './ControlButton' 14 15export function VolumeControl({ 16 muted, 17 changeMuted, 18 hovered, 19 onHover, 20 onEndHover, 21 drawFocus, 22}: { 23 muted: boolean 24 changeMuted: (muted: boolean | ((prev: boolean) => boolean)) => void 25 hovered: boolean 26 onHover: () => void 27 onEndHover: () => void 28 drawFocus: () => void 29}) { 30 const {_} = useLingui() 31 const [volume, setVolume] = useVideoVolumeState() 32 33 const onVolumeChange = useCallback( 34 (evt: React.ChangeEvent<HTMLInputElement>) => { 35 drawFocus() 36 const vol = sliderVolumeToVideoVolume(Number(evt.target.value)) 37 setVolume(vol) 38 changeMuted(vol === 0) 39 }, 40 [setVolume, drawFocus, changeMuted], 41 ) 42 43 const sliderVolume = muted ? 0 : videoVolumeToSliderVolume(volume) 44 45 const isZeroVolume = volume === 0 46 const onPressMute = useCallback(() => { 47 drawFocus() 48 if (isZeroVolume) { 49 setVolume(1) 50 changeMuted(false) 51 } else { 52 changeMuted(prevMuted => !prevMuted) 53 } 54 }, [drawFocus, setVolume, isZeroVolume, changeMuted]) 55 56 return ( 57 <View 58 onPointerEnter={onHover} 59 onPointerLeave={onEndHover} 60 style={[a.relative]}> 61 {hovered && !isTouchDevice && ( 62 <Animated.View 63 entering={FadeIn.duration(100)} 64 exiting={FadeOut.duration(100)} 65 style={[a.absolute, a.w_full, {height: 100, bottom: '100%'}]}> 66 <View 67 style={[ 68 a.flex_1, 69 a.mb_xs, 70 a.px_2xs, 71 a.py_xs, 72 {backgroundColor: 'rgba(0, 0, 0, 0.6)'}, 73 a.rounded_xs, 74 a.align_center, 75 ]}> 76 <input 77 type="range" 78 min={0} 79 max={100} 80 value={sliderVolume} 81 aria-label={_(msg`Volume`)} 82 style={ 83 // Ridiculous safari hack for old version of safari. Fixed in sonoma beta -h 84 isSafari ? {height: 92, minHeight: '100%'} : {height: '100%'} 85 } 86 onChange={onVolumeChange} 87 // @ts-expect-error for old versions of firefox, and then re-using it for targeting the CSS -sfn 88 orient="vertical" 89 /> 90 </View> 91 </Animated.View> 92 )} 93 <ControlButton 94 active={muted || volume === 0} 95 activeLabel={_(msg({message: `Unmute`, context: 'video'}))} 96 inactiveLabel={_(msg({message: `Mute`, context: 'video'}))} 97 activeIcon={MuteIcon} 98 inactiveIcon={UnmuteIcon} 99 onPress={onPressMute} 100 /> 101 </View> 102 ) 103} 104 105function sliderVolumeToVideoVolume(value: number) { 106 return Math.pow(value / 100, 4) 107} 108 109function videoVolumeToSliderVolume(value: number) { 110 return Math.round(Math.pow(value, 1 / 4) * 100) 111}