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

387 lines
12 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
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';
2022-10-21 21:47:54 +03:00
import { CardOptionsI, QueryI, ViewSettingsI } from './interface';
import ServerConnections from '../../components/ServerConnections';
import { useLocalStorage } from '../hook/useLocalStorage';
import listview from '../../components/listview/listview';
import cardBuilder from '../../components/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'
}];
};
const defaultViewSettingsValue: ViewSettingsI = {
showTitle: true,
showYear: true,
imageType: 'primary',
viewType: '',
cardLayout: true,
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-21 21:47:54 +03:00
const [viewSettings, setViewSettings] = useLocalStorage<ViewSettingsI>(
2022-10-21 22:06:39 +03:00
`viewSettings - ${getSettingsKey()}`,
2022-10-21 21:47:54 +03:00
defaultViewSettingsValue
);
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;
if (viewSettings.imageType === 'banner') {
shape = 'banner';
} else if (viewSettings.imageType === 'disc') {
shape = 'square';
preferDisc = true;
} else if (viewSettings.imageType === 'logo') {
shape = 'backdrop';
preferLogo = true;
} else if (viewSettings.imageType === 'thumb') {
shape = 'backdrop';
preferThumb = true;
} else {
shape = 'autoVertical';
}
2022-10-21 21:47:54 +03:00
const cardOptions: CardOptionsI = {
shape: shape,
showTitle: viewSettings.showTitle,
showYear: viewSettings.showYear,
cardLayout: viewSettings.cardLayout,
centerText: true,
context: getContext(),
coverImage: true,
preferThumb: preferThumb,
preferDisc: preferDisc,
preferLogo: preferLogo,
overlayPlayButton: false,
overlayMoreButton: true,
overlayText: !viewSettings.showTitle
};
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;
}, [getContext, itemsResult.Items, viewSettings.cardLayout, viewSettings.imageType, viewSettings.showTitle, viewSettings.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-21 21:47:54 +03:00
if (viewSettings.imageType === 'list') {
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;
}, [getCardOptions, getContext, itemsResult.Items, getNoItemsMessage, viewSettings.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-21 21:47:54 +03:00
if (viewSettings.imageType === 'primary') {
fields += ',PrimaryImageAspectRatio';
2022-10-03 02:33:43 +03:00
}
2022-10-21 21:47:54 +03:00
if (viewSettings.showYear) {
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-21 21:47:54 +03:00
if (viewSettings.IsPlayed) {
queryFilters.push('IsPlayed');
2022-10-03 02:33:43 +03:00
}
2022-10-21 21:47:54 +03:00
if (viewSettings.IsUnplayed) {
queryFilters.push('IsUnplayed');
2022-10-03 02:33:43 +03:00
}
2022-10-21 21:47:54 +03:00
if (viewSettings.IsFavorite) {
queryFilters.push('IsFavorite');
2022-10-03 02:33:43 +03:00
}
2022-10-21 21:47:54 +03:00
if (viewSettings.IsResumable) {
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-21 21:47:54 +03:00
if (viewSettings.IsHD) {
queryIsHD = true;
2022-10-03 02:33:43 +03:00
}
2022-10-21 21:47:54 +03:00
if (viewSettings.IsSD) {
queryIsHD = false;
2022-10-03 02:33:43 +03:00
}
2022-10-21 21:47:54 +03:00
const options: QueryI = {
SortBy: viewSettings.SortBy,
SortOrder: viewSettings.SortOrder,
IncludeItemTypes: getItemTypes().join(','),
Recursive: true,
Fields: fields,
ImageTypeLimit: 1,
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb,Disc,Logo',
Limit: userSettings.libraryPageSize(undefined),
IsFavorite: getBasekey() === 'favorites' ? true : null,
VideoTypes: viewSettings.VideoTypes,
GenreIds: viewSettings.GenreIds,
Is4K: viewSettings.Is4K ? true : null,
IsHD: queryIsHD,
Is3D: viewSettings.Is3D ? true : null,
HasSubtitles: viewSettings.HasSubtitles ? true : null,
HasTrailer: viewSettings.HasTrailer ? true : null,
HasSpecialFeature: viewSettings.HasSpecialFeature ? true : null,
HasThemeSong: viewSettings.HasThemeSong ? true : null,
HasThemeVideo: viewSettings.HasThemeVideo ? true : null,
Filters: queryFilters.length ? queryFilters.join(',') : null,
StartIndex: viewSettings.StartIndex,
NameLessThan: viewSettings.NameLessThan,
NameStartsWith: viewSettings.NameStartsWith,
ParentId: topParentId
2022-10-03 02:33:43 +03:00
};
2022-10-21 22:06:39 +03:00
2022-10-21 21:47:54 +03:00
return options;
}, [viewSettings.imageType, viewSettings.showYear, viewSettings.IsPlayed, viewSettings.IsUnplayed, viewSettings.IsFavorite, viewSettings.IsResumable, viewSettings.IsHD, viewSettings.IsSD, viewSettings.SortBy, viewSettings.SortOrder, viewSettings.VideoTypes, viewSettings.GenreIds, viewSettings.Is4K, viewSettings.Is3D, viewSettings.HasSubtitles, viewSettings.HasTrailer, viewSettings.HasSpecialFeature, viewSettings.HasThemeSong, viewSettings.HasThemeVideo, viewSettings.StartIndex, viewSettings.NameLessThan, viewSettings.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-21 21:47:54 +03:00
viewSettings={viewSettings}
setViewSettings={setViewSettings}
/>
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-21 21:47:54 +03:00
viewSettings={viewSettings}
setViewSettings={setViewSettings}
/>
<Sort
getSortMenuOptions={getSortMenuOptions}
2022-10-21 21:47:54 +03:00
viewSettings={viewSettings}
setViewSettings={setViewSettings}
/>
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-21 21:47:54 +03:00
viewSettings={viewSettings}
setViewSettings={setViewSettings}
2022-10-03 02:33:43 +03:00
/>}
2022-08-21 03:09:22 +03:00
{isBtnNewCollectionEnabled && <NewCollection />}
</div>
{isAlphaPickerEnabled && <AlphaPickerContainer
2022-10-21 21:47:54 +03:00
viewSettings={viewSettings}
setViewSettings={setViewSettings}
/>}
2022-08-21 03:09:22 +03:00
2022-10-21 21:47:54 +03:00
{isLoading && <ItemsContainer
viewSettings={viewSettings}
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-21 21:47:54 +03:00
viewSettings={viewSettings}
setViewSettings={setViewSettings}
/>
2022-08-21 03:09:22 +03:00
</div>
</div>
);
};
export default ViewItemsContainer;