DocSpace-client/web/ASC.Web.Common/src/components/MediaViewer/sub-components/video-viewer.js

465 lines
11 KiB
JavaScript
Raw Normal View History

2020-04-19 20:09:12 +00:00
import React, { Component } from 'react'
2020-04-30 07:35:02 +00:00
import PropTypes from "prop-types";
2020-04-19 20:09:12 +00:00
import { findDOMNode } from 'react-dom'
import screenfull from 'screenfull'
import ReactPlayer from 'react-player'
import Duration from './duration'
2020-04-25 18:03:13 +00:00
import Progress from './progress'
2020-04-19 20:09:12 +00:00
import styled from "styled-components"
import { Icons } from "asc-web-components";
2020-05-05 13:15:33 +00:00
const controlsHeight = 40;
2020-04-19 20:09:12 +00:00
const StyledControls = styled.div`
2020-05-05 13:15:33 +00:00
height: ${props => props.height}px;
display: block;
position: absolute;
z-index: 4001;
${props => !props.isVideo && "background-color: rgba(11,11,11,0.7);"}
top: ${props => props.top}px;
left: ${props => props.left}px;
2020-04-19 20:09:12 +00:00
`;
const StyledVideoControlBtn = styled.div`
display: inline-block;
height: 30px;
line-height: 30px;
margin: 5px;
width: 40px;
border-radius: 2px;
cursor: pointer;
text-align: center;
2020-05-05 13:15:33 +00:00
vertical-align: top;
2020-04-19 20:09:12 +00:00
&:hover{
background-color: rgba(200,200,200,0.2);
}
2020-05-05 13:15:33 +00:00
.playBtnContainer{
width: 23px;
line-height: 0;
margin: 3px auto;
}
.pauseBtnContainer{
display: block;
width: 19px;
margin: 3px 10px;
line-height: 19px;
}
.muteBtnContainer{
display: block;
width: 26px;
margin: 3px 7px;
line-height: 19px;
}
.fullscreenBtnContainer{
display: block;
width: 20px;
margin: 3px 10px;
line-height: 19px;
}
2020-04-19 20:09:12 +00:00
`;
const VideoControlBtn = props => {
return (
<StyledVideoControlBtn {...props} >
{props.children}
</StyledVideoControlBtn>
);
}
VideoControlBtn.propTypes = {
children: PropTypes.any
2020-04-19 20:09:12 +00:00
}
const Controls = props => {
return (
<StyledControls {...props} >
{props.children}
2020-04-19 20:09:12 +00:00
</StyledControls>
);
}
Controls.propTypes = {
children: PropTypes.any
2020-04-19 20:09:12 +00:00
}
const PlayBtn = props => {
2020-05-05 13:15:33 +00:00
return (
<VideoControlBtn onClick={props.onClick}>
2020-05-05 13:15:33 +00:00
{props.playing ?
<div className="pauseBtnContainer">
<Icons.MediaPauseIcon size="scale" />
</div>
:
<div className="playBtnContainer">
<Icons.MediaPlayIcon size="scale" />
</div>
}
</VideoControlBtn>
);
}
PlayBtn.propTypes = {
playing: PropTypes.bool,
onClick: PropTypes.func
}
const FullScreenBtn = props => {
return (
<VideoControlBtn onClick={props.onClick}>
2020-05-05 13:15:33 +00:00
<div className = "fullscreenBtnContainer">
<Icons.MediaFullScreenIcon size="scale" />
</div>
</VideoControlBtn>
);
}
FullScreenBtn.propTypes = {
onClick: PropTypes.func
2020-04-19 20:09:12 +00:00
}
const StyledValumeContainer = styled.div`
display: inline-block;
2020-05-05 13:15:33 +00:00
line-height: 39px;
2020-04-19 20:09:12 +00:00
position: relative;
.muteConteiner{
display: none;
position: absolute;
width: 40px;
height: 80px;
border-radius: 5px;
top: -76px;
left: 5px;
background: black;
}
&:hover{
.muteConteiner{
display: inline-block;
}
}
.mute{
display: inline-block;
transform: rotate(-90deg);
margin: 22px -12px;
}
`;
2020-04-21 10:49:23 +00:00
const StyledDuration = styled.div`
display: inline-block;
height: 30px;
line-height: 30px;
margin: 5px;
width: 60px;
text-align: center;
border-radius: 2px;
cursor: pointer;
2020-04-19 20:09:12 +00:00
2020-04-21 10:49:23 +00:00
&:hover{
background-color: rgba(200,200,200,0.2);
}
`;
2020-04-19 20:09:12 +00:00
const StyledVideoViewer = styled.div`
2020-04-21 10:49:23 +00:00
color: #d1d1d1;
.playerWrapper{
display: ${props => props.isVideo ? "block" : "none"};
width: ${props => props.width}px;
height: ${props => props.height}px;
left: ${props => props.left}px;
top: ${props => props.top}px;
z-index: 4001;
position: absolute;
padding-bottom: 40px;
background-color: rgba(11,11,11,0.7);
2020-04-25 18:03:13 +00:00
video{
z-index: 4000;
}
}
2020-04-19 20:09:12 +00:00
`;
class ValumeBtn extends Component {
2020-04-19 20:09:12 +00:00
constructor(props) {
super(props);
}
render() {
return (
<StyledValumeContainer>
<div className="muteConteiner">
<Progress
className="mute"
width={this.props.width}
value={this.props.volume}
onMouseDown={this.props.onMouseDown}
onChange={this.props.onChange}
onMouseUp={this.props.handleSeekMouseUp}
/>
</div>
<VideoControlBtn onClick={this.props.onChangeMute}>
2020-05-05 13:15:33 +00:00
<div className = "muteBtnContainer">
{this.props.muted ? <Icons.MediaMuteOffIcon size="scale" /> : <Icons.MediaMuteIcon size="scale" />}
</div>
</VideoControlBtn>
</StyledValumeContainer>
);
2020-04-19 20:09:12 +00:00
}
}
ValumeBtn.propTypes = {
width: PropTypes.number,
volume: PropTypes.number,
muted: PropTypes.bool,
onMouseDown: PropTypes.func,
onChange: PropTypes.func,
handleSeekMouseUp: PropTypes.func,
onChangeMute: PropTypes.func
}
2020-04-19 20:09:12 +00:00
class VideoViewer extends Component {
state = {
url: this.props.url,
2020-04-19 20:09:12 +00:00
pip: false,
playing: this.props.playing,
2020-04-19 20:09:12 +00:00
controls: false,
light: false,
2020-04-25 18:03:13 +00:00
volume: 0.3,
2020-04-19 20:09:12 +00:00
muted: false,
played: 0,
loaded: 0,
duration: 0,
playbackRate: 1.0,
loop: false
}
load = url => {
this.setState({
url,
played: 0,
loaded: 0,
pip: false
})
}
componentDidUpdate(prevProps, prevState) {
let newUrl = prevState.url;
let newPlaying = prevState.playing;
if (this.props.url !== prevProps.url || this.props.playing !== prevProps.playing) {
if (this.props.url !== prevProps.url) {
newUrl = this.props.url
}
if (this.props.playing !== prevProps.playing) {
newPlaying = this.props.playing
}
this.setState(
{
url: newUrl,
playing: newPlaying
}
);
}
}
2020-05-05 13:15:33 +00:00
2020-04-19 20:09:12 +00:00
handlePlayPause = () => {
this.setState({ playing: !this.state.playing })
}
handleStop = () => {
this.setState({ url: null, playing: false })
}
handleVolumeChange = e => {
this.setState({
2020-04-19 20:09:12 +00:00
volume: parseFloat(e.target.value),
muted: false
})
}
handleToggleMuted = () => {
this.setState({ muted: !this.state.muted })
}
handlePlay = () => {
this.setState({ playing: true })
}
handleEnablePIP = () => {
this.setState({ pip: true })
}
handleDisablePIP = () => {
this.setState({ pip: false })
}
handlePause = () => {
this.setState({ playing: false })
}
handleSeekMouseDown = e => {
this.setState({ seeking: true })
}
handleSeekChange = e => {
this.setState({ played: parseFloat(e.target.value) })
}
handleSeekMouseUp = e => {
this.setState({ seeking: false })
this.player.seekTo(parseFloat(e.target.value))
}
handleProgress = state => {
if (!this.state.seeking) {
this.setState(state)
}
}
handleEnded = () => {
this.setState({ playing: this.state.loop })
}
handleDuration = (duration) => {
this.setState({ duration })
}
handleClickFullscreen = () => {
screenfull.request(findDOMNode(this.player))
}
renderLoadButton = (url, label) => {
return (
<button onClick={() => this.load(url)}>
{label}
</button>
)
}
ref = player => {
this.player = player
}
resizePlayer = (videoSize, screenSize) => {
var ratio = videoSize.h / videoSize.w;
if (videoSize.h > screenSize.h) {
videoSize.h = screenSize.h;
videoSize.w = videoSize.h / ratio;
}
if (videoSize.w > screenSize.w) {
videoSize.w = screenSize.w;
videoSize.h = videoSize.w * ratio;
}
return {
width: videoSize.w,
height: videoSize.h
};
};
render() {
2020-04-19 20:09:12 +00:00
const { url, playing, controls, light, volume, muted, loop, played, loaded, duration, playbackRate, pip } = this.state
2020-05-05 13:15:33 +00:00
const parentOffset = this.props.getOffset() || 0;
var screenSize = {
w: window.innerWidth,
h: window.innerHeight
};
2020-05-05 13:15:33 +00:00
screenSize.h -= parentOffset + controlsHeight;
let width = screenSize.w;
let height = screenSize.h;
var centerAreaOx = screenSize.w / 2 + document.documentElement.scrollLeft;
var centerAreaOy = screenSize.h / 2 + document.documentElement.scrollTop;
if (document.getElementsByTagName('video')[0]) {
width = this.props.isVideo ? document.getElementsByTagName('video')[0].videoWidth || 480 : screenSize.w - 300;
height = this.props.isVideo ? document.getElementsByTagName('video')[0].videoHeight || 270 : 0;
2020-05-05 13:15:33 +00:00
let resize = this.resizePlayer(
{
w: width,
h: height
},
screenSize
)
width = resize.width;
height = resize.height;
}
2020-05-05 13:15:33 +00:00
let left = this.props.isVideo ? centerAreaOx - width / 2 : centerAreaOx + parentOffset / 4 - width / 2;
let top = this.props.isVideo ? centerAreaOy - height / 2 + parentOffset / 2 : centerAreaOy + parentOffset / 2;
2020-04-19 20:09:12 +00:00
return (
<StyledVideoViewer
isVideo={this.props.isVideo}
width={width}
height={height}
left={left}
top={top}
>
<div>
<div className='playerWrapper'>
<ReactPlayer
ref={this.ref}
className='react-player'
width='100%'
height='100%'
url={url}
pip={pip}
playing={playing}
controls={controls}
light={light}
loop={loop}
playbackRate={playbackRate}
volume={volume}
muted={muted}
onPlay={this.handlePlay}
onEnablePIP={this.handleEnablePIP}
onDisablePIP={this.handleDisablePIP}
onPause={this.handlePause}
onEnded={this.handleEnded}
onError={e => console.log('onError', e)}
onProgress={this.handleProgress}
onDuration={this.handleDuration}
/>
2020-04-19 20:09:12 +00:00
</div>
<Controls
2020-05-05 13:15:33 +00:00
height={controlsHeight}
left={left}
top={top + height}
isVideo={this.props.isVideo}
>
<PlayBtn onClick={this.handlePlayPause} playing={playing} />
<Progress
value={played}
width={width - 220}
onMouseDown={this.handleSeekMouseDown}
2020-05-05 13:15:33 +00:00
handleSeekChange={this.handleSeekChange}
onMouseUp={this.handleSeekMouseUp}
/>
<StyledDuration>-<Duration seconds={duration * (1 - played)} /></StyledDuration>
<ValumeBtn
width={64}
muted={muted}
volume={muted ? 0 : volume}
onChangeMute={this.handleToggleMuted}
onChange={this.handleVolumeChange}
/>
{this.props.isVideo && <FullScreenBtn onClick={this.handleClickFullscreen} />}
</Controls>
</div>
</StyledVideoViewer>
2020-04-19 20:09:12 +00:00
)
}
}
2020-04-30 07:35:02 +00:00
VideoViewer.propTypes = {
isVideo: PropTypes.bool,
url: PropTypes.string,
2020-05-05 13:15:33 +00:00
playing: PropTypes.bool,
getOffset :PropTypes.func
2020-04-30 07:35:02 +00:00
}
2020-04-19 20:09:12 +00:00
export default VideoViewer;