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:
commit
5fb4b51cfb
12 changed files with 235 additions and 292 deletions
|
@ -10,6 +10,7 @@ import MuiAccordionSummary, {
|
|||
AccordionSummaryProps
|
||||
} from '@mui/material/AccordionSummary';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import { Badge } from '@mui/material';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Typography from '@mui/material/Typography';
|
||||
|
||||
|
@ -152,6 +153,9 @@ const FilterButton: FC<FilterButtonProps> = ({
|
|||
return viewType === LibraryTab.Episodes;
|
||||
};
|
||||
|
||||
const hasFilters =
|
||||
Object.values(libraryViewSettings.Filters || {}).some((filter) => !!filter);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<IconButton
|
||||
|
@ -161,7 +165,9 @@ const FilterButton: FC<FilterButtonProps> = ({
|
|||
className='paper-icon-button-light btnShuffle autoSize'
|
||||
onClick={handleClick}
|
||||
>
|
||||
<FilterListIcon />
|
||||
<Badge color='info' variant='dot' invisible={!hasFilters}>
|
||||
<FilterListIcon />
|
||||
</Badge>
|
||||
</IconButton>
|
||||
<Popover
|
||||
id={id}
|
||||
|
@ -239,7 +245,9 @@ const FilterButton: FC<FilterButtonProps> = ({
|
|||
id='filtersEpisodesStatus-header'
|
||||
>
|
||||
<Typography>
|
||||
{globalize.translate('HeaderEpisodesStatus')}
|
||||
{globalize.translate(
|
||||
'HeaderEpisodesStatus'
|
||||
)}
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
|
|
|
@ -3,12 +3,12 @@ import FormGroup from '@mui/material/FormGroup';
|
|||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import Checkbox from '@mui/material/Checkbox';
|
||||
import globalize from 'scripts/globalize';
|
||||
import { LibraryViewSettings } from 'types/library';
|
||||
import { EpisodeFilter, LibraryViewSettings } from 'types/library';
|
||||
|
||||
const episodesStatusOptions = [
|
||||
{ label: 'OptionSpecialEpisode', value: 'ParentIndexNumber' },
|
||||
{ label: 'OptionMissingEpisode', value: 'IsMissing' },
|
||||
{ label: 'OptionUnairedEpisode', value: 'IsUnaired' }
|
||||
const episodeFilterOptions = [
|
||||
{ label: 'OptionSpecialEpisode', value: EpisodeFilter.ParentIndexNumber },
|
||||
{ label: 'OptionMissingEpisode', value: EpisodeFilter.IsMissing },
|
||||
{ label: 'OptionUnairedEpisode', value: EpisodeFilter.IsUnaired }
|
||||
];
|
||||
|
||||
interface FiltersEpisodesStatusProps {
|
||||
|
@ -23,46 +23,39 @@ const FiltersEpisodesStatus: FC<FiltersEpisodesStatusProps> = ({
|
|||
const onFiltersEpisodesStatusChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
event.preventDefault();
|
||||
const value = String(event.target.value);
|
||||
const existingValue = libraryViewSettings?.Filters?.EpisodesStatus;
|
||||
const value = event.target.value as EpisodeFilter;
|
||||
const existingEpisodeFilter = libraryViewSettings?.Filters?.EpisodeFilter ?? [];
|
||||
|
||||
if (existingValue?.includes(value)) {
|
||||
const newValue = existingValue?.filter(
|
||||
(prevState: string) => prevState !== value
|
||||
);
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: { ...prevState.Filters, EpisodesStatus: newValue }
|
||||
}));
|
||||
} else {
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
EpisodesStatus: [...(existingValue ?? []), value]
|
||||
}
|
||||
}));
|
||||
}
|
||||
const updatedEpisodeFilter = existingEpisodeFilter.includes(value) ?
|
||||
existingEpisodeFilter.filter((filter) => filter !== value) :
|
||||
[...existingEpisodeFilter, value];
|
||||
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
EpisodeFilter: updatedEpisodeFilter.length ? updatedEpisodeFilter : undefined
|
||||
}
|
||||
}));
|
||||
},
|
||||
[setLibraryViewSettings, libraryViewSettings?.Filters?.EpisodesStatus]
|
||||
[setLibraryViewSettings, libraryViewSettings?.Filters?.EpisodeFilter]
|
||||
);
|
||||
|
||||
return (
|
||||
<FormGroup>
|
||||
{episodesStatusOptions.map((filter) => (
|
||||
{episodeFilterOptions.map((filter) => (
|
||||
<FormControlLabel
|
||||
key={filter.value}
|
||||
control={
|
||||
<Checkbox
|
||||
checked={
|
||||
!!libraryViewSettings?.Filters?.EpisodesStatus?.includes(
|
||||
String( filter.value)
|
||||
!!libraryViewSettings?.Filters?.EpisodeFilter?.includes(
|
||||
filter.value
|
||||
)
|
||||
}
|
||||
onChange={onFiltersEpisodesStatusChange}
|
||||
value={String(filter.value)}
|
||||
value={filter.value}
|
||||
/>
|
||||
}
|
||||
label={globalize.translate(filter.label)}
|
||||
|
|
|
@ -3,14 +3,14 @@ import FormGroup from '@mui/material/FormGroup';
|
|||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import Checkbox from '@mui/material/Checkbox';
|
||||
import globalize from 'scripts/globalize';
|
||||
import { LibraryViewSettings } from 'types/library';
|
||||
import { FeatureFilters, LibraryViewSettings } from 'types/library';
|
||||
|
||||
const featuresOptions = [
|
||||
{ label: 'Subtitles', value: 'HasSubtitles' },
|
||||
{ label: 'Trailers', value: 'HasTrailer' },
|
||||
{ label: 'Extras', value: 'HasSpecialFeature' },
|
||||
{ label: 'ThemeSongs', value: 'HasThemeSong' },
|
||||
{ label: 'ThemeVideos', value: 'HasThemeVideo' }
|
||||
{ label: 'Subtitles', value: FeatureFilters.HasSubtitles },
|
||||
{ label: 'Trailers', value: FeatureFilters.HasTrailer },
|
||||
{ label: 'Extras', value: FeatureFilters.HasSpecialFeature },
|
||||
{ label: 'ThemeSongs', value: FeatureFilters.HasThemeSong },
|
||||
{ label: 'ThemeVideos', value: FeatureFilters.HasThemeVideo }
|
||||
];
|
||||
|
||||
interface FiltersFeaturesProps {
|
||||
|
@ -27,29 +27,21 @@ const FiltersFeatures: FC<FiltersFeaturesProps> = ({
|
|||
const onFiltersFeaturesChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
event.preventDefault();
|
||||
const value = String(event.target.value);
|
||||
const existingValue =
|
||||
libraryViewSettings?.Filters?.Features;
|
||||
const value = event.target.value as FeatureFilters;
|
||||
const existingFeatures = libraryViewSettings?.Filters?.Features ?? [];
|
||||
|
||||
if (existingValue?.includes(value)) {
|
||||
const newValue = existingValue?.filter(
|
||||
(prevState: string) => prevState !== value
|
||||
);
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: { ...prevState.Filters, Features: newValue }
|
||||
}));
|
||||
} else {
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
Features: [...(existingValue ?? []), value]
|
||||
}
|
||||
}));
|
||||
}
|
||||
const updatedFeatures = existingFeatures.includes(value) ?
|
||||
existingFeatures.filter((filter) => filter !== value) :
|
||||
[...existingFeatures, value];
|
||||
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
Features: updatedFeatures.length ? updatedFeatures : undefined
|
||||
}
|
||||
}));
|
||||
},
|
||||
[setLibraryViewSettings, libraryViewSettings?.Filters?.Features]
|
||||
);
|
||||
|
@ -64,11 +56,11 @@ const FiltersFeatures: FC<FiltersFeaturesProps> = ({
|
|||
<Checkbox
|
||||
checked={
|
||||
!!libraryViewSettings?.Filters?.Features?.includes(
|
||||
String(filter.value)
|
||||
filter.value
|
||||
)
|
||||
}
|
||||
onChange={onFiltersFeaturesChange}
|
||||
value={String(filter.value)}
|
||||
value={filter.value}
|
||||
/>
|
||||
}
|
||||
label={globalize.translate(filter.label)}
|
||||
|
|
|
@ -19,28 +19,21 @@ const FiltersGenres: FC<FiltersGenresProps> = ({
|
|||
const onFiltersGenresChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
event.preventDefault();
|
||||
const value = String(event.target.value);
|
||||
const existingValue = libraryViewSettings?.Filters?.Genres;
|
||||
const value = event.target.value;
|
||||
const existingGenres = libraryViewSettings?.Filters?.Genres ?? [];
|
||||
|
||||
if (existingValue?.includes(value)) {
|
||||
const newValue = existingValue?.filter(
|
||||
(prevState: string) => prevState !== value
|
||||
);
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: { ...prevState.Filters, Genres: newValue }
|
||||
}));
|
||||
} else {
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
Genres: [...(existingValue ?? []), value]
|
||||
}
|
||||
}));
|
||||
}
|
||||
const updatedGenres = existingGenres.includes(value) ?
|
||||
existingGenres.filter((filter) => filter !== value) :
|
||||
[...existingGenres, value];
|
||||
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
Genres: updatedGenres.length ? updatedGenres : undefined
|
||||
}
|
||||
}));
|
||||
},
|
||||
[setLibraryViewSettings, libraryViewSettings?.Filters?.Genres]
|
||||
);
|
||||
|
|
|
@ -19,28 +19,21 @@ const FiltersOfficialRatings: FC<FiltersOfficialRatingsProps> = ({
|
|||
const onFiltersOfficialRatingsChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
event.preventDefault();
|
||||
const value = String(event.target.value);
|
||||
const existingValue = libraryViewSettings?.Filters?.OfficialRatings;
|
||||
const value = event.target.value;
|
||||
const existingOfficialRatings = libraryViewSettings?.Filters?.OfficialRatings ?? [];
|
||||
|
||||
if (existingValue?.includes(value)) {
|
||||
const newValue = existingValue?.filter(
|
||||
(prevState: string) => prevState !== value
|
||||
);
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: { ...prevState.Filters, OfficialRatings: newValue }
|
||||
}));
|
||||
} else {
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
OfficialRatings: [...(existingValue ?? []), value]
|
||||
}
|
||||
}));
|
||||
}
|
||||
const updatedOfficialRatings = existingOfficialRatings.includes(value) ?
|
||||
existingOfficialRatings.filter((filter) => filter !== value) :
|
||||
[...existingOfficialRatings, value];
|
||||
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
OfficialRatings: updatedOfficialRatings.length ? updatedOfficialRatings : undefined
|
||||
}
|
||||
}));
|
||||
},
|
||||
[setLibraryViewSettings, libraryViewSettings?.Filters?.OfficialRatings]
|
||||
);
|
||||
|
|
|
@ -25,27 +25,20 @@ const FiltersSeriesStatus: FC<FiltersSeriesStatusProps> = ({
|
|||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
event.preventDefault();
|
||||
const value = event.target.value as SeriesStatus;
|
||||
const existingValue = libraryViewSettings?.Filters?.SeriesStatus;
|
||||
const existingSeriesStatus = libraryViewSettings?.Filters?.SeriesStatus ?? [];
|
||||
|
||||
if (existingValue?.includes(value)) {
|
||||
const newValue = existingValue?.filter(
|
||||
(prevState: SeriesStatus) => prevState !== value
|
||||
);
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: { ...prevState.Filters, SeriesStatus: newValue }
|
||||
}));
|
||||
} else {
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
SeriesStatus: [...(existingValue ?? []), value]
|
||||
}
|
||||
}));
|
||||
}
|
||||
const updatedSeriesStatus = existingSeriesStatus.includes(value) ?
|
||||
existingSeriesStatus.filter((filter) => filter !== value) :
|
||||
[...existingSeriesStatus, value];
|
||||
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
SeriesStatus: updatedSeriesStatus.length ? updatedSeriesStatus : undefined
|
||||
}
|
||||
}));
|
||||
},
|
||||
[setLibraryViewSettings, libraryViewSettings?.Filters?.SeriesStatus]
|
||||
);
|
||||
|
|
|
@ -29,27 +29,20 @@ const FiltersStatus: FC<FiltersStatusProps> = ({
|
|||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
event.preventDefault();
|
||||
const value = event.target.value as ItemFilter;
|
||||
const existingValue = libraryViewSettings?.Filters?.Status;
|
||||
const existingStatus = libraryViewSettings?.Filters?.Status ?? [];
|
||||
|
||||
if (existingValue?.includes(value)) {
|
||||
const newValue = existingValue?.filter(
|
||||
(prevState: ItemFilter) => prevState !== value
|
||||
);
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: { ...prevState.Filters, Status: newValue }
|
||||
}));
|
||||
} else {
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
Status: [...(existingValue ?? []), value]
|
||||
}
|
||||
}));
|
||||
}
|
||||
const updatedStatus = existingStatus.includes(value) ?
|
||||
existingStatus.filter((filter) => filter !== value) :
|
||||
[...existingStatus, value];
|
||||
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
Status: updatedStatus.length ? updatedStatus : undefined
|
||||
}
|
||||
}));
|
||||
},
|
||||
[setLibraryViewSettings, libraryViewSettings?.Filters?.Status]
|
||||
);
|
||||
|
|
|
@ -19,30 +19,23 @@ const FiltersStudios: FC<FiltersStudiosProps> = ({
|
|||
const onFiltersStudiosChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
event.preventDefault();
|
||||
const value = String(event.target.value);
|
||||
const existingValue = libraryViewSettings?.Filters?.StudioIds;
|
||||
const value = event.target.value;
|
||||
const existingStudioIds = libraryViewSettings?.Filters?.StudioIds ?? [];
|
||||
|
||||
if (existingValue?.includes(value)) {
|
||||
const newValue = existingValue?.filter(
|
||||
(prevState: string) => prevState !== value
|
||||
);
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: { ...prevState.Filters, StudioIds: newValue }
|
||||
}));
|
||||
} else {
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
StudioIds: [...(existingValue ?? []), value]
|
||||
}
|
||||
}));
|
||||
}
|
||||
const updatedStudioIds = existingStudioIds.includes(value) ?
|
||||
existingStudioIds.filter((filter) => filter !== value) :
|
||||
[...existingStudioIds, value];
|
||||
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
StudioIds: updatedStudioIds.length ? updatedStudioIds : undefined
|
||||
}
|
||||
}));
|
||||
},
|
||||
[setLibraryViewSettings, libraryViewSettings?.Filters?.StudioIds]
|
||||
[setLibraryViewSettings, libraryViewSettings.Filters?.StudioIds]
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
@ -19,30 +19,23 @@ const FiltersTags: FC<FiltersTagsProps> = ({
|
|||
const onFiltersTagsChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
event.preventDefault();
|
||||
const value = String(event.target.value);
|
||||
const existingValue = libraryViewSettings?.Filters?.Tags;
|
||||
const value = event.target.value;
|
||||
const existingTags = libraryViewSettings?.Filters?.Tags ?? [];
|
||||
|
||||
if (existingValue?.includes(value)) {
|
||||
const newValue = existingValue?.filter(
|
||||
(prevState: string) => prevState !== value
|
||||
);
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: { ...prevState.Filters, Tags: newValue }
|
||||
}));
|
||||
} else {
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
Tags: [...(existingValue ?? []), value]
|
||||
}
|
||||
}));
|
||||
}
|
||||
const updatedTags = existingTags.includes(value) ?
|
||||
existingTags.filter((filter) => filter !== value) :
|
||||
[...existingTags, value];
|
||||
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
Tags: updatedTags.length ? updatedTags : undefined
|
||||
}
|
||||
}));
|
||||
},
|
||||
[setLibraryViewSettings, libraryViewSettings?.Filters?.Tags]
|
||||
[setLibraryViewSettings, libraryViewSettings.Filters?.Tags]
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
@ -2,9 +2,15 @@ import React, { FC, useCallback } from 'react';
|
|||
import FormGroup from '@mui/material/FormGroup';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
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 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 = [
|
||||
{ label: 'DVD', value: VideoType.Dvd },
|
||||
|
@ -21,93 +27,67 @@ const FiltersVideoTypes: FC<FiltersVideoTypesProps> = ({
|
|||
libraryViewSettings,
|
||||
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(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
event.preventDefault();
|
||||
const value = event.target.value as VideoType;
|
||||
const existingValue = libraryViewSettings?.Filters?.VideoTypes;
|
||||
const existingVideoTypes = libraryViewSettings?.Filters?.VideoTypes ?? [];
|
||||
|
||||
if (existingValue?.includes(value)) {
|
||||
const newValue = existingValue?.filter(
|
||||
(prevState: VideoType) => prevState !== value
|
||||
);
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: { ...prevState.Filters, VideoTypes: newValue }
|
||||
}));
|
||||
} else {
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
VideoTypes: [...(existingValue ?? []), value]
|
||||
}
|
||||
}));
|
||||
}
|
||||
const updatedVideoTypes = existingVideoTypes.includes(value) ?
|
||||
existingVideoTypes.filter((filter) => filter !== value) :
|
||||
[...existingVideoTypes, value];
|
||||
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
VideoTypes: updatedVideoTypes.length ? updatedVideoTypes : undefined
|
||||
}
|
||||
}));
|
||||
},
|
||||
[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 (
|
||||
<FormGroup>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={libraryViewSettings.IsSD}
|
||||
onChange={handleChange}
|
||||
name='IsSD'
|
||||
/>
|
||||
}
|
||||
label={globalize.translate('SD')}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={libraryViewSettings.IsHD}
|
||||
onChange={handleChange}
|
||||
name='IsHD'
|
||||
/>
|
||||
}
|
||||
label={globalize.translate('HD')}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={
|
||||
libraryViewSettings.Is4K
|
||||
{videoBasicFilterOptions
|
||||
.map((filter) => (
|
||||
<FormControlLabel
|
||||
key={filter.value}
|
||||
control={
|
||||
<Checkbox
|
||||
checked={
|
||||
!!libraryViewSettings?.Filters?.VideoBasicFilter?.includes(filter.value)
|
||||
}
|
||||
onChange={onFiltersvideoStandardChange}
|
||||
value={filter.value}
|
||||
/>
|
||||
}
|
||||
onChange={handleChange}
|
||||
name='Is4K'
|
||||
label={filter.label}
|
||||
/>
|
||||
}
|
||||
label={globalize.translate('4K')}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={
|
||||
libraryViewSettings.Is3D
|
||||
}
|
||||
onChange={handleChange}
|
||||
name='Is3D'
|
||||
/>
|
||||
}
|
||||
label={globalize.translate('3D')}
|
||||
/>
|
||||
))}
|
||||
{videoTypesOptions
|
||||
.map((filter) => (
|
||||
<FormControlLabel
|
||||
|
|
|
@ -20,27 +20,20 @@ const FiltersYears: FC<FiltersYearsProps> = ({
|
|||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
event.preventDefault();
|
||||
const value = Number(event.target.value);
|
||||
const existingValue = libraryViewSettings?.Filters?.Years;
|
||||
const existingYears = libraryViewSettings?.Filters?.Years ?? [];
|
||||
|
||||
if (existingValue?.includes(value)) {
|
||||
const newValue = existingValue?.filter(
|
||||
(prevState: number) => prevState !== value
|
||||
);
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: { ...prevState.Filters, Years: newValue }
|
||||
}));
|
||||
} else {
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
Years: [...(existingValue ?? []), value]
|
||||
}
|
||||
}));
|
||||
}
|
||||
const updatedYears = existingYears.includes(value) ?
|
||||
existingYears.filter((filter) => filter !== value) :
|
||||
[...existingYears, value];
|
||||
|
||||
setLibraryViewSettings((prevState) => ({
|
||||
...prevState,
|
||||
StartIndex: 0,
|
||||
Filters: {
|
||||
...prevState.Filters,
|
||||
Years: updatedYears.length ? updatedYears : undefined
|
||||
}
|
||||
}));
|
||||
},
|
||||
[setLibraryViewSettings, libraryViewSettings?.Filters?.Years]
|
||||
);
|
||||
|
|
|
@ -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 { SortOrder } from '@jellyfin/sdk/lib/generated-client/models/sort-order';
|
||||
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 { ImageType } from '@jellyfin/sdk/lib/generated-client';
|
||||
|
||||
export type ParentId = string | null | undefined;
|
||||
|
||||
|
@ -11,15 +11,38 @@ export interface LibraryViewProps {
|
|||
parentId: string | null;
|
||||
}
|
||||
|
||||
interface Filters {
|
||||
Features?: string[];
|
||||
export enum FeatureFilters {
|
||||
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[];
|
||||
OfficialRatings?: string[];
|
||||
EpisodeFilter?: EpisodeFilter[];
|
||||
Status?: ItemFilter[];
|
||||
EpisodesStatus?: string[];
|
||||
SeriesStatus?: SeriesStatus[];
|
||||
StudioIds?: string[];
|
||||
Tags?: string[];
|
||||
VideoBasicFilter?: VideoBasicFilter[];
|
||||
VideoTypes?: VideoType[];
|
||||
Years?: number[];
|
||||
}
|
||||
|
@ -39,10 +62,6 @@ export interface LibraryViewSettings {
|
|||
ShowTitle: boolean;
|
||||
ShowYear?: boolean;
|
||||
Filters?: Filters;
|
||||
IsSD?: boolean;
|
||||
IsHD?: boolean;
|
||||
Is4K?: boolean;
|
||||
Is3D?: boolean;
|
||||
NameLessThan?: string | null;
|
||||
NameStartsWith?: string | null;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue