2022-10-05 02:44:28 +03:00
|
|
|
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';
|
2022-10-03 01:23:59 +03:00
|
|
|
import globalize from '../../scripts/globalize';
|
2022-10-05 02:44:28 +03:00
|
|
|
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>({});
|
2022-10-05 02:44:28 +03:00
|
|
|
const [ startIndex, setStartIndex ] = useState<number>(0);
|
|
|
|
const [ alphaPickerValue, setAlphaPickerValue ] = useState<AlphaPickerValueI>({});
|
2022-08-21 03:09:22 +03:00
|
|
|
|
|
|
|
const element = useRef<HTMLDivElement>(null);
|
|
|
|
|
2022-10-05 02:44:28 +03:00
|
|
|
const queryAlphaPickerValue = useMemo(() => ({
|
|
|
|
...alphaPickerValue
|
|
|
|
}), [alphaPickerValue]);
|
|
|
|
|
2022-08-21 03:09:22 +03:00
|
|
|
const getSettingsKey = useCallback(() => {
|
|
|
|
return `${topParentId} - ${getBasekey()}`;
|
|
|
|
}, [getBasekey, topParentId]);
|
|
|
|
|
2022-10-05 02:44:28 +03:00
|
|
|
const getVisibleViewSettings = useCallback(() => {
|
|
|
|
return [
|
|
|
|
'showTitle',
|
|
|
|
'showYear',
|
|
|
|
'imageType',
|
|
|
|
'cardLayout'
|
|
|
|
];
|
|
|
|
}, []);
|
|
|
|
|
2022-08-21 03:09:22 +03:00
|
|
|
const getViewSettings = useCallback(() => {
|
2022-10-05 02:44:28 +03:00
|
|
|
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]);
|
|
|
|
|
2022-10-03 01:23:59 +03:00
|
|
|
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'
|
|
|
|
];
|
|
|
|
}, []);
|
|
|
|
|
2022-10-03 01:23:59 +03:00
|
|
|
const getQuery = useCallback(() => {
|
2022-10-05 02:44:28 +03:00
|
|
|
let fields = 'BasicSyncInfo,MediaSourceCount';
|
|
|
|
const viewsettings = getViewSettings();
|
|
|
|
if (viewsettings.imageType === 'primary') {
|
|
|
|
fields += ',PrimaryImageAspectRatio';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (viewsettings.showYear) {
|
|
|
|
fields += ',ProductionYear';
|
|
|
|
}
|
|
|
|
|
2022-10-03 01:23:59 +03:00
|
|
|
const query: QueryI = {
|
|
|
|
SortBy: getSortValues().sortBy,
|
|
|
|
SortOrder: getSortValues().sortOrder,
|
2022-10-03 02:33:43 +03:00
|
|
|
IncludeItemTypes: getItemTypes().join(','),
|
2022-10-03 01:23:59 +03:00
|
|
|
Recursive: true,
|
2022-10-05 02:44:28 +03:00
|
|
|
Fields: fields,
|
2022-10-03 01:23:59 +03:00
|
|
|
ImageTypeLimit: 1,
|
2022-10-05 02:44:28 +03:00
|
|
|
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb,Disc,Logo',
|
2022-10-03 01:23:59 +03:00
|
|
|
Limit: userSettings.libraryPageSize(undefined),
|
2022-10-05 02:44:28 +03:00
|
|
|
StartIndex: startIndex,
|
2022-10-03 01:23:59 +03:00
|
|
|
ParentId: topParentId
|
|
|
|
};
|
|
|
|
|
|
|
|
if (getBasekey() === 'favorites') {
|
|
|
|
query.IsFavorite = true;
|
|
|
|
}
|
|
|
|
|
2022-10-05 02:44:28 +03:00
|
|
|
const queryInfo: QueryI = Object.assign(query, queryAlphaPickerValue || {});
|
|
|
|
|
|
|
|
return queryInfo;
|
|
|
|
}, [getViewSettings, getSortValues, getItemTypes, startIndex, topParentId, getBasekey, queryAlphaPickerValue]);
|
2022-10-03 01:23:59 +03:00
|
|
|
|
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]);
|
|
|
|
|
2022-10-03 01:23:59 +03:00
|
|
|
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();
|
2022-10-05 02:44:28 +03:00
|
|
|
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'>
|
2022-10-05 02:44:28 +03:00
|
|
|
<Pagination
|
|
|
|
itemsResult= {itemsResult}
|
|
|
|
startIndex={startIndex}
|
|
|
|
setStartIndex={setStartIndex}
|
|
|
|
/>
|
2022-08-21 03:09:22 +03:00
|
|
|
|
|
|
|
{isBtnShuffleEnabled && <Shuffle itemsResult={itemsResult} topParentId={topParentId} />}
|
2022-10-05 02:44:28 +03:00
|
|
|
|
|
|
|
{<SelectView
|
|
|
|
getSettingsKey={getSettingsKey}
|
|
|
|
getVisibleViewSettings={getVisibleViewSettings}
|
|
|
|
getViewSettings={getViewSettings}
|
|
|
|
reloadItems={reloadItems}
|
|
|
|
/>}
|
2022-10-03 01:23:59 +03:00
|
|
|
|
|
|
|
<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>
|
|
|
|
|
2022-10-05 02:44:28 +03:00
|
|
|
{isAlphaPickerEnabled && <AlphaPickerContainer
|
|
|
|
getQuery={getQuery}
|
|
|
|
setAlphaPickerValue={setAlphaPickerValue}
|
|
|
|
setStartIndex={setStartIndex}
|
|
|
|
/>}
|
2022-08-21 03:09:22 +03:00
|
|
|
|
|
|
|
<ItemsContainer
|
2022-10-05 02:44:28 +03:00
|
|
|
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'>
|
2022-10-05 02:44:28 +03:00
|
|
|
<Pagination
|
|
|
|
itemsResult= {itemsResult}
|
|
|
|
startIndex={startIndex}
|
|
|
|
setStartIndex={setStartIndex}
|
|
|
|
/>
|
2022-08-21 03:09:22 +03:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default ViewItemsContainer;
|