Skip to content

Commit

Permalink
feat: keyboard shortcuts ui gestures (#149)
Browse files Browse the repository at this point in the history
Refactor the overlay-play component and rename it to overlay-action which can display overlay action gesture of any kind of icon.
Added store for the overlay-action component. Using this store the keyboard component (or any other component) can call updateOverlayActionIcon(...) and supply an icon/s. The overlay-action component will know to display the correct icon based on the updated iconType prop.
Fix the overlay animation to look like in Hillel's demo.
  • Loading branch information
Dan Ziv authored Jan 10, 2018
1 parent 8ab4980 commit 9e922db
Show file tree
Hide file tree
Showing 23 changed files with 421 additions and 16,136 deletions.
15,975 changes: 5 additions & 15,970 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.

1 change: 0 additions & 1 deletion src/components/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ class BaseComponent extends Component {
*/
constructor(obj?: Object = {config: {}}) {
super();

this.name = obj.name;
this.player = obj.player;
this.config = obj.config;
Expand Down
20 changes: 20 additions & 0 deletions src/components/icon/icon.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const IconType = {
Pause: 'pause',
VolumeBase: 'volume-base',
VolumeWaves: 'volume-waves',
VolumeWave: 'volume-wave',
VolumeMute: 'volume-mute',
Close: 'close',
Share: 'share',
Expand All @@ -18,6 +19,8 @@ const IconType = {
Quality: 'quality',
Captions: 'captions',
Speed: 'speed',
SpeedDown: 'speed-down',
SpeedUp: 'speed-up',
Audio: 'audio',
Copy: 'copy',
Facebook: 'facebook',
Expand All @@ -29,6 +32,8 @@ const IconType = {
Link: 'link',
ArrowDown: 'arrow-down',
StartOver: 'start-over',
SeekForward: 'seek-forward',
SeekEnd: 'seek-end',
Rewind: 'rewind',
Rewind10: 'rewind10'
};
Expand Down Expand Up @@ -68,6 +73,9 @@ class Icon extends Component {
case IconType.VolumeWaves:
return (<i className={[style.icon, style.iconVolumeWaves].join(' ')}/>);

case IconType.VolumeWave:
return (<i className={[style.icon, style.iconVolumeWave].join(' ')}/>);

case IconType.VolumeMute:
return (<i className={[style.icon, style.iconVolumeMute].join(' ')}/>);

Expand Down Expand Up @@ -95,6 +103,12 @@ class Icon extends Component {
case IconType.Speed:
return (<i className={[style.icon, style.iconSpeed].join(' ')}/>);

case IconType.SpeedDown:
return (<i className={[style.icon, style.iconSpeedDown].join(' ')}/>);

case IconType.SpeedUp:
return (<i className={[style.icon, style.iconSpeedUp].join(' ')}/>);

case IconType.Audio:
return (<i className={[style.icon, style.iconAudio].join(' ')}/>);

Expand Down Expand Up @@ -128,6 +142,12 @@ class Icon extends Component {
case IconType.StartOver:
return (<i className={[style.icon, style.iconStartOver].join(' ')}/>);

case IconType.SeekForward:
return (<i className={[style.icon, style.iconSeekForward].join(' ')}/>);

case IconType.SeekEnd:
return (<i className={[style.icon, style.iconSeekEnd].join(' ')}/>);

case IconType.Rewind:
return (<i className={[style.icon, style.iconRewind].join(' ')}/>);

Expand Down
25 changes: 25 additions & 0 deletions src/components/icon/icon.scss

Large diffs are not rendered by default.

86 changes: 71 additions & 15 deletions src/components/keyboard/keyboard.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
//@flow
import BaseComponent from '../base';
import {connect} from 'preact-redux';
import {actions} from '../../reducers/shell';
import {actions as shellActions} from '../../reducers/shell';
import {actions as overlayIconActions} from '../../reducers/overlay-action';
import {bindActions} from '../../utils/bind-actions';
import {KeyMap, getKeyName} from "../../utils/key-map";
import {IconType} from '../icon';
import {CONTROL_BAR_HOVER_DEFAULT_TIMEOUT} from "../shell/shell";

/**
* mapping state to props
Expand All @@ -14,10 +17,20 @@ const mapStateToProps = state => ({
playerNav: state.shell.playerNav
});

const SEEK_JUMP: number = 5;
const VOLUME_JUMP: number = 5;
/**
* Default seek jump
* @type {number}
* @const
*/
export const KEYBOARD_DEFAULT_SEEK_JUMP: number = 5;
/**
* Default volume jump
* @type {number}
* @const
*/
export const KEYBOARD_DEFAULT_VOLUME_JUMP: number = 5;

@connect(mapStateToProps, bindActions(actions))
@connect(mapStateToProps, bindActions(Object.assign(shellActions, overlayIconActions)))
/**
* KeyboardControl component
*
Expand All @@ -26,9 +39,11 @@ const VOLUME_JUMP: number = 5;
*/
class KeyboardControl extends BaseComponent {
_activeTextTrack: ?Object = null;
_hoverTimeout: ?number = null;

/**
* Creates an instance of KeyboardControl.
* creates an instance of KeyboardControl
*
* @param {Object} obj obj
* @memberof KeyboardControl
*/
Expand All @@ -47,30 +62,40 @@ class KeyboardControl extends BaseComponent {
}

/**
* Handlers for keyboard commands
* @type { Object } - Maps key number to his handler
* handlers for keyboard commands
* @type {Object} - maps key number to his handler
*
* @memberof KeyboardControl
*/
keyboardHandlers: { [key: number]: Function } = {
[KeyMap.SPACE]: () => {
this.player.paused ? this.player.play() : this.player.pause();
if (this.player.paused) {
this.player.play();
this.props.updateOverlayActionIcon(IconType.Play);
} else {
this.player.pause();
this.props.updateOverlayActionIcon(IconType.Pause);
}
},
[KeyMap.UP]: () => {
const newVolume = Math.round(this.player.volume * 100) + VOLUME_JUMP;
const newVolume = (Math.round(this.player.volume * 100) + KEYBOARD_DEFAULT_VOLUME_JUMP) / 100;
this.logger.debug(`Changing volume. ${this.player.volume} => ${newVolume}`);
if (this.player.muted) {
this.player.muted = false;
}
this.player.volume = newVolume / 100;
this.player.volume = newVolume;
this.props.updateOverlayActionIcon([IconType.VolumeBase, IconType.VolumeWaves]);
},
[KeyMap.DOWN]: () => {
const newVolume = Math.round(this.player.volume * 100) - VOLUME_JUMP;
if (newVolume < 5) {
const newVolume = (Math.round(this.player.volume * 100) - KEYBOARD_DEFAULT_VOLUME_JUMP) / 100;
if (newVolume === 0) {
this.player.muted = true;
this.props.updateOverlayActionIcon([IconType.VolumeBase, IconType.VolumeMute]);
return;
}
this.logger.debug(`Changing volume. ${this.player.volume} => ${newVolume}`);
this.player.volume = newVolume / 100;
this.player.volume = newVolume;
this.props.updateOverlayActionIcon([IconType.VolumeBase, IconType.VolumeWave]);
},
[KeyMap.F]: () => {
if (!this.player.isFullscreen()) {
Expand All @@ -85,31 +110,43 @@ class KeyboardControl extends BaseComponent {
}
},
[KeyMap.LEFT]: () => {
const newTime = this.player.currentTime - SEEK_JUMP;
const newTime = this.player.currentTime - KEYBOARD_DEFAULT_SEEK_JUMP;
this.logger.debug(`Seek. ${this.player.currentTime} => ${(newTime > 0) ? newTime : 0}`);
this.player.currentTime = (newTime > 0) ? newTime : 0;
this.props.updateOverlayActionIcon(IconType.Rewind);
this.toggleHoverState();
},
[KeyMap.RIGHT]: () => {
const newTime = this.player.currentTime + SEEK_JUMP;
const newTime = this.player.currentTime + KEYBOARD_DEFAULT_SEEK_JUMP;
this.logger.debug(`Seek. ${this.player.currentTime} => ${(newTime > this.player.duration) ? this.player.duration : newTime}`);
this.player.currentTime = (newTime > this.player.duration) ? this.player.duration : newTime;
this.props.updateOverlayActionIcon(IconType.SeekForward);
this.toggleHoverState();
},
[KeyMap.HOME]: () => {
this.logger.debug(`Seek. ${this.player.currentTime} => 0`);
this.player.currentTime = 0;
this.props.updateOverlayActionIcon(IconType.StartOver);
this.toggleHoverState();
},
[KeyMap.END]: () => {
this.logger.debug(`Seek. ${this.player.currentTime} => ${this.player.duration}`);
this.player.currentTime = this.player.duration;
this.props.updateOverlayActionIcon(IconType.SeekEnd);
this.toggleHoverState();
},
[KeyMap.M]: () => {
this.logger.debug(this.player.muted ? "Umnute" : "Mute");
this.player.muted = !this.player.muted;
this.player.muted ?
this.props.updateOverlayActionIcon([IconType.VolumeBase, IconType.VolumeMute]) :
this.props.updateOverlayActionIcon([IconType.VolumeBase, IconType.VolumeWaves]);
},
[KeyMap.SEMI_COLON]: (shiftKey: boolean) => {
if (shiftKey) {
this.logger.debug(`Changing playback rate. ${this.player.playbackRate} => ${this.player.defaultPlaybackRate}`);
this.player.playbackRate = this.player.defaultPlaybackRate;
this.props.updateOverlayActionIcon(IconType.Speed);
}
},
[KeyMap.PERIOD]: (shiftKey: boolean) => {
Expand All @@ -120,6 +157,7 @@ class KeyboardControl extends BaseComponent {
this.logger.debug(`Changing playback rate. ${playbackRate} => ${this.player.playbackRates[index + 1]}`);
this.player.playbackRate = this.player.playbackRates[index + 1];
}
this.props.updateOverlayActionIcon(IconType.SpeedUp);
}
},
[KeyMap.COMMA]: (shiftKey: boolean) => {
Expand All @@ -131,6 +169,7 @@ class KeyboardControl extends BaseComponent {
this.player.playbackRate = this.player.playbackRates[index - 1];
}
}
this.props.updateOverlayActionIcon(IconType.SpeedDown);
},
[KeyMap.C]: () => {
let activeTextTrack = this.player.getActiveTracks().text;
Expand All @@ -145,6 +184,23 @@ class KeyboardControl extends BaseComponent {
}
}
};

/**
* toggles the shell hover state
*
* @returns {void}
* @memberof KeyboardControl
*/
toggleHoverState(): void {
if (this._hoverTimeout !== null) {
clearTimeout(this._hoverTimeout);
this._hoverTimeout = null;
}
this.props.updatePlayerHoverState(true);
this._hoverTimeout = setTimeout(() => {
this.props.updatePlayerHoverState(false);
}, CONTROL_BAR_HOVER_DEFAULT_TIMEOUT);
}
}

export default KeyboardControl;
2 changes: 1 addition & 1 deletion src/components/language/language.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class LanguageControl extends BaseComponent {
this.state.smartContainerOpen &&
!this.state.cvaaOverlay
) {
if (e.target.classList.contains('overlay-play')) {
if (e.target.classList.contains('overlay-action')) {
e.stopPropagation();
}
this.setState({smartContainerOpen: false});
Expand Down
88 changes: 88 additions & 0 deletions src/components/overlay-action/_overlay-action.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
@keyframes overlayActionIconIn {
0% {
opacity: 0;
transform: scale(0);
}
10% {
opacity: 0.1;
transform: scale(0.1);
}
20% {
opacity: 0.3;
transform: scale(0.2);
}
30% {
opacity: 0.5;
transform: scale(0.3);
}
40% {
opacity: 0.7;
transform: scale(0.4);
}
50% {
opacity: 0.9;
transform: scale(0.5);
}
60% {
opacity: 0.9;
transform: scale(0.5);
}
70% {
opacity: 0.9;
transform: scale(0.5);
}
75% {
opacity: 0.9;
transform: scale(0.5);
}
80% {
opacity: 1;
transform: scale(0.5);
}
85% {
opacity: 1;
transform: scale(0.5);
}
90% {
opacity: 1;
transform: scale(0.5);
}
93% {
opacity: 0.7;
transform: scale(0.5);
}
95% {
opacity: 0.5;
transform: scale(0.5);
}
98% {
opacity: 0.2;
transform: scale(0.5);
}
100% {
opacity: 0.0;
transform: scale(0.5);
}
}

.overlay-action {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;

&.in .icon {
animation: overlayActionIconIn 300ms linear forwards;
}

.icon {
width: 144px;
height: 144px;
position: absolute;
top: 50%;
left: 50%;
margin: -72px 0 0 -72px;
opacity: 0;
}
}
1 change: 1 addition & 0 deletions src/components/overlay-action/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default from './overlay-action';
Loading

0 comments on commit 9e922db

Please sign in to comment.