mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge remote-tracking branch 'upstream/master' into bugfix/web0s-fullscreen
This commit is contained in:
commit
f925138695
98 changed files with 5870 additions and 3582 deletions
|
@ -13,6 +13,7 @@
|
|||
case 'Kodi':
|
||||
return baseUrl + 'kodi.svg';
|
||||
case 'Jellyfin Android':
|
||||
case 'AndroidTV':
|
||||
case 'Android TV':
|
||||
return baseUrl + 'android.svg';
|
||||
case 'Jellyfin Web':
|
||||
|
|
|
@ -54,8 +54,8 @@ import dom from '../scripts/dom';
|
|||
|
||||
let lastPointerMoveData;
|
||||
function onPointerMove(e) {
|
||||
const eventX = e.screenX;
|
||||
const eventY = e.screenY;
|
||||
const eventX = e.screenX || e.clientX;
|
||||
const eventY = e.screenY || e.clientY;
|
||||
|
||||
// if coord don't exist how could it move
|
||||
if (typeof eventX === 'undefined' && typeof eventY === 'undefined') {
|
||||
|
|
|
@ -103,6 +103,8 @@ function centerOnFocusVertical(e) {
|
|||
|
||||
export const centerFocus = {
|
||||
on: function (element, horizontal) {
|
||||
element.setAttribute(`data-scroll-mode-${horizontal ? 'x' : 'y'}`, 'custom');
|
||||
|
||||
if (horizontal) {
|
||||
dom.addEventListener(element, 'focus', centerOnFocusHorizontal, {
|
||||
capture: true,
|
||||
|
@ -116,6 +118,8 @@ export const centerFocus = {
|
|||
}
|
||||
},
|
||||
off: function (element, horizontal) {
|
||||
element.removeAttribute(`data-scroll-mode-${horizontal ? 'x' : 'y'}`);
|
||||
|
||||
if (horizontal) {
|
||||
dom.removeEventListener(element, 'focus', centerOnFocusHorizontal, {
|
||||
capture: true,
|
||||
|
|
|
@ -239,6 +239,32 @@ export class UserSettings {
|
|||
return val === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set 'disableCustomCss' state.
|
||||
* @param {boolean|undefined} val - Flag to enable 'disableCustomCss' or undefined.
|
||||
* @return {boolean} 'disableCustomCss' state.
|
||||
*/
|
||||
disableCustomCss(val) {
|
||||
if (val !== undefined) {
|
||||
return this.set('disableCustomCss', val.toString(), false);
|
||||
}
|
||||
|
||||
return this.get('disableCustomCss', false) === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set customCss.
|
||||
* @param {string|undefined} val - Language.
|
||||
* @return {string} Language.
|
||||
*/
|
||||
customCss(val) {
|
||||
if (val !== undefined) {
|
||||
return this.set('customCss', val.toString(), false);
|
||||
}
|
||||
|
||||
return this.get('customCss', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set 'Details Banner' state.
|
||||
* @param {boolean|undefined} val - Flag to enable 'Details Banner' or undefined.
|
||||
|
@ -253,6 +279,20 @@ export class UserSettings {
|
|||
return val !== 'false';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set 'Use Episode Images in Next Up and Continue Watching' state.
|
||||
* @param {string|boolean|undefined} val - Flag to enable 'Use Episode Images in Next Up and Continue Watching' or undefined.
|
||||
* @return {boolean} 'Use Episode Images in Next Up' state.
|
||||
*/
|
||||
useEpisodeImagesInNextUpAndResume(val) {
|
||||
if (val !== undefined) {
|
||||
return this.set('useEpisodeImagesInNextUpAndResume', val.toString(), true);
|
||||
}
|
||||
|
||||
val = this.get('useEpisodeImagesInNextUpAndResume', true);
|
||||
return val === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set language.
|
||||
* @param {string|undefined} val - Language.
|
||||
|
@ -494,6 +534,7 @@ export const enableFastFadein = currentSettings.enableFastFadein.bind(currentSet
|
|||
export const enableBlurhash = currentSettings.enableBlurhash.bind(currentSettings);
|
||||
export const enableBackdrops = currentSettings.enableBackdrops.bind(currentSettings);
|
||||
export const detailsBanner = currentSettings.detailsBanner.bind(currentSettings);
|
||||
export const useEpisodeImagesInNextUpAndResume = currentSettings.useEpisodeImagesInNextUpAndResume.bind(currentSettings);
|
||||
export const language = currentSettings.language.bind(currentSettings);
|
||||
export const dateTimeLocale = currentSettings.dateTimeLocale.bind(currentSettings);
|
||||
export const chromecastVersion = currentSettings.chromecastVersion.bind(currentSettings);
|
||||
|
@ -511,3 +552,5 @@ export const getSubtitleAppearanceSettings = currentSettings.getSubtitleAppearan
|
|||
export const setSubtitleAppearanceSettings = currentSettings.setSubtitleAppearanceSettings.bind(currentSettings);
|
||||
export const setFilter = currentSettings.setFilter.bind(currentSettings);
|
||||
export const getFilter = currentSettings.getFilter.bind(currentSettings);
|
||||
export const customCss = currentSettings.customCss.bind(currentSettings);
|
||||
export const disableCustomCss = currentSettings.disableCustomCss.bind(currentSettings);
|
||||
|
|
|
@ -1,30 +1,40 @@
|
|||
// TODO: This seems like a good candidate for deprecation
|
||||
export default {
|
||||
enableFullscreen: function() {
|
||||
window.NativeShell?.enableFullscreen();
|
||||
if (window.NativeShell?.enableFullscreen) {
|
||||
window.NativeShell.enableFullscreen();
|
||||
}
|
||||
},
|
||||
disableFullscreen: function() {
|
||||
window.NativeShell?.disableFullscreen();
|
||||
if (window.NativeShell?.disableFullscreen) {
|
||||
window.NativeShell.disableFullscreen();
|
||||
}
|
||||
},
|
||||
openUrl: function(url, target) {
|
||||
if (window.NativeShell) {
|
||||
if (window.NativeShell?.openUrl) {
|
||||
window.NativeShell.openUrl(url, target);
|
||||
} else {
|
||||
window.open(url, target || '_blank');
|
||||
}
|
||||
},
|
||||
updateMediaSession(mediaInfo) {
|
||||
window.NativeShell?.updateMediaSession(mediaInfo);
|
||||
if (window.NativeShell?.updateMediaSession) {
|
||||
window.NativeShell.updateMediaSession(mediaInfo);
|
||||
}
|
||||
},
|
||||
hideMediaSession() {
|
||||
window.NativeShell?.hideMediaSession();
|
||||
if (window.NativeShell?.hideMediaSession) {
|
||||
window.NativeShell.hideMediaSession();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Notify the NativeShell about volume level changes.
|
||||
* Useful for e.g. remote playback.
|
||||
*/
|
||||
updateVolumeLevel(volume) {
|
||||
window.NativeShell?.updateVolumeLevel(volume);
|
||||
if (window.NativeShell?.updateVolumeLevel) {
|
||||
window.NativeShell.updateVolumeLevel(volume);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Download specified files with NativeShell if possible
|
||||
|
@ -32,7 +42,7 @@ export default {
|
|||
* @returns true on success
|
||||
*/
|
||||
downloadFiles(items) {
|
||||
if (window.NativeShell) {
|
||||
if (window.NativeShell?.downloadFile) {
|
||||
items.forEach(item => window.NativeShell.downloadFile(item));
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import { playbackManager } from '../components/playback/playbackmanager';
|
|||
import SyncPlayNoActivePlayer from '../components/syncPlay/ui/players/NoActivePlayer';
|
||||
import SyncPlayHtmlVideoPlayer from '../components/syncPlay/ui/players/HtmlVideoPlayer';
|
||||
import SyncPlayHtmlAudioPlayer from '../components/syncPlay/ui/players/HtmlAudioPlayer';
|
||||
import { currentSettings } from './settings/userSettings';
|
||||
|
||||
// TODO: Move this elsewhere
|
||||
window.getWindowLocationSearch = function(win) {
|
||||
|
@ -173,7 +174,7 @@ function initSyncPlay() {
|
|||
Events.on(ServerConnections, 'apiclientcreated', (e, newApiClient) => SyncPlay.Manager.init(newApiClient));
|
||||
}
|
||||
|
||||
function onAppReady() {
|
||||
async function onAppReady() {
|
||||
console.debug('begin onAppReady');
|
||||
|
||||
console.debug('onAppReady: loading dependencies');
|
||||
|
@ -216,27 +217,63 @@ function onAppReady() {
|
|||
|
||||
const apiClient = ServerConnections.currentApiClient();
|
||||
if (apiClient) {
|
||||
fetch(apiClient.getUrl('Branding/Css'))
|
||||
const updateStyle = (css) => {
|
||||
let style = document.querySelector('#cssBranding');
|
||||
if (!style) {
|
||||
// Inject the branding css as a dom element in body so it will take
|
||||
// precedence over other stylesheets
|
||||
style = document.createElement('style');
|
||||
style.id = 'cssBranding';
|
||||
document.body.appendChild(style);
|
||||
}
|
||||
style.textContent = css;
|
||||
};
|
||||
|
||||
const style = fetch(apiClient.getUrl('Branding/Css'))
|
||||
.then(function(response) {
|
||||
if (!response.ok) {
|
||||
throw new Error(response.status + ' ' + response.statusText);
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then(function(css) {
|
||||
let style = document.querySelector('#cssBranding');
|
||||
if (!style) {
|
||||
// Inject the branding css as a dom element in body so it will take
|
||||
// precedence over other stylesheets
|
||||
style = document.createElement('style');
|
||||
style.id = 'cssBranding';
|
||||
document.body.appendChild(style);
|
||||
}
|
||||
style.textContent = css;
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.warn('Error applying custom css', err);
|
||||
});
|
||||
|
||||
const handleStyleChange = async () => {
|
||||
if (currentSettings.disableCustomCss()) {
|
||||
updateStyle('');
|
||||
} else {
|
||||
updateStyle(await style);
|
||||
}
|
||||
|
||||
const localCss = currentSettings.customCss();
|
||||
let localStyle = document.querySelector('#localCssBranding');
|
||||
if (localCss) {
|
||||
if (!localStyle) {
|
||||
// Inject the branding css as a dom element in body so it will take
|
||||
// precedence over other stylesheets
|
||||
localStyle = document.createElement('style');
|
||||
localStyle.id = 'localCssBranding';
|
||||
document.body.appendChild(localStyle);
|
||||
}
|
||||
localStyle.textContent = localCss;
|
||||
} else {
|
||||
if (localStyle) {
|
||||
localStyle.textContent = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Events.on(ServerConnections, 'localusersignedin', handleStyleChange);
|
||||
Events.on(ServerConnections, 'localusersignedout', handleStyleChange);
|
||||
Events.on(currentSettings, 'change', (e, prop) => {
|
||||
if (prop == 'disableCustomCss' || prop == 'customCss') {
|
||||
handleStyleChange();
|
||||
}
|
||||
});
|
||||
|
||||
style.then(updateStyle);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue