play/pause button when autoplay disabled

This commit is contained in:
Samuel Newman
2024-09-12 12:14:47 +01:00
parent b3065b2ba9
commit 5c7beb29b2
2 changed files with 110 additions and 34 deletions
@@ -1,4 +1,5 @@
import React from 'react'
import {StyleProp, ViewStyle} from 'react-native'
import Animated, {FadeInDown, FadeOutDown} from 'react-native-reanimated'
import {atoms as a, native, useTheme} from '#/alf'
@@ -8,7 +9,13 @@ import {Text} from '#/components/Typography'
* Absolutely positioned time indicator showing how many seconds are remaining
* Time is in seconds
*/
export function TimeIndicator({time}: {time: number}) {
export function TimeIndicator({
time,
style,
}: {
time: number
style?: StyleProp<ViewStyle>
}) {
const t = useTheme()
if (isNaN(time)) {
@@ -22,18 +29,20 @@ export function TimeIndicator({time}: {time: number}) {
<Animated.View
entering={native(FadeInDown.duration(300))}
exiting={native(FadeOutDown.duration(500))}
pointerEvents="none"
style={[
{
backgroundColor: 'rgba(0, 0, 0, 0.5)',
borderRadius: 6,
paddingHorizontal: 6,
paddingVertical: 3,
position: 'absolute',
left: 6,
bottom: 6,
minHeight: 21,
justifyContent: 'center',
},
a.absolute,
a.justify_center,
style,
]}>
<Text
style={[
@@ -1,5 +1,5 @@
import React, {useCallback, useRef} from 'react'
import {Pressable, View} from 'react-native'
import React, {useCallback, useEffect, useRef} from 'react'
import {Pressable, StyleProp, View, ViewStyle} from 'react-native'
import Animated, {FadeInDown} from 'react-native-reanimated'
import {VideoView} from 'expo-video'
import {AppBskyEmbedVideo} from '@atproto/api'
@@ -8,10 +8,13 @@ import {useLingui} from '@lingui/react'
import {HITSLOP_30} from '#/lib/constants'
import {clamp} from '#/lib/numbers'
import {useAutoplayDisabled} from '#/state/preferences'
import {isAndroid} from 'platform/detection'
import {useActiveVideoNative} from 'view/com/util/post-embeds/ActiveVideoNativeContext'
import {atoms as a, useTheme} from '#/alf'
import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute'
import {Pause_Filled_Corner0_Rounded as PauseIcon} from '#/components/icons/Pause'
import {Play_Filled_Corner0_Rounded as PlayIcon} from '#/components/icons/Play'
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker'
import {
AudioCategory,
@@ -99,6 +102,18 @@ function VideoControls({
const {_} = useLingui()
const t = useTheme()
const {player, setMutedInFeed} = useActiveVideoNative()
const autoplayDisabled = useAutoplayDisabled()
const [isPlaying, setIsPlaying] = React.useState(player.playing)
useEffect(() => {
function listener(newIsPlaying: boolean) {
setIsPlaying(newIsPlaying)
}
player.addListener('playingChange', listener)
return () => {
player.removeListener('playingChange', listener)
}
}, [player])
const onPressFullscreen = useCallback(() => {
switch (player.status) {
@@ -116,6 +131,15 @@ function VideoControls({
}
}, [player, enterFullscreen])
const togglePlayPause = useCallback(() => {
setIsPlaying(!player.playing)
if (player.playing) {
player.pause()
} else {
player.play()
}
}, [player])
const toggleMuted = useCallback(() => {
const muted = !player.muted
// We want to set this to the _inverse_ of the new value, because we actually want for the audio to be mixed when
@@ -137,7 +161,6 @@ function VideoControls({
return (
<View style={[a.absolute, a.inset_0]}>
{showTime && <TimeIndicator time={timeRemaining} />}
<Pressable
onPress={onPressFullscreen}
style={a.flex_1}
@@ -145,36 +168,80 @@ function VideoControls({
accessibilityHint={_(msg`Tap to enter full screen`)}
accessibilityRole="button"
/>
<Animated.View
entering={FadeInDown.duration(300)}
style={[
a.absolute,
a.rounded_full,
a.justify_center,
{
backgroundColor: 'rgba(0, 0, 0, 0.5)',
paddingHorizontal: 4,
paddingVertical: 4,
bottom: 6,
right: 6,
minHeight: 21,
minWidth: 21,
},
]}>
<Pressable
onPress={toggleMuted}
style={a.flex_1}
accessibilityLabel={isMuted ? _(msg`Muted`) : _(msg`Unmuted`)}
accessibilityHint={_(msg`Tap to toggle sound`)}
accessibilityRole="button"
hitSlop={HITSLOP_30}>
{isMuted ? (
<MuteIcon width={13} fill={t.palette.white} />
{autoplayDisabled && (
<ControlButton
onPress={togglePlayPause}
label={isPlaying ? _(msg`Pause`) : _(msg`Play`)}
accessibilityHint={_(msg`Tap to play or pause`)}
style={{left: 6}}>
{isPlaying ? (
<PauseIcon width={13} fill={t.palette.white} />
) : (
<UnmuteIcon width={13} fill={t.palette.white} />
<PlayIcon width={13} fill={t.palette.white} />
)}
</Pressable>
</Animated.View>
</ControlButton>
)}
{showTime && (
<TimeIndicator
time={timeRemaining}
style={autoplayDisabled ? {left: 33} : {}}
/>
)}
<ControlButton
onPress={toggleMuted}
label={isMuted ? _(msg`Unmute`) : _(msg`Mute`)}
accessibilityHint={_(msg`Tap to toggle sound`)}
style={{right: 6}}>
{isMuted ? (
<MuteIcon width={13} fill={t.palette.white} />
) : (
<UnmuteIcon width={13} fill={t.palette.white} />
)}
</ControlButton>
</View>
)
}
function ControlButton({
onPress,
children,
label,
accessibilityHint,
style,
}: {
onPress: () => void
children: React.ReactNode
label: string
accessibilityHint: string
style?: StyleProp<ViewStyle>
}) {
return (
<Animated.View
entering={FadeInDown.duration(300)}
style={[
a.absolute,
a.rounded_full,
a.justify_center,
{
backgroundColor: 'rgba(0, 0, 0, 0.5)',
paddingHorizontal: 4,
paddingVertical: 4,
bottom: 6,
minHeight: 21,
minWidth: 21,
},
style,
]}>
<Pressable
onPress={onPress}
style={a.flex_1}
accessibilityLabel={label}
accessibilityHint={accessibilityHint}
accessibilityRole="button"
hitSlop={HITSLOP_30}>
{children}
</Pressable>
</Animated.View>
)
}