-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactored theme media playback settings menus based on github discus…
…sion #5958 The Theme Media and Backdrop settings has been moved to separate popover component in the experimental layout. For the classic layout the settings were moved to a separate "Background Playback" settings menu. Consolidated the widgets to select the Sort By/ Sort Order options for playing theme media to be one a single row with a \<select> (dropdown) widget providing the Sort by options followed by an \<IconButton> with arrow icons which indicates the Sort Order direction.
- Loading branch information
1 parent
87f1e20
commit a62fbbc
Showing
14 changed files
with
653 additions
and
133 deletions.
There are no files selected for viewing
80 changes: 80 additions & 0 deletions
80
src/apps/experimental/features/preferences/components/BackgroundPlaybackPreferences.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
.backgroundPlaybackDialog { | ||
display: inherit; | ||
margin-bottom: 0; | ||
align-items: center; | ||
position: relative; | ||
min-width: 300px; | ||
} | ||
|
||
.backgroundPlaybackPopover { | ||
display: inherit; | ||
margin-bottom: 0; | ||
align-items: center; | ||
position: relative; | ||
min-width: 300px; | ||
} | ||
|
||
.backgroundPlaybackStack { | ||
position: relative; | ||
min-width: 300px; | ||
} | ||
|
||
#background-playback-settings-header { | ||
margin-bottom: 1em; | ||
} | ||
|
||
#background-playback-settings-play-theme-media-label { | ||
margin-left: 9px; | ||
margin-top: 0.5em; | ||
position: relative; | ||
max-width: calc(100% - 24px); | ||
} | ||
|
||
#background-playback-sort-by-select-stack { | ||
margin-left: 9px; | ||
margin-bottom: 1.5em; | ||
} | ||
|
||
#background-playback-sort-by-select-container { | ||
display: inline-flex; | ||
margin-bottom: 0; | ||
align-items: center; | ||
flex-direction: column; | ||
position: relative; | ||
} | ||
|
||
|
||
#background-playback-sort-by-select-dropdown { | ||
min-width: 100px; | ||
} | ||
|
||
#background-playback-sort-order-icon-button { | ||
position: relative; | ||
display: inline-block; | ||
box-sizing: border-box; | ||
margin: 0; | ||
text-align: center; | ||
font-size: inherit; | ||
font-family: inherit; | ||
color: inherit; | ||
|
||
/* These are getting an outline in opera tv browsers, which run chrome 30 */ | ||
outline: none !important; | ||
outline-width: 0; | ||
user-select: none; | ||
cursor: pointer; | ||
z-index: 0; | ||
vertical-align: middle; | ||
border: 0; | ||
border-radius: 0.2em; | ||
font-weight: 600; | ||
|
||
/* Disable webkit tap highlighting */ | ||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); | ||
text-decoration: none; | ||
|
||
/* Not crazy about this but it normalizes heights between anchors and buttons */ | ||
line-height: 1.35; | ||
transform-origin: center; | ||
transition: 0.2s; | ||
} |
236 changes: 236 additions & 0 deletions
236
src/apps/experimental/features/preferences/components/BackgroundPlaybackPreferences.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
import Checkbox from "@mui/material/Checkbox"; | ||
import FormControl from "@mui/material/FormControl"; | ||
import FormControlLabel from "@mui/material/FormControlLabel"; | ||
import InputLabel from "@mui/material/InputLabel"; | ||
import MenuItem from "@mui/material/MenuItem"; | ||
import Select, { SelectChangeEvent } from "@mui/material/Select"; | ||
import Stack from "@mui/material/Stack"; | ||
import Typography from "@mui/material/Typography"; | ||
import React, { useCallback } from "react"; | ||
|
||
import globalize from "lib/globalize"; | ||
|
||
import type { DisplaySettingsValues } from "../types/displaySettingsValues"; | ||
|
||
import { ItemSortBy, SortOrder } from "@jellyfin/sdk/lib/generated-client"; | ||
import { Button, Dialog, IconButton, Popover, SxProps } from "@mui/material"; | ||
import { ArrowDownward, ArrowUpward } from "@mui/icons-material"; | ||
import classNames from "classnames"; | ||
import "./BackgroundPlaybackPreferences.scss"; | ||
|
||
interface BackgroundPlaybackPreferencesProps { | ||
onChange: (event: SelectChangeEvent | React.SyntheticEvent) => void; | ||
values: DisplaySettingsValues; | ||
} | ||
|
||
export function BackgroundPlaybackPreferences({ | ||
onChange, | ||
values, | ||
}: Readonly<BackgroundPlaybackPreferencesProps>) { | ||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); | ||
const openPopover = Boolean(anchorEl); | ||
|
||
const handleClick = useCallback((event: React.MouseEvent<HTMLElement>) => { | ||
setAnchorEl(event.currentTarget); | ||
}, []); | ||
|
||
const handleClosePopover = useCallback(() => { | ||
setAnchorEl(null); | ||
}, []); | ||
|
||
const [open, setOpen] = React.useState(false); | ||
const handleOpen = () => setOpen(true); | ||
const handleClose = () => setOpen(false); | ||
|
||
// Create wrapper on change callback to toggle the Sort Order state | ||
// when the Icon Button is pressed | ||
const handleSortOrderChange = ( | ||
e: SelectChangeEvent | React.SyntheticEvent | ||
) => { | ||
let target = e.currentTarget as HTMLInputElement; | ||
const fieldName = target.name as keyof DisplaySettingsValues; | ||
const fieldValue = target.value; | ||
|
||
// Toggle the ascending/descending variable on the event target when the Sort Icon Button is pressed | ||
if (Object.is(values.libraryThemeMediaSortOrder, values?.[fieldName])) { | ||
let newSortOrder = null; | ||
switch (fieldValue) { | ||
case SortOrder.Ascending: | ||
newSortOrder = SortOrder.Descending; | ||
break; | ||
case SortOrder.Descending: | ||
newSortOrder = SortOrder.Ascending; | ||
break; | ||
} | ||
|
||
target.value = newSortOrder ?? target.value; | ||
// For an Icon Button, the event target can be either the pressed icon <svg> | ||
// or the <button> element depending on where the click occurs. | ||
// Therefore replace `e.target` with `e.currentTarget` | ||
// which has the updated event value | ||
e.target = target; | ||
} | ||
|
||
// Delegate to the supplied onChange function for normal processing | ||
onChange(e); | ||
}; | ||
|
||
const popoverCssClass = classNames("backgroundPlaybackPopover"); | ||
const dialogCssClass = classNames("backgroundPlaybackDialog"); | ||
const stackCssClass = classNames("backgroundPlaybackStack"); | ||
const themeMediaCheckboxCssClass = classNames( | ||
"checkboxContainer", | ||
"checkboxContainer-withDescription" | ||
); | ||
|
||
const themeMediaCheckboxLabelStyleProps: SxProps = { | ||
marginLeft: 0, | ||
}; | ||
|
||
return ( | ||
<div id="background-playback-settings-preferences"> | ||
<Typography variant='h2' id="background-playback-settings-header">{globalize.translate('BackgroundPlayback')}</Typography> | ||
<Button onClick={handleClick} id="background-playback-settings-model-button"> | ||
{globalize.translate("BackgroundPlayback")} | ||
</Button> | ||
<Popover | ||
id="background-playback-settings-popover" | ||
aria-describedBy="background-playback-settings-popover-description" | ||
className={popoverCssClass} | ||
open={openPopover} | ||
anchorEl={anchorEl} | ||
onClose={handleClosePopover} | ||
anchorOrigin={{ | ||
vertical: 'bottom', | ||
horizontal: 'center' | ||
}} | ||
transformOrigin={{ | ||
vertical: 'bottom', | ||
horizontal: 'left' | ||
}} | ||
> | ||
{/*<Dialog | ||
open={open} | ||
onClose={handleClose} | ||
className={dialogCssClass} | ||
aria-describedby="background-playback-settings-model-description" | ||
>*/} | ||
<Stack spacing={1} className={stackCssClass}> | ||
<Typography | ||
variant="h3" | ||
id="background-playback-settings-play-theme-media-label" | ||
> | ||
{globalize.translate("ThemeMediaPlayInBackgroundHelp")} | ||
</Typography> | ||
<FormControl | ||
fullWidth | ||
className={themeMediaCheckboxCssClass} | ||
> | ||
<FormControlLabel | ||
aria-describedby="background-playback-settings-lib-backdrops-description" | ||
control={ | ||
<Checkbox | ||
checked={values.enableLibraryBackdrops} | ||
onChange={onChange} | ||
/> | ||
} | ||
label={globalize.translate("Backdrops")} | ||
name="enableLibraryBackdrops" | ||
sx={themeMediaCheckboxLabelStyleProps} | ||
/> | ||
<FormControlLabel | ||
aria-describedby="background-playback-settings-lib-theme-songs-description" | ||
control={ | ||
<Checkbox | ||
checked={values.enableLibraryThemeSongs} | ||
onChange={onChange} | ||
/> | ||
} | ||
label={globalize.translate("ThemeSongs")} | ||
name="enableLibraryThemeSongs" | ||
sx={themeMediaCheckboxLabelStyleProps} | ||
/> | ||
<FormControlLabel | ||
aria-describedby="background-playback-settings-lib-theme-videos-description" | ||
control={ | ||
<Checkbox | ||
checked={values.enableLibraryThemeVideos} | ||
onChange={onChange} | ||
/> | ||
} | ||
label={globalize.translate("ThemeVideos")} | ||
name="enableLibraryThemeVideos" | ||
sx={themeMediaCheckboxLabelStyleProps} | ||
/> | ||
</FormControl> | ||
|
||
<Stack | ||
direction={"row"} | ||
spacing={1} | ||
id="background-playback-sort-by-select-stack" | ||
> | ||
<FormControl id="background-playback-sort-by-select-container"> | ||
<InputLabel id="background-playback-sort-by-select-label"> | ||
{globalize.translate("ThemeMediaSortBy")} | ||
</InputLabel> | ||
<Select | ||
aria-describedby="background-playback-settings-lib-theme-media-sort-by-description" | ||
inputProps={{ | ||
name: "libraryThemeMediaSortBy", | ||
}} | ||
labelId="background-playback-sort-by-select-label" | ||
id="background-playback-sort-by-select-dropdown" | ||
onChange={onChange} | ||
value={values.libraryThemeMediaSortBy} | ||
> | ||
<MenuItem value={ItemSortBy.Random}> | ||
{globalize.translate("OptionRandom")} | ||
</MenuItem> | ||
<MenuItem value={ItemSortBy.SortName}> | ||
{globalize.translate("Name")} | ||
</MenuItem> | ||
<MenuItem value={ItemSortBy.Album}> | ||
{globalize.translate("Album")} | ||
</MenuItem> | ||
<MenuItem value={ItemSortBy.AlbumArtist}> | ||
{globalize.translate("AlbumArtist")} | ||
</MenuItem> | ||
<MenuItem value={ItemSortBy.Artist}> | ||
{globalize.translate("Artist")} | ||
</MenuItem> | ||
<MenuItem value={ItemSortBy.DateCreated}> | ||
{globalize.translate("OptionDateAdded")} | ||
</MenuItem> | ||
<MenuItem value={ItemSortBy.DatePlayed}> | ||
{globalize.translate("OptionDatePlayed")} | ||
</MenuItem> | ||
<MenuItem value={ItemSortBy.PlayCount}> | ||
{globalize.translate("OptionPlayCount")} | ||
</MenuItem> | ||
<MenuItem value={ItemSortBy.PremiereDate}> | ||
{globalize.translate("OptionReleaseDate")} | ||
</MenuItem> | ||
<MenuItem value={ItemSortBy.Runtime}> | ||
{globalize.translate("Runtime")} | ||
</MenuItem> | ||
</Select> | ||
</FormControl> | ||
<IconButton | ||
id="background-playback-sort-order-icon-button" | ||
aria-label="sort-order-by" | ||
onClick={handleSortOrderChange} | ||
name="libraryThemeMediaSortOrder" | ||
value={values.libraryThemeMediaSortOrder} | ||
> | ||
{values.libraryThemeMediaSortOrder == | ||
SortOrder.Ascending && <ArrowUpward />} | ||
{values.libraryThemeMediaSortOrder == | ||
SortOrder.Descending && <ArrowDownward />} | ||
</IconButton> | ||
</Stack> | ||
</Stack> | ||
{/*</Dialog>*/} | ||
</Popover> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.