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

Merge branch 'jellyfin:master' into master

This commit is contained in:
hazil 2021-09-04 17:35:05 +05:30 committed by Hazil Mohamed
commit 13f55130a7
98 changed files with 5871 additions and 3582 deletions

View file

@ -134,6 +134,7 @@
<option value="reinhard">Reinhard</option>
<option value="hable">Hable</option>
<option value="mobius">Mobius</option>
<option value="bt2390">BT.2390</option>
</select>
<div class="fieldDescription">
<a is="emby-linkbutton" rel="noopener noreferrer" class="button-link" href="http://ffmpeg.org/ffmpeg-all.html#tonemap_005fopencl" target="_blank">${TonemappingAlgorithmHelp}</a>

View file

@ -1,15 +1,12 @@
<div id="itemDetailPage" data-role="page" class="page libraryPage itemDetailPage noSecondaryNavPage selfBackdropPage" data-backbutton="true">
<div id="itemBackdrop" class="itemBackdrop">
</div>
<div id="itemBackdrop" class="itemBackdrop"></div>
<div class="detailLogo"></div>
<div class="detailPageWrapperContainer padded-bottom-page">
<div class="detailPagePrimaryContainer padded-left padded-right">
<div class="primaryImageWrapper hide">
<img id="primaryImage" />
</div>
<div class="infoWrapper infoText">
<div class="infoWrapper">
<div class="detailImageContainer padded-left"></div>
<div class="nameContainer"></div>
<div class="itemMiscInfo itemMiscInfo-primary" style="margin-bottom: 0.6em;"></div>
<div class="itemMiscInfo itemMiscInfo-secondary" style="margin-bottom: 0.6em;"></div>
@ -90,7 +87,6 @@
</div>
</div>
<div class="detailPageSecondaryContainer">
<div class="detailImageContainer padded-left"></div>
<div class="detailPageContent">
<div class="detailPagePrimaryContent padded-right">
<div class="detailSection">

View file

@ -367,6 +367,14 @@ function reloadPlayButtons(page, item) {
hideAll(page, 'btnShuffle');
}
const btnResume = page.querySelector('.mainDetailButtons .btnResume');
const btnPlay = page.querySelector('.mainDetailButtons .btnPlay');
if (layoutManager.tv && !btnResume.classList.contains('hide')) {
btnResume.classList.add('fab');
} else if (layoutManager.tv && btnResume.classList.contains('hide')) {
btnPlay.classList.add('fab');
}
return canPlay;
}
@ -552,14 +560,20 @@ function renderBackdrop(item) {
}
function renderDetailPageBackdrop(page, item, apiClient) {
// Details banner is disabled in user settings
if (!userSettings.detailsBanner()) {
return false;
}
// Disable item backdrop for books and people because they only have primary images
if (item.Type === 'Person' || item.Type === 'Book') {
return false;
}
let imgUrl;
let hasbackdrop = false;
const itemBackdropElement = page.querySelector('#itemBackdrop');
if (layoutManager.mobile || !userSettings.detailsBanner()) {
return false;
}
if (item.BackdropImageTags && item.BackdropImageTags.length) {
imgUrl = apiClient.getScaledImageUrl(item.Id, {
type: 'Backdrop',
@ -593,24 +607,6 @@ function renderDetailPageBackdrop(page, item, apiClient) {
return hasbackdrop;
}
function renderPrimaryImage(page, item, apiClient) {
if (item?.ImageTags?.Primary) {
const imageUrl = apiClient.getScaledImageUrl(item.Id, {
type: 'Primary',
maxWidth: dom.getScreenWidth(),
tag: item.ImageTags.Primary
});
const imageElem = page.querySelector('#primaryImage');
imageElem.src = imageUrl;
imageElem.alt = item.Name;
if (item.PrimaryImageAspectRatio === 1) {
imageElem.classList.add('aspect-square');
}
page.querySelector('.primaryImageWrapper')?.classList.remove('hide');
}
}
function reloadFromItem(instance, page, params, item, user) {
const apiClient = ServerConnections.getApiClient(item.ServerId);
@ -623,9 +619,7 @@ function reloadFromItem(instance, page, params, item, user) {
renderLogo(page, item, apiClient);
renderDetailPageBackdrop(page, item, apiClient);
}
if (layoutManager.mobile) {
renderPrimaryImage(page, item, apiClient);
}
renderBackdrop(item);
// Render the main information for the item
@ -812,8 +806,8 @@ function renderDetailImage(elem, item, imageLoader) {
overlayText: false,
transition: false,
disableIndicators: true,
overlayPlayButton: true,
action: 'play',
overlayPlayButton: layoutManager.mobile ? false : true,
action: layoutManager.mobile ? 'none' : 'play',
width: dom.getWindowSize().innerWidth * 0.25
});
@ -1216,11 +1210,9 @@ function renderMoreFromArtist(view, item, apiClient) {
};
if (item.Type === 'MusicArtist') {
query.ContributingArtistIds = item.Id;
} else if (apiClient.isMinServerVersion('3.4.1.18')) {
query.AlbumArtistIds = item.AlbumArtists[0].Id;
query.AlbumArtistIds = item.Id;
} else {
query.ArtistIds = item.AlbumArtists[0].Id;
query.AlbumArtistIds = item.AlbumArtists[0].Id;
}
apiClient.getItems(apiClient.getCurrentUserId(), query).then(function (result) {
@ -2063,16 +2055,6 @@ export default function (view, params) {
function init() {
const apiClient = getApiClient();
const btnResume = view.querySelector('.mainDetailButtons .btnResume');
const btnPlay = view.querySelector('.mainDetailButtons .btnPlay');
if (layoutManager.tv && !btnResume.classList.contains('hide')) {
btnResume.classList.add('fab');
btnResume.classList.add('detailFloatingButton');
} else if (layoutManager.tv && btnResume.classList.contains('hide')) {
btnPlay.classList.add('fab');
btnPlay.classList.add('detailFloatingButton');
}
view.querySelectorAll('.btnPlay');
bindAll(view, '.btnPlay', 'click', onPlayClick);
bindAll(view, '.btnResume', 'click', onPlayClick);

View file

@ -1115,7 +1115,11 @@ class ItemsView {
let imageType = userSettings.get(basekey + '-imageType');
if (!imageType && params.type === 'nextup') {
imageType = 'thumb';
if (userSettings.useEpisodeImagesInNextUpAndResume()) {
imageType = 'primary';
} else {
imageType = 'thumb';
}
}
return {

View file

@ -313,8 +313,8 @@ import { appRouter } from '../../../components/appRouter';
function onPointerMove(e) {
if ((e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse')) === 'mouse') {
const eventX = e.screenX || 0;
const eventY = e.screenY || 0;
const eventX = e.screenX || e.clientX || 0;
const eventY = e.screenY || e.clientY || 0;
const obj = lastPointerMoveData;
if (!obj) {
@ -716,6 +716,7 @@ import { appRouter } from '../../../components/appRouter';
} else {
nowPlayingPositionSlider.value = 0;
}
if (runtimeTicks && positionTicks != null && currentRuntimeTicks && !enableProgressByTimeOfDay && currentItem.RunTimeTicks && currentItem.Type !== 'Recording' && playbackRate !== null) {
endsAtText.innerHTML = '&nbsp;&nbsp;&nbsp;&nbsp;' + mediaInfo.getEndsAtFromPosition(runtimeTicks, positionTicks, playbackRate, true);
} else {
@ -902,7 +903,8 @@ import { appRouter } from '../../../components/appRouter';
actionsheet.show({
items: menuItems,
title: globalize.translate('Audio'),
positionTo: positionTo
positionTo: positionTo,
enableHistory: false
}).then(function (id) {
const index = parseInt(id);
@ -948,7 +950,8 @@ import { appRouter } from '../../../components/appRouter';
actionsheet.show({
title: globalize.translate('Subtitles'),
items: menuItems,
positionTo: positionTo
positionTo: positionTo,
enableHistory: false
}).then(function (id) {
const index = parseInt(id);

View file

@ -260,9 +260,9 @@ import cardBuilder from '../../../components/cardbuilder/cardBuilder';
const apiClient = getApiClient();
apiClient.getQuickConnect('Status')
.then(status => {
if (status !== 'Unavailable') {
apiClient.getQuickConnect('Enabled')
.then(enabled => {
if (enabled === true) {
view.querySelector('.btnQuick').classList.remove('hide');
}
})

View file

@ -119,6 +119,7 @@ import autoFocuser from '../../components/autoFocuser';
cardBuilder.buildCards(result.Items, {
itemsContainer: container,
preferThumb: true,
inheritThumb: !userSettings.useEpisodeImagesInNextUpAndResume(),
shape: getThumbShape(),
scalable: true,
overlayPlayButton: true,
@ -197,6 +198,7 @@ import autoFocuser from '../../components/autoFocuser';
parentContainer: section,
itemsContainer: container,
preferThumb: true,
inheritThumb: !userSettings.useEpisodeImagesInNextUpAndResume(),
shape: 'backdrop',
scalable: true,
showTitle: true,

View file

@ -12,6 +12,15 @@
</div>
</a>
<a is="emby-linkbutton" data-ripple="false" href="#" style="display:block;padding:0;margin:0;" class="lnkQuickConnectPreferences listItem-border hide">
<div class="listItem">
<em class="material-icons listItemIcon listItemIcon-transparent">tap_and_play</em>
<div class="listItemBody">
<div class="listItemBodyText">${QuickConnect}</div>
</div>
</div>
</a>
<a is="emby-linkbutton" data-ripple="false" href="#" style="display:block;padding:0;margin:0;" class="lnkDisplayPreferences listItem-border">
<div class="listItem">
<span class="material-icons listItemIcon listItemIcon-transparent tv"></span>
@ -48,16 +57,6 @@
</div>
</a>
<a is="emby-linkbutton" data-ripple="false" href="#" style="display:block;padding:0;margin:0;" class="lnkQuickConnectPreferences listItem-border hide">
<div class="listItem">
<em class="material-icons listItemIcon listItemIcon-transparent">tap_and_play</em>
<div class="listItemBody">
<div class="listItemBodyText">${QuickConnect}</div>
</div>
</div>
</a>
<a is="emby-linkbutton" data-ripple="false" href="#" style="display:block;padding:0;margin:0;" class="clientSettings listItem-border">
<div class="listItem">
<span class="material-icons listItemIcon listItemIcon-transparent devices_other"></span>

View file

@ -38,16 +38,15 @@ export default function (view, params) {
page.querySelector('.lnkControlsPreferences').classList.toggle('hide', layoutManager.mobile);
ApiClient.getQuickConnect('Status')
.then(status => {
if (status !== 'Unavailable') {
ApiClient.getQuickConnect('Enabled')
.then(enabled => {
if (enabled === true) {
page.querySelector('.lnkQuickConnectPreferences').classList.remove('hide');
}
})
.catch(() => {
console.debug('Failed to get QuickConnect status');
});
ApiClient.getUser(userId).then(function (user) {
page.querySelector('.headerUsername').innerHTML = user.Name;
if (user.Policy.IsAdministrator && !layoutManager.tv) {

View file

@ -1,6 +1,5 @@
import globalize from '../../../scripts/globalize';
import toast from '../../../components/toast/toast';
import Dashboard from '../../../scripts/clientUtils';
export const authorize = (code) => {
const url = ApiClient.getUrl('/QuickConnect/Authorize?Code=' + code);
@ -16,22 +15,3 @@ export const authorize = (code) => {
// prevent bubbling
return false;
};
export const activate = () => {
const url = ApiClient.getUrl('/QuickConnect/Activate');
return ApiClient.ajax({
type: 'POST',
url: url
}).then(() => {
toast(globalize.translate('QuickConnectActivationSuccessful'));
return true;
}).catch((e) => {
console.error('Error activating quick connect. Error:', e);
Dashboard.alert({
title: globalize.translate('HeaderError'),
message: globalize.translate('DefaultErrorMessage')
});
throw e;
});
};

View file

@ -1,19 +1,15 @@
<div id="quickConnectPreferencesPage" data-role="page" class="page libraryPage userPreferencesPage noSecondaryNavPage" data-title="${QuickConnect}" data-backbutton="true" style="margin: 0 auto; max-width: 54em">
<div class="settingsContainer padded-left padded-right padded-bottom-page">
<button is="emby-button" id="btnQuickConnectActivate" type="button" class="raised button-submit block">
<span>${ButtonActivate}</span>
</button>
<form class="quickConnectSettingsContainer">
<div style="margin-bottom: 1em">
${QuickConnectDescription}
</div>
<form class="quickConnectSettingsContainer">
<div class="verticalSection">
<h2 class="sectionTitle">${QuickConnect}</h2>
<div>${QuickConnectDescription}</div>
<br />
<div class="inputContainer">
<input is="emby-input" type="number" min="0" max="999999" required id="txtQuickConnectCode" label="${LabelQuickConnectCode}" autocomplete="off" />
</div>
<button id="btnQuickConnectAuthorize" is="emby-button" type="submit" class="raised button-submit block">
<span>${Authorize}</span>
</button>
</form>
</div>
</div>
</form>
</div>

View file

@ -1,4 +1,4 @@
import { activate, authorize } from './helper';
import { authorize } from './helper';
import globalize from '../../../scripts/globalize';
import toast from '../../../components/toast/toast';
@ -6,52 +6,16 @@ export default function (view) {
view.addEventListener('viewshow', function () {
const codeElement = view.querySelector('#txtQuickConnectCode');
view.querySelector('#btnQuickConnectActivate').addEventListener('click', () => {
activate().then(() => {
renderPage();
});
});
view.querySelector('.quickConnectSettingsContainer').addEventListener('submit', (e) => {
e.preventDefault();
view.querySelector('#btnQuickConnectAuthorize').addEventListener('click', () => {
if (!codeElement.validity.valid) {
toast(globalize.translate('QuickConnectInvalidCode'));
return;
}
const code = codeElement.value;
authorize(code);
authorize(codeElement.value);
});
view.querySelector('.quickConnectSettingsContainer').addEventListener('submit', (e) => {
e.preventDefault();
});
renderPage();
});
function renderPage(forceActive = false) {
ApiClient.getQuickConnect('Status').then((status) => {
const btn = view.querySelector('#btnQuickConnectActivate');
const container = view.querySelector('.quickConnectSettingsContainer');
// The activation button should only be visible when quick connect is unavailable (with the text replaced with an error) or when it is available (so it can be activated)
// The authorization container is only usable when quick connect is active, so it should be hidden otherwise
container.style.display = 'none';
if (status === 'Unavailable') {
btn.textContent = globalize.translate('QuickConnectNotAvailable');
btn.disabled = true;
btn.classList.remove('button-submit');
btn.classList.add('button');
} else if (status === 'Active' || forceActive) {
container.style.display = '';
btn.style.display = 'none';
}
return true;
}).catch((e) => {
throw e;
});
}
}