Add videos to be played across all pages. #1523
23 changed files with 391 additions and 25 deletions
12
src/renderer/component/overlay/index.js
Normal file
12
src/renderer/component/overlay/index.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectShowOverlay } from 'redux/selectors/media';
|
||||
import Overlay from './view';
|
||||
|
||||
const select = state => ({
|
||||
showOverlay: selectShowOverlay(state),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
null
|
||||
)(Overlay);
|
15
src/renderer/component/overlay/view.jsx
Normal file
15
src/renderer/component/overlay/view.jsx
Normal file
|
@ -0,0 +1,15 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
|
||||
type Props = {
|
||||
children: ?React.node,
|
||||
};
|
||||
|
||||
class Overlay extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
return <div className="overlay">{children}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export default Overlay;
|
|
@ -2,8 +2,8 @@ import { connect } from 'react-redux';
|
|||
import * as settings from 'constants/settings';
|
||||
import { doChangeVolume } from 'redux/actions/app';
|
||||
import { selectVolume } from 'redux/selectors/app';
|
||||
import { doPlayUri, doSetPlayingUri } from 'redux/actions/content';
|
||||
import { doPlay, doPause, savePosition } from 'redux/actions/media';
|
||||
import { doPlayUri, doSetPlayingUri, doLoadVideo } from 'redux/actions/content';
|
||||
import { doPlay, doPause, savePosition, doHideOverlay, doShowOverlay } from 'redux/actions/media';
|
||||
import {
|
||||
makeSelectMetadataForUri,
|
||||
makeSelectContentTypeForUri,
|
||||
|
@ -15,7 +15,11 @@ import {
|
|||
selectSearchBarFocused,
|
||||
} from 'lbry-redux';
|
||||
import { makeSelectClientSetting, selectShowNsfw } from 'redux/selectors/settings';
|
||||
import { selectMediaPaused, makeSelectMediaPositionForUri } from 'redux/selectors/media';
|
||||
import {
|
||||
selectMediaPaused,
|
||||
makeSelectMediaPositionForUri,
|
||||
selectShowOverlay,
|
||||
} from 'redux/selectors/media';
|
||||
import { selectPlayingUri } from 'redux/selectors/content';
|
||||
import Video from './view';
|
||||
|
||||
|
@ -34,14 +38,20 @@ const select = (state, props) => ({
|
|||
mediaPosition: makeSelectMediaPositionForUri(props.uri)(state),
|
||||
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
||||
searchBarFocused: selectSearchBarFocused(state),
|
||||
showOverlay: selectShowOverlay(state),
|
||||
hiddenControls: props.hiddenControls,
|
||||
fromOverlay: props.fromOverlay,
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
play: uri => dispatch(doPlayUri(uri)),
|
||||
load: uri => dispatch(doLoadVideo(uri)),
|
||||
cancelPlay: () => dispatch(doSetPlayingUri(null)),
|
||||
changeVolume: volume => dispatch(doChangeVolume(volume)),
|
||||
doPlay: () => dispatch(doPlay()),
|
||||
doPause: () => dispatch(doPause()),
|
||||
doShowOverlay: () => dispatch(doShowOverlay()),
|
||||
doHideOverlay: () => dispatch(doHideOverlay()),
|
||||
savePosition: (claimId, position) => dispatch(savePosition(claimId, position)),
|
||||
});
|
||||
|
||||
|
|
|
@ -22,14 +22,9 @@ class VideoPlayer extends React.PureComponent {
|
|||
this.toggleFullScreenVideo = this.toggleFullScreen.bind(this);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const el = this.refs.media.children[0];
|
||||
if (!this.props.paused && nextProps.paused && !el.paused) el.pause();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const container = this.media;
|
||||
const { contentType, changeVolume, volume, position, claim } = this.props;
|
||||
const { contentType, changeVolume, volume, position, claim, hiddenControls } = this.props;
|
||||
|
||||
const loadedMetadata = () => {
|
||||
this.setState({ hasMetadata: true, startedPlaying: true });
|
||||
|
@ -48,6 +43,12 @@ class VideoPlayer extends React.PureComponent {
|
|||
}
|
||||
};
|
||||
|
||||
// Hide overlay video when the video ends only if its overlayed
|
||||
const ended = () => {
|
||||
this.props.doPause();
|
||||
this.props.savePosition(claim.claim_id, 0);
|
||||
};
|
||||
|
||||
// use renderAudio override for mp3
|
||||
if (VideoPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) {
|
||||
this.renderAudio(container, null, false);
|
||||
|
@ -55,7 +56,7 @@ class VideoPlayer extends React.PureComponent {
|
|||
player.append(
|
||||
this.file(),
|
||||
container,
|
||||
{ autoplay: true, controls: true },
|
||||
{ autoplay: true, controls: !hiddenControls },
|
||||
renderMediaCallback.bind(this)
|
||||
);
|
||||
}
|
||||
|
@ -79,16 +80,21 @@ class VideoPlayer extends React.PureComponent {
|
|||
});
|
||||
mediaElement.volume = volume;
|
||||
mediaElement.addEventListener('dblclick', this.toggleFullScreenVideo);
|
||||
mediaElement.addEventListener('ended', ended);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(next) {
|
||||
const el = this.media.children[0];
|
||||
if (!this.props.paused && next.paused && !el.paused) el.pause();
|
||||
if (!this.props.paused && next.paused && !el.paused) {
|
||||
el.pause();
|
||||
} else if (this.props.paused && !next.paused && el.paused) {
|
||||
el.play();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const { contentType, downloadCompleted } = this.props;
|
||||
const { contentType, downloadCompleted, hiddenControls } = this.props;
|
||||
const { startedPlaying } = this.state;
|
||||
|
||||
if (this.playableType() && !startedPlaying && downloadCompleted) {
|
||||
|
@ -99,7 +105,7 @@ class VideoPlayer extends React.PureComponent {
|
|||
} else {
|
||||
player.render(this.file(), container, {
|
||||
autoplay: true,
|
||||
controls: true,
|
||||
controls: !hiddenControls,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +117,7 @@ class VideoPlayer extends React.PureComponent {
|
|||
if (mediaElement) {
|
||||
mediaElement.removeEventListener('click', this.togglePlayListener);
|
||||
}
|
||||
this.props.doPause();
|
||||
// this.props.doPause();
|
||||
}
|
||||
|
||||
toggleFullScreen(event) {
|
||||
|
|
|
@ -6,11 +6,11 @@ import type { Claim } from 'types/claim';
|
|||
import VideoPlayer from './internal/player';
|
||||
import VideoPlayButton from './internal/play-button';
|
||||
import LoadingScreen from './internal/loading-screen';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
const SPACE_BAR_KEYCODE = 32;
|
||||
|
||||
type Props = {
|
||||
cancelPlay: () => void,
|
||||
fileInfo: {
|
||||
outpoint: string,
|
||||
file_name: string,
|
||||
|
@ -34,12 +34,19 @@ type Props = {
|
|||
doPlay: () => void,
|
||||
doPause: () => void,
|
||||
savePosition: (string, number) => void,
|
||||
doShowOverlay: () => void,
|
||||
doHideOverlay: () => void,
|
||||
mediaPaused: boolean,
|
||||
mediaPosition: ?number,
|
||||
className: ?string,
|
||||
obscureNsfw: boolean,
|
||||
play: string => void,
|
||||
searchBarFocused: boolean,
|
||||
showOverlay: boolean,
|
||||
hiddenControls: boolean,
|
||||
fromOverlay: boolean,
|
||||
overlayed: boolean,
|
||||
fromOverlay: boolean,
|
||||
};
|
||||
|
||||
class Video extends React.PureComponent<Props> {
|
||||
|
@ -53,6 +60,11 @@ class Video extends React.PureComponent<Props> {
|
|||
componentDidMount() {
|
||||
this.handleAutoplay(this.props);
|
||||
window.addEventListener('keydown', this.handleKeyDown);
|
||||
|
||||
const { showOverlay, doHideOverlay, uri, playingUri } = this.props;
|
||||
if (showOverlay && uri === playingUri) {
|
||||
doHideOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
|
@ -64,13 +76,53 @@ class Video extends React.PureComponent<Props> {
|
|||
) {
|
||||
this.handleAutoplay(nextProps);
|
||||
}
|
||||
if (nextProps.fromOverlay) {
|
||||
this.moveVideoFromOverlayToNormal();
|
||||
this.destroyVideoOnOverlay();
|
||||
this.props.doHideOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.cancelPlay();
|
||||
const { overlayed, doShowOverlay, mediaPaused } = this.props;
|
||||
if (!overlayed && !mediaPaused) {
|
||||
doShowOverlay();
|
||||
this.moveVideoToOverlay();
|
||||
}
|
||||
window.removeEventListener('keydown', this.handleKeyDown);
|
||||
}
|
||||
|
||||
moveVideoToOverlay() {
|
||||
const topContainer = document.getElementById('video__overlay_id_top_container');
|
||||
const container = document.getElementById('video__overlay_id');
|
||||
const videoContainer = this.mediaContainer.media ? this.mediaContainer.media : document.getElementById('insert_video');
|
||||
const video = videoContainer.getElementsByTagName('video')[0];
|
||||
if (video) {
|
||||
topContainer.classList.remove('hiddenContainer');
|
||||
container.appendChild(video);
|
||||
video.controls = false;
|
||||
video.play();
|
||||
}
|
||||
}
|
||||
|
||||
moveVideoFromOverlayToNormal() {
|
||||
const videoContainer = document.getElementById('video__overlay_id');
|
||||
if (!videoContainer) return;
|
||||
const video = videoContainer.getElementsByTagName('video')[0];
|
||||
if (!video) return;
|
||||
const filePageVideoContainer = document.getElementById('insert_video');
|
||||
filePageVideoContainer.appendChild(video);
|
||||
video.controls = true;
|
||||
video.play();
|
||||
}
|
||||
|
||||
destroyVideoOnOverlay() {
|
||||
const topContainer = document.getElementById('video__overlay_id_top_container');
|
||||
const videoContainer = document.getElementById('video__overlay_id');
|
||||
topContainer.classList.add('hiddenContainer');
|
||||
videoContainer.innerHTML = '';
|
||||
}
|
||||
|
||||
handleKeyDown(event: SyntheticKeyboardEvent<*>) {
|
||||
const { searchBarFocused } = this.props;
|
||||
if (!searchBarFocused && event.keyCode === SPACE_BAR_KEYCODE) {
|
||||
|
@ -100,9 +152,17 @@ class Video extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
playContent() {
|
||||
const { play, uri } = this.props;
|
||||
const { play, uri, playingUri, doHideOverlay } = this.props;
|
||||
if (playingUri) {
|
||||
if (playingUri === uri) {
|
||||
this.moveVideoFromOverlayToNormal();
|
||||
}
|
||||
this.destroyVideoOnOverlay();
|
||||
doHideOverlay();
|
||||
} else {
|
||||
play(uri);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
|
@ -123,6 +183,10 @@ class Video extends React.PureComponent<Props> {
|
|||
mediaPosition,
|
||||
className,
|
||||
obscureNsfw,
|
||||
hiddenControls,
|
||||
doHideOverlay,
|
||||
showOverlay,
|
||||
fromOverlay,
|
||||
} = this.props;
|
||||
|
||||
const isPlaying = playingUri === uri;
|
||||
|
@ -147,6 +211,7 @@ class Video extends React.PureComponent<Props> {
|
|||
const layoverStyle =
|
||||
!shouldObscureNsfw && poster ? { backgroundImage: `url("${poster}")` } : {};
|
||||
|
||||
const commingFromOverlay = playingUri === uri;
|
||||
return (
|
||||
<div className={classnames('video', {}, className)}>
|
||||
{isPlaying && (
|
||||
|
@ -155,7 +220,7 @@ class Video extends React.PureComponent<Props> {
|
|||
<div className={layoverClass} style={layoverStyle}>
|
||||
<LoadingScreen status={loadStatusMessage} />
|
||||
</div>
|
||||
) : (
|
||||
) : (commingFromOverlay && fromOverlay ? <div id="insert_video" ref={mediaContainer => this.mediaContainer = mediaContainer} /> :
|
||||
<VideoPlayer
|
||||
filename={fileInfo.file_name}
|
||||
poster={poster}
|
||||
|
@ -172,6 +237,9 @@ class Video extends React.PureComponent<Props> {
|
|||
uri={uri}
|
||||
paused={mediaPaused}
|
||||
position={mediaPosition}
|
||||
hiddenControls={hiddenControls}
|
||||
doHideOverlay={doHideOverlay}
|
||||
ref={mediaContainer => this.mediaContainer = mediaContainer }
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
26
src/renderer/component/videoOverlay/index.js
Normal file
26
src/renderer/component/videoOverlay/index.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectPlayingUri } from 'redux/selectors/content';
|
||||
import { doSetPlayingUri } from 'redux/actions/content';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doPlay, doPause, doHideOverlay } from 'redux/actions/media';
|
||||
import { selectMediaPaused, selectShowOverlay } from 'redux/selectors/media';
|
||||
import VideoOverlay from './view';
|
||||
|
||||
const select = state => ({
|
||||
playingUri: selectPlayingUri(state),
|
||||
mediaPaused: selectMediaPaused(state),
|
||||
showOverlay: selectShowOverlay(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
doCancelPlay: () => dispatch(doSetPlayingUri(null)),
|
||||
doHideOverlay: () => dispatch(doHideOverlay()),
|
||||
doPlay: () => dispatch(doPlay()),
|
||||
doPause: () => dispatch(doPause()),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
perform
|
||||
)(VideoOverlay);
|
92
src/renderer/component/videoOverlay/view.jsx
Normal file
92
src/renderer/component/videoOverlay/view.jsx
Normal file
|
@ -0,0 +1,92 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import Video from 'component/video';
|
||||
import Overlay from 'component/overlay';
|
||||
import VideoOverlayHeader from 'component/videoOverlayHeader';
|
||||
import Button from 'component/button';
|
||||
import * as icons from 'constants/icons';
|
||||
|
||||
type Props = {
|
||||
doCancelPlay: () => void,
|
||||
doHideOverlay: () => void,
|
||||
navigate: (string, ?{}) => void,
|
||||
doPlay: () => void,
|
||||
doPause: () => void,
|
||||
playingUri: ?string,
|
||||
mediaPaused: boolean,
|
||||
showOverlay: boolean,
|
||||
};
|
||||
|
||||
class VideoOverlay extends React.Component<Props> {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
(this: any).closeVideo = this.closeVideo.bind(this);
|
||||
(this: any).returnToMedia = this.returnToMedia.bind(this);
|
||||
}
|
||||
|
||||
closeVideo() {
|
||||
const { doCancelPlay, doHideOverlay } = this.props;
|
||||
doCancelPlay();
|
||||
doHideOverlay();
|
||||
this.destroyMediaPlayer();
|
||||
}
|
||||
|
||||
returnToMedia() {
|
||||
const { navigate, playingUri, doHideOverlay } = this.props;
|
||||
doHideOverlay();
|
||||
this.destroyMediaPlayer(false);
|
||||
navigate('/show', { uri: playingUri, fromOverlay: true });
|
||||
}
|
||||
|
||||
renderPlayOrPauseButton() {
|
||||
const { mediaPaused, doPause, doPlay } = this.props;
|
||||
if (mediaPaused) {
|
||||
return <Button noPadding button="secondary" icon={icons.PLAY} onClick={() => this.getPlayer().play()} />;
|
||||
}
|
||||
return <Button noPadding button="secondary" icon={icons.PAUSE} onClick={() => this.getPlayer().pause()} />;
|
||||
}
|
||||
|
||||
getPlayer() {
|
||||
return document.getElementById('video__overlay_id').getElementsByTagName("video")[0];
|
||||
}
|
||||
|
||||
destroyMediaPlayer(clearVideo = true){
|
||||
const topContainer = document.getElementById('video__overlay_id_top_container')
|
||||
const videoContainer = document.getElementById('video__overlay_id');
|
||||
topContainer.classList.add('hiddenContainer');
|
||||
if (clearVideo) videoContainer.innerHTML = '';
|
||||
}
|
||||
|
||||
render() {
|
||||
const { playingUri, showOverlay } = this.props;
|
||||
|
||||
return (
|
||||
<Overlay>
|
||||
{(showOverlay && <VideoOverlayHeader uri={playingUri} onClose={this.closeVideo} />)}
|
||||
|
||||
<div className="video__overlay">
|
||||
{/* <Video className="content__embedded" uri={playingUri} overlayed hiddenControls /> */}
|
||||
{/* <div id="asdf"></div> */}
|
||||
<div className="video content__embedded hiddenContainer" id="video__overlay_id_top_container">
|
||||
<div className="content__view">
|
||||
<div className="content__view--container" id="video__overlay_id">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{(showOverlay && <div className="video__mask" id="video_mask">
|
||||
{this.renderPlayOrPauseButton()}
|
||||
<Button
|
||||
noPadding
|
||||
button="secondary"
|
||||
icon={icons.MAXIMIZE}
|
||||
onClick={() => this.returnToMedia()}
|
||||
/>
|
||||
</div>)}
|
||||
</div>
|
||||
</Overlay>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default VideoOverlay;
|
10
src/renderer/component/videoOverlayHeader/index.js
Normal file
10
src/renderer/component/videoOverlayHeader/index.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { makeSelectTitleForUri } from 'lbry-redux';
|
||||
import VideoOverlayHeader from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
title: makeSelectTitleForUri(props.uri)(state),
|
||||
onClose: props.onClose,
|
||||
});
|
||||
|
||||
export default connect(select, null)(VideoOverlayHeader);
|
31
src/renderer/component/videoOverlayHeader/view.jsx
Normal file
31
src/renderer/component/videoOverlayHeader/view.jsx
Normal file
|
@ -0,0 +1,31 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import Button from 'component/button';
|
||||
import * as icons from 'constants/icons';
|
||||
import TruncatedText from 'component/common/truncated-text';
|
||||
|
||||
type Props = {
|
||||
onClose: () => void,
|
||||
title: string,
|
||||
};
|
||||
|
||||
class VideoOverlayHeader extends React.Component<Props> {
|
||||
render() {
|
||||
const { onClose, title } = this.props;
|
||||
return (
|
||||
<header className="video_overlay__header">
|
||||
<h4 className="overlay__title--small">
|
||||
<TruncatedText lines={2}>{title}</TruncatedText>
|
||||
</h4>
|
||||
<Button
|
||||
icon={icons.CLOSE}
|
||||
onClick={() => {
|
||||
onClose();
|
||||
}}
|
||||
/>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default VideoOverlayHeader;
|
|
@ -188,6 +188,9 @@ export const SET_VIDEO_PAUSE = 'SET_VIDEO_PAUSE';
|
|||
export const MEDIA_PLAY = 'MEDIA_PLAY';
|
||||
export const MEDIA_PAUSE = 'MEDIA_PAUSE';
|
||||
export const MEDIA_POSITION = 'MEDIA_POSITION';
|
||||
// Overlay Media
|
||||
export const SHOW_OVERLAY_MEDIA = 'SHOW_OVERLAY_MEDIA';
|
||||
export const HIDE_OVERLAY_MEDIA = 'HIDE_OVERLAY_MEDIA';
|
||||
|
||||
// Publishing
|
||||
export const CLEAR_PUBLISH = 'CLEAR_PUBLISH';
|
||||
|
|
|
@ -25,4 +25,7 @@ export const CHECK = 'CheckCircle';
|
|||
export const HEART = 'Heart';
|
||||
export const UNLOCK = 'Unlock';
|
||||
export const CHECK_SIMPLE = 'Check';
|
||||
export const PLAY = 'Play';
|
||||
export const MAXIMIZE = 'Maximize2';
|
||||
export const PAUSE = 'Pause';
|
||||
export const GLOBE = 'Globe';
|
||||
|
|
|
@ -16,6 +16,7 @@ import 'scss/all.scss';
|
|||
import store from 'store';
|
||||
import app from './app';
|
||||
import analytics from './analytics';
|
||||
import VideoOverlay from './component/videoOverlay/';
|
||||
import doLogWarningConsoleMessage from './logWarningConsoleMessage';
|
||||
|
||||
const { autoUpdater } = remote.require('electron-updater');
|
||||
|
@ -148,6 +149,7 @@ const init = () => {
|
|||
<div>
|
||||
<App />
|
||||
<SnackBar />
|
||||
<VideoOverlay />
|
||||
</div>
|
||||
</Provider>,
|
||||
document.getElementById('app')
|
||||
|
|
|
@ -34,6 +34,7 @@ const select = (state, props) => ({
|
|||
isPaused: selectMediaPaused(state),
|
||||
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
||||
fromOverlay: Boolean(props.fromOverlay),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -45,6 +45,7 @@ type Props = {
|
|||
prepareEdit: ({}, string) => void,
|
||||
setClientSetting: (string, boolean | string) => void,
|
||||
checkSubscription: ({ channelName: string, uri: string }) => void,
|
||||
fromOverlay: boolean,
|
||||
subscriptions: Array<Subscription>,
|
||||
};
|
||||
|
||||
|
@ -107,6 +108,7 @@ class FilePage extends React.Component<Props> {
|
|||
prepareEdit,
|
||||
navigate,
|
||||
autoplay,
|
||||
fromOverlay,
|
||||
costInfo,
|
||||
} = this.props;
|
||||
|
||||
|
@ -150,7 +152,7 @@ class FilePage extends React.Component<Props> {
|
|||
</section>
|
||||
) : (
|
||||
<section className="card">
|
||||
{isPlayable && <Video className="content__embedded" uri={uri} />}
|
||||
{isPlayable && <Video className="content__embedded" uri={uri} fromOverlay={fromOverlay} />}
|
||||
{!isPlayable &&
|
||||
(thumbnail ? (
|
||||
<Thumbnail shouldObscure={shouldObscureThumbnail} src={thumbnail} />
|
||||
|
|
|
@ -11,6 +11,7 @@ const select = (state, props) => ({
|
|||
claim: makeSelectClaimForUri(props.uri)(state),
|
||||
isResolvingUri: makeSelectIsUriResolving(props.uri)(state),
|
||||
blackListedOutpoints: selectBlackListedOutpoints(state),
|
||||
fromOverlay: props.fromOverlay,
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -12,6 +12,7 @@ type Props = {
|
|||
resolveUri: string => void,
|
||||
uri: string,
|
||||
claim: Claim,
|
||||
fromOverlay: boolean,
|
||||
blackListedOutpoints: Array<{
|
||||
txid: string,
|
||||
nout: number,
|
||||
|
@ -34,7 +35,7 @@ class ShowPage extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { claim, isResolvingUri, uri, blackListedOutpoints } = this.props;
|
||||
const { claim, isResolvingUri, uri, blackListedOutpoints, fromOverlay } = this.props;
|
||||
|
||||
let innerContent = '';
|
||||
|
||||
|
@ -85,7 +86,7 @@ class ShowPage extends React.PureComponent<Props> {
|
|||
</Page>
|
||||
);
|
||||
} else {
|
||||
innerContent = <FilePage uri={uri} />;
|
||||
innerContent = <FilePage uri={uri} fromOverlay={fromOverlay} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,3 +26,13 @@ export function savePosition(claimId: String, position: Number) {
|
|||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const doShowOverlay = () => (dispatch: Dispatch) =>
|
||||
dispatch({
|
||||
type: actions.SHOW_OVERLAY_MEDIA,
|
||||
});
|
||||
|
||||
export const doHideOverlay = () => (dispatch: Dispatch) =>
|
||||
dispatch({
|
||||
type: actions.HIDE_OVERLAY_MEDIA,
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as ACTIONS from 'constants/action_types';
|
|||
|
||||
const reducers = {};
|
||||
const defaultState = {
|
||||
showOverlay: false,
|
||||
playingUri: null,
|
||||
currentlyIsPlaying: false,
|
||||
rewardedContentClaimIds: [],
|
||||
|
|
|
@ -3,6 +3,7 @@ import * as actions from 'constants/action_types';
|
|||
import { handleActions } from 'util/redux-utils';
|
||||
|
||||
export type MediaState = {
|
||||
showOverlay: Boolean,
|
||||
paused: Boolean,
|
||||
positions: {
|
||||
[string]: number,
|
||||
|
@ -12,16 +13,17 @@ export type MediaState = {
|
|||
export type Action = any;
|
||||
export type Dispatch = (action: Action) => any;
|
||||
|
||||
const defaultState = { paused: true, positions: {} };
|
||||
const defaultState = { paused: true, positions: {}, showOverlay: false };
|
||||
|
||||
export default handleActions(
|
||||
{
|
||||
[actions.MEDIA_PLAY]: (state: MediaState, action: Action) => ({
|
||||
// if parameters: state: MediaState, action: Action
|
||||
[actions.MEDIA_PLAY]: (state: MediaState) => ({
|
||||
...state,
|
||||
paused: false,
|
||||
}),
|
||||
|
||||
[actions.MEDIA_PAUSE]: (state: MediaState, action: Action) => ({
|
||||
[actions.MEDIA_PAUSE]: (state: MediaState) => ({
|
||||
...state,
|
||||
paused: true,
|
||||
}),
|
||||
|
@ -36,6 +38,16 @@ export default handleActions(
|
|||
},
|
||||
};
|
||||
},
|
||||
|
||||
[actions.SHOW_OVERLAY_MEDIA]: (state: MediaState) => ({
|
||||
...state,
|
||||
showOverlay: true,
|
||||
}),
|
||||
|
||||
[actions.HIDE_OVERLAY_MEDIA]: (state: MediaState) => ({
|
||||
...state,
|
||||
showOverlay: false,
|
||||
}),
|
||||
},
|
||||
defaultState
|
||||
);
|
||||
|
|
|
@ -10,3 +10,5 @@ export const makeSelectMediaPositionForUri = uri =>
|
|||
const outpoint = `${claim.txid}:${claim.nout}`;
|
||||
return state.positions[outpoint] || null;
|
||||
});
|
||||
|
||||
export const selectShowOverlay = createSelector(selectState, state => state.showOverlay);
|
||||
|
|
|
@ -24,4 +24,5 @@
|
|||
@import 'component/_nav.scss';
|
||||
@import 'component/_file-list.scss';
|
||||
@import 'component/_search.scss';
|
||||
@import 'component/_overlay.scss';
|
||||
@import 'component/_toggle.scss';
|
||||
|
|
57
src/renderer/scss/component/_overlay.scss
Normal file
57
src/renderer/scss/component/_overlay.scss
Normal file
|
@ -0,0 +1,57 @@
|
|||
.hiddenContainer {
|
||||
display: none;
|
||||
}
|
||||
.overlay {
|
||||
position: fixed;
|
||||
max-height: 50%;
|
||||
max-width: 50%;
|
||||
width: 20%;
|
||||
height: inherit;
|
||||
bottom: 1%;
|
||||
right: 1%;
|
||||
z-index: 3;
|
||||
box-shadow: var(--box-shadow-layer);
|
||||
|
||||
.video__overlay {
|
||||
position: relative;
|
||||
|
||||
.video__mask {
|
||||
opacity: 0;
|
||||
background-color: rgba(0, 0, 8, 0.7);
|
||||
transition: all 0.4s ease-in-out;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.btn {
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .video__mask {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.video_overlay__header {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 2rem;
|
||||
background-color: var(--header-primary-color);
|
||||
padding: 20px 10px;
|
||||
|
||||
.overlay__title--small {
|
||||
font-size: 15px;
|
||||
line-height: 15px;
|
||||
}
|
||||
}
|
0
src/renderer/scss/component/_video_overlay.scss
Normal file
0
src/renderer/scss/component/_video_overlay.scss
Normal file
Loading…
Reference in a new issue