diff --git a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css index 1aa307e495..caedcbcf0d 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css +++ b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/card.css @@ -1,3 +1,8 @@ +button::-moz-focus-inner { + padding: 0; + border: 0 +} + .card { border: 0; font-size: inherit !important; @@ -196,6 +201,20 @@ background-position: center bottom; } +.cardImage-img { + max-height: 100%; + max-width: 100%; + align-self: flex-end; + position: static; +} + +.coveredImage-img { + max-height: none; + max-width: none; + height: 100%; + width: 100%; +} + .coveredImage { background-size: 100% 100%; background-position: center center; diff --git a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js index fbdda488c2..2b871d8195 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js +++ b/dashboard-ui/bower_components/emby-webcomponents/cardbuilder/cardbuilder.js @@ -712,18 +712,19 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo for (i = 0, length = lines.length; i < length; i++) { + var currentCssClass = cssClass; var text = lines[i]; - if (i === 1 && isOuterFooter) { - cssClass += ' cardText-secondary'; + if (valid > 0 && isOuterFooter) { + currentCssClass += ' cardText-secondary'; } if (isOuterFooter && cardLayout) { - cssClass += ' cardText-rightmargin'; + currentCssClass += ' cardText-rightmargin'; } if (text) { - html += "
"; + html += "
"; html += text; html += "
"; valid++; @@ -740,7 +741,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo return html; } - function getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerClass, progressHtml, isOuterFooter) { + var uniqueFooterIndex = 0; + function getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerClass, progressHtml, isOuterFooter, cardFooterId, vibrantSwatch) { var html = ''; @@ -982,7 +984,18 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo } if (html) { - html = '
' + html; + + var style = ''; + + if (options.vibrant && vibrantSwatch) { + var swatch = vibrantSwatch.split('|'); + if (swatch.length) { + + var index = 0; + style = ' style="color:' + swatch[index + 1] + ';background-color:' + swatch[index] + ';"'; + } + } + html = '
' + html; //cardFooter html += "
"; @@ -1139,7 +1152,9 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo } var cardImageContainerClass = 'cardImageContainer'; - if (options.coverImage || imgInfo.coverImage) { + var coveredImage = options.coverImage || imgInfo.coverImage; + + if (coveredImage) { cardImageContainerClass += ' coveredImage'; if (item.MediaType === 'Photo' || item.Type === 'PhotoAlbum' || item.Type === 'Folder' || item.ProgramInfo || item.Type === 'Program') { @@ -1167,10 +1182,13 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo var footerOverlayed = false; + var cardFooterId = 'cardFooter' + uniqueFooterIndex; + uniqueFooterIndex++; + if (overlayText) { footerCssClass = progressHtml ? 'innerCardFooter fullInnerCardFooter' : 'innerCardFooter'; - innerCardFooter += getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, false); + innerCardFooter += getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, false, cardFooterId); footerOverlayed = true; } else if (progressHtml) { @@ -1186,10 +1204,12 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo innerCardFooter += '
' + mediaSourceCount + '
'; } + var vibrantSwatch = options.vibrant && imgUrl ? imageLoader.getCachedVibrantInfo(imgUrl) : null; + var outerCardFooter = ''; if (!overlayText && !footerOverlayed) { footerCssClass = options.cardLayout ? 'cardFooter visualCardBox-cardFooter' : 'cardFooter transparent'; - outerCardFooter = getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, true); + outerCardFooter = getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerCssClass, progressHtml, true, cardFooterId, vibrantSwatch); } if (outerCardFooter && !options.cardLayout && options.allowBottomPadding !== false) { @@ -1241,7 +1261,19 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo cardContentOpen = ''; } - cardImageContainerOpen = imgUrl ? ('
') : ('
'); + + if (options.vibrant && imgUrl && !vibrantSwatch) { + cardImageContainerOpen = imgUrl ? ('
') : ('
'); + + var imgClass = 'cardImage cardImage-img lazy'; + if (coveredImage) { + imgClass += ' coveredImage-img'; + } + cardImageContainerOpen += ''; + + } else { + cardImageContainerOpen = imgUrl ? ('
') : ('
'); + } var cardScalableClass = options.cardLayout ? 'cardScalable visualCardBox-cardScalable' : 'cardScalable'; cardImageContainerOpen = '
' + cardContentOpen + cardImageContainerOpen; @@ -1439,10 +1471,11 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'mediaInfo playedIndicator = document.createElement('div'); playedIndicator.classList.add('playedIndicator'); + playedIndicator.classList.add('indicator'); indicatorsElem = ensureIndicators(card, indicatorsElem); indicatorsElem.appendChild(playedIndicator); } - playedIndicator.innerHTML = 'check'; + playedIndicator.innerHTML = 'check'; } else { playedIndicator = card.querySelector('.playedIndicator'); diff --git a/dashboard-ui/bower_components/emby-webcomponents/images/basicimagefetcher.js b/dashboard-ui/bower_components/emby-webcomponents/images/basicimagefetcher.js index 4b3f17b241..751e3a4620 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/images/basicimagefetcher.js +++ b/dashboard-ui/bower_components/emby-webcomponents/images/basicimagefetcher.js @@ -1,16 +1,24 @@ -define([], function () { +define(['dom'], function (dom) { function loadImage(elem, url) { if (elem.tagName !== "IMG") { elem.style.backgroundImage = "url('" + url + "')"; - return Promise.resolve(elem); + return Promise.resolve(); - } else { - elem.setAttribute("src", url); - return Promise.resolve(elem); } + return loadImageIntoImg(elem, url); + } + + function loadImageIntoImg(elem, url) { + return new Promise(function (resolve, reject) { + + dom.addEventListener(elem, 'load', resolve, { + once: true + }); + elem.setAttribute("src", url); + }); } return { diff --git a/dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js b/dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js index 0066a30ffd..6d05f402cc 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js +++ b/dashboard-ui/bower_components/emby-webcomponents/images/imagehelper.js @@ -1,4 +1,4 @@ -define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser', 'dom'], function (visibleinviewport, imageFetcher, layoutManager, events, browser, dom) { +define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser', 'dom', 'appSettings', 'vibrant'], function (visibleinviewport, imageFetcher, layoutManager, events, browser, dom, appSettings) { var thresholdX; var thresholdY; @@ -47,16 +47,105 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser if (!source) { source = elem.getAttribute('data-src'); } + if (source) { - if (enableFade && !layoutManager.tv && enableEffects !== false) { - imageFetcher.loadImage(elem, source).then(fadeIn); - } else { - imageFetcher.loadImage(elem, source); - } - elem.removeAttribute("data-src"); + + imageFetcher.loadImage(elem, source).then(function () { + + fillVibrant(elem, source); + + if (enableFade && !layoutManager.tv && enableEffects !== false) { + fadeIn(elem); + } + + elem.removeAttribute("data-src"); + }); } } + function fillVibrant(img, url) { + + if (img.tagName != 'IMG') { + return; + } + + var vibrantElement = img.getAttribute('data-vibrant'); + if (!vibrantElement) { + return; + } + + vibrantElement = document.getElementById(vibrantElement); + if (!vibrantElement) { + return; + } + + var swatch = getVibrantInfo(img, url).split('|'); + if (swatch.length) { + + var index = 0; + vibrantElement.style['backgroundColor'] = swatch[index]; + vibrantElement.style['color'] = swatch[index + 1]; + } + /* + * Results into: + * Vibrant #7a4426 + * Muted #7b9eae + * DarkVibrant #348945 + * DarkMuted #141414 + * LightVibrant #f3ccb4 + */ + } + + function getSettingsKey(url) { + return 'vibrant2-' + url.split('?')[0]; + } + + function getCachedVibrantInfo(url) { + + return appSettings.get(getSettingsKey(url)); + } + + function getVibrantInfo(img, url) { + + var value = getCachedVibrantInfo(url); + if (value) { + return value; + } + + var vibrant = new Vibrant(img); + var swatches = vibrant.swatches(); + + value = ''; + var swatch = swatches['DarkVibrant']; + if (swatch) { + value += swatch.getHex() + '|' + swatch.getBodyTextColor(); + } + swatch = swatches['DarkMuted']; + if (swatch) { + value += '|' + swatch.getHex() + '|' + swatch.getBodyTextColor(); + } else { + value += '||'; + } + swatch = swatches['Vibrant']; + if (swatch) { + value += '|' + swatch.getHex() + '|' + swatch.getBodyTextColor(); + } else { + value += '||'; + } + swatch = swatches['Muted']; + if (swatch) { + value += '|' + swatch.getHex() + '|' + swatch.getBodyTextColor(); + } else { + value += '||'; + } + + if (value) { + appSettings.set(getSettingsKey(url), value); + } + + return value; + } + function fadeIn(elem) { var duration = layoutManager.tv ? 160 : 300; @@ -268,6 +357,7 @@ define(['visibleinviewport', 'imageFetcher', 'layoutManager', 'events', 'browser self.lazyImage = fillImage; self.lazyChildren = lazyChildren; self.getPrimaryImageAspectRatio = getPrimaryImageAspectRatio; + self.getCachedVibrantInfo = getCachedVibrantInfo; return self; }); \ No newline at end of file diff --git a/dashboard-ui/css/site.css b/dashboard-ui/css/site.css index 73bf746deb..4d634a179a 100644 --- a/dashboard-ui/css/site.css +++ b/dashboard-ui/css/site.css @@ -162,7 +162,7 @@ input:not([type='checkbox']):not([type='radio']):not([type='file']):not([type='r .ui-body-a select, .ui-body-a [is="emby-input"], .ui-body-a [is="emby-textarea"] { background: none; - border-color: #ccc!important; + border-color: #ccc !important; } .ui-body-a .secondaryText { @@ -420,6 +420,12 @@ div[data-role='page'] { background-color: #fff; } +.ui-body-a .visualCardBox { + border: 0; + margin: 6px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + .ui-body-a .cardFooter .cardText + .cardText { opacity: .8; } diff --git a/dashboard-ui/livetvseriestimer.html b/dashboard-ui/livetvseriestimer.html index 6896dc7eef..d13cea650b 100644 --- a/dashboard-ui/livetvseriestimer.html +++ b/dashboard-ui/livetvseriestimer.html @@ -20,12 +20,6 @@

${HeaderSchedule}

-
- -
${WillRecord}
- -
${NotScheduledToRecord}
-
diff --git a/dashboard-ui/scripts/dashboardpage.js b/dashboard-ui/scripts/dashboardpage.js index f5f5aa2dd4..901bd9269e 100644 --- a/dashboard-ui/scripts/dashboardpage.js +++ b/dashboard-ui/scripts/dashboardpage.js @@ -32,7 +32,7 @@ label: Globalize.translate('LabelFriendlyServerName'), description: Globalize.translate('LabelFriendlyServerNameHelp'), value: page.querySelector('.serverNameHeader').innerHTML, - submitText: Globalize.translate('ButtonSave') + confirmText: Globalize.translate('ButtonSave') }).then(function (value) { diff --git a/dashboard-ui/scripts/livetvcomponents.js b/dashboard-ui/scripts/livetvcomponents.js index ac39f71ae4..eec80cb3fe 100644 --- a/dashboard-ui/scripts/livetvcomponents.js +++ b/dashboard-ui/scripts/livetvcomponents.js @@ -90,6 +90,7 @@ showChannelName: true, lazy: true, cardLayout: true, + vibrant: true, action: 'edit', cardFooterAside: 'none', preferThumb: true, diff --git a/dashboard-ui/scripts/livetvrecordings.js b/dashboard-ui/scripts/livetvrecordings.js index 2b29f26642..26dba40d7d 100644 --- a/dashboard-ui/scripts/livetvrecordings.js +++ b/dashboard-ui/scripts/livetvrecordings.js @@ -84,6 +84,7 @@ coverImage: true, lazy: true, cardLayout: true, + vibrant: true, allowBottomPadding: !enableScrollX(), preferThumb: 'auto' diff --git a/dashboard-ui/scripts/livetvseriestimers.js b/dashboard-ui/scripts/livetvseriestimers.js index 1c9ee4b247..cea15b472d 100644 --- a/dashboard-ui/scripts/livetvseriestimers.js +++ b/dashboard-ui/scripts/livetvseriestimers.js @@ -35,6 +35,7 @@ shape: 'backdrop', showTitle: true, cardLayout: true, + vibrant: true, cardFooterAside: 'none', preferThumb: true, coverImage: true, diff --git a/dashboard-ui/scripts/medialibrarypage.js b/dashboard-ui/scripts/medialibrarypage.js index de2ea55339..2ed88e3a33 100644 --- a/dashboard-ui/scripts/medialibrarypage.js +++ b/dashboard-ui/scripts/medialibrarypage.js @@ -75,7 +75,8 @@ require(['prompt'], function (prompt) { prompt({ - label: Globalize.translate('LabelNewName') + label: Globalize.translate('LabelNewName'), + confirmText: Globalize.translate('ButtonRename') }).then(function (newName) { if (newName && newName != virtualFolder.Name) { diff --git a/dashboard-ui/scripts/movies.js b/dashboard-ui/scripts/movies.js index 8132124779..9bce149fbb 100644 --- a/dashboard-ui/scripts/movies.js +++ b/dashboard-ui/scripts/movies.js @@ -113,7 +113,8 @@ lazy: true, cardLayout: true, showTitle: true, - showYear: true + showYear: true, + vibrant: true }); } else if (viewStyle == "Banner") { @@ -143,7 +144,8 @@ showTitle: true, showYear: true, lazy: true, - cardLayout: true + cardLayout: true, + vibrant: true }); } else { diff --git a/dashboard-ui/scripts/tvshows.js b/dashboard-ui/scripts/tvshows.js index a100b7b711..4830913407 100644 --- a/dashboard-ui/scripts/tvshows.js +++ b/dashboard-ui/scripts/tvshows.js @@ -113,7 +113,8 @@ lazy: true, cardLayout: true, showTitle: true, - showSeriesYear: true + showSeriesYear: true, + vibrant: true }); } else if (viewStyle == "Banner") { @@ -143,7 +144,8 @@ showTitle: true, showYear: true, lazy: true, - cardLayout: true + cardLayout: true, + vibrant: true }); } else {