jellyfish-web/src/view/components/ViewItemsContainer.tsx

382 lines
13 KiB
TypeScript
Raw Normal View History

import type { BaseItemDtoQueryResult } from '@jellyfin/sdk/lib/generated-client';
import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2022-08-21 03:09:22 +03:00
import loading from '../../components/loading/loading';
import * as userSettings from '../../scripts/settings/userSettings';
import AlphaPickerContainer from './AlphaPickerContainer';
import Filter from './Filter';
import ItemsContainer from './ItemsContainer';
import Pagination from './Pagination';
import SelectView from './SelectView';
import Shuffle from './Shuffle';
import Sort from './Sort';
import NewCollection from './NewCollection';
import globalize from '../../scripts/globalize';
import layoutManager from '../../components/layoutManager';
import { AlphaPickerValueI, QueryI } from './interface';
2022-08-21 03:09:22 +03:00
2022-10-02 19:07:42 +03:00
interface ViewItemsContainerI {
2022-08-21 03:09:22 +03:00
topParentId: string | null;
isBtnShuffleEnabled?: boolean;
isBtnFilterEnabled?: boolean;
isBtnNewCollectionEnabled?: boolean;
isAlphaPickerEnabled?: boolean;
getBasekey: () => string;
2022-10-03 02:33:43 +03:00
getItemTypes: () => string[];
2022-08-21 03:09:22 +03:00
getNoItemsMessage: () => string;
}
2022-10-02 19:07:42 +03:00
const ViewItemsContainer: FC<ViewItemsContainerI> = ({
2022-08-21 03:09:22 +03:00
topParentId,
isBtnShuffleEnabled = false,
isBtnFilterEnabled = true,
isBtnNewCollectionEnabled = false,
isAlphaPickerEnabled = true,
getBasekey,
getItemTypes,
getNoItemsMessage
2022-10-02 19:07:42 +03:00
}) => {
2022-08-21 03:09:22 +03:00
const [ itemsResult, setItemsResult ] = useState<BaseItemDtoQueryResult>({});
const [ startIndex, setStartIndex ] = useState<number>(0);
const [ alphaPickerValue, setAlphaPickerValue ] = useState<AlphaPickerValueI>({});
2022-08-21 03:09:22 +03:00
const element = useRef<HTMLDivElement>(null);
const queryAlphaPickerValue = useMemo(() => ({
...alphaPickerValue
}), [alphaPickerValue]);
2022-08-21 03:09:22 +03:00
const getSettingsKey = useCallback(() => {
return `${topParentId} - ${getBasekey()}`;
}, [getBasekey, topParentId]);
const getVisibleViewSettings = useCallback(() => {
return [
'showTitle',
'showYear',
'imageType',
'cardLayout'
];
}, []);
2022-08-21 03:09:22 +03:00
const getViewSettings = useCallback(() => {
const basekey = getSettingsKey();
return {
showTitle: userSettings.get(basekey + '-showTitle', false) !== 'false',
showYear: userSettings.get(basekey + '-showYear', false) !== 'false',
imageType: userSettings.get(basekey + '-imageType', false) || 'primary',
viewType: userSettings.get(basekey + '-viewType', false) || 'images',
cardLayout: userSettings.get(basekey + '-cardLayout', false) !== 'false'
};
2022-08-21 03:09:22 +03:00
}, [getSettingsKey]);
const getDefaultSortBy = useCallback(() => {
return 'SortName';
}, []);
const getSortValues = useCallback(() => {
const basekey = getSettingsKey();
return {
sortBy: userSettings.getFilter(basekey + '-sortby') || getDefaultSortBy(),
sortOrder: userSettings.getFilter(basekey + '-sortorder') === 'Descending' ? 'Descending' : 'Ascending'
};
}, [getDefaultSortBy, getSettingsKey]);
2022-10-03 02:33:43 +03:00
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(() => {
let fields = 'BasicSyncInfo,MediaSourceCount';
const viewsettings = getViewSettings();
if (viewsettings.imageType === 'primary') {
fields += ',PrimaryImageAspectRatio';
}
if (viewsettings.showYear) {
fields += ',ProductionYear';
}
const query: QueryI = {
SortBy: getSortValues().sortBy,
SortOrder: getSortValues().sortOrder,
2022-10-03 02:33:43 +03:00
IncludeItemTypes: getItemTypes().join(','),
Recursive: true,
Fields: fields,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb,Disc,Logo',
Limit: userSettings.libraryPageSize(undefined),
StartIndex: startIndex,
ParentId: topParentId
};
if (getBasekey() === 'favorites') {
query.IsFavorite = true;
}
const queryInfo: QueryI = Object.assign(query, queryAlphaPickerValue || {});
return queryInfo;
}, [getViewSettings, getSortValues, getItemTypes, startIndex, topParentId, getBasekey, queryAlphaPickerValue]);
2022-10-03 02:33:43 +03:00
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(() => {
return [{
name: globalize.translate('Name'),
value: 'SortName,ProductionYear'
}, {
name: globalize.translate('OptionRandom'),
value: 'Random'
}, {
name: globalize.translate('OptionImdbRating'),
value: 'CommunityRating,SortName,ProductionYear'
}, {
name: globalize.translate('OptionCriticRating'),
value: 'CriticRating,SortName,ProductionYear'
}, {
name: globalize.translate('OptionDateAdded'),
value: 'DateCreated,SortName,ProductionYear'
}, {
name: globalize.translate('OptionDatePlayed'),
value: 'DatePlayed,SortName,ProductionYear'
}, {
name: globalize.translate('OptionParentalRating'),
value: 'OfficialRating,SortName,ProductionYear'
}, {
name: globalize.translate('OptionPlayCount'),
value: 'PlayCount,SortName,ProductionYear'
}, {
name: globalize.translate('OptionReleaseDate'),
value: 'PremiereDate,SortName,ProductionYear'
}, {
name: globalize.translate('Runtime'),
value: 'Runtime,SortName,ProductionYear'
}];
}, []);
2022-08-21 03:09:22 +03:00
const getContext = useCallback(() => {
2022-10-03 02:33:43 +03:00
const itemType = getItemTypes().join(',');
2022-08-21 03:09:22 +03:00
if (itemType === 'Movie' || itemType === 'BoxSet') {
return 'movies';
}
return null;
}, [getItemTypes]);
const reloadItems = useCallback(() => {
const page = element.current;
if (!page) {
console.error('Unexpected null reference');
return;
}
loading.show();
const query = getQueryWithFilters().query;
window.ApiClient.getItems(window.ApiClient.getCurrentUserId(), query).then((result) => {
2022-08-21 03:09:22 +03:00
setItemsResult(result);
window.scrollTo(0, 0);
loading.hide();
import('../../components/autoFocuser').then(({ default: autoFocuser }) => {
autoFocuser.autoFocus(page);
});
});
2022-10-03 02:33:43 +03:00
}, [getQueryWithFilters]);
2022-08-21 03:09:22 +03:00
useEffect(() => {
reloadItems();
}, [reloadItems]);
return (
<div ref={element}>
<div className='flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom focuscontainer-x'>
<Pagination
itemsResult= {itemsResult}
startIndex={startIndex}
setStartIndex={setStartIndex}
/>
2022-08-21 03:09:22 +03:00
{isBtnShuffleEnabled && <Shuffle itemsResult={itemsResult} topParentId={topParentId} />}
{<SelectView
getSettingsKey={getSettingsKey}
getVisibleViewSettings={getVisibleViewSettings}
getViewSettings={getViewSettings}
reloadItems={reloadItems}
/>}
<Sort
getSortMenuOptions={getSortMenuOptions}
getSortValues={getSortValues}
getSettingsKey={getSettingsKey}
reloadItems={reloadItems}
/>
2022-08-21 03:09:22 +03:00
2022-10-03 02:33:43 +03:00
{isBtnFilterEnabled && <Filter
topParentId={topParentId}
getFilters={getFilters}
getSettingsKey={getSettingsKey}
getItemTypes={getItemTypes}
getVisibleFilters={getVisibleFilters}
getFilterMenuOptions={getFilterMenuOptions}
reloadItems={reloadItems}
/>}
2022-08-21 03:09:22 +03:00
{isBtnNewCollectionEnabled && <NewCollection />}
</div>
{isAlphaPickerEnabled && <AlphaPickerContainer
getQuery={getQuery}
setAlphaPickerValue={setAlphaPickerValue}
setStartIndex={setStartIndex}
/>}
2022-08-21 03:09:22 +03:00
<ItemsContainer
getViewSettings={getViewSettings}
2022-08-21 03:09:22 +03:00
getContext={getContext}
items={itemsResult?.Items}
noItemsMessage={getNoItemsMessage()}
/>
<div className='flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom focuscontainer-x'>
<Pagination
itemsResult= {itemsResult}
startIndex={startIndex}
setStartIndex={setStartIndex}
/>
2022-08-21 03:09:22 +03:00
</div>
</div>
);
};
export default ViewItemsContainer;