about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorHailey <me@haileyok.com>2024-09-06 15:01:05 -0700
committerGitHub <noreply@github.com>2024-09-06 15:01:05 -0700
commit7e4f8cabd3971bdf19647d122e3267ab6d1991e8 (patch)
tree412ab40714dde2e8d5b53a9fe931648053bb81fe /src
parent00ce95893d9f661a378db002f25def281e433d8b (diff)
downloadvoidsky-7e4f8cabd3971bdf19647d122e3267ab6d1991e8.tar.zst
[Video] Handle push/pop on Android for autoplay (#5194)
Diffstat (limited to 'src')
-rw-r--r--src/view/com/util/post-embeds/ActiveVideoNativeContext.tsx15
-rw-r--r--src/view/com/util/post-embeds/VideoEmbed.tsx2
-rw-r--r--src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx4
-rw-r--r--src/view/shell/index.tsx25
4 files changed, 42 insertions, 4 deletions
diff --git a/src/view/com/util/post-embeds/ActiveVideoNativeContext.tsx b/src/view/com/util/post-embeds/ActiveVideoNativeContext.tsx
index da8c7a98c..95fa0bb0e 100644
--- a/src/view/com/util/post-embeds/ActiveVideoNativeContext.tsx
+++ b/src/view/com/util/post-embeds/ActiveVideoNativeContext.tsx
@@ -1,7 +1,7 @@
 import React from 'react'
 import {useVideoPlayer, VideoPlayer} from 'expo-video'
 
-import {isNative} from '#/platform/detection'
+import {isAndroid, isNative} from '#/platform/detection'
 
 const Context = React.createContext<{
   activeSource: string
@@ -26,7 +26,18 @@ export function Provider({children}: {children: React.ReactNode}) {
   })
 
   const setActiveSourceOuter = (src: string | null, viewId: string | null) => {
-    setActiveSource(src ? src : '')
+    // HACK
+    // expo-video doesn't like it when you try and move a `player` to another `VideoView`. Instead, we need to actually
+    // unregister that player to let the new screen register it. This is only a problem on Android, so we only need to
+    // apply it there.
+    if (src === activeSource && isAndroid) {
+      setActiveSource('')
+      setTimeout(() => {
+        setActiveSource(src ? src : '')
+      }, 100)
+    } else {
+      setActiveSource(src ? src : '')
+    }
     setActiveViewId(viewId ? viewId : '')
   }
 
diff --git a/src/view/com/util/post-embeds/VideoEmbed.tsx b/src/view/com/util/post-embeds/VideoEmbed.tsx
index e5457555b..9c3a34dda 100644
--- a/src/view/com/util/post-embeds/VideoEmbed.tsx
+++ b/src/view/com/util/post-embeds/VideoEmbed.tsx
@@ -71,7 +71,7 @@ function InnerWrapper({embed}: Props) {
 
   const [playerStatus, setPlayerStatus] = useState<
     VideoPlayerStatus | 'paused'
-  >(player.playing ? 'readyToPlay' : 'paused')
+  >('paused')
   const [isMuted, setIsMuted] = useState(player.muted)
   const [isFullscreen, setIsFullscreen] = React.useState(false)
   const [timeRemaining, setTimeRemaining] = React.useState(0)
diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx
index 31e863038..de9a2c74c 100644
--- a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx
+++ b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx
@@ -8,6 +8,7 @@ import {useLingui} from '@lingui/react'
 
 import {HITSLOP_30} from '#/lib/constants'
 import {clamp} from '#/lib/numbers'
+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'
@@ -61,6 +62,9 @@ export function VideoEmbedInnerNative({
           PlatformInfo.setAudioActive(true)
           player.muted = false
           setIsFullscreen(true)
+          if (isAndroid) {
+            player.play()
+          }
         }}
         onFullscreenExit={() => {
           PlatformInfo.setAudioCategory(AudioCategory.Ambient)
diff --git a/src/view/shell/index.tsx b/src/view/shell/index.tsx
index 7d080e57b..aed92cbb7 100644
--- a/src/view/shell/index.tsx
+++ b/src/view/shell/index.tsx
@@ -11,7 +11,7 @@ import Animated from 'react-native-reanimated'
 import {useSafeAreaInsets} from 'react-native-safe-area-context'
 import * as NavigationBar from 'expo-navigation-bar'
 import {StatusBar} from 'expo-status-bar'
-import {useNavigationState} from '@react-navigation/native'
+import {useNavigation, useNavigationState} from '@react-navigation/native'
 
 import {useSession} from '#/state/session'
 import {
@@ -20,6 +20,7 @@ import {
   useSetDrawerOpen,
 } from '#/state/shell'
 import {useCloseAnyActiveElement} from '#/state/util'
+import {useDedupe} from 'lib/hooks/useDedupe'
 import {useNotificationsHandler} from 'lib/hooks/useNotificationHandler'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useNotificationsRegistration} from 'lib/notifications/notifications'
@@ -33,6 +34,7 @@ import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
 import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
 import {SigninDialog} from '#/components/dialogs/Signin'
 import {Outlet as PortalOutlet} from '#/components/Portal'
+import {updateActiveViewAsync} from '../../../modules/expo-bluesky-swiss-army/src/VisibilityView'
 import {RoutesContainer, TabsNavigator} from '../../Navigation'
 import {Composer} from './Composer'
 import {DrawerContent} from './Drawer'
@@ -76,6 +78,27 @@ function ShellInner() {
     }
   }, [closeAnyActiveElement])
 
+  // HACK
+  // expo-video doesn't like it when you try and move a `player` to another `VideoView`. Instead, we need to actually
+  // unregister that player to let the new screen register it. This is only a problem on Android, so we only need to
+  // apply it there.
+  // The `state` event should only fire whenever we push or pop to a screen, and should not fire consecutively quickly.
+  // To be certain though, we will also dedupe these calls.
+  const navigation = useNavigation()
+  const dedupe = useDedupe(1000)
+  React.useEffect(() => {
+    if (!isAndroid) return
+    const onFocusOrBlur = () => {
+      setTimeout(() => {
+        dedupe(updateActiveViewAsync)
+      }, 500)
+    }
+    navigation.addListener('state', onFocusOrBlur)
+    return () => {
+      navigation.removeListener('state', onFocusOrBlur)
+    }
+  }, [dedupe, navigation])
+
   return (
     <>
       <Animated.View