diff --git a/src/App.native.tsx b/src/App.native.tsx index 69c7629b..a4282e7f 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 9ec79253..69a8020c 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 00000000..77616d78 --- /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 ( + + {children} + + ) +} + +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 similarity index 66% rename from src/view/com/util/post-embeds/ActiveVideoContext.tsx rename to src/view/com/util/post-embeds/ActiveVideoWebContext.tsx index d18dfc09..bc43e997 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(null) const activeViewLocationRef = useRef(Infinity) - const [source, setSource] = useState(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 ( - - - {children} - - - ) + return {children} } -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 4e2909f4..b2bcd851 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 ? ( ) : (