Refactor DownloadMenuDialog to use useTranscodingOptions hook

This commit is contained in:
Deluan 2023-01-22 00:49:22 -05:00
parent c8293fcdd8
commit 65174d3fb2
9 changed files with 107 additions and 211 deletions

View file

@ -132,7 +132,7 @@ const AlbumActions = ({
{...shareDialog.props} {...shareDialog.props}
ids={[record.id]} ids={[record.id]}
resource={'album'} resource={'album'}
title={`Share album '${record.name}'`} name={record.name}
/> />
</TopToolbar> </TopToolbar>
) )

View file

@ -22,3 +22,7 @@ DraggableTypes.ALL.push(
export const MAX_SIDEBAR_PLAYLISTS = 100 export const MAX_SIDEBAR_PLAYLISTS = 100
export const DEFAULT_SHARE_BITRATE = 128 export const DEFAULT_SHARE_BITRATE = 128
export const BITRATE_CHOICES = [
32, 48, 64, 80, 96, 112, 128, 160, 192, 256, 320,
].map((b) => ({ id: b, name: b.toString() }))

View file

@ -1,45 +1,16 @@
import React, { useState } from 'react' import { SimpleForm, useTranslate } from 'react-admin'
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import { ReferenceManyField, useTranslate } from 'react-admin'
import { import {
Box,
Button, Button,
Dialog, Dialog,
DialogActions, DialogActions,
DialogContent, DialogContent,
DialogTitle, DialogTitle,
FormControlLabel,
FormGroup,
MenuItem,
Switch,
TextField,
} from '@material-ui/core' } from '@material-ui/core'
import subsonic from '../subsonic' import subsonic from '../subsonic'
import { closeDownloadMenu } from '../actions' import { closeDownloadMenu } from '../actions'
import { formatBytes } from '../utils' import { formatBytes } from '../utils'
import { useTranscodingOptions } from './useTranscodingOptions'
const DownloadTranscodings = (props) => {
const translate = useTranslate()
return (
<>
<TextField
fullWidth
id="downloadFormat"
select
label={translate('resources.transcoding.fields.targetFormat')}
onChange={(e) => props.onChange(e.target.value)}
value={props.value}
>
{Object.values(props.data).map((transcoding) => (
<MenuItem key={transcoding.id} value={transcoding.targetFormat}>
{transcoding.name}
</MenuItem>
))}
</TextField>
</>
)
}
const DownloadMenuDialog = () => { const DownloadMenuDialog = () => {
const { open, record, recordType } = useSelector( const { open, record, recordType } = useSelector(
@ -48,9 +19,8 @@ const DownloadMenuDialog = () => {
const dispatch = useDispatch() const dispatch = useDispatch()
const translate = useTranslate() const translate = useTranslate()
const [originalFormat, setUseOriginalFormat] = useState(true) const { TranscodingOptionsInput, format, maxBitRate, originalFormat } =
const [targetFormat, setTargetFormat] = useState('') useTranscodingOptions()
const [targetRate, setTargetRate] = useState(0)
const handleClose = (e) => { const handleClose = (e) => {
dispatch(closeDownloadMenu()) dispatch(closeDownloadMenu())
@ -59,114 +29,51 @@ const DownloadMenuDialog = () => {
const handleDownload = (e) => { const handleDownload = (e) => {
if (record) { if (record) {
subsonic.download( if (originalFormat) {
record.id, subsonic.download(record.id, 'raw')
originalFormat ? 'raw' : targetFormat, } else {
targetRate subsonic.download(record.id, format, maxBitRate?.toString())
) }
dispatch(closeDownloadMenu()) dispatch(closeDownloadMenu())
} }
e.stopPropagation() e.stopPropagation()
} }
const handleOriginal = (e) => {
const original = e.target.checked
setUseOriginalFormat(original)
if (original) {
setTargetFormat('')
setTargetRate(0)
}
}
const type = recordType
? translate(`resources.${recordType}.name`, {
smart_count: 1,
}).toLocaleLowerCase()
: ''
return ( return (
<> <Dialog
<Dialog open={open}
open={open} onClose={handleClose}
onClose={handleClose} onBackdropClick={handleClose}
onBackdropClick={handleClose} aria-labelledby="download-dialog"
aria-labelledby="download-dialog" fullWidth={true}
fullWidth={true} maxWidth={'sm'}
maxWidth={'sm'} >
> <DialogTitle id="download-dialog">
<DialogTitle id="download-dialog"> {translate('message.downloadDialogTitle', {
{record && resource: translate(`resources.${recordType}.name`, {
`${translate('resources.album.actions.download')} ${type} ${ smart_count: 1,
record.name || record.title }).toLocaleLowerCase(),
} (${formatBytes(record.size)})`} name: record?.name || record?.title,
</DialogTitle> size: formatBytes(record?.size),
<DialogContent> })}
<Box </DialogTitle>
component="form" <DialogContent>
sx={{ <SimpleForm toolbar={null} variant={'outlined'}>
'& .MuiTextField-root': { m: 1, width: '25ch' }, <TranscodingOptionsInput
}} fullWidth
> label={translate('message.originalFormat')}
<div> />
<FormGroup> </SimpleForm>
<FormControlLabel </DialogContent>
control={<Switch checked={originalFormat} />} <DialogActions>
label={translate('message.originalFormat')} <Button onClick={handleDownload} color="primary">
onChange={handleOriginal} {translate('ra.action.download')}
/> </Button>
</FormGroup> <Button onClick={handleClose} color="secondary">
{!originalFormat && ( {translate('ra.action.close')}
<> </Button>
<ReferenceManyField </DialogActions>
fullWidth </Dialog>
source=""
target="name"
reference="transcoding"
sort={{ field: 'name', order: 'ASC' }}
>
<DownloadTranscodings
onChange={setTargetFormat}
value={targetFormat}
/>
</ReferenceManyField>
<TextField
fullWidth
id="downloadRate"
select
label={translate('resources.player.fields.maxBitRate')}
value={targetRate}
onChange={(e) => setTargetRate(e.target.value)}
>
<MenuItem value={0}>-</MenuItem>
{[32, 48, 64, 80, 96, 112, 128, 160, 192, 256, 320].map(
(bits) => (
<MenuItem key={bits} value={bits}>
{bits}
</MenuItem>
)
)}
</TextField>
</>
)}
</div>
</Box>
</DialogContent>
<DialogActions>
<Button
onClick={handleDownload}
color="primary"
disabled={!originalFormat && !targetFormat}
>
{translate('resources.album.actions.download')}
</Button>
<Button onClick={handleClose} color="secondary">
{translate('ra.action.close')}
</Button>
</DialogActions>
</Dialog>
</>
) )
} }

View file

@ -5,13 +5,20 @@ import {
DialogContent, DialogContent,
DialogTitle, DialogTitle,
} from '@material-ui/core' } from '@material-ui/core'
import { SimpleForm, TextInput, useCreate, useNotify } from 'react-admin' import {
SimpleForm,
TextInput,
useCreate,
useNotify,
useTranslate,
} from 'react-admin'
import { useState } from 'react' import { useState } from 'react'
import { shareUrl } from '../utils' import { shareUrl } from '../utils'
import { useTranscodingOptions } from './useTranscodingOptions' import { useTranscodingOptions } from './useTranscodingOptions'
export const ShareDialog = ({ open, onClose, ids, resource, title }) => { export const ShareDialog = ({ open, onClose, ids, resource, name }) => {
const notify = useNotify() const notify = useNotify()
const translate = useTranslate()
const [description, setDescription] = useState('') const [description, setDescription] = useState('')
const { TranscodingOptionsInput, format, maxBitRate, originalFormat } = const { TranscodingOptionsInput, format, maxBitRate, originalFormat } =
useTranscodingOptions() useTranscodingOptions()
@ -57,9 +64,16 @@ export const ShareDialog = ({ open, onClose, ids, resource, title }) => {
onBackdropClick={onClose} onBackdropClick={onClose}
aria-labelledby="share-dialog" aria-labelledby="share-dialog"
fullWidth={true} fullWidth={true}
maxWidth={'xs'} maxWidth={'sm'}
> >
<DialogTitle id="share-dialog">{title}</DialogTitle> <DialogTitle id="share-dialog">
{translate('message.shareDialogTitle', {
resource: translate(`resources.${resource}.name`, {
smart_count: ids?.length,
}).toLocaleLowerCase(),
name,
})}
</DialogTitle>
<DialogContent> <DialogContent>
<SimpleForm toolbar={null} variant={'outlined'}> <SimpleForm toolbar={null} variant={'outlined'}>
<TextInput <TextInput
@ -69,15 +83,18 @@ export const ShareDialog = ({ open, onClose, ids, resource, title }) => {
setDescription(event.target.value) setDescription(event.target.value)
}} }}
/> />
<TranscodingOptionsInput /> <TranscodingOptionsInput
fullWidth
label={translate('message.shareOriginalFormat')}
/>
</SimpleForm> </SimpleForm>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={createShare} color="primary"> <Button onClick={createShare} color="primary">
Share {translate('ra.action.share')}
</Button> </Button>
<Button onClick={onClose} color="primary"> <Button onClick={onClose} color="primary">
Cancel {translate('ra.action.close')}
</Button> </Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>

View file

@ -1,9 +1,15 @@
import React, { useCallback, useMemo, useState } from 'react' import React, { useCallback, useMemo, useState } from 'react'
import config from '../config' import config from '../config'
import { DEFAULT_SHARE_BITRATE } from '../consts' import { BITRATE_CHOICES, DEFAULT_SHARE_BITRATE } from '../consts'
import { BooleanInput, SelectInput, useGetList } from 'react-admin' import {
BooleanInput,
SelectInput,
useGetList,
useTranslate,
} from 'react-admin'
export const useTranscodingOptions = () => { export const useTranscodingOptions = () => {
const translate = useTranslate()
const [format, setFormat] = useState(config.defaultDownsamplingFormat) const [format, setFormat] = useState(config.defaultDownsamplingFormat)
const [maxBitRate, setMaxBitRate] = useState(DEFAULT_SHARE_BITRATE) const [maxBitRate, setMaxBitRate] = useState(DEFAULT_SHARE_BITRATE)
const [originalFormat, setUseOriginalFormat] = useState(true) const [originalFormat, setUseOriginalFormat] = useState(true)
@ -22,7 +28,7 @@ export const useTranscodingOptions = () => {
loadingFormats loadingFormats
? [] ? []
: Object.values(formats).map((f) => { : Object.values(formats).map((f) => {
return { id: f.targetFormat, name: f.targetFormat } return { id: f.targetFormat, name: f.name }
}), }),
[formats, loadingFormats] [formats, loadingFormats]
) )
@ -39,14 +45,15 @@ export const useTranscodingOptions = () => {
) )
const TranscodingOptionsInput = useMemo(() => { const TranscodingOptionsInput = useMemo(() => {
return ({ basePath, ...props }) => { return ({ label, basePath, ...props }) => {
return ( return (
<> <>
<BooleanInput <BooleanInput
{...props} {...props}
source="original" source="original"
defaultValue={originalFormat} defaultValue={originalFormat}
label={'Share in original format'} label={label}
fullWidth
onChange={handleOriginal} onChange={handleOriginal}
/> />
{!originalFormat && ( {!originalFormat && (
@ -55,6 +62,7 @@ export const useTranscodingOptions = () => {
{...props} {...props}
source="format" source="format"
defaultValue={format} defaultValue={format}
label={translate('resources.player.fields.transcodingId')}
choices={formatOptions} choices={formatOptions}
onChange={(event) => { onChange={(event) => {
setFormat(event.target.value) setFormat(event.target.value)
@ -63,20 +71,9 @@ export const useTranscodingOptions = () => {
<SelectInput <SelectInput
{...props} {...props}
source="maxBitRate" source="maxBitRate"
label={translate('resources.player.fields.maxBitRate')}
defaultValue={maxBitRate} defaultValue={maxBitRate}
choices={[ choices={BITRATE_CHOICES}
{ id: 32, name: '32' },
{ id: 48, name: '48' },
{ id: 64, name: '64' },
{ id: 80, name: '80' },
{ id: 96, name: '96' },
{ id: 112, name: '112' },
{ id: 128, name: '128' },
{ id: 160, name: '160' },
{ id: 192, name: '192' },
{ id: 256, name: '256' },
{ id: 320, name: '320' },
]}
onChange={(event) => { onChange={(event) => {
setMaxBitRate(event.target.value) setMaxBitRate(event.target.value)
}} }}
@ -86,7 +83,14 @@ export const useTranscodingOptions = () => {
</> </>
) )
} }
}, [handleOriginal, formatOptions, format, maxBitRate, originalFormat]) }, [
handleOriginal,
formatOptions,
format,
maxBitRate,
originalFormat,
translate,
])
return { return {
TranscodingOptionsInput, TranscodingOptionsInput,

View file

@ -257,7 +257,9 @@
"open_menu": "Open menu", "open_menu": "Open menu",
"close_menu": "Close menu", "close_menu": "Close menu",
"unselect": "Unselect", "unselect": "Unselect",
"skip": "Skip" "skip": "Skip",
"share": "Share",
"download": "Download"
}, },
"boolean": { "boolean": {
"true": "Yes", "true": "Yes",
@ -367,6 +369,9 @@
"musicbrainz": "Open in MusicBrainz" "musicbrainz": "Open in MusicBrainz"
}, },
"lastfmLink": "Read More...", "lastfmLink": "Read More...",
"shareOriginalFormat": "Share in original format",
"shareDialogTitle": "Share %{resource} '%{name}'",
"downloadDialogTitle": "Download %{resource} '%{name}' (%{size})",
"originalFormat": "Download in original format" "originalFormat": "Download in original format"
}, },
"menu": { "menu": {

View file

@ -1,4 +1,3 @@
import React from 'react'
import { import {
TextInput, TextInput,
BooleanInput, BooleanInput,
@ -12,6 +11,7 @@ import {
} from 'react-admin' } from 'react-admin'
import { Title } from '../common' import { Title } from '../common'
import config from '../config' import config from '../config'
import { BITRATE_CHOICES } from '../consts'
const PlayerTitle = ({ record }) => { const PlayerTitle = ({ record }) => {
const translate = useTranslate() const translate = useTranslate()
@ -30,23 +30,7 @@ const PlayerEdit = (props) => (
> >
<SelectInput source="name" resettable /> <SelectInput source="name" resettable />
</ReferenceInput> </ReferenceInput>
<SelectInput <SelectInput source="maxBitRate" resettable choices={BITRATE_CHOICES} />
source="maxBitRate"
choices={[
{ id: 32, name: '32' },
{ id: 48, name: '48' },
{ id: 64, name: '64' },
{ id: 80, name: '80' },
{ id: 96, name: '96' },
{ id: 112, name: '112' },
{ id: 128, name: '128' },
{ id: 160, name: '160' },
{ id: 192, name: '192' },
{ id: 256, name: '256' },
{ id: 320, name: '320' },
{ id: 0, name: '-' },
]}
/>
<BooleanInput source="reportRealPath" fullWidth /> <BooleanInput source="reportRealPath" fullWidth />
{(config.lastFMEnabled || config.listenBrainzEnabled) && ( {(config.lastFMEnabled || config.listenBrainzEnabled) && (
<BooleanInput source="scrobbleEnabled" fullWidth /> <BooleanInput source="scrobbleEnabled" fullWidth />

View file

@ -8,6 +8,7 @@ import {
useTranslate, useTranslate,
} from 'react-admin' } from 'react-admin'
import { Title } from '../common' import { Title } from '../common'
import { BITRATE_CHOICES } from '../consts'
const TranscodingTitle = () => { const TranscodingTitle = () => {
const translate = useTranslate() const translate = useTranslate()
@ -27,19 +28,7 @@ const TranscodingCreate = (props) => (
<TextInput source="targetFormat" validate={[required()]} /> <TextInput source="targetFormat" validate={[required()]} />
<SelectInput <SelectInput
source="defaultBitRate" source="defaultBitRate"
choices={[ choices={BITRATE_CHOICES}
{ id: 32, name: '32' },
{ id: 48, name: '48' },
{ id: 64, name: '64' },
{ id: 80, name: '80' },
{ id: 96, name: '96' },
{ id: 112, name: '112' },
{ id: 128, name: '128' },
{ id: 160, name: '160' },
{ id: 192, name: '192' },
{ id: 256, name: '256' },
{ id: 320, name: '320' },
]}
defaultValue={192} defaultValue={192}
/> />
<TextInput <TextInput

View file

@ -9,6 +9,7 @@ import {
} from 'react-admin' } from 'react-admin'
import { Title } from '../common' import { Title } from '../common'
import { TranscodingNote } from './TranscodingNote' import { TranscodingNote } from './TranscodingNote'
import { BITRATE_CHOICES } from '../consts'
const TranscodingTitle = ({ record }) => { const TranscodingTitle = ({ record }) => {
const translate = useTranslate() const translate = useTranslate()
@ -27,22 +28,7 @@ const TranscodingEdit = (props) => {
<SimpleForm variant={'outlined'}> <SimpleForm variant={'outlined'}>
<TextInput source="name" validate={[required()]} /> <TextInput source="name" validate={[required()]} />
<TextInput source="targetFormat" validate={[required()]} /> <TextInput source="targetFormat" validate={[required()]} />
<SelectInput <SelectInput source="defaultBitRate" choices={BITRATE_CHOICES} />
source="defaultBitRate"
choices={[
{ id: 32, name: '32' },
{ id: 48, name: '48' },
{ id: 64, name: '64' },
{ id: 80, name: '80' },
{ id: 96, name: '96' },
{ id: 112, name: '112' },
{ id: 128, name: '128' },
{ id: 160, name: '160' },
{ id: 192, name: '192' },
{ id: 256, name: '256' },
{ id: 320, name: '320' },
]}
/>
<TextInput source="command" fullWidth validate={[required()]} /> <TextInput source="command" fullWidth validate={[required()]} />
</SimpleForm> </SimpleForm>
</Edit> </Edit>