import * as React from "react"; import styled, { css } from "styled-components"; import { isMobileOnly } from "react-device-detect"; import { tablet } from "@docspace/components/utils/device"; import IconPlay from "../../../../public/images/videoplayer.play.react.svg"; import IconStop from "../../../../public/images/videoplayer.stop.react.svg"; import IconSound from "../../../../public/images/videoplayer.sound.react.svg"; import IconMuted from "../../../../public/images/videoplayer.mute.react.svg"; import IconFullScreen from "../../../../public/images/videoplayer.full.react.svg"; import IconExitFullScreen from "../../../../public/images/videoplayer.exit.react.svg"; import IconSpeed from "../../../../public/images/videoplayer.speed.react.svg"; import MediaContextMenu from "../../../../public/images/vertical-dots.react.svg"; import BigIconPlay from "../../../../public/images/videoplayer.bgplay.react.svg"; import { useSwipeable } from "react-swipeable"; let iconWidth = 80; let iconHeight = 60; const ACTION_TYPES = { setActiveIndex: "setActiveIndex", update: "update", }; function createAction(type, payload) { return { type, payload: payload || {}, }; } const StyledVideoPlayer = styled.div` &:focus-visible, #videoPlayer:focus-visible { outline: none; } .video-wrapper { position: fixed; z-index: 305; top: 0; ${isMobileOnly && css` top: 0; `} bottom: 0; right: 0; left: 0; ${(props) => props.isFullScreen ? "background: #000" : "background: transparent"}; } svg { path { fill: #fff; } } .dropdown-speed { position: relative; display: inline-block; } .dropdown-item { display: flex; align-items: center; justify-content: center; border-radius: 3px 3px 0px 0px; height: 30px; width: 40px; &:hover { cursor: pointer; background: #222; } } .dropdown-content { display: flex; flex-direction: column; align-items: center; position: absolute; bottom: 52px; color: #fff; background: #000; text-align: center; border-radius: 3px 3px 0px 0px; } .bg-play { position: fixed; &:hover { cursor: pointer; } } input[type="range"] { -webkit-appearance: none; margin-right: 15px; width: 80%; height: 8px; background: #4d4d4d; border: 1px solid rgba(0, 0, 0, 0.4); border-radius: 5px; background-image: linear-gradient(#d1d1d1, #d1d1d1); background-repeat: no-repeat; @media ${tablet} { width: 63%; } } input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; height: 14px; width: 14px; border-radius: 50%; background: #fff; border: 1px solid rgba(0, 0, 0); } .mobile-video-progress { display: flex; justify-content: center; align-items: center; position: fixed; right: 0; bottom: 48px; left: 0; z-index: 307; padding: 0 20px; height: 30px; background: RGB(110, 110, 110); input[type="range"] { width: 100%; margin-right: 0px; } } `; const StyledVideoActions = styled.div` .actions-container { display: flex; justify-content: start; align-items: center; ${isMobileOnly && css` justify-content: center; .fullscreen-button { order: -1; } `} } .controller { display: flex; justify-content: center; align-items: center; min-width: 48px; height: 48px; &:hover { cursor: pointer; background: rgb(77, 77, 77); } } `; const StyledVideoControls = styled.div` position: fixed; right: 0; bottom: 0; left: 0; z-index: 307; height: 48px; background: RGB(110, 110, 110); .volume-container { position: relative; } .volume-wrapper { background: #000; position: absolute; bottom: 78px; padding: 9px; transform: rotate(270deg); // left: -4px; } .volume-toolbar { width: 50px !important; } `; const getDuration = (time) => { const timestamp = Math.floor(time); const hours = Math.floor(timestamp / 60 / 60); const minutes = Math.floor(timestamp / 60) - hours * 60; const seconds = timestamp % 60; const formatted = hours ? [ hours.toString().padStart(2, "0"), minutes.toString().padStart(2, "0"), seconds.toString().padStart(2, "0"), ].join(":") : [ minutes.toString().padStart(2, "0"), seconds.toString().padStart(2, "0"), ].join(":"); return formatted; }; export default function ViewerPlayer(props) { const { setIsFullScreen, videoRef, generateContextMenu, mobileDetails, onPrevClick, onNextClick, } = props; const initialState = { width: 0, height: 0, left: 0, top: 0, activeIndex: props.activeIndex, isPlaying: false, isMuted: false, isFullScreen: false, speedSelection: false, progress: 0, duration: 0, volumeSelection: false, volume: 100, size: "0%", }; function reducer(state, action) { switch (action.type) { case ACTION_TYPES.setActiveIndex: return { ...state, activeIndex: action.payload.index, startLoading: true, }; case ACTION_TYPES.update: return { ...state, ...action.payload, }; default: break; } return state; } const inputRef = React.useRef(null); const volumeRef = React.useRef(null); const [state, dispatch] = React.useReducer(reducer, initialState); const [isOpen, setIsOpen] = React.useState(false); const handlers = useSwipeable({ onSwipedLeft: (e) => { if (e.event.path[0] === inputRef.current) return; onNextClick(); }, onSwipedRight: (e) => { if (e.event.path[0] === inputRef.current) return; onPrevClick(); }, }); const footerHeight = 48; const titleHeight = 53; const togglePlay = () => dispatch( createAction(ACTION_TYPES.update, { isPlaying: !state.isPlaying, }) ); const handleVolumeUpdate = (e) => { const volume = e.target.value / 100; videoRef.current.volume = volume; dispatch( createAction(ACTION_TYPES.update, { isMuted: volume ? false : true, volume: e.target.value, }) ); }; const toggleVolumeSelection = () => dispatch( createAction(ACTION_TYPES.update, { volumeSelection: !state.volumeSelection, }) ); const toggleScreen = () => { handleFullScreen(!state.isFullScreen); setIsFullScreen(!state.isFullScreen); dispatch( createAction(ACTION_TYPES.update, { isFullScreen: !state.isFullScreen, }) ); }; const toggleSpeedSelectionMenu = () => dispatch( createAction(ACTION_TYPES.update, { speedSelection: !state.speedSelection, }) ); const elem = document.documentElement; const handleFullScreen = (isFull) => { if (elem.requestFullscreen && isFull) return elem.requestFullscreen(); return document.exitFullscreen(); }; const handleVideoProgress = (e) => { const manualChange = Number(e.target.value); videoRef.current.currentTime = (videoRef.current.duration / 100) * manualChange; dispatch( createAction(ACTION_TYPES.update, { progress: manualChange, }) ); }; const handleVideoSpeed = (speed) => { const currentSpeeed = Number(speed); videoRef.current.playbackRate = currentSpeeed; }; const SpeedButtonComponent = () => { const speed = ["0.5", "1", "1.5", "2"]; const items = speed.map((speed) => (