Removing tracks from playlists on a global stage
This commit is contained in:
@ -29,6 +29,8 @@ class ContextMenu extends React.Component{
|
||||
case 'editable-playlist':
|
||||
items = [
|
||||
{ handleClick: 'playItems', label: 'Play' },
|
||||
{ handleClick: 'playItemsNext', label: 'Play next' },
|
||||
{ handleClick: 'addToQueue', label: 'Add to queue' },
|
||||
{ handleClick: 'removeFromPlaylist', label: 'Remove' }
|
||||
];
|
||||
break;
|
||||
@ -113,7 +115,7 @@ class ContextMenu extends React.Component{
|
||||
}
|
||||
|
||||
removeFromPlaylist(){
|
||||
console.log('removeFromPlaylist')
|
||||
this.props.uiActions.removeTracksFromPlaylist( this.props.context_menu.data.selected_tracks_indexes )
|
||||
this.props.uiActions.hideContextMenu();
|
||||
}
|
||||
|
||||
|
||||
@ -92,8 +92,10 @@ class TrackList extends React.Component{
|
||||
}
|
||||
|
||||
handleContextMenu(e, index){
|
||||
var selected_tracks = this.selectedTracks()
|
||||
var data = {
|
||||
selected_tracks: this.selectedTracks()
|
||||
selected_tracks: selected_tracks,
|
||||
selected_tracks_indexes: this.tracksIndexes( selected_tracks )
|
||||
}
|
||||
this.props.uiActions.showContextMenu( e, this.props.context, data )
|
||||
}
|
||||
@ -105,6 +107,14 @@ class TrackList extends React.Component{
|
||||
return this.state.tracks.filter(isSelected)
|
||||
}
|
||||
|
||||
tracksIndexes(tracks){
|
||||
var indexes = []
|
||||
for( var i = 0; i < tracks.length; i++ ){
|
||||
indexes.push( this.props.tracks.indexOf(tracks[i]))
|
||||
}
|
||||
return indexes
|
||||
}
|
||||
|
||||
playTracks(){
|
||||
|
||||
var tracks = this.selectedTracks();
|
||||
@ -123,12 +133,12 @@ class TrackList extends React.Component{
|
||||
}
|
||||
|
||||
removeTracks(){
|
||||
|
||||
var tracks = this.selectedTracks();
|
||||
|
||||
// if we've got a specific action, run it
|
||||
// if this tracklist handles removal, handle it
|
||||
if( typeof(this.props.removeTracks) !== 'undefined' ){
|
||||
return this.props.removeTracks( tracks );
|
||||
var tracks = this.selectedTracks();
|
||||
var tracks_indexes = this.tracksIndexes(tracks);
|
||||
return this.props.removeTracks( tracks_indexes );
|
||||
}
|
||||
|
||||
// by default, do nothing
|
||||
|
||||
@ -26,7 +26,7 @@ const sendRequest = ( dispatch, getState, endpoint, method = 'GET', data = false
|
||||
headers: {
|
||||
Authorization: 'Bearer '+ response
|
||||
},
|
||||
data: data
|
||||
data: JSON.stringify(data)
|
||||
}).then(
|
||||
response => {
|
||||
resolve(response)
|
||||
@ -326,75 +326,6 @@ export function getAlbum( uri ){
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Single playlist
|
||||
*
|
||||
* @oaram uri string
|
||||
**/
|
||||
export function getPlaylist( uri ){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
// flush out the previous store value
|
||||
dispatch({ type: 'SPOTIFY_PLAYLIST_LOADED', data: false });
|
||||
|
||||
var playlist = {};
|
||||
|
||||
$.when(
|
||||
|
||||
sendRequest( dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri) +'/playlists/'+ helpers.getFromUri('playlistid',uri) +'?market='+getState().spotify.country )
|
||||
.then( response => {
|
||||
Object.assign( playlist, response );
|
||||
}),
|
||||
|
||||
// TODO: Check if we're authenticated before sending this request, otherwise we get a 403
|
||||
sendRequest( dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri) + '/playlists/'+ helpers.getFromUri('playlistid',uri) + '/followers/contains?ids='+getState().spotify.me.id )
|
||||
.then( response => {
|
||||
var is_following = 0
|
||||
if( response.length > 0 ) is_following = response[0]
|
||||
Object.assign(playlist, { following: response[0] } );
|
||||
})
|
||||
|
||||
).then( () => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_PLAYLIST_LOADED',
|
||||
data: playlist
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* All of my playlists
|
||||
**/
|
||||
|
||||
function loadNextPlaylistsBatch( dispatch, getState, playlists, lastResponse ){
|
||||
if( lastResponse.next ){
|
||||
sendRequest( dispatch, getState, lastResponse.next )
|
||||
.then( response => {
|
||||
playlists = [...playlists, ...response.items]
|
||||
loadNextPlaylistsBatch( dispatch, getState, playlists, response )
|
||||
});
|
||||
}else{
|
||||
dispatch({
|
||||
type: 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED',
|
||||
data: playlists
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getAllLibraryPlaylists(){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
dispatch({ type: 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED', data: false });
|
||||
|
||||
sendRequest( dispatch, getState, 'me/playlists?limit=50' )
|
||||
.then( response => {
|
||||
loadNextPlaylistsBatch( dispatch, getState, response.items, response )
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function getLibraryArtists(){
|
||||
return (dispatch, getState) => {
|
||||
@ -567,10 +498,70 @@ export function getSearchResults( query, type = 'album,artist,playlist,track', l
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Following toggles
|
||||
* Playlists
|
||||
**/
|
||||
|
||||
export function getPlaylist( uri ){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
// flush out the previous store value
|
||||
dispatch({ type: 'SPOTIFY_PLAYLIST_LOADED', data: false });
|
||||
|
||||
var playlist = {};
|
||||
|
||||
$.when(
|
||||
|
||||
sendRequest( dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri) +'/playlists/'+ helpers.getFromUri('playlistid',uri) +'?market='+getState().spotify.country )
|
||||
.then( response => {
|
||||
Object.assign( playlist, response );
|
||||
}),
|
||||
|
||||
// TODO: Check if we're authenticated before sending this request, otherwise we get a 403
|
||||
sendRequest( dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri) + '/playlists/'+ helpers.getFromUri('playlistid',uri) + '/followers/contains?ids='+getState().spotify.me.id )
|
||||
.then( response => {
|
||||
var is_following = 0
|
||||
if( response.length > 0 ) is_following = response[0]
|
||||
Object.assign(playlist, { following: response[0] } );
|
||||
})
|
||||
|
||||
).then( () => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_PLAYLIST_LOADED',
|
||||
data: playlist
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function loadNextPlaylistsBatch( dispatch, getState, playlists, lastResponse ){
|
||||
if( lastResponse.next ){
|
||||
sendRequest( dispatch, getState, lastResponse.next )
|
||||
.then( response => {
|
||||
playlists = [...playlists, ...response.items]
|
||||
loadNextPlaylistsBatch( dispatch, getState, playlists, response )
|
||||
});
|
||||
}else{
|
||||
dispatch({
|
||||
type: 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED',
|
||||
data: playlists
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getAllLibraryPlaylists(){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
dispatch({ type: 'SPOTIFY_LIBRARY_PLAYLISTS_LOADED', data: false });
|
||||
|
||||
sendRequest( dispatch, getState, 'me/playlists?limit=50' )
|
||||
.then( response => {
|
||||
loadNextPlaylistsBatch( dispatch, getState, response.items, response )
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function toggleFollowingPlaylist( uri, method ){
|
||||
if( method == 'PUT' ) var new_state = 1
|
||||
if( method == 'DELETE' ) var new_state = 0
|
||||
@ -586,5 +577,16 @@ export function toggleFollowingPlaylist( uri, method ){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function deleteTracksFromPlaylist( uri, snapshot_id, positions ){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest( dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri) + '/playlists/'+ helpers.getFromUri('playlistid',uri) + '/tracks', 'DELETE', { snapshot_id: snapshot_id, positions: positions } )
|
||||
.then( response => {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_PLAYLIST_TRACKS_REMOVED',
|
||||
positions: positions,
|
||||
snapshot_id: response.snapshot_id
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -65,4 +65,11 @@ export function dragEnd(){
|
||||
return { type: 'DRAG_END' }
|
||||
}
|
||||
|
||||
export function removeTracksFromPlaylist( track_indexes ){
|
||||
return {
|
||||
type: 'REMOVE_TRACKS_FROM_PLAYLIST',
|
||||
track_indexes: track_indexes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -178,6 +178,14 @@ export default function reducer(ui = {}, action){
|
||||
var playlist = Object.assign({}, ui.playlist, { following: action.data })
|
||||
return Object.assign({}, ui, { playlist: playlist });
|
||||
|
||||
case 'SPOTIFY_PLAYLIST_TRACKS_REMOVED':
|
||||
var tracks = Object.assign([], ui.playlist.tracks)
|
||||
for( var i = 0; i < action.positions.length; i++ ){
|
||||
tracks.splice( action.positions[i], 1 )
|
||||
}
|
||||
var playlist = Object.assign({}, ui.playlist, action.snapshot_id, { tracks: tracks })
|
||||
return Object.assign({}, ui, { playlist: playlist });
|
||||
|
||||
|
||||
/**
|
||||
* Library Playlists
|
||||
|
||||
@ -11,8 +11,9 @@ import Dater from '../components/Dater'
|
||||
import ConfirmationButton from '../components/ConfirmationButton'
|
||||
import LazyLoadListener from '../components/LazyLoadListener'
|
||||
|
||||
import * as spotifyActions from '../services/spotify/actions'
|
||||
import * as uiActions from '../services/ui/actions'
|
||||
import * as mopidyActions from '../services/mopidy/actions'
|
||||
import * as spotifyActions from '../services/spotify/actions'
|
||||
|
||||
class Playlist extends React.Component{
|
||||
|
||||
@ -35,11 +36,16 @@ class Playlist extends React.Component{
|
||||
}
|
||||
|
||||
loadPlaylist( props = this.props ){
|
||||
var source = helpers.uriSource( props.params.uri );
|
||||
if( source == 'spotify' ){
|
||||
this.props.spotifyActions.getPlaylist( props.params.uri );
|
||||
}else if( source == 'm3u' && props.mopidy_connected ){
|
||||
this.props.mopidyActions.getPlaylist( props.params.uri );
|
||||
switch( helpers.uriSource( props.params.uri ) ){
|
||||
|
||||
case 'spotify':
|
||||
this.props.spotifyActions.getPlaylist( props.params.uri );
|
||||
break
|
||||
|
||||
case 'm3u':
|
||||
if( props.mopidy_connected ) this.props.mopidyActions.getPlaylist( props.params.uri );
|
||||
break
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,6 +70,10 @@ class Playlist extends React.Component{
|
||||
alert('Delete me')
|
||||
}
|
||||
|
||||
removeTracks( track_indexes ){
|
||||
this.props.uiActions.removeTracksFromPlaylist( track_indexes )
|
||||
}
|
||||
|
||||
renderFollowOrDeleteButton(){
|
||||
if( !this.props.spotify_authorized ) return null
|
||||
|
||||
@ -117,7 +127,7 @@ class Playlist extends React.Component{
|
||||
</div>
|
||||
|
||||
<section className="list-wrapper">
|
||||
{ this.props.playlist.tracks ? <TrackList tracks={ this.props.playlist.tracks } /> : null }
|
||||
{ this.props.playlist.tracks ? <TrackList context="editable-playlist" tracks={ this.props.playlist.tracks } removeTracks={ track_indexes => this.removeTracks(track_indexes) } /> : null }
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
</section>
|
||||
|
||||
@ -145,6 +155,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user