diff --git a/ui/src/App.js b/ui/src/App.js index db2fe06d2..33e72bf6b 100644 --- a/ui/src/App.js +++ b/ui/src/App.js @@ -29,6 +29,7 @@ import { settingsReducer, replayGainReducer, downloadMenuDialogReducer, + shareDialogReducer, } from './reducers' import createAdminStore from './store/createAdminStore' import { i18nProvider } from './i18n' @@ -60,6 +61,7 @@ const adminStore = createAdminStore({ downloadMenuDialog: downloadMenuDialogReducer, expandInfoDialog: expandInfoDialogReducer, listenBrainzTokenDialog: listenBrainzTokenDialogReducer, + shareDialog: shareDialogReducer, activity: activityReducer, settings: settingsReducer, replayGain: replayGainReducer, diff --git a/ui/src/actions/dialogs.js b/ui/src/actions/dialogs.js index d3764b852..5f64f87c3 100644 --- a/ui/src/actions/dialogs.js +++ b/ui/src/actions/dialogs.js @@ -12,6 +12,19 @@ export const DOWNLOAD_MENU_ALBUM = 'album' export const DOWNLOAD_MENU_ARTIST = 'artist' export const DOWNLOAD_MENU_PLAY = 'playlist' 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 }) => ({ type: ADD_TO_PLAYLIST_OPEN, diff --git a/ui/src/album/AlbumActions.js b/ui/src/album/AlbumActions.js index eef23b2b7..02ee743a2 100644 --- a/ui/src/album/AlbumActions.js +++ b/ui/src/album/AlbumActions.js @@ -7,11 +7,13 @@ import { TopToolbar, useTranslate, } from 'react-admin' +import { useMediaQuery, makeStyles } from '@material-ui/core' import PlayArrowIcon from '@material-ui/icons/PlayArrow' import ShuffleIcon from '@material-ui/icons/Shuffle' import CloudDownloadOutlinedIcon from '@material-ui/icons/CloudDownloadOutlined' import { RiPlayListAddFill, RiPlayList2Fill } from 'react-icons/ri' import PlaylistAddIcon from '@material-ui/icons/PlaylistAdd' +import ShareIcon from '@material-ui/icons/Share' import { playNext, addTracks, @@ -20,14 +22,11 @@ import { openAddToPlaylist, openDownloadMenu, DOWNLOAD_MENU_ALBUM, + openShareMenu, } from '../actions' import { formatBytes } from '../utils' -import { useMediaQuery, makeStyles } from '@material-ui/core' import config from '../config' import { ToggleFieldsMenu } from '../common' -import { useDialog } from '../dialogs/useDialog' -import { ShareDialog } from '../dialogs/ShareDialog' -import ShareIcon from '@material-ui/icons/Share' const useStyles = makeStyles({ toolbar: { display: 'flex', justifyContent: 'space-between', width: '100%' }, @@ -38,6 +37,7 @@ const AlbumActions = ({ ids, data, record, + resource, permanentFilter, ...rest }) => { @@ -46,7 +46,6 @@ const AlbumActions = ({ const classes = useStyles() const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md')) const isNotSmall = useMediaQuery((theme) => theme.breakpoints.up('sm')) - const shareDialog = useDialog() const handlePlay = React.useCallback(() => { dispatch(playTracks(data, ids)) @@ -68,6 +67,10 @@ const AlbumActions = ({ dispatch(openAddToPlaylist({ selectedIds: ids })) }, [dispatch, ids]) + const handleShare = React.useCallback(() => { + dispatch(openShareMenu([record.id], resource, record.name)) + }, [dispatch, record, resource]) + const handleDownload = React.useCallback(() => { dispatch(openDownloadMenu(record, DOWNLOAD_MENU_ALBUM)) }, [dispatch, record]) @@ -107,10 +110,7 @@ const AlbumActions = ({ {config.devEnableShare && ( - )} @@ -128,12 +128,6 @@ const AlbumActions = ({
{isNotSmall && }
- ) } diff --git a/ui/src/dialogs/Dialogs.js b/ui/src/dialogs/Dialogs.js index 3de28725c..74f5a094d 100644 --- a/ui/src/dialogs/Dialogs.js +++ b/ui/src/dialogs/Dialogs.js @@ -1,11 +1,13 @@ import { AddToPlaylistDialog } from './AddToPlaylistDialog' import DownloadMenuDialog from './DownloadMenuDialog' import { HelpDialog } from './HelpDialog' +import { ShareDialog } from './ShareDialog' export const Dialogs = (props) => ( <> + ) diff --git a/ui/src/dialogs/DownloadMenuDialog.js b/ui/src/dialogs/DownloadMenuDialog.js index 0b01dcfb3..0a51720bb 100644 --- a/ui/src/dialogs/DownloadMenuDialog.js +++ b/ui/src/dialogs/DownloadMenuDialog.js @@ -67,12 +67,12 @@ const DownloadMenuDialog = () => { - + ) diff --git a/ui/src/dialogs/ShareDialog.js b/ui/src/dialogs/ShareDialog.js index 39228f04a..8ac2c4f70 100644 --- a/ui/src/dialogs/ShareDialog.js +++ b/ui/src/dialogs/ShareDialog.js @@ -15,8 +15,14 @@ import { import { useState } from 'react' import { shareUrl } from '../utils' 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 translate = useTranslate() const [description, setDescription] = useState('') @@ -34,15 +40,10 @@ export const ShareDialog = ({ open, onClose, ids, resource, name }) => { { onSuccess: (res) => { const url = shareUrl(res?.data?.id) - onClose() navigator.clipboard .writeText(url) .then(() => { - notify(translate('message.shareSuccess', { url }), { - type: 'info', - multiLine: true, - duration: 0, - }) + notify('message.shareSuccess', 'info', { url }, false, 0) }) .catch((err) => { notify( @@ -56,26 +57,40 @@ export const ShareDialog = ({ open, onClose, ids, resource, name }) => { }) }, 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 ( - {translate('message.shareDialogTitle', { - resource: translate(`resources.${resource}.name`, { - smart_count: ids?.length, - }).toLocaleLowerCase(), - name, - })} + {resource && + translate('message.shareDialogTitle', { + resource: translate(`resources.${resource}.name`, { + smart_count: ids?.length, + }).toLocaleLowerCase(), + name, + })} @@ -93,12 +108,12 @@ export const ShareDialog = ({ open, onClose, ids, resource, name }) => { - - + ) diff --git a/ui/src/playlist/PlaylistActions.js b/ui/src/playlist/PlaylistActions.js index a2106d978..d9f2b3fc3 100644 --- a/ui/src/playlist/PlaylistActions.js +++ b/ui/src/playlist/PlaylistActions.js @@ -8,11 +8,13 @@ import { useDataProvider, useNotify, } from 'react-admin' +import { useMediaQuery, makeStyles } from '@material-ui/core' import PlayArrowIcon from '@material-ui/icons/PlayArrow' import ShuffleIcon from '@material-ui/icons/Shuffle' import CloudDownloadOutlinedIcon from '@material-ui/icons/CloudDownloadOutlined' import { RiPlayListAddFill, RiPlayList2Fill } from 'react-icons/ri' import QueueMusicIcon from '@material-ui/icons/QueueMusic' +import ShareIcon from '@material-ui/icons/Share' import { httpClient } from '../dataProvider' import { playNext, @@ -21,22 +23,26 @@ import { shuffleTracks, openDownloadMenu, DOWNLOAD_MENU_PLAY, + openShareMenu, } from '../actions' import { M3U_MIME_TYPE, REST_URL } from '../consts' import PropTypes from 'prop-types' import { formatBytes } from '../utils' -import { useMediaQuery, makeStyles } from '@material-ui/core' import config from '../config' import { ToggleFieldsMenu } from '../common' -import { ShareDialog } from '../dialogs/ShareDialog' -import { useDialog } from '../dialogs/useDialog' -import ShareIcon from '@material-ui/icons/Share' const useStyles = makeStyles({ 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 translate = useTranslate() const classes = useStyles() @@ -44,7 +50,6 @@ const PlaylistActions = ({ className, ids, data, record, ...rest }) => { const notify = useNotify() const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('md')) const isNotSmall = useMediaQuery((theme) => theme.breakpoints.up('sm')) - const shareDialog = useDialog() const getAllSongsAndDispatch = React.useCallback( (action) => { @@ -88,6 +93,10 @@ const PlaylistActions = ({ className, ids, data, record, ...rest }) => { getAllSongsAndDispatch(shuffleTracks) }, [getAllSongsAndDispatch]) + const handleShare = React.useCallback(() => { + dispatch(openShareMenu([record.id], resource, record.name)) + }, [dispatch, record, resource]) + const handleDownload = React.useCallback(() => { dispatch(openDownloadMenu(record, DOWNLOAD_MENU_PLAY)) }, [dispatch, record]) @@ -138,10 +147,7 @@ const PlaylistActions = ({ className, ids, data, record, ...rest }) => { {config.devEnableShare && ( - )} @@ -165,12 +171,6 @@ const PlaylistActions = ({ className, ids, data, record, ...rest }) => {
{isNotSmall && }
- ) } diff --git a/ui/src/reducers/dialogReducer.js b/ui/src/reducers/dialogReducer.js index 0468e32c4..b21419a93 100644 --- a/ui/src/reducers/dialogReducer.js +++ b/ui/src/reducers/dialogReducer.js @@ -13,8 +13,39 @@ import { EXTENDED_INFO_CLOSE, LISTENBRAINZ_TOKEN_OPEN, LISTENBRAINZ_TOKEN_CLOSE, + SHARE_MENU_OPEN, + SHARE_MENU_CLOSE, } 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 = ( previousState = { open: false, diff --git a/ui/src/share/ShareEdit.js b/ui/src/share/ShareEdit.js index 75bd06ed6..98872c31f 100644 --- a/ui/src/share/ShareEdit.js +++ b/ui/src/share/ShareEdit.js @@ -10,11 +10,11 @@ import { Link } from '@material-ui/core' import { DateField } from '../common' export const ShareEdit = (props) => { - const { id } = props + const { id, basePath, hasCreate, ...rest } = props const url = shareUrl(id) return ( - + {url}