From 3896c18e2646f99d35d0c3c1eb468495ca168350 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Sat, 9 Nov 2019 11:48:52 +0300 Subject: [PATCH 1/4] Make navigation and playback control TV-friendly --- src/components/emby-slider/emby-slider.css | 4 + src/components/emby-slider/emby-slider.js | 118 +++++++++++++++++++++ src/controllers/videoosd.js | 19 ++++ src/videoosd.html | 2 +- 4 files changed, 142 insertions(+), 1 deletion(-) diff --git a/src/components/emby-slider/emby-slider.css b/src/components/emby-slider/emby-slider.css index bd258d3bc5..b173f5c511 100644 --- a/src/components/emby-slider/emby-slider.css +++ b/src/components/emby-slider/emby-slider.css @@ -87,6 +87,10 @@ _:-ms-input-placeholder { transform: scale(1.6); } +.mdl-slider.show-focus:focus::-webkit-slider-thumb { + transform: scale(1.6); +} + .slider-no-webkit-thumb::-webkit-slider-thumb { opacity: 0 !important; } diff --git a/src/components/emby-slider/emby-slider.js b/src/components/emby-slider/emby-slider.js index 1ca1448ea1..c1d58d59a3 100644 --- a/src/components/emby-slider/emby-slider.js +++ b/src/components/emby-slider/emby-slider.js @@ -19,6 +19,11 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement function updateValues() { + // Do not update values when dragging with keyboard to keep current progress for reference + if (!!this.keyboardDragging) { + return; + } + var range = this; var value = range.value; @@ -82,6 +87,9 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement if (!layoutManager.mobile) { this.classList.add('mdl-slider-hoverthumb'); } + if (layoutManager.tv) { + this.classList.add('show-focus'); + } var containerElement = this.parentNode; containerElement.classList.add('mdl-slider-container'); @@ -177,6 +185,116 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement } }; + /** + * Keyboard dragging timeout. + * After this delay "change" event will be fired. + */ + var KeyboardDraggingTimeout = 1000; + + /** + * Keyboard dragging timer. + */ + var keyboardDraggingTimer; + + /** + * Start keyboard dragging. + * + * @param {Object} elem slider itself + */ + function startKeyboardDragging(elem) { + + elem.keyboardDragging = true; + + clearTimeout(keyboardDraggingTimer); + + keyboardDraggingTimer = setTimeout(function () { + finishKeyboardDragging(elem); + }, KeyboardDraggingTimeout); + } + + /** + * Finish keyboard dragging. + * + * @param {Object} elem slider itself + */ + function finishKeyboardDragging(elem) { + + clearTimeout(keyboardDraggingTimer); + keyboardDraggingTimer = undefined; + + elem.keyboardDragging = false; + + var event = new Event('change', { + bubbles: true, + cancelable: false + }); + elem.dispatchEvent(event); + } + + /** + * Do step by delta. + * + * @param {Object} elem slider itself + * @param {number} delta step amount + */ + function stepKeyboard(elem, delta) { + + startKeyboardDragging(elem); + + elem.value = Math.max(elem.min, Math.min(elem.max, parseFloat(elem.value) + delta)); + + var event = new Event('input', { + bubbles: true, + cancelable: false + }); + elem.dispatchEvent(event); + } + + /** + * Handle KeyDown event + */ + function onKeyDown(e) { + + switch (e.key) { + case 'ArrowLeft': + case 'Left': + stepKeyboard(this, -this.keyboardStepDown || -1); + e.preventDefault(); + e.stopPropagation(); + break; + + case 'ArrowRight': + case 'Right': + stepKeyboard(this, this.keyboardStepUp || 1); + e.preventDefault(); + e.stopPropagation(); + break; + } + } + + /** + * Enable keyboard dragging. + */ + EmbySliderPrototype.enableKeyboardDragging = function () { + + if (!this.keyboardDraggingEnabled) { + this.addEventListener('keydown', onKeyDown); + this.keyboardDraggingEnabled = true; + } + } + + /** + * Set steps for keyboard input. + * + * @param {number} stepDown step to reduce + * @param {number} stepUp step to increase + */ + EmbySliderPrototype.setKeyboardSteps = function (stepDown, stepUp) { + + this.keyboardStepDown = stepDown || stepUp || 1; + this.keyboardStepUp = stepUp || stepDown || 1; + } + function setRange(elem, startPercent, endPercent) { var style = elem.style; diff --git a/src/controllers/videoosd.js b/src/controllers/videoosd.js index b610886963..81e819e4e0 100644 --- a/src/controllers/videoosd.js +++ b/src/controllers/videoosd.js @@ -770,6 +770,10 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med var isProgressClear = state.MediaSource && null == state.MediaSource.RunTimeTicks; nowPlayingPositionSlider.setIsClear(isProgressClear); + if (nowPlayingItem.RunTimeTicks) { + nowPlayingPositionSlider.setKeyboardSteps(userSettings.skipBackLength() * 1000000 / nowPlayingItem.RunTimeTicks, userSettings.skipForwardLength() * 1000000 / nowPlayingItem.RunTimeTicks); + } + if (-1 === supportedCommands.indexOf("ToggleFullscreen") || player.isLocalPlayer && layoutManager.tv && playbackManager.isFullscreen(player)) { view.querySelector(".btnFullscreen").classList.add("hide"); } else { @@ -1070,12 +1074,21 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } } + /** + * Keys used for keyboard navigation. + */ + var NavigationKeys = ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"]; + function onWindowKeyDown(e) { if (!currentVisibleMenu && 32 === e.keyCode) { playbackManager.playPause(currentPlayer); return void showOsd(); } + if (layoutManager.tv && NavigationKeys.indexOf(e.key) != -1) { + return void showOsd(); + } + switch (e.key) { case "k": playbackManager.playPause(currentPlayer); @@ -1237,6 +1250,12 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med var transitionEndEventName = dom.whichTransitionEvent(); var headerElement = document.querySelector(".skinHeader"); var osdBottomElement = document.querySelector(".videoOsdBottom-maincontrols"); + + if (layoutManager.tv) { + nowPlayingPositionSlider.classList.add("focusable"); + nowPlayingPositionSlider.enableKeyboardDragging(); + } + view.addEventListener("viewbeforeshow", function (e) { headerElement.classList.add("osdHeader"); Emby.Page.setTransparency("full"); diff --git a/src/videoosd.html b/src/videoosd.html index 0f4be75916..34c73a3019 100644 --- a/src/videoosd.html +++ b/src/videoosd.html @@ -31,7 +31,7 @@
-
+
From e090b78d66af197932b4377a8ed410943b7c7716 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo <56478732+dmitrylyzo@users.noreply.github.com> Date: Wed, 13 Nov 2019 00:19:00 +0300 Subject: [PATCH 2/4] Apply suggestions from code review Co-Authored-By: Vasily --- src/components/emby-slider/emby-slider.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/components/emby-slider/emby-slider.js b/src/components/emby-slider/emby-slider.js index c1d58d59a3..fc7a743306 100644 --- a/src/components/emby-slider/emby-slider.js +++ b/src/components/emby-slider/emby-slider.js @@ -202,11 +202,9 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement * @param {Object} elem slider itself */ function startKeyboardDragging(elem) { - elem.keyboardDragging = true; clearTimeout(keyboardDraggingTimer); - keyboardDraggingTimer = setTimeout(function () { finishKeyboardDragging(elem); }, KeyboardDraggingTimeout); @@ -218,7 +216,6 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement * @param {Object} elem slider itself */ function finishKeyboardDragging(elem) { - clearTimeout(keyboardDraggingTimer); keyboardDraggingTimer = undefined; @@ -238,7 +235,6 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement * @param {number} delta step amount */ function stepKeyboard(elem, delta) { - startKeyboardDragging(elem); elem.value = Math.max(elem.min, Math.min(elem.max, parseFloat(elem.value) + delta)); @@ -261,14 +257,14 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement stepKeyboard(this, -this.keyboardStepDown || -1); e.preventDefault(); e.stopPropagation(); - break; + break; case 'ArrowRight': case 'Right': stepKeyboard(this, this.keyboardStepUp || 1); e.preventDefault(); e.stopPropagation(); - break; + break; } } @@ -276,7 +272,6 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement * Enable keyboard dragging. */ EmbySliderPrototype.enableKeyboardDragging = function () { - if (!this.keyboardDraggingEnabled) { this.addEventListener('keydown', onKeyDown); this.keyboardDraggingEnabled = true; @@ -290,7 +285,6 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement * @param {number} stepUp step to increase */ EmbySliderPrototype.setKeyboardSteps = function (stepDown, stepUp) { - this.keyboardStepDown = stepDown || stepUp || 1; this.keyboardStepUp = stepUp || stepDown || 1; } From 8df85172cb02c3911cf1a197183c7d26a183bb74 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Wed, 13 Nov 2019 00:30:33 +0300 Subject: [PATCH 3/4] Apply suggestions from code review --- src/controllers/videoosd.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controllers/videoosd.js b/src/controllers/videoosd.js index 81e819e4e0..0905095338 100644 --- a/src/controllers/videoosd.js +++ b/src/controllers/videoosd.js @@ -771,7 +771,8 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med nowPlayingPositionSlider.setIsClear(isProgressClear); if (nowPlayingItem.RunTimeTicks) { - nowPlayingPositionSlider.setKeyboardSteps(userSettings.skipBackLength() * 1000000 / nowPlayingItem.RunTimeTicks, userSettings.skipForwardLength() * 1000000 / nowPlayingItem.RunTimeTicks); + nowPlayingPositionSlider.setKeyboardSteps(userSettings.skipBackLength() * 1000000 / nowPlayingItem.RunTimeTicks, + userSettings.skipForwardLength() * 1000000 / nowPlayingItem.RunTimeTicks); } if (-1 === supportedCommands.indexOf("ToggleFullscreen") || player.isLocalPlayer && layoutManager.tv && playbackManager.isFullscreen(player)) { From 63483677113ff964f7873eadf6f6e1adf5845154 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Mon, 18 Nov 2019 17:31:09 +0300 Subject: [PATCH 4/4] Apply suggestions from code review --- src/components/emby-slider/emby-slider.js | 2 -- src/controllers/videoosd.js | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/emby-slider/emby-slider.js b/src/components/emby-slider/emby-slider.js index fc7a743306..c340e79359 100644 --- a/src/components/emby-slider/emby-slider.js +++ b/src/components/emby-slider/emby-slider.js @@ -250,7 +250,6 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement * Handle KeyDown event */ function onKeyDown(e) { - switch (e.key) { case 'ArrowLeft': case 'Left': @@ -258,7 +257,6 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement e.preventDefault(); e.stopPropagation(); break; - case 'ArrowRight': case 'Right': stepKeyboard(this, this.keyboardStepUp || 1); diff --git a/src/controllers/videoosd.js b/src/controllers/videoosd.js index 0905095338..6232c1f2e0 100644 --- a/src/controllers/videoosd.js +++ b/src/controllers/videoosd.js @@ -1083,11 +1083,13 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med function onWindowKeyDown(e) { if (!currentVisibleMenu && 32 === e.keyCode) { playbackManager.playPause(currentPlayer); - return void showOsd(); + showOsd(); + return; } if (layoutManager.tv && NavigationKeys.indexOf(e.key) != -1) { - return void showOsd(); + showOsd(); + return; } switch (e.key) {