diff --git a/dashboard-ui/bower_components/emby-apiclient/.bower.json b/dashboard-ui/bower_components/emby-apiclient/.bower.json index d68eeba61f..945ed79613 100644 --- a/dashboard-ui/bower_components/emby-apiclient/.bower.json +++ b/dashboard-ui/bower_components/emby-apiclient/.bower.json @@ -16,12 +16,12 @@ }, "devDependencies": {}, "ignore": [], - "version": "1.1.64", - "_release": "1.1.64", + "version": "1.1.65", + "_release": "1.1.65", "_resolution": { "type": "version", - "tag": "1.1.64", - "commit": "a1d00ddc6a767b00a588729b13c8202b99b1eadb" + "tag": "1.1.65", + "commit": "7ba3ab66a503b3cf099ff63a7dc923490401c0bc" }, "_source": "https://github.com/MediaBrowser/Emby.ApiClient.Javascript.git", "_target": "^1.1.51", diff --git a/dashboard-ui/bower_components/emby-apiclient/connectionmanager.js b/dashboard-ui/bower_components/emby-apiclient/connectionmanager.js index 71845c59bf..68061a87cf 100644 --- a/dashboard-ui/bower_components/emby-apiclient/connectionmanager.js +++ b/dashboard-ui/bower_components/emby-apiclient/connectionmanager.js @@ -215,7 +215,7 @@ return connectUser; }; - var minServerVersion = '3.0.5882'; + var minServerVersion = '3.0.5911'; self.minServerVersion = function (val) { if (val) { diff --git a/dashboard-ui/bower_components/emby-webcomponents/.bower.json b/dashboard-ui/bower_components/emby-webcomponents/.bower.json index 3080f5b978..4480485a45 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.78", - "_release": "1.4.78", + "version": "1.4.91", + "_release": "1.4.91", "_resolution": { "type": "version", - "tag": "1.4.78", - "commit": "33c9381ec8872ebd87e46def5a2b86dcbf952f0d" + "tag": "1.4.91", + "commit": "a4c5466d5a59e57b157aa941fcadb1e0df602f75" }, "_source": "https://github.com/MediaBrowser/emby-webcomponents.git", "_target": "^1.2.0", diff --git a/dashboard-ui/bower_components/emby-webcomponents/actionsheet/actionsheet.js b/dashboard-ui/bower_components/emby-webcomponents/actionsheet/actionsheet.js index 3ff151b3dd..6d40530d21 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/actionsheet/actionsheet.js +++ b/dashboard-ui/bower_components/emby-webcomponents/actionsheet/actionsheet.js @@ -112,8 +112,8 @@ } else { dialogOptions.modal = false; - dialogOptions.entryAnimationDuration = 160; - dialogOptions.exitAnimationDuration = 200; + dialogOptions.entryAnimationDuration = 140; + dialogOptions.exitAnimationDuration = 180; dialogOptions.autoFocus = false; } diff --git a/dashboard-ui/bower_components/emby-webcomponents/browser.js b/dashboard-ui/bower_components/emby-webcomponents/browser.js index bb64e7b349..955c1dafc5 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/browser.js +++ b/dashboard-ui/bower_components/emby-webcomponents/browser.js @@ -134,7 +134,7 @@ browser.xboxOne = userAgent.toLowerCase().indexOf('xbox') != -1; browser.animate = document.documentElement.animate != null; - browser.tizen = userAgent.toLowerCase().indexOf('tizen') != -1; + browser.tizen = userAgent.toLowerCase().indexOf('tizen') != -1 || userAgent.toLowerCase().indexOf('smarthub') != -1; browser.web0s = userAgent.toLowerCase().indexOf('Web0S'.toLowerCase()) != -1; browser.tv = isTv(); diff --git a/dashboard-ui/bower_components/emby-webcomponents/emby-itemscontainer/emby-itemscontainer.js b/dashboard-ui/bower_components/emby-webcomponents/emby-itemscontainer/emby-itemscontainer.js new file mode 100644 index 0000000000..751c121495 --- /dev/null +++ b/dashboard-ui/bower_components/emby-webcomponents/emby-itemscontainer/emby-itemscontainer.js @@ -0,0 +1,111 @@ +define(['itemShortcuts', 'connectionManager', 'registerElement'], function (itemShortcuts, connectionManager) { + + var ItemsContainerProtoType = Object.create(HTMLDivElement.prototype); + + function parentWithClass(elem, className) { + + while (!elem.classList || !elem.classList.contains(className)) { + elem = elem.parentNode; + + if (!elem) { + return null; + } + } + + return elem; + } + + function parentWithAttribute(elem, name) { + + while (!elem.getAttribute(name)) { + elem = elem.parentNode; + + if (!elem) { + return null; + } + } + + return elem; + } + + function getItem(button) { + + button = parentWithAttribute(button, 'data-id'); + var serverId = button.getAttribute('data-serverid'); + var id = button.getAttribute('data-id'); + var type = button.getAttribute('data-type'); + + var apiClient = connectionManager.getApiClient(serverId); + + return apiClient.getItem(apiClient.getCurrentUserId(), id); + } + + function showContextMenu(button, itemsContainer) { + + getItem(button).then(function (item) { + + var playlistId = itemsContainer.getAttribute('data-playlistid'); + var collectionId = itemsContainer.getAttribute('data-collectionid'); + + if (playlistId) { + var elem = parentWithAttribute(button, 'data-playlistitemid'); + item.PlaylistItemId = elem ? elem.getAttribute('data-playlistitemid') : null; + } + + require(['itemContextMenu'], function (itemContextMenu) { + itemContextMenu.show({ + positionTo: button, + item: item, + play: true, + queue: true, + playAllFromHere: !item.IsFolder, + queueAllFromHere: !item.IsFolder, + identify: false, + playlistId: playlistId, + collectionId: collectionId + + }).then(function (result) { + + if (result.command == 'playallfromhere' || result.command == 'queueallfromhere') { + itemShortcuts.execute(button, result.command); + } + else if (result.command == 'removefromplaylist' || result.command == 'removefromcollection') { + + itemsContainer.dispatchEvent(new CustomEvent('needsrefresh', { + detail: {}, + cancelable: false, + bubbles: true + })); + } + }); + }); + }); + } + + function onClick(e) { + + var itemsContainer = this; + + var menuButton = parentWithClass(e.target, 'menuButton'); + if (menuButton) { + showContextMenu(menuButton, itemsContainer); + e.stopPropagation(); + return false; + } + } + + ItemsContainerProtoType.attachedCallback = function () { + this.addEventListener('click', onClick); + itemShortcuts.on(this); + }; + + ItemsContainerProtoType.detachedCallback = function () { + this.removeEventListener('click', onClick); + itemShortcuts.off(this); + }; + + document.registerElement('emby-itemscontainer', { + prototype: ItemsContainerProtoType, + extends: 'div' + }); +}); \ No newline at end of file diff --git a/dashboard-ui/bower_components/emby-webcomponents/indicators/indicators.css b/dashboard-ui/bower_components/emby-webcomponents/indicators/indicators.css index 0ce002f1a1..dc35703038 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/indicators/indicators.css +++ b/dashboard-ui/bower_components/emby-webcomponents/indicators/indicators.css @@ -8,8 +8,58 @@ top: 0; left: 0; bottom: 0; + background-color: #52B54B; } .timerIndicator { color: #CB272A; -} \ No newline at end of file +} + +.indicator + .indicator { + margin-left: .25em; +} + +.countIndicator { + background: rgba(82,181,75,1); + border-radius: 500px; + display: -ms-flex; + display: -webkit-flex; + display: flex; + align-items: center; + justify-content: center; + font-weight: 500; + color: #fff; +} + +.playedIndicator { + background: rgba(82,181,75,1); + border-radius: 500px; + display: -ms-flex; + display: -webkit-flex; + display: flex; + align-items: center; + justify-content: center; + color: #fff; +} + +.countIndicator, .playedIndicator { + width: 28px; + height: 28px; +} + + .playedIndicator i { + width: 22px; + height: 22px; + font-size: 22px; + } + +.layout-tv .countIndicator, .layout-tv .playedIndicator { + width: 3.8vh; + height: 3.8vh; +} + + .layout-tv .playedIndicator i { + width: 2.6vh; + height: 2.6vh; + font-size: 2.6vh; + } diff --git a/dashboard-ui/bower_components/emby-webcomponents/itemcontextmenu.js b/dashboard-ui/bower_components/emby-webcomponents/itemcontextmenu.js index 67b09637a1..8d8afc0752 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/itemcontextmenu.js +++ b/dashboard-ui/bower_components/emby-webcomponents/itemcontextmenu.js @@ -1,4 +1,9 @@ -define(['apphost', 'globalize', 'connectionManager', 'itemHelper'], function (appHost, globalize, connectionManager, itemHelper) { +define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'embyRouter', 'playbackManager'], function (appHost, globalize, connectionManager, itemHelper, embyRouter, playbackManager) { + + var isTheater = true; + appHost.appInfo().then(function (result) { + isTheater = result.appName.toLowerCase().indexOf('theater') != -1; + }); function getCommands(options) { @@ -7,6 +12,8 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper'], function (ap var serverId = item.ServerId; var apiClient = connectionManager.getApiClient(serverId); + var canPlay = playbackManager.canPlay(item); + return apiClient.getCurrentUser().then(function (user) { var commands = []; @@ -32,12 +39,25 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper'], function (ap }); } - if (user.Policy.IsAdministrator) { - if (item.MediaType == 'Video' && item.Type != 'TvChannel' && item.Type != 'Program' && item.LocationType != 'Virtual') { - commands.push({ - name: globalize.translate('sharedcomponents#EditSubtitles'), - id: 'editsubtitles' - }); + if (options.edit !== false) { + if (itemHelper.canEdit(user, item.Type)) { + + if (!isTheater) { + commands.push({ + name: globalize.translate('sharedcomponents#EditInfo'), + id: 'edit' + }); + commands.push({ + name: globalize.translate('sharedcomponents#EditImages'), + id: 'editimages' + }); + } + if (item.MediaType == 'Video' && item.Type != 'TvChannel' && item.Type != 'Program' && item.LocationType != 'Virtual') { + commands.push({ + name: globalize.translate('sharedcomponents#EditSubtitles'), + id: 'editsubtitles' + }); + } } } @@ -48,18 +68,135 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper'], function (ap }); } - if (user.Policy.IsAdministrator) { + if (!isTheater && options.identify !== false) { + if (itemHelper.canIdentify(user, item.Type)) { + commands.push({ + name: globalize.translate('sharedcomponents#Identify'), + id: 'identify' + }); + } + } + + if (item.MediaType == "Audio" || item.Type == "MusicAlbum" || item.Type == "MusicArtist" || item.Type == "MusicGenre" || item.CollectionType == "music") { + if (options.instantMix !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#InstantMix'), + id: 'instantmix' + }); + } + } + + if (options.open !== false) { + if (item.Type != 'Timer' && item.Type != 'Audio') { + commands.push({ + name: globalize.translate('sharedcomponents#Open'), + id: 'open' + }); + } + } + + if (canPlay) { + if (options.play !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#Play'), + id: 'resume' + }); + } + + if (options.playAllFromHere) { + commands.push({ + name: globalize.translate('sharedcomponents#PlayAllFromHere'), + id: 'playallfromhere' + }); + } + + if (playbackManager.canQueueMediaType(item.MediaType)) { + if (options.queue !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#Queue'), + id: 'queue' + }); + } + + if (options.queueAllFromHere) { + commands.push({ + name: globalize.translate('sharedcomponents#QueueAllFromHere'), + id: 'queueallfromhere' + }); + } + } + } + + if (item.Type == 'Program' && (!item.TimerId && !item.SeriesTimerId)) { commands.push({ - name: globalize.translate('Refresh'), - id: 'refresh' + name: Globalize.translate('sharedcomponents#Record'), + id: 'record' }); } - if (item.Type != 'Timer' && user.Policy.EnablePublicSharing && appHost.supports('sharing')) { + if (user.Policy.IsAdministrator) { + + if (item.Type != 'Timer') { + commands.push({ + name: globalize.translate('sharedcomponents#Refresh'), + id: 'refresh' + }); + } + } + + if (item.PlaylistItemId && options.playlistId) { commands.push({ - name: globalize.translate('Share'), - id: 'share' + name: globalize.translate('sharedcomponents#RemoveFromPlaylist'), + id: 'removefromplaylist' + }); + } + + if (options.collectionId) { + commands.push({ + name: globalize.translate('sharedcomponents#RemoveFromCollection'), + id: 'removefromcollection' + }); + } + + if (options.share !== false) { + if (itemHelper.canShare(user, item)) { + commands.push({ + name: globalize.translate('sharedcomponents#Share'), + id: 'share' + }); + } + } + + if (item.IsFolder || item.Type == "MusicArtist" || item.Type == "MusicGenre") { + if (options.shuffle !== false) { + commands.push({ + name: globalize.translate('sharedcomponents#Shuffle'), + id: 'shuffle' + }); + } + } + + if (!isTheater && options.sync !== false) { + if (itemHelper.canSync(user, item)) { + commands.push({ + name: globalize.translate('sharedcomponents#Sync'), + id: 'sync' + }); + } + } + + if (options.openAlbum !== false && item.AlbumId) { + commands.push({ + name: Globalize.translate('sharedcomponents#ViewAlbum'), + id: 'album' + }); + } + + if (options.openArtist !== false && item.ArtistItems && item.ArtistItems.length) { + commands.push({ + name: Globalize.translate('sharedcomponents#ViewArtist'), + id: 'artist' }); } @@ -67,7 +204,18 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper'], function (ap }); } - function executeCommand(item, id) { + function getResolveFunction(resolve, id, changed, deleted) { + + return function () { + resolve({ + command: id, + updated: changed, + deleted: deleted + }); + }; + } + + function executeCommand(item, id, options) { var itemId = item.Id; var serverId = item.ServerId; @@ -85,7 +233,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper'], function (ap items: [itemId], serverId: serverId - }).then(reject, reject); + }).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); }); break; } @@ -97,7 +245,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper'], function (ap items: [itemId], serverId: serverId - }).then(reject, reject); + }).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); }); break; } @@ -115,7 +263,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper'], function (ap serverId: serverId }]); - reject(); + getResolveFunction(getResolveFunction(resolve, id), id)(); }); break; @@ -125,21 +273,81 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper'], function (ap require(['subtitleEditor'], function (subtitleEditor) { var serverId = apiClient.serverInfo().Id; - subtitleEditor.show(itemId, serverId).then(resolve, reject); + subtitleEditor.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); + }); + break; + } + case 'edit': + { + editItem(apiClient, item).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); + break; + } + case 'editimages': + { + require(['components/imageeditor/imageeditor'], function (ImageEditor) { + + ImageEditor.show(itemId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); + }); + break; + } + case 'identify': + { + require(['components/itemidentifier/itemidentifier'], function (itemidentifier) { + + itemidentifier.show(itemId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); }); break; } case 'refresh': { refresh(apiClient, itemId); - reject(); + getResolveFunction(resolve, id)(); + break; + } + case 'open': + { + embyRouter.showItem(item); + getResolveFunction(resolve, id)(); + break; + } + case 'play': + { + play(item, false); + getResolveFunction(resolve, id)(); + break; + } + case 'resume': + { + play(item, true); + getResolveFunction(resolve, id)(); + break; + } + case 'queue': + { + play(item, false, true); + getResolveFunction(resolve, id)(); + break; + } + case 'record': + require(['recordingCreator'], function (recordingCreator) { + recordingCreator.show(itemId, serverId).then(getResolveFunction(resolve, id, true), getResolveFunction(resolve, id)); + }); + break; + case 'shuffle': + { + playbackManager.shuffle(item); + getResolveFunction(resolve, id)(); + break; + } + case 'instantmix': + { + playbackManager.instantMix(item); + getResolveFunction(resolve, id)(); break; } case 'delete': { - deleteItem(apiClient, itemId).then(function () { - resolve(true); - }); + deleteItem(apiClient, itemId).then(getResolveFunction(resolve, id, true, true), getResolveFunction(resolve, id)); break; } case 'share': @@ -149,10 +357,76 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper'], function (ap serverId: serverId, itemId: itemId - }).then(reject); + }).then(getResolveFunction(resolve, id)); }); break; } + case 'album': + { + embyRouter.showItem(item.AlbumId, item.ServerId); + getResolveFunction(resolve, id)(); + break; + } + case 'artist': + { + embyRouter.showItem(item.ArtistItems[0].Id, item.ServerId); + getResolveFunction(resolve, id)(); + break; + } + case 'playallfromhere': + { + getResolveFunction(resolve, id)(); + break; + } + case 'queueallfromhere': + { + getResolveFunction(resolve, id)(); + break; + } + case 'sync': + { + require(['syncDialog'], function (syncDialog) { + syncDialog.showMenu({ + items: [ + { + Id: itemId + }] + }); + }); + getResolveFunction(resolve, id)(); + break; + } + case 'removefromplaylist': + + apiClient.ajax({ + + url: apiClient.getUrl('Playlists/' + options.playlistId + '/Items', { + EntryIds: [item.PlaylistItemId].join(',') + }), + + type: 'DELETE' + + }).then(function () { + + getResolveFunction(resolve, id, true)(); + }); + + break; + case 'removefromcollection': + + apiClient.ajax({ + type: "DELETE", + url: apiClient.getUrl("Collections/" + options.collectionId + "/Items", { + + Ids: [item.Id].join(',') + }) + + }).then(function () { + + getResolveFunction(resolve, id, true)(); + }); + + break; default: reject(); break; @@ -160,6 +434,40 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper'], function (ap }); } + function play(item, resume, queue) { + + var method = queue ? 'queue' : 'play'; + + if (item.Type == 'Program') { + playbackManager[method]({ + ids: [item.ChannelId] + }); + } else { + playbackManager[method]({ + items: [item] + }); + } + } + + function editItem(apiClient, item) { + + return new Promise(function (resolve, reject) { + + if (item.Type == 'Timer') { + require(['recordingEditor'], function (recordingEditor) { + + var serverId = apiClient.serverInfo().Id; + recordingEditor.show(item.Id, serverId).then(resolve, reject); + }); + } else { + require(['components/metadataeditor/metadataeditor'], function (metadataeditor) { + + metadataeditor.show(item.Id).then(resolve, reject); + }); + } + }); + } + function deleteItem(apiClient, itemId) { return new Promise(function (resolve, reject) { @@ -200,9 +508,12 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper'], function (ap require(['actionsheet'], function (actionSheet) { actionSheet.show({ - items: commands + + items: commands, + positionTo: options.positionTo + }).then(function (id) { - executeCommand(options.item, id).then(resolve); + executeCommand(options.item, id, options).then(resolve); }, reject); }); }); diff --git a/dashboard-ui/bower_components/emby-webcomponents/itemhelper.js b/dashboard-ui/bower_components/emby-webcomponents/itemhelper.js index 1056f685f2..65bb913559 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/itemhelper.js +++ b/dashboard-ui/bower_components/emby-webcomponents/itemhelper.js @@ -1,4 +1,4 @@ -define([], function () { +define(['apphost'], function (appHost) { function getDisplayName(item, options) { @@ -49,6 +49,11 @@ define([], function () { } function supportsAddingToCollection(item) { + + if (item.Type == 'Timer') { + return false; + } + var invalidTypes = ['Person', 'Genre', 'MusicGenre', 'Studio', 'GameGenre', 'BoxSet', 'Playlist', 'UserView', 'CollectionFolder', 'Audio', 'TvChannel', 'Program', 'MusicAlbum', 'Timer']; return !item.CollectionType && invalidTypes.indexOf(item.Type) == -1 && item.MediaType != 'Photo'; @@ -67,6 +72,58 @@ define([], function () { return { getDisplayName: getDisplayName, supportsAddingToCollection: supportsAddingToCollection, - supportsAddingToPlaylist: supportsAddingToPlaylist + supportsAddingToPlaylist: supportsAddingToPlaylist, + + canIdentify: function (user, itemType) { + + if (itemType == "Movie" || + itemType == "Trailer" || + itemType == "Series" || + itemType == "Game" || + itemType == "BoxSet" || + itemType == "Person" || + itemType == "Book" || + itemType == "MusicAlbum" || + itemType == "MusicArtist") { + + if (user.Policy.IsAdministrator) { + + return true; + } + } + + return false; + }, + + canEdit: function (user, itemType) { + + if (itemType == "UserRootFolder" || /*itemType == "CollectionFolder" ||*/ itemType == "UserView") { + return false; + } + + if (user.Policy.IsAdministrator) { + + return true; + } + + return false; + }, + + canSync: function (user, item) { + + if (user && !user.Policy.EnableSync) { + return false; + } + + return item.SupportsSync; + }, + + canShare: function (user, item) { + + if (item.Type == 'Timer') { + return false; + } + return user.Policy.EnablePublicSharing && appHost.supports('sharing'); + } }; }); \ No newline at end of file diff --git a/dashboard-ui/bower_components/emby-webcomponents/listview/listview.css b/dashboard-ui/bower_components/emby-webcomponents/listview/listview.css index 4b6d505654..539d832121 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/listview/listview.css +++ b/dashboard-ui/bower_components/emby-webcomponents/listview/listview.css @@ -1,6 +1,7 @@ button.listItem { background: transparent; border: 0 !important; + border-bottom: 1px solid #2a2a2a !important; cursor: pointer; outline: none !important; color: inherit; @@ -11,29 +12,43 @@ button.listItem { } .listItem { + margin: 0; display: block; align-items: center; text-align: left; - padding: 0 1em !important; + padding: .25em .25em .25em .25em !important; line-height: 170%; + border-bottom: 1px solid #2a2a2a; } - .listItem.largeImage { - padding: 1em 0 1em 1em; - } +div.listItem { + cursor: pointer; +} - .listItem > *:not(.listItemBody) { - flex-shrink: 0; - } +.listItem.largeImage { + padding: .5em !important; +} - .listItem > * { - display: inline-block; - vertical-align: middle; - } +.listItem > *:not(.listItemBody) { + flex-shrink: 0; +} + +.listItem > * { + display: inline-block; + vertical-align: middle; +} + +.listItem [is=paper-icon-button-light] { + margin: 0; +} + +.listViewDragHandle { + margin-left: -.25em !important; +} .listItemBody { flex-grow: 1; - padding: 0 1.15em; + padding: 0 1em; overflow: hidden; text-overflow: ellipsis; flex-direction: column; @@ -54,9 +69,8 @@ button.listItem { padding-bottom: 0; } - .listItemBody h3 { + .listItemBody h2, .listItemBody h3 { margin: 0; - font-weight: normal; padding: 0; overflow: hidden; text-overflow: ellipsis; @@ -78,10 +92,13 @@ button.listItem { .listItemImage { width: 7.4vh; height: 7.4vh; + min-width: 40px; + min-height: 40px; background-repeat: no-repeat; background-size: contain; flex-shrink: 0; - margin-left: -.75em; + background-position: center center; + position: relative; } .listItemIcon { @@ -94,7 +111,6 @@ button.listItem { width: 45vh; height: 30vh; background-position: center center; - position: relative; margin-right: 2%; margin-left: 1%; } @@ -133,10 +149,48 @@ button.listItem { background-color: transparent !important; } +.listItemMediaInfo { + align-items: center; +} + +.layout-tv .listItemMediaInfo { + margin: .5em 0; +} + +.listItemMediaInfo > * { + display: inline-block; +} + +.listGroupHeader { + margin: 2em 0 1em; +} + + .listGroupHeader.first { + margin-top: 0; + } + +.listItem .indicators { + right: .5vh; + top: .5vh; + position: absolute; + display: flex; + align-items: center; +} @supports (display: flex) { - .listItem, .listItemBody { + .listItem > * { + display: flex; + } + + .listItem, .listItemBody, .listItemMediaInfo { display: flex; } } + +@media all and (max-width: 800px) { + + .listItem .endsAt, .listItem .criticRating { + display: none !important; + } +} diff --git a/dashboard-ui/bower_components/emby-webcomponents/listview/listview.js b/dashboard-ui/bower_components/emby-webcomponents/listview/listview.js index f987dc5981..a2d52f8edc 100644 --- a/dashboard-ui/bower_components/emby-webcomponents/listview/listview.js +++ b/dashboard-ui/bower_components/emby-webcomponents/listview/listview.js @@ -1,8 +1,116 @@ -define(['itemHelper', 'mediaInfo', 'indicators', 'css!./listview'], function (itemHelper, mediaInfo, indicators) { +define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutManager', 'globalize', 'userdataButtons', 'css!./listview'], function (itemHelper, mediaInfo, indicators, connectionManager, layoutManager, globalize, userdataButtons) { + + function getIndex(item, options) { + + if (options.index == 'disc') { + + return item.ParentIndexNumber == null ? '' : globalize.translate('sharedcomponents#ValueDiscNumber', item.ParentIndexNumber); + } + + var sortBy = (options.sortBy || '').toLowerCase(); + var code, name; + + if (sortBy.indexOf('sortname') == 0) { + + if (item.Type == 'Episode') return ''; + + // SortName + name = (item.SortName || item.Name || '?')[0].toUpperCase(); + + code = name.charCodeAt(0); + if (code < 65 || code > 90) { + return '#'; + } + + return name.toUpperCase(); + } + if (sortBy.indexOf('officialrating') == 0) { + + return item.OfficialRating || globalize.translate('sharedcomponents#Unrated'); + } + if (sortBy.indexOf('communityrating') == 0) { + + if (item.CommunityRating == null) { + return globalize.translate('sharedcomponents#Unrated'); + } + + return Math.floor(item.CommunityRating); + } + if (sortBy.indexOf('criticrating') == 0) { + + if (item.CriticRating == null) { + return globalize.translate('sharedcomponents#Unrated'); + } + + return Math.floor(item.CriticRating); + } + if (sortBy.indexOf('metascore') == 0) { + + if (item.Metascore == null) { + return globalize.translate('sharedcomponents#Unrated'); + } + + return Math.floor(item.Metascore); + } + if (sortBy.indexOf('albumartist') == 0) { + + // SortName + if (!item.AlbumArtist) return ''; + + name = item.AlbumArtist[0].toUpperCase(); + + code = name.charCodeAt(0); + if (code < 65 || code > 90) { + return '#'; + } + + return name.toUpperCase(); + } + return ''; + } + + function getImageUrl(item, width) { + + var apiClient = connectionManager.getApiClient(item.ServerId); + + var options = { + width: width, + type: "Primary" + }; + + if (item.ImageTags && item.ImageTags['Primary']) { + + options.tag = item.ImageTags['Primary']; + return apiClient.getScaledImageUrl(item.Id, options); + } + + if (item.AlbumId && item.AlbumPrimaryImageTag) { + + options.tag = item.AlbumPrimaryImageTag; + return apiClient.getScaledImageUrl(item.AlbumId, options); + } + + else if (item.SeriesId && item.SeriesPrimaryImageTag) { + + options.tag = item.SeriesPrimaryImageTag; + return apiClient.getScaledImageUrl(item.SeriesId, options); + + } + else if (item.ParentPrimaryImageTag) { + + options.tag = item.ParentPrimaryImageTag; + return apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, options); + } + + return null; + } function getListViewHtml(items, options) { - var outerHtml = ""; + if (arguments.length == 1) { + options = items; + items = options.items; + } var index = 0; var groupTitle = ''; @@ -11,11 +119,46 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'css!./listview'], function (it var isLargeStyle = options.imageSize == 'large'; var enableOverview = options.enableOverview; + var clickEntireItem = layoutManager.tv ? true : false; + var outerTagName = clickEntireItem ? 'button' : 'div'; + var enableSideMediaInfo = options.enableSideMediaInfo != null ? options.enableSideMediaInfo : clickEntireItem; + + var outerHtml = ''; + outerHtml += items.map(function (item) { var html = ''; - var cssClass = "itemAction listItem"; + if (options.showIndex) { + + var itemGroupTitle = getIndex(item, options); + + if (itemGroupTitle != groupTitle) { + + if (html) { + html += ''; + } + + if (index == 0) { + html += '