import { AVPlayerView, Button, Navigation, NavigationStack, Script, Text, VStack,
useEffect, useObservable, useRef, useState, PIPStatus } from "scripting";
function Demo() {
const playerRef = useRef<AVPlayer | null>(null);
const pipRef = useRef<VideoPictureInPictureController | null>(null);
const alive = useRef(true);
const hasSource = useRef(false);
if (!playerRef.current) playerRef.current = new AVPlayer();
if (!pipRef.current) pipRef.current = new VideoPictureInPictureController();
const player = playerRef.current;
const pip = pipRef.current;
const pipStatus = useObservable<PIPStatus>();
const [loaded, setLoaded] = useState(false);
const [possible, setPossible] = useState(false);
const [message, setMessage] = useState("Choose a local video, then start PiP. Keep this page open.");
useEffect(() => {
pip.onPossibleChanged = value => { if (alive.current) setPossible(value); };
pip.onStateChanged = state => {
if (alive.current) setMessage(state === "failedToStart" ? (pip.lastError ?? state) : state);
};
return () => {
alive.current = false;
pip.dispose();
player.stop();
player.dispose();
};
}, []);
const chooseVideo = async () => {
if (hasSource.current) { setMessage("Reopen this example to choose another video."); return; }
try {
const paths = await DocumentPicker.pickFiles({ types: ["public.movie"], allowsMultipleSelection: false });
if (!alive.current || hasSource.current || !paths[0]) return;
await SharedAudioSession.setCategory("playback", []);
await SharedAudioSession.setActive(true);
if (!alive.current || hasSource.current) return;
if (!player.setSource(paths[0])) { setMessage("Unable to load video"); return; }
hasSource.current = true;
setLoaded(true);
setPossible(pip.isPossible);
player.play();
setMessage("Wait until PiP is possible, then tap Start PiP.");
} catch (error) {
if (alive.current) setMessage(String(error));
}
};
return <NavigationStack><VStack spacing={16} padding={16}>
<Text>Video PiP</Text>
<Text>{VideoPictureInPictureController.isSupported() ? "PiP supported" : "PiP unsupported"}</Text>
{loaded ? <AVPlayerView player={player} pipStatus={pipStatus}
renderingMode="layer" pictureInPictureController={pip} frame={{ height: 240 }} /> : <Text>No video loaded</Text>}
<Button title="Choose and play video" action={chooseVideo} />
<Text>{possible ? "PiP possible" : "PiP not possible"}</Text>
<Button title="Start PiP" action={() => { if (!pip.start()) setMessage(pip.lastError ?? "Cannot start PiP"); }} />
<Button title="Stop PiP" action={() => pip.stop()} />
<Text>{message}</Text>
</VStack></NavigationStack>;
}
async function run() {
try { await Navigation.present({ element: <Demo /> }); }
finally { Script.exit(); }
}
run();