Use redux for ShareDialog

This commit is contained in:
Deluan 2023-01-24 13:04:00 -05:00
parent 17d9573f4d
commit 051e9c556d
9 changed files with 113 additions and 56 deletions

View File

@ -29,6 +29,7 @@ import {
settingsReducer, settingsReducer,
replayGainReducer, replayGainReducer,
downloadMenuDialogReducer, downloadMenuDialogReducer,
shareDialogReducer,
} from './reducers' } from './reducers'
import createAdminStore from './store/createAdminStore' import createAdminStore from './store/createAdminStore'
import { i18nProvider } from './i18n' import { i18nProvider } from './i18n'
@ -60,6 +61,7 @@ const adminStore = createAdminStore({
downloadMenuDialog: downloadMenuDialogReducer, downloadMenuDialog: downloadMenuDialogReducer,
expandInfoDialog: expandInfoDialogReducer, expandInfoDialog: expandInfoDialogReducer,
listenBrainzTokenDialog: listenBrainzTokenDialogReducer, listenBrainzTokenDialog: listenBrainzTokenDialogReducer,
shareDialog: shareDialogReducer,
activity: activityReducer, activity: activityReducer,
settings: settingsReducer, settings: settingsReducer,
replayGain: replayGainReducer, replayGain: replayGainReducer,

View File

@ -12,6 +12,19 @@ export const DOWNLOAD_MENU_ALBUM = 'album'
export const DOWNLOAD_MENU_ARTIST = 'artist' export const DOWNLOAD_MENU_ARTIST = 'artist'
export const DOWNLOAD_MENU_PLAY = 'playlist' export const DOWNLOAD_MENU_PLAY = 'playlist'
export const DOWNLOAD_MENU_SONG = 'song' export const DOWNLOAD_MENU_SONG = 'song'
export const SHARE_MENU_OPEN = 'SHARE_MENU_OPEN'
export const SHARE_MENU_CLOSE = 'SHARE_MENU_CLOSE'
export const openShareMenu = (ids, resource, name) => ({
type: SHARE_MENU_OPEN,
ids,
resource,
name,
})
export const closeShareMenu = () => ({
type: SHARE_MENU_CLOSE,
})
export const openAddToPlaylist = ({ selectedIds, onSuccess }) => ({ export const openAddToPlaylist = ({ selectedIds, onSuccess }) => ({
type: ADD_TO_PLAYLIST_OPEN, type: ADD_TO_PLAYLIST_OPEN,

View File

@ -7,11 +7,13 @@ import {
TopToolbar, TopToolbar,
useTranslate, useTranslate,
} from 'react-admin' } from 'react-admin'
import { useMediaQuery, makeStyles } from '@material-ui/core'
import PlayArrowIcon from '@material-ui/icons/PlayArrow' import PlayArrowIcon from '@material-ui/icons/PlayArrow'
import ShuffleIcon from '@material-ui/icons/Shuffle' import ShuffleIcon from '@material-ui/icons/Shuffle'
import CloudDownloadOutlinedIcon from '@material-ui/icons/CloudDownloadOutlined' import CloudDownloadOutlinedIcon from '@material-ui/icons/CloudDownloadOutlined'
import { RiPlayListAddFill, RiPlayList2Fill } from 'react-icons/ri' import { RiPlayListAddFill, RiPlayList2Fill } from 'react-icons/ri'
import PlaylistAddIcon from '@material-ui/icons/PlaylistAdd' import PlaylistAddIcon from '@material-ui/icons/PlaylistAdd'
import ShareIcon from '@material-ui/icons/Share'
import { import {
playNext, playNext,
addTracks, addTracks,
@ -20,14 +22,11 @@ import {
openAddToPlaylist, openAddToPlaylist,
openDownloadMenu, openDownloadMenu,
DOWNLOAD_MENU_ALBUM, DOWNLOAD_MENU_ALBUM,
openShareMenu,
} from '../actions' } from '../actions'
import { formatBytes } from '../utils' import { formatBytes } from '../utils'
import { useMediaQuery, makeStyles } from '@material-ui/core'
import config from '../config' import config from '../config'
import { ToggleFieldsMenu } from '../common' import { ToggleFieldsMenu } from '../common'
import { useDialog } from '../dialogs/useDialog'
import { ShareDialog } from '../dialogs/ShareDialog'
import ShareIcon from '@material-ui/icons/Share'
const useStyles = makeStyles({ const useStyles = makeStyles({
toolbar: { display: 'flex', justifyContent: 'space-between', width: '100%' }, toolbar: { display: 'flex', justifyContent: 'space-between', width: '100%' },
@ -38,6 +37,7 @@ const AlbumActions = ({
ids, ids,
data, data,
record, record,
resource,
permanentFilter, permanentFilter,
...rest ...rest
}) => { }) => {
@ -46,7 +46,6 @@ const AlbumActions = ({
const classes = useStyles() const classes = useStyles()
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md')) const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md'))
const isNotSmall = useMediaQuery((theme) => theme.breakpoints.up('sm')) const isNotSmall = useMediaQuery((theme) => theme.breakpoints.up('sm'))
const shareDialog = useDialog()
const handlePlay = React.useCallback(() => { const handlePlay = React.useCallback(() => {
dispatch(playTracks(data, ids)) dispatch(playTracks(data, ids))
@ -68,6 +67,10 @@ const AlbumActions = ({
dispatch(openAddToPlaylist({ selectedIds: ids })) dispatch(openAddToPlaylist({ selectedIds: ids }))
}, [dispatch, ids]) }, [dispatch, ids])
const handleShare = React.useCallback(() => {
dispatch(openShareMenu([record.id], resource, record.name))
}, [dispatch, record, resource])
const handleDownload = React.useCallback(() => { const handleDownload = React.useCallback(() => {
dispatch(openDownloadMenu(record, DOWNLOAD_MENU_ALBUM)) dispatch(openDownloadMenu(record, DOWNLOAD_MENU_ALBUM))
}, [dispatch, record]) }, [dispatch, record])
@ -107,10 +110,7 @@ const AlbumActions = ({
<PlaylistAddIcon /> <PlaylistAddIcon />
</Button> </Button>
{config.devEnableShare && ( {config.devEnableShare && (
<Button <Button onClick={handleShare} label={translate('ra.action.share')}>
onClick={shareDialog.openDialog}
label={translate('ra.action.share')}
>
<ShareIcon /> <ShareIcon />
</Button> </Button>
)} )}
@ -128,12 +128,6 @@ const AlbumActions = ({
</div> </div>
<div>{isNotSmall && <ToggleFieldsMenu resource="albumSong" />}</div> <div>{isNotSmall && <ToggleFieldsMenu resource="albumSong" />}</div>
</div> </div>
<ShareDialog
{...shareDialog.props}
ids={[record.id]}
resource={'album'}
name={record.name}
/>
</TopToolbar> </TopToolbar>
) )
} }

View File

@ -1,11 +1,13 @@
import { AddToPlaylistDialog } from './AddToPlaylistDialog' import { AddToPlaylistDialog } from './AddToPlaylistDialog'
import DownloadMenuDialog from './DownloadMenuDialog' import DownloadMenuDialog from './DownloadMenuDialog'
import { HelpDialog } from './HelpDialog' import { HelpDialog } from './HelpDialog'
import { ShareDialog } from './ShareDialog'
export const Dialogs = (props) => ( export const Dialogs = (props) => (
<> <>
<AddToPlaylistDialog /> <AddToPlaylistDialog />
<DownloadMenuDialog /> <DownloadMenuDialog />
<HelpDialog /> <HelpDialog />
<ShareDialog />
</> </>
) )

View File

@ -67,12 +67,12 @@ const DownloadMenuDialog = () => {
</SimpleForm> </SimpleForm>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={handleDownload} color="primary">
{translate('ra.action.download')}
</Button>
<Button onClick={handleClose} color="secondary"> <Button onClick={handleClose} color="secondary">
{translate('ra.action.close')} {translate('ra.action.close')}
</Button> </Button>
<Button onClick={handleDownload} color="primary">
{translate('ra.action.download')}
</Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
) )

View File

@ -15,8 +15,14 @@ import {
import { useState } from 'react' import { useState } from 'react'
import { shareUrl } from '../utils' import { shareUrl } from '../utils'
import { useTranscodingOptions } from './useTranscodingOptions' import { useTranscodingOptions } from './useTranscodingOptions'
import { useDispatch, useSelector } from 'react-redux'
import { closeShareMenu } from '../actions'
export const ShareDialog = ({ open, onClose, ids, resource, name }) => { export const ShareDialog = () => {
const { open, ids, resource, name } = useSelector(
(state) => state.shareDialog
)
const dispatch = useDispatch()
const notify = useNotify() const notify = useNotify()
const translate = useTranslate() const translate = useTranslate()
const [description, setDescription] = useState('') const [description, setDescription] = useState('')
@ -34,15 +40,10 @@ export const ShareDialog = ({ open, onClose, ids, resource, name }) => {
{ {
onSuccess: (res) => { onSuccess: (res) => {
const url = shareUrl(res?.data?.id) const url = shareUrl(res?.data?.id)
onClose()
navigator.clipboard navigator.clipboard
.writeText(url) .writeText(url)
.then(() => { .then(() => {
notify(translate('message.shareSuccess', { url }), { notify('message.shareSuccess', 'info', { url }, false, 0)
type: 'info',
multiLine: true,
duration: 0,
})
}) })
.catch((err) => { .catch((err) => {
notify( notify(
@ -56,26 +57,40 @@ export const ShareDialog = ({ open, onClose, ids, resource, name }) => {
}) })
}, },
onFailure: (error) => onFailure: (error) =>
notify(`Error sharing media: ${error.message}`, { type: 'warning' }), notify(translate('ra.page.error') + ': ' + error.message, {
type: 'warning',
}),
} }
) )
const handleShare = (e) => {
createShare()
dispatch(closeShareMenu())
e.stopPropagation()
}
const handleClose = (e) => {
dispatch(closeShareMenu())
e.stopPropagation()
}
return ( return (
<Dialog <Dialog
open={open} open={open}
onClose={onClose} onClose={handleClose}
onBackdropClick={onClose} onBackdropClick={handleClose}
aria-labelledby="share-dialog" aria-labelledby="share-dialog"
fullWidth={true} fullWidth={true}
maxWidth={'sm'} maxWidth={'sm'}
> >
<DialogTitle id="share-dialog"> <DialogTitle id="share-dialog">
{translate('message.shareDialogTitle', { {resource &&
resource: translate(`resources.${resource}.name`, { translate('message.shareDialogTitle', {
smart_count: ids?.length, resource: translate(`resources.${resource}.name`, {
}).toLocaleLowerCase(), smart_count: ids?.length,
name, }).toLocaleLowerCase(),
})} name,
})}
</DialogTitle> </DialogTitle>
<DialogContent> <DialogContent>
<SimpleForm toolbar={null} variant={'outlined'}> <SimpleForm toolbar={null} variant={'outlined'}>
@ -93,12 +108,12 @@ export const ShareDialog = ({ open, onClose, ids, resource, name }) => {
</SimpleForm> </SimpleForm>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={createShare} color="primary"> <Button onClick={handleClose} color="primary">
{translate('ra.action.share')}
</Button>
<Button onClick={onClose} color="primary">
{translate('ra.action.close')} {translate('ra.action.close')}
</Button> </Button>
<Button onClick={handleShare} color="primary">
{translate('ra.action.share')}
</Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
) )

View File

@ -8,11 +8,13 @@ import {
useDataProvider, useDataProvider,
useNotify, useNotify,
} from 'react-admin' } from 'react-admin'
import { useMediaQuery, makeStyles } from '@material-ui/core'
import PlayArrowIcon from '@material-ui/icons/PlayArrow' import PlayArrowIcon from '@material-ui/icons/PlayArrow'
import ShuffleIcon from '@material-ui/icons/Shuffle' import ShuffleIcon from '@material-ui/icons/Shuffle'
import CloudDownloadOutlinedIcon from '@material-ui/icons/CloudDownloadOutlined' import CloudDownloadOutlinedIcon from '@material-ui/icons/CloudDownloadOutlined'
import { RiPlayListAddFill, RiPlayList2Fill } from 'react-icons/ri' import { RiPlayListAddFill, RiPlayList2Fill } from 'react-icons/ri'
import QueueMusicIcon from '@material-ui/icons/QueueMusic' import QueueMusicIcon from '@material-ui/icons/QueueMusic'
import ShareIcon from '@material-ui/icons/Share'
import { httpClient } from '../dataProvider' import { httpClient } from '../dataProvider'
import { import {
playNext, playNext,
@ -21,22 +23,26 @@ import {
shuffleTracks, shuffleTracks,
openDownloadMenu, openDownloadMenu,
DOWNLOAD_MENU_PLAY, DOWNLOAD_MENU_PLAY,
openShareMenu,
} from '../actions' } from '../actions'
import { M3U_MIME_TYPE, REST_URL } from '../consts' import { M3U_MIME_TYPE, REST_URL } from '../consts'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { formatBytes } from '../utils' import { formatBytes } from '../utils'
import { useMediaQuery, makeStyles } from '@material-ui/core'
import config from '../config' import config from '../config'
import { ToggleFieldsMenu } from '../common' import { ToggleFieldsMenu } from '../common'
import { ShareDialog } from '../dialogs/ShareDialog'
import { useDialog } from '../dialogs/useDialog'
import ShareIcon from '@material-ui/icons/Share'
const useStyles = makeStyles({ const useStyles = makeStyles({
toolbar: { display: 'flex', justifyContent: 'space-between', width: '100%' }, toolbar: { display: 'flex', justifyContent: 'space-between', width: '100%' },
}) })
const PlaylistActions = ({ className, ids, data, record, ...rest }) => { const PlaylistActions = ({
className,
ids,
data,
record,
resource,
...rest
}) => {
const dispatch = useDispatch() const dispatch = useDispatch()
const translate = useTranslate() const translate = useTranslate()
const classes = useStyles() const classes = useStyles()
@ -44,7 +50,6 @@ const PlaylistActions = ({ className, ids, data, record, ...rest }) => {
const notify = useNotify() const notify = useNotify()
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md')) const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md'))
const isNotSmall = useMediaQuery((theme) => theme.breakpoints.up('sm')) const isNotSmall = useMediaQuery((theme) => theme.breakpoints.up('sm'))
const shareDialog = useDialog()
const getAllSongsAndDispatch = React.useCallback( const getAllSongsAndDispatch = React.useCallback(
(action) => { (action) => {
@ -88,6 +93,10 @@ const PlaylistActions = ({ className, ids, data, record, ...rest }) => {
getAllSongsAndDispatch(shuffleTracks) getAllSongsAndDispatch(shuffleTracks)
}, [getAllSongsAndDispatch]) }, [getAllSongsAndDispatch])
const handleShare = React.useCallback(() => {
dispatch(openShareMenu([record.id], resource, record.name))
}, [dispatch, record, resource])
const handleDownload = React.useCallback(() => { const handleDownload = React.useCallback(() => {
dispatch(openDownloadMenu(record, DOWNLOAD_MENU_PLAY)) dispatch(openDownloadMenu(record, DOWNLOAD_MENU_PLAY))
}, [dispatch, record]) }, [dispatch, record])
@ -138,10 +147,7 @@ const PlaylistActions = ({ className, ids, data, record, ...rest }) => {
<RiPlayListAddFill /> <RiPlayListAddFill />
</Button> </Button>
{config.devEnableShare && ( {config.devEnableShare && (
<Button <Button onClick={handleShare} label={translate('ra.action.share')}>
onClick={shareDialog.openDialog}
label={translate('ra.action.share')}
>
<ShareIcon /> <ShareIcon />
</Button> </Button>
)} )}
@ -165,12 +171,6 @@ const PlaylistActions = ({ className, ids, data, record, ...rest }) => {
</div> </div>
<div>{isNotSmall && <ToggleFieldsMenu resource="playlistTrack" />}</div> <div>{isNotSmall && <ToggleFieldsMenu resource="playlistTrack" />}</div>
</div> </div>
<ShareDialog
{...shareDialog.props}
ids={[record.id]}
resource={'playlist'}
name={record.name}
/>
</TopToolbar> </TopToolbar>
) )
} }

View File

@ -13,8 +13,39 @@ import {
EXTENDED_INFO_CLOSE, EXTENDED_INFO_CLOSE,
LISTENBRAINZ_TOKEN_OPEN, LISTENBRAINZ_TOKEN_OPEN,
LISTENBRAINZ_TOKEN_CLOSE, LISTENBRAINZ_TOKEN_CLOSE,
SHARE_MENU_OPEN,
SHARE_MENU_CLOSE,
} from '../actions' } from '../actions'
export const shareDialogReducer = (
previousState = {
open: false,
ids: [],
resource: '',
name: '',
},
payload
) => {
const { type, ids, resource, name } = payload
switch (type) {
case SHARE_MENU_OPEN:
return {
...previousState,
open: true,
ids,
resource,
name,
}
case SHARE_MENU_CLOSE:
return {
...previousState,
open: false,
}
default:
return previousState
}
}
export const addToPlaylistDialogReducer = ( export const addToPlaylistDialogReducer = (
previousState = { previousState = {
open: false, open: false,

View File

@ -10,11 +10,11 @@ import { Link } from '@material-ui/core'
import { DateField } from '../common' import { DateField } from '../common'
export const ShareEdit = (props) => { export const ShareEdit = (props) => {
const { id } = props const { id, basePath, hasCreate, ...rest } = props
const url = shareUrl(id) const url = shareUrl(id)
return ( return (
<Edit {...props}> <Edit {...props}>
<SimpleForm> <SimpleForm {...rest}>
<Link source="URL" href={url} target="_blank" rel="noopener noreferrer"> <Link source="URL" href={url} target="_blank" rel="noopener noreferrer">
{url} {url}
</Link> </Link>