diff options
author | Hailey <me@haileyok.com> | 2024-08-28 08:46:47 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-28 08:46:47 -0700 |
commit | 5ae0d40a14e7015daa0161e7e9d877690f8a339e (patch) | |
tree | e8be0c39c72ef55ae65b69f3cf8cb34b902bdbff | |
parent | 9aa2b2d14e833a7efa8a22688ac8bd80f8f57dac (diff) | |
download | voidsky-5ae0d40a14e7015daa0161e7e9d877690f8a339e.tar.zst |
[Video] 🫧 Move logic around by platform (#5003)
-rw-r--r-- | src/App.native.tsx | 2 | ||||
-rw-r--r-- | src/App.web.tsx | 2 | ||||
-rw-r--r-- | src/view/com/util/post-embeds/ActiveVideoNativeContext.tsx | 40 | ||||
-rw-r--r-- | src/view/com/util/post-embeds/ActiveVideoWebContext.tsx (renamed from src/view/com/util/post-embeds/ActiveVideoContext.tsx) | 51 | ||||
-rw-r--r-- | src/view/com/util/post-embeds/VideoEmbed.tsx | 13 | ||||
-rw-r--r-- | src/view/com/util/post-embeds/VideoEmbed.web.tsx | 4 | ||||
-rw-r--r-- | src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx | 4 | ||||
-rw-r--r-- | src/view/com/util/post-embeds/VideoPlayerContext.tsx | 47 | ||||
-rw-r--r-- | src/view/com/util/post-embeds/VideoPlayerContext.web.tsx | 9 |
9 files changed, 77 insertions, 95 deletions
diff --git a/src/App.native.tsx b/src/App.native.tsx index 69c7629bf..a4282e7fb 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -52,7 +52,7 @@ import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed' import {Provider as StarterPackProvider} from '#/state/shell/starter-pack' import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies' import {TestCtrls} from '#/view/com/testing/TestCtrls' -import {ActiveVideoProvider} from '#/view/com/util/post-embeds/ActiveVideoContext' +import {Provider as ActiveVideoProvider} from '#/view/com/util/post-embeds/ActiveVideoNativeContext' import * as Toast from '#/view/com/util/Toast' import {Shell} from '#/view/shell' import {ThemeProvider as Alf} from '#/alf' diff --git a/src/App.web.tsx b/src/App.web.tsx index 9ec792530..69a8020c2 100644 --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -40,7 +40,7 @@ import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide' import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed' import {Provider as StarterPackProvider} from '#/state/shell/starter-pack' import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies' -import {ActiveVideoProvider} from '#/view/com/util/post-embeds/ActiveVideoContext' +import {Provider as ActiveVideoProvider} from '#/view/com/util/post-embeds/ActiveVideoWebContext' import * as Toast from '#/view/com/util/Toast' import {ToastContainer} from '#/view/com/util/Toast.web' import {Shell} from '#/view/shell/index' diff --git a/src/view/com/util/post-embeds/ActiveVideoNativeContext.tsx b/src/view/com/util/post-embeds/ActiveVideoNativeContext.tsx new file mode 100644 index 000000000..77616d788 --- /dev/null +++ b/src/view/com/util/post-embeds/ActiveVideoNativeContext.tsx @@ -0,0 +1,40 @@ +import React from 'react' +import {useVideoPlayer, VideoPlayer} from 'expo-video' + +import {isNative} from '#/platform/detection' + +const Context = React.createContext<{ + activeSource: string | null + setActiveSource: (src: string) => void + player: VideoPlayer +} | null>(null) + +export function Provider({children}: {children: React.ReactNode}) { + if (!isNative) { + throw new Error('ActiveVideoProvider may only be used on native.') + } + + const [activeSource, setActiveSource] = React.useState('') + + const player = useVideoPlayer(activeSource, p => { + p.muted = true + p.loop = true + p.play() + }) + + return ( + <Context.Provider value={{activeSource, setActiveSource, player}}> + {children} + </Context.Provider> + ) +} + +export function useActiveVideoNative() { + const context = React.useContext(Context) + if (!context) { + throw new Error( + 'useActiveVideoNative must be used within a ActiveVideoNativeProvider', + ) + } + return context +} diff --git a/src/view/com/util/post-embeds/ActiveVideoContext.tsx b/src/view/com/util/post-embeds/ActiveVideoWebContext.tsx index d18dfc090..bc43e997c 100644 --- a/src/view/com/util/post-embeds/ActiveVideoContext.tsx +++ b/src/view/com/util/post-embeds/ActiveVideoWebContext.tsx @@ -8,19 +8,21 @@ import React, { } from 'react' import {useWindowDimensions} from 'react-native' -import {isNative} from '#/platform/detection' -import {VideoPlayerProvider} from './VideoPlayerContext' +import {isNative, isWeb} from '#/platform/detection' -const ActiveVideoContext = React.createContext<{ +const Context = React.createContext<{ activeViewId: string | null - setActiveView: (viewId: string, src: string) => void + setActiveView: (viewId: string) => void sendViewPosition: (viewId: string, y: number) => void } | null>(null) -export function ActiveVideoProvider({children}: {children: React.ReactNode}) { +export function Provider({children}: {children: React.ReactNode}) { + if (!isWeb) { + throw new Error('ActiveVideoWebContext may onl be used on web.') + } + const [activeViewId, setActiveViewId] = useState<string | null>(null) const activeViewLocationRef = useRef(Infinity) - const [source, setSource] = useState<string | null>(null) const {height: windowHeight} = useWindowDimensions() // minimising re-renders by using refs @@ -31,9 +33,8 @@ export function ActiveVideoProvider({children}: {children: React.ReactNode}) { }, [activeViewId]) const setActiveView = useCallback( - (viewId: string, src: string) => { + (viewId: string) => { setActiveViewId(viewId) - setSource(src) manuallySetRef.current = true // we don't know the exact position, but it's definitely on screen // so just guess that it's in the middle. Any value is fine @@ -88,32 +89,26 @@ export function ActiveVideoProvider({children}: {children: React.ReactNode}) { [activeViewId, setActiveView, sendViewPosition], ) - return ( - <ActiveVideoContext.Provider value={value}> - <VideoPlayerProvider source={source ?? ''}> - {children} - </VideoPlayerProvider> - </ActiveVideoContext.Provider> - ) + return <Context.Provider value={value}>{children}</Context.Provider> } -export function useActiveVideoView({source}: {source: string}) { - const context = React.useContext(ActiveVideoContext) +export function useActiveVideoWeb() { + const context = React.useContext(Context) if (!context) { - throw new Error('useActiveVideo must be used within a ActiveVideoProvider') + throw new Error( + 'useActiveVideoWeb must be used within a ActiveVideoWebProvider', + ) } + + const {activeViewId, setActiveView, sendViewPosition} = context const id = useId() return { - active: context.activeViewId === id, - setActive: useCallback( - () => context.setActiveView(id, source), - [context, id, source], - ), - currentActiveView: context.activeViewId, - sendPosition: useCallback( - (y: number) => context.sendViewPosition(id, y), - [context, id], - ), + active: activeViewId === id, + setActive: () => { + setActiveView(id) + }, + currentActiveView: activeViewId, + sendPosition: (y: number) => sendViewPosition(id, y), } } diff --git a/src/view/com/util/post-embeds/VideoEmbed.tsx b/src/view/com/util/post-embeds/VideoEmbed.tsx index 4e2909f40..b2bcd8511 100644 --- a/src/view/com/util/post-embeds/VideoEmbed.tsx +++ b/src/view/com/util/post-embeds/VideoEmbed.tsx @@ -9,12 +9,13 @@ import {Button, ButtonIcon} from '#/components/Button' import {Play_Filled_Corner2_Rounded as PlayIcon} from '#/components/icons/Play' import {VisibilityView} from '../../../../../modules/expo-bluesky-swiss-army' import {ErrorBoundary} from '../ErrorBoundary' -import {useActiveVideoView} from './ActiveVideoContext' +import {useActiveVideoNative} from './ActiveVideoNativeContext' import * as VideoFallback from './VideoEmbedInner/VideoFallback' export function VideoEmbed({source}: {source: string}) { const t = useTheme() - const {active, setActive} = useActiveVideoView({source}) + const {activeSource, setActiveSource} = useActiveVideoNative() + const isActive = source === activeSource const {_} = useLingui() const [key, setKey] = useState(0) @@ -40,15 +41,17 @@ export function VideoEmbed({source}: {source: string}) { enabled={true} onChangeStatus={isActive => { if (isActive) { - setActive() + setActiveSource(source) } }}> - {active ? ( + {isActive ? ( <VideoEmbedInnerNative /> ) : ( <Button style={[a.flex_1, t.atoms.bg_contrast_25]} - onPress={setActive} + onPress={() => { + setActiveSource(source) + }} label={_(msg`Play video`)} variant="ghost" color="secondary" diff --git a/src/view/com/util/post-embeds/VideoEmbed.web.tsx b/src/view/com/util/post-embeds/VideoEmbed.web.tsx index 5803b836d..c0d774abe 100644 --- a/src/view/com/util/post-embeds/VideoEmbed.web.tsx +++ b/src/view/com/util/post-embeds/VideoEmbed.web.tsx @@ -8,14 +8,14 @@ import { } from 'view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb' import {atoms as a, useTheme} from '#/alf' import {ErrorBoundary} from '../ErrorBoundary' -import {useActiveVideoView} from './ActiveVideoContext' +import {useActiveVideoWeb} from './ActiveVideoWebContext' import * as VideoFallback from './VideoEmbedInner/VideoFallback' export function VideoEmbed({source}: {source: string}) { const t = useTheme() const ref = useRef<HTMLDivElement>(null) const {active, setActive, sendPosition, currentActiveView} = - useActiveVideoView({source}) + useActiveVideoWeb() const [onScreen, setOnScreen] = useState(false) useEffect(() => { diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx index 8cbf32a83..ea56f2997 100644 --- a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx +++ b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx @@ -9,7 +9,7 @@ import {useIsFocused} from '@react-navigation/native' import {HITSLOP_30} from '#/lib/constants' import {useAppState} from '#/lib/hooks/useAppState' import {logger} from '#/logger' -import {useVideoPlayer} from '#/view/com/util/post-embeds/VideoPlayerContext' +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 {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker' @@ -20,7 +20,7 @@ import { import {TimeIndicator} from './TimeIndicator' export function VideoEmbedInnerNative() { - const player = useVideoPlayer() + const {player} = useActiveVideoNative() const ref = useRef<VideoView>(null) const isScreenFocused = useIsFocused() const isAppFocused = useAppState() diff --git a/src/view/com/util/post-embeds/VideoPlayerContext.tsx b/src/view/com/util/post-embeds/VideoPlayerContext.tsx deleted file mode 100644 index 95511099e..000000000 --- a/src/view/com/util/post-embeds/VideoPlayerContext.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import React, {useContext} from 'react' -import type {VideoPlayer} from 'expo-video' -import {useVideoPlayer as useExpoVideoPlayer} from 'expo-video' - -import {logger} from '#/logger' -import { - AudioCategory, - PlatformInfo, -} from '../../../../../modules/expo-bluesky-swiss-army' - -const VideoPlayerContext = React.createContext<VideoPlayer | null>(null) - -export function VideoPlayerProvider({ - source, - children, -}: { - source: string - children: React.ReactNode -}) { - // eslint-disable-next-line @typescript-eslint/no-shadow - const player = useExpoVideoPlayer(source, player => { - try { - PlatformInfo.setAudioCategory(AudioCategory.Ambient) - PlatformInfo.setAudioActive(false) - - player.loop = true - player.muted = true - player.play() - } catch (err) { - logger.error('Failed to init video player', {safeMessage: err}) - } - }) - - return ( - <VideoPlayerContext.Provider value={player}> - {children} - </VideoPlayerContext.Provider> - ) -} - -export function useVideoPlayer() { - const context = useContext(VideoPlayerContext) - if (!context) { - throw new Error('useVideoPlayer must be used within a VideoPlayerProvider') - } - return context -} diff --git a/src/view/com/util/post-embeds/VideoPlayerContext.web.tsx b/src/view/com/util/post-embeds/VideoPlayerContext.web.tsx deleted file mode 100644 index 329fb1206..000000000 --- a/src/view/com/util/post-embeds/VideoPlayerContext.web.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react' - -export function VideoPlayerProvider({children}: {children: React.ReactNode}) { - return children -} - -export function useVideoPlayer() { - throw new Error('useVideoPlayer must not be used on web') -} |