Add videos to be played across all pages.

This commit is contained in:
Daniel Dominguez 2018-05-26 18:25:37 -03:00
parent 3ecf05e6ab
commit 3287d3616e
14 changed files with 154 additions and 10 deletions

View file

@ -0,0 +1,14 @@
import { connect } from 'react-redux';
import { selectShowOverlay } from 'redux/selectors/media';
import { doHideOverlay } from 'redux/actions/media';
import Overlay from './view';
const select = state => ({
showOverlay: selectShowOverlay(state),
});
const perform = dispatch => ({
doCloseOverlay: dispatch(doHideOverlay()),
});
export default connect(select, perform)(Overlay);

View file

@ -0,0 +1,16 @@
// @flow
import React from 'react';
type Props = {
showOverlay: ?boolean,
children: ?React.node,
};
class Overlay extends React.PureComponent<Props> {
render() {
const { showOverlay, children } = this.props;
return <div className="overlay">{showOverlay ? children : ''}</div>;
}
}
export default Overlay;

View file

@ -3,7 +3,7 @@ import * as settings from 'constants/settings';
import { doChangeVolume } from 'redux/actions/app'; import { doChangeVolume } from 'redux/actions/app';
import { selectVolume } from 'redux/selectors/app'; import { selectVolume } from 'redux/selectors/app';
import { doPlayUri, doSetPlayingUri, doLoadVideo } from 'redux/actions/content'; import { doPlayUri, doSetPlayingUri, doLoadVideo } from 'redux/actions/content';
import { doPlay, doPause, savePosition } from 'redux/actions/media'; import { doPlay, doPause, savePosition, doHideOverlay, doShowOverlay } from 'redux/actions/media';
import { import {
makeSelectMetadataForUri, makeSelectMetadataForUri,
makeSelectContentTypeForUri, makeSelectContentTypeForUri,
@ -15,7 +15,11 @@ import {
selectSearchBarFocused, selectSearchBarFocused,
} from 'lbry-redux'; } from 'lbry-redux';
import { makeSelectClientSetting, selectShowNsfw } from 'redux/selectors/settings'; 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 { selectPlayingUri } from 'redux/selectors/content';
import Video from './view'; import Video from './view';
@ -34,15 +38,18 @@ const select = (state, props) => ({
mediaPosition: makeSelectMediaPositionForUri(props.uri)(state), mediaPosition: makeSelectMediaPositionForUri(props.uri)(state),
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state), autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
searchBarFocused: selectSearchBarFocused(state), searchBarFocused: selectSearchBarFocused(state),
showOverlay: selectShowOverlay(state),
overlayed: props.overlayed,
}); });
const perform = dispatch => ({ const perform = dispatch => ({
play: uri => dispatch(doPlayUri(uri)), play: uri => dispatch(doPlayUri(uri)),
load: uri => dispatch(doLoadVideo(uri)), load: uri => dispatch(doLoadVideo(uri)),
cancelPlay: () => dispatch(doSetPlayingUri(null)),
changeVolume: volume => dispatch(doChangeVolume(volume)), changeVolume: volume => dispatch(doChangeVolume(volume)),
doPlay: () => dispatch(doPlay()), doPlay: () => dispatch(doPlay()),
doPause: () => dispatch(doPause()), doPause: () => dispatch(doPause()),
doShowOverlay: () => dispatch(doShowOverlay()),
doHideOverlay: () => dispatch(doHideOverlay()),
savePosition: (claimId, position) => dispatch(savePosition(claimId, position)), savePosition: (claimId, position) => dispatch(savePosition(claimId, position)),
}); });

View file

@ -10,7 +10,6 @@ import LoadingScreen from './internal/loading-screen';
const SPACE_BAR_KEYCODE = 32; const SPACE_BAR_KEYCODE = 32;
type Props = { type Props = {
cancelPlay: () => void,
fileInfo: { fileInfo: {
outpoint: string, outpoint: string,
file_name: string, file_name: string,
@ -34,12 +33,16 @@ type Props = {
doPlay: () => void, doPlay: () => void,
doPause: () => void, doPause: () => void,
savePosition: (string, number) => void, savePosition: (string, number) => void,
doShowOverlay: () => void,
doHideOverlay: () => void,
mediaPaused: boolean, mediaPaused: boolean,
mediaPosition: ?number, mediaPosition: ?number,
className: ?string, className: ?string,
obscureNsfw: boolean, obscureNsfw: boolean,
play: string => void, play: string => void,
searchBarFocused: boolean, searchBarFocused: boolean,
showOverlay: boolean,
overlayed: boolean,
}; };
class Video extends React.PureComponent<Props> { class Video extends React.PureComponent<Props> {
@ -53,6 +56,11 @@ class Video extends React.PureComponent<Props> {
componentDidMount() { componentDidMount() {
this.handleAutoplay(this.props); this.handleAutoplay(this.props);
window.addEventListener('keydown', this.handleKeyDown); window.addEventListener('keydown', this.handleKeyDown);
const { showOverlay, doHideOverlay, uri, playingUri, overlayed } = this.props;
if (showOverlay && uri === playingUri && !overlayed) {
doHideOverlay();
}
} }
componentWillReceiveProps(nextProps: Props) { componentWillReceiveProps(nextProps: Props) {
@ -67,7 +75,10 @@ class Video extends React.PureComponent<Props> {
} }
componentWillUnmount() { componentWillUnmount() {
this.props.cancelPlay(); const { overlayed, doShowOverlay } = this.props;
if (!overlayed) {
doShowOverlay();
}
window.removeEventListener('keydown', this.handleKeyDown); window.removeEventListener('keydown', this.handleKeyDown);
} }
@ -111,7 +122,10 @@ class Video extends React.PureComponent<Props> {
} }
playContent() { playContent() {
const { play, uri } = this.props; const { play, uri, showOverlay, playingUri, doHideOverlay } = this.props;
if (playingUri && showOverlay) {
doHideOverlay();
}
play(uri); play(uri);
} }

View file

@ -0,0 +1,9 @@
import { connect } from 'react-redux';
import { selectPlayingUri } from 'redux/selectors/content';
import VideoOverlay from './view';
const select = state => ({
playingUri: selectPlayingUri(state),
});
export default connect(select, null)(VideoOverlay);

View file

@ -0,0 +1,25 @@
// @flow
import React from 'react';
import Video from 'component/video';
import FileActions from 'component/fileActions';
import Overlay from 'component/overlay';
type Props = {
playingUri: ?string,
};
class VideoOverlay extends React.Component<Props> {
render() {
const { playingUri } = this.props;
return (
<Overlay>
<div className="card-media__internal-links">
<FileActions uri={playingUri} vertical />
</div>
{playingUri ? <Video className="content__embedded" uri={playingUri} overlayed /> : ''}
</Overlay>
);
}
}
export default VideoOverlay;

View file

@ -187,6 +187,9 @@ export const SET_VIDEO_PAUSE = 'SET_VIDEO_PAUSE';
export const MEDIA_PLAY = 'MEDIA_PLAY'; export const MEDIA_PLAY = 'MEDIA_PLAY';
export const MEDIA_PAUSE = 'MEDIA_PAUSE'; export const MEDIA_PAUSE = 'MEDIA_PAUSE';
export const MEDIA_POSITION = 'MEDIA_POSITION'; 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 // Publishing
export const CLEAR_PUBLISH = 'CLEAR_PUBLISH'; export const CLEAR_PUBLISH = 'CLEAR_PUBLISH';

View file

@ -16,6 +16,7 @@ import 'scss/all.scss';
import store from 'store'; import store from 'store';
import app from './app'; import app from './app';
import analytics from './analytics'; import analytics from './analytics';
import VideoOverlay from './component/videoOverlay/';
const { autoUpdater } = remote.require('electron-updater'); const { autoUpdater } = remote.require('electron-updater');
@ -131,6 +132,7 @@ const init = () => {
<div> <div>
<App /> <App />
<SnackBar /> <SnackBar />
<VideoOverlay />
</div> </div>
</Provider>, </Provider>,
document.getElementById('app') document.getElementById('app')

View file

@ -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,
});

View file

@ -2,6 +2,7 @@ import * as ACTIONS from 'constants/action_types';
const reducers = {}; const reducers = {};
const defaultState = { const defaultState = {
showOverlay: false,
playingUri: null, playingUri: null,
currentlyIsPlaying: false, currentlyIsPlaying: false,
rewardedContentClaimIds: [], rewardedContentClaimIds: [],

View file

@ -3,6 +3,7 @@ import * as actions from 'constants/action_types';
import { handleActions } from 'util/redux-utils'; import { handleActions } from 'util/redux-utils';
export type MediaState = { export type MediaState = {
showOverlay: Boolean,
paused: Boolean, paused: Boolean,
positions: { positions: {
[string]: number, [string]: number,
@ -12,21 +13,22 @@ export type MediaState = {
export type Action = any; export type Action = any;
export type Dispatch = (action: Action) => any; export type Dispatch = (action: Action) => any;
const defaultState = { paused: true, positions: {} }; const defaultState = { paused: true, positions: {}, showOverlay: false };
export default handleActions( export default handleActions(
{ {
[actions.MEDIA_PLAY]: (state: MediaState, action: Action) => ({ // if parameters: state: MediaState, action: Action
[actions.MEDIA_PLAY]: (state: MediaState) => ({
...state, ...state,
paused: false, paused: false,
}), }),
[actions.MEDIA_PAUSE]: (state: MediaState, action: Action) => ({ [actions.MEDIA_PAUSE]: (state: MediaState) => ({
...state, ...state,
paused: true, paused: true,
}), }),
[actions.MEDIA_POSITION]: (state: MediaState, action: Action) => { [actions.MEDIA_POSITION]: (state: MediaState) => {
const { outpoint, position } = action.data; const { outpoint, position } = action.data;
return { return {
...state, ...state,
@ -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 defaultState
); );

View file

@ -10,3 +10,5 @@ export const makeSelectMediaPositionForUri = uri =>
const outpoint = `${claim.txid}:${claim.nout}`; const outpoint = `${claim.txid}:${claim.nout}`;
return state.positions[outpoint] || null; return state.positions[outpoint] || null;
}); });
export const selectShowOverlay = createSelector(selectState, state => state.showOverlay);

View file

@ -24,3 +24,4 @@
@import 'component/_nav.scss'; @import 'component/_nav.scss';
@import 'component/_file-list.scss'; @import 'component/_file-list.scss';
@import 'component/_search.scss'; @import 'component/_search.scss';
@import 'component/_overlay.scss';

View file

@ -0,0 +1,28 @@
.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);
&:hover .button-close {
display: inline-block;
background: rgba(0, 0, 0, 0.5);
position: absolute;
height: 22px;
width: 22px;
top: 0px;
right: 0px;
color: #000;
text-align: center;
cursor: pointer;
z-index: 4;
}
}
.overlay .button-close {
display: none;
}