diff --git a/src/video/components/popouts/CaptionSelectionPopout.tsx b/src/video/components/popouts/CaptionSelectionPopout.tsx index 363f27b4..e98bc669 100644 --- a/src/video/components/popouts/CaptionSelectionPopout.tsx +++ b/src/video/components/popouts/CaptionSelectionPopout.tsx @@ -13,7 +13,6 @@ function makeCaptionId(caption: MWCaption, isLinked: boolean): string { return isLinked ? `linked-${caption.langIso}` : `external-${caption.langIso}`; } -// TODO add option to clear captions export function CaptionSelectionPopout() { const descriptor = useVideoPlayerDescriptor(); const meta = useMeta(descriptor); @@ -42,10 +41,23 @@ export function CaptionSelectionPopout() {
Captions
+ + { + controls.clearCaption(); + controls.closePopout(); + }} + > + No captions + + +

Linked captions

+
{linkedCaptions.map((link) => ( diff --git a/src/video/components/popouts/PopoutAnchor.tsx b/src/video/components/popouts/PopoutAnchor.tsx index 4443501a..3439f468 100644 --- a/src/video/components/popouts/PopoutAnchor.tsx +++ b/src/video/components/popouts/PopoutAnchor.tsx @@ -18,8 +18,10 @@ export function PopoutAnchor(props: Props) { if (state.interface.popout !== props.for) return; - let handle = -1; + let cancelled = false; function render() { + if (cancelled) return; + if (ref.current) { const current = JSON.stringify(state.interface.popoutBounds); const newer = ref.current.getBoundingClientRect(); @@ -28,12 +30,12 @@ export function PopoutAnchor(props: Props) { updateInterface(descriptor, state); } } - handle = window.requestAnimationFrame(render); + window.requestAnimationFrame(render); } - handle = window.requestAnimationFrame(render); + window.requestAnimationFrame(render); return () => { - window.cancelAnimationFrame(handle); + cancelled = true; }; }, [descriptor, props]); diff --git a/src/video/components/popouts/PopoutProviderAction.tsx b/src/video/components/popouts/PopoutProviderAction.tsx index 470f309e..de88057e 100644 --- a/src/video/components/popouts/PopoutProviderAction.tsx +++ b/src/video/components/popouts/PopoutProviderAction.tsx @@ -4,8 +4,11 @@ import { EpisodeSelectionPopout } from "@/video/components/popouts/EpisodeSelect import { CaptionSelectionPopout } from "@/video/components/popouts/CaptionSelectionPopout"; import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; -import { useInterface } from "@/video/state/logic/interface"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { + useInterface, + VideoInterfaceEvent, +} from "@/video/state/logic/interface"; +import { useCallback, useEffect, useRef, useState } from "react"; import "./Popouts.css"; @@ -22,9 +25,44 @@ function ShowPopout(props: { popoutId: string | null }) { return null; } -// TODO bug: coords are sometimes completely broken -export function PopoutProviderAction() { +function PopoutContainer(props: { videoInterface: VideoInterfaceEvent }) { const ref = useRef(null); + const [right, setRight] = useState(0); + const [bottom, setBottom] = useState(0); + const [width, setWidth] = useState(0); + + const calculateAndSetCoords = useCallback((rect: DOMRect, w: number) => { + const buttonCenter = rect.left + rect.width / 2; + + setBottom(rect ? rect.height + 30 : 30); + setRight(Math.max(window.innerWidth - buttonCenter - w / 2, 30)); + }, []); + + useEffect(() => { + if (!props.videoInterface.popoutBounds) return; + calculateAndSetCoords(props.videoInterface.popoutBounds, width); + }, [props.videoInterface.popoutBounds, calculateAndSetCoords, width]); + + useEffect(() => { + const rect = ref.current?.getBoundingClientRect(); + setWidth(rect?.width ?? 0); + }, []); + + return ( +
+ +
+ ); +} + +export function PopoutProviderAction() { const descriptor = useVideoPlayerDescriptor(); const videoInterface = useInterface(descriptor); const controls = useControls(descriptor); @@ -34,26 +72,6 @@ export function PopoutProviderAction() { controls.closePopout(); }, [controls]); - const distanceFromRight = useMemo(() => { - if (!videoInterface.popoutBounds) return 30; - - const buttonCenter = - videoInterface.popoutBounds.left + videoInterface.popoutBounds.width / 2; - - return Math.max( - window.innerWidth - - buttonCenter - - (ref.current?.getBoundingClientRect().width ?? 0) / 2, - 30 - ); - }, [videoInterface.popoutBounds]); - - const distanceFromBottom = useMemo(() => { - return videoInterface.popoutBounds - ? videoInterface.popoutBounds.height + 30 - : 30; - }, [videoInterface.popoutBounds]); - return (
-
- -
+
); diff --git a/src/video/components/popouts/PopoutUtils.tsx b/src/video/components/popouts/PopoutUtils.tsx index 3420e77f..018afb20 100644 --- a/src/video/components/popouts/PopoutUtils.tsx +++ b/src/video/components/popouts/PopoutUtils.tsx @@ -45,11 +45,6 @@ export function ScrollToActive(props: ScrollToActiveProps) { wrapper?.querySelector(".active"); if (wrapper && active) { - active.scrollIntoView({ - block: "nearest", - inline: "nearest", - }); - let activeYPositionCentered = 0; const setActiveYPositionCentered = () => { activeYPositionCentered = diff --git a/src/video/state/logic/controls.ts b/src/video/state/logic/controls.ts index e6b73eca..b4367526 100644 --- a/src/video/state/logic/controls.ts +++ b/src/video/state/logic/controls.ts @@ -74,7 +74,6 @@ export function useControls( }, closePopout() { state.interface.popout = null; - state.interface.popoutBounds = null; updateInterface(descriptor, state); }, setFocused(focused) {