[Video] Remember mute state while scrolling (#5331)

zio/dev^2
Hailey 2024-09-13 14:07:13 -07:00 committed by GitHub
parent 791bc7afbe
commit 843f9925f5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 121 additions and 83 deletions

View File

@ -68,7 +68,7 @@
"@fortawesome/free-regular-svg-icons": "^6.1.1", "@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1", "@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/react-native-fontawesome": "^0.3.2", "@fortawesome/react-native-fontawesome": "^0.3.2",
"@haileyok/bluesky-video": "0.1.2", "@haileyok/bluesky-video": "0.1.4",
"@lingui/react": "^4.5.0", "@lingui/react": "^4.5.0",
"@mattermost/react-native-paste-input": "^0.7.1", "@mattermost/react-native-paste-input": "^0.7.1",
"@miblanchard/react-native-slider": "^2.3.1", "@miblanchard/react-native-slider": "^2.3.1",

View File

@ -52,6 +52,7 @@ import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
import {Provider as StarterPackProvider} from '#/state/shell/starter-pack' import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies' import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
import {TestCtrls} from '#/view/com/testing/TestCtrls' import {TestCtrls} from '#/view/com/testing/TestCtrls'
import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext'
import * as Toast from '#/view/com/util/Toast' import * as Toast from '#/view/com/util/Toast'
import {Shell} from '#/view/shell' import {Shell} from '#/view/shell'
import {ThemeProvider as Alf} from '#/alf' import {ThemeProvider as Alf} from '#/alf'
@ -109,6 +110,7 @@ function InnerApp() {
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<Splash isReady={isReady && hasCheckedReferrer}> <Splash isReady={isReady && hasCheckedReferrer}>
<RootSiblingParent> <RootSiblingParent>
<VideoVolumeProvider>
<React.Fragment <React.Fragment
// Resets the entire tree below when it changes: // Resets the entire tree below when it changes:
key={currentAccount?.did}> key={currentAccount?.did}>
@ -125,7 +127,8 @@ function InnerApp() {
<BackgroundNotificationPreferencesProvider> <BackgroundNotificationPreferencesProvider>
<MutedThreadsProvider> <MutedThreadsProvider>
<ProgressGuideProvider> <ProgressGuideProvider>
<GestureHandlerRootView style={s.h100pct}> <GestureHandlerRootView
style={s.h100pct}>
<TestCtrls /> <TestCtrls />
<Shell /> <Shell />
<NuxDialogs /> <NuxDialogs />
@ -143,6 +146,7 @@ function InnerApp() {
</StatsigProvider> </StatsigProvider>
</QueryProvider> </QueryProvider>
</React.Fragment> </React.Fragment>
</VideoVolumeProvider>
</RootSiblingParent> </RootSiblingParent>
</Splash> </Splash>
</ThemeProvider> </ThemeProvider>

View File

@ -41,6 +41,7 @@ import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
import {Provider as StarterPackProvider} from '#/state/shell/starter-pack' import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies' import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
import {Provider as ActiveVideoProvider} from '#/view/com/util/post-embeds/ActiveVideoWebContext' import {Provider as ActiveVideoProvider} from '#/view/com/util/post-embeds/ActiveVideoWebContext'
import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext'
import * as Toast from '#/view/com/util/Toast' import * as Toast from '#/view/com/util/Toast'
import {ToastContainer} from '#/view/com/util/Toast.web' import {ToastContainer} from '#/view/com/util/Toast.web'
import {Shell} from '#/view/shell/index' import {Shell} from '#/view/shell/index'
@ -95,6 +96,7 @@ function InnerApp() {
<Alf theme={theme}> <Alf theme={theme}>
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<RootSiblingParent> <RootSiblingParent>
<VideoVolumeProvider>
<ActiveVideoProvider> <ActiveVideoProvider>
<React.Fragment <React.Fragment
// Resets the entire tree below when it changes: // Resets the entire tree below when it changes:
@ -131,6 +133,7 @@ function InnerApp() {
</React.Fragment> </React.Fragment>
<ToastContainer /> <ToastContainer />
</ActiveVideoProvider> </ActiveVideoProvider>
</VideoVolumeProvider>
</RootSiblingParent> </RootSiblingParent>
</ThemeProvider> </ThemeProvider>
</Alf> </Alf>

View File

@ -9,6 +9,7 @@ import {useLingui} from '@lingui/react'
import {HITSLOP_30} from '#/lib/constants' import {HITSLOP_30} from '#/lib/constants'
import {clamp} from '#/lib/numbers' import {clamp} from '#/lib/numbers'
import {useAutoplayDisabled} from '#/state/preferences' import {useAutoplayDisabled} from '#/state/preferences'
import {useVideoVolumeState} from 'view/com/util/post-embeds/VideoVolumeContext'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {useIsWithinMessage} from '#/components/dms/MessageContext' import {useIsWithinMessage} from '#/components/dms/MessageContext'
import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute' import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute'
@ -37,8 +38,8 @@ export const VideoEmbedInnerNative = React.forwardRef(
const videoRef = useRef<BlueskyVideoView>(null) const videoRef = useRef<BlueskyVideoView>(null)
const autoplayDisabled = useAutoplayDisabled() const autoplayDisabled = useAutoplayDisabled()
const isWithinMessage = useIsWithinMessage() const isWithinMessage = useIsWithinMessage()
const {muted, setMuted} = useVideoVolumeState()
const [isMuted, setIsMuted] = React.useState(true)
const [isPlaying, setIsPlaying] = React.useState(false) const [isPlaying, setIsPlaying] = React.useState(false)
const [timeRemaining, setTimeRemaining] = React.useState(0) const [timeRemaining, setTimeRemaining] = React.useState(0)
const [error, setError] = React.useState<string>() const [error, setError] = React.useState<string>()
@ -66,7 +67,7 @@ export const VideoEmbedInnerNative = React.forwardRef(
<BlueskyVideoView <BlueskyVideoView
url={embed.playlist} url={embed.playlist}
autoplay={!autoplayDisabled && !isWithinMessage} autoplay={!autoplayDisabled && !isWithinMessage}
beginMuted={true} beginMuted={autoplayDisabled ? false : muted}
style={[a.rounded_sm]} style={[a.rounded_sm]}
onActiveChange={e => { onActiveChange={e => {
setIsActive(e.nativeEvent.isActive) setIsActive(e.nativeEvent.isActive)
@ -75,7 +76,7 @@ export const VideoEmbedInnerNative = React.forwardRef(
setIsLoading(e.nativeEvent.isLoading) setIsLoading(e.nativeEvent.isLoading)
}} }}
onMutedChange={e => { onMutedChange={e => {
setIsMuted(e.nativeEvent.isMuted) setMuted(e.nativeEvent.isMuted)
}} }}
onStatusChange={e => { onStatusChange={e => {
setStatus(e.nativeEvent.status) setStatus(e.nativeEvent.status)
@ -103,7 +104,6 @@ export const VideoEmbedInnerNative = React.forwardRef(
togglePlayback={() => { togglePlayback={() => {
videoRef.current?.togglePlayback() videoRef.current?.togglePlayback()
}} }}
isMuted={isMuted}
isPlaying={isPlaying} isPlaying={isPlaying}
timeRemaining={timeRemaining} timeRemaining={timeRemaining}
/> />
@ -119,17 +119,16 @@ function VideoControls({
togglePlayback, togglePlayback,
timeRemaining, timeRemaining,
isPlaying, isPlaying,
isMuted,
}: { }: {
enterFullscreen: () => void enterFullscreen: () => void
toggleMuted: () => void toggleMuted: () => void
togglePlayback: () => void togglePlayback: () => void
timeRemaining: number timeRemaining: number
isPlaying: boolean isPlaying: boolean
isMuted: boolean
}) { }) {
const {_} = useLingui() const {_} = useLingui()
const t = useTheme() const t = useTheme()
const {muted} = useVideoVolumeState()
// show countdown when: // show countdown when:
// 1. timeRemaining is a number - was seeing NaNs // 1. timeRemaining is a number - was seeing NaNs
@ -161,10 +160,10 @@ function VideoControls({
<ControlButton <ControlButton
onPress={toggleMuted} onPress={toggleMuted}
label={isMuted ? _(msg`Unmute`) : _(msg`Mute`)} label={muted ? _(msg`Unmute`) : _(msg`Mute`)}
accessibilityHint={_(msg`Tap to toggle sound`)} accessibilityHint={_(msg`Tap to toggle sound`)}
style={{right: 6}}> style={{right: 6}}>
{isMuted ? ( {muted ? (
<MuteIcon width={13} fill={t.palette.white} /> <MuteIcon width={13} fill={t.palette.white} />
) : ( ) : (
<UnmuteIcon width={13} fill={t.palette.white} /> <UnmuteIcon width={13} fill={t.palette.white} />

View File

@ -0,0 +1,32 @@
import React from 'react'
const Context = React.createContext(
{} as {
muted: boolean
setMuted: (muted: boolean) => void
},
)
export function Provider({children}: {children: React.ReactNode}) {
const [muted, setMuted] = React.useState(true)
const value = React.useMemo(
() => ({
muted,
setMuted,
}),
[muted, setMuted],
)
return <Context.Provider value={value}>{children}</Context.Provider>
}
export function useVideoVolumeState() {
const context = React.useContext(Context)
if (!context) {
throw new Error(
'useVideoVolumeState must be used within a VideoVolumeProvider',
)
}
return context
}

View File

@ -4104,10 +4104,10 @@
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861"
integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==
"@haileyok/bluesky-video@0.1.2": "@haileyok/bluesky-video@0.1.4":
version "0.1.2" version "0.1.4"
resolved "https://registry.yarnpkg.com/@haileyok/bluesky-video/-/bluesky-video-0.1.2.tgz#53abb04c22885fcf8a1d8a7510d2cfbe7d45ff91" resolved "https://registry.yarnpkg.com/@haileyok/bluesky-video/-/bluesky-video-0.1.4.tgz#76acad0dffb9c80745bb752577be23cb566e4562"
integrity sha512-OPltVPNhjrm/+d4YYbaSsKLK7VQWC62ci8J05GO4I/PhWsYLWsAu79CGfZ1YTpfpIjYXyo0HjMmiig5X/hhOsQ== integrity sha512-ggpk6E6U3giT+tmTc4GPraViA3ssnP32/Bty61UbZ3LiCQuc694LX+AOt01SfQ0B0fyd63J9DtT5rfaEJyjuzg==
"@hapi/accept@^6.0.3": "@hapi/accept@^6.0.3":
version "6.0.3" version "6.0.3"