mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
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}