Skip to content

Commit

Permalink
feat(FEC-8632): add graphic indication to chrome picture in picture m…
Browse files Browse the repository at this point in the history
…ode (#326)

* add an overlay when playing inn PIP mode

* change docs

* fix es lint
  • Loading branch information
odedhutzler committed Jan 21, 2019
1 parent 2ae9925 commit 9be71ac
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 2 deletions.
9 changes: 9 additions & 0 deletions src/components/engine-connector/engine-connector.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class EngineConnector extends BaseComponent {

this.eventManager.listen(this.player, this.player.Event.SOURCE_SELECTED, () => {
this.props.updateIsVr(this.player.isVr());
this.props.updateIsInPictureInPicture(this.player.isInPictureInPicture());
if (this.player.config.playback.autoplay) {
this.props.updateLoadingSpinnerState(true);
} else {
Expand Down Expand Up @@ -266,6 +267,14 @@ class EngineConnector extends BaseComponent {
this.eventManager.listen(this.player, this.player.Event.Playlist.PLAYLIST_ITEM_CHANGED, () => {
this.props.updatePlaylist({next: this.player.playlist.next, prev: this.player.playlist.prev});
});

this.eventManager.listen(this.player, this.player.Event.ENTER_PICTURE_IN_PICTURE, () => {
this.props.updateIsInPictureInPicture(true);
});

this.eventManager.listen(this.player, this.player.Event.LEAVE_PICTURE_IN_PICTURE, () => {
this.props.updateIsInPictureInPicture(false);
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
@import '~styles/variables';

.picture-in-picture-overlay{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
font-family: $font-family;
display: flex;
align-items: center;
justify-content: center;

.picture-in-picture-poster {
all: inherit;
background-size: contain;
background: black no-repeat center center;

&.has-poster {
background-color: #000;
}

.dark-layer {
background-color: rgba(0, 0, 0, 0.4);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}

.picture-in-picture-control {
position: absolute;
display: flex;
flex-direction: column;
}

.picture-in-picture-text {
color: $white;
font-size: $headline-font-size;
white-space: nowrap;
overflow: hidden;
}

.picture-in-picture-button {
height: 36px;
width: 120px;
border: 2px solid $grayscale2;
border-radius: 18px;
background-color: $grayscale1;
color: $white;
font-size: 15px;
font-weight: bold;
line-height: 30px;
cursor: pointer;
margin-top: 20px;
align-self: center;
&:hover{
background-color: $grayscale2;
}
}
}
1 change: 1 addition & 0 deletions src/components/picture-in-picture-overlay/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {PictureInPictureOverlay} from './picture-in-picture-overlay';
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//@flow
import style from '../../styles/style.scss';
import {h} from 'preact';
import BaseComponent from '../base';
import {connect} from 'preact-redux';
import {Localizer, Text} from 'preact-i18n';

/**
* mapping state to props
* @param {*} state - redux store state
* @returns {Object} - mapped state to this component
*/
const mapStateToProps = state => ({
poster: state.engine.poster,
isInPictureInPicture: state.engine.isInPictureInPicture,
isChangingSource: state.engine.isChangingSource
});

@connect(mapStateToProps)
/**
* PictureInPictureOverlay component
*
* @class PictureInPictureOverlay
* @example <PictureInPictureOverlay player={this.player} />
* @extends {BaseComponent}
*/
class PictureInPictureOverlay extends BaseComponent {
/**
* Creates an instance of PictureInPictureOverlay.
* @param {Object} obj obj
* @memberof PictureInPictureOverlay
*/
constructor(obj: Object) {
super({name: 'PictureInPictureOverlay', player: obj.player});
}

/**
* The button is clicked, play the video in the player instead of in picture in picture
* @returns {void}
* @memberof PictureInPictureOverlay
*/
_handleClick(): void {
this.player.exitPictureInPicture();
}

/**
* render component
*
* @returns {?React$Element} - component element
* @memberof PictureInPictureOverlay
*/
render(): ?React$Element<any> {
if (!this.props.isInPictureInPicture) {
return;
}

let posterStyle = {};
const posterClasses = [style.pictureInPicturePoster];
if (this.props.poster) {
const backgroundImage = this.props.isChangingSource ? '' : `url(${this.props.poster})`;
posterStyle = {
backgroundImage,
backgroundSize: 'contain'
};
posterClasses.push(style.hasPoster);
}

return (
<div>
<div className={style.pictureInPictureOverlay}>
<div className={posterClasses.join(' ')} style={posterStyle} onMouseOver={e => e.stopPropagation()}>
<div className={style.darkLayer} />
</div>
<div className={style.pictureInPictureControl}>
<Localizer>
<span className={style.pictureInPictureText}>
<Text id="pictureInPicture.overlay_text" />
</span>
</Localizer>
<Localizer>
<button className={[style.pictureInPictureButton, style.controlButtonContainer].join(' ')} onClick={() => this._handleClick()}>
<Text id="pictureInPicture.overlay_button" />
</button>
</Localizer>
</div>
</div>
</div>
);
}
}

export {PictureInPictureOverlay};
13 changes: 11 additions & 2 deletions src/reducers/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export const types = {
UPDATE_CAST_SESSION: `${component}/UPDATE_CAST_SESSION`,
UPDATE_IS_CAST_AVAILABLE: `${component}/UPDATE_IS_CAST_AVAILABLE`,
UPDATE_PLAYLIST: `${component}/UPDATE_PLAYLIST`,
UPDATE_PICTURE_IN_PICTURE_SUPPORTED: `${component}/UPDATE_PICTURE_IN_PICTURE_SUPPORTED`
UPDATE_PICTURE_IN_PICTURE_SUPPORTED: `${component}/UPDATE_PICTURE_IN_PICTURE_SUPPORTED`,
UPDATE_PICTURE_IN_PICTURE_MODE: `${component}/UPDATE_PICTURE_IN_PICTURE_MODE`
};

export const initialState = {
Expand Down Expand Up @@ -90,6 +91,7 @@ export const initialState = {
castSession: null,
isCastAvailable: false,
pictureInPictureSupported: false,
isInPictureInPicture: false,
playlist: null
};

Expand Down Expand Up @@ -338,6 +340,12 @@ export default (state: Object = initialState, action: Object) => {
isPictureInPictureSupported: action.isPictureInPictureSupported
};

case types.UPDATE_PICTURE_IN_PICTURE_MODE:
return {
...state,
isInPictureInPicture: action.isInPictureInPicture
};

default:
return state;
}
Expand Down Expand Up @@ -397,5 +405,6 @@ export const actions = {
updatePictureInPictureSupport: (isPictureInPictureSupported: boolean) => ({
type: types.UPDATE_PICTURE_IN_PICTURE_SUPPORTED,
isPictureInPictureSupported
})
}),
updateIsInPictureInPicture: (isInPictureInPicture: boolean) => ({type: types.UPDATE_PICTURE_IN_PICTURE_MODE, isInPictureInPicture})
};
1 change: 1 addition & 0 deletions src/styles/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@
@import '../components/playback-controls/playback-controls';
@import '../components/playlist-countdown/playlist-countdown';
@import '../components/playlist-next-screen/playlist-next-screen';
@import '../components/picture-in-picture-overlay/picture-in-picture-overlay';
4 changes: 4 additions & 0 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,9 @@
"next": "Next",
"up_next": "Up Next",
"cancel": "Cancel"
},
"pictureInPicture": {
"overlay_text": "Playing in Picture In Picture mode",
"overlay_button": "Play Here"
}
}
2 changes: 2 additions & 0 deletions src/ui-presets/live.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {CastBeforePlay} from '../components/cast-on-tv/cast-before-play';
import {Backdrop} from '../components/backdrop/backdrop';
import {PlaybackControls} from '../components/playback-controls';
import {PictureInPicture} from '../components/picture-in-picture';
import {PictureInPictureOverlay} from '../components/picture-in-picture-overlay';

/**
* Live ui intrface
Expand Down Expand Up @@ -59,6 +60,7 @@ export function liveUI(props: any): React$Element<any> {
{Watermark.shouldRender(props) ? <Watermark player={props.player} /> : undefined}
<PrePlaybackPlayOverlay player={props.player} />
<CastBeforePlay player={props.player} />
<PictureInPictureOverlay player={props.player} />
<Backdrop />
</div>
);
Expand Down
2 changes: 2 additions & 0 deletions src/ui-presets/playback.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {PlaybackControls} from '../components/playback-controls';
import {PlaylistCountdown} from '../components/playlist-countdown';
import {PlaylistNextScreen} from '../components/playlist-next-screen';
import {PictureInPicture} from '../components/picture-in-picture';
import {PictureInPictureOverlay} from '../components/picture-in-picture-overlay';

/**
* Playback ui interface
Expand Down Expand Up @@ -65,6 +66,7 @@ export function playbackUI(props: any): React$Element<any> {
{PlaylistCountdown.shouldRender(props) ? <PlaylistCountdown player={props.player} /> : undefined}
<PrePlaybackPlayOverlay player={props.player} />
<CastBeforePlay player={props.player} />
<PictureInPictureOverlay player={props.player} />
<Backdrop />
</div>
);
Expand Down

0 comments on commit 9be71ac

Please sign in to comment.