mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
use filtermenu
This commit is contained in:
parent
0acac1b52d
commit
0dc9ad8904
7 changed files with 215 additions and 51 deletions
|
@ -1,38 +1,53 @@
|
||||||
import React, { FC, useCallback, useEffect, useRef } from 'react';
|
import React, { FC, useCallback, useEffect, useRef } from 'react';
|
||||||
import { Events } from 'jellyfin-apiclient';
|
|
||||||
import IconButtonElement from '../../elements/IconButtonElement';
|
import IconButtonElement from '../../elements/IconButtonElement';
|
||||||
import { QueryI } from './interface';
|
import { FiltersI } from './interface';
|
||||||
|
|
||||||
interface FilterI {
|
interface FilterI {
|
||||||
query: QueryI;
|
topParentId?: string | null;
|
||||||
getFilterMode: () => string | null;
|
getItemTypes: () => string[];
|
||||||
|
getFilters: () => FiltersI;
|
||||||
|
getSettingsKey: () => string;
|
||||||
|
getFilterMenuOptions: () => Record<string, never>;
|
||||||
|
getVisibleFilters: () => string[];
|
||||||
reloadItems: () => void;
|
reloadItems: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Filter: FC<FilterI> = ({ query, getFilterMode, reloadItems }) => {
|
const Filter: FC<FilterI> = ({
|
||||||
|
topParentId,
|
||||||
|
getItemTypes,
|
||||||
|
getSettingsKey,
|
||||||
|
getFilters,
|
||||||
|
getVisibleFilters,
|
||||||
|
getFilterMenuOptions,
|
||||||
|
reloadItems
|
||||||
|
}) => {
|
||||||
const element = useRef<HTMLDivElement>(null);
|
const element = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const showFilterMenu = useCallback(() => {
|
const showFilterMenu = useCallback(() => {
|
||||||
import('../../components/filterdialog/filterdialog').then(({default: filterDialogFactory}) => {
|
import('../../components/filtermenu/filtermenu').then(({default: FilterMenu}) => {
|
||||||
const filterDialog = new filterDialogFactory({
|
const filterMenu = new FilterMenu();
|
||||||
query: query,
|
filterMenu.show({
|
||||||
mode: getFilterMode(),
|
settingsKey: getSettingsKey(),
|
||||||
serverId: window.ApiClient.serverId()
|
settings: getFilters(),
|
||||||
});
|
visibleSettings: getVisibleFilters(),
|
||||||
Events.on(filterDialog, 'filterchange', () => {
|
parentId: topParentId,
|
||||||
query.StartIndex = 0;
|
itemTypes: getItemTypes(),
|
||||||
|
serverId: window.ApiClient.serverId(),
|
||||||
|
filterMenuOptions: getFilterMenuOptions()
|
||||||
|
}).then(() => {
|
||||||
reloadItems();
|
reloadItems();
|
||||||
});
|
});
|
||||||
filterDialog.show();
|
|
||||||
});
|
});
|
||||||
}, [getFilterMode, query, reloadItems]);
|
}, [getSettingsKey, getFilters, getVisibleFilters, topParentId, getItemTypes, getFilterMenuOptions, reloadItems]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const btnFilter = element.current?.querySelector('.btnFilter');
|
const btnFilter = element.current?.querySelector('.btnFilter');
|
||||||
|
|
||||||
if (btnFilter) {
|
btnFilter?.addEventListener('click', showFilterMenu);
|
||||||
btnFilter.addEventListener('click', showFilterMenu);
|
|
||||||
}
|
return () => {
|
||||||
|
btnFilter?.removeEventListener('click', showFilterMenu);
|
||||||
|
};
|
||||||
}, [showFilterMenu]);
|
}, [showFilterMenu]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -21,8 +21,7 @@ interface ViewItemsContainerI {
|
||||||
isBtnNewCollectionEnabled?: boolean;
|
isBtnNewCollectionEnabled?: boolean;
|
||||||
isAlphaPickerEnabled?: boolean;
|
isAlphaPickerEnabled?: boolean;
|
||||||
getBasekey: () => string;
|
getBasekey: () => string;
|
||||||
getFilterMode: () => string;
|
getItemTypes: () => string[];
|
||||||
getItemTypes: () => string;
|
|
||||||
getNoItemsMessage: () => string;
|
getNoItemsMessage: () => string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +32,6 @@ const ViewItemsContainer: FC<ViewItemsContainerI> = ({
|
||||||
isBtnNewCollectionEnabled = false,
|
isBtnNewCollectionEnabled = false,
|
||||||
isAlphaPickerEnabled = true,
|
isAlphaPickerEnabled = true,
|
||||||
getBasekey,
|
getBasekey,
|
||||||
getFilterMode,
|
|
||||||
getItemTypes,
|
getItemTypes,
|
||||||
getNoItemsMessage
|
getNoItemsMessage
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -62,11 +60,52 @@ const ViewItemsContainer: FC<ViewItemsContainerI> = ({
|
||||||
};
|
};
|
||||||
}, [getDefaultSortBy, getSettingsKey]);
|
}, [getDefaultSortBy, getSettingsKey]);
|
||||||
|
|
||||||
|
const getFilters = useCallback(() => {
|
||||||
|
const basekey = getSettingsKey();
|
||||||
|
return {
|
||||||
|
IsPlayed: userSettings.getFilter(basekey + '-filter-IsPlayed') === 'true',
|
||||||
|
IsUnplayed: userSettings.getFilter(basekey + '-filter-IsUnplayed') === 'true',
|
||||||
|
IsFavorite: userSettings.getFilter(basekey + '-filter-IsFavorite') === 'true',
|
||||||
|
IsResumable: userSettings.getFilter(basekey + '-filter-IsResumable') === 'true',
|
||||||
|
Is4K: userSettings.getFilter(basekey + '-filter-Is4K') === 'true',
|
||||||
|
IsHD: userSettings.getFilter(basekey + '-filter-IsHD') === 'true',
|
||||||
|
IsSD: userSettings.getFilter(basekey + '-filter-IsSD') === 'true',
|
||||||
|
Is3D: userSettings.getFilter(basekey + '-filter-Is3D') === 'true',
|
||||||
|
VideoTypes: userSettings.getFilter(basekey + '-filter-VideoTypes'),
|
||||||
|
SeriesStatus: userSettings.getFilter(basekey + '-filter-SeriesStatus'),
|
||||||
|
HasSubtitles: userSettings.getFilter(basekey + '-filter-HasSubtitles'),
|
||||||
|
HasTrailer: userSettings.getFilter(basekey + '-filter-HasTrailer'),
|
||||||
|
HasSpecialFeature: userSettings.getFilter(basekey + '-filter-HasSpecialFeature'),
|
||||||
|
HasThemeSong: userSettings.getFilter(basekey + '-filter-HasThemeSong'),
|
||||||
|
HasThemeVideo: userSettings.getFilter(basekey + '-filter-HasThemeVideo'),
|
||||||
|
GenreIds: userSettings.getFilter(basekey + '-filter-GenreIds')
|
||||||
|
};
|
||||||
|
}, [getSettingsKey]);
|
||||||
|
|
||||||
|
const getFilterMenuOptions = useCallback(() => {
|
||||||
|
return {};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getVisibleFilters = useCallback(() => {
|
||||||
|
return [
|
||||||
|
'IsUnplayed',
|
||||||
|
'IsPlayed',
|
||||||
|
'IsFavorite',
|
||||||
|
'IsResumable',
|
||||||
|
'VideoType',
|
||||||
|
'HasSubtitles',
|
||||||
|
'HasTrailer',
|
||||||
|
'HasSpecialFeature',
|
||||||
|
'HasThemeSong',
|
||||||
|
'HasThemeVideo'
|
||||||
|
];
|
||||||
|
}, []);
|
||||||
|
|
||||||
const getQuery = useCallback(() => {
|
const getQuery = useCallback(() => {
|
||||||
const query: QueryI = {
|
const query: QueryI = {
|
||||||
SortBy: getSortValues().sortBy,
|
SortBy: getSortValues().sortBy,
|
||||||
SortOrder: getSortValues().sortOrder,
|
SortOrder: getSortValues().sortOrder,
|
||||||
IncludeItemTypes: getItemTypes(),
|
IncludeItemTypes: getItemTypes().join(','),
|
||||||
Recursive: true,
|
Recursive: true,
|
||||||
Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo',
|
Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo',
|
||||||
ImageTypeLimit: 1,
|
ImageTypeLimit: 1,
|
||||||
|
@ -84,6 +123,97 @@ const ViewItemsContainer: FC<ViewItemsContainerI> = ({
|
||||||
return query;
|
return query;
|
||||||
}, [getSortValues, getItemTypes, topParentId, getBasekey, getSettingsKey]);
|
}, [getSortValues, getItemTypes, topParentId, getBasekey, getSettingsKey]);
|
||||||
|
|
||||||
|
const getQueryWithFilters = useCallback(() => {
|
||||||
|
const query = getQuery();
|
||||||
|
|
||||||
|
const queryFilters = [];
|
||||||
|
let hasFilters;
|
||||||
|
|
||||||
|
const filters = getFilters();
|
||||||
|
|
||||||
|
if (filters.IsPlayed) {
|
||||||
|
queryFilters.push('IsPlayed');
|
||||||
|
hasFilters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.IsUnplayed) {
|
||||||
|
queryFilters.push('IsUnplayed');
|
||||||
|
hasFilters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.IsFavorite) {
|
||||||
|
queryFilters.push('IsFavorite');
|
||||||
|
hasFilters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.IsResumable) {
|
||||||
|
queryFilters.push('IsResumable');
|
||||||
|
hasFilters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.VideoTypes) {
|
||||||
|
hasFilters = true;
|
||||||
|
query.VideoTypes = filters.VideoTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.GenreIds) {
|
||||||
|
hasFilters = true;
|
||||||
|
query.GenreIds = filters.GenreIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.Is4K) {
|
||||||
|
query.Is4K = true;
|
||||||
|
hasFilters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.IsHD) {
|
||||||
|
query.IsHD = true;
|
||||||
|
hasFilters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.IsSD) {
|
||||||
|
query.IsHD = false;
|
||||||
|
hasFilters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.Is3D) {
|
||||||
|
query.Is3D = true;
|
||||||
|
hasFilters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.HasSubtitles) {
|
||||||
|
query.HasSubtitles = true;
|
||||||
|
hasFilters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.HasTrailer) {
|
||||||
|
query.HasTrailer = true;
|
||||||
|
hasFilters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.HasSpecialFeature) {
|
||||||
|
query.HasSpecialFeature = true;
|
||||||
|
hasFilters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.HasThemeSong) {
|
||||||
|
query.HasThemeSong = true;
|
||||||
|
hasFilters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters.HasThemeVideo) {
|
||||||
|
query.HasThemeVideo = true;
|
||||||
|
hasFilters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
query.Filters = queryFilters.length ? queryFilters.join(',') : null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
query: query,
|
||||||
|
hasFilters: hasFilters
|
||||||
|
};
|
||||||
|
}, [getQuery, getFilters]);
|
||||||
|
|
||||||
const getSortMenuOptions = useCallback(() => {
|
const getSortMenuOptions = useCallback(() => {
|
||||||
return [{
|
return [{
|
||||||
name: globalize.translate('Name'),
|
name: globalize.translate('Name'),
|
||||||
|
@ -123,7 +253,7 @@ const ViewItemsContainer: FC<ViewItemsContainerI> = ({
|
||||||
}, [getViewSettings]);
|
}, [getViewSettings]);
|
||||||
|
|
||||||
const getContext = useCallback(() => {
|
const getContext = useCallback(() => {
|
||||||
const itemType = getItemTypes();
|
const itemType = getItemTypes().join(',');
|
||||||
if (itemType === 'Movie' || itemType === 'BoxSet') {
|
if (itemType === 'Movie' || itemType === 'BoxSet') {
|
||||||
return 'movies';
|
return 'movies';
|
||||||
}
|
}
|
||||||
|
@ -139,8 +269,8 @@ const ViewItemsContainer: FC<ViewItemsContainerI> = ({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
loading.show();
|
loading.show();
|
||||||
const query = getQuery();
|
const querywithfilters = getQueryWithFilters().query;
|
||||||
window.ApiClient.getItems(window.ApiClient.getCurrentUserId(), query).then((result) => {
|
window.ApiClient.getItems(window.ApiClient.getCurrentUserId(), querywithfilters).then((result) => {
|
||||||
setItemsResult(result);
|
setItemsResult(result);
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
|
|
||||||
|
@ -150,7 +280,7 @@ const ViewItemsContainer: FC<ViewItemsContainerI> = ({
|
||||||
autoFocuser.autoFocus(page);
|
autoFocuser.autoFocus(page);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, [getQuery]);
|
}, [getQueryWithFilters]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reloadItems();
|
reloadItems();
|
||||||
|
@ -171,7 +301,15 @@ const ViewItemsContainer: FC<ViewItemsContainerI> = ({
|
||||||
reloadItems={reloadItems}
|
reloadItems={reloadItems}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{isBtnFilterEnabled && <Filter query={getQuery()} getFilterMode={getFilterMode} reloadItems={reloadItems} />}
|
{isBtnFilterEnabled && <Filter
|
||||||
|
topParentId={topParentId}
|
||||||
|
getFilters={getFilters}
|
||||||
|
getSettingsKey={getSettingsKey}
|
||||||
|
getItemTypes={getItemTypes}
|
||||||
|
getVisibleFilters={getVisibleFilters}
|
||||||
|
getFilterMenuOptions={getFilterMenuOptions}
|
||||||
|
reloadItems={reloadItems}
|
||||||
|
/>}
|
||||||
|
|
||||||
{isBtnNewCollectionEnabled && <NewCollection />}
|
{isBtnNewCollectionEnabled && <NewCollection />}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,39 @@ export interface QueryI {
|
||||||
IsFavorite?: boolean;
|
IsFavorite?: boolean;
|
||||||
IsMissing?: boolean;
|
IsMissing?: boolean;
|
||||||
Limit:number;
|
Limit:number;
|
||||||
|
NameStartsWithOrGreater?: string;
|
||||||
NameLessThan?: string;
|
NameLessThan?: string;
|
||||||
NameStartsWith?: string;
|
NameStartsWith?: string;
|
||||||
|
VideoTypes?: string;
|
||||||
|
GenreIds?: string;
|
||||||
|
Is4K?: boolean;
|
||||||
|
IsHD?: boolean;
|
||||||
|
Is3D?: boolean;
|
||||||
|
HasSubtitles?: boolean;
|
||||||
|
HasTrailer?: boolean;
|
||||||
|
HasSpecialFeature?: boolean;
|
||||||
|
HasThemeSong?: boolean;
|
||||||
|
HasThemeVideo?: boolean;
|
||||||
|
Filters?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FiltersI {
|
||||||
|
IsPlayed: boolean;
|
||||||
|
IsUnplayed: boolean;
|
||||||
|
IsFavorite: boolean;
|
||||||
|
IsResumable: boolean;
|
||||||
|
Is4K: boolean;
|
||||||
|
IsHD: boolean;
|
||||||
|
IsSD: boolean;
|
||||||
|
Is3D: boolean;
|
||||||
|
VideoTypes: string;
|
||||||
|
SeriesStatus: string;
|
||||||
|
HasSubtitles: string;
|
||||||
|
HasTrailer: string;
|
||||||
|
HasSpecialFeature: string;
|
||||||
|
HasThemeSong: string;
|
||||||
|
HasThemeVideo: string;
|
||||||
|
GenreIds: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CardOptionsI {
|
export interface CardOptionsI {
|
||||||
|
|
|
@ -11,12 +11,8 @@ const CollectionsView: FC<CollectionsViewI> = ({ topParentId }) => {
|
||||||
return 'collections';
|
return 'collections';
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getFilterMode = useCallback(() => {
|
|
||||||
return 'movies';
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const getItemTypes = useCallback(() => {
|
const getItemTypes = useCallback(() => {
|
||||||
return 'BoxSet';
|
return ['BoxSet'];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getNoItemsMessage = useCallback(() => {
|
const getNoItemsMessage = useCallback(() => {
|
||||||
|
@ -30,7 +26,6 @@ const CollectionsView: FC<CollectionsViewI> = ({ topParentId }) => {
|
||||||
isBtnNewCollectionEnabled={true}
|
isBtnNewCollectionEnabled={true}
|
||||||
isAlphaPickerEnabled={false}
|
isAlphaPickerEnabled={false}
|
||||||
getBasekey={getBasekey}
|
getBasekey={getBasekey}
|
||||||
getFilterMode={getFilterMode}
|
|
||||||
getItemTypes={getItemTypes}
|
getItemTypes={getItemTypes}
|
||||||
getNoItemsMessage={getNoItemsMessage}
|
getNoItemsMessage={getNoItemsMessage}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -11,12 +11,8 @@ const FavoritesView: FC<FavoritesViewI> = ({ topParentId }) => {
|
||||||
return 'favorites';
|
return 'favorites';
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getFilterMode = useCallback(() => {
|
|
||||||
return 'movies';
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const getItemTypes = useCallback(() => {
|
const getItemTypes = useCallback(() => {
|
||||||
return 'Movie';
|
return ['Movie'];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getNoItemsMessage = useCallback(() => {
|
const getNoItemsMessage = useCallback(() => {
|
||||||
|
@ -27,7 +23,6 @@ const FavoritesView: FC<FavoritesViewI> = ({ topParentId }) => {
|
||||||
<ViewItemsContainer
|
<ViewItemsContainer
|
||||||
topParentId={topParentId}
|
topParentId={topParentId}
|
||||||
getBasekey={getBasekey}
|
getBasekey={getBasekey}
|
||||||
getFilterMode={getFilterMode}
|
|
||||||
getItemTypes={getItemTypes}
|
getItemTypes={getItemTypes}
|
||||||
getNoItemsMessage={getNoItemsMessage}
|
getNoItemsMessage={getNoItemsMessage}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -11,12 +11,8 @@ const MoviesView: FC<MoviesViewI> = ({ topParentId }) => {
|
||||||
return 'movies';
|
return 'movies';
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getFilterMode = useCallback(() => {
|
|
||||||
return 'movies';
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const getItemTypes = useCallback(() => {
|
const getItemTypes = useCallback(() => {
|
||||||
return 'Movie';
|
return ['Movie'];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getNoItemsMessage = useCallback(() => {
|
const getNoItemsMessage = useCallback(() => {
|
||||||
|
@ -28,7 +24,6 @@ const MoviesView: FC<MoviesViewI> = ({ topParentId }) => {
|
||||||
topParentId={topParentId}
|
topParentId={topParentId}
|
||||||
isBtnShuffleEnabled={true}
|
isBtnShuffleEnabled={true}
|
||||||
getBasekey={getBasekey}
|
getBasekey={getBasekey}
|
||||||
getFilterMode={getFilterMode}
|
|
||||||
getItemTypes={getItemTypes}
|
getItemTypes={getItemTypes}
|
||||||
getNoItemsMessage={getNoItemsMessage}
|
getNoItemsMessage={getNoItemsMessage}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -12,12 +12,8 @@ const TrailersView: FC<TrailersViewI> = ({ topParentId }) => {
|
||||||
return 'trailers';
|
return 'trailers';
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getFilterMode = useCallback(() => {
|
|
||||||
return 'movies';
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const getItemTypes = useCallback(() => {
|
const getItemTypes = useCallback(() => {
|
||||||
return 'Trailer';
|
return ['Trailer'];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getNoItemsMessage = useCallback(() => {
|
const getNoItemsMessage = useCallback(() => {
|
||||||
|
@ -28,7 +24,6 @@ const TrailersView: FC<TrailersViewI> = ({ topParentId }) => {
|
||||||
<ViewItemsContainer
|
<ViewItemsContainer
|
||||||
topParentId={topParentId}
|
topParentId={topParentId}
|
||||||
getBasekey={getBasekey}
|
getBasekey={getBasekey}
|
||||||
getFilterMode={getFilterMode}
|
|
||||||
getItemTypes={getItemTypes}
|
getItemTypes={getItemTypes}
|
||||||
getNoItemsMessage={getNoItemsMessage}
|
getNoItemsMessage={getNoItemsMessage}
|
||||||
/>
|
/>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue