mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Refactoring duplicates code
This commit is contained in:
parent
368a6064c2
commit
cf137497a0
20 changed files with 491 additions and 513 deletions
|
@ -145,9 +145,15 @@
|
||||||
windowSize = null;
|
windowSize = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} windowSize
|
||||||
|
* @property {number} innerHeight - window innerHeight.
|
||||||
|
* @property {number} innerWidth - window innerWidth.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns window size.
|
* Returns window size.
|
||||||
* @returns {Object} Window size.
|
* @returns {windowSize} Window size.
|
||||||
*/
|
*/
|
||||||
export function getWindowSize() {
|
export function getWindowSize() {
|
||||||
if (!windowSize) {
|
if (!windowSize) {
|
||||||
|
|
|
@ -467,11 +467,17 @@ export class UserSettings {
|
||||||
return this.get('soundeffects', false);
|
return this.get('soundeffects', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} Query
|
||||||
|
* @property {number} StartIndex - query StartIndex.
|
||||||
|
* @property {number} Limit - query Limit.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load query settings.
|
* Load query settings.
|
||||||
* @param {string} key - Query key.
|
* @param {string} key - Query key.
|
||||||
* @param {Object} query - Query base.
|
* @param {Object} query - Query base.
|
||||||
* @return {Object} Query.
|
* @return {Query} Query.
|
||||||
*/
|
*/
|
||||||
loadQuerySettings(key, query) {
|
loadQuerySettings(key, query) {
|
||||||
let values = this.get(key);
|
let values = this.get(key);
|
||||||
|
|
|
@ -1065,6 +1065,7 @@
|
||||||
"MessageItemsAdded": "Items added.",
|
"MessageItemsAdded": "Items added.",
|
||||||
"MessageItemSaved": "Item saved.",
|
"MessageItemSaved": "Item saved.",
|
||||||
"MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item or the global default value.",
|
"MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item or the global default value.",
|
||||||
|
"MessageNoItemsAvailable": "No Items are currently available.",
|
||||||
"MessageNoFavoritesAvailable": "No favorites are currently available.",
|
"MessageNoFavoritesAvailable": "No favorites are currently available.",
|
||||||
"MessageNoAvailablePlugins": "No available plugins.",
|
"MessageNoAvailablePlugins": "No available plugins.",
|
||||||
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, and Albums. Click the '+' button to start creating collections.",
|
"MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, and Albums. Click the '+' button to start creating collections.",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
|
import React, { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import AlphaPicker from '../../components/alphaPicker/alphaPicker';
|
import AlphaPicker from '../../components/alphaPicker/alphaPicker';
|
||||||
import { IQuery } from './type';
|
import { IQuery } from './type';
|
||||||
|
|
||||||
|
@ -13,11 +13,7 @@ const AlphaPickerContainer: FunctionComponent<AlphaPickerProps> = ({ query, relo
|
||||||
|
|
||||||
alphaPicker?.updateControls(query);
|
alphaPicker?.updateControls(query);
|
||||||
|
|
||||||
useEffect(() => {
|
const onAlphaPickerChange = useCallback((e) => {
|
||||||
const alphaPickerElement = element.current?.querySelector('.alphaPicker');
|
|
||||||
|
|
||||||
if (alphaPickerElement) {
|
|
||||||
alphaPickerElement.addEventListener('alphavaluechanged', (e) => {
|
|
||||||
const newValue = (e as CustomEvent).detail.value;
|
const newValue = (e as CustomEvent).detail.value;
|
||||||
if (newValue === '#') {
|
if (newValue === '#') {
|
||||||
query.NameLessThan = 'A';
|
query.NameLessThan = 'A';
|
||||||
|
@ -28,19 +24,24 @@ const AlphaPickerContainer: FunctionComponent<AlphaPickerProps> = ({ query, relo
|
||||||
}
|
}
|
||||||
query.StartIndex = 0;
|
query.StartIndex = 0;
|
||||||
reloadItems();
|
reloadItems();
|
||||||
});
|
}, [query, reloadItems]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const alphaPickerElement = element.current?.querySelector('.alphaPicker');
|
||||||
|
|
||||||
setAlphaPicker(new AlphaPicker({
|
setAlphaPicker(new AlphaPicker({
|
||||||
element: alphaPickerElement,
|
element: alphaPickerElement,
|
||||||
valueChangeEvent: 'click'
|
valueChangeEvent: 'click'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
alphaPickerElement.classList.add('alphaPicker-fixed-right');
|
if (alphaPickerElement) {
|
||||||
|
alphaPickerElement.addEventListener('alphavaluechanged', onAlphaPickerChange);
|
||||||
}
|
}
|
||||||
}, [query, reloadItems, setAlphaPicker]);
|
}, [onAlphaPickerChange]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<div ref={element}>
|
||||||
<div className='alphaPicker alphaPicker-fixed alphaPicker-vertical alphabetPicker-right' />
|
<div className='alphaPicker alphaPicker-fixed alphaPicker-fixed-right alphaPicker-vertical alphabetPicker-right' />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,17 +5,18 @@ import { IQuery } from './type';
|
||||||
|
|
||||||
type FilterProps = {
|
type FilterProps = {
|
||||||
query: IQuery;
|
query: IQuery;
|
||||||
|
getFilterMode: () => string | null;
|
||||||
reloadItems: () => void;
|
reloadItems: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Filter: FunctionComponent<FilterProps> = ({ query, reloadItems }: FilterProps) => {
|
const Filter: FunctionComponent<FilterProps> = ({ query, getFilterMode, reloadItems }: FilterProps) => {
|
||||||
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/filterdialog/filterdialog').then(({default: filterDialogFactory}) => {
|
||||||
const filterDialog = new filterDialogFactory({
|
const filterDialog = new filterDialogFactory({
|
||||||
query: query,
|
query: query,
|
||||||
mode: 'movies',
|
mode: getFilterMode(),
|
||||||
serverId: window.ApiClient.serverId()
|
serverId: window.ApiClient.serverId()
|
||||||
});
|
});
|
||||||
Events.on(filterDialog, 'filterchange', () => {
|
Events.on(filterDialog, 'filterchange', () => {
|
||||||
|
@ -24,15 +25,13 @@ const Filter: FunctionComponent<FilterProps> = ({ query, reloadItems }: FilterPr
|
||||||
});
|
});
|
||||||
filterDialog.show();
|
filterDialog.show();
|
||||||
});
|
});
|
||||||
}, [query, reloadItems]);
|
}, [getFilterMode, query, reloadItems]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const btnFilter = element.current?.querySelector('.btnFilter');
|
const btnFilter = element.current?.querySelector('.btnFilter');
|
||||||
|
|
||||||
if (btnFilter) {
|
if (btnFilter) {
|
||||||
btnFilter.addEventListener('click', () => {
|
btnFilter.addEventListener('click', showFilterMenu);
|
||||||
showFilterMenu();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [showFilterMenu]);
|
}, [showFilterMenu]);
|
||||||
|
|
||||||
|
|
|
@ -126,13 +126,8 @@ const GenresItemsContainer: FunctionComponent<GenresItemsContainerProps> = ({ to
|
||||||
html += '</a>';
|
html += '</a>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
if (enableScrollX()) {
|
if (enableScrollX()) {
|
||||||
let scrollXClass = 'scrollX hiddenScrollX';
|
html += '<div is="emby-scroller" class="padded-top-focusscale padded-bottom-focusscale" data-centerfocus="true">';
|
||||||
|
html += '<div is="emby-itemscontainer" class="itemsContainer scrollSlider focuscontainer-x lazy" data-id="' + item.Id + '">';
|
||||||
if (layoutManager.tv) {
|
|
||||||
scrollXClass += 'smoothScrollX padded-top-focusscale padded-bottom-focusscale';
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<div is="emby-itemscontainer" class="itemsContainer ' + scrollXClass + ' lazy padded-left padded-right" data-id="' + item.Id + '">';
|
|
||||||
} else {
|
} else {
|
||||||
html += '<div is="emby-itemscontainer" class="itemsContainer vertical-wrap lazy padded-left padded-right" data-id="' + item.Id + '">';
|
html += '<div is="emby-itemscontainer" class="itemsContainer vertical-wrap lazy padded-left padded-right" data-id="' + item.Id + '">';
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,12 @@ import { IQuery } from './type';
|
||||||
type ItemsContainerProps = {
|
type ItemsContainerProps = {
|
||||||
getCurrentViewStyle: () => string;
|
getCurrentViewStyle: () => string;
|
||||||
query: IQuery;
|
query: IQuery;
|
||||||
|
getContext: () => string | null;
|
||||||
items?: BaseItemDto[] | null;
|
items?: BaseItemDto[] | null;
|
||||||
noItemsMessage?: string;
|
noItemsMessage?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ItemsContainer: FunctionComponent<ItemsContainerProps> = ({ getCurrentViewStyle, query, items = [], noItemsMessage }: ItemsContainerProps) => {
|
const ItemsContainer: FunctionComponent<ItemsContainerProps> = ({ getCurrentViewStyle, query, getContext, items = [], noItemsMessage }: ItemsContainerProps) => {
|
||||||
const element = useRef<HTMLDivElement>(null);
|
const element = useRef<HTMLDivElement>(null);
|
||||||
const viewStyle = getCurrentViewStyle();
|
const viewStyle = getCurrentViewStyle();
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ const ItemsContainer: FunctionComponent<ItemsContainerProps> = ({ getCurrentView
|
||||||
items: items,
|
items: items,
|
||||||
shape: 'backdrop',
|
shape: 'backdrop',
|
||||||
preferThumb: true,
|
preferThumb: true,
|
||||||
context: 'movies',
|
context: getContext(),
|
||||||
lazy: true,
|
lazy: true,
|
||||||
overlayPlayButton: true,
|
overlayPlayButton: true,
|
||||||
showTitle: true,
|
showTitle: true,
|
||||||
|
@ -40,7 +41,7 @@ const ItemsContainer: FunctionComponent<ItemsContainerProps> = ({ getCurrentView
|
||||||
items: items,
|
items: items,
|
||||||
shape: 'backdrop',
|
shape: 'backdrop',
|
||||||
preferThumb: true,
|
preferThumb: true,
|
||||||
context: 'movies',
|
context: getContext(),
|
||||||
lazy: true,
|
lazy: true,
|
||||||
cardLayout: true,
|
cardLayout: true,
|
||||||
showTitle: true,
|
showTitle: true,
|
||||||
|
@ -52,20 +53,20 @@ const ItemsContainer: FunctionComponent<ItemsContainerProps> = ({ getCurrentView
|
||||||
items: items,
|
items: items,
|
||||||
shape: 'banner',
|
shape: 'banner',
|
||||||
preferBanner: true,
|
preferBanner: true,
|
||||||
context: 'movies',
|
context: getContext(),
|
||||||
lazy: true
|
lazy: true
|
||||||
});
|
});
|
||||||
} else if (viewStyle == 'List') {
|
} else if (viewStyle == 'List') {
|
||||||
html = listview.getListViewHtml({
|
html = listview.getListViewHtml({
|
||||||
items: items,
|
items: items,
|
||||||
context: 'movies',
|
context: getContext(),
|
||||||
sortBy: query.SortBy
|
sortBy: query.SortBy
|
||||||
});
|
});
|
||||||
} else if (viewStyle == 'PosterCard') {
|
} else if (viewStyle == 'PosterCard') {
|
||||||
html = cardBuilder.getCardsHtml(items, {
|
html = cardBuilder.getCardsHtml(items, {
|
||||||
items: items,
|
items: items,
|
||||||
shape: 'portrait',
|
shape: 'portrait',
|
||||||
context: 'movies',
|
context: getContext(),
|
||||||
showTitle: true,
|
showTitle: true,
|
||||||
showYear: true,
|
showYear: true,
|
||||||
centerText: true,
|
centerText: true,
|
||||||
|
@ -76,7 +77,7 @@ const ItemsContainer: FunctionComponent<ItemsContainerProps> = ({ getCurrentView
|
||||||
html = cardBuilder.getCardsHtml(items, {
|
html = cardBuilder.getCardsHtml(items, {
|
||||||
items: items,
|
items: items,
|
||||||
shape: 'portrait',
|
shape: 'portrait',
|
||||||
context: 'movies',
|
context: getContext(),
|
||||||
overlayPlayButton: true,
|
overlayPlayButton: true,
|
||||||
showTitle: true,
|
showTitle: true,
|
||||||
showYear: true,
|
showYear: true,
|
||||||
|
@ -96,14 +97,14 @@ const ItemsContainer: FunctionComponent<ItemsContainerProps> = ({ getCurrentView
|
||||||
const itemsContainer = element.current?.querySelector('.itemsContainer') as HTMLDivElement;
|
const itemsContainer = element.current?.querySelector('.itemsContainer') as HTMLDivElement;
|
||||||
itemsContainer.innerHTML = html;
|
itemsContainer.innerHTML = html;
|
||||||
imageLoader.lazyChildren(itemsContainer);
|
imageLoader.lazyChildren(itemsContainer);
|
||||||
}, [query.SortBy, items, noItemsMessage, viewStyle]);
|
}, [query.SortBy, items, noItemsMessage, viewStyle, getContext]);
|
||||||
|
|
||||||
const cssClass = viewStyle == 'List' ? 'vertical-list' : 'vertical-wrap';
|
const cssClass = viewStyle == 'List' ? 'vertical-list' : 'vertical-wrap';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<div ref={element}>
|
||||||
<ItemsContainerElement
|
<ItemsContainerElement
|
||||||
className={`itemsContainer ${cssClass} centered padded-left padded-right`}
|
className={`itemsContainer ${cssClass} centered padded-left padded-right padded-right-withalphapicker`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
import React, { FunctionComponent, useEffect, useRef } from 'react';
|
import React, { FunctionComponent, useCallback, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
import IconButtonElement from '../../elements/IconButtonElement';
|
import IconButtonElement from '../../elements/IconButtonElement';
|
||||||
|
|
||||||
const NewCollection: FunctionComponent = () => {
|
const NewCollection: FunctionComponent = () => {
|
||||||
const element = useRef<HTMLDivElement>(null);
|
const element = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
const showCollectionEditor = useCallback(() => {
|
||||||
const btnNewCollection = element.current?.querySelector('.btnNewCollection') as HTMLButtonElement;
|
|
||||||
if (btnNewCollection) {
|
|
||||||
btnNewCollection.addEventListener('click', () => {
|
|
||||||
import('../../components/collectionEditor/collectionEditor').then(({default: CollectionEditor}) => {
|
import('../../components/collectionEditor/collectionEditor').then(({default: CollectionEditor}) => {
|
||||||
const serverId = window.ApiClient.serverId();
|
const serverId = window.ApiClient.serverId();
|
||||||
const collectionEditor = new CollectionEditor();
|
const collectionEditor = new CollectionEditor();
|
||||||
|
@ -17,10 +14,15 @@ const NewCollection: FunctionComponent = () => {
|
||||||
serverId: serverId
|
serverId: serverId
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const btnNewCollection = element.current?.querySelector('.btnNewCollection');
|
||||||
|
if (btnNewCollection) {
|
||||||
|
btnNewCollection.addEventListener('click', showCollectionEditor);
|
||||||
|
}
|
||||||
|
}, [showCollectionEditor]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<div ref={element}>
|
||||||
<IconButtonElement
|
<IconButtonElement
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { BaseItemDtoQueryResult } from '@thornbill/jellyfin-sdk/dist/generated-client';
|
import { BaseItemDtoQueryResult } from '@thornbill/jellyfin-sdk/dist/generated-client';
|
||||||
import React, { FunctionComponent, useEffect, useRef } from 'react';
|
import React, { FunctionComponent, useCallback, useEffect, useRef } from 'react';
|
||||||
import libraryBrowser from '../../scripts/libraryBrowser';
|
import IconButtonElement from '../../elements/IconButtonElement';
|
||||||
|
import globalize from '../../scripts/globalize';
|
||||||
import * as userSettings from '../../scripts/settings/userSettings';
|
|
||||||
import { IQuery } from './type';
|
import { IQuery } from './type';
|
||||||
|
|
||||||
type PaginationProps = {
|
type PaginationProps = {
|
||||||
|
@ -12,49 +11,72 @@ type PaginationProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Pagination: FunctionComponent<PaginationProps> = ({ query, itemsResult = {}, reloadItems }: PaginationProps) => {
|
const Pagination: FunctionComponent<PaginationProps> = ({ query, itemsResult = {}, reloadItems }: PaginationProps) => {
|
||||||
|
const startIndex = query.StartIndex;
|
||||||
|
const limit = query.Limit;
|
||||||
|
const totalRecordCount = itemsResult.TotalRecordCount || 0;
|
||||||
|
const recordsEnd = Math.min(startIndex + limit, totalRecordCount);
|
||||||
|
const showControls = limit < totalRecordCount;
|
||||||
const element = useRef<HTMLDivElement>(null);
|
const element = useRef<HTMLDivElement>(null);
|
||||||
useEffect(() => {
|
|
||||||
function onNextPageClick() {
|
const onNextPageClick = useCallback(() => {
|
||||||
if (userSettings.libraryPageSize(undefined) > 0) {
|
if (query.Limit > 0) {
|
||||||
query.StartIndex += query.Limit;
|
query.StartIndex += query.Limit;
|
||||||
}
|
}
|
||||||
reloadItems();
|
reloadItems();
|
||||||
}
|
}, [query, reloadItems]);
|
||||||
|
|
||||||
function onPreviousPageClick() {
|
const onPreviousPageClick = useCallback(() => {
|
||||||
if (userSettings.libraryPageSize(undefined) > 0) {
|
if (query.Limit > 0) {
|
||||||
query.StartIndex = Math.max(0, query.StartIndex - query.Limit);
|
query.StartIndex = Math.max(0, query.StartIndex - query.Limit);
|
||||||
}
|
}
|
||||||
reloadItems();
|
reloadItems();
|
||||||
}
|
}, [query, reloadItems]);
|
||||||
const pagingHtml = libraryBrowser.getQueryPagingHtml({
|
|
||||||
startIndex: query.StartIndex,
|
|
||||||
limit: query.Limit,
|
|
||||||
totalRecordCount: itemsResult.TotalRecordCount,
|
|
||||||
showLimit: false,
|
|
||||||
updatePageSizeSetting: false,
|
|
||||||
addLayoutButton: false,
|
|
||||||
sortButton: false,
|
|
||||||
filterButton: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const paging = element.current?.querySelector('.paging') as HTMLDivElement;
|
|
||||||
paging.innerHTML = pagingHtml;
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
const btnNextPage = element.current?.querySelector('.btnNextPage') as HTMLButtonElement;
|
const btnNextPage = element.current?.querySelector('.btnNextPage') as HTMLButtonElement;
|
||||||
if (btnNextPage) {
|
if (btnNextPage) {
|
||||||
|
if (startIndex + limit >= totalRecordCount) {
|
||||||
|
btnNextPage.disabled = true;
|
||||||
|
} else {
|
||||||
|
btnNextPage.disabled = false;
|
||||||
|
}
|
||||||
btnNextPage.addEventListener('click', onNextPageClick);
|
btnNextPage.addEventListener('click', onNextPageClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
const btnPreviousPage = element.current?.querySelector('.btnPreviousPage') as HTMLButtonElement;
|
const btnPreviousPage = element.current?.querySelector('.btnPreviousPage') as HTMLButtonElement;
|
||||||
if (btnPreviousPage) {
|
if (btnPreviousPage) {
|
||||||
|
if (startIndex) {
|
||||||
|
btnPreviousPage.disabled = false;
|
||||||
|
} else {
|
||||||
|
btnPreviousPage.disabled = true;
|
||||||
|
}
|
||||||
btnPreviousPage.addEventListener('click', onPreviousPageClick);
|
btnPreviousPage.addEventListener('click', onPreviousPageClick);
|
||||||
}
|
}
|
||||||
}, [itemsResult, query, reloadItems]);
|
}, [totalRecordCount, onNextPageClick, onPreviousPageClick, limit, startIndex]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<div ref={element}>
|
||||||
<div className='paging' />
|
<div className='paging'>
|
||||||
|
{showControls && (
|
||||||
|
<div className='listPaging' style={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{globalize.translate('ListPaging', (totalRecordCount ? startIndex + 1 : 0), recordsEnd, totalRecordCount)}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<IconButtonElement
|
||||||
|
is='paper-icon-button-light'
|
||||||
|
className='btnPreviousPage autoSize'
|
||||||
|
icon='material-icons arrow_back'
|
||||||
|
/>
|
||||||
|
<IconButtonElement
|
||||||
|
is='paper-icon-button-light'
|
||||||
|
className='btnNextPage autoSize'
|
||||||
|
icon='material-icons arrow_forward'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,11 +8,11 @@ import { IQuery } from './type';
|
||||||
type SelectViewProps = {
|
type SelectViewProps = {
|
||||||
getCurrentViewStyle: () => string;
|
getCurrentViewStyle: () => string;
|
||||||
query: IQuery;
|
query: IQuery;
|
||||||
savedViewKey: string;
|
getViewSettings: () => string;
|
||||||
reloadItems: () => void;
|
reloadItems: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SelectView: FunctionComponent<SelectViewProps> = ({ getCurrentViewStyle, savedViewKey, query, reloadItems }: SelectViewProps) => {
|
const SelectView: FunctionComponent<SelectViewProps> = ({ getCurrentViewStyle, getViewSettings, query, reloadItems }: SelectViewProps) => {
|
||||||
const element = useRef<HTMLDivElement>(null);
|
const element = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -22,11 +22,11 @@ const SelectView: FunctionComponent<SelectViewProps> = ({ getCurrentViewStyle, s
|
||||||
});
|
});
|
||||||
btnSelectView.addEventListener('layoutchange', (e) => {
|
btnSelectView.addEventListener('layoutchange', (e) => {
|
||||||
const viewStyle = (e as CustomEvent).detail.viewStyle;
|
const viewStyle = (e as CustomEvent).detail.viewStyle;
|
||||||
userSettings.set(savedViewKey, viewStyle, false);
|
userSettings.set(getViewSettings(), viewStyle, false);
|
||||||
query.StartIndex = 0;
|
query.StartIndex = 0;
|
||||||
reloadItems();
|
reloadItems();
|
||||||
});
|
});
|
||||||
}, [getCurrentViewStyle, query, reloadItems, savedViewKey]);
|
}, [getCurrentViewStyle, query, reloadItems, getViewSettings]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<div ref={element}>
|
||||||
|
|
|
@ -22,8 +22,7 @@ const Shuffle: FunctionComponent<ShuffleProps> = ({ itemsResult = {}, topParentI
|
||||||
}, [topParentId]);
|
}, [topParentId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const btnShuffle = element.current?.querySelector('.btnShuffle') as HTMLButtonElement;
|
const btnShuffle = element.current?.querySelector('.btnShuffle');
|
||||||
btnShuffle.classList.toggle('hide', typeof itemsResult.TotalRecordCount === 'number' && itemsResult.TotalRecordCount < 1);
|
|
||||||
if (btnShuffle) {
|
if (btnShuffle) {
|
||||||
btnShuffle.addEventListener('click', shuffle);
|
btnShuffle.addEventListener('click', shuffle);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +32,7 @@ const Shuffle: FunctionComponent<ShuffleProps> = ({ itemsResult = {}, topParentI
|
||||||
<div ref={element}>
|
<div ref={element}>
|
||||||
<IconButtonElement
|
<IconButtonElement
|
||||||
is='paper-icon-button-light'
|
is='paper-icon-button-light'
|
||||||
className='btnShuffle autoSize hide'
|
className='btnShuffle autoSize'
|
||||||
title='Shuffle'
|
title='Shuffle'
|
||||||
icon='material-icons shuffle'
|
icon='material-icons shuffle'
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -5,13 +5,16 @@ import * as userSettings from '../../scripts/settings/userSettings';
|
||||||
import { IQuery } from './type';
|
import { IQuery } from './type';
|
||||||
|
|
||||||
type SortProps = {
|
type SortProps = {
|
||||||
sortMenuOptions: () => { name: string; id: string}[];
|
getSortMenuOptions: () => {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
}[];
|
||||||
query: IQuery;
|
query: IQuery;
|
||||||
savedQueryKey: string;
|
getSettingsKey: () => string;
|
||||||
reloadItems: () => void;
|
reloadItems: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Sort: FunctionComponent<SortProps> = ({ sortMenuOptions, query, savedQueryKey, reloadItems }: SortProps) => {
|
const Sort: FunctionComponent<SortProps> = ({ getSortMenuOptions, query, getSettingsKey, reloadItems }: SortProps) => {
|
||||||
const element = useRef<HTMLDivElement>(null);
|
const element = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -20,10 +23,10 @@ const Sort: FunctionComponent<SortProps> = ({ sortMenuOptions, query, savedQuery
|
||||||
if (btnSort) {
|
if (btnSort) {
|
||||||
btnSort.addEventListener('click', (e) => {
|
btnSort.addEventListener('click', (e) => {
|
||||||
libraryBrowser.showSortMenu({
|
libraryBrowser.showSortMenu({
|
||||||
items: sortMenuOptions(),
|
items: getSortMenuOptions(),
|
||||||
callback: () => {
|
callback: () => {
|
||||||
query.StartIndex = 0;
|
query.StartIndex = 0;
|
||||||
userSettings.saveQuerySettings(savedQueryKey, query);
|
userSettings.saveQuerySettings(getSettingsKey(), query);
|
||||||
reloadItems();
|
reloadItems();
|
||||||
},
|
},
|
||||||
query: query,
|
query: query,
|
||||||
|
@ -31,7 +34,7 @@ const Sort: FunctionComponent<SortProps> = ({ sortMenuOptions, query, savedQuery
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [sortMenuOptions, query, reloadItems, savedQueryKey]);
|
}, [getSortMenuOptions, query, reloadItems, getSettingsKey]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<div ref={element}>
|
||||||
|
|
144
src/view/components/ViewItemsContainer.tsx
Normal file
144
src/view/components/ViewItemsContainer.tsx
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
import { BaseItemDtoQueryResult } from '@thornbill/jellyfin-sdk/dist/generated-client';
|
||||||
|
import React, { FunctionComponent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
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 { IQuery } from './type';
|
||||||
|
import NewCollection from './NewCollection';
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
topParentId: string | null;
|
||||||
|
isBtnShuffleEnabled?: boolean;
|
||||||
|
isBtnFilterEnabled?: boolean;
|
||||||
|
isBtnNewCollectionEnabled?: boolean;
|
||||||
|
isAlphaPickerEnabled?: boolean;
|
||||||
|
getBasekey: () => string;
|
||||||
|
getFilterMode: () => string;
|
||||||
|
getItemTypes: () => string;
|
||||||
|
getSortMenuOptions: () => {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
}[];
|
||||||
|
getNoItemsMessage: () => string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ViewItemsContainer: FunctionComponent<IProps> = ({
|
||||||
|
topParentId,
|
||||||
|
isBtnShuffleEnabled = false,
|
||||||
|
isBtnFilterEnabled = true,
|
||||||
|
isBtnNewCollectionEnabled = false,
|
||||||
|
isAlphaPickerEnabled = true,
|
||||||
|
getBasekey,
|
||||||
|
getFilterMode,
|
||||||
|
getItemTypes,
|
||||||
|
getSortMenuOptions,
|
||||||
|
getNoItemsMessage
|
||||||
|
}: IProps) => {
|
||||||
|
const [ itemsResult, setItemsResult ] = useState<BaseItemDtoQueryResult>({});
|
||||||
|
|
||||||
|
const element = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const getSettingsKey = useCallback(() => {
|
||||||
|
return `${topParentId} - ${getBasekey()}`;
|
||||||
|
}, [getBasekey, topParentId]);
|
||||||
|
|
||||||
|
const getViewSettings = useCallback(() => {
|
||||||
|
return `${getSettingsKey()} -view`;
|
||||||
|
}, [getSettingsKey]);
|
||||||
|
|
||||||
|
let query = useMemo<IQuery>(() => ({
|
||||||
|
SortBy: 'SortName,ProductionYear',
|
||||||
|
SortOrder: 'Ascending',
|
||||||
|
IncludeItemTypes: getItemTypes(),
|
||||||
|
Recursive: true,
|
||||||
|
Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo',
|
||||||
|
ImageTypeLimit: 1,
|
||||||
|
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
|
||||||
|
Limit: userSettings.libraryPageSize(undefined),
|
||||||
|
StartIndex: 0,
|
||||||
|
ParentId: topParentId
|
||||||
|
}), [getItemTypes, topParentId]);
|
||||||
|
|
||||||
|
if (getBasekey() === 'favorites') {
|
||||||
|
query.IsFavorite = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
query = userSettings.loadQuerySettings(getSettingsKey(), query);
|
||||||
|
|
||||||
|
const getCurrentViewStyle = useCallback(() => {
|
||||||
|
return userSettings.get(getViewSettings(), false) || 'Poster';
|
||||||
|
}, [getViewSettings]);
|
||||||
|
|
||||||
|
const getContext = useCallback(() => {
|
||||||
|
const itemType = getItemTypes();
|
||||||
|
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();
|
||||||
|
window.ApiClient.getItems(window.ApiClient.getCurrentUserId(), query).then((result) => {
|
||||||
|
setItemsResult(result);
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
|
||||||
|
loading.hide();
|
||||||
|
|
||||||
|
import('../../components/autoFocuser').then(({ default: autoFocuser }) => {
|
||||||
|
autoFocuser.autoFocus(page);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, [query]);
|
||||||
|
|
||||||
|
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} query={query} reloadItems={reloadItems} />
|
||||||
|
|
||||||
|
{isBtnShuffleEnabled && <Shuffle itemsResult={itemsResult} topParentId={topParentId} />}
|
||||||
|
<SelectView getCurrentViewStyle={getCurrentViewStyle} getViewSettings={getViewSettings} query={query} reloadItems={reloadItems} />
|
||||||
|
<Sort getSortMenuOptions={getSortMenuOptions} query={query} getSettingsKey={getSettingsKey} reloadItems={reloadItems} />
|
||||||
|
|
||||||
|
{isBtnFilterEnabled && <Filter query={query} getFilterMode={getFilterMode} reloadItems={reloadItems} />}
|
||||||
|
|
||||||
|
{isBtnNewCollectionEnabled && <NewCollection />}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{isAlphaPickerEnabled && <AlphaPickerContainer query={query} reloadItems={reloadItems} />}
|
||||||
|
|
||||||
|
<ItemsContainer
|
||||||
|
getCurrentViewStyle={getCurrentViewStyle}
|
||||||
|
query={query}
|
||||||
|
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} query={query} reloadItems={reloadItems} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ViewItemsContainer;
|
|
@ -5,6 +5,7 @@ export type IQuery = {
|
||||||
Recursive?: boolean;
|
Recursive?: boolean;
|
||||||
Fields?: string;
|
Fields?: string;
|
||||||
ImageTypeLimit?: number;
|
ImageTypeLimit?: number;
|
||||||
|
EnableTotalRecordCount?: boolean;
|
||||||
EnableImageTypes?: string;
|
EnableImageTypes?: string;
|
||||||
StartIndex: number;
|
StartIndex: number;
|
||||||
ParentId?: string | null;
|
ParentId?: string | null;
|
||||||
|
|
|
@ -1,19 +1,30 @@
|
||||||
import '../../elements/emby-itemscontainer/emby-itemscontainer';
|
import React, { FunctionComponent, useCallback } from 'react';
|
||||||
|
|
||||||
import { BaseItemDtoQueryResult } from '@thornbill/jellyfin-sdk/dist/generated-client';
|
|
||||||
import React, { FunctionComponent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
||||||
|
|
||||||
import loading from '../../components/loading/loading';
|
|
||||||
import globalize from '../../scripts/globalize';
|
import globalize from '../../scripts/globalize';
|
||||||
import * as userSettings from '../../scripts/settings/userSettings';
|
import ViewItemsContainer from '../components/ViewItemsContainer';
|
||||||
import ItemsContainer from '../components/ItemsContainer';
|
|
||||||
import NewCollection from '../components/NewCollection';
|
|
||||||
import Pagination from '../components/Pagination';
|
|
||||||
import SelectView from '../components/SelectView';
|
|
||||||
import Sort from '../components/Sort';
|
|
||||||
import { IQuery } from '../components/type';
|
|
||||||
|
|
||||||
const SortMenuOptions = () => {
|
type IProps = {
|
||||||
|
topParentId: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CollectionsView: FunctionComponent<IProps> = ({ topParentId }: IProps) => {
|
||||||
|
const getBasekey = useCallback(() => {
|
||||||
|
return 'collections';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getFilterMode = useCallback(() => {
|
||||||
|
return 'movies';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getItemTypes = useCallback(() => {
|
||||||
|
return 'BoxSet';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getNoItemsMessage = useCallback(() => {
|
||||||
|
return 'MessageNoCollectionsAvailable';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getSortMenuOptions = useCallback(() => {
|
||||||
return [{
|
return [{
|
||||||
name: globalize.translate('Name'),
|
name: globalize.translate('Name'),
|
||||||
id: 'SortName'
|
id: 'SortName'
|
||||||
|
@ -21,79 +32,20 @@ const SortMenuOptions = () => {
|
||||||
name: globalize.translate('OptionDateAdded'),
|
name: globalize.translate('OptionDateAdded'),
|
||||||
id: 'DateCreated,SortName'
|
id: 'DateCreated,SortName'
|
||||||
}];
|
}];
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
type IProps = {
|
|
||||||
topParentId: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CollectionsView: FunctionComponent<IProps> = ({ topParentId }: IProps) => {
|
|
||||||
const savedQueryKey = topParentId + '-moviecollections';
|
|
||||||
const savedViewKey = savedQueryKey + '-view';
|
|
||||||
|
|
||||||
const [ itemsResult, setItemsResult ] = useState<BaseItemDtoQueryResult>({});
|
|
||||||
const element = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const query = useMemo<IQuery>(() => ({
|
|
||||||
SortBy: 'SortName',
|
|
||||||
SortOrder: 'Ascending',
|
|
||||||
IncludeItemTypes: 'BoxSet',
|
|
||||||
Recursive: true,
|
|
||||||
Fields: 'PrimaryImageAspectRatio,SortName',
|
|
||||||
ImageTypeLimit: 1,
|
|
||||||
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
|
|
||||||
Limit: userSettings.libraryPageSize(undefined),
|
|
||||||
StartIndex: 0,
|
|
||||||
ParentId: topParentId }), [topParentId]);
|
|
||||||
|
|
||||||
userSettings.loadQuerySettings(savedQueryKey, query);
|
|
||||||
|
|
||||||
const getCurrentViewStyle = useCallback(() => {
|
|
||||||
return userSettings.get(savedViewKey, false) || 'Poster';
|
|
||||||
}, [savedViewKey]);
|
|
||||||
|
|
||||||
const reloadItems = useCallback(() => {
|
|
||||||
const page = element.current;
|
|
||||||
|
|
||||||
if (!page) {
|
|
||||||
console.error('Unexpected null reference');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loading.show();
|
|
||||||
window.ApiClient.getItems(window.ApiClient.getCurrentUserId(), query).then((result) => {
|
|
||||||
setItemsResult(result);
|
|
||||||
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
|
|
||||||
loading.hide();
|
|
||||||
|
|
||||||
import('../../components/autoFocuser').then(({ default: autoFocuser }) => {
|
|
||||||
autoFocuser.autoFocus(page);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, [query]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
reloadItems();
|
|
||||||
}, [reloadItems]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<ViewItemsContainer
|
||||||
<div className='flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom focuscontainer-x'>
|
topParentId={topParentId}
|
||||||
<Pagination itemsResult= {itemsResult} query={query} reloadItems={reloadItems} />
|
isBtnFilterEnabled={false}
|
||||||
|
isBtnNewCollectionEnabled={true}
|
||||||
<SelectView getCurrentViewStyle={getCurrentViewStyle} savedViewKey={savedViewKey} query={query} reloadItems={reloadItems} />
|
isAlphaPickerEnabled={false}
|
||||||
<Sort sortMenuOptions={SortMenuOptions} query={query} savedQueryKey={savedQueryKey} reloadItems={reloadItems} />
|
getBasekey={getBasekey}
|
||||||
<NewCollection />
|
getFilterMode={getFilterMode}
|
||||||
|
getItemTypes={getItemTypes}
|
||||||
</div>
|
getSortMenuOptions={getSortMenuOptions}
|
||||||
|
getNoItemsMessage={getNoItemsMessage}
|
||||||
<ItemsContainer getCurrentViewStyle={getCurrentViewStyle} query={query} items={itemsResult?.Items} noItemsMessage= 'MessageNoCollectionsAvailable' />
|
/>
|
||||||
|
|
||||||
<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} query={query} reloadItems={reloadItems} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,30 @@
|
||||||
import { BaseItemDtoQueryResult } from '@thornbill/jellyfin-sdk/dist/generated-client';
|
import React, { FunctionComponent, useCallback } from 'react';
|
||||||
import React, { FunctionComponent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
||||||
|
|
||||||
import loading from '../../components/loading/loading';
|
|
||||||
import globalize from '../../scripts/globalize';
|
import globalize from '../../scripts/globalize';
|
||||||
import * as userSettings from '../../scripts/settings/userSettings';
|
import ViewItemsContainer from '../components/ViewItemsContainer';
|
||||||
import AlphaPickerContainer from '../components/AlphaPickerContainer';
|
|
||||||
import Filter from '../components/Filter';
|
|
||||||
import ItemsContainer from '../components/ItemsContainer';
|
|
||||||
import Pagination from '../components/Pagination';
|
|
||||||
import SelectView from '../components/SelectView';
|
|
||||||
import Sort from '../components/Sort';
|
|
||||||
import { IQuery } from '../components/type';
|
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
topParentId: string | null;
|
topParentId: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SortMenuOptions = () => {
|
const FavoritesView: FunctionComponent<IProps> = ({ topParentId }: IProps) => {
|
||||||
|
const getBasekey = useCallback(() => {
|
||||||
|
return 'favorites';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getFilterMode = useCallback(() => {
|
||||||
|
return 'movies';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getItemTypes = useCallback(() => {
|
||||||
|
return 'Movie';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getNoItemsMessage = useCallback(() => {
|
||||||
|
return 'MessageNoFavoritesAvailable';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getSortMenuOptions = useCallback(() => {
|
||||||
return [{
|
return [{
|
||||||
name: globalize.translate('Name'),
|
name: globalize.translate('Name'),
|
||||||
id: 'SortName,ProductionYear'
|
id: 'SortName,ProductionYear'
|
||||||
|
@ -48,77 +56,17 @@ const SortMenuOptions = () => {
|
||||||
name: globalize.translate('Runtime'),
|
name: globalize.translate('Runtime'),
|
||||||
id: 'Runtime,SortName,ProductionYear'
|
id: 'Runtime,SortName,ProductionYear'
|
||||||
}];
|
}];
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
const FavoritesView: FunctionComponent<IProps> = ({ topParentId }: IProps) => {
|
|
||||||
const savedQueryKey = topParentId + '-favorites';
|
|
||||||
const savedViewKey = savedQueryKey + '-view';
|
|
||||||
|
|
||||||
const [ itemsResult, setItemsResult ] = useState<BaseItemDtoQueryResult>({});
|
|
||||||
const element = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const query = useMemo<IQuery>(() => ({
|
|
||||||
SortBy: 'SortName,ProductionYear',
|
|
||||||
SortOrder: 'Ascending',
|
|
||||||
IncludeItemTypes: 'Movie',
|
|
||||||
Recursive: true,
|
|
||||||
Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo',
|
|
||||||
ImageTypeLimit: 1,
|
|
||||||
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
|
|
||||||
Limit: userSettings.libraryPageSize(undefined),
|
|
||||||
IsFavorite: true,
|
|
||||||
StartIndex: 0,
|
|
||||||
ParentId: topParentId }), [topParentId]);
|
|
||||||
|
|
||||||
userSettings.loadQuerySettings(savedQueryKey, query);
|
|
||||||
|
|
||||||
const getCurrentViewStyle = useCallback(() => {
|
|
||||||
return userSettings.get(savedViewKey, false) || 'Poster';
|
|
||||||
}, [savedViewKey]);
|
|
||||||
|
|
||||||
const reloadItems = useCallback(() => {
|
|
||||||
const page = element.current;
|
|
||||||
|
|
||||||
if (!page) {
|
|
||||||
console.error('Unexpected null reference');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
loading.show();
|
|
||||||
window.ApiClient.getItems(window.ApiClient.getCurrentUserId(), query).then((result) => {
|
|
||||||
setItemsResult(result);
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
loading.hide();
|
|
||||||
|
|
||||||
import('../../components/autoFocuser').then(({ default: autoFocuser }) => {
|
|
||||||
autoFocuser.autoFocus(page);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, [query]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
reloadItems();
|
|
||||||
}, [query, reloadItems]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<ViewItemsContainer
|
||||||
<div className='flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom focuscontainer-x'>
|
topParentId={topParentId}
|
||||||
<Pagination itemsResult= {itemsResult} query={query} reloadItems={reloadItems} />
|
getBasekey={getBasekey}
|
||||||
|
getFilterMode={getFilterMode}
|
||||||
<SelectView getCurrentViewStyle={getCurrentViewStyle} savedViewKey={savedViewKey} query={query} reloadItems={reloadItems} />
|
getItemTypes={getItemTypes}
|
||||||
<Sort sortMenuOptions={SortMenuOptions} query={query} savedQueryKey={savedQueryKey} reloadItems={reloadItems} />
|
getSortMenuOptions={getSortMenuOptions}
|
||||||
<Filter query={query} reloadItems={reloadItems} />
|
getNoItemsMessage={getNoItemsMessage}
|
||||||
|
/>
|
||||||
</div>
|
|
||||||
|
|
||||||
<AlphaPickerContainer query={query} reloadItems={reloadItems} />
|
|
||||||
|
|
||||||
<ItemsContainer getCurrentViewStyle={getCurrentViewStyle} query={query} items={itemsResult?.Items} noItemsMessage= 'MessageNoFavoritesAvailable' />
|
|
||||||
|
|
||||||
<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} query={query} reloadItems={reloadItems} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,18 @@ type IProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GenresView: FunctionComponent<IProps> = ({ topParentId }: IProps) => {
|
const GenresView: FunctionComponent<IProps> = ({ topParentId }: IProps) => {
|
||||||
const savedQueryKey = topParentId + '-moviegenres';
|
|
||||||
const savedViewKey = savedQueryKey + '-view';
|
|
||||||
|
|
||||||
const [ itemsResult, setItemsResult ] = useState<BaseItemDtoQueryResult>({});
|
const [ itemsResult, setItemsResult ] = useState<BaseItemDtoQueryResult>({});
|
||||||
const element = useRef<HTMLDivElement>(null);
|
const element = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const query = useMemo<IQuery>(() => ({
|
const getSettingsKey = useCallback(() => {
|
||||||
|
return topParentId + '-genres';
|
||||||
|
}, [topParentId]);
|
||||||
|
|
||||||
|
const getViewSettings = useCallback(() => {
|
||||||
|
return getSettingsKey() + '-view';
|
||||||
|
}, [getSettingsKey]);
|
||||||
|
|
||||||
|
let query = useMemo<IQuery>(() => ({
|
||||||
SortBy: 'SortName',
|
SortBy: 'SortName',
|
||||||
SortOrder: 'Ascending',
|
SortOrder: 'Ascending',
|
||||||
IncludeItemTypes: 'Movie',
|
IncludeItemTypes: 'Movie',
|
||||||
|
@ -27,20 +32,13 @@ const GenresView: FunctionComponent<IProps> = ({ topParentId }: IProps) => {
|
||||||
StartIndex: 0,
|
StartIndex: 0,
|
||||||
ParentId: topParentId }), [topParentId]);
|
ParentId: topParentId }), [topParentId]);
|
||||||
|
|
||||||
userSettings.loadQuerySettings(savedQueryKey, query);
|
query = userSettings.loadQuerySettings(getSettingsKey(), query);
|
||||||
|
|
||||||
const getCurrentViewStyle = useCallback(() => {
|
const getCurrentViewStyle = useCallback(() => {
|
||||||
return userSettings.get(savedViewKey, false) || 'Poster';
|
return userSettings.get(getViewSettings(), false) || 'Poster';
|
||||||
}, [savedViewKey]);
|
}, [getViewSettings]);
|
||||||
|
|
||||||
const reloadItems = useCallback(() => {
|
const reloadItems = useCallback(() => {
|
||||||
const page = element.current;
|
|
||||||
|
|
||||||
if (!page) {
|
|
||||||
console.error('Unexpected null reference');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
loading.show();
|
loading.show();
|
||||||
window.ApiClient.getGenres(window.ApiClient.getCurrentUserId(), query).then((result) => {
|
window.ApiClient.getGenres(window.ApiClient.getCurrentUserId(), query).then((result) => {
|
||||||
setItemsResult(result);
|
setItemsResult(result);
|
||||||
|
|
|
@ -1,23 +1,30 @@
|
||||||
import { BaseItemDtoQueryResult } from '@thornbill/jellyfin-sdk/dist/generated-client';
|
import React, { FunctionComponent, useCallback } from 'react';
|
||||||
import React, { FunctionComponent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
||||||
|
|
||||||
import loading from '../../components/loading/loading';
|
|
||||||
import globalize from '../../scripts/globalize';
|
import globalize from '../../scripts/globalize';
|
||||||
import * as userSettings from '../../scripts/settings/userSettings';
|
|
||||||
import AlphaPickerContainer from '../components/AlphaPickerContainer';
|
import ViewItemsContainer from '../components/ViewItemsContainer';
|
||||||
import Filter from '../components/Filter';
|
|
||||||
import ItemsContainer from '../components/ItemsContainer';
|
|
||||||
import Pagination from '../components/Pagination';
|
|
||||||
import SelectView from '../components/SelectView';
|
|
||||||
import Shuffle from '../components/Shuffle';
|
|
||||||
import Sort from '../components/Sort';
|
|
||||||
import { IQuery } from '../components/type';
|
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
topParentId: string | null;
|
topParentId: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SortMenuOptions = () => {
|
const MoviesView: FunctionComponent<IProps> = ({ topParentId }: IProps) => {
|
||||||
|
const getBasekey = useCallback(() => {
|
||||||
|
return 'movies';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getFilterMode = useCallback(() => {
|
||||||
|
return 'movies';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getItemTypes = useCallback(() => {
|
||||||
|
return 'Movie';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getNoItemsMessage = useCallback(() => {
|
||||||
|
return 'MessageNoItemsAvailable';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getSortMenuOptions = useCallback(() => {
|
||||||
return [{
|
return [{
|
||||||
name: globalize.translate('Name'),
|
name: globalize.translate('Name'),
|
||||||
id: 'SortName,ProductionYear'
|
id: 'SortName,ProductionYear'
|
||||||
|
@ -49,79 +56,18 @@ const SortMenuOptions = () => {
|
||||||
name: globalize.translate('Runtime'),
|
name: globalize.translate('Runtime'),
|
||||||
id: 'Runtime,SortName,ProductionYear'
|
id: 'Runtime,SortName,ProductionYear'
|
||||||
}];
|
}];
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
const MoviesView: FunctionComponent<IProps> = ({ topParentId }: IProps) => {
|
|
||||||
const savedQueryKey = topParentId + '-movies';
|
|
||||||
const savedViewKey = savedQueryKey + '-view';
|
|
||||||
|
|
||||||
const [ itemsResult, setItemsResult ] = useState<BaseItemDtoQueryResult>();
|
|
||||||
|
|
||||||
const element = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const query = useMemo<IQuery>(() => ({
|
|
||||||
SortBy: 'SortName,ProductionYear',
|
|
||||||
SortOrder: 'Ascending',
|
|
||||||
IncludeItemTypes: 'Movie',
|
|
||||||
Recursive: true,
|
|
||||||
Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo',
|
|
||||||
ImageTypeLimit: 1,
|
|
||||||
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
|
|
||||||
Limit: userSettings.libraryPageSize(undefined),
|
|
||||||
StartIndex: 0,
|
|
||||||
ParentId: topParentId }), [topParentId]);
|
|
||||||
|
|
||||||
userSettings.loadQuerySettings(savedQueryKey, query);
|
|
||||||
|
|
||||||
const getCurrentViewStyle = useCallback(() => {
|
|
||||||
return userSettings.get(savedViewKey, false) || 'Poster';
|
|
||||||
}, [savedViewKey]);
|
|
||||||
|
|
||||||
const reloadItems = useCallback(() => {
|
|
||||||
const page = element.current;
|
|
||||||
|
|
||||||
if (!page) {
|
|
||||||
console.error('Unexpected null reference');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loading.show();
|
|
||||||
window.ApiClient.getItems(window.ApiClient.getCurrentUserId(), query).then((result) => {
|
|
||||||
setItemsResult(result);
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
|
|
||||||
loading.hide();
|
|
||||||
|
|
||||||
import('../../components/autoFocuser').then(({ default: autoFocuser }) => {
|
|
||||||
autoFocuser.autoFocus(page);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, [query]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
reloadItems();
|
|
||||||
}, [query, reloadItems]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<ViewItemsContainer
|
||||||
<div className='flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom focuscontainer-x'>
|
topParentId={topParentId}
|
||||||
<Pagination itemsResult= {itemsResult} query={query} reloadItems={reloadItems} />
|
isBtnShuffleEnabled={true}
|
||||||
|
getBasekey={getBasekey}
|
||||||
<Shuffle itemsResult= {itemsResult} topParentId={topParentId} />
|
getFilterMode={getFilterMode}
|
||||||
|
getItemTypes={getItemTypes}
|
||||||
<SelectView getCurrentViewStyle={getCurrentViewStyle} savedViewKey={savedViewKey} query={query} reloadItems={reloadItems} />
|
getSortMenuOptions={getSortMenuOptions}
|
||||||
<Sort sortMenuOptions={SortMenuOptions} query={query} savedQueryKey={savedQueryKey} reloadItems={reloadItems} />
|
getNoItemsMessage={getNoItemsMessage}
|
||||||
<Filter query={query} reloadItems={reloadItems} />
|
/>
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<AlphaPickerContainer query={query} reloadItems={reloadItems} />
|
|
||||||
|
|
||||||
<ItemsContainer getCurrentViewStyle={getCurrentViewStyle} query={query} items={itemsResult?.Items} noItemsMessage= 'NoCreatedLibraries' />
|
|
||||||
|
|
||||||
<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} query={query} reloadItems={reloadItems} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ const SuggestionsView: FunctionComponent<IProps> = (props: IProps) => {
|
||||||
|
|
||||||
const loadResume = useCallback((page, userId, parentId) => {
|
const loadResume = useCallback((page, userId, parentId) => {
|
||||||
loading.show();
|
loading.show();
|
||||||
const screenWidth: any = dom.getWindowSize();
|
const screenWidth = dom.getWindowSize();
|
||||||
const options = {
|
const options = {
|
||||||
SortBy: 'DatePlayed',
|
SortBy: 'DatePlayed',
|
||||||
SortOrder: 'Descending',
|
SortOrder: 'Descending',
|
||||||
|
@ -82,7 +82,7 @@ const SuggestionsView: FunctionComponent<IProps> = (props: IProps) => {
|
||||||
}, [autoFocus]);
|
}, [autoFocus]);
|
||||||
|
|
||||||
const loadSuggestions = useCallback((page, userId) => {
|
const loadSuggestions = useCallback((page, userId) => {
|
||||||
const screenWidth: any = dom.getWindowSize();
|
const screenWidth = dom.getWindowSize();
|
||||||
let itemLimit = 5;
|
let itemLimit = 5;
|
||||||
if (screenWidth.innerWidth >= 1600) {
|
if (screenWidth.innerWidth >= 1600) {
|
||||||
itemLimit = 8;
|
itemLimit = 8;
|
||||||
|
|
|
@ -1,19 +1,31 @@
|
||||||
import '../../elements/emby-itemscontainer/emby-itemscontainer';
|
|
||||||
|
|
||||||
import { BaseItemDtoQueryResult } from '@thornbill/jellyfin-sdk/dist/generated-client';
|
import React, { FunctionComponent, useCallback } from 'react';
|
||||||
import React, { FunctionComponent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
||||||
|
|
||||||
import loading from '../../components/loading/loading';
|
|
||||||
import globalize from '../../scripts/globalize';
|
import globalize from '../../scripts/globalize';
|
||||||
import * as userSettings from '../../scripts/settings/userSettings';
|
import ViewItemsContainer from '../components/ViewItemsContainer';
|
||||||
import AlphaPickerContainer from '../components/AlphaPickerContainer';
|
|
||||||
import Filter from '../components/Filter';
|
|
||||||
import ItemsContainer from '../components/ItemsContainer';
|
|
||||||
import Pagination from '../components/Pagination';
|
|
||||||
import Sort from '../components/Sort';
|
|
||||||
import { IQuery } from '../components/type';
|
|
||||||
|
|
||||||
const SortMenuOptions = () => {
|
type IProps = {
|
||||||
|
topParentId: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TrailersView: FunctionComponent<IProps> = ({ topParentId }: IProps) => {
|
||||||
|
const getBasekey = useCallback(() => {
|
||||||
|
return 'trailers';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getFilterMode = useCallback(() => {
|
||||||
|
return 'movies';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getItemTypes = useCallback(() => {
|
||||||
|
return 'Trailer';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getNoItemsMessage = useCallback(() => {
|
||||||
|
return 'MessageNoTrailersFound';
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getSortMenuOptions = useCallback(() => {
|
||||||
return [{
|
return [{
|
||||||
name: globalize.translate('Name'),
|
name: globalize.translate('Name'),
|
||||||
id: 'SortName'
|
id: 'SortName'
|
||||||
|
@ -36,75 +48,17 @@ const SortMenuOptions = () => {
|
||||||
name: globalize.translate('OptionReleaseDate'),
|
name: globalize.translate('OptionReleaseDate'),
|
||||||
id: 'PremiereDate,SortName'
|
id: 'PremiereDate,SortName'
|
||||||
}];
|
}];
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
type IProps = {
|
|
||||||
topParentId: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TrailersView: FunctionComponent<IProps> = ({ topParentId }: IProps) => {
|
|
||||||
const savedQueryKey = topParentId + '-trailers';
|
|
||||||
const savedViewKey = savedQueryKey + '-view';
|
|
||||||
|
|
||||||
const [ itemsResult, setItemsResult ] = useState<BaseItemDtoQueryResult>();
|
|
||||||
const element = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const query = useMemo<IQuery>(() => ({
|
|
||||||
SortBy: 'SortName',
|
|
||||||
SortOrder: 'Ascending',
|
|
||||||
IncludeItemTypes: 'Trailer',
|
|
||||||
Recursive: true,
|
|
||||||
Fields: 'PrimaryImageAspectRatio,SortName,BasicSyncInfo',
|
|
||||||
ImageTypeLimit: 1,
|
|
||||||
EnableImageTypes: 'Primary,Backdrop,Banner,Thumb',
|
|
||||||
Limit: userSettings.libraryPageSize(undefined),
|
|
||||||
StartIndex: 0,
|
|
||||||
ParentId: topParentId }), [topParentId]);
|
|
||||||
|
|
||||||
userSettings.loadQuerySettings(savedQueryKey, query);
|
|
||||||
|
|
||||||
const getCurrentViewStyle = useCallback(() => {
|
|
||||||
return userSettings.get(savedViewKey, false) || 'Poster';
|
|
||||||
}, [savedViewKey]);
|
|
||||||
|
|
||||||
const reloadItems = useCallback(() => {
|
|
||||||
const page = element.current;
|
|
||||||
|
|
||||||
if (!page) {
|
|
||||||
console.error('Unexpected null reference');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loading.show();
|
|
||||||
window.ApiClient.getItems(window.ApiClient.getCurrentUserId(), query).then((result) => {
|
|
||||||
setItemsResult(result);
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
|
|
||||||
loading.hide();
|
|
||||||
});
|
|
||||||
}, [query]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
reloadItems();
|
|
||||||
}, [query, reloadItems]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<ViewItemsContainer
|
||||||
<div className='flex align-items-center justify-content-center flex-wrap-wrap padded-top padded-left padded-right padded-bottom focuscontainer-x'>
|
topParentId={topParentId}
|
||||||
<Pagination itemsResult= {itemsResult} query={query} reloadItems={reloadItems} />
|
getBasekey={getBasekey}
|
||||||
|
getFilterMode={getFilterMode}
|
||||||
<Sort sortMenuOptions={SortMenuOptions} query={query} savedQueryKey={savedQueryKey} reloadItems={reloadItems} />
|
getItemTypes={getItemTypes}
|
||||||
<Filter query={query} reloadItems={reloadItems} />
|
getSortMenuOptions={getSortMenuOptions}
|
||||||
|
getNoItemsMessage={getNoItemsMessage}
|
||||||
</div>
|
/>
|
||||||
|
|
||||||
<AlphaPickerContainer query={query} reloadItems={reloadItems} />
|
|
||||||
|
|
||||||
<ItemsContainer getCurrentViewStyle={getCurrentViewStyle} query={query} items={itemsResult?.Items} noItemsMessage= 'MessageNoTrailersFound' />
|
|
||||||
|
|
||||||
<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} query={query} reloadItems={reloadItems} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue