Skip to content

Commit

Permalink
Fix: Media controls and usability fixes for mobile (#217)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeremy Press authored Jul 17, 2017
1 parent eae3c74 commit 38ecce7
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 60 deletions.
13 changes: 7 additions & 6 deletions src/lib/viewers/box3d/video360/Video360.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
display: flex;
}

.bp-video-360 canvas {
cursor: move; /* fallback if grab cursor is unsupported */
cursor: grab;
}

.bp-is-mobile {
.bp-is-mobile .bp-video-360 .bp-media-container {
.bp-media-controls-wrapper {
/* stylelint-disable declaration-no-important */
opacity: 1 !important;
visibility: visible !important;
/* stylelint-enable declaration-no-important */
}
}

.bp-video-360 canvas {
cursor: move; /* fallback if grab cursor is unsupported */
cursor: grab;
}
1 change: 1 addition & 0 deletions src/lib/viewers/media/DashViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ const MANIFEST = 'manifest.mpd';

// Make media element visible after resize
this.showMedia();
this.mediaControls.show();
this.mediaContainerEl.focus();
}

Expand Down
43 changes: 42 additions & 1 deletion src/lib/viewers/media/MediaControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { activationHandler, addActivationListener, removeActivationListener, ins
const SHOW_CONTROLS_CLASS = 'bp-media-controls-is-visible';
const PLAYING_CLASS = 'bp-media-is-playing';
const VOLUME_SCRUBBER_EXPAND_CLASS = 'bp-media-controls-volume-scrubber-expand';
const CONTROLS_AUTO_HIDE_TIMEOUT_IN_MILLIS = 1500;
const CONTROLS_AUTO_HIDE_TIMEOUT_IN_MILLIS = 2000;
const VOLUME_LEVEL_CLASS_NAMES = [
'bp-media-volume-icon-is-mute',
'bp-media-volume-icon-is-low',
Expand Down Expand Up @@ -613,6 +613,31 @@ const FILMSTRIP_FRAME_HEIGHT = 90;
}
}

/**
* Toggles the media controls
*
* @return {void}
*/
toggle() {
if (this.isVisible()) {
// Clear all controls hiding blockers to allow hiding
this.preventHiding = false;
this.settings.hide();
this.hide();
} else {
this.show();
}
}

/**
* Determines if media controls are shown
*
* @return {boolean} If the controls are visible
*/
isVisible() {
return this.wrapperEl.parentNode.classList.contains(SHOW_CONTROLS_CLASS);
}

/**
* Resizes the time scrubber
*
Expand Down Expand Up @@ -669,6 +694,11 @@ const FILMSTRIP_FRAME_HEIGHT = 90;
// aspect ratio as the original video.

this.timeScrubber.getHandleEl().addEventListener('mousedown', this.timeScrubbingStartHandler);

if (this.hasTouch) {
this.timeScrubberEl.addEventListener('touchstart', this.timeScrubbingStartHandler);
}

this.timeScrubber.getConvertedEl().addEventListener('mousemove', this.filmstripShowHandler);
this.timeScrubber.getConvertedEl().addEventListener('mouseleave', this.filmstripHideHandler);

Expand All @@ -692,16 +722,23 @@ const FILMSTRIP_FRAME_HEIGHT = 90;
timeScrubbingStartHandler() {
// Flag that we are scrubbing
this.isScrubbing = true;
this.preventHiding = true;

// Add event listener for the entire document that when mouse up happens
// anywhere, consider scrubbing has stopped. This is added on the document
// itself so that the user doesn't have to scrub in a straight line.
document.addEventListener('mouseup', this.timeScrubbingStopHandler);
if (this.hasTouch) {
document.addEventListener('touchend', this.timeScrubbingStopHandler);
}

// Likewise add a mouse move handler to the entire document so that when
// the user is scrubbing and they are randomly moving mouse anywhere on the
// document, we still continue to show the film strip
document.addEventListener('mousemove', this.filmstripShowHandler);
if (this.hasTouch) {
document.addEventListener('touchmove', this.show);
}
}

/**
Expand All @@ -714,11 +751,15 @@ const FILMSTRIP_FRAME_HEIGHT = 90;
timeScrubbingStopHandler(event) {
// Flag that scrubbing is done
this.isScrubbing = false;
this.preventHiding = false;

// Remove any even listeners that were added when scrubbing started
document.removeEventListener('mouseup', this.timeScrubbingStopHandler);
document.removeEventListener('mousemove', this.filmstripShowHandler);

document.removeEventListener('touchend', this.timeScrubbingStopHandler);
document.removeEventListener('touchmove', this.show);

if (!this.timeScrubberEl.contains(event.target)) {
// Don't hide the filmstrip if we were hovering over the scrubber when
// mouse up happened. Since we show film strip on hover. On all other cases
Expand Down
4 changes: 3 additions & 1 deletion src/lib/viewers/media/MediaControls.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
.bp-media-controls-wrapper:active,
.bp-media-controls-wrapper:focus {
opacity: 1;
visibility: visible;
}

.bp-media-controls-wrapper {
Expand All @@ -17,7 +18,8 @@
overflow: hidden;
position: absolute;
right: 0;
transition: opacity .3s;
transition: visibility .3s, opacity .3s;
visibility: hidden;
width: 100%;
}

Expand Down
29 changes: 27 additions & 2 deletions src/lib/viewers/media/VideoBaseViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const CLASS_PLAY_BUTTON = 'bp-media-play-button';
// Video element
this.mediaEl = this.mediaContainerEl.appendChild(document.createElement('video'));
this.mediaEl.setAttribute('preload', 'auto');
// Prevents native iOS UI from taking over
this.mediaEl.setAttribute('playsinline', '');

// Play button
this.playButtonEl = this.mediaContainerEl.appendChild(document.createElement('div'));
Expand All @@ -37,7 +39,8 @@ const CLASS_PLAY_BUTTON = 'bp-media-play-button';
destroy() {
if (this.mediaEl) {
this.mediaEl.removeEventListener('mousemove', this.mousemoveHandler);
this.mediaEl.removeEventListener('click', this.togglePlay);
this.mediaEl.removeEventListener('click', this.pointerHandler);
this.mediaEl.removeEventListener('touchstart', this.pointerHandler);
this.mediaEl.removeEventListener('waiting', this.waitingHandler);
}

Expand All @@ -57,6 +60,24 @@ const CLASS_PLAY_BUTTON = 'bp-media-play-button';
loadeddataHandler() {
super.loadeddataHandler();
this.showPlayButton();
this.mediaControls.show();
}

/**
* Handler for a pointer event on the media element.
*
* @param {Event} event pointer event, either touch or mouse
* @return {void}
*/
pointerHandler(event) {
if (event.type === 'touchstart') {
// Prevents 'click' event from firing which would pause the video
event.preventDefault();
event.stopPropagation();
this.mediaControls.toggle();
} else if (event.type === 'click') {
this.togglePlay();
}
}

/**
Expand Down Expand Up @@ -132,7 +153,11 @@ const CLASS_PLAY_BUTTON = 'bp-media-play-button';
}, MOUSE_MOVE_TIMEOUT_IN_MILLIS);

this.mediaEl.addEventListener('mousemove', this.mousemoveHandler);
this.mediaEl.addEventListener('click', this.togglePlay);
if (this.hasTouch) {
this.mediaEl.addEventListener('touchstart', this.pointerHandler);
}

this.mediaEl.addEventListener('click', this.pointerHandler);
this.mediaEl.addEventListener('waiting', this.waitingHandler);
this.playButtonEl.addEventListener('click', this.togglePlay);
}
Expand Down
4 changes: 3 additions & 1 deletion src/lib/viewers/media/__tests__/DashViewer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ describe('lib/viewers/media/DashViewer', () => {
initFilmstrip: () => {},
initSubtitles: () => {},
removeAllListeners: () => {},
removeListener: () => {}
removeListener: () => {},
show: sandbox.stub()
};
stubs.mockControls = sandbox.mock(dash.mediaControls);

Expand Down Expand Up @@ -430,6 +431,7 @@ describe('lib/viewers/media/DashViewer', () => {
expect(dash.emit).to.be.calledWith('load');
expect(dash.loaded).to.be.true;
expect(document.activeElement).to.equal(dash.mediaContainerEl);
expect(dash.mediaControls.show).to.be.called;
});
});

Expand Down
Loading

0 comments on commit 38ecce7

Please sign in to comment.