Web:Common:Components:MediaViewer:Sub-Components: Removed old unnecessary components
This commit is contained in:
parent
bcfef89ef1
commit
e810217b42
@ -1,24 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
export default function Duration({ className, seconds }) {
|
||||
return (
|
||||
<time dateTime={`P${Math.round(seconds)}S`} className={className}>
|
||||
{format(seconds)}
|
||||
</time>
|
||||
);
|
||||
}
|
||||
|
||||
function format(seconds) {
|
||||
const date = new Date(seconds * 1000);
|
||||
const hh = date.getUTCHours();
|
||||
const mm = date.getUTCMinutes();
|
||||
const ss = pad(date.getUTCSeconds());
|
||||
if (hh) {
|
||||
return `${hh}:${pad(mm)}:${ss}`;
|
||||
}
|
||||
return `${mm}:${ss}`;
|
||||
}
|
||||
|
||||
function pad(string) {
|
||||
return ("0" + string).slice(-2);
|
||||
}
|
@ -1,415 +0,0 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import styled from "styled-components";
|
||||
|
||||
import MediaZoomInIcon from "PUBLIC_DIR/images/media.zoomin.react.svg";
|
||||
import MediaZoomOutIcon from "PUBLIC_DIR/images/media.zoomout.react.svg";
|
||||
import MediaRotateLeftIcon from "PUBLIC_DIR/images/media.rotateleft.react.svg";
|
||||
import MediaRotateRightIcon from "PUBLIC_DIR/images/media.rotateright.react.svg";
|
||||
import MediaDeleteIcon from "PUBLIC_DIR/images/media.delete.react.svg";
|
||||
import MediaDownloadIcon from "PUBLIC_DIR/images/download.react.svg";
|
||||
import commonIconsStyles from "@docspace/components/utils/common-icons-style";
|
||||
import MediaFavoriteIcon from "PUBLIC_DIR/images/favorite.react.svg";
|
||||
|
||||
import ViewerSeparator from "PUBLIC_DIR/images/viewer.separator.react.svg";
|
||||
import MediaShare from "PUBLIC_DIR/images/share.react.svg";
|
||||
|
||||
import DropDownItem from "@docspace/components/drop-down-item";
|
||||
import DropDown from "@docspace/components/drop-down";
|
||||
import equal from "fast-deep-equal/react";
|
||||
import { Base } from "@docspace/components/themes";
|
||||
import { Viewer } from "@docspace/components/viewer";
|
||||
|
||||
const StyledViewer = styled(Viewer)`
|
||||
.react-viewer-footer {
|
||||
bottom: 5px !important;
|
||||
z-index: 301 !important;
|
||||
overflow: visible;
|
||||
}
|
||||
.react-viewer-canvas {
|
||||
z-index: 300 !important;
|
||||
margin-top: 50px;
|
||||
}
|
||||
.react-viewer-navbar,
|
||||
.react-viewer-mask,
|
||||
.react-viewer-attribute,
|
||||
.react-viewer-close {
|
||||
display: none;
|
||||
}
|
||||
.react-viewer-toolbar {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
bottom: 4px;
|
||||
}
|
||||
.react-viewer-toolbar li {
|
||||
width: 40px;
|
||||
height: 30px;
|
||||
margin-top: 4px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
line-height: 24px;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.react-viewer-btn {
|
||||
background-color: transparent;
|
||||
&:hover {
|
||||
background-color: ${(props) =>
|
||||
props.theme.mediaViewer.imageViewer.backgroundColor};
|
||||
}
|
||||
}
|
||||
.react-viewer-image-transition {
|
||||
transition-duration: 0s;
|
||||
}
|
||||
li[data-key="prev"] {
|
||||
left: 20px;
|
||||
}
|
||||
li[data-key="next"] {
|
||||
right: 20px;
|
||||
}
|
||||
li[data-key="prev"],
|
||||
li[data-key="next"] {
|
||||
position: fixed;
|
||||
top: calc(50% - 20px);
|
||||
|
||||
height: auto;
|
||||
background: none;
|
||||
|
||||
&:hover {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
li[data-key="delete"],
|
||||
li[data-key="customDownload"] {
|
||||
position: fixed;
|
||||
@media (max-width: 600px) {
|
||||
position: initial;
|
||||
}
|
||||
bottom: 9px;
|
||||
.controlBtn {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
li[data-key="delete"] {
|
||||
right: 62px;
|
||||
}
|
||||
li[data-key="customDownload"] {
|
||||
right: 12px;
|
||||
}
|
||||
.iconContainer {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
line-height: 20px;
|
||||
margin: 3px auto;
|
||||
|
||||
&.reset {
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
path,
|
||||
rect {
|
||||
fill: ${(props) => props.theme.mediaViewer.imageViewer.fill};
|
||||
}
|
||||
}
|
||||
|
||||
.btnContainer {
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 4px 12px;
|
||||
line-height: 19px;
|
||||
|
||||
path,
|
||||
rect {
|
||||
fill: ${(props) => props.theme.mediaViewer.imageViewer.fill};
|
||||
}
|
||||
}
|
||||
.scrollBtn {
|
||||
cursor: ${(props) => (props.inactive ? "default" : "pointer")};
|
||||
opacity: ${(props) => (props.inactive ? "0.2" : "1")};
|
||||
&:hover {
|
||||
background-color: ${(props) =>
|
||||
!props.inactive
|
||||
? props.theme.mediaViewer.imageViewer.backgroundColor
|
||||
: props.theme.mediaViewer.imageViewer.inactiveBackgroundColor};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledDropDown = styled(DropDown)`
|
||||
background: #333;
|
||||
`;
|
||||
|
||||
const StyledDropDownItem = styled(DropDownItem)`
|
||||
color: #fff;
|
||||
|
||||
.drop-down-item_icon svg {
|
||||
path {
|
||||
fill: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* .is-separator {
|
||||
height: 1px;
|
||||
background: #474747;
|
||||
} */
|
||||
|
||||
&:hover {
|
||||
background: #444;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledViewer.defaultProps = { theme: Base };
|
||||
|
||||
class ImageViewer extends React.Component {
|
||||
// componentDidUpdate() {
|
||||
// document.getElementsByClassName("iconContainer reset").length > 0 &&
|
||||
// document.getElementsByClassName("iconContainer reset")[0].click();
|
||||
// }
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !equal(this.props, nextProps);
|
||||
}
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
visible,
|
||||
images,
|
||||
inactive,
|
||||
onClose,
|
||||
userAccess,
|
||||
title,
|
||||
errorTitle,
|
||||
onPrevClick,
|
||||
onNextClick,
|
||||
playlist,
|
||||
playlistPos,
|
||||
isImage,
|
||||
isAudio,
|
||||
isVideo,
|
||||
isPreviewFile,
|
||||
archiveRoom,
|
||||
contextModel,
|
||||
audioIcon,
|
||||
headerIcon,
|
||||
onSetSelectionFile,
|
||||
onDownloadClick,
|
||||
} = this.props;
|
||||
|
||||
const generateContextMenu = (isOpen, right, bottom) => {
|
||||
const model = contextModel();
|
||||
|
||||
const onItemClick = (e, item) => {
|
||||
const { action, onClick } = item;
|
||||
|
||||
return onClick({ originalEvent: e, action: action, item });
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledDropDown
|
||||
open={isOpen}
|
||||
isDefaultMode={false}
|
||||
directionY="top"
|
||||
directionX="right"
|
||||
fixedDirection={true}
|
||||
withBackdrop={false}
|
||||
manualY={(bottom || "63") + "px"}
|
||||
manualX={(right || "-31") + "px"}
|
||||
>
|
||||
{model.map((item) => {
|
||||
if (item.disabled) return;
|
||||
|
||||
const onClick = (e) => {
|
||||
onClose();
|
||||
onItemClick(e, item);
|
||||
};
|
||||
return (
|
||||
<StyledDropDownItem
|
||||
className={`${item.isSeparator ? "is-separator" : ""}`}
|
||||
key={item.key}
|
||||
label={item.label}
|
||||
icon={item.icon ? item.icon : ""}
|
||||
action={item.action}
|
||||
onClick={onClick}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</StyledDropDown>
|
||||
);
|
||||
};
|
||||
|
||||
var customToolbar = [
|
||||
{
|
||||
key: "zoomOut",
|
||||
percent: true,
|
||||
actionType: 2,
|
||||
render: (
|
||||
<div className="iconContainer zoomOut">
|
||||
<MediaZoomOutIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "percent",
|
||||
actionType: 999,
|
||||
},
|
||||
{
|
||||
key: "zoomIn",
|
||||
actionType: 1,
|
||||
render: (
|
||||
<div className="iconContainer zoomIn">
|
||||
<MediaZoomInIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "rotateLeft",
|
||||
actionType: 5,
|
||||
render: (
|
||||
<div className="iconContainer rotateLeft">
|
||||
<MediaRotateLeftIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "rotateRight",
|
||||
actionType: 6,
|
||||
render: (
|
||||
<div className="iconContainer rotateRight">
|
||||
<MediaRotateRightIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "separator download-separator",
|
||||
actionType: -1,
|
||||
noHover: true,
|
||||
render: (
|
||||
<div className="separator" style={{ height: "16px" }}>
|
||||
<ViewerSeparator size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
// {
|
||||
// key: "share",
|
||||
// actionType: 101,
|
||||
// render: (
|
||||
// <div className="iconContainer share" style={{ height: "16px" }}>
|
||||
// <MediaShare size="scale" />
|
||||
// </div>
|
||||
// ),
|
||||
// },
|
||||
{
|
||||
key: "download",
|
||||
actionType: 102,
|
||||
render: (
|
||||
<div className="iconContainer download" style={{ height: "16px" }}>
|
||||
<MediaDownloadIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "context-separator",
|
||||
actionType: -1,
|
||||
noHover: true,
|
||||
render: (
|
||||
<div className="separator" style={{ height: "16px" }}>
|
||||
<ViewerSeparator size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "context-menu",
|
||||
actionType: -1,
|
||||
},
|
||||
{
|
||||
key: "delete",
|
||||
actionType: 103,
|
||||
render: (
|
||||
<div className="iconContainer viewer-delete">
|
||||
<MediaDeleteIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "favorite",
|
||||
actionType: 104,
|
||||
render: (
|
||||
<div className="iconContainer viewer-favorite">
|
||||
<MediaFavoriteIcon size="scale" />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
customToolbar.forEach((button) => {
|
||||
switch (button.key) {
|
||||
case "prev":
|
||||
button.onClick = this.props.onPrevClick;
|
||||
break;
|
||||
case "next":
|
||||
button.onClick = this.props.onNextClick;
|
||||
break;
|
||||
case "delete":
|
||||
button.onClick = this.props.onDeleteClick;
|
||||
break;
|
||||
case "download":
|
||||
button.onClick = onDownloadClick;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
const canShare = playlist[playlistPos].canShare;
|
||||
const toolbars =
|
||||
!canShare && userAccess
|
||||
? customToolbar.filter(
|
||||
(x) => x.key !== "share" && x.key !== "share-separator"
|
||||
)
|
||||
: customToolbar.filter((x) => x.key !== "delete");
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<Viewer
|
||||
inactive={inactive}
|
||||
visible={visible}
|
||||
zoomSpeed={0.25}
|
||||
title={title}
|
||||
errorTitle={errorTitle}
|
||||
contextModel={contextModel}
|
||||
generateContextMenu={generateContextMenu}
|
||||
isImage={isImage}
|
||||
headerIcon={headerIcon}
|
||||
isAudio={isAudio}
|
||||
isVideo={isVideo}
|
||||
isPreviewFile={isPreviewFile}
|
||||
archiveRoom={archiveRoom}
|
||||
audioIcon={audioIcon}
|
||||
onSetSelectionFile={onSetSelectionFile}
|
||||
onMaskClick={onClose}
|
||||
onNextClick={onNextClick}
|
||||
onPrevClick={onPrevClick}
|
||||
onDownloadClick={onDownloadClick}
|
||||
playlist={playlist}
|
||||
playlistPos={playlistPos}
|
||||
customToolbar={() => toolbars}
|
||||
images={images}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ImageViewer.propTypes = {
|
||||
className: PropTypes.string,
|
||||
visible: PropTypes.bool,
|
||||
inactive: PropTypes.bool,
|
||||
images: PropTypes.arrayOf(PropTypes.object),
|
||||
onNextClick: PropTypes.func,
|
||||
onPrevClick: PropTypes.func,
|
||||
onDeleteClick: PropTypes.func,
|
||||
onDownloadClick: PropTypes.func,
|
||||
onClose: PropTypes.func,
|
||||
};
|
||||
|
||||
export default ImageViewer;
|
@ -1,138 +0,0 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import PropTypes from "prop-types";
|
||||
import { Base } from "@docspace/components/themes";
|
||||
|
||||
const StyledProgress = styled.div`
|
||||
display: inline-block;
|
||||
|
||||
.slider-container {
|
||||
display: inline-block;
|
||||
border-radius: 2px;
|
||||
position: relative;
|
||||
width: ${(props) => props.width}px;
|
||||
height: 6px;
|
||||
background: ${(props) =>
|
||||
props.theme.mediaViewer.progressBar.backgroundColor};
|
||||
margin: 15px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.fill {
|
||||
cursor: pointer;
|
||||
width: ${(props) => 100 * props.value}%;
|
||||
position: absolute;
|
||||
|
||||
top: calc(50% - 3px);
|
||||
height: 6px;
|
||||
background: ${(props) => props.theme.mediaViewer.progressBar.background};
|
||||
border-radius: 2px;
|
||||
}
|
||||
input[type="range"] {
|
||||
display: block;
|
||||
overflow: visible;
|
||||
background: transparent;
|
||||
width: ${(props) => props.width}px;
|
||||
height: 6px;
|
||||
outline: none;
|
||||
margin: 0;
|
||||
-webkit-appearance: none;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type="range"]::-webkit-slider-thumb {
|
||||
position: relative;
|
||||
appearance: none;
|
||||
box-sizing: content-box;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-top: -3px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type="range"]::-moz-range-thumb {
|
||||
position: relative;
|
||||
appearance: none;
|
||||
box-sizing: content-box;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
margin-top: -3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type="range"]::-ms-thumb {
|
||||
position: relative;
|
||||
appearance: none;
|
||||
box-sizing: content-box;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
margin-top: -3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type="range"]::-webkit-slider-runnable-track {
|
||||
margin: 12px 0;
|
||||
height: 6px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
text-align: right;
|
||||
pointer-events: none;
|
||||
}
|
||||
input[type="range"]::-moz-range-track {
|
||||
margin: 12px 0;
|
||||
height: 6px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
text-align: right;
|
||||
pointer-events: none;
|
||||
}
|
||||
input[type="range"]::-ms-track {
|
||||
border-color: transparent;
|
||||
color: transparent;
|
||||
|
||||
margin: 12px 0;
|
||||
height: 6px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
text-align: right;
|
||||
pointer-events: none;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledProgress.defaultProps = { theme: Base };
|
||||
const Progress = (props) => {
|
||||
return (
|
||||
<StyledProgress {...props}>
|
||||
<div className="slider-container">
|
||||
<div className="fill"></div>
|
||||
<input
|
||||
type="range"
|
||||
min={0}
|
||||
max={0.999999}
|
||||
step="any"
|
||||
value={props.value}
|
||||
onMouseDown={props.handleSeekMouseDown}
|
||||
onChange={(event) => props.handleSeekChange(event)}
|
||||
onMouseUp={props.handleSeekMouseUp}
|
||||
/>
|
||||
</div>
|
||||
</StyledProgress>
|
||||
);
|
||||
};
|
||||
|
||||
Progress.propTypes = {
|
||||
value: PropTypes.number,
|
||||
handleSeekMouseDown: PropTypes.func,
|
||||
handleSeekChange: PropTypes.func,
|
||||
handleSeekMouseUp: PropTypes.func,
|
||||
};
|
||||
|
||||
export default Progress;
|
@ -1,579 +0,0 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import styled, { css } from "styled-components";
|
||||
import { findDOMNode } from "react-dom";
|
||||
import screenfull from "screenfull";
|
||||
import ReactPlayer from "react-player";
|
||||
|
||||
import Duration from "./duration";
|
||||
import Progress from "./progress";
|
||||
import MediaPauseIcon from "PUBLIC_DIR/images/media.pause.react.svg";
|
||||
import MediaPlayIcon from "PUBLIC_DIR/images/media.play.react.svg";
|
||||
import MediaFullScreenIcon from "PUBLIC_DIR/images/media.fullscreen.video.react.svg";
|
||||
import MediaMuteIcon from "PUBLIC_DIR/images/media.mute.react.svg";
|
||||
import MediaMuteOffIcon from "PUBLIC_DIR/images/media.muteoff.react.svg";
|
||||
import commonIconsStyles from "@docspace/components/utils/common-icons-style";
|
||||
import { Base } from "@docspace/components/themes";
|
||||
|
||||
const iconsStyles = css`
|
||||
path,
|
||||
stroke,
|
||||
rect {
|
||||
fill: ${(props) => props.theme.mediaViewer.videoViewer.fill};
|
||||
}
|
||||
`;
|
||||
|
||||
const controlsHeight = 40;
|
||||
const StyledControls = styled.div`
|
||||
height: ${(props) => props.height}px;
|
||||
display: block;
|
||||
position: fixed;
|
||||
z-index: 301;
|
||||
${(props) =>
|
||||
!props.isVideo &&
|
||||
`background-color: ${props.theme.mediaViewer.videoViewer.backgroundColor};`}
|
||||
top: calc(50% + ${(props) => props.top}px);
|
||||
left: ${(props) => props.left}px;
|
||||
`;
|
||||
|
||||
StyledControls.defaultProps = { theme: Base };
|
||||
const StyledVideoControlBtn = styled.div`
|
||||
display: inline-block;
|
||||
height: 26px;
|
||||
line-height: 30px;
|
||||
margin: 5px 2px;
|
||||
width: 38px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
&:hover {
|
||||
background-color: ${(props) =>
|
||||
props.theme.mediaViewer.videoViewer.background};
|
||||
}
|
||||
|
||||
.playBtnContainer {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
line-height: 0;
|
||||
margin: 5px auto;
|
||||
}
|
||||
.pauseBtnContainer {
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 3px 10px;
|
||||
line-height: 19px;
|
||||
}
|
||||
.muteBtnContainer {
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 3px 11px;
|
||||
line-height: 19px;
|
||||
}
|
||||
.fullscreenBtnContainer {
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 3px 11px;
|
||||
line-height: 19px;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledVideoControlBtn.defaultProps = { theme: Base };
|
||||
const StyledMediaPauseIcon = styled(MediaPauseIcon)`
|
||||
${commonIconsStyles}
|
||||
${iconsStyles}
|
||||
`;
|
||||
StyledMediaPauseIcon.defaultProps = { theme: Base };
|
||||
const StyledMediaPlayIcon = styled(MediaPlayIcon)`
|
||||
${commonIconsStyles}
|
||||
${iconsStyles}
|
||||
`;
|
||||
StyledMediaPlayIcon.defaultProps = { theme: Base };
|
||||
const StyledMediaFullScreenIcon = styled(MediaFullScreenIcon)`
|
||||
${commonIconsStyles}
|
||||
${iconsStyles}
|
||||
`;
|
||||
StyledMediaFullScreenIcon.defaultProps = { theme: Base };
|
||||
const StyledMediaMuteIcon = styled(MediaMuteIcon)`
|
||||
${commonIconsStyles}
|
||||
|
||||
path:first-child {
|
||||
stroke: ${(props) => props.theme.mediaViewer.videoViewer.stroke};
|
||||
}
|
||||
|
||||
path:last-child {
|
||||
fill: ${(props) => props.theme.mediaViewer.videoViewer.fill};
|
||||
}
|
||||
`;
|
||||
const StyledMediaMuteOffIcon = styled(MediaMuteOffIcon)`
|
||||
${commonIconsStyles}
|
||||
|
||||
path, rect {
|
||||
fill: ${(props) => props.theme.mediaViewer.videoViewer.fill};
|
||||
}
|
||||
`;
|
||||
|
||||
StyledMediaMuteIcon.defaultProps = { theme: Base };
|
||||
const VideoControlBtn = (props) => {
|
||||
return (
|
||||
<StyledVideoControlBtn {...props}>{props.children}</StyledVideoControlBtn>
|
||||
);
|
||||
};
|
||||
VideoControlBtn.propTypes = {
|
||||
children: PropTypes.any,
|
||||
};
|
||||
const Controls = (props) => {
|
||||
return <StyledControls {...props}>{props.children}</StyledControls>;
|
||||
};
|
||||
Controls.propTypes = {
|
||||
children: PropTypes.any,
|
||||
};
|
||||
const PlayBtn = (props) => {
|
||||
return (
|
||||
<VideoControlBtn onClick={props.onClick}>
|
||||
{props.playing ? (
|
||||
<div className="pauseBtnContainer">
|
||||
<StyledMediaPauseIcon size="scale" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="playBtnContainer">
|
||||
<StyledMediaPlayIcon size="scale" />
|
||||
</div>
|
||||
)}
|
||||
</VideoControlBtn>
|
||||
);
|
||||
};
|
||||
PlayBtn.propTypes = {
|
||||
playing: PropTypes.bool,
|
||||
onClick: PropTypes.func,
|
||||
};
|
||||
const FullScreenBtn = (props) => {
|
||||
return (
|
||||
<VideoControlBtn onClick={props.onClick}>
|
||||
<div className="fullscreenBtnContainer">
|
||||
<StyledMediaFullScreenIcon size="scale" />
|
||||
</div>
|
||||
</VideoControlBtn>
|
||||
);
|
||||
};
|
||||
FullScreenBtn.propTypes = {
|
||||
onClick: PropTypes.func,
|
||||
};
|
||||
|
||||
const StyledValumeContainer = styled.div`
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
line-height: 39px;
|
||||
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 -14px;
|
||||
}
|
||||
`;
|
||||
const StyledDuration = styled.div`
|
||||
display: inline-block;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
margin: 5px;
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: ${(props) =>
|
||||
props.theme.mediaViewer.videoViewer.background};
|
||||
}
|
||||
`;
|
||||
|
||||
StyledValumeContainer.defaultProps = { theme: Base };
|
||||
const StyledVideoViewer = styled.div`
|
||||
color: ${(props) => props.theme.mediaViewer.videoViewer.color};
|
||||
|
||||
.playerWrapper {
|
||||
display: ${(props) => (props.isVideo ? "block" : "none")};
|
||||
width: ${(props) => props.width}px;
|
||||
height: ${(props) => props.height}px;
|
||||
left: ${(props) => props.left}px;
|
||||
top: calc(50% - ${(props) => props.top / 2}px);
|
||||
z-index: 301;
|
||||
position: fixed;
|
||||
padding-bottom: 40px;
|
||||
background-color: ${(props) =>
|
||||
props.theme.mediaViewer.videoViewer.backgroundColor};
|
||||
|
||||
video {
|
||||
z-index: 300;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
StyledVideoViewer.defaultProps = { theme: Base };
|
||||
|
||||
const ErrorContainer = styled.div`
|
||||
z-index: 301;
|
||||
display: block;
|
||||
position: fixed;
|
||||
left: calc(50% - 110px);
|
||||
top: calc(50% - 40px);
|
||||
background-color: ${(props) =>
|
||||
props.theme.mediaViewer.videoViewer.backgroundColorError};
|
||||
color: ${(props) => props.theme.mediaViewer.videoViewer.colorError};
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
ErrorContainer.defaultProps = { theme: Base };
|
||||
|
||||
class ValumeBtn extends Component {
|
||||
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}
|
||||
handleSeekChange={this.props.onChange}
|
||||
onMouseUp={this.props.handleSeekMouseUp}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<VideoControlBtn onClick={this.props.onChangeMute}>
|
||||
<div className="muteBtnContainer">
|
||||
{this.props.muted ? (
|
||||
<StyledMediaMuteOffIcon size="scale" />
|
||||
) : (
|
||||
<StyledMediaMuteIcon size="scale" />
|
||||
)}
|
||||
</div>
|
||||
</VideoControlBtn>
|
||||
</StyledValumeContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
ValumeBtn.propTypes = {
|
||||
width: PropTypes.number,
|
||||
volume: PropTypes.number,
|
||||
muted: PropTypes.bool,
|
||||
onMouseDown: PropTypes.func,
|
||||
onChange: PropTypes.func,
|
||||
handleSeekMouseUp: PropTypes.func,
|
||||
onChangeMute: PropTypes.func,
|
||||
};
|
||||
|
||||
class VideoViewer extends Component {
|
||||
state = {
|
||||
url: this.props.url,
|
||||
pip: false,
|
||||
playing: false,
|
||||
controls: false,
|
||||
light: false,
|
||||
volume: 0.3,
|
||||
muted: false,
|
||||
played: 0,
|
||||
loaded: 0,
|
||||
duration: 0,
|
||||
playbackRate: 1.0,
|
||||
loop: false,
|
||||
isNew: false,
|
||||
error: false,
|
||||
isLoaded: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
document.addEventListener("keydown", this.onKeydown, false);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener("keydown", this.onKeydown, false);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.props.url !== prevProps.url) {
|
||||
this.setState({
|
||||
url: this.props.url,
|
||||
isNew: true,
|
||||
error: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onKeydown = (e) => {
|
||||
if (e.keyCode === 32) this.handlePlayPause();
|
||||
};
|
||||
|
||||
handlePlayPause = () => {
|
||||
this.setState({ playing: !this.state.playing, isNew: false });
|
||||
};
|
||||
|
||||
handleStop = () => {
|
||||
this.setState({ url: null, playing: false });
|
||||
};
|
||||
|
||||
handleVolumeChange = (e) => {
|
||||
this.setState({
|
||||
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) => {
|
||||
console.log(!isNaN(parseFloat(e.target.value)), parseFloat(e.target.value));
|
||||
if (!isNaN(parseFloat(e.target.value))) {
|
||||
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));
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
};
|
||||
|
||||
onError = (e) => {
|
||||
console.log("onError", e);
|
||||
this.setState({ error: true });
|
||||
};
|
||||
|
||||
onPlay = () => {
|
||||
this.setState({ playing: !this.state.isNew, isNew: false, isLoaded: true });
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
url,
|
||||
playing,
|
||||
controls,
|
||||
light,
|
||||
volume,
|
||||
muted,
|
||||
loop,
|
||||
played,
|
||||
loaded,
|
||||
duration,
|
||||
playbackRate,
|
||||
pip,
|
||||
error,
|
||||
isLoaded,
|
||||
} = this.state;
|
||||
const { errorLabel } = this.props;
|
||||
|
||||
const parentOffset = this.props.getOffset() || 0;
|
||||
var screenSize = {
|
||||
w: window.innerWidth,
|
||||
h: window.innerHeight,
|
||||
};
|
||||
screenSize.h -= parentOffset + controlsHeight;
|
||||
|
||||
let width = screenSize.w;
|
||||
let height = screenSize.h;
|
||||
|
||||
let centerAreaOx = screenSize.w / 2 + document.documentElement.scrollLeft;
|
||||
let centerAreaOy = screenSize.h / 2 + document.documentElement.scrollTop;
|
||||
|
||||
let videoElement = document.getElementsByTagName("video")[0];
|
||||
if (videoElement) {
|
||||
width = this.props.isVideo
|
||||
? videoElement.videoWidth || 480
|
||||
: screenSize.w - 150;
|
||||
height = this.props.isVideo ? videoElement.videoHeight || 270 : 0;
|
||||
|
||||
let resize = this.resizePlayer(
|
||||
{
|
||||
w: width,
|
||||
h: height,
|
||||
},
|
||||
screenSize
|
||||
);
|
||||
width = resize.width;
|
||||
height = resize.height;
|
||||
}
|
||||
|
||||
let left = this.props.isVideo
|
||||
? centerAreaOx - width / 2
|
||||
: centerAreaOx - width / 2;
|
||||
|
||||
const videoControlBtnWidth = 220;
|
||||
const audioControlBtnWidth = 170;
|
||||
let progressWidth = this.props.isVideo
|
||||
? width - videoControlBtnWidth
|
||||
: width - audioControlBtnWidth;
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<ErrorContainer>
|
||||
<p>{errorLabel}</p>
|
||||
</ErrorContainer>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledVideoViewer
|
||||
isVideo={this.props.isVideo}
|
||||
width={width}
|
||||
height={height}
|
||||
left={left}
|
||||
top={height + controlsHeight}
|
||||
>
|
||||
<div>
|
||||
<div className="playerWrapper" onClick={this.handlePlayPause}>
|
||||
<ReactPlayer
|
||||
ref={this.ref}
|
||||
className="react-player"
|
||||
style={{ opacity: isLoaded ? 1 : 0 }}
|
||||
width="100%"
|
||||
height="100%"
|
||||
url={url}
|
||||
pip={pip}
|
||||
playing={playing}
|
||||
playsinline={true}
|
||||
controls={controls}
|
||||
light={light}
|
||||
loop={loop}
|
||||
playbackRate={playbackRate}
|
||||
volume={volume}
|
||||
muted={muted}
|
||||
onPlay={this.onPlay}
|
||||
onEnablePIP={this.handleEnablePIP}
|
||||
onDisablePIP={this.handleDisablePIP}
|
||||
onPause={this.handlePause}
|
||||
onEnded={this.handleEnded}
|
||||
onError={this.onError}
|
||||
onProgress={this.handleProgress}
|
||||
onDuration={this.handleDuration}
|
||||
/>
|
||||
</div>
|
||||
<Controls
|
||||
height={controlsHeight}
|
||||
left={left}
|
||||
top={height / 2 - controlsHeight / 2}
|
||||
isVideo={this.props.isVideo}
|
||||
>
|
||||
<PlayBtn onClick={this.handlePlayPause} playing={playing} />
|
||||
<Progress
|
||||
value={played}
|
||||
width={progressWidth}
|
||||
onMouseDown={this.handleSeekMouseDown}
|
||||
handleSeekChange={this.handleSeekChange}
|
||||
onMouseUp={this.handleSeekMouseUp}
|
||||
onTouchEnd={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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
VideoViewer.propTypes = {
|
||||
isVideo: PropTypes.bool,
|
||||
url: PropTypes.string,
|
||||
getOffset: PropTypes.func,
|
||||
errorLabel: PropTypes.string,
|
||||
};
|
||||
|
||||
export default VideoViewer;
|
Loading…
Reference in New Issue
Block a user