Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

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

[Video] Fix fullscreen on Chrome (#5246)

authored by

Samuel Newman and committed by
GitHub
66239ba1 0f6be244

+67 -30
+53
src/components/hooks/useFullscreen.ts
··· 1 + import { 2 + useCallback, 3 + useEffect, 4 + useRef, 5 + useState, 6 + useSyncExternalStore, 7 + } from 'react' 8 + 9 + import {isFirefox, isSafari} from '#/lib/browser' 10 + import {isWeb} from '#/platform/detection' 11 + 12 + function fullscreenSubscribe(onChange: () => void) { 13 + document.addEventListener('fullscreenchange', onChange) 14 + return () => document.removeEventListener('fullscreenchange', onChange) 15 + } 16 + 17 + export function useFullscreen(ref?: React.RefObject<HTMLElement>) { 18 + if (!isWeb) throw new Error("'useFullscreen' is a web-only hook") 19 + const isFullscreen = useSyncExternalStore(fullscreenSubscribe, () => 20 + Boolean(document.fullscreenElement), 21 + ) 22 + const scrollYRef = useRef<null | number>(null) 23 + const [prevIsFullscreen, setPrevIsFullscreen] = useState(isFullscreen) 24 + 25 + const toggleFullscreen = useCallback(() => { 26 + if (isFullscreen) { 27 + document.exitFullscreen() 28 + } else { 29 + if (!ref) throw new Error('No ref provided') 30 + if (!ref.current) return 31 + scrollYRef.current = window.scrollY 32 + ref.current.requestFullscreen() 33 + } 34 + }, [isFullscreen, ref]) 35 + 36 + useEffect(() => { 37 + if (prevIsFullscreen === isFullscreen) return 38 + setPrevIsFullscreen(isFullscreen) 39 + 40 + // Chrome has an issue where it doesn't scroll back to the top after exiting fullscreen 41 + // Let's play it safe and do it if not FF or Safari, since anything else will probably be chromium 42 + if (prevIsFullscreen && !isFirefox && !isSafari) { 43 + setTimeout(() => { 44 + if (scrollYRef.current !== null) { 45 + window.scrollTo(0, scrollYRef.current) 46 + scrollYRef.current = null 47 + } 48 + }, 100) 49 + } 50 + }, [isFullscreen, prevIsFullscreen]) 51 + 52 + return [isFullscreen, toggleFullscreen] as const 53 + }
+12 -1
src/view/com/util/post-embeds/VideoEmbed.web.tsx
··· 12 12 VideoNotFoundError, 13 13 } from '#/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb' 14 14 import {atoms as a} from '#/alf' 15 + import {useFullscreen} from '#/components/hooks/useFullscreen' 15 16 import {ErrorBoundary} from '../ErrorBoundary' 16 17 import {useActiveVideoWeb} from './ActiveVideoWebContext' 17 18 import * as VideoFallback from './VideoEmbedInner/VideoFallback' ··· 106 107 }) { 107 108 const ref = useRef<HTMLDivElement>(null) 108 109 const [nearScreen, setNearScreen] = useState(false) 110 + const [isFullscreen] = useFullscreen() 111 + const [nearScreenOrFullscreen, setNearScreenOrFullscreen] = useState(false) 109 112 110 113 // Send position when scrolling. This is done with an IntersectionObserver 111 114 // observing a div of 100vh height ··· 135 138 } 136 139 }, [isAnyViewActive, sendPosition]) 137 140 141 + // disguesting effect - it should be `nearScreen` except when fullscreen 142 + // when it should be whatever it was before fullscreen changed 143 + useEffect(() => { 144 + if (!isFullscreen) { 145 + setNearScreenOrFullscreen(nearScreen) 146 + } 147 + }, [isFullscreen, nearScreen]) 148 + 138 149 return ( 139 150 <View style={[a.flex_1, a.flex_row]}> 140 - {nearScreen && children} 151 + {nearScreenOrFullscreen && children} 141 152 <div 142 153 ref={ref} 143 154 style={{
+2 -29
src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx
··· 1 - import React, { 2 - useCallback, 3 - useEffect, 4 - useRef, 5 - useState, 6 - useSyncExternalStore, 7 - } from 'react' 1 + import React, {useCallback, useEffect, useRef, useState} from 'react' 8 2 import {Pressable, View} from 'react-native' 9 3 import {SvgProps} from 'react-native-svg' 10 4 import {msg, Trans} from '@lingui/macro' ··· 21 15 } from '#/state/preferences' 22 16 import {atoms as a, useTheme, web} from '#/alf' 23 17 import {Button} from '#/components/Button' 18 + import {useFullscreen} from '#/components/hooks/useFullscreen' 24 19 import {useInteractionState} from '#/components/hooks/useInteractionState' 25 20 import { 26 21 ArrowsDiagonalIn_Stroke2_Corner0_Rounded as ArrowsInIcon, ··· 850 845 canPlay, 851 846 } 852 847 } 853 - 854 - function fullscreenSubscribe(onChange: () => void) { 855 - document.addEventListener('fullscreenchange', onChange) 856 - return () => document.removeEventListener('fullscreenchange', onChange) 857 - } 858 - 859 - function useFullscreen(ref: React.RefObject<HTMLElement>) { 860 - const isFullscreen = useSyncExternalStore(fullscreenSubscribe, () => 861 - Boolean(document.fullscreenElement), 862 - ) 863 - 864 - const toggleFullscreen = useCallback(() => { 865 - if (isFullscreen) { 866 - document.exitFullscreen() 867 - } else { 868 - if (!ref.current) return 869 - ref.current.requestFullscreen() 870 - } 871 - }, [isFullscreen, ref]) 872 - 873 - return [isFullscreen, toggleFullscreen] as const 874 - }