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

418 lines
13 KiB
TypeScript
Raw Normal View History

import type { BaseItemDtoQueryResult } from '@jellyfin/sdk/lib/generated-client';
2022-10-14 02:07:54 +03:00
import React, { FC, useCallback, useEffect, useRef, useState } from 'react';
2022-08-21 03:09:22 +03:00
2022-10-27 00:59:46 +03:00
import loading from '../loading/loading';
2022-08-21 03:09:22 +03:00
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';
2022-10-27 00:59:46 +03:00
import { CardOptions, ViewQuerySettings } from '../../types/interface';
import ServerConnections from '../ServerConnections';
import { useLocalStorage } from '../../hooks/useLocalStorage';
import listview from '../listview/listview';
import cardBuilder from '../cardbuilder/cardBuilder';
2022-08-21 03:09:22 +03:00
2022-10-14 02:07:54 +03:00
interface ViewItemsContainerProps {
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-21 21:47:54 +03:00
const getDefaultSortBy = () => {
return 'SortName';
};
const getVisibleViewSettings = () => {
return [
'showTitle',
'showYear',
'imageType',
'cardLayout'
];
};
const getFilterMenuOptions = () => {
return {};
};
const getVisibleFilters = () => {
return [
'IsUnplayed',
'IsPlayed',
'IsFavorite',
'IsResumable',
'VideoType',
'HasSubtitles',
'HasTrailer',
'HasSpecialFeature',
'HasThemeSong',
'HasThemeVideo'
];
};
const getSortMenuOptions = () => {
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-10-27 00:59:46 +03:00
const defaultViewQuerySettings: ViewQuerySettings = {
2022-10-21 21:47:54 +03:00
showTitle: true,
showYear: true,
imageType: 'primary',
viewType: '',
2022-10-27 00:59:46 +03:00
cardLayout: false,
2022-10-21 21:47:54 +03:00
SortBy: getDefaultSortBy(),
SortOrder: 'Ascending',
IsPlayed: false,
IsUnplayed: false,
IsFavorite: false,
IsResumable: false,
Is4K: null,
IsHD: null,
IsSD: null,
Is3D: null,
VideoTypes: '',
SeriesStatus: '',
HasSubtitles: null,
HasTrailer: null,
HasSpecialFeature: null,
HasThemeSong: null,
HasThemeVideo: null,
GenreIds: '',
StartIndex: 0
};
2022-10-14 02:07:54 +03:00
const ViewItemsContainer: FC<ViewItemsContainerProps> = ({
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 getSettingsKey = useCallback(() => {
return `${topParentId} - ${getBasekey()}`;
}, [getBasekey, topParentId]);
2022-10-21 21:47:54 +03:00
const [isLoading, setisLoading] = useState(false);
2022-10-27 00:59:46 +03:00
const [viewQuerySettings, setViewQuerySettings] = useLocalStorage<ViewQuerySettings>(
`viewQuerySettings - ${getSettingsKey()}`,
defaultViewQuerySettings
2022-10-21 21:47:54 +03:00
);
2022-10-21 21:47:54 +03:00
const [ itemsResult, setItemsResult ] = useState<BaseItemDtoQueryResult>({});
2022-10-03 02:33:43 +03:00
2022-10-21 21:47:54 +03:00
const element = useRef<HTMLDivElement>(null);
2022-10-21 21:47:54 +03:00
const getContext = useCallback(() => {
const itemType = getItemTypes().join(',');
if (itemType === 'Movie' || itemType === 'BoxSet') {
return 'movies';
}
2022-10-21 21:47:54 +03:00
return null;
}, [getItemTypes]);
2022-10-21 21:47:54 +03:00
const getCardOptions = useCallback(() => {
let shape;
let preferThumb;
let preferDisc;
let preferLogo;
2022-10-27 00:59:46 +03:00
if (viewQuerySettings.imageType === 'banner') {
2022-10-21 21:47:54 +03:00
shape = 'banner';
2022-10-27 00:59:46 +03:00
} else if (viewQuerySettings.imageType === 'disc') {
2022-10-21 21:47:54 +03:00
shape = 'square';
preferDisc = true;
2022-10-27 00:59:46 +03:00
} else if (viewQuerySettings.imageType === 'logo') {
2022-10-21 21:47:54 +03:00
shape = 'backdrop';
preferLogo = true;
2022-10-27 00:59:46 +03:00
} else if (viewQuerySettings.imageType === 'thumb') {
2022-10-21 21:47:54 +03:00
shape = 'backdrop';
preferThumb = true;
} else {
shape = 'autoVertical';
}
2022-10-27 00:59:46 +03:00
const cardOptions: CardOptions = {
2022-10-21 21:47:54 +03:00
shape: shape,
2022-10-27 00:59:46 +03:00
showTitle: viewQuerySettings.showTitle,
showYear: viewQuerySettings.showYear,
cardLayout: viewQuerySettings.cardLayout,
2022-10-21 21:47:54 +03:00
centerText: true,
context: getContext(),
coverImage: true,
preferThumb: preferThumb,
preferDisc: preferDisc,
preferLogo: preferLogo,
overlayPlayButton: false,
overlayMoreButton: true,
2022-10-27 00:59:46 +03:00
overlayText: !viewQuerySettings.showTitle
2022-10-21 21:47:54 +03:00
};
2022-10-03 02:33:43 +03:00
2022-10-21 21:47:54 +03:00
cardOptions.items = itemsResult.Items || [];
2022-10-21 22:06:39 +03:00
2022-10-21 21:47:54 +03:00
return cardOptions;
2022-10-27 00:59:46 +03:00
}, [
getContext,
itemsResult.Items,
viewQuerySettings.cardLayout,
viewQuerySettings.imageType,
viewQuerySettings.showTitle,
viewQuerySettings.showYear
]);
2022-10-03 02:33:43 +03:00
2022-10-21 21:47:54 +03:00
const getItemsHtml = useCallback(() => {
let html = '';
2022-10-03 02:33:43 +03:00
2022-10-27 00:59:46 +03:00
if (viewQuerySettings.imageType === 'list') {
2022-10-21 21:47:54 +03:00
html = listview.getListViewHtml({
items: itemsResult.Items || [],
context: getContext()
});
} else {
html = cardBuilder.getCardsHtml(itemsResult.Items || [], getCardOptions());
2022-10-03 02:33:43 +03:00
}
2022-10-21 21:47:54 +03:00
if (!itemsResult.Items?.length) {
html += '<div class="noItemsMessage centerMessage">';
html += '<h1>' + globalize.translate('MessageNothingHere') + '</h1>';
html += '<p>' + globalize.translate(getNoItemsMessage()) + '</p>';
html += '</div>';
2022-10-03 02:33:43 +03:00
}
2022-10-21 21:47:54 +03:00
return html;
2022-10-27 00:59:46 +03:00
}, [getCardOptions, getContext, itemsResult.Items, getNoItemsMessage, viewQuerySettings.imageType]);
2022-10-03 02:33:43 +03:00
2022-10-21 21:47:54 +03:00
const getQuery = useCallback(() => {
let fields = 'BasicSyncInfo,MediaSourceCount';
2022-10-03 02:33:43 +03:00
2022-10-27 00:59:46 +03:00
if (viewQuerySettings.imageType === 'primary') {
2022-10-21 21:47:54 +03:00
fields += ',PrimaryImageAspectRatio';
2022-10-03 02:33:43 +03:00
}
2022-10-27 00:59:46 +03:00
if (viewQuerySettings.showYear) {
2022-10-21 21:47:54 +03:00
fields += ',ProductionYear';
2022-10-03 02:33:43 +03:00
}
2022-10-21 21:47:54 +03:00
const queryFilters: string[] = [];
2022-10-03 02:33:43 +03:00
2022-10-27 00:59:46 +03:00
if (viewQuerySettings.IsPlayed) {
2022-10-21 21:47:54 +03:00
queryFilters.push('IsPlayed');
2022-10-03 02:33:43 +03:00
}
2022-10-27 00:59:46 +03:00
if (viewQuerySettings.IsUnplayed) {
2022-10-21 21:47:54 +03:00
queryFilters.push('IsUnplayed');
2022-10-03 02:33:43 +03:00
}
2022-10-27 00:59:46 +03:00
if (viewQuerySettings.IsFavorite) {
2022-10-21 21:47:54 +03:00
queryFilters.push('IsFavorite');
2022-10-03 02:33:43 +03:00
}
2022-10-27 00:59:46 +03:00
if (viewQuerySettings.IsResumable) {
2022-10-21 21:47:54 +03:00
queryFilters.push('IsResumable');
2022-10-03 02:33:43 +03:00
}
2022-10-21 21:47:54 +03:00
let queryIsHD;
2022-10-03 02:33:43 +03:00
2022-10-27 00:59:46 +03:00
if (viewQuerySettings.IsHD) {
2022-10-21 21:47:54 +03:00
queryIsHD = true;
2022-10-03 02:33:43 +03:00
}
2022-10-27 00:59:46 +03:00
if (viewQuerySettings.IsSD) {
2022-10-21 21:47:54 +03:00
queryIsHD = false;
2022-10-03 02:33:43 +03:00
}
2022-10-27 00:59:46 +03:00
return {
SortBy: viewQuerySettings.SortBy,
SortOrder: viewQuerySettings.SortOrder,
2022-10-21 21:47:54 +03:00
IncludeItemTypes: getItemTypes().join(','),
Recursive: true,
Fields: fields,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb,Disc,Logo',
Limit: userSettings.libraryPageSize(undefined) || undefined,
2022-10-21 21:47:54 +03:00
IsFavorite: getBasekey() === 'favorites' ? true : null,
2022-10-27 00:59:46 +03:00
VideoTypes: viewQuerySettings.VideoTypes,
GenreIds: viewQuerySettings.GenreIds,
Is4K: viewQuerySettings.Is4K ? true : null,
2022-10-21 21:47:54 +03:00
IsHD: queryIsHD,
2022-10-27 00:59:46 +03:00
Is3D: viewQuerySettings.Is3D ? true : null,
HasSubtitles: viewQuerySettings.HasSubtitles ? true : null,
HasTrailer: viewQuerySettings.HasTrailer ? true : null,
HasSpecialFeature: viewQuerySettings.HasSpecialFeature ? true : null,
HasThemeSong: viewQuerySettings.HasThemeSong ? true : null,
HasThemeVideo: viewQuerySettings.HasThemeVideo ? true : null,
2022-10-21 21:47:54 +03:00
Filters: queryFilters.length ? queryFilters.join(',') : null,
2022-10-27 00:59:46 +03:00
StartIndex: viewQuerySettings.StartIndex,
NameLessThan: viewQuerySettings.NameLessThan,
NameStartsWith: viewQuerySettings.NameStartsWith,
2022-10-21 21:47:54 +03:00
ParentId: topParentId
2022-10-03 02:33:43 +03:00
};
2022-10-27 00:59:46 +03:00
}, [
viewQuerySettings.imageType,
viewQuerySettings.showYear,
viewQuerySettings.IsPlayed,
viewQuerySettings.IsUnplayed,
viewQuerySettings.IsFavorite,
viewQuerySettings.IsResumable,
viewQuerySettings.IsHD,
viewQuerySettings.IsSD,
viewQuerySettings.SortBy,
viewQuerySettings.SortOrder,
viewQuerySettings.VideoTypes,
viewQuerySettings.GenreIds,
viewQuerySettings.Is4K,
viewQuerySettings.Is3D,
viewQuerySettings.HasSubtitles,
viewQuerySettings.HasTrailer,
viewQuerySettings.HasSpecialFeature,
viewQuerySettings.HasThemeSong,
viewQuerySettings.HasThemeVideo,
viewQuerySettings.StartIndex,
viewQuerySettings.NameLessThan,
viewQuerySettings.NameStartsWith,
getItemTypes,
getBasekey,
topParentId
]);
2022-08-21 03:09:22 +03:00
2022-10-21 21:47:54 +03:00
const fetchData = useCallback(() => {
loading.show();
2022-08-21 03:09:22 +03:00
2022-10-21 21:47:54 +03:00
const apiClient = ServerConnections.getApiClient(window.ApiClient.serverId());
return apiClient.getItems(
apiClient.getCurrentUserId(),
{
...getQuery()
}
);
}, [getQuery]);
2022-08-21 03:09:22 +03:00
const reloadItems = useCallback(() => {
const page = element.current;
if (!page) {
console.error('Unexpected null reference');
return;
}
2022-10-21 21:47:54 +03:00
setisLoading(false);
fetchData().then((result) => {
2022-08-21 03:09:22 +03:00
setItemsResult(result);
2022-10-21 21:47:54 +03:00
window.scrollTo(0, 0);
2022-08-21 03:09:22 +03:00
import('../../components/autoFocuser').then(({ default: autoFocuser }) => {
autoFocuser.autoFocus(page);
});
2022-10-21 21:47:54 +03:00
loading.hide();
setisLoading(true);
2022-08-21 03:09:22 +03:00
});
2022-10-21 21:47:54 +03:00
}, [fetchData]);
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}
2022-10-27 00:59:46 +03:00
viewQuerySettings={viewQuerySettings}
setViewQuerySettings={setViewQuerySettings}
/>
2022-08-21 03:09:22 +03:00
{isBtnShuffleEnabled && <Shuffle itemsResult={itemsResult} topParentId={topParentId} />}
2022-10-21 21:47:54 +03:00
<SelectView
getVisibleViewSettings={getVisibleViewSettings}
2022-10-27 00:59:46 +03:00
viewQuerySettings={viewQuerySettings}
setViewQuerySettings={setViewQuerySettings}
2022-10-21 21:47:54 +03:00
/>
<Sort
getSortMenuOptions={getSortMenuOptions}
2022-10-27 00:59:46 +03:00
viewQuerySettings={viewQuerySettings}
setViewQuerySettings={setViewQuerySettings}
/>
2022-08-21 03:09:22 +03:00
2022-10-03 02:33:43 +03:00
{isBtnFilterEnabled && <Filter
topParentId={topParentId}
getItemTypes={getItemTypes}
getVisibleFilters={getVisibleFilters}
getFilterMenuOptions={getFilterMenuOptions}
2022-10-27 00:59:46 +03:00
viewQuerySettings={viewQuerySettings}
setViewQuerySettings={setViewQuerySettings}
2022-10-03 02:33:43 +03:00
/>}
2022-08-21 03:09:22 +03:00
{isBtnNewCollectionEnabled && <NewCollection />}
</div>
{isAlphaPickerEnabled && <AlphaPickerContainer
2022-10-27 00:59:46 +03:00
viewQuerySettings={viewQuerySettings}
setViewQuerySettings={setViewQuerySettings}
/>}
2022-08-21 03:09:22 +03:00
2022-10-21 21:47:54 +03:00
{isLoading && <ItemsContainer
2022-10-27 00:59:46 +03:00
viewQuerySettings={viewQuerySettings}
2022-10-21 21:47:54 +03:00
getItemsHtml={getItemsHtml}
/>}
2022-08-21 03:09:22 +03:00
<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}
2022-10-27 00:59:46 +03:00
viewQuerySettings={viewQuerySettings}
setViewQuerySettings={setViewQuerySettings}
/>
2022-08-21 03:09:22 +03:00
</div>
</div>
);
};
export default ViewItemsContainer;