Merge pull request #6777 from thornbill/library-controls

This commit is contained in:
Bill Thornton
2025-05-06 08:19:55 -04:00
committed by GitHub
12 changed files with 430 additions and 321 deletions

View File

@@ -1,64 +0,0 @@
import React, { FC, useCallback } from 'react';
import ButtonGroup from '@mui/material/ButtonGroup/ButtonGroup';
import IconButton from '@mui/material/IconButton';
import ViewModuleIcon from '@mui/icons-material/ViewModule';
import ViewListIcon from '@mui/icons-material/ViewList';
import globalize from 'lib/globalize';
import { LibraryViewSettings, ViewMode } from 'types/library';
import { LibraryTab } from 'types/libraryTab';
import ViewSettingsButton from './ViewSettingsButton';
interface GridListViewButtonProps {
viewType: LibraryTab;
libraryViewSettings: LibraryViewSettings;
setLibraryViewSettings: React.Dispatch<React.SetStateAction<LibraryViewSettings>>;
}
const GridListViewButton: FC<GridListViewButtonProps> = ({
viewType,
libraryViewSettings,
setLibraryViewSettings
}) => {
const handleToggleCurrentView = useCallback(() => {
setLibraryViewSettings((prevState) => ({
...prevState,
ViewMode:
prevState.ViewMode === ViewMode.ListView ? ViewMode.GridView : ViewMode.ListView
}));
}, [setLibraryViewSettings]);
const isGridView = libraryViewSettings.ViewMode === ViewMode.GridView;
return (
<ButtonGroup>
{isGridView ? (
<ViewSettingsButton
viewType={viewType}
libraryViewSettings={libraryViewSettings}
setLibraryViewSettings={setLibraryViewSettings}
/>
) : (
<IconButton
title={globalize.translate('GridView')}
className='paper-icon-button-light autoSize'
disabled={isGridView}
onClick={handleToggleCurrentView}
>
<ViewModuleIcon />
</IconButton>
)}
<IconButton
title={globalize.translate('ListView')}
className='paper-icon-button-light autoSize'
disabled={!isGridView}
onClick={handleToggleCurrentView}
>
<ViewListIcon />
</IconButton>
</ButtonGroup>
);
};
export default GridListViewButton;

View File

@@ -2,9 +2,12 @@ import type { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/bas
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type';
import { ImageType } from '@jellyfin/sdk/lib/generated-client/models/image-type';
import { ItemSortBy } from '@jellyfin/sdk/lib/generated-client/models/item-sort-by';
import React, { type FC, useCallback } from 'react';
import Box from '@mui/material/Box';
import ButtonGroup from '@mui/material/ButtonGroup';
import type { Theme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery';
import classNames from 'classnames';
import React, { type FC, useCallback } from 'react';
import { useApi } from 'hooks/useApi';
import { useLocalStorage } from 'hooks/useLocalStorage';
@@ -31,8 +34,8 @@ import PlayAllButton from './PlayAllButton';
import QueueButton from './QueueButton';
import ShuffleButton from './ShuffleButton';
import SortButton from './SortButton';
import GridListViewButton from './GridListViewButton';
import LibraryViewMenu from './LibraryViewMenu';
import ViewSettingsButton from './ViewSettingsButton';
interface ItemsViewProps {
viewType: LibraryTab;
@@ -72,10 +75,11 @@ const ItemsView: FC<ItemsViewProps> = ({
getSettingsKey(viewType, parentId),
getDefaultLibraryViewSettings(viewType)
);
const isSmallScreen = useMediaQuery((t: Theme) => t.breakpoints.up('sm'));
const { __legacyApiClient__ } = useApi();
const {
isLoading,
isPending,
data: itemsResult,
isPlaceholderData,
refetch
@@ -229,90 +233,142 @@ const ItemsView: FC<ItemsViewProps> = ({
);
return (
<Box>
<Box className='padded-bottom-page'>
<Box
className={classNames(
'padded-top padded-left padded-right padded-bottom',
'padded-top padded-left padded-right',
{ 'padded-right-withalphapicker': isAlphabetPickerEnabled }
)}
sx={{
display: 'flex',
flexWrap: 'wrap'
flexWrap: 'wrap',
alignItems: 'center'
}}
>
<Box
sx={{ marginRight: 1 }}
>
<LibraryViewMenu />
</Box>
<LibraryViewMenu />
{isBtnPlayAllEnabled && (
<PlayAllButton
item={item}
items={items}
viewType={viewType}
hasFilters={hasFilters}
libraryViewSettings={libraryViewSettings}
/>
)}
{isBtnShuffleEnabled && totalRecordCount > 1 && (
<ShuffleButton
item={item}
items={items}
viewType={viewType}
hasFilters={hasFilters}
libraryViewSettings={libraryViewSettings}
/>
)}
{isBtnQueueEnabled
&& item
&& playbackManager.canQueue(item) && (
<QueueButton
item={item}
items={items}
hasFilters={hasFilters}
/>
)}
{isBtnSortEnabled && (
<SortButton
viewType={viewType}
libraryViewSettings={libraryViewSettings}
setLibraryViewSettings={setLibraryViewSettings}
/>
)}
{isBtnFilterEnabled && (
<FilterButton
parentId={parentId}
itemType={itemType}
viewType={viewType}
hasFilters={hasFilters}
libraryViewSettings={libraryViewSettings}
setLibraryViewSettings={setLibraryViewSettings}
/>
)}
{isBtnNewCollectionEnabled && <NewCollectionButton />}
{isBtnGridListEnabled && (
<GridListViewButton
viewType={viewType}
libraryViewSettings={libraryViewSettings}
setLibraryViewSettings={setLibraryViewSettings}
/>
)}
{isPaginationEnabled && (
<Box
sx={{
display: 'flex',
justifyContent: 'flex-end',
flexGrow: 1,
order: 10
}}
<Box
sx={{
flexGrow: {
xs: 1,
sm: 0
},
marginRight: 1
}}
>
<ButtonGroup
color='inherit'
variant='text'
>
{isBtnFilterEnabled && (
<FilterButton
parentId={parentId}
itemType={itemType}
viewType={viewType}
hasFilters={hasFilters}
libraryViewSettings={libraryViewSettings}
setLibraryViewSettings={setLibraryViewSettings}
/>
)}
{isBtnSortEnabled && (
<SortButton
viewType={viewType}
libraryViewSettings={libraryViewSettings}
setLibraryViewSettings={setLibraryViewSettings}
/>
)}
{isBtnGridListEnabled && (
<ViewSettingsButton
viewType={viewType}
libraryViewSettings={libraryViewSettings}
setLibraryViewSettings={setLibraryViewSettings}
/>
)}
</ButtonGroup>
</Box>
<Box
sx={{
display: 'flex',
flexGrow: {
xs: 1,
sm: 0
},
justifyContent: 'end'
}}
>
{!isPending && (
<>
<ButtonGroup
variant='contained'
>
{isBtnPlayAllEnabled && (
<PlayAllButton
item={item}
items={items}
viewType={viewType}
hasFilters={hasFilters}
isTextVisible={isSmallScreen}
libraryViewSettings={libraryViewSettings}
/>
)}
{isBtnShuffleEnabled && totalRecordCount > 1 && (
<ShuffleButton
item={item}
items={items}
viewType={viewType}
hasFilters={hasFilters}
isTextVisible={isSmallScreen && !isBtnPlayAllEnabled}
libraryViewSettings={libraryViewSettings}
/>
)}
{isBtnQueueEnabled && item && playbackManager.canQueue(item) && (
<QueueButton
item={item}
items={items}
hasFilters={hasFilters}
isTextVisible={isSmallScreen && !isBtnPlayAllEnabled && !isBtnShuffleEnabled}
/>
)}
</ButtonGroup>
{isBtnNewCollectionEnabled && <NewCollectionButton isTextVisible={isSmallScreen} />}
</>
)}
</Box>
<Box
sx={{
display: 'flex',
justifyContent: 'end',
flexBasis: {
xs: '100%',
sm: 'auto'
},
flexGrow: 1,
marginTop: {
xs: 0.5,
sm: 0
}
}}
>
{!isPending && isPaginationEnabled && (
<Pagination
totalRecordCount={totalRecordCount}
libraryViewSettings={libraryViewSettings}
isPlaceholderData={isPlaceholderData}
setLibraryViewSettings={setLibraryViewSettings}
/>
</Box>
)}
)}
</Box>
</Box>
{isAlphabetPickerEnabled && hasSortName && (
@@ -322,7 +378,7 @@ const ItemsView: FC<ItemsViewProps> = ({
/>
)}
{isLoading ? (
{isPending ? (
<Loading />
) : (
<ItemsContainer
@@ -335,10 +391,10 @@ const ItemsView: FC<ItemsViewProps> = ({
</ItemsContainer>
)}
{isPaginationEnabled && (
{!isPending && isPaginationEnabled && (
<Box
className={classNames(
'padded-top padded-left padded-right padded-bottom',
'padded-left padded-right',
{ 'padded-right-withalphapicker': isAlphabetPickerEnabled }
)}
sx={{

View File

@@ -1,9 +1,16 @@
import React, { FC, useCallback } from 'react';
import IconButton from '@mui/material/IconButton';
import AddIcon from '@mui/icons-material/Add';
import Add from '@mui/icons-material/Add';
import Button from '@mui/material/Button';
import globalize from 'lib/globalize';
const NewCollectionButton: FC = () => {
interface NewCollectionButtonProps {
isTextVisible: boolean
}
const NewCollectionButton: FC<NewCollectionButtonProps> = ({
isTextVisible
}) => {
const showCollectionEditor = useCallback(() => {
import('components/collectionEditor/collectionEditor').then(
({ default: CollectionEditor }) => {
@@ -21,13 +28,17 @@ const NewCollectionButton: FC = () => {
}, []);
return (
<IconButton
title={globalize.translate('Add')}
className='paper-icon-button-light btnNewCollection autoSize'
<Button
variant='contained'
startIcon={isTextVisible ? <Add /> : undefined}
onClick={showCollectionEditor}
>
<AddIcon />
</IconButton>
{isTextVisible ? (
globalize.translate('NewCollection')
) : (
<Add />
)}
</Button>
);
};

View File

@@ -2,8 +2,12 @@ import React, { FC, useCallback } from 'react';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import ButtonGroup from '@mui/material/ButtonGroup';
import IconButton from '@mui/material/IconButton';
import Stack from '@mui/material/Stack';
import type { Theme } from '@mui/material/styles';
import Typography from '@mui/material/Typography';
import useMediaQuery from '@mui/material/useMediaQuery';
import globalize from 'lib/globalize';
import * as userSettings from 'scripts/settings/userSettings';
@@ -22,6 +26,8 @@ const Pagination: FC<PaginationProps> = ({
totalRecordCount,
isPlaceholderData
}) => {
const isSmallScreen = useMediaQuery((t: Theme) => t.breakpoints.up('sm'));
const limit = userSettings.libraryPageSize(undefined);
const startIndex = libraryViewSettings.StartIndex ?? 0;
const recordsStart = totalRecordCount ? startIndex + 1 : 0;
@@ -47,47 +53,88 @@ const Pagination: FC<PaginationProps> = ({
}, [limit, setLibraryViewSettings, startIndex]);
return (
<Box
className='paging'
<Stack
direction='row'
spacing={0.5}
sx={{
display: 'flex'
alignItems: 'center',
flexGrow: {
xs: 1,
sm: 0
},
marginLeft: {
xs: 0,
sm: 0.5
}
}}
>
{!isSmallScreen && (
<Button
color='inherit'
variant='text'
title={globalize.translate('Previous')}
disabled={!showControls || startIndex == 0 || isPlaceholderData}
onClick={onPreviousPageClick}
>
<ArrowBackIcon />
</Button>
)}
<Box
className='listPaging'
sx={{ display: 'flex', alignItems: 'center' }}
sx={{
display: 'flex',
flexGrow: 1,
alignItems: 'center',
justifyContent: 'center',
marginLeft: 1,
marginRight: 1
}}
>
<span>
<Typography variant='body2'>
{globalize.translate(
'ListPaging',
recordsStart,
recordsEnd,
totalRecordCount
)}
</span>
{showControls && (
<ButtonGroup>
<IconButton
title={globalize.translate('Previous')}
className='paper-icon-button-light btnPreviousPage autoSize'
disabled={startIndex == 0 || isPlaceholderData}
onClick={onPreviousPageClick}
>
<ArrowBackIcon />
</IconButton>
<IconButton
title={globalize.translate('Next')}
className='paper-icon-button-light btnNextPage autoSize'
disabled={startIndex + limit >= totalRecordCount || isPlaceholderData }
onClick={onNextPageClick}
>
<ArrowForwardIcon />
</IconButton>
</ButtonGroup>
)}
</Typography>
</Box>
</Box>
{isSmallScreen && (
<ButtonGroup
color='inherit'
variant='text'
>
<Button
title={globalize.translate('Previous')}
disabled={!showControls || startIndex == 0 || isPlaceholderData}
onClick={onPreviousPageClick}
>
<ArrowBackIcon />
</Button>
<Button
title={globalize.translate('Next')}
disabled={!showControls || startIndex + limit >= totalRecordCount || isPlaceholderData }
onClick={onNextPageClick}
>
<ArrowForwardIcon />
</Button>
</ButtonGroup>
)}
{!isSmallScreen && (
<Button
color='inherit'
variant='text'
title={globalize.translate('Next')}
disabled={!showControls || startIndex + limit >= totalRecordCount || isPlaceholderData }
onClick={onNextPageClick}
>
<ArrowForwardIcon />
</Button>
)}
</Stack>
);
};

View File

@@ -1,6 +1,6 @@
import React, { FC, useCallback } from 'react';
import IconButton from '@mui/material/IconButton';
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
import Button from '@mui/material/Button';
import PlayArrow from '@mui/icons-material/PlayArrow';
import { playbackManager } from 'components/playback/playbackmanager';
import globalize from 'lib/globalize';
@@ -10,14 +10,22 @@ import { LibraryTab } from 'types/libraryTab';
import type { ItemDto } from 'types/base/models/item-dto';
interface PlayAllButtonProps {
item: ItemDto | undefined;
items: ItemDto[];
viewType: LibraryTab;
hasFilters: boolean;
item: ItemDto | undefined
items: ItemDto[]
viewType: LibraryTab
hasFilters: boolean
isTextVisible: boolean
libraryViewSettings: LibraryViewSettings
}
const PlayAllButton: FC<PlayAllButtonProps> = ({ item, items, viewType, hasFilters, libraryViewSettings }) => {
const PlayAllButton: FC<PlayAllButtonProps> = ({
item,
items,
viewType,
hasFilters,
isTextVisible,
libraryViewSettings
}) => {
const play = useCallback(() => {
if (item && !hasFilters) {
playbackManager.play({
@@ -47,19 +55,17 @@ const PlayAllButton: FC<PlayAllButtonProps> = ({ item, items, viewType, hasFilte
}, [hasFilters, item, items, libraryViewSettings, viewType]);
return (
<IconButton
<Button
title={globalize.translate('HeaderPlayAll')}
className='paper-icon-button-light btnPlay autoSize'
startIcon={isTextVisible ? <PlayArrow /> : undefined}
onClick={play}
sx={{
order: {
xs: 1,
sm: 'unset'
}
}}
>
<PlayArrowIcon />
</IconButton>
{isTextVisible ? (
globalize.translate('HeaderPlayAll')
) : (
<PlayArrow />
)}
</Button>
);
};

View File

@@ -1,6 +1,6 @@
import React, { FC, useCallback } from 'react';
import IconButton from '@mui/material/IconButton';
import QueueIcon from '@mui/icons-material/Queue';
import Button from '@mui/material/Button';
import Queue from '@mui/icons-material/Queue';
import { playbackManager } from 'components/playback/playbackmanager';
import globalize from 'lib/globalize';
@@ -8,11 +8,17 @@ import type { ItemDto } from 'types/base/models/item-dto';
interface QueueButtonProps {
item: ItemDto | undefined
items: ItemDto[];
hasFilters: boolean;
items: ItemDto[]
hasFilters: boolean
isTextVisible: boolean
}
const QueueButton: FC<QueueButtonProps> = ({ item, items, hasFilters }) => {
const QueueButton: FC<QueueButtonProps> = ({
item,
items,
hasFilters,
isTextVisible
}) => {
const queue = useCallback(() => {
if (item && !hasFilters) {
playbackManager.queue({
@@ -30,19 +36,17 @@ const QueueButton: FC<QueueButtonProps> = ({ item, items, hasFilters }) => {
}, [hasFilters, item, items]);
return (
<IconButton
<Button
title={globalize.translate('AddToPlayQueue')}
className='paper-icon-button-light btnQueue autoSize'
startIcon={isTextVisible ? <Queue /> : undefined}
onClick={queue}
sx={{
order: {
xs: 3,
sm: 'unset'
}
}}
>
<QueueIcon />
</IconButton>
{isTextVisible ? (
globalize.translate('AddToPlayQueue')
) : (
<Queue />
)}
</Button>
);
};

View File

@@ -1,7 +1,7 @@
import { ItemSortBy } from '@jellyfin/sdk/lib/generated-client/models/item-sort-by';
import React, { FC, useCallback } from 'react';
import IconButton from '@mui/material/IconButton';
import ShuffleIcon from '@mui/icons-material/Shuffle';
import Shuffle from '@mui/icons-material/Shuffle';
import Button from '@mui/material/Button';
import { playbackManager } from 'components/playback/playbackmanager';
import globalize from 'lib/globalize';
@@ -11,14 +11,22 @@ import { LibraryTab } from 'types/libraryTab';
import type { ItemDto } from 'types/base/models/item-dto';
interface ShuffleButtonProps {
item: ItemDto | undefined;
items: ItemDto[];
item: ItemDto | undefined
items: ItemDto[]
viewType: LibraryTab
hasFilters: boolean;
hasFilters: boolean
isTextVisible: boolean
libraryViewSettings: LibraryViewSettings
}
const ShuffleButton: FC<ShuffleButtonProps> = ({ item, items, viewType, hasFilters, libraryViewSettings }) => {
const ShuffleButton: FC<ShuffleButtonProps> = ({
item,
items,
viewType,
hasFilters,
isTextVisible,
libraryViewSettings
}) => {
const shuffle = useCallback(() => {
if (item && !hasFilters) {
playbackManager.shuffle(item);
@@ -38,19 +46,17 @@ const ShuffleButton: FC<ShuffleButtonProps> = ({ item, items, viewType, hasFilte
}, [hasFilters, item, items, libraryViewSettings, viewType]);
return (
<IconButton
<Button
title={globalize.translate('Shuffle')}
className='paper-icon-button-light btnShuffle autoSize'
startIcon={isTextVisible ? <Shuffle /> : undefined}
onClick={shuffle}
sx={{
order: {
xs: 2,
sm: 'unset'
}
}}
>
<ShuffleIcon />
</IconButton>
{isTextVisible ? (
globalize.translate('Shuffle')
) : (
<Shuffle />
)}
</Button>
);
};

View File

@@ -1,12 +1,11 @@
import { ItemSortBy } from '@jellyfin/sdk/lib/generated-client/models/item-sort-by';
import { SortOrder } from '@jellyfin/sdk/lib/generated-client/models/sort-order';
import React, { FC, useCallback } from 'react';
import IconButton from '@mui/material/IconButton';
import Button from '@mui/material/Button';
import MenuItem from '@mui/material/MenuItem';
import Popover from '@mui/material/Popover';
import Typography from '@mui/material/Typography';
import Divider from '@mui/material/Divider';
import Box from '@mui/material/Box';
import InputLabel from '@mui/material/InputLabel';
import FormControl from '@mui/material/FormControl';
import Select, { SelectChangeEvent } from '@mui/material/Select';
@@ -149,16 +148,14 @@ const SortButton: FC<SortButtonProps> = ({
const sortMenuOptions = getSortMenuOptions(viewType);
return (
<Box>
<IconButton
<>
<Button
title={globalize.translate('Sort')}
sx={{ ml: 2 }}
aria-describedby={id}
className='paper-icon-button-light btnSort autoSize'
onClick={handleClick}
>
<SortByAlphaIcon />
</IconButton>
</Button>
<Popover
id={id}
open={open}
@@ -229,7 +226,7 @@ const SortButton: FC<SortButtonProps> = ({
</Select>
</FormControl>
</Popover>
</Box>
</>
);
};

View File

@@ -1,25 +1,28 @@
import { ImageType } from '@jellyfin/sdk/lib/generated-client/models/image-type';
import React, { FC, useCallback } from 'react';
import IconButton from '@mui/material/IconButton';
import MenuItem from '@mui/material/MenuItem';
import Check from '@mui/icons-material/Check';
import MoreVert from '@mui/icons-material/MoreVert';
import Button from '@mui/material/Button';
import Checkbox from '@mui/material/Checkbox';
import Typography from '@mui/material/Typography';
import Divider from '@mui/material/Divider';
import Box from '@mui/material/Box';
import InputLabel from '@mui/material/InputLabel';
import FormControl from '@mui/material/FormControl';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormGroup from '@mui/material/FormGroup';
import Select, { SelectChangeEvent } from '@mui/material/Select';
import InputLabel from '@mui/material/InputLabel';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import MenuItem from '@mui/material/MenuItem';
import MenuList from '@mui/material/MenuList';
import Popover from '@mui/material/Popover';
import ViewComfyIcon from '@mui/icons-material/ViewComfy';
import Select, { SelectChangeEvent } from '@mui/material/Select';
import Typography from '@mui/material/Typography';
import globalize from 'lib/globalize';
import { LibraryViewSettings } from 'types/library';
import { LibraryViewSettings, ViewMode } from 'types/library';
import { LibraryTab } from 'types/libraryTab';
const excludedViewType = [
const IMAGE_TYPE_EXCLUDED_VIEWS = [
LibraryTab.Episodes,
LibraryTab.Artists,
LibraryTab.AlbumArtists,
@@ -71,6 +74,20 @@ const ViewSettingsButton: FC<ViewSettingsButtonProps> = ({
[setLibraryViewSettings]
);
const onGridViewClick = useCallback(() => {
setLibraryViewSettings(prevState => ({
...prevState,
ViewMode: ViewMode.GridView
}));
}, [ setLibraryViewSettings ]);
const onListViewClick = useCallback(() => {
setLibraryViewSettings(prevState => ({
...prevState,
ViewMode: ViewMode.ListView
}));
}, [ setLibraryViewSettings ]);
const onSelectChange = useCallback(
(event: SelectChangeEvent) => {
setLibraryViewSettings((prevState) => ({
@@ -81,19 +98,18 @@ const ViewSettingsButton: FC<ViewSettingsButtonProps> = ({
[setLibraryViewSettings]
);
const isVisible = !excludedViewType.includes(viewType);
const isGridView = libraryViewSettings.ViewMode === ViewMode.GridView;
const isImageTypeVisible = !IMAGE_TYPE_EXCLUDED_VIEWS.includes(viewType);
return (
<Box>
<IconButton
title={globalize.translate('ButtonSelectView')}
sx={{ ml: 2 }}
<>
<Button
title={globalize.translate('ViewSettings')}
aria-describedby={id}
className='paper-icon-button-light btnSelectView autoSize'
onClick={handleClick}
>
<ViewComfyIcon />
</IconButton>
<MoreVert />
</Button>
<Popover
id={id}
open={open}
@@ -111,70 +127,101 @@ const ViewSettingsButton: FC<ViewSettingsButtonProps> = ({
'& .MuiFormControl-root': { m: 1, width: 220 }
}}
>
{isVisible && (
<FormControl>
<InputLabel id='select-sort-label'>
<Typography component='span'>
{globalize.translate('LabelImageType')}
</Typography>
</InputLabel>
<Select
value={libraryViewSettings.ImageType}
label={globalize.translate('LabelImageType')}
onChange={onSelectChange}
>
{imageTypesOptions.map((imageType) => (
<MenuItem
key={imageType.value}
value={imageType.value}
>
<Typography component='span'>
{globalize.translate(imageType.label)}
</Typography>
</MenuItem>
))}
</Select>
</FormControl>
)}
<Divider />
<FormControl>
<FormGroup>
<FormControlLabel
control={
<Checkbox
checked={libraryViewSettings.ShowTitle}
onChange={handleChange}
name='ShowTitle'
/>
}
label={globalize.translate('ShowTitle')}
/>
{isVisible && (
<FormControlLabel
control={
<Checkbox
checked={libraryViewSettings.ShowYear}
onChange={handleChange}
name='ShowYear'
/>
}
label={globalize.translate('ShowYear')}
/>
<MenuList>
<MenuItem
onClick={onGridViewClick}
>
{isGridView && (
<ListItemIcon><Check /></ListItemIcon>
)}
<FormControlLabel
control={
<Checkbox
checked={libraryViewSettings.CardLayout}
onChange={handleChange}
name='CardLayout'
/>
}
label={globalize.translate('EnableCardLayout')}
/>
</FormGroup>
</FormControl>
<ListItemText inset={!isGridView}>
{globalize.translate('GridView')}
</ListItemText>
</MenuItem>
<MenuItem
onClick={onListViewClick}
>
{!isGridView && (
<ListItemIcon><Check /></ListItemIcon>
)}
<ListItemText inset={isGridView}>
{globalize.translate('ListView')}
</ListItemText>
</MenuItem>
{isGridView && (
<>
<Divider />
{isImageTypeVisible && (
<>
<FormControl>
<InputLabel>
<Typography component='span'>
{globalize.translate('LabelImageType')}
</Typography>
</InputLabel>
<Select
value={libraryViewSettings.ImageType}
label={globalize.translate('LabelImageType')}
onChange={onSelectChange}
>
{imageTypesOptions.map((imageType) => (
<MenuItem
key={imageType.value}
value={imageType.value}
>
<Typography component='span'>
{globalize.translate(imageType.label)}
</Typography>
</MenuItem>
))}
</Select>
</FormControl>
<Divider />
</>
)}
<FormControl>
<FormGroup>
<FormControlLabel
control={
<Checkbox
checked={libraryViewSettings.ShowTitle}
onChange={handleChange}
name='ShowTitle'
/>
}
label={globalize.translate('ShowTitle')}
/>
{isImageTypeVisible && (
<FormControlLabel
control={
<Checkbox
checked={libraryViewSettings.ShowYear}
onChange={handleChange}
name='ShowYear'
/>
}
label={globalize.translate('ShowYear')}
/>
)}
<FormControlLabel
control={
<Checkbox
checked={libraryViewSettings.CardLayout}
onChange={handleChange}
name='CardLayout'
/>
}
label={globalize.translate('EnableCardLayout')}
/>
</FormGroup>
</FormControl>
</>
)}
</MenuList>
</Popover>
</Box>
</>
);
};

View File

@@ -1,8 +1,8 @@
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
import React, { FC, useCallback } from 'react';
import ArrowForwardIosSharpIcon from '@mui/icons-material/ArrowForwardIosSharp';
import Box from '@mui/material/Box';
import FilterListIcon from '@mui/icons-material/FilterList';
import FilterAlt from '@mui/icons-material/FilterAlt';
import Button from '@mui/material/Button';
import Popover from '@mui/material/Popover';
import MuiAccordion, { AccordionProps } from '@mui/material/Accordion';
import MuiAccordionDetails from '@mui/material/AccordionDetails';
@@ -10,7 +10,6 @@ import MuiAccordionSummary, {
AccordionSummaryProps
} from '@mui/material/AccordionSummary';
import Badge from '@mui/material/Badge';
import IconButton from '@mui/material/IconButton';
import { styled } from '@mui/material/styles';
import Typography from '@mui/material/Typography';
@@ -158,18 +157,16 @@ const FilterButton: FC<FilterButtonProps> = ({
};
return (
<Box>
<IconButton
<>
<Button
title={globalize.translate('Filter')}
sx={{ ml: 2 }}
aria-describedby={id}
className='paper-icon-button-light btnFilter autoSize'
onClick={handleClick}
>
<Badge color='info' variant='dot' invisible={!hasFilters}>
<FilterListIcon />
<FilterAlt />
</Badge>
</IconButton>
</Button>
<Popover
id={id}
open={open}
@@ -451,7 +448,7 @@ const FilterButton: FC<FilterButtonProps> = ({
</Accordion>
)}
</Popover>
</Box>
</>
);
};

View File

@@ -39,6 +39,7 @@ const playlistsTabContent: LibraryTabContent = {
const songsTabContent: LibraryTabContent = {
viewType: LibraryTab.Songs,
isBtnShuffleEnabled: true,
isBtnGridListEnabled: false,
isAlphabetPickerEnabled: false,
itemType: [BaseItemKind.Audio]

View File

@@ -1666,6 +1666,7 @@
"ViewAlbumArtist": "View album artist",
"ViewLyrics": "View lyrics",
"ViewPlaybackInfo": "View playback info",
"ViewSettings": "View settings",
"Watched": "Watched",
"Wednesday": "Wednesday",
"WeeklyAt": "{0}s at {1}",