diff --git a/src/apps/experimental/components/library/GridListViewButton.tsx b/src/apps/experimental/components/library/GridListViewButton.tsx new file mode 100644 index 0000000000..26588b1883 --- /dev/null +++ b/src/apps/experimental/components/library/GridListViewButton.tsx @@ -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>; +} + +const GridListViewButton: FC = ({ + 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 ( + + {isGridView ? ( + + ) : ( + + + + )} + + + + + + ); +}; + +export default GridListViewButton; diff --git a/src/apps/experimental/components/library/ViewSettingsButton.tsx b/src/apps/experimental/components/library/ViewSettingsButton.tsx new file mode 100644 index 0000000000..cec5090acc --- /dev/null +++ b/src/apps/experimental/components/library/ViewSettingsButton.tsx @@ -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>; +} + +const ViewSettingsButton: FC = ({ + viewType, + libraryViewSettings, + setLibraryViewSettings +}) => { + const [anchorEl, setAnchorEl] = React.useState(null); + const open = Boolean(anchorEl); + const id = open ? 'selectview-popover' : undefined; + + const handleClick = useCallback((event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }, []); + + const handleClose = useCallback(() => { + setAnchorEl(null); + }, []); + + const handleChange = useCallback( + (event: React.ChangeEvent) => { + 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 ( + + + + + + + + + {globalize.translate('LabelImageType')} + + + + + {isViewSettingsEnabled() && ( + <> + + + + + } + label={globalize.translate('ShowTitle')} + /> + + } + label={globalize.translate('ShowYear')} + /> + + } + label={globalize.translate( + 'EnableCardLayout' + )} + /> + + + + )} + + + ); +}; + +export default ViewSettingsButton; diff --git a/src/types/library.ts b/src/types/library.ts index 313a5ebe3e..2994dd3ca5 100644 --- a/src/types/library.ts +++ b/src/types/library.ts @@ -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 { SeriesStatus } from '@jellyfin/sdk/lib/generated-client/models/series-status'; 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; @@ -23,12 +24,18 @@ interface Filters { Years?: number[]; } +export enum ViewMode { + GridView = 'grid', + ListView = 'list', +} + export interface LibraryViewSettings { SortBy: ItemSortBy; SortOrder: SortOrder; StartIndex: number; CardLayout: boolean; - ImageType: string; + ImageType: ImageType; + ViewMode: ViewMode; ShowTitle: boolean; ShowYear?: boolean; Filters?: Filters;