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

Merge pull request #4776 from grafixeyehero/Add-filters-status-indicator

This commit is contained in:
Bill Thornton 2023-09-16 22:00:44 -04:00 committed by GitHub
commit 5fb4b51cfb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 235 additions and 292 deletions

View file

@ -10,6 +10,7 @@ import MuiAccordionSummary, {
AccordionSummaryProps AccordionSummaryProps
} from '@mui/material/AccordionSummary'; } from '@mui/material/AccordionSummary';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import { Badge } from '@mui/material';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
@ -152,6 +153,9 @@ const FilterButton: FC<FilterButtonProps> = ({
return viewType === LibraryTab.Episodes; return viewType === LibraryTab.Episodes;
}; };
const hasFilters =
Object.values(libraryViewSettings.Filters || {}).some((filter) => !!filter);
return ( return (
<Box> <Box>
<IconButton <IconButton
@ -161,7 +165,9 @@ const FilterButton: FC<FilterButtonProps> = ({
className='paper-icon-button-light btnShuffle autoSize' className='paper-icon-button-light btnShuffle autoSize'
onClick={handleClick} onClick={handleClick}
> >
<FilterListIcon /> <Badge color='info' variant='dot' invisible={!hasFilters}>
<FilterListIcon />
</Badge>
</IconButton> </IconButton>
<Popover <Popover
id={id} id={id}
@ -239,7 +245,9 @@ const FilterButton: FC<FilterButtonProps> = ({
id='filtersEpisodesStatus-header' id='filtersEpisodesStatus-header'
> >
<Typography> <Typography>
{globalize.translate('HeaderEpisodesStatus')} {globalize.translate(
'HeaderEpisodesStatus'
)}
</Typography> </Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>

View file

@ -3,12 +3,12 @@ import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel'; import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox'; import Checkbox from '@mui/material/Checkbox';
import globalize from 'scripts/globalize'; import globalize from 'scripts/globalize';
import { LibraryViewSettings } from 'types/library'; import { EpisodeFilter, LibraryViewSettings } from 'types/library';
const episodesStatusOptions = [ const episodeFilterOptions = [
{ label: 'OptionSpecialEpisode', value: 'ParentIndexNumber' }, { label: 'OptionSpecialEpisode', value: EpisodeFilter.ParentIndexNumber },
{ label: 'OptionMissingEpisode', value: 'IsMissing' }, { label: 'OptionMissingEpisode', value: EpisodeFilter.IsMissing },
{ label: 'OptionUnairedEpisode', value: 'IsUnaired' } { label: 'OptionUnairedEpisode', value: EpisodeFilter.IsUnaired }
]; ];
interface FiltersEpisodesStatusProps { interface FiltersEpisodesStatusProps {
@ -23,46 +23,39 @@ const FiltersEpisodesStatus: FC<FiltersEpisodesStatusProps> = ({
const onFiltersEpisodesStatusChange = useCallback( const onFiltersEpisodesStatusChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => { (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault(); event.preventDefault();
const value = String(event.target.value); const value = event.target.value as EpisodeFilter;
const existingValue = libraryViewSettings?.Filters?.EpisodesStatus; const existingEpisodeFilter = libraryViewSettings?.Filters?.EpisodeFilter ?? [];
if (existingValue?.includes(value)) { const updatedEpisodeFilter = existingEpisodeFilter.includes(value) ?
const newValue = existingValue?.filter( existingEpisodeFilter.filter((filter) => filter !== value) :
(prevState: string) => prevState !== value [...existingEpisodeFilter, value];
);
setLibraryViewSettings((prevState) => ({ setLibraryViewSettings((prevState) => ({
...prevState, ...prevState,
StartIndex: 0, StartIndex: 0,
Filters: { ...prevState.Filters, EpisodesStatus: newValue } Filters: {
})); ...prevState.Filters,
} else { EpisodeFilter: updatedEpisodeFilter.length ? updatedEpisodeFilter : undefined
setLibraryViewSettings((prevState) => ({ }
...prevState, }));
StartIndex: 0,
Filters: {
...prevState.Filters,
EpisodesStatus: [...(existingValue ?? []), value]
}
}));
}
}, },
[setLibraryViewSettings, libraryViewSettings?.Filters?.EpisodesStatus] [setLibraryViewSettings, libraryViewSettings?.Filters?.EpisodeFilter]
); );
return ( return (
<FormGroup> <FormGroup>
{episodesStatusOptions.map((filter) => ( {episodeFilterOptions.map((filter) => (
<FormControlLabel <FormControlLabel
key={filter.value} key={filter.value}
control={ control={
<Checkbox <Checkbox
checked={ checked={
!!libraryViewSettings?.Filters?.EpisodesStatus?.includes( !!libraryViewSettings?.Filters?.EpisodeFilter?.includes(
String( filter.value) filter.value
) )
} }
onChange={onFiltersEpisodesStatusChange} onChange={onFiltersEpisodesStatusChange}
value={String(filter.value)} value={filter.value}
/> />
} }
label={globalize.translate(filter.label)} label={globalize.translate(filter.label)}

View file

@ -3,14 +3,14 @@ import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel'; import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox'; import Checkbox from '@mui/material/Checkbox';
import globalize from 'scripts/globalize'; import globalize from 'scripts/globalize';
import { LibraryViewSettings } from 'types/library'; import { FeatureFilters, LibraryViewSettings } from 'types/library';
const featuresOptions = [ const featuresOptions = [
{ label: 'Subtitles', value: 'HasSubtitles' }, { label: 'Subtitles', value: FeatureFilters.HasSubtitles },
{ label: 'Trailers', value: 'HasTrailer' }, { label: 'Trailers', value: FeatureFilters.HasTrailer },
{ label: 'Extras', value: 'HasSpecialFeature' }, { label: 'Extras', value: FeatureFilters.HasSpecialFeature },
{ label: 'ThemeSongs', value: 'HasThemeSong' }, { label: 'ThemeSongs', value: FeatureFilters.HasThemeSong },
{ label: 'ThemeVideos', value: 'HasThemeVideo' } { label: 'ThemeVideos', value: FeatureFilters.HasThemeVideo }
]; ];
interface FiltersFeaturesProps { interface FiltersFeaturesProps {
@ -27,29 +27,21 @@ const FiltersFeatures: FC<FiltersFeaturesProps> = ({
const onFiltersFeaturesChange = useCallback( const onFiltersFeaturesChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => { (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault(); event.preventDefault();
const value = String(event.target.value); const value = event.target.value as FeatureFilters;
const existingValue = const existingFeatures = libraryViewSettings?.Filters?.Features ?? [];
libraryViewSettings?.Filters?.Features;
if (existingValue?.includes(value)) { const updatedFeatures = existingFeatures.includes(value) ?
const newValue = existingValue?.filter( existingFeatures.filter((filter) => filter !== value) :
(prevState: string) => prevState !== value [...existingFeatures, value];
);
setLibraryViewSettings((prevState) => ({ setLibraryViewSettings((prevState) => ({
...prevState, ...prevState,
StartIndex: 0, StartIndex: 0,
Filters: { ...prevState.Filters, Features: newValue } Filters: {
})); ...prevState.Filters,
} else { Features: updatedFeatures.length ? updatedFeatures : undefined
setLibraryViewSettings((prevState) => ({ }
...prevState, }));
StartIndex: 0,
Filters: {
...prevState.Filters,
Features: [...(existingValue ?? []), value]
}
}));
}
}, },
[setLibraryViewSettings, libraryViewSettings?.Filters?.Features] [setLibraryViewSettings, libraryViewSettings?.Filters?.Features]
); );
@ -64,11 +56,11 @@ const FiltersFeatures: FC<FiltersFeaturesProps> = ({
<Checkbox <Checkbox
checked={ checked={
!!libraryViewSettings?.Filters?.Features?.includes( !!libraryViewSettings?.Filters?.Features?.includes(
String(filter.value) filter.value
) )
} }
onChange={onFiltersFeaturesChange} onChange={onFiltersFeaturesChange}
value={String(filter.value)} value={filter.value}
/> />
} }
label={globalize.translate(filter.label)} label={globalize.translate(filter.label)}

View file

@ -19,28 +19,21 @@ const FiltersGenres: FC<FiltersGenresProps> = ({
const onFiltersGenresChange = useCallback( const onFiltersGenresChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => { (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault(); event.preventDefault();
const value = String(event.target.value); const value = event.target.value;
const existingValue = libraryViewSettings?.Filters?.Genres; const existingGenres = libraryViewSettings?.Filters?.Genres ?? [];
if (existingValue?.includes(value)) { const updatedGenres = existingGenres.includes(value) ?
const newValue = existingValue?.filter( existingGenres.filter((filter) => filter !== value) :
(prevState: string) => prevState !== value [...existingGenres, value];
);
setLibraryViewSettings((prevState) => ({ setLibraryViewSettings((prevState) => ({
...prevState, ...prevState,
StartIndex: 0, StartIndex: 0,
Filters: { ...prevState.Filters, Genres: newValue } Filters: {
})); ...prevState.Filters,
} else { Genres: updatedGenres.length ? updatedGenres : undefined
setLibraryViewSettings((prevState) => ({ }
...prevState, }));
StartIndex: 0,
Filters: {
...prevState.Filters,
Genres: [...(existingValue ?? []), value]
}
}));
}
}, },
[setLibraryViewSettings, libraryViewSettings?.Filters?.Genres] [setLibraryViewSettings, libraryViewSettings?.Filters?.Genres]
); );

View file

@ -19,28 +19,21 @@ const FiltersOfficialRatings: FC<FiltersOfficialRatingsProps> = ({
const onFiltersOfficialRatingsChange = useCallback( const onFiltersOfficialRatingsChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => { (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault(); event.preventDefault();
const value = String(event.target.value); const value = event.target.value;
const existingValue = libraryViewSettings?.Filters?.OfficialRatings; const existingOfficialRatings = libraryViewSettings?.Filters?.OfficialRatings ?? [];
if (existingValue?.includes(value)) { const updatedOfficialRatings = existingOfficialRatings.includes(value) ?
const newValue = existingValue?.filter( existingOfficialRatings.filter((filter) => filter !== value) :
(prevState: string) => prevState !== value [...existingOfficialRatings, value];
);
setLibraryViewSettings((prevState) => ({ setLibraryViewSettings((prevState) => ({
...prevState, ...prevState,
StartIndex: 0, StartIndex: 0,
Filters: { ...prevState.Filters, OfficialRatings: newValue } Filters: {
})); ...prevState.Filters,
} else { OfficialRatings: updatedOfficialRatings.length ? updatedOfficialRatings : undefined
setLibraryViewSettings((prevState) => ({ }
...prevState, }));
StartIndex: 0,
Filters: {
...prevState.Filters,
OfficialRatings: [...(existingValue ?? []), value]
}
}));
}
}, },
[setLibraryViewSettings, libraryViewSettings?.Filters?.OfficialRatings] [setLibraryViewSettings, libraryViewSettings?.Filters?.OfficialRatings]
); );

View file

@ -25,27 +25,20 @@ const FiltersSeriesStatus: FC<FiltersSeriesStatusProps> = ({
(event: React.ChangeEvent<HTMLInputElement>) => { (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault(); event.preventDefault();
const value = event.target.value as SeriesStatus; const value = event.target.value as SeriesStatus;
const existingValue = libraryViewSettings?.Filters?.SeriesStatus; const existingSeriesStatus = libraryViewSettings?.Filters?.SeriesStatus ?? [];
if (existingValue?.includes(value)) { const updatedSeriesStatus = existingSeriesStatus.includes(value) ?
const newValue = existingValue?.filter( existingSeriesStatus.filter((filter) => filter !== value) :
(prevState: SeriesStatus) => prevState !== value [...existingSeriesStatus, value];
);
setLibraryViewSettings((prevState) => ({ setLibraryViewSettings((prevState) => ({
...prevState, ...prevState,
StartIndex: 0, StartIndex: 0,
Filters: { ...prevState.Filters, SeriesStatus: newValue } Filters: {
})); ...prevState.Filters,
} else { SeriesStatus: updatedSeriesStatus.length ? updatedSeriesStatus : undefined
setLibraryViewSettings((prevState) => ({ }
...prevState, }));
StartIndex: 0,
Filters: {
...prevState.Filters,
SeriesStatus: [...(existingValue ?? []), value]
}
}));
}
}, },
[setLibraryViewSettings, libraryViewSettings?.Filters?.SeriesStatus] [setLibraryViewSettings, libraryViewSettings?.Filters?.SeriesStatus]
); );

View file

@ -29,27 +29,20 @@ const FiltersStatus: FC<FiltersStatusProps> = ({
(event: React.ChangeEvent<HTMLInputElement>) => { (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault(); event.preventDefault();
const value = event.target.value as ItemFilter; const value = event.target.value as ItemFilter;
const existingValue = libraryViewSettings?.Filters?.Status; const existingStatus = libraryViewSettings?.Filters?.Status ?? [];
if (existingValue?.includes(value)) { const updatedStatus = existingStatus.includes(value) ?
const newValue = existingValue?.filter( existingStatus.filter((filter) => filter !== value) :
(prevState: ItemFilter) => prevState !== value [...existingStatus, value];
);
setLibraryViewSettings((prevState) => ({ setLibraryViewSettings((prevState) => ({
...prevState, ...prevState,
StartIndex: 0, StartIndex: 0,
Filters: { ...prevState.Filters, Status: newValue } Filters: {
})); ...prevState.Filters,
} else { Status: updatedStatus.length ? updatedStatus : undefined
setLibraryViewSettings((prevState) => ({ }
...prevState, }));
StartIndex: 0,
Filters: {
...prevState.Filters,
Status: [...(existingValue ?? []), value]
}
}));
}
}, },
[setLibraryViewSettings, libraryViewSettings?.Filters?.Status] [setLibraryViewSettings, libraryViewSettings?.Filters?.Status]
); );

View file

@ -19,30 +19,23 @@ const FiltersStudios: FC<FiltersStudiosProps> = ({
const onFiltersStudiosChange = useCallback( const onFiltersStudiosChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => { (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault(); event.preventDefault();
const value = String(event.target.value); const value = event.target.value;
const existingValue = libraryViewSettings?.Filters?.StudioIds; const existingStudioIds = libraryViewSettings?.Filters?.StudioIds ?? [];
if (existingValue?.includes(value)) { const updatedStudioIds = existingStudioIds.includes(value) ?
const newValue = existingValue?.filter( existingStudioIds.filter((filter) => filter !== value) :
(prevState: string) => prevState !== value [...existingStudioIds, value];
);
setLibraryViewSettings((prevState) => ({ setLibraryViewSettings((prevState) => ({
...prevState, ...prevState,
StartIndex: 0, StartIndex: 0,
Filters: { ...prevState.Filters, StudioIds: newValue } Filters: {
})); ...prevState.Filters,
} else { StudioIds: updatedStudioIds.length ? updatedStudioIds : undefined
setLibraryViewSettings((prevState) => ({ }
...prevState, }));
StartIndex: 0,
Filters: {
...prevState.Filters,
StudioIds: [...(existingValue ?? []), value]
}
}));
}
}, },
[setLibraryViewSettings, libraryViewSettings?.Filters?.StudioIds] [setLibraryViewSettings, libraryViewSettings.Filters?.StudioIds]
); );
return ( return (

View file

@ -19,30 +19,23 @@ const FiltersTags: FC<FiltersTagsProps> = ({
const onFiltersTagsChange = useCallback( const onFiltersTagsChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => { (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault(); event.preventDefault();
const value = String(event.target.value); const value = event.target.value;
const existingValue = libraryViewSettings?.Filters?.Tags; const existingTags = libraryViewSettings?.Filters?.Tags ?? [];
if (existingValue?.includes(value)) { const updatedTags = existingTags.includes(value) ?
const newValue = existingValue?.filter( existingTags.filter((filter) => filter !== value) :
(prevState: string) => prevState !== value [...existingTags, value];
);
setLibraryViewSettings((prevState) => ({ setLibraryViewSettings((prevState) => ({
...prevState, ...prevState,
StartIndex: 0, StartIndex: 0,
Filters: { ...prevState.Filters, Tags: newValue } Filters: {
})); ...prevState.Filters,
} else { Tags: updatedTags.length ? updatedTags : undefined
setLibraryViewSettings((prevState) => ({ }
...prevState, }));
StartIndex: 0,
Filters: {
...prevState.Filters,
Tags: [...(existingValue ?? []), value]
}
}));
}
}, },
[setLibraryViewSettings, libraryViewSettings?.Filters?.Tags] [setLibraryViewSettings, libraryViewSettings.Filters?.Tags]
); );
return ( return (

View file

@ -2,9 +2,15 @@ import React, { FC, useCallback } from 'react';
import FormGroup from '@mui/material/FormGroup'; import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel'; import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox'; import Checkbox from '@mui/material/Checkbox';
import { LibraryViewSettings } from 'types/library'; import { LibraryViewSettings, VideoBasicFilter } from 'types/library';
import { VideoType } from '@jellyfin/sdk/lib/generated-client'; import { VideoType } from '@jellyfin/sdk/lib/generated-client';
import globalize from 'scripts/globalize';
const videoBasicFilterOptions = [
{ label: 'SD', value: VideoBasicFilter.IsSD },
{ label: 'HD', value: VideoBasicFilter.IsHD },
{ label: '4K', value: VideoBasicFilter.Is4K },
{ label: '3D', value: VideoBasicFilter.Is3D }
];
const videoTypesOptions = [ const videoTypesOptions = [
{ label: 'DVD', value: VideoType.Dvd }, { label: 'DVD', value: VideoType.Dvd },
@ -21,93 +27,67 @@ const FiltersVideoTypes: FC<FiltersVideoTypesProps> = ({
libraryViewSettings, libraryViewSettings,
setLibraryViewSettings setLibraryViewSettings
}) => { }) => {
const onFiltersvideoStandardChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault();
const value = event.target.value as VideoBasicFilter;
const existingVideoBasicFilter = libraryViewSettings?.Filters?.VideoBasicFilter ?? [];
const updatedVideoBasicFilter = existingVideoBasicFilter.includes(value) ?
existingVideoBasicFilter.filter((filter) => filter !== value) :
[...existingVideoBasicFilter, value];
setLibraryViewSettings((prevState) => ({
...prevState,
Filters: {
...prevState.Filters,
VideoBasicFilter: updatedVideoBasicFilter.length ? updatedVideoBasicFilter : undefined
}
}));
},
[setLibraryViewSettings, libraryViewSettings?.Filters?.VideoBasicFilter]
);
const onFiltersVideoTypesChange = useCallback( const onFiltersVideoTypesChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => { (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault(); event.preventDefault();
const value = event.target.value as VideoType; const value = event.target.value as VideoType;
const existingValue = libraryViewSettings?.Filters?.VideoTypes; const existingVideoTypes = libraryViewSettings?.Filters?.VideoTypes ?? [];
if (existingValue?.includes(value)) { const updatedVideoTypes = existingVideoTypes.includes(value) ?
const newValue = existingValue?.filter( existingVideoTypes.filter((filter) => filter !== value) :
(prevState: VideoType) => prevState !== value [...existingVideoTypes, value];
);
setLibraryViewSettings((prevState) => ({ setLibraryViewSettings((prevState) => ({
...prevState, ...prevState,
StartIndex: 0, StartIndex: 0,
Filters: { ...prevState.Filters, VideoTypes: newValue } Filters: {
})); ...prevState.Filters,
} else { VideoTypes: updatedVideoTypes.length ? updatedVideoTypes : undefined
setLibraryViewSettings((prevState) => ({ }
...prevState, }));
StartIndex: 0,
Filters: {
...prevState.Filters,
VideoTypes: [...(existingValue ?? []), value]
}
}));
}
}, },
[setLibraryViewSettings, libraryViewSettings?.Filters?.VideoTypes] [setLibraryViewSettings, libraryViewSettings?.Filters?.VideoTypes]
); );
const handleChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
const name = event.target.name;
setLibraryViewSettings((prevState) => ({
...prevState,
[name]: event.target.checked
}));
},
[setLibraryViewSettings]
);
return ( return (
<FormGroup> <FormGroup>
<FormControlLabel {videoBasicFilterOptions
control={ .map((filter) => (
<Checkbox <FormControlLabel
checked={libraryViewSettings.IsSD} key={filter.value}
onChange={handleChange} control={
name='IsSD' <Checkbox
/> checked={
} !!libraryViewSettings?.Filters?.VideoBasicFilter?.includes(filter.value)
label={globalize.translate('SD')} }
/> onChange={onFiltersvideoStandardChange}
<FormControlLabel value={filter.value}
control={ />
<Checkbox
checked={libraryViewSettings.IsHD}
onChange={handleChange}
name='IsHD'
/>
}
label={globalize.translate('HD')}
/>
<FormControlLabel
control={
<Checkbox
checked={
libraryViewSettings.Is4K
} }
onChange={handleChange} label={filter.label}
name='Is4K'
/> />
} ))}
label={globalize.translate('4K')}
/>
<FormControlLabel
control={
<Checkbox
checked={
libraryViewSettings.Is3D
}
onChange={handleChange}
name='Is3D'
/>
}
label={globalize.translate('3D')}
/>
{videoTypesOptions {videoTypesOptions
.map((filter) => ( .map((filter) => (
<FormControlLabel <FormControlLabel

View file

@ -20,27 +20,20 @@ const FiltersYears: FC<FiltersYearsProps> = ({
(event: React.ChangeEvent<HTMLInputElement>) => { (event: React.ChangeEvent<HTMLInputElement>) => {
event.preventDefault(); event.preventDefault();
const value = Number(event.target.value); const value = Number(event.target.value);
const existingValue = libraryViewSettings?.Filters?.Years; const existingYears = libraryViewSettings?.Filters?.Years ?? [];
if (existingValue?.includes(value)) { const updatedYears = existingYears.includes(value) ?
const newValue = existingValue?.filter( existingYears.filter((filter) => filter !== value) :
(prevState: number) => prevState !== value [...existingYears, value];
);
setLibraryViewSettings((prevState) => ({ setLibraryViewSettings((prevState) => ({
...prevState, ...prevState,
StartIndex: 0, StartIndex: 0,
Filters: { ...prevState.Filters, Years: newValue } Filters: {
})); ...prevState.Filters,
} else { Years: updatedYears.length ? updatedYears : undefined
setLibraryViewSettings((prevState) => ({ }
...prevState, }));
StartIndex: 0,
Filters: {
...prevState.Filters,
Years: [...(existingValue ?? []), value]
}
}));
}
}, },
[setLibraryViewSettings, libraryViewSettings?.Filters?.Years] [setLibraryViewSettings, libraryViewSettings?.Filters?.Years]
); );

View file

@ -2,8 +2,8 @@ import type { ItemFilter } from '@jellyfin/sdk/lib/generated-client/models/item-
import type { VideoType } from '@jellyfin/sdk/lib/generated-client/models/video-type'; import type { VideoType } from '@jellyfin/sdk/lib/generated-client/models/video-type';
import type { SortOrder } from '@jellyfin/sdk/lib/generated-client/models/sort-order'; import type { SortOrder } from '@jellyfin/sdk/lib/generated-client/models/sort-order';
import type { SeriesStatus } from '@jellyfin/sdk/lib/generated-client/models/series-status'; import type { SeriesStatus } from '@jellyfin/sdk/lib/generated-client/models/series-status';
import type { ImageType } from '@jellyfin/sdk/lib/generated-client';
import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by'; import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by';
import { ImageType } from '@jellyfin/sdk/lib/generated-client';
export type ParentId = string | null | undefined; export type ParentId = string | null | undefined;
@ -11,15 +11,38 @@ export interface LibraryViewProps {
parentId: string | null; parentId: string | null;
} }
interface Filters { export enum FeatureFilters {
Features?: string[]; HasSubtitles = 'HasSubtitles',
HasTrailer = 'HasTrailer',
HasSpecialFeature = 'HasSpecialFeature',
HasThemeSong = 'HasThemeSong',
HasThemeVideo = 'HasThemeVideo',
}
export enum EpisodeFilter {
ParentIndexNumber = 'ParentIndexNumber',
IsMissing = 'IsMissing',
IsUnaired = 'IsUnaired',
}
export enum VideoBasicFilter {
IsSD = 'IsSD',
IsHD = 'IsHD',
Is4K = 'Is4K',
Is3D = 'Is3D',
}
export interface Filters {
Features?: FeatureFilters[];
Genres?: string[]; Genres?: string[];
OfficialRatings?: string[]; OfficialRatings?: string[];
EpisodeFilter?: EpisodeFilter[];
Status?: ItemFilter[]; Status?: ItemFilter[];
EpisodesStatus?: string[]; EpisodesStatus?: string[];
SeriesStatus?: SeriesStatus[]; SeriesStatus?: SeriesStatus[];
StudioIds?: string[]; StudioIds?: string[];
Tags?: string[]; Tags?: string[];
VideoBasicFilter?: VideoBasicFilter[];
VideoTypes?: VideoType[]; VideoTypes?: VideoType[];
Years?: number[]; Years?: number[];
} }
@ -39,10 +62,6 @@ export interface LibraryViewSettings {
ShowTitle: boolean; ShowTitle: boolean;
ShowYear?: boolean; ShowYear?: boolean;
Filters?: Filters; Filters?: Filters;
IsSD?: boolean;
IsHD?: boolean;
Is4K?: boolean;
Is3D?: boolean;
NameLessThan?: string | null; NameLessThan?: string | null;
NameStartsWith?: string | null; NameStartsWith?: string | null;
} }