diff --git a/dashboard-ui/bower_components/emby-webcomponents/.bower.json b/dashboard-ui/bower_components/emby-webcomponents/.bower.json index 55c82eb283..486302a5e6 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/.bower.json +++ b/dashboard-ui/bower_components/emby-webcomponents/.bower.json @@ -15,12 +15,12 @@ }, "devDependencies": {}, "ignore": [], - "version": "1.4.27", - "_release": "1.4.27", + "version": "1.4.29", + "_release": "1.4.29", "_resolution": { "type": "version", - "tag": "1.4.27", - "commit": "f0b0925d56c650501ba6c92a9413b55201f6b129" + "tag": "1.4.29", + "commit": "7292111f0088d466ef25b0d3a99d17b6e07ff0d0" }, "_source": "https://github.com/MediaBrowser/emby-webcomponents.git", "_target": "^1.2.0", diff --git a/dashboard-ui/bower_components/emby-webcomponents/backdrop/backdrop.js b/dashboard-ui/bower_components/emby-webcomponents/backdrop/backdrop.js index dcc48b8eb3..5b48e8a52a 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/backdrop/backdrop.js +++ b/dashboard-ui/bower_components/emby-webcomponents/backdrop/backdrop.js @@ -1,8 +1,9 @@ -define(['browser', 'css!./style'], function (browser) { +define(['browser', 'connectionManager', 'playbackManager', 'css!./style'], function (browser, connectionManager, playbackManager) { function enableAnimation(elem) { if (browser.mobile) { + i return false; } @@ -99,6 +100,8 @@ function clearBackdrop(clearAll) { + clearRotation(); + if (currentLoadingBackdrop) { currentLoadingBackdrop.destroy(); currentLoadingBackdrop = null; @@ -107,8 +110,6 @@ var elem = getBackdropContainer(); elem.innerHTML = ''; - getSkinContainer().removeAttribute('data-backdroptype'); - if (clearAll) { hasExternalBackdrop = false; } @@ -170,64 +171,146 @@ currentLoadingBackdrop = instance; } - function setBackdrops(items, type) { + var windowWidth; + function resetWindowSize() { + windowWidth = screen.availWidth || window.innerWidth; + } + window.addEventListener("orientationchange", resetWindowSize); + window.addEventListener('resize', resetWindowSize); + resetWindowSize(); - var images = items.map(function (i) { + function getItemImageUrls(item) { - if (i.BackdropImageTags && i.BackdropImageTags.length > 0) { - return { - id: i.Id, - tag: i.BackdropImageTags[0], - serverId: i.ServerId - }; - } + var apiClient = connectionManager.getApiClient(item.ServerId); - if (i.ParentBackdropItemId && i.ParentBackdropImageTags && i.ParentBackdropImageTags.length) { + if (item.BackdropImageTags && item.BackdropImageTags.length > 0) { - return { - id: i.ParentBackdropItemId, - tag: i.ParentBackdropImageTags[0], - serverId: i.ServerId - }; - } - return null; + return item.BackdropImageTags.map(function (imgTag, index) { - }).filter(function (i) { - return i != null; - }); + return apiClient.getScaledImageUrl(item.Id, { + type: "Backdrop", + tag: imgTag, + maxWidth: Math.min(windowWidth, 1920), + index: index + }); + }); + } + if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { + + return item.ParentBackdropImageTags.map(function (imgTag, index) { + + return apiClient.getScaledImageUrl(item.ParentBackdropItemId, { + type: "Backdrop", + tag: imgTag, + maxWidth: Math.min(windowWidth, 1920), + index: index + }); + }); + } + + return []; + } + + function getImageUrls(items) { + + var list = []; + + for (var i = 0, length = items.length; i < length; i++) { + + var itemImages = getItemImageUrls(items[i]); + + itemImages.forEach(function (img) { + list.push(img); + }); + } + + return list; + } + + function arraysEqual(a, b) { + if (a === b) return true; + if (a == null || b == null) return false; + if (a.length != b.length) return false; + + // If you don't care about the order of the elements inside + // the array, you should sort both arrays here. + + for (var i = 0; i < a.length; ++i) { + if (a[i] !== b[i]) return false; + } + return true; + } + + var rotationInterval; + var currentRotatingImages = []; + var currentRotationIndex = -1; + function setBackdrops(items, imageSetId) { + + var images = getImageUrls(items); + + imageSetId = imageSetId || new Date().getTime(); if (images.length) { - var index = getRandom(0, images.length - 1); - var item = images[index]; - - require(['connectionManager'], function (connectionManager) { - - var apiClient = connectionManager.getApiClient(item.serverId); - var imgUrl = apiClient.getScaledImageUrl(item.id, { - type: "Backdrop", - tag: item.tag, - maxWidth: Math.min(screen.availWidth || window.innerWidth, 1920) - }); - - setBackdrop(imgUrl, type); - }); + startRotation(images, imageSetId); } else { clearBackdrop(); } } - function setBackdrop(url, type) { + function startRotation(images) { + + if (arraysEqual(images, currentRotatingImages)) { + return; + } + + clearRotation(); + + currentRotatingImages = images; + currentRotationIndex = -1; + + if (images.length > 1) { + rotationInterval = setInterval(onRotationInterval, 20000); + } + onRotationInterval(); + } + + function onRotationInterval() { + + if (playbackManager.isPlayingVideo()) { + return; + } + + var newIndex = currentRotationIndex + 1; + if (newIndex >= currentRotatingImages.length) { + newIndex = 0; + } + + currentRotationIndex = newIndex; + setBackdropImage(currentRotatingImages[newIndex]); + } + + function clearRotation() { + var interval = rotationInterval; + if (interval) { + clearInterval(interval); + } + rotationInterval = null; + currentRotatingImages = []; + currentRotationIndex = -1; + } + + function setBackdrop(url) { + + if (typeof url !== 'string') { + url = getImageUrls([url])[0]; + } if (url) { - setBackdropImage(url); + clearRotation(); - if (type) { - getSkinContainer().setAttribute('data-backdroptype', type); - } else { - getSkinContainer().removeAttribute('data-backdroptype'); - } + setBackdropImage(url); } else { clearBackdrop(); diff --git a/dashboard-ui/bower_components/emby-webcomponents/emby-button/emby-button.css b/dashboard-ui/bower_components/emby-webcomponents/emby-button/emby-button.css index 941e9c2e0b..18d616bb74 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/emby-button/emby-button.css +++ b/dashboard-ui/bower_components/emby-webcomponents/emby-button/emby-button.css @@ -99,6 +99,8 @@ user-select: none; cursor: pointer; z-index: 0; + min-width: 40px; + min-height: 40px; width: 40px; height: 40px; padding: 8px; @@ -113,39 +115,45 @@ font-weight: 500; text-transform: uppercase; border-radius: 50%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } - [is=paper-icon-button-light] iron-icon { - width: 100%; - height: 100%; - /* Make sure its on top of the ripple */ - position: relative; - z-index: 1; - } +.layout-tv [is=paper-icon-button-light] { + width: 4vh; + height: 4vh; +} - [is=paper-icon-button-light] img { - width: 100%; - height: 100%; - /* Make sure its on top of the ripple */ - position: relative; - z-index: 1; - } +[is=paper-icon-button-light] iron-icon { + width: 100%; + height: 100%; + /* Make sure its on top of the ripple */ + position: relative; + z-index: 1; +} - [is=paper-icon-button-light]:after { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - transition: opacity .3s ease-out; - background: currentcolor; - opacity: 0; - } +[is=paper-icon-button-light] img { + width: 100%; + height: 100%; + /* Make sure its on top of the ripple */ + position: relative; + z-index: 1; +} - [is=paper-icon-button-light]:focus:after { - opacity: .3; - } +[is=paper-icon-button-light]:after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + transition: opacity .3s ease-out; + background: currentcolor; + opacity: 0; +} + +[is=paper-icon-button-light]:focus:after { + opacity: .2; +} .ripple-effect { position: absolute; diff --git a/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css index c665943f12..3d1f8a3551 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css +++ b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.css @@ -4,6 +4,25 @@ align-items: initial; } + .tvguide ::-webkit-scrollbar { + width: 10px; + height: 10px; + } + + .tvguide ::-webkit-scrollbar-button:start:decrement, + .tvguide ::-webkit-scrollbar-button:end:increment { + display: none; + } + + .tvguide ::-webkit-scrollbar-track-piece { + background-color: #3b3b3b; + } + + .tvguide ::-webkit-scrollbar-thumb:vertical, .tvguide ::-webkit-scrollbar-thumb:horizontal { + -webkit-border-radius: 2px; + background: #888 no-repeat center; + } + .tvGuideHeader { white-space: nowrap; width: 100%; @@ -105,6 +124,44 @@ position: relative; } +.timeslotHeadersInner { + position: relative; +} + +.currentTimeIndicator { + position: absolute; + bottom: .05em; + left: 0; + width: 100%; + height: 2px; + display: flex; + align-items: flex-end; + transition: all 500ms ease-out; +} + +.layout-tv .currentTimeIndicator { + /* Need to account for the scrollbar not being there */ + margin-left: 4px; +} + +.currentTimeIndicatorBar { + background-color: #52B54B; + height: 2px; + flex-grow: 1; + width: 100%; + margin-left: .65vh; +} + +.currentTimeIndicator iron-icon { + width: 4vh; + height: 4vh; + color: #52B54B; + flex-shrink: 0; + position: relative; + margin-left: -2vh; + top: 1.45vh; +} + .channelPrograms, .timeslotHeadersInner { width: 1800vw; } diff --git a/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js index 6aba1a7df7..a6e4ed8736 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js +++ b/dashboard-ui/bower_components/emby-webcomponents/guide/guide.js @@ -11,6 +11,7 @@ }; self.destroy = function () { + clearCurrentTimeUpdateInterval(); itemShortcuts.off(options.element); items = {}; }; @@ -21,6 +22,7 @@ var cellCurationMinutes = 30; var cellDurationMs = cellCurationMinutes * 60 * 1000; var msPerDay = 86400000; + var totalRendererdMs = msPerDay; var currentDate; @@ -56,6 +58,46 @@ loading.hide(); } + var currentTimeUpdateInterval; + var currentTimeIndicatorElement; + function startCurrentTimeUpdateInterval() { + clearCurrentTimeUpdateInterval(); + + //currentTimeUpdateInterval = setInterval(updateCurrentTimeIndicator, 1000); + currentTimeUpdateInterval = setInterval(updateCurrentTimeIndicator, 60000); + updateCurrentTimeIndicator(); + } + + function clearCurrentTimeUpdateInterval() { + var interval = currentTimeUpdateInterval; + if (interval) { + clearInterval(interval); + } + currentTimeUpdateInterval = null; + currentTimeIndicatorElement = null; + } + + function updateCurrentTimeIndicator() { + + if (!currentTimeIndicatorElement) { + currentTimeIndicatorElement = options.element.querySelector('.currentTimeIndicator'); + } + + var dateDifference = new Date().getTime() - currentDate.getTime(); + var pct = dateDifference > 0 ? (dateDifference / totalRendererdMs) : 0; + pct = Math.min(pct, 1); + + if (pct <= 0 || pct >= 1) { + currentTimeIndicatorElement.classList.add('hide'); + } else { + currentTimeIndicatorElement.classList.remove('hide'); + + //pct *= 100; + //pct = 100 - pct; + currentTimeIndicatorElement.style.width = (pct * 100) + '%'; + } + } + function getChannelLimit(context) { return registrationServices.validateFeature('livetv').then(function () { @@ -159,6 +201,13 @@ // Add 30 mins startDate.setTime(startDate.getTime() + cellDurationMs); } + + html += '
'; + html += ''; return html; @@ -436,6 +485,7 @@ var startDate = date; var endDate = new Date(startDate.getTime() + msPerDay); context.querySelector('.timeslotHeaders').innerHTML = getTimeslotHeadersHtml(startDate, endDate); + startCurrentTimeUpdateInterval(); items = {}; renderPrograms(context, date, channels, programs); @@ -522,6 +572,8 @@ function changeDate(page, date) { + clearCurrentTimeUpdateInterval(); + var newStartDate = normalizeDateToTimeslot(date); currentDate = newStartDate; diff --git a/dashboard-ui/bower_components/emby-webcomponents/icons/nav.html b/dashboard-ui/bower_components/emby-webcomponents/icons/nav.html index 2c69896cce..39c6ced14e 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/icons/nav.html +++ b/dashboard-ui/bower_components/emby-webcomponents/icons/nav.html @@ -35,6 +35,7 @@ See [iron-iconset](#iron-iconset) and [iron-iconset-svg](#iron-iconset-svg) for