({
setQuality,
options,
contentId,
onReady,
onVideoEnd,
appxVideoId,
appxCourseId,
})
| 48 | const VOLUME_LEVELS: number[] = [0, 0.2, 0.4, 0.6, 0.8, 1.0]; |
| 49 | |
| 50 | export const VideoPlayer: FunctionComponent<VideoPlayerProps> = ({ |
| 51 | setQuality, |
| 52 | options, |
| 53 | contentId, |
| 54 | onReady, |
| 55 | onVideoEnd, |
| 56 | appxVideoId, |
| 57 | appxCourseId, |
| 58 | }) => { |
| 59 | const videoRef = useRef<HTMLDivElement>(null); |
| 60 | const playerRef = useRef<Player | null>(null); |
| 61 | const [player, setPlayer] = useState<any>(null); |
| 62 | const searchParams = useSearchParams(); |
| 63 | const vidUrl = options.sources[0].src; |
| 64 | |
| 65 | const togglePictureInPicture = async () => { |
| 66 | try { |
| 67 | if (document.pictureInPictureElement) { |
| 68 | await document.exitPictureInPicture(); |
| 69 | } else if (document.pictureInPictureEnabled && playerRef.current) { |
| 70 | playerRef.current.requestPictureInPicture(); |
| 71 | } |
| 72 | } catch (error) { |
| 73 | // Ignore specific errors that might occur during normal operation |
| 74 | if ( |
| 75 | error instanceof Error && |
| 76 | error.name !== 'NotAllowedError' && |
| 77 | error.name !== 'NotSupportedError' |
| 78 | ) { |
| 79 | console.error('Failed to toggle Picture-in-Picture mode:', error); |
| 80 | toast.error('Failed to toggle Picture-in-Picture mode.'); |
| 81 | } |
| 82 | } |
| 83 | }; |
| 84 | |
| 85 | const PipButton = () => ( |
| 86 | <button |
| 87 | onClick={togglePictureInPicture} |
| 88 | className="flex items-center justify-center text-white focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 dark:focus:ring-offset-gray-800" |
| 89 | type="button" |
| 90 | title="Picture-in-Picture" |
| 91 | > |
| 92 | <span className="absolute inset-0 rounded bg-black bg-opacity-50 opacity-0 transition-opacity duration-200 group-hover:opacity-100"></span> |
| 93 | <PictureInPicture2 className="relative z-10 h-5 w-5" /> |
| 94 | <span className="sr-only">Picture-in-Picture</span> |
| 95 | </button> |
| 96 | ); |
| 97 | |
| 98 | const createPipButton = (player: Player) => { |
| 99 | const pipButtonContainer = (player as any).controlBar.addChild('button', { |
| 100 | clickHandler: (event: any) => { |
| 101 | event.preventDefault(); |
| 102 | event.stopPropagation(); |
| 103 | togglePictureInPicture(); |
| 104 | }, |
| 105 | }); |
| 106 | |
| 107 | const root = createRoot(pipButtonContainer.el()); |
nothing calls this directly
no test coverage detected