Drag-and-drop support for adding to new playlist, #723
This commit is contained in:
@ -43,7 +43,7 @@ export default class Dropzone extends React.Component {
|
||||
return (
|
||||
<div
|
||||
className={hover ? 'dropzone hover' : 'dropzone'}
|
||||
onMouseUp={handleMouseUp}
|
||||
onMouseUp={() => handleMouseUp(data)}
|
||||
>
|
||||
<Icon name={data.icon} />
|
||||
<span className="title">{ data.title }</span>
|
||||
|
||||
@ -1,106 +1,81 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { withRouter } from 'react-router';
|
||||
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import Dropzone from './Dropzone';
|
||||
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
import * as mopidyActions from '../../services/mopidy/actions';
|
||||
import * as spotifyActions from '../../services/spotify/actions';
|
||||
import { arrayOf } from '../../util/arrays';
|
||||
import { i18n } from '../../locale';
|
||||
import { encodeUri } from '../../util/format';
|
||||
|
||||
class Dropzones extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const Dropzones = () => {
|
||||
const dispatch = useDispatch();
|
||||
const history = useHistory();
|
||||
const {
|
||||
victims,
|
||||
from_uri,
|
||||
active,
|
||||
} = useSelector((state) => state.ui.dragger || {});
|
||||
const zones = [
|
||||
{
|
||||
title: i18n('actions.add_to_queue'),
|
||||
icon: 'play_arrow',
|
||||
action: 'enqueue',
|
||||
},
|
||||
{
|
||||
title: i18n('actions.play_next'),
|
||||
icon: 'play_arrow',
|
||||
action: 'enqueue_next',
|
||||
},
|
||||
{
|
||||
title: i18n('actions.add_to_playlist'),
|
||||
icon: 'playlist_add',
|
||||
action: 'add_to_playlist',
|
||||
accepts: ['tltrack', 'track', 'album', 'playlist', 'artist'],
|
||||
},
|
||||
{
|
||||
title: i18n('modal.edit_playlist.create_playlist'),
|
||||
icon: 'playlist_add',
|
||||
action: 'create_playlist_and_add',
|
||||
accepts: ['tltrack', 'track', 'album', 'playlist', 'artist'],
|
||||
},
|
||||
];
|
||||
|
||||
this._zones = [
|
||||
{
|
||||
title: i18n('actions.add_to_queue'),
|
||||
icon: 'play_arrow',
|
||||
action: 'enqueue',
|
||||
},
|
||||
{
|
||||
title: i18n('actions.play_next'),
|
||||
icon: 'play_arrow',
|
||||
action: 'enqueue_next',
|
||||
},
|
||||
{
|
||||
title: i18n('actions.add_to_playlist'),
|
||||
icon: 'playlist_add',
|
||||
action: 'add_to_playlist',
|
||||
accepts: ['tltrack', 'track', 'album', 'playlist', 'artist'],
|
||||
},
|
||||
];
|
||||
}
|
||||
if (!active) return null;
|
||||
|
||||
handleMouseMove = (e) => {
|
||||
const { dragger = {}, uiActions: { dragMove } } = this.props;
|
||||
if (!dragger || !dragger.active) return null;
|
||||
return dragMove(e);
|
||||
}
|
||||
|
||||
handleMouseUp = (zone) => {
|
||||
const {
|
||||
dragger: {
|
||||
victims = [],
|
||||
from_uri,
|
||||
},
|
||||
mopidyActions: {
|
||||
enqueueURIs,
|
||||
},
|
||||
history,
|
||||
} = this.props;
|
||||
const handleMouseUp = (zone) => {
|
||||
const uris = arrayOf('uri', victims);
|
||||
|
||||
switch (zone.action) {
|
||||
case 'enqueue':
|
||||
enqueueURIs(uris, from_uri);
|
||||
dispatch(mopidyActions.enqueueURIs(uris, from_uri));
|
||||
break;
|
||||
case 'enqueue_next':
|
||||
enqueueURIs(uris, from_uri, true);
|
||||
dispatch(mopidyActions.enqueueURIs(uris, from_uri, true));
|
||||
break;
|
||||
case 'add_to_playlist':
|
||||
history.push(`/add-to-playlist/${encodeUri(uris.join(','))}`);
|
||||
// uris
|
||||
break;
|
||||
case 'create_playlist_and_add':
|
||||
history.push(`/playlist/create/${encodeUri(uris.join(','))}`);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render = () => {
|
||||
const {
|
||||
dragger = {},
|
||||
} = this.props;
|
||||
if (!dragger || !dragger.active) return null;
|
||||
return (
|
||||
<div className="dropzones">
|
||||
{
|
||||
zones.map((zone) => (
|
||||
<Dropzone
|
||||
key={zone.action}
|
||||
data={zone}
|
||||
handleMouseUp={handleMouseUp}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="dropzones">
|
||||
{
|
||||
this._zones.map((zone) => (
|
||||
<Dropzone
|
||||
key={zone.action}
|
||||
data={zone}
|
||||
handleMouseUp={() => this.handleMouseUp(zone)}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
dragger: state.ui.dragger,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
});
|
||||
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Dropzones));
|
||||
export default Dropzones;
|
||||
|
||||
@ -27,6 +27,7 @@ actions:
|
||||
stop: Stop
|
||||
add_to_playlist: Add to playlist
|
||||
add_to_library: Add to library
|
||||
create_playlist_and_add: New playlist
|
||||
added_tracks_to: 'Added %{count} tracks to '
|
||||
remove_from_library: Remove from library
|
||||
add_to_queue: Add to queue
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import Link from '../../components/Link';
|
||||
import Modal from './Modal';
|
||||
import Thumbnail from '../../components/Thumbnail';
|
||||
import LinksSentence from '../../components/LinksSentence';
|
||||
@ -12,7 +11,7 @@ import * as mopidyActions from '../../services/mopidy/actions';
|
||||
import * as geniusActions from '../../services/genius/actions';
|
||||
import { isLoading } from '../../util/helpers';
|
||||
import { i18n, I18n } from '../../locale';
|
||||
import { makeItemSelector } from '../../util/selectors';
|
||||
import { makeItemSelector, makeLoadingSelector } from '../../util/selectors';
|
||||
|
||||
const LyricsScroller = ({
|
||||
content = '',
|
||||
@ -33,17 +32,17 @@ const LyricsScroller = ({
|
||||
|
||||
const Lyrics = ({
|
||||
show_lyrics,
|
||||
load_queue,
|
||||
time_position = null,
|
||||
current_track,
|
||||
}) => {
|
||||
if (!show_lyrics) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const loadingSelector = makeLoadingSelector(['genius_(.*)']);
|
||||
const loading = useSelector(loadingSelector);
|
||||
const { lyrics, duration } = current_track || {};
|
||||
|
||||
if (isLoading(load_queue, ['genius_'])) {
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="lyrics">
|
||||
<Loader body loading />
|
||||
@ -225,6 +224,6 @@ const KioskMode = () => {
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default KioskMode;
|
||||
|
||||
Reference in New Issue
Block a user