@playkit-js/playkit-js-ui
Version:
[](https://github.com/kaltura/playkit-js-ui/actions/workflows/run_canary_full_flow.yaml) [ • 13.4 kB
text/typescript
/* eslint-disable @typescript-eslint/no-use-before-define */
import {FakeEvent} from '@playkit-js/playkit-js';
import {types as shell} from '../reducers/shell';
import {AudioSelectedEvent} from '../event/events/audio-selected-event';
import {CaptionSelectedEvent} from '../event/events/caption-selected-event';
import {CaptionsStyleSelectedEvent} from '../event/events/captions-style-selected-event';
import {QualitySelectedEvent} from '../event/events/quality-selected-event';
import {SeekedEvent} from '../event/events/seeked-event';
import {SpeedSelectedEvent} from '../event/events/speed-selected-event';
import {PlayerResizeEvent} from '../event/events/player-resize-event';
import {GuiResizeEvent} from '../event/events/gui-resize-event';
import {VideoResizeEvent} from '../event/events/video-resize-event';
import {UIVisibilityChangedEvent} from '../event/events/ui-visibility-changed-event';
import {RewindClickedEvent} from '../event/events/rewind-clicked';
import {ForwardClickedEvent} from '../event/events/forward-clicked';
import {VolumeChangedEvent} from '../event/events/volume-changed';
import {KeyMap} from '../utils';
import {EventType} from '../event';
const namespace = 'event-dispatcher-middleware';
const types = {
COMPONENT_CLICKED: `${namespace}/COMPONENT_CLICKED`,
COMPONENT_CHANGED: `${namespace}/COMPONENT_CHANGED`
};
/**
* EventDispatcher Middleware function.
* @param {any} player - The video player.
* @returns {void}
*/
const eventDispatcherMiddleware =
(player: any) =>
(store: any) =>
(next: (...args: any) => any) =>
(action: any): void => {
switch (action.type) {
case types.COMPONENT_CLICKED:
onClickableComponentsHandler(store, action, player);
break;
case types.COMPONENT_CHANGED:
onChangeableComponentsHandler(store, action, player);
break;
case shell.UPDATE_PLAYER_HOVER_STATE:
onPlayerHoverStateChangeHandler(store, action, player);
break;
default:
break;
}
next(action);
switch (action.type) {
case shell.UPDATE_GUI_CLIENT_RECT:
onGuiResizeHandler(store, action, player);
break;
case shell.UPDATE_PLAYER_CLIENT_RECT:
onPlayerResizeHandler(store, action, player);
break;
case shell.UPDATE_VIDEO_CLIENT_RECT:
onVideoResizeHandler(store, action, player);
break;
default:
break;
}
};
/**
* Handler for gui resize change action
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onGuiResizeHandler(store: any, action: any, player: any): void {
const guiClientRect = store.getState().shell.guiClientRect;
player.dispatchEvent(new GuiResizeEvent(guiClientRect));
}
/**
* Handler for player resize change action
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onPlayerResizeHandler(store: any, action: any, player: any): void {
const playerClientRect = store.getState().shell.playerClientRect;
player.dispatchEvent(new PlayerResizeEvent(playerClientRect));
}
/**
* Handler for video resize change action
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onVideoResizeHandler(store: any, action: any, player: any): void {
const videoClientRect = store.getState().shell.videoClientRect;
player.dispatchEvent(new VideoResizeEvent(videoClientRect));
}
/**
* Handler for hover state change action.
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onPlayerHoverStateChangeHandler(store: any, action: any, player: any): void {
const engineState = store.getState().engine;
const shellState = store.getState().shell;
if (!engineState.adBreak && engineState.isPlaying && shellState.playerHover !== action.hover) {
player.dispatchEvent(new UIVisibilityChangedEvent(action.hover));
}
}
/**
* Handler for changeable components actions.
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onChangeableComponentsHandler(store: any, action: any, player: any): void {
switch (action.name) {
case 'Volume':
player.dispatchEvent(new VolumeChangedEvent(action.payload.volume));
break;
case 'SeekBarPlaybackContainer':
player.dispatchEvent(new SeekedEvent(action.payload.from, action.payload.to));
break;
case 'ActivePreset':
player.dispatchEvent(new FakeEvent(EventType.UI_PRESET_CHANGE, action.payload));
break;
default:
break;
}
}
/**
* Handler for clickable components actions.
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onClickableComponentsHandler(store: any, action: any, player: any): void {
switch (action.name) {
case 'Keyboard':
keyboardHandlers[action.payload.key](store, action, player);
break;
case 'OverlayAction':
onOverlayActionClicked(store, action, player);
break;
case 'CaptionsMenu':
onCaptionsClick(store, action, player);
break;
case 'AudioMenu':
onAudioClicked(store, action, player);
break;
case 'QualityMenu':
onQualityClicked(store, action, player);
break;
case 'SpeedMenu':
onSpeedClicked(store, action, player);
break;
case 'AdvancedAudioDescToggle':
onAdvancedAudioDescriptionClicked(store, action, player);
break;
case 'CVAAOverlay':
player.dispatchEvent(new CaptionsStyleSelectedEvent(action.payload.textStyle));
break;
case 'Fullscreen':
onFullScreenClicked(store, action, player);
break;
case 'Shell':
player.dispatchEvent(new FakeEvent(EventType.UI_CLICKED));
break;
case 'Rewind':
player.dispatchEvent(new RewindClickedEvent(action.payload.from, action.payload.to));
break;
case 'Forward':
player.dispatchEvent(new ForwardClickedEvent(action.payload.from, action.payload.to));
break;
case 'LiveTag':
player.dispatchEvent(new FakeEvent(EventType.USER_CLICKED_LIVE_TAG));
break;
case 'PrePlaybackPlayOverlay':
case 'PlayPause':
onPlayPauseClicked(store, action, player);
break;
case 'Volume':
onVolumeClicked(store, action, player);
break;
}
}
/**
* Handler for play-pause clicked actions.
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onPlayPauseClicked(store: any, action: any, player: any): void {
const engineState = store.getState().engine;
if (engineState.adBreak) {
engineState.adIsPlaying
? player.dispatchEvent(new FakeEvent(EventType.USER_CLICKED_PAUSE))
: player.dispatchEvent(new FakeEvent(EventType.USER_CLICKED_PLAY));
} else {
engineState.isPlaying
? player.dispatchEvent(new FakeEvent(EventType.USER_CLICKED_PAUSE))
: player.dispatchEvent(new FakeEvent(EventType.USER_CLICKED_PLAY));
}
}
/**
* Handler for volume clicked actions.
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onVolumeClicked(store: any, action: any, player: any): void {
const engineState = store.getState().engine;
engineState.muted
? player.dispatchEvent(new FakeEvent(EventType.USER_CLICKED_MUTE))
: player.dispatchEvent(new FakeEvent(EventType.USER_CLICKED_UNMUTE));
}
/**
* Handler for fullscreen clicked actions.
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onFullScreenClicked(store: any, action: any, player: any): void {
player.isFullscreen()
? player.dispatchEvent(new FakeEvent(EventType.USER_EXITED_FULL_SCREEN))
: player.dispatchEvent(new FakeEvent(EventType.USER_ENTERED_FULL_SCREEN));
}
/**
* Handler for PictureInPicture clicked actions.
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onPictureInPictureClicked(store: any, action: any, player: any): void {
player.isInPictureInPicture()
? player.dispatchEvent(new FakeEvent(EventType.USER_EXITED_PICTURE_IN_PICTURE))
: player.dispatchEvent(new FakeEvent(EventType.USER_ENTERED_PICTURE_IN_PICTURE));
}
/**
* Handler for captions menu clicked actions.
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onCaptionsClick(store: any, action: any, player: any): void {
if (action.payload.type === player.Track.TEXT) {
player.dispatchEvent(new CaptionSelectedEvent(action.payload.track));
}
}
/**
* Handler for audio menu clicked actions.
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onAudioClicked(store: any, action: any, player: any): void {
if (action.payload.type === player.Track.AUDIO) {
player.dispatchEvent(new AudioSelectedEvent(action.payload.track));
}
}
/**
* Handler for Quality menu clicked actions.
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onQualityClicked(store: any, action: any, player: any): void {
if (action.payload.type === player.Track.VIDEO) {
player.dispatchEvent(new QualitySelectedEvent(action.payload.track));
}
}
/**
* Handler for Speed menu clicked actions.
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onSpeedClicked(store: any, action: any, player: any): void {
if (action.payload.type === 'speed') {
player.dispatchEvent(new SpeedSelectedEvent(action.payload.speed));
}
}
/**
* Handler for AdvancedAudioDescription menu clicked actions.
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onAdvancedAudioDescriptionClicked(store: any, action: any, player: any): void {
if (action.payload.type === 'AdvancedAudioDescription') {
player.dispatchEvent(new FakeEvent(EventType.USER_CLICKED_ADVANCED_AUDIO_DESCRIPTION, action.payload));
}
}
/**
* Handler for overlay clicked actions.
* @param {any} store - The redux store.
* @param {any} action - The action object.
* @param {any} player - The video player.
* @returns {void}
*/
function onOverlayActionClicked(store: any, action: any, player: any): void {
if (action.payload.type === 'PlayPause') {
onPlayPauseClicked(store, action, player);
} else if (action.payload.type === 'Fullscreen') {
onFullScreenClicked(store, action, player);
}
}
/**
* Keyboard handler object.
* Maps key code to its event dispatching logic.
* @type {any}
*/
const keyboardHandlers: {[key: number]: Function} = {
[KeyMap.SPACE]: (store, action, player) => {
onPlayPauseClicked(store, action, player);
},
[KeyMap.UP]: (store, action, player) => {
player.dispatchEvent(new VolumeChangedEvent(action.payload.volume));
},
[KeyMap.DOWN]: (store, action, player) => {
player.dispatchEvent(new VolumeChangedEvent(action.payload.volume));
},
[KeyMap.F]: (store, action, player) => {
onFullScreenClicked(store, action, player);
},
[KeyMap.P]: (store, action, player) => {
onPictureInPictureClicked(store, action, player);
},
[KeyMap.ESC]: (store, action, player) => {
onFullScreenClicked(store, action, player);
},
[KeyMap.LEFT]: (store, action, player) => {
player.dispatchEvent(new SeekedEvent(action.payload.from, action.payload.to));
},
[KeyMap.RIGHT]: (store, action, player) => {
player.dispatchEvent(new SeekedEvent(action.payload.from, action.payload.to));
},
[KeyMap.HOME]: (store, action, player) => {
player.dispatchEvent(new SeekedEvent(action.payload.from, action.payload.to));
},
[KeyMap.END]: (store, action, player) => {
player.dispatchEvent(new SeekedEvent(action.payload.from, action.payload.to));
},
[KeyMap.M]: (store, action, player) => {
onVolumeClicked(store, action, player);
},
[KeyMap.SEMI_COLON]: (store, action, player) => {
player.dispatchEvent(new SpeedSelectedEvent(action.payload.speed));
},
[KeyMap.PERIOD]: (store, action, player) => {
player.dispatchEvent(new SpeedSelectedEvent(action.payload.speed));
},
[KeyMap.COMMA]: (store, action, player) => {
player.dispatchEvent(new SpeedSelectedEvent(action.payload.speed));
},
[KeyMap.C]: (store, action, player) => {
player.dispatchEvent(new CaptionSelectedEvent(action.payload.track));
}
};
export {types, eventDispatcherMiddleware};