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

feat: (preferences) hide display settings when unsupported

This commit is contained in:
Grady Hallenbeck 2024-01-04 21:34:20 -08:00
parent 3dd26c7785
commit 5edcadd423
5 changed files with 163 additions and 99 deletions

View file

@ -2,13 +2,16 @@ import Checkbox from '@mui/material/Checkbox';
import FormControl from '@mui/material/FormControl'; import FormControl from '@mui/material/FormControl';
import FormControlLabel from '@mui/material/FormControlLabel'; import FormControlLabel from '@mui/material/FormControlLabel';
import FormHelperText from '@mui/material/FormHelperText'; import FormHelperText from '@mui/material/FormHelperText';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import Select, { SelectChangeEvent } from '@mui/material/Select'; import Select, { SelectChangeEvent } from '@mui/material/Select';
import Stack from '@mui/material/Stack'; import Stack from '@mui/material/Stack';
import TextField from '@mui/material/TextField'; import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import React from 'react'; import React, { Fragment } from 'react';
import { appHost } from 'components/apphost';
import { useApi } from 'hooks/useApi';
import globalize from 'scripts/globalize'; import globalize from 'scripts/globalize';
import { DisplaySettingsValues } from './types'; import { DisplaySettingsValues } from './types';
import { useScreensavers } from './hooks/useScreensavers'; import { useScreensavers } from './hooks/useScreensavers';
@ -20,20 +23,23 @@ interface DisplayPreferencesProps {
} }
export function DisplayPreferences({ onChange, values }: Readonly<DisplayPreferencesProps>) { export function DisplayPreferences({ onChange, values }: Readonly<DisplayPreferencesProps>) {
const { user } = useApi();
const { screensavers } = useScreensavers(); const { screensavers } = useScreensavers();
const { themes } = useServerThemes(); const { themes } = useServerThemes();
return ( return (
<Stack spacing={2}> <Stack spacing={3}>
<Typography variant='h2'>{globalize.translate('Display')}</Typography> <Typography variant='h2'>{globalize.translate('Display')}</Typography>
{ appHost.supports('displaymode') && (
<FormControl fullWidth> <FormControl fullWidth>
<InputLabel id='display-settings-layout-label'>{globalize.translate('LabelDisplayMode')}</InputLabel>
<Select <Select
aria-describedby='display-settings-layout-description' aria-describedby='display-settings-layout-description'
inputProps={{ inputProps={{
name: 'layout' name: 'layout'
}} }}
label={globalize.translate('LabelDisplayMode')} labelId='display-settings-layout-label'
onChange={onChange} onChange={onChange}
value={values.layout} value={values.layout}
> >
@ -48,13 +54,16 @@ export function DisplayPreferences({ onChange, values }: Readonly<DisplayPrefere
<span>{globalize.translate('LabelPleaseRestart')}</span> <span>{globalize.translate('LabelPleaseRestart')}</span>
</FormHelperText> </FormHelperText>
</FormControl> </FormControl>
) }
{ themes.length > 0 && (
<FormControl fullWidth> <FormControl fullWidth>
<InputLabel id='display-settings-theme-label'>{globalize.translate('LabelTheme')}</InputLabel>
<Select <Select
inputProps={{ inputProps={{
name: 'theme' name: 'theme'
}} }}
label={globalize.translate('LabelTheme')} labelId='display-settings-theme-label'
onChange={onChange} onChange={onChange}
value={values.theme} value={values.theme}
> >
@ -63,6 +72,7 @@ export function DisplayPreferences({ onChange, values }: Readonly<DisplayPrefere
))} ))}
</Select> </Select>
</FormControl> </FormControl>
) }
<FormControl fullWidth> <FormControl fullWidth>
<FormControlLabel <FormControlLabel
@ -84,7 +94,7 @@ export function DisplayPreferences({ onChange, values }: Readonly<DisplayPrefere
<FormControl fullWidth> <FormControl fullWidth>
<TextField <TextField
aria-describedby='display-settings-custom-css-description' aria-describedby='display-settings-custom-css-description'
defaultValue={values.customCss} value={values.customCss}
label={globalize.translate('LabelCustomCss')} label={globalize.translate('LabelCustomCss')}
multiline multiline
name='customCss' name='customCss'
@ -95,15 +105,33 @@ export function DisplayPreferences({ onChange, values }: Readonly<DisplayPrefere
</FormHelperText> </FormHelperText>
</FormControl> </FormControl>
{/* TODO: There are some admin-only options here */} { themes.length > 0 && user?.Policy?.IsAdministrator && (
{/* Server Dashboard Theme */}
<FormControl fullWidth> <FormControl fullWidth>
<InputLabel id='display-settings-dashboard-theme-label'>{globalize.translate('LabelDashboardTheme')}</InputLabel>
<Select
inputProps={{
name: 'dashboardTheme'
}}
labelId='display-settings-dashboard-theme-label'
onChange={ onChange }
value={ values.dashboardTheme }
>
{ ...themes.map(({ id, name }) => (
<MenuItem key={ id } value={ id }>{ name }</MenuItem>
)) }
</Select>
</FormControl>
) }
{ screensavers.length > 0 && appHost.supports('screensaver') && (
<Fragment>
<FormControl fullWidth>
<InputLabel id='display-settings-screensaver-label'>{globalize.translate('LabelScreensaver')}</InputLabel>
<Select <Select
inputProps={{ inputProps={{
name: 'screensaver' name: 'screensaver'
}} }}
label={globalize.translate('LabelScreensaver')} labelId='display-settings-screensaver-label'
onChange={onChange} onChange={onChange}
value={values.screensaver} value={values.screensaver}
> >
@ -113,7 +141,29 @@ export function DisplayPreferences({ onChange, values }: Readonly<DisplayPrefere
</Select> </Select>
</FormControl> </FormControl>
{/* TODO: There are some extra options here related to screensavers */} <FormControl fullWidth>
<TextField
aria-describedby='display-settings-screensaver-interval-description'
value={values.screensaverInterval}
inputProps={{
inputMode: 'numeric',
max: '3600',
min: '1',
pattern: '[0-9]',
required: true,
step: '1',
type: 'number'
}}
label={globalize.translate('LabelBackdropScreensaverInterval')}
name='screensaverInterval'
onChange={onChange}
/>
<FormHelperText id='display-settings-screensaver-interval-description'>
{globalize.translate('LabelBackdropScreensaverIntervalHelp')}
</FormHelperText>
</FormControl>
</Fragment>
) }
<FormControl fullWidth> <FormControl fullWidth>
<FormControlLabel <FormControlLabel

View file

@ -17,7 +17,7 @@ interface LibraryPreferencesProps {
export function LibraryPreferences({ onChange, values }: Readonly<LibraryPreferencesProps>) { export function LibraryPreferences({ onChange, values }: Readonly<LibraryPreferencesProps>) {
return ( return (
<Stack spacing={2}> <Stack spacing={3}>
<Typography variant='h2'>{globalize.translate('HeaderLibraries')}</Typography> <Typography variant='h2'>{globalize.translate('HeaderLibraries')}</Typography>
<FormControl fullWidth> <FormControl fullWidth>
@ -32,7 +32,7 @@ export function LibraryPreferences({ onChange, values }: Readonly<LibraryPrefere
required: true, required: true,
step: '1' step: '1'
}} }}
defaultValue={values.libraryPageSize} value={values.libraryPageSize}
label={globalize.translate('LabelLibraryPageSize')} label={globalize.translate('LabelLibraryPageSize')}
name='libraryPageSize' name='libraryPageSize'
onChange={onChange} onChange={onChange}

View file

@ -1,5 +1,6 @@
import FormControl from '@mui/material/FormControl'; import FormControl from '@mui/material/FormControl';
import FormHelperText from '@mui/material/FormHelperText'; import FormHelperText from '@mui/material/FormHelperText';
import InputLabel from '@mui/material/InputLabel';
import Link from '@mui/material/Link'; import Link from '@mui/material/Link';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import Select, { SelectChangeEvent } from '@mui/material/Select'; import Select, { SelectChangeEvent } from '@mui/material/Select';
@ -7,6 +8,8 @@ import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import React from 'react'; import React from 'react';
import { appHost } from 'components/apphost';
import datetime from 'scripts/datetime';
import globalize from 'scripts/globalize'; import globalize from 'scripts/globalize';
import { DATE_LOCALE_OPTIONS, LANGUAGE_OPTIONS } from './constants'; import { DATE_LOCALE_OPTIONS, LANGUAGE_OPTIONS } from './constants';
import { DisplaySettingsValues } from './types'; import { DisplaySettingsValues } from './types';
@ -17,17 +20,22 @@ interface LocalizationPreferencesProps {
} }
export function LocalizationPreferences({ onChange, values }: Readonly<LocalizationPreferencesProps>) { export function LocalizationPreferences({ onChange, values }: Readonly<LocalizationPreferencesProps>) {
if (!appHost.supports('displaylanguage') && !datetime.supportsLocalization()) {
return null;
}
return ( return (
<Stack spacing={2}> <Stack spacing={3}>
<Typography variant='h2'>{globalize.translate('Localization')}</Typography> <Typography variant='h2'>{globalize.translate('Localization')}</Typography>
{ appHost.supports('displaylanguage') && (
<FormControl fullWidth> <FormControl fullWidth>
<InputLabel id='display-settings-language-label'>{globalize.translate('LabelDisplayLanguage')}</InputLabel>
<Select <Select
aria-describedby='display-settings-language-description' aria-describedby='display-settings-language-description'
inputProps={{ inputProps={{
name: 'language' name: 'language'
}} }}
label={globalize.translate('LabelDisplayLanguage')} labelId='display-settings-language-label'
onChange={onChange} onChange={onChange}
value={values.language} value={values.language}
> >
@ -37,6 +45,7 @@ export function LocalizationPreferences({ onChange, values }: Readonly<Localizat
</Select> </Select>
<FormHelperText component={Stack} id='display-settings-language-description'> <FormHelperText component={Stack} id='display-settings-language-description'>
<span>{globalize.translate('LabelDisplayLanguageHelp')}</span> <span>{globalize.translate('LabelDisplayLanguageHelp')}</span>
{ appHost.supports('externallinks') && (
<Link <Link
href='https://github.com/jellyfin/jellyfin' href='https://github.com/jellyfin/jellyfin'
rel='noopener noreferrer' rel='noopener noreferrer'
@ -44,15 +53,19 @@ export function LocalizationPreferences({ onChange, values }: Readonly<Localizat
> >
{globalize.translate('LearnHowYouCanContribute')} {globalize.translate('LearnHowYouCanContribute')}
</Link> </Link>
) }
</FormHelperText> </FormHelperText>
</FormControl> </FormControl>
) }
{ datetime.supportsLocalization() && (
<FormControl fullWidth> <FormControl fullWidth>
<InputLabel id='display-settings-locale-label'>{globalize.translate('LabelDateTimeLocale')}</InputLabel>
<Select <Select
inputProps={{ inputProps={{
name: 'dateTimeLocale' name: 'dateTimeLocale'
}} }}
label={globalize.translate('LabelDateTimeLocale')} labelId='display-settings-locale-label'
onChange={onChange} onChange={onChange}
value={values.dateTimeLocale} value={values.dateTimeLocale}
> >
@ -61,6 +74,7 @@ export function LocalizationPreferences({ onChange, values }: Readonly<Localizat
))} ))}
</Select> </Select>
</FormControl> </FormControl>
) }
</Stack> </Stack>
); );
} }

View file

@ -17,13 +17,13 @@ interface NextUpPreferencesProps {
export function NextUpPreferences({ onChange, values }: Readonly<NextUpPreferencesProps>) { export function NextUpPreferences({ onChange, values }: Readonly<NextUpPreferencesProps>) {
return ( return (
<Stack spacing={2}> <Stack spacing={3}>
<Typography variant='h2'>{globalize.translate('NextUp')}</Typography> <Typography variant='h2'>{globalize.translate('NextUp')}</Typography>
<FormControl fullWidth> <FormControl fullWidth>
<TextField <TextField
aria-describedby='display-settings-max-days-next-up-description' aria-describedby='display-settings-max-days-next-up-description'
defaultValue={values.maxDaysForNextUp} value={values.maxDaysForNextUp}
inputProps={{ inputProps={{
type: 'number', type: 'number',
inputMode: 'numeric', inputMode: 'numeric',

View file

@ -31,7 +31,7 @@ export default function UserDisplayPreferences() {
const handleFieldChange = useCallback((e: SelectChangeEvent | React.SyntheticEvent) => { const handleFieldChange = useCallback((e: SelectChangeEvent | React.SyntheticEvent) => {
const target = e.target as HTMLInputElement; const target = e.target as HTMLInputElement;
const fieldName = target.name as keyof DisplaySettingsValues; const fieldName = target.name as keyof DisplaySettingsValues;
const fieldValue = target.checked ?? target.value; const fieldValue = target.type === 'checkbox' ? target.checked : target.value;
if (values?.[fieldName] !== fieldValue) { if (values?.[fieldName] !== fieldValue) {
updateField({ updateField({