From 0298eb16553b715f96d82c9a2c94ab5d9822f846 Mon Sep 17 00:00:00 2001 From: Alan Orozco Date: Sun, 17 Feb 2019 21:11:25 -0800 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8Flick=20to=20dismiss=20docked=20vi?= =?UTF-8?q?deo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0.1/amp-video-docking.js | 121 ++++++++++++++++-- .../amp-video-docking/amp-video-docking.md | 1 + 2 files changed, 113 insertions(+), 9 deletions(-) diff --git a/extensions/amp-video-docking/0.1/amp-video-docking.js b/extensions/amp-video-docking/0.1/amp-video-docking.js index 31c0518f946c..af79bdd75540 100644 --- a/extensions/amp-video-docking/0.1/amp-video-docking.js +++ b/extensions/amp-video-docking/0.1/amp-video-docking.js @@ -347,6 +347,12 @@ export class VideoDocking { /** @private {boolean} */ this.isDragging_ = false; + /** @private {number} */ + this.previousDragOffsetX_ = 0; + + /** @private {number} */ + this.dragVelocityX_ = 0; + /** @private {!Array} */ this.observed_ = []; @@ -1320,6 +1326,11 @@ export class VideoDocking { const {centerX} = this.getCenter_(offsetX, offsetY); const offsetRelativeX = this.calculateRelativeX_(centerX); + this.dragVelocityX_ = offsetX - this.previousDragOffsetX_; + this.previousDragOffsetX_ = offsetX; + + dev().info(TAG, 'drag velocity', this.dragVelocityX_); + this.placeAt_(video, x + offsetX, y + offsetY, scale, step, transitionDurationMs, offsetRelativeX); } @@ -1471,7 +1482,92 @@ export class VideoDocking { this.getControls_().enable(); - this.snap_(offset.x, offset.y); + if (Math.abs(this.dragVelocityX_) < 40) { + this.snap_(offset.x, offset.y); + } else { + this.flickToDismiss_(this.previousDragOffsetX_, + Math.sign(this.dragVelocityX_)); + } + + this.dragVelocityX_ = 0; + this.previousDragOffsetX_ = 0; + } + + /** + * @param {number} offsetX + * @param {number} direction -1 or 1 + * @private + */ + flickToDismiss_(offsetX, direction) { + devAssert(Math.abs(direction) == 1); + + const video = this.getDockedVideo_(); + + video.pause(); + + if (this.isVisible_(video.element, 0.2)) { + this.bounceToDismiss_(offsetX, direction); + return; + } + + const step = 1; + const {target} = devAssert(this.currentlyDocked_); + + const {x, y, width} = this.getTargetArea_(video, target); + const {scale} = this.getDims_(video, target, step); + + const currentX = x + offsetX; + const nextX = direction == 1 ? + this.getRightEdge_() : + this.getLeftEdge_() - width; + + const transitionDurationMs = Math.min(600, Math.abs(nextX - currentX)); + + const {centerX} = this.getCenter_(nextX, /* offsetY */ 0); + const offsetRelativeX = this.calculateRelativeX_(centerX); + + this.reconcileUndocked_(); + + video.showControls(); + + this.placeAt_(video, nextX, y, scale, /* step */ 0, transitionDurationMs, + offsetRelativeX).then(() => { + this.resetOnUndock_(video); + }); + } + + /** + * @param {number} offsetX + * @param {number} direction -1 or 1 + * @private + */ + bounceToDismiss_(offsetX, direction) { + devAssert(Math.abs(direction) == 1); + + const video = this.getDockedVideo_(); + + const step = 1; + const {target} = devAssert(this.currentlyDocked_); + + const {x, y, width} = this.getTargetArea_(video, target); + const {scale} = this.getDims_(video, target, step); + + const areaWidth = this.getAreaWidth_(); + + const currentX = x + offsetX; + const nextX = direction == 1 ? + calculateRightJustifiedX(areaWidth, width, /* margin */ 0, step) : + calculateLeftJustifiedX(areaWidth, width, /* margin */ 0, step); + + const transitionDurationMs = Math.min(300, Math.abs(nextX - currentX) / 2); + + this.reconcileUndocked_(); + + this.placeAt_(video, nextX, y, scale, /* step */ 0, transitionDurationMs) + .then(() => { + this.undock_(video, /* reconciled */ true); + video.showControls(); + }); } /** @@ -1637,16 +1733,14 @@ export class VideoDocking { /** * @param {!../../../src/video-interface.VideoOrBaseElementDef} video + * @param {boolean=} opt_reconciled * @return {!Promise} * @private */ - undock_(video) { + undock_(video, opt_reconciled) { dev().info(TAG, 'undock', {video}); - this.getControls_().disable(); - const {element} = video; - const isMostlyInView = this.isVisible_(element, REVERT_TO_INLINE_RATIO); if (!isMostlyInView) { @@ -1658,10 +1752,9 @@ export class VideoDocking { video.showControls(); } - // Prevents ghosting - this.getControls_().hide(/* respectSticky */ false, /* immediately */ true); - - this.trigger_(Actions.UNDOCK); + if (!opt_reconciled) { + this.reconcileUndocked_(); + } const step = 0; @@ -1685,6 +1778,16 @@ export class VideoDocking { }); } + /** @private */ + reconcileUndocked_() { + this.getControls_().disable(); + + // Prevents ghosting + this.getControls_().hide(/* respectSticky */ false, /* immediately */ true); + + this.trigger_(Actions.UNDOCK); + } + /** * @param {!../../../src/video-interface.VideoOrBaseElementDef} video diff --git a/extensions/amp-video-docking/amp-video-docking.md b/extensions/amp-video-docking/amp-video-docking.md index 888ac1fd49f4..94d12c9e1d1a 100644 --- a/extensions/amp-video-docking/amp-video-docking.md +++ b/extensions/amp-video-docking/amp-video-docking.md @@ -55,6 +55,7 @@ component's visual area. If the user scrolls back, the video reverts to its orig - The video can be docked to a default corner or to a custom fixed position. - The video can be dragged and repositioned by the user on a different corner. +- The video can be flicked to be dismissed from its docked position. - Multiple videos on the same page can be docked, but only one at a time will be docked and fixed. ### Support From ecef4424fd98840fedb9895476ffac24ae9252c2 Mon Sep 17 00:00:00 2001 From: Alan Orozco Date: Sun, 17 Feb 2019 21:25:05 -0800 Subject: [PATCH 2/3] cleanup --- .../0.1/amp-video-docking.js | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/extensions/amp-video-docking/0.1/amp-video-docking.js b/extensions/amp-video-docking/0.1/amp-video-docking.js index af79bdd75540..98f8706bef37 100644 --- a/extensions/amp-video-docking/0.1/amp-video-docking.js +++ b/extensions/amp-video-docking/0.1/amp-video-docking.js @@ -1506,7 +1506,7 @@ export class VideoDocking { video.pause(); if (this.isVisible_(video.element, 0.2)) { - this.bounceToDismiss_(offsetX, direction); + this.bounceToDismiss_(video, offsetX, direction); return; } @@ -1521,31 +1521,29 @@ export class VideoDocking { this.getRightEdge_() : this.getLeftEdge_() - width; - const transitionDurationMs = Math.min(600, Math.abs(nextX - currentX)); - - const {centerX} = this.getCenter_(nextX, /* offsetY */ 0); - const offsetRelativeX = this.calculateRelativeX_(centerX); + const transitionDurationMs = + this.calculateDismissalTransitionDurationMs_(nextX - currentX); this.reconcileUndocked_(); + // Show immediately due to Chrome freeze bug when out-of-view. video.showControls(); - this.placeAt_(video, nextX, y, scale, /* step */ 0, transitionDurationMs, - offsetRelativeX).then(() => { - this.resetOnUndock_(video); - }); + this.placeAt_(video, nextX, y, scale, /* step */ 0, transitionDurationMs) + .then(() => { + this.resetOnUndock_(video); + }); } /** + * @param {!../../../src/video-interface.VideoOrBaseElementDef} video * @param {number} offsetX * @param {number} direction -1 or 1 * @private */ - bounceToDismiss_(offsetX, direction) { + bounceToDismiss_(video, offsetX, direction) { devAssert(Math.abs(direction) == 1); - const video = this.getDockedVideo_(); - const step = 1; const {target} = devAssert(this.currentlyDocked_); @@ -1559,7 +1557,8 @@ export class VideoDocking { calculateRightJustifiedX(areaWidth, width, /* margin */ 0, step) : calculateLeftJustifiedX(areaWidth, width, /* margin */ 0, step); - const transitionDurationMs = Math.min(300, Math.abs(nextX - currentX) / 2); + const transitionDurationMs = + this.calculateDismissalTransitionDurationMs_(nextX - currentX); this.reconcileUndocked_(); @@ -1570,6 +1569,15 @@ export class VideoDocking { }); } + /** + * @param {number} deltaX + * @return {number} + * @private + */ + calculateDismissalTransitionDurationMs_(deltaX) { + return Math.min(300, Math.abs(deltaX) / 2); + } + /** * Gets the center of the currently docked video, offset by (x, y). * @param {number} offsetX From c518b3d85db2a15faf27d4375d8e72b01881d854 Mon Sep 17 00:00:00 2001 From: Alan Orozco Date: Tue, 19 Feb 2019 17:17:28 -0800 Subject: [PATCH 3/3] Remove dev().info() --- extensions/amp-video-docking/0.1/amp-video-docking.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/extensions/amp-video-docking/0.1/amp-video-docking.js b/extensions/amp-video-docking/0.1/amp-video-docking.js index 98f8706bef37..2eb1ca525eec 100644 --- a/extensions/amp-video-docking/0.1/amp-video-docking.js +++ b/extensions/amp-video-docking/0.1/amp-video-docking.js @@ -1329,8 +1329,6 @@ export class VideoDocking { this.dragVelocityX_ = offsetX - this.previousDragOffsetX_; this.previousDragOffsetX_ = offsetX; - dev().info(TAG, 'drag velocity', this.dragVelocityX_); - this.placeAt_(video, x + offsetX, y + offsetY, scale, step, transitionDurationMs, offsetRelativeX); }