Merge pull request #4713 from grafixeyehero/Add-ViewSettings-mui
Add view layout settings components.
This commit is contained in:
commit
6541ee8e8e
4 changed files with 270 additions and 1 deletions
|
@ -0,0 +1,62 @@
|
||||||
|
import React, { FC, useCallback } from 'react';
|
||||||
|
import { ButtonGroup, IconButton } from '@mui/material';
|
||||||
|
import ViewModuleIcon from '@mui/icons-material/ViewModule';
|
||||||
|
import ViewListIcon from '@mui/icons-material/ViewList';
|
||||||
|
import globalize from 'scripts/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;
|
198
src/apps/experimental/components/library/ViewSettingsButton.tsx
Normal file
198
src/apps/experimental/components/library/ViewSettingsButton.tsx
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
import { ImageType } from '@jellyfin/sdk/lib/generated-client';
|
||||||
|
import React, { FC, useCallback } from 'react';
|
||||||
|
|
||||||
|
import IconButton from '@mui/material/IconButton';
|
||||||
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
|
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 Popover from '@mui/material/Popover';
|
||||||
|
import ViewComfyIcon from '@mui/icons-material/ViewComfy';
|
||||||
|
|
||||||
|
import globalize from 'scripts/globalize';
|
||||||
|
import { LibraryViewSettings, ViewMode } from 'types/library';
|
||||||
|
import { LibraryTab } from 'types/libraryTab';
|
||||||
|
|
||||||
|
const imageTypesOptions = [
|
||||||
|
{ label: 'Primary', value: ImageType.Primary },
|
||||||
|
{ label: 'Banner', value: ImageType.Banner },
|
||||||
|
{ label: 'Disc', value: ImageType.Disc },
|
||||||
|
{ label: 'Logo', value: ImageType.Logo },
|
||||||
|
{ label: 'Thumb', value: ImageType.Thumb }
|
||||||
|
];
|
||||||
|
|
||||||
|
interface ViewSettingsButtonProps {
|
||||||
|
viewType: LibraryTab;
|
||||||
|
libraryViewSettings: LibraryViewSettings;
|
||||||
|
setLibraryViewSettings: React.Dispatch<React.SetStateAction<LibraryViewSettings>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ViewSettingsButton: FC<ViewSettingsButtonProps> = ({
|
||||||
|
viewType,
|
||||||
|
libraryViewSettings,
|
||||||
|
setLibraryViewSettings
|
||||||
|
}) => {
|
||||||
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
|
const open = Boolean(anchorEl);
|
||||||
|
const id = open ? 'selectview-popover' : undefined;
|
||||||
|
|
||||||
|
const handleClick = useCallback((event: React.MouseEvent<HTMLElement>) => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleClose = useCallback(() => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const name = event.target.name;
|
||||||
|
|
||||||
|
setLibraryViewSettings((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
[name]: event.target.checked
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
[setLibraryViewSettings]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSelectChange = useCallback(
|
||||||
|
(event: SelectChangeEvent) => {
|
||||||
|
setLibraryViewSettings((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
ImageType: event.target.value as ImageType
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
[setLibraryViewSettings]
|
||||||
|
);
|
||||||
|
|
||||||
|
const getVisibleImageType = () => {
|
||||||
|
const visibleImageType: ImageType[] = [ImageType.Primary];
|
||||||
|
|
||||||
|
if (
|
||||||
|
viewType !== LibraryTab.Episodes
|
||||||
|
&& viewType !== LibraryTab.Artists
|
||||||
|
&& viewType !== LibraryTab.AlbumArtists
|
||||||
|
&& viewType !== LibraryTab.Albums
|
||||||
|
) {
|
||||||
|
visibleImageType.push(ImageType.Banner);
|
||||||
|
visibleImageType.push(ImageType.Disc);
|
||||||
|
visibleImageType.push(ImageType.Logo);
|
||||||
|
visibleImageType.push(ImageType.Thumb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return visibleImageType;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isViewSettingsEnabled = () => {
|
||||||
|
return libraryViewSettings.ViewMode !== ViewMode.ListView;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<IconButton
|
||||||
|
title={globalize.translate('ButtonSelectView')}
|
||||||
|
sx={{ ml: 2 }}
|
||||||
|
aria-describedby={id}
|
||||||
|
className='paper-icon-button-light btnShuffle autoSize'
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
<ViewComfyIcon />
|
||||||
|
</IconButton>
|
||||||
|
<Popover
|
||||||
|
id={id}
|
||||||
|
open={open}
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
onClose={handleClose}
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'bottom',
|
||||||
|
horizontal: 'center'
|
||||||
|
}}
|
||||||
|
transformOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'center'
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
'& .MuiFormControl-root': { m: 1, width: 220 }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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
|
||||||
|
.filter((imageType) => getVisibleImageType().includes(imageType.value))
|
||||||
|
.map((imageType) => (
|
||||||
|
<MenuItem
|
||||||
|
key={imageType.value}
|
||||||
|
value={imageType.value}
|
||||||
|
>
|
||||||
|
<Typography component='span'>
|
||||||
|
{globalize.translate(imageType.label)}
|
||||||
|
</Typography>
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
{isViewSettingsEnabled() && (
|
||||||
|
<>
|
||||||
|
<Divider />
|
||||||
|
<FormControl>
|
||||||
|
<FormGroup>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={libraryViewSettings.ShowTitle}
|
||||||
|
onChange={handleChange}
|
||||||
|
name='ShowTitle'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={globalize.translate('ShowTitle')}
|
||||||
|
/>
|
||||||
|
<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>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Popover>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ViewSettingsButton;
|
|
@ -298,6 +298,7 @@
|
||||||
"Genres": "Genres",
|
"Genres": "Genres",
|
||||||
"GetThePlugin": "Get the Plugin",
|
"GetThePlugin": "Get the Plugin",
|
||||||
"GoogleCastUnsupported": "Google Cast Unsupported",
|
"GoogleCastUnsupported": "Google Cast Unsupported",
|
||||||
|
"GridView": "Grid View",
|
||||||
"GroupBySeries": "Group by series",
|
"GroupBySeries": "Group by series",
|
||||||
"GroupVersions": "Group versions",
|
"GroupVersions": "Group versions",
|
||||||
"GuestStar": "Guest star",
|
"GuestStar": "Guest star",
|
||||||
|
@ -999,6 +1000,7 @@
|
||||||
"LeaveBlankToNotSetAPassword": "You can leave this field blank to set no password.",
|
"LeaveBlankToNotSetAPassword": "You can leave this field blank to set no password.",
|
||||||
"LibraryAccessHelp": "Select the libraries to share with this user. Administrators will be able to edit all folders using the metadata manager.",
|
"LibraryAccessHelp": "Select the libraries to share with this user. Administrators will be able to edit all folders using the metadata manager.",
|
||||||
"List": "List",
|
"List": "List",
|
||||||
|
"ListView": "List View",
|
||||||
"ListPaging": "{0}-{1} of {2}",
|
"ListPaging": "{0}-{1} of {2}",
|
||||||
"Live": "Live",
|
"Live": "Live",
|
||||||
"LiveBroadcasts": "Live broadcasts",
|
"LiveBroadcasts": "Live broadcasts",
|
||||||
|
|
|
@ -3,6 +3,7 @@ import type { VideoType } from '@jellyfin/sdk/lib/generated-client/models/video-
|
||||||
import type { SortOrder } from '@jellyfin/sdk/lib/generated-client/models/sort-order';
|
import type { SortOrder } from '@jellyfin/sdk/lib/generated-client/models/sort-order';
|
||||||
import type { SeriesStatus } from '@jellyfin/sdk/lib/generated-client/models/series-status';
|
import type { SeriesStatus } from '@jellyfin/sdk/lib/generated-client/models/series-status';
|
||||||
import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by';
|
import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by';
|
||||||
|
import { ImageType } from '@jellyfin/sdk/lib/generated-client';
|
||||||
|
|
||||||
export type ParentId = string | null | undefined;
|
export type ParentId = string | null | undefined;
|
||||||
|
|
||||||
|
@ -23,12 +24,18 @@ interface Filters {
|
||||||
Years?: number[];
|
Years?: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ViewMode {
|
||||||
|
GridView = 'grid',
|
||||||
|
ListView = 'list',
|
||||||
|
}
|
||||||
|
|
||||||
export interface LibraryViewSettings {
|
export interface LibraryViewSettings {
|
||||||
SortBy: ItemSortBy;
|
SortBy: ItemSortBy;
|
||||||
SortOrder: SortOrder;
|
SortOrder: SortOrder;
|
||||||
StartIndex: number;
|
StartIndex: number;
|
||||||
CardLayout: boolean;
|
CardLayout: boolean;
|
||||||
ImageType: string;
|
ImageType: ImageType;
|
||||||
|
ViewMode: ViewMode;
|
||||||
ShowTitle: boolean;
|
ShowTitle: boolean;
|
||||||
ShowYear?: boolean;
|
ShowYear?: boolean;
|
||||||
Filters?: Filters;
|
Filters?: Filters;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue