Skip to content

Commit

Permalink
feat(FEC-10311): timeline scrubber design update (#557)
Browse files Browse the repository at this point in the history
1. Increase the seekbar height on hovering (exclude touch device and tiny player)
2. Redesign the virtual progress indicator 
3. Hide the seekbar preview in tiny player

Solves FEC-10311
  • Loading branch information
yairans committed Dec 10, 2020
1 parent 50f19ca commit dcad062
Show file tree
Hide file tree
Showing 23 changed files with 474 additions and 156 deletions.
2 changes: 1 addition & 1 deletion src/components/gui-area/_gui-area.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.gui-area {
pointer-events: none;
transition: all $default-transition-time;
transition: all #{$default-transition-time}ms;
transition-property: left, right, bottom, top;
display: flex;
flex-flow: column nowrap;
Expand Down
2 changes: 1 addition & 1 deletion src/components/interactive-area/_interactive-area.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
height: 100%;
position: relative;
top: 0;
transition: top $default-transition-time, height $default-transition-time;
transition: top #{$default-transition-time}ms, height #{$default-transition-time}ms;
}
1 change: 1 addition & 0 deletions src/components/managers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {Managers} from './managers';
75 changes: 75 additions & 0 deletions src/components/managers/managers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//@flow
import {UIManager} from '../../ui-manager';
import getLogger from '../../utils/logger';
import {EventManager} from 'event/event-manager';

/**
* @class Managers
*/
class Managers {
static _logger: any;
_managerRegistry: Map<string, Object> = new Map();
_eventManager: EventManager;

/**
* @constructor
* @param {UIManager} uiManager - The UI manager.
* @param {any} store - The store.
* @param {any} player - The player.
*/
constructor(uiManager: UIManager, store: any, player: any) {
Managers._logger = getLogger('Managers');
this._eventManager = new EventManager();
this._eventManager.listen(player, player.Event.Core.PLAYER_RESET, () => this.reset());
}

/**
* @param {string} name - the manager name
* @param {Object} manager - the manager object
* @returns {void}
*/
register(name: string, manager: Object): void {
if (this._managerRegistry.has(name)) {
Managers._logger.debug(`${name} manager already exists`);
} else {
this._managerRegistry.set(name, manager);
Managers._logger.debug(`${name} manager registered`);
}
}

/**
*
* @param {string} name - the manager name
* @returns {Object} - the manager object
*/
get(name: string): Object | void {
return this._managerRegistry.get(name);
}

/**
*
* @param {string} name - the manager name
* @returns {boolean} - if the manager exist
*/
has(name: string): boolean {
return this._managerRegistry.has(name);
}

/**
* @returns {void}
*/
reset() {
this._managerRegistry.forEach(manager => typeof manager.reset === 'function' && manager.reset());
}

/**
* @returns {void}
*/
destroy() {
this._managerRegistry.forEach(manager => typeof manager.destroy === 'function' && manager.destroy());
this._eventManager.removeAll();
this._managerRegistry.clear();
}
}

export {Managers};
2 changes: 1 addition & 1 deletion src/components/overlay-action/_overlay-action.scss
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
}
}

.player:not(.touch, .size-sm) {
.player:not(.touch):not(.size-sm) {
.overlay-action.in .icon {
animation: overlayActionIconIn 300ms linear forwards;
}
Expand Down
14 changes: 11 additions & 3 deletions src/components/player-area/player-area.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,11 @@ class PlayerArea extends Component {
* @memberof OverlayAction
*/
shouldComponentUpdate(nextProps: Object, nextState: Object): boolean {
return this.state.playerAreaComponents !== nextState.playerAreaComponents || nextProps.activePresetName !== this.props.activePresetName;
return (
nextProps.shouldUpdate ||
this.state.playerAreaComponents !== nextState.playerAreaComponents ||
nextProps.activePresetName !== this.props.activePresetName
);
}

/**
Expand Down Expand Up @@ -234,6 +238,11 @@ class PlayerArea extends Component {
}
const {replace, before, after} = positionedComponent;
if (replace) {
if (typeof replace.get !== 'string') {
// pass the replaced component props to the override one (if it's not an html element e.g. "div")
replace.props = replace.props || {};
replace.props.replacedComponentProps = child.props;
}
newChildren.push(this._renderUIComponent(replace));
return;
}
Expand All @@ -259,9 +268,8 @@ class PlayerArea extends Component {
* @memberof PlayerArea
*/
render(): React$Element<any> | null {
const {show, name} = this.props;
const {show} = this.props;
const {playerAreaComponents, hasPositionedComponents, presetComponentsOnlyMode} = this.state;
this.props.logger.debug(`Player area '${name}' - render`);

if (presetComponentsOnlyMode) {
return this.renderContent(this._actualChildren);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {withEventDispatcher} from 'components/event-dispatcher';
*/
const mapStateToProps = state => ({
currentTime: state.seekbar.currentTime,
virtualTime: state.seekbar.virtualTime,
duration: state.engine.duration,
isDraggingActive: state.seekbar.draggingActive,
isMobile: state.shell.isMobile,
Expand Down Expand Up @@ -77,9 +78,12 @@ class SeekBarLivePlaybackContainer extends Component {
playerPoster={this.props.poster}
updateSeekbarDraggingStatus={data => this.props.updateSeekbarDraggingStatus(data)}
updateSeekbarHoverActive={data => this.props.updateSeekbarHoverActive(data)}
updateSeekbarClientRect={data => this.props.updateSeekbarClientRect(data)}
updateCurrentTime={data => this.props.updateCurrentTime(data)}
updateVirtualTime={data => this.props.updateVirtualTime(data)}
isDvr={this.props.isDvr}
currentTime={this.props.currentTime}
virtualTime={this.props.virtualTime}
duration={this.duration}
isDraggingActive={this.props.isDraggingActive}
isMobile={this.props.isMobile}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {withEventDispatcher} from 'components/event-dispatcher';
*/
const mapStateToProps = state => ({
currentTime: state.seekbar.currentTime,
virtualTime: state.seekbar.virtualTime,
duration: state.engine.duration,
isDraggingActive: state.seekbar.draggingActive,
isMobile: state.shell.isMobile,
Expand Down Expand Up @@ -68,8 +69,11 @@ class SeekBarPlaybackContainer extends Component {
playerPoster={this.props.poster}
updateSeekbarDraggingStatus={data => this.props.updateSeekbarDraggingStatus(data)}
updateSeekbarHoverActive={data => this.props.updateSeekbarHoverActive(data)}
updateSeekbarClientRect={data => this.props.updateSeekbarClientRect(data)}
updateCurrentTime={data => this.props.updateCurrentTime(data)}
updateVirtualTime={data => this.props.updateVirtualTime(data)}
currentTime={this.props.currentTime}
virtualTime={this.props.virtualTime}
duration={this.props.duration}
isDraggingActive={this.props.isDraggingActive}
isMobile={this.props.isMobile}
Expand Down
1 change: 1 addition & 0 deletions src/components/seekbar-preview/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {SeekBarPreview} from './seekbar-preview';
60 changes: 60 additions & 0 deletions src/components/seekbar-preview/seekbar-preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//@flow
import style from '../../styles/style.scss';
import {h, Component} from 'preact';
import {connect} from 'react-redux';

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

/**
* SeekBarPreview component
*
* @class SeekBarPreview
* @extends {Component}
*/
@connect(mapStateToProps)
class SeekBarPreview extends Component {
/**
* utility function to get the thumb sprite background position
* @returns {string} background-position string value
*/
getThumbSpriteOffset(): string {
const percent = this.props.virtualTime / this.props.duration;
const sliceIndex = Math.ceil(this.props.thumbsSlices * percent);
return -(sliceIndex * this.props.thumbsWidth) + 'px 0px';
}

/**
* Gets the style of the frame preview image.
* @returns {string} - The css style string.
* @private
*/
_getFramePreviewImgStyle(): string {
let framePreviewImgStyle = `background-image: url(${this.props.thumbsSprite});`;
framePreviewImgStyle += `background-position: ${this.getThumbSpriteOffset()};`;
framePreviewImgStyle += `background-size: ${this.props.thumbsSlices * this.props.thumbsWidth}px 100%;`;
return framePreviewImgStyle;
}

/**
* render component
* @returns {React$Element} - component element
*/
render() {
if (!this.props.thumbsSprite || !this.props.thumbsSlices || !this.props.thumbsWidth) return undefined;
return (
<div className={[style.framePreviewImgContainer, style.nonSticky].join(' ')}>
<div className={style.framePreviewImg} style={this._getFramePreviewImgStyle()} />
</div>
);
}
}

SeekBarPreview.displayName = 'SeekBarPreview';
export {SeekBarPreview};
17 changes: 17 additions & 0 deletions src/components/seekbar-preview/seekbar-preview.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@import '~styles/variables';

.frame-preview {
.frame-preview-img-container {
height: $frame-preview-img-height + 4px;
width: $frame-preview-img-width + 4px;
border: 2px solid rgba(255, 255, 255, 0.2);
border-radius: 4px;

.frame-preview-img {
background-size: auto 100%;
width: 100%;
height: 100%;
position: relative;
}
}
}

0 comments on commit dcad062

Please sign in to comment.