An ATproto social media client -- with an independent Appview.

[APP-1083] bug fix: videos not accurately autoplaying on web (#8692)

* update: auto play video on web with intersection position

* place back the threshold: 0.5

* update: optimize the intersection observer with a throttled scroll listener

---------

Co-authored-by: Anastasiya <anastasiya@Mac.localdomain>
Co-authored-by: Anastasiya <anastasiya@Anastasiyas-MacBook-Pro.local>

authored by

Anastasiya Uraleva
Anastasiya
Anastasiya
and committed by
GitHub
9aa35e9f 14e39c4a

+38 -7
+38 -7
src/components/Post/Embed/VideoEmbed/index.web.tsx
··· 138 138 useEffect(() => { 139 139 if (!ref.current) return 140 140 if (isFullscreen && !isFirefox) return 141 + 142 + let scrollTimeout: NodeJS.Timeout | null = null 143 + let lastObserverEntry: IntersectionObserverEntry | null = null 144 + 145 + const updatePositionFromEntry = () => { 146 + if (!lastObserverEntry) return 147 + const rect = lastObserverEntry.boundingClientRect 148 + const position = rect.y + rect.height / 2 149 + sendPosition(position) 150 + } 151 + 152 + const handleScroll = () => { 153 + if (scrollTimeout) { 154 + clearTimeout(scrollTimeout) 155 + } 156 + scrollTimeout = setTimeout(updatePositionFromEntry, 4) // ~240fps 157 + } 158 + 141 159 const observer = new IntersectionObserver( 142 160 entries => { 143 161 const entry = entries[0] 144 162 if (!entry) return 145 - const position = 146 - entry.boundingClientRect.y + entry.boundingClientRect.height / 2 163 + lastObserverEntry = entry 164 + setNearScreen(entry.isIntersecting) 165 + const rect = entry.boundingClientRect 166 + const position = rect.y + rect.height / 2 147 167 sendPosition(position) 148 - setNearScreen(entry.isIntersecting) 149 168 }, 150 - {threshold: Array.from({length: 101}, (_, i) => i / 100)}, 169 + {threshold: [0, 0.1, 0.25, 0.5, 0.75, 1.0]}, 151 170 ) 171 + 152 172 observer.observe(ref.current) 153 - return () => observer.disconnect() 154 - }, [sendPosition, isFullscreen]) 155 173 156 - // In case scrolling hasn't started yet, send up the position 174 + if (nearScreen) { 175 + window.addEventListener('scroll', handleScroll, {passive: true}) 176 + } 177 + 178 + return () => { 179 + observer.disconnect() 180 + if (scrollTimeout) { 181 + clearTimeout(scrollTimeout) 182 + } 183 + window.removeEventListener('scroll', handleScroll) 184 + } 185 + }, [sendPosition, isFullscreen, nearScreen]) 186 + 187 + // In case scrolling hasn't started yet, send the original position 157 188 useEffect(() => { 158 189 if (ref.current && !isAnyViewActive) { 159 190 const rect = ref.current.getBoundingClientRect()