1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Merge branch 'master' into networkChange

This commit is contained in:
BaronGreenback 2020-11-05 16:55:53 +00:00 committed by GitHub
commit 76e7262061
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
93 changed files with 4463 additions and 2977 deletions

View file

@ -16,6 +16,9 @@
</div>
<div style="margin-top:1em;">
<button is="emby-button" type="button" class="raised btnRefresh">
<span>${ButtonScanAllLibraries}</span>
</button>
<button is="emby-button" type="button" id="btnRestartServer" class="raised" onclick="DashboardPage.restart(this);" style="margin-left:0;">
<span>${Restart}</span>
</button>

View file

@ -3,6 +3,7 @@ import events from 'events';
import itemHelper from 'itemHelper';
import serverNotifications from 'serverNotifications';
import dom from 'dom';
import taskButton from 'scripts/taskbutton';
import globalize from 'globalize';
import * as datefns from 'date-fns';
import dfnshelper from 'dfnshelper';
@ -550,13 +551,13 @@ import 'emby-itemscontainer';
row.classList.remove('playingSession');
}
if (session.ServerId && session.SupportedCommands.indexOf('DisplayMessage') !== -1 && session.DeviceId !== window.connectionManager.deviceId()) {
if (session.ServerId && session.SupportedCommands.indexOf('DisplayMessage') !== -1) {
row.querySelector('.btnSessionSendMessage').classList.remove('hide');
} else {
row.querySelector('.btnSessionSendMessage').classList.add('hide');
}
if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons.length) {
if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo) {
row.querySelector('.btnSessionInfo').classList.remove('hide');
} else {
row.querySelector('.btnSessionInfo').classList.add('hide');
@ -564,7 +565,7 @@ import 'emby-itemscontainer';
const btnSessionPlayPause = row.querySelector('.btnSessionPlayPause');
if (session.ServerId && nowPlayingItem && session.SupportsRemoteControl && session.DeviceId !== window.connectionManager.deviceId()) {
if (session.ServerId && nowPlayingItem && session.SupportsRemoteControl) {
btnSessionPlayPause.classList.remove('hide');
row.querySelector('.btnSessionStop').classList.remove('hide');
} else {
@ -827,9 +828,17 @@ import 'emby-itemscontainer';
refreshActiveRecordings(view, apiClient);
loading.hide();
}
taskButton({
mode: 'on',
taskKey: 'RefreshLibrary',
button: page.querySelector('.btnRefresh')
});
});
view.addEventListener('viewbeforehide', function () {
const apiClient = ApiClient;
const page = this;
events.off(serverNotifications, 'RestartRequired', onRestartRequired);
events.off(serverNotifications, 'ServerShuttingDown', onServerShuttingDown);
events.off(serverNotifications, 'ServerRestarting', onServerRestarting);
@ -841,6 +850,12 @@ import 'emby-itemscontainer';
if (apiClient) {
DashboardPage.stopInterval(apiClient);
}
taskButton({
mode: 'off',
taskKey: 'RefreshLibrary',
button: page.querySelector('.btnRefresh')
});
});
view.addEventListener('viewdestroy', function () {
const page = this;

View file

@ -5,6 +5,7 @@
<div class="sectionTitleContainer sectionTitleContainer-cards flex align-items-center">
<h2 class="sectionTitle sectionTitle-cards">${HeaderDevices}</h2>
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://docs.jellyfin.org/general/server/devices.html">${Help}</a>
<button id="deviceDeleteAll" is="emby-button" type="button" class="raised button-alt">${DeleteAll}</button>
</div>
</div>
<div is="emby-itemscontainer" class="devicesList vertical-wrap" data-multiselect="false"></div>

View file

@ -10,10 +10,32 @@ import 'cardStyle';
/* eslint-disable indent */
// Local cache of loaded
let deviceIds = [];
function canDelete(deviceId) {
return deviceId !== ApiClient.deviceId();
}
function deleteAllDevices(page) {
const msg = globalize.translate('DeleteDevicesConfirmation');
require(['confirm'], async function (confirm) {
await confirm({
text: msg,
title: globalize.translate('HeaderDeleteDevices'),
confirmText: globalize.translate('ButtonDelete'),
primary: 'delete'
});
loading.show();
await Promise.all(
deviceIds.filter(canDelete).map((id) => ApiClient.deleteDevice(id))
);
loadData(page);
});
}
function deleteDevice(page, id) {
const msg = globalize.translate('DeleteDeviceConfirmation');
@ -23,16 +45,10 @@ import 'cardStyle';
title: globalize.translate('HeaderDeleteDevice'),
confirmText: globalize.translate('Delete'),
primary: 'delete'
}).then(function () {
}).then(async () => {
loading.show();
ApiClient.ajax({
type: 'DELETE',
url: ApiClient.getUrl('Devices', {
Id: id
})
}).then(function () {
loadData(page);
});
await ApiClient.deleteDevice(id);
loadData(page);
});
});
}
@ -129,6 +145,7 @@ import 'cardStyle';
loading.show();
ApiClient.getJSON(ApiClient.getUrl('Devices')).then(function (result) {
load(page, result.Items);
deviceIds = result.Items.map((device) => device.Id);
loading.hide();
});
}
@ -145,6 +162,9 @@ import 'cardStyle';
view.addEventListener('viewshow', function () {
loadData(this);
});
}
view.querySelector('#deviceDeleteAll').addEventListener('click', function() {
deleteAllDevices(view);
});
}
/* eslint-enable indent */

View file

@ -0,0 +1,24 @@
<div id="quickConnectPage" data-role="page" class="page type-interior advancedConfigurationPage">
<div class="content-primary">
<form class="quickConnectSettings">
<div class="verticalSection">
<div class="sectionTitleContainer flex align-items-center">
<h2 class="sectionTitle">${QuickConnect}</h2>
</div>
</div>
<div>${LabelCurrentStatus}<span id="quickConnectStatus" style="padding:0 0.4em;"></span></div>
<div class="checkboxList paperList" style="padding:.5em 1em;">
<label>
<input type="checkbox" is="emby-checkbox" id="chkQuickConnectAvailable" />
<span>${EnableQuickConnect}</span>
</label>
</div>
<button is="emby-button" id="btnQuickConnectSubmit" type="submit" class="raised button-submit block">
<span>${Save}</span>
</button>
</form>
</div>
</div>

View file

@ -140,32 +140,13 @@
</div>
<div class="fieldDescription">${OptionAllowRemoteSharedDevicesHelp}</div>
</div>
<div class="verticalSection">
<h2 class="checkboxListLabel">${HeaderDownloadSync}</h2>
<div class="checkboxList paperList" style="padding:.5em 1em;">
<label>
<input type="checkbox" is="emby-checkbox" id="chkEnableDownloading" />
<span>${OptionAllowContentDownloading}</span>
</label>
<label>
<input type="checkbox" is="emby-checkbox" id="chkEnableSyncTranscoding" />
<span>${OptionAllowSyncTranscoding}</span>
</label>
</div>
</div>
<h2 class="checkboxListLabel">${Other}</h2>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input type="checkbox" is="emby-checkbox" id="chkEnableConversion" />
<span>${AllowMediaConversion}</span>
<input type="checkbox" is="emby-checkbox" id="chkEnableDownloading" />
<span>${OptionAllowContentDownload}</span>
</label>
<div class="fieldDescription checkboxFieldDescription">${AllowMediaConversionHelp}</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label>
<input type="checkbox" is="emby-checkbox" id="chkEnableSharing" />
<span>${OptionAllowLinkSharing}</span>
</label>
<div class="fieldDescription checkboxFieldDescription sharingHelp"></div>
<div class="fieldDescription checkboxFieldDescription">${OptionAllowContentDownloadHelp}</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription" id="fldIsEnabled">
<label>

View file

@ -97,9 +97,6 @@ import globalize from 'globalize';
$('#chkEnableVideoPlaybackRemuxing', page).prop('checked', user.Policy.EnablePlaybackRemuxing);
$('#chkForceRemoteSourceTranscoding', page).prop('checked', user.Policy.ForceRemoteSourceTranscoding);
$('#chkRemoteAccess', page).prop('checked', user.Policy.EnableRemoteAccess == null || user.Policy.EnableRemoteAccess);
$('#chkEnableSyncTranscoding', page).prop('checked', user.Policy.EnableSyncTranscoding);
$('#chkEnableConversion', page).prop('checked', user.Policy.EnableMediaConversion || false);
$('#chkEnableSharing', page).prop('checked', user.Policy.EnablePublicSharing);
$('#txtRemoteClientBitrateLimit', page).val(user.Policy.RemoteClientBitrateLimit / 1e6 || '');
$('#txtLoginAttemptsBeforeLockout', page).val(user.Policy.LoginAttemptsBeforeLockout || '0');
$('#txtMaxActiveSessions', page).val(user.Policy.MaxActiveSessions || '0');
@ -133,9 +130,6 @@ import globalize from 'globalize';
user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).is(':checked');
user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).is(':checked');
user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).is(':checked');
user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).is(':checked');
user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).is(':checked');
user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).is(':checked');
user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).is(':checked');
user.Policy.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($('#txtRemoteClientBitrateLimit', page).val() || '0'));
user.Policy.LoginAttemptsBeforeLockout = parseInt($('#txtLoginAttemptsBeforeLockout', page).val() || '0');

View file

@ -51,7 +51,9 @@ import globalize from 'globalize';
$('.channelAccessContainer', page).hide();
}
$('#chkEnableAllChannels', page).prop('checked', user.Policy.EnableAllChannels);
const chkEnableAllChannels = page.querySelector('#chkEnableAllChannels');
chkEnableAllChannels.checked = user.Policy.EnableAllChannels;
triggerChange(chkEnableAllChannels);
}
function loadDevices(page, user, devices) {
@ -67,7 +69,9 @@ import globalize from 'globalize';
html += '</div>';
$('.deviceAccess', page).show().html(html);
$('#chkEnableAllDevices', page).prop('checked', user.Policy.EnableAllDevices);
const chkEnableAllDevices = page.querySelector('#chkEnableAllDevices');
chkEnableAllDevices.checked = user.Policy.EnableAllDevices;
triggerChange(chkEnableAllDevices);
if (user.Policy.IsAdministrator) {
page.querySelector('.deviceAccessContainer').classList.add('hide');

View file

@ -649,7 +649,10 @@ function reloadFromItem(instance, page, params, item, user) {
const itemBirthLocation = page.querySelector('#itemBirthLocation');
if (item.Type == 'Person' && item.ProductionLocations && item.ProductionLocations.length) {
const gmap = '<a is="emby-linkbutton" class="button-link textlink" target="_blank" href="https://maps.google.com/maps?q=' + item.ProductionLocations[0] + '">' + item.ProductionLocations[0] + '</a>';
let gmap = item.ProductionLocations[0];
if (!layoutManager.tv && appHost.supports('externallinks')) {
gmap = `<a is="emby-linkbutton" class="button-link textlink" target="_blank" href="https://maps.google.com/maps?q=${gmap}">${gmap}</a>`;
}
itemBirthLocation.classList.remove('hide');
itemBirthLocation.innerHTML = globalize.translate('BirthPlaceValue', gmap);
} else {
@ -1066,7 +1069,7 @@ function renderDetails(page, item, apiClient, context, isStatic) {
reloadUserDataButtons(page, item);
// Don't allow redirection to other websites from the TV layout
if (!layoutManager.tv) {
if (!layoutManager.tv && appHost.supports('externallinks')) {
renderLinks(page, item);
}
@ -1724,7 +1727,7 @@ function renderCollectionItemType(page, parentItem, type, items) {
html += '</div>';
const collectionItems = page.querySelector('.collectionItems');
collectionItems.insertAdjacentHTML('beforeend', html);
imageLoader.lazyChildren(collectionItems);
imageLoader.lazyChildren(collectionItems.lastChild);
}
function renderMusicVideos(page, item, user) {

View file

@ -248,7 +248,7 @@ import 'emby-itemscontainer';
tabContent.querySelector('.btnNewCollection').addEventListener('click', () => {
import('collectionEditor').then(({default: collectionEditor}) => {
const serverId = ApiClient.serverInfo().Id;
new collectionEditor.showEditor({
new collectionEditor({
items: [],
serverId: serverId
});

View file

@ -1,6 +1,6 @@
<div id="moviesPage" data-role="page" data-dom-cache="true" class="page libraryPage backdropPage collectionEditorPage pageWithAbsoluteTabs withTabs" data-backdroptype="movie">
<div class="pageTabContent" data-index="0">
<div class="pageTabContent" id="moviesTab" data-index="0">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
@ -17,7 +17,7 @@
<div class="paging"></div>
</div>
</div>
<div class="pageTabContent" data-index="1">
<div class="pageTabContent" id="suggestionsTab" data-index="1">
<div id="resumableSection" class="verticalSection hide">
<div class="sectionTitleContainer sectionTitleContainer-cards">
<h2 class="sectionTitle sectionTitle-cards padded-left">${HeaderContinueWatching}</h2>
@ -43,7 +43,7 @@
<p>${MessageNoMovieSuggestionsAvailable}</p>
</div>
</div>
<div class="pageTabContent" data-index="2">
<div class="pageTabContent" id="trailersTab" data-index="2">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
@ -59,7 +59,7 @@
<div class="paging"></div>
</div>
</div>
<div class="pageTabContent" data-index="3">
<div class="pageTabContent" id="favoritesTab" data-index="3">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
@ -71,7 +71,7 @@
<div class="paging"></div>
</div>
</div>
<div class="pageTabContent" data-index="4">
<div class="pageTabContent" id="collectionsTab" data-index="4">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
@ -85,9 +85,7 @@
<div class="paging"></div>
</div>
</div>
<div class="pageTabContent" data-index="5">
<div class="pageTabContent" id="genresTab" data-index="5">
<div id="items"></div>
</div>
<div class="pageTabContent" data-index="6">
</div>
</div>

View file

@ -320,11 +320,6 @@ import 'emby-button';
if (index === suggestionsTabIndex) {
controller = this;
} else if (index === 6) {
controller = new controllerFactory(view, tabContent, {
collectionType: 'movies',
parentId: params.topParentId
});
} else if (index == 0 || index == 3) {
controller = new controllerFactory(view, params, tabContent, {
mode: index ? 'favorites' : 'movies'

View file

@ -8,7 +8,26 @@
}
}
</style>
<div class="pageTabContent pageTabContent" id="suggestionsTab" data-index="0">
<div class="pageTabContent pageTabContent" id="albumsTab" data-index="0">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnPlayAll musicglobalButton" title="${HeaderPlayAll}"><span class="material-icons play_arrow"></span></button>
<button is="paper-icon-button-light" class="btnShuffle musicglobalButton" title="${Shuffle}"><span class="material-icons shuffle"></span></button>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div>
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical">
</div>
<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right">
</div>
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
</div>
</div>
<div class="pageTabContent pageTabContent" id="suggestionsTab" data-index="1">
<div class="verticalSection">
@ -34,25 +53,6 @@
<div class="favoriteSections verticalSection"></div>
</div>
<div class="pageTabContent pageTabContent" id="albumsTab" data-index="1">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnPlayAll musicglobalButton" title="${HeaderPlayAll}"><span class="material-icons play_arrow"></span></button>
<button is="paper-icon-button-light" class="btnShuffle musicglobalButton" title="${Shuffle}"><span class="material-icons shuffle"></span></button>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
<button is="paper-icon-button-light" class="btnSort autoSize" title="${Sort}"><span class="material-icons sort_by_alpha"></span></button>
<button is="paper-icon-button-light" class="btnFilter autoSize" title="${Filter}"><span class="material-icons filter_list"></span></button>
</div>
<div class="alphaPicker alphaPicker-fixed alphaPicker-vertical">
</div>
<div is="emby-itemscontainer" class="itemsContainer padded-left padded-right">
</div>
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
</div>
</div>
<div class="pageTabContent" id="albumArtistsTab" data-index="2">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
@ -85,7 +85,7 @@
<div class="paging"></div>
</div>
</div>
<div class="pageTabContent" data-index="4">
<div class="pageTabContent" id="playlistsTab" data-index="4">
<div is="emby-itemscontainer" id="items" class="itemsContainer padded-left padded-right padded-top vertical-wrap centered"></div>
</div>
@ -105,6 +105,4 @@
<div class="pageTabContent" id="genresTab" data-index="6">
<div is="emby-itemscontainer" id="items" class="itemsContainer padded-left padded-right padded-top vertical-wrap"></div>
</div>
<div class="pageTabContent" data-index="7">
</div>
</div>

View file

@ -177,9 +177,9 @@ import 'flexStyles';
function getTabs() {
return [{
name: globalize.translate('Suggestions')
}, {
name: globalize.translate('Albums')
}, {
name: globalize.translate('Suggestions')
}, {
name: globalize.translate('HeaderAlbumArtists')
}, {
@ -195,7 +195,7 @@ import 'flexStyles';
function getDefaultTabIndex(folderId) {
switch (userSettings.get('landing-' + folderId)) {
case 'albums':
case 'suggestions':
return 1;
case 'albumartists':
@ -221,7 +221,7 @@ import 'flexStyles';
export default function (view, params) {
function reload() {
loading.show();
const tabContent = view.querySelector(".pageTabContent[data-index='0']");
const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
loadSuggestionsTab(view, tabContent, params.topParentId);
}
@ -268,11 +268,11 @@ import 'flexStyles';
switch (index) {
case 0:
depends = 'controllers/music/musicrecommended';
depends = 'controllers/music/musicalbums';
break;
case 1:
depends = 'controllers/music/musicalbums';
depends = 'controllers/music/musicrecommended';
break;
case 2:
@ -296,7 +296,7 @@ import 'flexStyles';
import(depends).then(({default: controllerFactory}) => {
let tabContent;
if (index == 0) {
if (index == 1) {
tabContent = view.querySelector(".pageTabContent[data-index='" + index + "']");
this.tabContent = tabContent;
}
@ -306,13 +306,8 @@ import 'flexStyles';
if (!controller) {
tabContent = view.querySelector(".pageTabContent[data-index='" + index + "']");
if (index === 0) {
if (index === 1) {
controller = this;
} else if (index === 7) {
controller = new controllerFactory(view, tabContent, {
collectionType: 'music',
parentId: params.topParentId
});
} else {
controller = new controllerFactory(view, params, tabContent);
}
@ -360,9 +355,10 @@ import 'flexStyles';
}
let currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId));
const suggestionsTabIndex = 1;
this.initTab = function () {
const tabContent = view.querySelector(".pageTabContent[data-index='0']");
const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
const containers = tabContent.querySelectorAll('.itemsContainer');
for (let i = 0, length = containers.length; i < length; i++) {

View file

@ -1,68 +0,0 @@
import loading from 'loading';
import groupedcards from 'components/groupedcards';
import cardBuilder from 'cardBuilder';
import imageLoader from 'imageLoader';
/* eslint-disable indent */
function getLatestPromise(context, params) {
loading.show();
const userId = ApiClient.getCurrentUserId();
const parentId = params.topParentId;
const options = {
IncludeItemTypes: 'Episode',
Limit: 30,
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo',
ParentId: parentId,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb'
};
return ApiClient.getJSON(ApiClient.getUrl('Users/' + userId + '/Items/Latest', options));
}
function loadLatest(context, params, promise) {
promise.then(function (items) {
let html = '';
html += cardBuilder.getCardsHtml({
items: items,
shape: 'backdrop',
preferThumb: true,
showTitle: true,
showSeriesYear: true,
showParentTitle: true,
overlayText: false,
cardLayout: false,
showUnplayedIndicator: false,
showChildCountIndicator: true,
centerText: true,
lazy: true,
overlayPlayButton: true,
lines: 2
});
const elem = context.querySelector('#latestEpisodes');
elem.innerHTML = html;
imageLoader.lazyChildren(elem);
loading.hide();
import('autoFocuser').then(({default: autoFocuser}) => {
autoFocuser.autoFocus(context);
});
});
}
export default function (view, params, tabContent) {
const self = this;
let latestPromise;
self.preRender = function () {
latestPromise = getLatestPromise(view, params);
};
self.renderTab = function () {
loadLatest(tabContent, params, latestPromise);
};
tabContent.querySelector('#latestEpisodes').addEventListener('click', groupedcards);
}
/* eslint-enable indent */

View file

@ -23,8 +23,15 @@
<div is="emby-itemscontainer" id="resumableItems" class="itemsContainer padded-left padded-right"></div>
</div>
<div id="latestItemsSection" class="hide verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards">
<h2 class="sectionTitle sectionTitle-cards padded-left">${HeaderLatestEpisodes}</h2>
</div>
<div class="verticalSection">
<div is="emby-itemscontainer" id="latestEpisodesItems" class="itemsContainer padded-left padded-right"></div>
</div>
<div id="nextUpItemsSection" class="hide verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards">
<h2 class="sectionTitle sectionTitle-cards padded-left nextUpHeader">${NextUp}</h2>
</div>
@ -33,16 +40,7 @@
</div>
<p class="noNextUpItems" style="display: none;">${MessageNoNextUpItems}</p>
</div>
<div class="pageTabContent" id="latestTab" data-index="2">
<div class="verticalSection">
<div class="sectionTitleContainer sectionTitleContainer-cards">
<h2 class="sectionTitle sectionTitle-cards padded-left">${HeaderLatestEpisodes}</h2>
</div>
<div is="emby-itemscontainer" id="latestEpisodes" class="itemsContainer vertical-wrap padded-left padded-right">
</div>
</div>
</div>
<div class="pageTabContent" id="upcomingTab" data-index="3">
<div class="pageTabContent" id="upcomingTab" data-index="2">
<div id="upcomingItems">
</div>
<div class="noItemsMessage centerMessage" style="display: none;">
@ -50,13 +48,13 @@
<p>${MessagePleaseEnsureInternetMetadata}</p>
</div>
</div>
<div class="pageTabContent" id="genresTab" data-index="4">
<div class="pageTabContent" id="genresTab" data-index="3">
<div id="items"></div>
</div>
<div class="pageTabContent" id="studiosTab" data-index="5">
<div class="pageTabContent" id="studiosTab" data-index="4">
<div is="emby-itemscontainer" id="items" class="itemsContainer padded-left padded-right padded-top vertical-wrap" style="text-align: center;"></div>
</div>
<div class="pageTabContent" data-index="6">
<div class="pageTabContent" id="episodesTab" data-index="5">
<div class="flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom">
<div class="paging"></div>
<button is="paper-icon-button-light" class="btnSelectView autoSize" title="${ButtonSelectView}"><span class="material-icons view_comfy"></span></button>
@ -69,6 +67,4 @@
<div class="paging"></div>
</div>
</div>
<div class="pageTabContent" data-index="7">
</div>
</div>

View file

@ -20,8 +20,6 @@ import 'emby-button';
name: globalize.translate('Shows')
}, {
name: globalize.translate('Suggestions')
}, {
name: globalize.translate('TabLatest')
}, {
name: globalize.translate('TabUpcoming')
}, {
@ -38,15 +36,18 @@ import 'emby-button';
case 'suggestions':
return 1;
case 'latest':
case 'upcoming':
return 2;
case 'favorites':
return 1;
case 'genres':
return 3;
case 'networks':
return 4;
case 'episodes':
return 5;
default:
return 0;
}
@ -70,102 +71,159 @@ import 'emby-button';
}
}
function initSuggestedTab(page, tabContent) {
const containers = tabContent.querySelectorAll('.itemsContainer');
for (let i = 0, length = containers.length; i < length; i++) {
setScrollClasses(containers[i], enableScrollX());
}
}
function loadSuggestionsTab(view, params, tabContent) {
const parentId = params.topParentId;
const userId = ApiClient.getCurrentUserId();
console.debug('loadSuggestionsTab');
loadResume(tabContent, userId, parentId);
loadLatest(tabContent, userId, parentId);
loadNextUp(tabContent, userId, parentId);
}
function loadResume(view, userId, parentId) {
const screenWidth = dom.getWindowSize().innerWidth;
const options = {
SortBy: 'DatePlayed',
SortOrder: 'Descending',
IncludeItemTypes: 'Episode',
Filters: 'IsResumable',
Limit: screenWidth >= 1920 ? 5 : screenWidth >= 1600 ? 5 : 3,
Recursive: true,
Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo',
CollapseBoxSetItems: false,
ParentId: parentId,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
EnableTotalRecordCount: false
};
ApiClient.getItems(userId, options).then(function (result) {
if (result.Items.length) {
view.querySelector('#resumableSection').classList.remove('hide');
} else {
view.querySelector('#resumableSection').classList.add('hide');
}
const allowBottomPadding = !enableScrollX();
const container = view.querySelector('#resumableItems');
cardBuilder.buildCards(result.Items, {
itemsContainer: container,
preferThumb: true,
shape: getThumbShape(),
scalable: true,
overlayPlayButton: true,
allowBottomPadding: allowBottomPadding,
cardLayout: false,
showTitle: true,
showYear: true,
centerText: true
});
loading.hide();
import('autoFocuser').then(({default: autoFocuser}) => {
autoFocuser.autoFocus(view);
});
});
}
function loadLatest(view, userId, parentId) {
const options = {
userId: userId,
IncludeItemTypes: 'Episode',
Limit: 30,
Fields: 'PrimaryImageAspectRatio,BasicSyncInfo',
ParentId: parentId,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb'
};
ApiClient.getLatestItems(options).then(function (items) {
const section = view.querySelector('#latestItemsSection');
const allowBottomPadding = !enableScrollX();
const container = section.querySelector('#latestEpisodesItems');
cardBuilder.buildCards(items, {
parentContainer: section,
itemsContainer: container,
items: items,
shape: 'backdrop',
preferThumb: true,
showTitle: true,
showSeriesYear: true,
showParentTitle: true,
overlayText: false,
cardLayout: false,
allowBottomPadding: allowBottomPadding,
showUnplayedIndicator: false,
showChildCountIndicator: true,
centerText: true,
lazy: true,
overlayPlayButton: true,
lines: 2
});
loading.hide();
import('autoFocuser').then(({default: autoFocuser}) => {
autoFocuser.autoFocus(view);
});
});
}
function loadNextUp(view, userId, parentId) {
const query = {
userId: userId,
Limit: 24,
Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo',
ParentId: parentId,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb',
EnableTotalRecordCount: false
};
query.ParentId = libraryMenu.getTopParentId();
ApiClient.getNextUpEpisodes(query).then(function (result) {
if (result.Items.length) {
view.querySelector('.noNextUpItems').classList.add('hide');
} else {
view.querySelector('.noNextUpItems').classList.remove('hide');
}
const section = view.querySelector('#nextUpItemsSection');
const container = section.querySelector('#nextUpItems');
cardBuilder.buildCards(result.Items, {
parentContainer: section,
itemsContainer: container,
preferThumb: true,
shape: 'backdrop',
scalable: true,
showTitle: true,
showParentTitle: true,
overlayText: false,
centerText: true,
overlayPlayButton: true,
cardLayout: false
});
loading.hide();
import('autoFocuser').then(({default: autoFocuser}) => {
autoFocuser.autoFocus(view);
});
});
}
function enableScrollX() {
return !layoutManager.desktop;
}
function getThumbShape() {
return enableScrollX() ? 'overflowBackdrop' : 'backdrop';
}
export default function (view, params) {
function reload() {
loading.show();
loadResume();
loadNextUp();
}
function loadNextUp() {
const query = {
Limit: 24,
Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo',
UserId: ApiClient.getCurrentUserId(),
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb',
EnableTotalRecordCount: false
};
query.ParentId = libraryMenu.getTopParentId();
ApiClient.getNextUpEpisodes(query).then(function (result) {
if (result.Items.length) {
view.querySelector('.noNextUpItems').classList.add('hide');
} else {
view.querySelector('.noNextUpItems').classList.remove('hide');
}
const container = view.querySelector('#nextUpItems');
cardBuilder.buildCards(result.Items, {
itemsContainer: container,
preferThumb: true,
shape: 'backdrop',
scalable: true,
showTitle: true,
showParentTitle: true,
overlayText: false,
centerText: true,
overlayPlayButton: true,
cardLayout: false
});
loading.hide();
import('autoFocuser').then(({default: autoFocuser}) => {
autoFocuser.autoFocus(view);
});
});
}
function enableScrollX() {
return !layoutManager.desktop;
}
function getThumbShape() {
return enableScrollX() ? 'overflowBackdrop' : 'backdrop';
}
function loadResume() {
const parentId = libraryMenu.getTopParentId();
const screenWidth = dom.getWindowSize().innerWidth;
const limit = screenWidth >= 1600 ? 5 : 6;
const options = {
SortBy: 'DatePlayed',
SortOrder: 'Descending',
IncludeItemTypes: 'Episode',
Filters: 'IsResumable',
Limit: limit,
Recursive: true,
Fields: 'PrimaryImageAspectRatio,SeriesInfo,UserData,BasicSyncInfo',
ExcludeLocationTypes: 'Virtual',
ParentId: parentId,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Thumb',
EnableTotalRecordCount: false
};
ApiClient.getItems(ApiClient.getCurrentUserId(), options).then(function (result) {
if (result.Items.length) {
view.querySelector('#resumableSection').classList.remove('hide');
} else {
view.querySelector('#resumableSection').classList.add('hide');
}
const allowBottomPadding = !enableScrollX();
const container = view.querySelector('#resumableItems');
cardBuilder.buildCards(result.Items, {
itemsContainer: container,
preferThumb: true,
shape: getThumbShape(),
scalable: true,
showTitle: true,
showParentTitle: true,
overlayText: false,
centerText: true,
overlayPlayButton: true,
allowBottomPadding: allowBottomPadding,
cardLayout: false
});
});
}
function onBeforeTabChange(e) {
preLoadTab(view, parseInt(e.detail.selectedTabIndex));
}
@ -196,22 +254,18 @@ import 'emby-button';
break;
case 2:
depends = 'controllers/shows/tvlatest';
break;
case 3:
depends = 'controllers/shows/tvupcoming';
break;
case 4:
case 3:
depends = 'controllers/shows/tvgenres';
break;
case 5:
case 4:
depends = 'controllers/shows/tvstudios';
break;
case 6:
case 5:
depends = 'controllers/shows/episodes';
break;
}
@ -231,11 +285,6 @@ import 'emby-button';
if (index === 1) {
controller = self;
} else if (index === 7) {
controller = new controllerFactory(view, tabContent, {
collectionType: 'tvshows',
parentId: params.topParentId
});
} else {
controller = new controllerFactory(view, params, tabContent);
}
@ -294,19 +343,20 @@ import 'emby-button';
const self = this;
let currentTabIndex = parseInt(params.tab || getDefaultTabIndex(params.topParentId));
const suggestionsTabIndex = 1;
self.initTab = function () {
const tabContent = self.tabContent;
setScrollClasses(tabContent.querySelector('#resumableItems'), enableScrollX());
const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
initSuggestedTab(view, tabContent);
};
self.renderTab = function () {
reload();
const tabContent = view.querySelector(".pageTabContent[data-index='" + suggestionsTabIndex + "']");
loadSuggestionsTab(view, params, tabContent);
};
const tabControllers = [];
let renderedTabs = [];
setScrollClasses(view.querySelector('#resumableItems'), enableScrollX());
view.addEventListener('viewshow', function (e) {
initTabs();
if (!view.getAttribute('data-title')) {