Add videos to be played across all pages. #1523
14 changed files with 154 additions and 10 deletions
14
src/renderer/component/overlay/index.js
Normal file
14
src/renderer/component/overlay/index.js
Normal 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);
|
16
src/renderer/component/overlay/view.jsx
Normal file
16
src/renderer/component/overlay/view.jsx
Normal 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;
|
|
@ -3,7 +3,7 @@ import * as settings from 'constants/settings';
|
|||
import { doChangeVolume } from 'redux/actions/app';
|
||||
import { selectVolume } from 'redux/selectors/app';
|
||||
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 {
|
||||
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,15 +38,18 @@ const select = (state, props) => ({
|
|||
mediaPosition: makeSelectMediaPositionForUri(props.uri)(state),
|
||||
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
||||
searchBarFocused: selectSearchBarFocused(state),
|
||||
showOverlay: selectShowOverlay(state),
|
||||
overlayed: props.overlayed,
|
||||
});
|
||||
|
||||
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)),
|
||||
});
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import LoadingScreen from './internal/loading-screen';
|
|||
const SPACE_BAR_KEYCODE = 32;
|
||||
|
||||
type Props = {
|
||||
cancelPlay: () => void,
|
||||
fileInfo: {
|
||||
outpoint: string,
|
||||
file_name: string,
|
||||
|
@ -34,12 +33,16 @@ 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,
|
||||
overlayed: boolean,
|
||||
};
|
||||
|
||||
class Video extends React.PureComponent<Props> {
|
||||
|
@ -53,6 +56,11 @@ class Video extends React.PureComponent<Props> {
|
|||
componentDidMount() {
|
||||
this.handleAutoplay(this.props);
|
||||
window.addEventListener('keydown', this.handleKeyDown);
|
||||
|
||||
const { showOverlay, doHideOverlay, uri, playingUri, overlayed } = this.props;
|
||||
if (showOverlay && uri === playingUri && !overlayed) {
|
||||
doHideOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
|
@ -67,7 +75,10 @@ class Video extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.cancelPlay();
|
||||
const { overlayed, doShowOverlay } = this.props;
|
||||
if (!overlayed) {
|
||||
doShowOverlay();
|
||||
}
|
||||
window.removeEventListener('keydown', this.handleKeyDown);
|
||||
}
|
||||
|
||||
|
@ -111,7 +122,10 @@ class Video extends React.PureComponent<Props> {
|
|||
}
|
||||
|
||||
playContent() {
|
||||
const { play, uri } = this.props;
|
||||
const { play, uri, showOverlay, playingUri, doHideOverlay } = this.props;
|
||||
if (playingUri && showOverlay) {
|
||||
doHideOverlay();
|
||||
}
|
||||
play(uri);
|
||||
}
|
||||
|
||||
|
|
9
src/renderer/component/videoOverlay/index.js
Normal file
9
src/renderer/component/videoOverlay/index.js
Normal 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);
|
25
src/renderer/component/videoOverlay/view.jsx
Normal file
25
src/renderer/component/videoOverlay/view.jsx
Normal 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;
|
|
@ -187,6 +187,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';
|
||||
|
|
|
@ -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/';
|
||||
|
||||
const { autoUpdater } = remote.require('electron-updater');
|
||||
|
||||
|
@ -131,6 +132,7 @@ const init = () => {
|
|||
<div>
|
||||
<App />
|
||||
<SnackBar />
|
||||
<VideoOverlay />
|
||||
</div>
|
||||
</Provider>,
|
||||
document.getElementById('app')
|
||||
|
|
|
@ -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,21 +13,22 @@ 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,
|
||||
}),
|
||||
|
||||
[actions.MEDIA_POSITION]: (state: MediaState, action: Action) => {
|
||||
[actions.MEDIA_POSITION]: (state: MediaState) => {
|
||||
const { outpoint, position } = action.data;
|
||||
return {
|
||||
...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
|
||||
);
|
||||
|
|
|
@ -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,3 +24,4 @@
|
|||
@import 'component/_nav.scss';
|
||||
@import 'component/_file-list.scss';
|
||||
@import 'component/_search.scss';
|
||||
@import 'component/_overlay.scss';
|
||||
|
|
28
src/renderer/scss/component/_overlay.scss
Normal file
28
src/renderer/scss/component/_overlay.scss
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue