Skip to content

Commit

Permalink
feat: ui events (#217)
Browse files Browse the repository at this point in the history
Add event framework for the ui manager.

Created an event middleware
Added notifyClick and notifyChange to the BaseComponent.
  • Loading branch information
Dan Ziv committed Apr 11, 2018
1 parent 3d456e8 commit 8471296
Show file tree
Hide file tree
Showing 35 changed files with 878 additions and 85 deletions.
92 changes: 86 additions & 6 deletions dist/playkit-ui.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/playkit-ui.js.map

Large diffs are not rendered by default.

36 changes: 21 additions & 15 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,53 @@ var uiManager = new playkit.ui.UIManager(player, config);
```js
{
targetId: string,
debugActions: boolean, // optional
forceTouchUI: boolean, // optional
logLevel: string, // optional
components: Object // optional
}
```
##
##
>### config.targetId
>##### Type: `string`
>##### Default: `-`
>##### Description: Defines the player container dom element id.
The UI manager needs this parameter since it renders the player UI below it.
The UI manager needs this parameter since it renders the player UI below it.
##
>### config.debugActions
>##### Type: `boolean`
>##### Default: `false`
>##### Description: Whether to print the fired redux actions.
##
>### config.forceTouchUI
>##### Type: `boolean`
>##### Default: `false`
>##### Description: Defines the view type of the UI (mobile or desktop).
Useful for applications that wants to force mobile view of player UI.
##
##
>### config.logLevel
>##### Type: `string`
>##### Default: `"ERROR"`
>##### Description: Defines the ui log level.
>Possible values: `"DEBUG", "INFO", "TIME", "WARN", "ERROR", "OFF"`
##
##
>### config.components
>##### Type: `Object`
>##### Default: `-`
>##### Description: Defines the ui components configuration.
>Optional components to configure: `watermark`,`seekbar`
##
##
>>### config.components.watermark
>>##### Type: `Object`
>>```js
>>{
>> img: string,
>> url: string,
>> placement: string,
>> url: string,
>> placement: string,
>> timeout: number
>>}
>>```
>>##### Default:
>>##### Default:
>>```js
>>{
>> img: '',
Expand All @@ -65,18 +71,18 @@ Useful for applications that wants to force mobile view of player UI.
>>>##### Type: `string`
>>>##### Default: `''`
>>>##### Description: The URL for the watermark image.
>>>##
>>>##
>>>### config.components.watermark.url
>>>##### Type: `string`
>>>##### Default: `''`
>>>##### Description: The URL to open on clicking the watermark.
>>>##
>>>##
>>>### config.components.watermark.placement
>>>##### Type: `string`
>>>##### Default: `'top-left'`
>>>##### Description: The placement of the watermark.
>>>Possible values: `'top-left', 'top-right', 'bottom-left', 'bottom-right'`
>>>##
>>>##
>>>### config.components.watermark.timeout
>>>##### Type: `number`
>>>##### Default: `0`
Expand All @@ -86,8 +92,8 @@ Useful for applications that wants to force mobile view of player UI.
>>##### Type: `Object`
>>```js
>>{
>> thumbsSprite: string,
>> thumbsWidth: number,
>> thumbsSprite: string,
>> thumbsWidth: number,
>> thumbsSlices: number
>>}
>>```
Expand All @@ -96,12 +102,12 @@ Useful for applications that wants to force mobile view of player UI.
>>>##### Type: `string`
>>>##### Default: `-`
>>>##### Description: The URL for the preview thumbnail image.
>>>##
>>>##
>>>### config.components.seekbar.thumbsWidth
>>>##### Type: `number`
>>>##### Default: `-`
>>>##### Description: The width of each preview thumbnail slice.
>>>##
>>>##
>>>### config.components.watermark.thumbsSlices
>>>##### Type: `number`
>>>##### Default: `-`
Expand Down
111 changes: 111 additions & 0 deletions docs/events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@

# UI Events

| Events List |
|--|
| [`UI_CLICKED`](#UI_CLICKED) |
| [`UI_ACTIVE_STATE_CHANGED`](#UI_ACTIVE_STATE_CHANGED) |
| [`USER_CLICKED_PLAY`](#USER_CLICKED_PLAY) |
| [`USER_CLICKED_PAUSE`](#USER_CLICKED_PAUSE) |
| [`USER_CLICKED_REWIND`](#USER_CLICKED_REWIND) |
| [`USER_CLICKED_MUTE`](#USER_CLICKED_MUTE) |
| [`USER_CLICKED_UNMUTE`](#USER_CLICKED_UNMUTE) |
| [`USER_CHANGED_VOLUME`](#USER_CHANGED_VOLUME) |
| [`USER_SELECTED_CAPTION_TRACK`](#USER_SELECTED_CAPTION_TRACK) |
| [`USER_SELECTED_AUDIO_TRACK`](#USER_SELECTED_AUDIO_TRACK) |
| [`USER_SELECTED_QUALITY_TRACK`](#USER_SELECTED_QUALITY_TRACK) |
| [`USER_ENTERED_FULL_SCREEN`](#USER_ENTERED_FULL_SCREEN) |
| [`USER_EXITED_FULL_SCREEN`](#USER_EXITED_FULL_SCREEN) |
| [`USER_SELECTED_CAPTIONS_STYLE`](#USER_SELECTED_CAPTIONS_STYLE) |
| [`USER_SELECTED_SPEED`](#USER_SELECTED_SPEED) |
| [`USER_SEEKED`](#USER_SEEKED) |

## Events
> ### <a name="UI_CLICKED"></a>UI_CLICKED
> Fires on any user interaction with the UI.
#
> ### <a name="UI_ACTIVE_STATE_CHANGED"></a>UI_ACTIVE_STATE_CHANGED
> Fires when the UI changes his active state, i.e, changes from visible to hidden or from hidden to visible.
> <br><br>_payload parameters:_
>
> | Name | Type | Description
> |--|--|--|
> | `isActive` | `boolean`| True when the UI is shown, false when the UI is hidden
#
> ### <a name="USER_CLICKED_PLAY"></a>USER_CLICKED_PLAY
> Fires when the user initiated play by the UI.<br>
> It will fires neither by clicking the play button or by clicking the video area.
#
> ### <a name="USER_CLICKED_PAUSE"></a>USER_CLICKED_PAUSE
> Fires when the user initiated pause by the UI.<br>
> It will fires neither by clicking the pause button or by clicking the video area.
#
> ### <a name="USER_CLICKED_REWIND"></a>USER_CLICKED_REWIND
> Fires when the rewind button has been clicked by the user.<br>
#
> ### <a name="USER_CLICKED_MUTE"></a>USER_CLICKED_MUTE
> Fires when the user clicked the volume button and changed his state to mute.
#
> ### <a name="USER_CLICKED_UNMUTE"></a>USER_CLICKED_UNMUTE
> Fires when the user clicked the volume button and changed his state to unmute.
#
> ### <a name="USER_CHANGED_VOLUME"></a>USER_CHANGED_VOLUME
> Fires when the user dragged the volume bar and changed its value.
#
> ### <a name="USER_SELECTED_CAPTION_TRACK"></a>USER_SELECTED_CAPTION_TRACK
> Fires when the user selected a caption from the Captions dropdown.
> <br><br>_payload parameters:_
>
> | Name | Type | Description
> |--|--|--|
> | `captionTrack` | `Object` | The selected caption track
#
> ### <a name="USER_SELECTED_AUDIO_TRACK"></a>USER_SELECTED_AUDIO_TRACK
> Fires when the user selected an audio track from the Audio dropdown.
> <br><br>_payload parameters:_
>
> | Name | Type | Description
> |--|--|--|
> | `audioTrack` | `Object` | The selected audio track
#
> ### <a name="USER_SELECTED_QUALITY_TRACK"></a>USER_SELECTED_QUALITY_TRACK
> Fires when the user selected quality from the Quality dropdown.
> <br><br>_payload parameters:_
>
> | Name | Type | Description
> |--|--|--|
> | `qualityTrack` | `Object` | The selected quality track
#
> ### <a name="USER_ENTERED_FULL_SCREEN"></a>USER_ENTERED_FULL_SCREEN
> Fires when the UI is entered to full screen mode due to user gesture.<br>
> This can be done neither by clicking the full screen button or by double clicking the video area.
#
> ### <a name="USER_EXITED_FULL_SCREEN"></a>USER_EXITED_FULL_SCREEN
> Fires when the UI is exited from full screen mode due to user gesture.<br>
> This can be done neither by clicking the full screen button or by double clicking the video area.
#
> ### <a name="USER_SELECTED_CAPTIONS_STYLE"></a>USER_SELECTED_CAPTIONS_STYLE
> Fires when the user selected a captions style from the Advanced Captions Settings menu.
> <br><br>_payload parameters:_
>
> | Name | Type | Description
> |--|--|--|
> | `captionsStyle` | `Object` | The selected captions style
#
> ### <a name="USER_SELECTED_SPEED"></a>USER_SELECTED_SPEED
> Fires when the user selected a certain speed from the Speed dropdown.
> <br><br>_payload parameters:_
>
> | Name | Type | Description
> |--|--|--|
> | `speed` | `number` | The selected speed
#
> ### <a name="USER_SEEKED"></a>USER_SEEKED
> Fires when the user initiated seek by dragging the seek bar.
> <br><br>_payload parameters:_
>
> | Name | Type | Description
> |--|--|--|
> | `from` | `number` | The playback time before the seek
> | `to` | `number` | The playback time after the seek
#
1 change: 1 addition & 0 deletions docs/guides.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
* [Create New Component](./create-new-component.md)
* [Customizing the Player CSS](./css-classes-override.md)
* [Custom UI Preset](./custom-ui-preset.md)
* [UI Events](./events.md)
1 change: 1 addition & 0 deletions flow-typed/types/ui-options.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow
declare type UIOptionsObject = {
targetId: string,
debugActions: boolean,
forceTouchUI?: boolean,
logLevel?: string,
components?: ComponentsConfig
Expand Down
31 changes: 31 additions & 0 deletions src/components/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import {Component} from 'preact';
import Player from 'playkit-js';
import getLogger from '../utils/logger';
import {types} from '../middlewares/event-dispatcher';

/**
* Base component to be extended by other player UI components
Expand Down Expand Up @@ -29,6 +30,36 @@ class BaseComponent extends Component {
this.logger = getLogger(`UI ${this.name}`);
this.logger.debug(`Initialized`);
}

/**
* Notify the store that a clickable component has been clicked.
* @param {any} payload - Optional payload.
* @returns {void}
*
* @memberof BaseComponent
*/
notifyClick(payload?: any): void {
this.context.store.dispatch({
type: types.COMPONENT_CLICKED,
name: this.name,
payload: payload
});
}

/**
* Notify the store that a changeable component has been change.
* @param {any} payload - Optional payload.
* @returns {void}
*
* @memberof BaseComponent
*/
notifyChange(payload?: any): void {
this.context.store.dispatch({
type: types.COMPONENT_CHANGED,
name: this.name,
payload: payload
});
}
}

export default BaseComponent;
Expand Down
3 changes: 3 additions & 0 deletions src/components/cvaa-overlay/cvaa-overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ class CVAAOverlay extends BaseComponent {
this.props.updateCaptionsStyle(textStyle);
this.props.player.textStyle = textStyle;
this.props.onClose();
this.notifyClick({
textStyle: textStyle
});
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/components/fullscreen/fullscreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ class FullscreenControl extends BaseComponent {
toggleFullscreen(): void {
this.logger.debug(`Toggle fullscreen`);
this.props.fullscreen ? this.exitFullscreen() : this.enterFullscreen();
this.notifyClick();
}

/**
Expand Down
8 changes: 8 additions & 0 deletions src/components/language/language.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ class LanguageControl extends BaseComponent {
*/
onAudioChange(audioTrack: Object): void {
this.player.selectTrack(audioTrack);
this.notifyClick({
type: this.player.Track.AUDIO,
track: audioTrack
});
}

/**
Expand All @@ -129,6 +133,10 @@ class LanguageControl extends BaseComponent {
*/
onCaptionsChange(textTrack: Object): void {
this.player.selectTrack(textTrack);
this.notifyClick({
type: this.player.Track.TEXT,
track: textTrack
});
}

/**
Expand Down
17 changes: 10 additions & 7 deletions src/components/overlay-action/overlay-action.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ class OverlayAction extends BaseComponent {
this.player.play();
this.props.updateOverlayActionIcon(IconType.Play);
}
this.notifyClick({
type: 'PlayPause'
});
}

/**
Expand All @@ -101,11 +104,13 @@ class OverlayAction extends BaseComponent {
if (!this.player.isFullscreen()) {
this.logger.debug("Enter fullscreen");
this.player.enterFullscreen();

} else {
this.logger.debug("Exit fullscreen");
this.player.exitFullscreen();
}
this.notifyClick({
type: 'Fullscreen'
});
}

/**
Expand All @@ -119,23 +124,21 @@ class OverlayAction extends BaseComponent {
return;
}

let currentTime = Date.now();

if (currentTime - this._firstClickTime < PLAY_PAUSE_BUFFER_TIME) {
const now = Date.now();
if (now - this._firstClickTime < PLAY_PAUSE_BUFFER_TIME) {
this.cancelClickTimeout();
this.toggleFullscreen();
return;
}
if (currentTime - this._firstClickTime < DOUBLE_CLICK_MAX_BUFFER_TIME) {
if (now - this._firstClickTime < DOUBLE_CLICK_MAX_BUFFER_TIME) {
this.cancelClickTimeout();
this.togglePlayPause();
this.toggleFullscreen();
this._firstClickTime = 0;
return;
}

this._firstClickTime = currentTime;

this._firstClickTime = now;
this._clickTimeout = setTimeout(() => {
this._clickTimeout = null;
this.togglePlayPause();
Expand Down
5 changes: 2 additions & 3 deletions src/components/play-pause/play-pause.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import style from '../../styles/style.scss';
import {h} from 'preact';
import {Localizer, Text} from 'preact-i18n';
import {connect} from 'preact-redux';
import {bindActions} from '../../utils/bind-actions';
import {actions} from '../../reducers/play-pause';
import BaseComponent from '../base';
import {default as Icon, IconType} from '../icon';
import {KeyMap} from "../../utils/key-map";
Expand All @@ -21,7 +19,7 @@ const mapStateToProps = state => ({
isEnded: state.engine.isEnded
});

@connect(mapStateToProps, bindActions(actions))
@connect(mapStateToProps)
/**
* PlayPauseControl component
*
Expand Down Expand Up @@ -49,6 +47,7 @@ class PlayPauseControl extends BaseComponent {
togglePlayPause(): void {
this.logger.debug('Toggle play');
this.isPlayingAdOrPlayback() ? this.player.pause() : this.player.play();
this.notifyClick();
}

/**
Expand Down

0 comments on commit 8471296

Please sign in to comment.