diff options
Diffstat (limited to 'src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VolumeControl.tsx')
-rw-r--r-- | src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VolumeControl.tsx | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VolumeControl.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VolumeControl.tsx new file mode 100644 index 000000000..63ac32b10 --- /dev/null +++ b/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VolumeControl.tsx @@ -0,0 +1,109 @@ +import React, {useCallback} from 'react' +import {View} from 'react-native' +import Animated, {FadeIn, FadeOut} from 'react-native-reanimated' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {isSafari, isTouchDevice} from '#/lib/browser' +import {atoms as a} from '#/alf' +import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute' +import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker' +import {useVideoVolumeState} from '../../VideoVolumeContext' +import {ControlButton} from './ControlButton' + +export function VolumeControl({ + muted, + changeMuted, + hovered, + onHover, + onEndHover, + drawFocus, +}: { + muted: boolean + changeMuted: (muted: boolean | ((prev: boolean) => boolean)) => void + hovered: boolean + onHover: () => void + onEndHover: () => void + drawFocus: () => void +}) { + const {_} = useLingui() + const [volume, setVolume] = useVideoVolumeState() + + const onVolumeChange = useCallback( + (evt: React.ChangeEvent<HTMLInputElement>) => { + drawFocus() + const vol = sliderVolumeToVideoVolume(Number(evt.target.value)) + setVolume(vol) + changeMuted(vol === 0) + }, + [setVolume, drawFocus, changeMuted], + ) + + const sliderVolume = muted ? 0 : videoVolumeToSliderVolume(volume) + + const isZeroVolume = volume === 0 + const onPressMute = useCallback(() => { + drawFocus() + if (isZeroVolume) { + setVolume(1) + changeMuted(false) + } else { + changeMuted(prevMuted => !prevMuted) + } + }, [drawFocus, setVolume, isZeroVolume, changeMuted]) + + return ( + <View + onPointerEnter={onHover} + onPointerLeave={onEndHover} + style={[a.relative]}> + {hovered && !isTouchDevice && ( + <Animated.View + entering={FadeIn.duration(100)} + exiting={FadeOut.duration(100)} + style={[a.absolute, a.w_full, {height: 100, bottom: '100%'}]}> + <View + style={[ + a.flex_1, + a.mb_xs, + a.px_2xs, + a.py_xs, + {backgroundColor: 'rgba(0, 0, 0, 0.6)'}, + a.rounded_xs, + a.align_center, + ]}> + <input + type="range" + min={0} + max={100} + value={sliderVolume} + style={ + // Ridiculous safari hack for old version of safari. Fixed in sonoma beta -h + isSafari ? {height: 92, minHeight: '100%'} : {height: '100%'} + } + onChange={onVolumeChange} + // @ts-expect-error for old versions of firefox, and then re-using it for targeting the CSS -sfn + orient="vertical" + /> + </View> + </Animated.View> + )} + <ControlButton + active={muted || volume === 0} + activeLabel={_(msg({message: `Unmute`, context: 'video'}))} + inactiveLabel={_(msg({message: `Mute`, context: 'video'}))} + activeIcon={MuteIcon} + inactiveIcon={UnmuteIcon} + onPress={onPressMute} + /> + </View> + ) +} + +function sliderVolumeToVideoVolume(value: number) { + return Math.pow(value / 100, 4) +} + +function videoVolumeToSliderVolume(value: number) { + return Math.round(Math.pow(value, 1 / 4) * 100) +} |