playable
Version:
Video player based on HTML5Video
249 lines (201 loc) • 6.57 kB
text/typescript
import { UIEvent, EngineState } from '../../../constants';
import View from './screen.view';
import playerAPI from '../../../core/player-api-decorator';
import { IEventEmitter } from '../../event-emitter/types';
import { IFullScreenManager } from '../../full-screen-manager/types';
import { IPlaybackEngine } from '../../playback-engine/types';
import { IInteractionIndicator } from '../interaction-indicator/types';
import { IPlayerConfig } from '../../../core/config';
import { IRootContainer } from '../../root-container/types';
import { IScreenAPI, IScreen, VideoViewMode, IScreenViewConfig } from './types';
const PLAYBACK_CHANGE_TIMEOUT = 300;
class Screen implements IScreen {
static moduleName = 'screen';
static View = View;
static dependencies = [
'engine',
'eventEmitter',
'config',
'fullScreenManager',
'interactionIndicator',
'rootContainer',
];
private _eventEmitter: IEventEmitter;
private _engine: IPlaybackEngine;
private _fullScreenManager: IFullScreenManager;
private _interactionIndicator: IInteractionIndicator;
private _delayedToggleVideoPlaybackTimeout: number;
private _isClickProcessingDisabled: boolean;
private _unbindEvents: () => void;
view: View;
isHidden: boolean;
constructor({
config,
eventEmitter,
engine,
fullScreenManager,
interactionIndicator,
rootContainer,
}: {
config: IPlayerConfig;
eventEmitter: IEventEmitter;
engine: IPlaybackEngine;
fullScreenManager: IFullScreenManager;
interactionIndicator: IInteractionIndicator;
rootContainer: IRootContainer;
}) {
this._eventEmitter = eventEmitter;
this._engine = engine;
this._fullScreenManager = fullScreenManager;
this._interactionIndicator = interactionIndicator;
this.isHidden = false;
this._delayedToggleVideoPlaybackTimeout = null;
this._isClickProcessingDisabled = Boolean(
config.disableControlWithClickOnPlayer,
);
this._bindCallbacks();
this._initUI(config.nativeBrowserControls);
this._bindEvents();
rootContainer.appendComponentElement(this.getElement());
}
getElement() {
return this.view.getElement();
}
private _bindCallbacks() {
this._processClick = this._processClick.bind(this);
this._processDblClick = this._processDblClick.bind(this);
this._toggleVideoPlayback = this._toggleVideoPlayback.bind(this);
}
private _initUI(isNativeControls: boolean) {
const config: IScreenViewConfig = {
nativeControls: isNativeControls,
callbacks: {
onWrapperMouseClick: this._processClick,
onWrapperMouseDblClick: this._processDblClick,
},
playbackViewElement: this._engine.getElement(),
};
this.view = new View(config);
}
private _bindEvents() {
this._unbindEvents = this._eventEmitter.bindEvents(
[
[UIEvent.PLAY_OVERLAY_CLICK, this.view.focusOnNode, this.view],
[UIEvent.RESIZE, this._updateSizes],
[EngineState.SRC_SET, this.view.resetBackground, this.view],
[EngineState.METADATA_LOADED, this.view.resetAspectRatio, this.view],
],
this,
);
}
private _updateSizes({ width, height }: { width: number; height: number }) {
this.view.setBackgroundSize(width, height);
this.view.resetAspectRatio();
}
showCursor() {
this.view.showCursor();
}
hideCursor() {
this.view.hideCursor();
}
private _processClick() {
if (this._isClickProcessingDisabled) {
return;
}
this._showPlaybackChangeIndicator();
if (!this._fullScreenManager.isEnabled) {
this._toggleVideoPlayback();
} else {
this._setDelayedPlaybackToggle();
}
}
private _processDblClick() {
if (this._isClickProcessingDisabled) {
return;
}
if (this._fullScreenManager.isEnabled) {
if (this._isDelayedPlaybackToggleExist) {
this._clearDelayedPlaybackToggle();
this._hideDelayedPlaybackChangeIndicator();
}
this._toggleFullScreen();
}
}
private _showPlaybackChangeIndicator() {
const state = this._engine.getCurrentState();
if (state === EngineState.PLAY_REQUESTED || state === EngineState.PLAYING) {
this._interactionIndicator.showPause();
} else {
this._interactionIndicator.showPlay();
}
}
private _hideDelayedPlaybackChangeIndicator() {
this._interactionIndicator.hideIcons();
}
private _setDelayedPlaybackToggle() {
this._clearDelayedPlaybackToggle();
this._delayedToggleVideoPlaybackTimeout = window.setTimeout(
this._toggleVideoPlayback,
PLAYBACK_CHANGE_TIMEOUT,
);
}
private _clearDelayedPlaybackToggle() {
window.clearTimeout(this._delayedToggleVideoPlaybackTimeout);
this._delayedToggleVideoPlaybackTimeout = null;
}
private get _isDelayedPlaybackToggleExist() {
return Boolean(this._delayedToggleVideoPlaybackTimeout);
}
private _toggleVideoPlayback() {
this._clearDelayedPlaybackToggle();
const state = this._engine.getCurrentState();
if (state === EngineState.PLAY_REQUESTED || state === EngineState.PLAYING) {
this._engine.pause();
this._eventEmitter.emitAsync(UIEvent.PAUSE_WITH_SCREEN_CLICK);
} else {
this._engine.play();
this._eventEmitter.emitAsync(UIEvent.PLAY_WITH_SCREEN_CLICK);
}
}
private _toggleFullScreen() {
if (this._fullScreenManager.isInFullScreen) {
this._fullScreenManager.exitFullScreen();
this._eventEmitter.emitAsync(UIEvent.EXIT_FULL_SCREEN_WITH_SCREEN_CLICK);
} else {
this._fullScreenManager.enterFullScreen();
this._eventEmitter.emitAsync(UIEvent.ENTER_FULL_SCREEN_WITH_SCREEN_CLICK);
}
}
hide() {
if (!this.isHidden) {
this.view.hide();
this.isHidden = true;
}
}
show() {
if (this.isHidden) {
this.view.show();
this.isHidden = false;
}
}
/**
* Method for setting video view mode.
* @param viewMode Possible values are "REGULAR", "FILL", "BLUR".
* With "REGULAR" video tag would try to be fully shown.
* With "FILL" video tag would fill all space, removing black lines on sides.
* With "BLUR" black lines would be filled with blured pixels from video.
* @example
* player.setVideoViewMode("BLUR");
*/
setVideoViewMode(viewMode: VideoViewMode) {
this.view.setViewMode(viewMode);
}
destroy() {
this._unbindEvents();
this._clearDelayedPlaybackToggle();
this.view.destroy();
}
}
export { IScreenAPI };
export default Screen;