Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

authored by

Hailey and committed by
GitHub
843f9925 791bc7af

+121 -83
+1 -1
package.json
··· 68 68 "@fortawesome/free-regular-svg-icons": "^6.1.1", 69 69 "@fortawesome/free-solid-svg-icons": "^6.1.1", 70 70 "@fortawesome/react-native-fontawesome": "^0.3.2", 71 - "@haileyok/bluesky-video": "0.1.2", 71 + "@haileyok/bluesky-video": "0.1.4", 72 72 "@lingui/react": "^4.5.0", 73 73 "@mattermost/react-native-paste-input": "^0.7.1", 74 74 "@miblanchard/react-native-slider": "^2.3.1",
+38 -34
src/App.native.tsx
··· 52 52 import {Provider as StarterPackProvider} from '#/state/shell/starter-pack' 53 53 import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies' 54 54 import {TestCtrls} from '#/view/com/testing/TestCtrls' 55 + import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext' 55 56 import * as Toast from '#/view/com/util/Toast' 56 57 import {Shell} from '#/view/shell' 57 58 import {ThemeProvider as Alf} from '#/alf' ··· 109 110 <ThemeProvider theme={theme}> 110 111 <Splash isReady={isReady && hasCheckedReferrer}> 111 112 <RootSiblingParent> 112 - <React.Fragment 113 - // Resets the entire tree below when it changes: 114 - key={currentAccount?.did}> 115 - <QueryProvider currentDid={currentAccount?.did}> 116 - <StatsigProvider> 117 - <MessagesProvider> 118 - {/* LabelDefsProvider MUST come before ModerationOptsProvider */} 119 - <LabelDefsProvider> 120 - <ModerationOptsProvider> 121 - <LoggedOutViewProvider> 122 - <SelectedFeedProvider> 123 - <HiddenRepliesProvider> 124 - <UnreadNotifsProvider> 125 - <BackgroundNotificationPreferencesProvider> 126 - <MutedThreadsProvider> 127 - <ProgressGuideProvider> 128 - <GestureHandlerRootView style={s.h100pct}> 129 - <TestCtrls /> 130 - <Shell /> 131 - <NuxDialogs /> 132 - </GestureHandlerRootView> 133 - </ProgressGuideProvider> 134 - </MutedThreadsProvider> 135 - </BackgroundNotificationPreferencesProvider> 136 - </UnreadNotifsProvider> 137 - </HiddenRepliesProvider> 138 - </SelectedFeedProvider> 139 - </LoggedOutViewProvider> 140 - </ModerationOptsProvider> 141 - </LabelDefsProvider> 142 - </MessagesProvider> 143 - </StatsigProvider> 144 - </QueryProvider> 145 - </React.Fragment> 113 + <VideoVolumeProvider> 114 + <React.Fragment 115 + // Resets the entire tree below when it changes: 116 + key={currentAccount?.did}> 117 + <QueryProvider currentDid={currentAccount?.did}> 118 + <StatsigProvider> 119 + <MessagesProvider> 120 + {/* LabelDefsProvider MUST come before ModerationOptsProvider */} 121 + <LabelDefsProvider> 122 + <ModerationOptsProvider> 123 + <LoggedOutViewProvider> 124 + <SelectedFeedProvider> 125 + <HiddenRepliesProvider> 126 + <UnreadNotifsProvider> 127 + <BackgroundNotificationPreferencesProvider> 128 + <MutedThreadsProvider> 129 + <ProgressGuideProvider> 130 + <GestureHandlerRootView 131 + style={s.h100pct}> 132 + <TestCtrls /> 133 + <Shell /> 134 + <NuxDialogs /> 135 + </GestureHandlerRootView> 136 + </ProgressGuideProvider> 137 + </MutedThreadsProvider> 138 + </BackgroundNotificationPreferencesProvider> 139 + </UnreadNotifsProvider> 140 + </HiddenRepliesProvider> 141 + </SelectedFeedProvider> 142 + </LoggedOutViewProvider> 143 + </ModerationOptsProvider> 144 + </LabelDefsProvider> 145 + </MessagesProvider> 146 + </StatsigProvider> 147 + </QueryProvider> 148 + </React.Fragment> 149 + </VideoVolumeProvider> 146 150 </RootSiblingParent> 147 151 </Splash> 148 152 </ThemeProvider>
+39 -36
src/App.web.tsx
··· 41 41 import {Provider as StarterPackProvider} from '#/state/shell/starter-pack' 42 42 import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies' 43 43 import {Provider as ActiveVideoProvider} from '#/view/com/util/post-embeds/ActiveVideoWebContext' 44 + import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext' 44 45 import * as Toast from '#/view/com/util/Toast' 45 46 import {ToastContainer} from '#/view/com/util/Toast.web' 46 47 import {Shell} from '#/view/shell/index' ··· 95 96 <Alf theme={theme}> 96 97 <ThemeProvider theme={theme}> 97 98 <RootSiblingParent> 98 - <ActiveVideoProvider> 99 - <React.Fragment 100 - // Resets the entire tree below when it changes: 101 - key={currentAccount?.did}> 102 - <QueryProvider currentDid={currentAccount?.did}> 103 - <StatsigProvider> 104 - <MessagesProvider> 105 - {/* LabelDefsProvider MUST come before ModerationOptsProvider */} 106 - <LabelDefsProvider> 107 - <ModerationOptsProvider> 108 - <LoggedOutViewProvider> 109 - <SelectedFeedProvider> 110 - <HiddenRepliesProvider> 111 - <UnreadNotifsProvider> 112 - <BackgroundNotificationPreferencesProvider> 113 - <MutedThreadsProvider> 114 - <SafeAreaProvider> 115 - <ProgressGuideProvider> 116 - <Shell /> 117 - <NuxDialogs /> 118 - </ProgressGuideProvider> 119 - </SafeAreaProvider> 120 - </MutedThreadsProvider> 121 - </BackgroundNotificationPreferencesProvider> 122 - </UnreadNotifsProvider> 123 - </HiddenRepliesProvider> 124 - </SelectedFeedProvider> 125 - </LoggedOutViewProvider> 126 - </ModerationOptsProvider> 127 - </LabelDefsProvider> 128 - </MessagesProvider> 129 - </StatsigProvider> 130 - </QueryProvider> 131 - </React.Fragment> 132 - <ToastContainer /> 133 - </ActiveVideoProvider> 99 + <VideoVolumeProvider> 100 + <ActiveVideoProvider> 101 + <React.Fragment 102 + // Resets the entire tree below when it changes: 103 + key={currentAccount?.did}> 104 + <QueryProvider currentDid={currentAccount?.did}> 105 + <StatsigProvider> 106 + <MessagesProvider> 107 + {/* LabelDefsProvider MUST come before ModerationOptsProvider */} 108 + <LabelDefsProvider> 109 + <ModerationOptsProvider> 110 + <LoggedOutViewProvider> 111 + <SelectedFeedProvider> 112 + <HiddenRepliesProvider> 113 + <UnreadNotifsProvider> 114 + <BackgroundNotificationPreferencesProvider> 115 + <MutedThreadsProvider> 116 + <SafeAreaProvider> 117 + <ProgressGuideProvider> 118 + <Shell /> 119 + <NuxDialogs /> 120 + </ProgressGuideProvider> 121 + </SafeAreaProvider> 122 + </MutedThreadsProvider> 123 + </BackgroundNotificationPreferencesProvider> 124 + </UnreadNotifsProvider> 125 + </HiddenRepliesProvider> 126 + </SelectedFeedProvider> 127 + </LoggedOutViewProvider> 128 + </ModerationOptsProvider> 129 + </LabelDefsProvider> 130 + </MessagesProvider> 131 + </StatsigProvider> 132 + </QueryProvider> 133 + </React.Fragment> 134 + <ToastContainer /> 135 + </ActiveVideoProvider> 136 + </VideoVolumeProvider> 134 137 </RootSiblingParent> 135 138 </ThemeProvider> 136 139 </Alf>
+7 -8
src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx
··· 9 9 import {HITSLOP_30} from '#/lib/constants' 10 10 import {clamp} from '#/lib/numbers' 11 11 import {useAutoplayDisabled} from '#/state/preferences' 12 + import {useVideoVolumeState} from 'view/com/util/post-embeds/VideoVolumeContext' 12 13 import {atoms as a, useTheme} from '#/alf' 13 14 import {useIsWithinMessage} from '#/components/dms/MessageContext' 14 15 import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute' ··· 37 38 const videoRef = useRef<BlueskyVideoView>(null) 38 39 const autoplayDisabled = useAutoplayDisabled() 39 40 const isWithinMessage = useIsWithinMessage() 41 + const {muted, setMuted} = useVideoVolumeState() 40 42 41 - const [isMuted, setIsMuted] = React.useState(true) 42 43 const [isPlaying, setIsPlaying] = React.useState(false) 43 44 const [timeRemaining, setTimeRemaining] = React.useState(0) 44 45 const [error, setError] = React.useState<string>() ··· 66 67 <BlueskyVideoView 67 68 url={embed.playlist} 68 69 autoplay={!autoplayDisabled && !isWithinMessage} 69 - beginMuted={true} 70 + beginMuted={autoplayDisabled ? false : muted} 70 71 style={[a.rounded_sm]} 71 72 onActiveChange={e => { 72 73 setIsActive(e.nativeEvent.isActive) ··· 75 76 setIsLoading(e.nativeEvent.isLoading) 76 77 }} 77 78 onMutedChange={e => { 78 - setIsMuted(e.nativeEvent.isMuted) 79 + setMuted(e.nativeEvent.isMuted) 79 80 }} 80 81 onStatusChange={e => { 81 82 setStatus(e.nativeEvent.status) ··· 103 104 togglePlayback={() => { 104 105 videoRef.current?.togglePlayback() 105 106 }} 106 - isMuted={isMuted} 107 107 isPlaying={isPlaying} 108 108 timeRemaining={timeRemaining} 109 109 /> ··· 119 119 togglePlayback, 120 120 timeRemaining, 121 121 isPlaying, 122 - isMuted, 123 122 }: { 124 123 enterFullscreen: () => void 125 124 toggleMuted: () => void 126 125 togglePlayback: () => void 127 126 timeRemaining: number 128 127 isPlaying: boolean 129 - isMuted: boolean 130 128 }) { 131 129 const {_} = useLingui() 132 130 const t = useTheme() 131 + const {muted} = useVideoVolumeState() 133 132 134 133 // show countdown when: 135 134 // 1. timeRemaining is a number - was seeing NaNs ··· 161 160 162 161 <ControlButton 163 162 onPress={toggleMuted} 164 - label={isMuted ? _(msg`Unmute`) : _(msg`Mute`)} 163 + label={muted ? _(msg`Unmute`) : _(msg`Mute`)} 165 164 accessibilityHint={_(msg`Tap to toggle sound`)} 166 165 style={{right: 6}}> 167 - {isMuted ? ( 166 + {muted ? ( 168 167 <MuteIcon width={13} fill={t.palette.white} /> 169 168 ) : ( 170 169 <UnmuteIcon width={13} fill={t.palette.white} />
+32
src/view/com/util/post-embeds/VideoVolumeContext.tsx
··· 1 + import React from 'react' 2 + 3 + const Context = React.createContext( 4 + {} as { 5 + muted: boolean 6 + setMuted: (muted: boolean) => void 7 + }, 8 + ) 9 + 10 + export function Provider({children}: {children: React.ReactNode}) { 11 + const [muted, setMuted] = React.useState(true) 12 + 13 + const value = React.useMemo( 14 + () => ({ 15 + muted, 16 + setMuted, 17 + }), 18 + [muted, setMuted], 19 + ) 20 + 21 + return <Context.Provider value={value}>{children}</Context.Provider> 22 + } 23 + 24 + export function useVideoVolumeState() { 25 + const context = React.useContext(Context) 26 + if (!context) { 27 + throw new Error( 28 + 'useVideoVolumeState must be used within a VideoVolumeProvider', 29 + ) 30 + } 31 + return context 32 + }
+4 -4
yarn.lock
··· 4104 4104 resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" 4105 4105 integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== 4106 4106 4107 - "@haileyok/bluesky-video@0.1.2": 4108 - version "0.1.2" 4109 - resolved "https://registry.yarnpkg.com/@haileyok/bluesky-video/-/bluesky-video-0.1.2.tgz#53abb04c22885fcf8a1d8a7510d2cfbe7d45ff91" 4110 - integrity sha512-OPltVPNhjrm/+d4YYbaSsKLK7VQWC62ci8J05GO4I/PhWsYLWsAu79CGfZ1YTpfpIjYXyo0HjMmiig5X/hhOsQ== 4107 + "@haileyok/bluesky-video@0.1.4": 4108 + version "0.1.4" 4109 + resolved "https://registry.yarnpkg.com/@haileyok/bluesky-video/-/bluesky-video-0.1.4.tgz#76acad0dffb9c80745bb752577be23cb566e4562" 4110 + integrity sha512-ggpk6E6U3giT+tmTc4GPraViA3ssnP32/Bty61UbZ3LiCQuc694LX+AOt01SfQ0B0fyd63J9DtT5rfaEJyjuzg== 4111 4111 4112 4112 "@hapi/accept@^6.0.3": 4113 4113 version "6.0.3"