Dragging vs context menu vs selection vs ctrl

This commit is contained in:
James Barnsley
2016-11-16 14:58:08 +13:00
parent 98770441cc
commit 86b9665ec8
9 changed files with 108 additions and 64 deletions

View File

@ -12,21 +12,15 @@ export default class Track extends React.Component{
super(props);
}
handleClick(e){
var target = $(e.target);
if( !target.is('a') && target.closest('a').length <= 0 ){
this.props.handleClick(e);
}
}
handleDoubleClick(e){
return this.props.handleDoubleClick(e);
}
handleMouseDown(e){
// if we're not selected, perform click behavior [first] << this is assumed
if( !this.props.track.selected ) this.handleClick(e)
this.props.handleMouseDown(e)
var target = $(e.target);
if( !target.is('a') && target.closest('a').length <= 0 ){
this.props.handleMouseDown(e);
}
}
handleMouseUp(e){
@ -35,11 +29,6 @@ export default class Track extends React.Component{
handleContextMenu(e){
e.preventDefault();
// trigger a regular click event
if( !this.props.track.selected ) this.handleClick(e);
// notify our tracklist
this.props.handleContextMenu(e);
}
@ -56,12 +45,11 @@ export default class Track extends React.Component{
className={className}
onMouseDown={ e => this.handleMouseDown(e) }
onMouseUp={ e => this.handleMouseUp(e) }
onClick={ e => this.handleClick(e) }
onDoubleClick={ e => this.handleDoubleClick(e) }
onContextMenu={ e => this.handleContextMenu(e) }>
{ this.props.track.selected ? <FontAwesome name="check" className="select-state" fixedWidth /> : null }
<span className="col name">
{ track.name ? track.name : track.uri }
{ track.name ? track.name : <span className="grey-text">{track.uri}</span> }
</span>
<span className="col artists">
{ track.artists ? <ArtistSentence artists={track.artists} /> : '-' }

View File

@ -48,9 +48,55 @@ class TrackList extends React.Component{
}
}
handleClick( e, index ){
handleDoubleClick(e, index){
if( this.props.context_menu.show ) this.props.uiActions.hideContextMenu()
this.playTracks()
}
handleMouseDown(e, index){
if( this.props.context_menu.show ) this.props.uiActions.hideContextMenu()
if( !this.state.tracks[index].selected && !this.isRightClick(e) && !e.ctrlKey ) this.toggleTrackSelections(e, index)
var selected_tracks = this.selectedTracks()
this.props.uiActions.dragStart( e, this.props.context, selected_tracks, this.tracksIndexes(selected_tracks) )
}
handleMouseUp(e, index){
// right-clicking on an un-highlighted track
if( !this.state.tracks[index].selected && this.isRightClick(e) ){
this.toggleTrackSelections(e, index)
// selected track, regular click
}else if( this.state.tracks[index].selected && !this.isRightClick(e) ){
this.toggleTrackSelections(e, index)
// ctrl key
}else if( e.ctrlKey ){
this.toggleTrackSelections(e, index)
}
if( this.props.dragger && this.props.dragger.active ){
// if this tracklist handles sorting, handle it
if( typeof(this.props.reorderTracks) !== 'undefined' ){
var indexes = this.props.dragger.victims_indexes
return this.props.reorderTracks( indexes, index );
}
}
}
handleContextMenu(e, index){
var selected_tracks = this.selectedTracks()
var data = {
selected_tracks: selected_tracks,
selected_tracks_indexes: this.tracksIndexes( selected_tracks )
}
this.props.uiActions.showContextMenu( e, this.props.context, data )
}
toggleTrackSelections(e, index){
var tracks = this.state.tracks
if( e.ctrlKey ){
@ -83,34 +129,12 @@ class TrackList extends React.Component{
this.setState({ tracks: tracks, lastSelectedTrack: index })
}
handleDoubleClick(e, index){
if( this.props.context_menu.show ) this.props.uiActions.hideContextMenu()
this.playTracks()
}
handleMouseDown(e, index){
var selected_tracks = this.selectedTracks()
this.props.uiActions.dragStart( e, this.props.context, selected_tracks, this.tracksIndexes(selected_tracks) )
}
handleMouseUp(e, index){
if( this.props.dragger && this.props.dragger.active ){
// if this tracklist handles sorting, handle it
if( typeof(this.props.reorderTracks) !== 'undefined' ){
var indexes = this.props.dragger.victims_indexes
return this.props.reorderTracks( indexes, index );
}
}
}
handleContextMenu(e, index){
var selected_tracks = this.selectedTracks()
var data = {
selected_tracks: selected_tracks,
selected_tracks_indexes: this.tracksIndexes( selected_tracks )
}
this.props.uiActions.showContextMenu( e, this.props.context, data )
isRightClick(e){
if( 'which' in e )
return e.which == 3
if( 'button' in e )
return e.button == 2
return false
}
keyifyTracks( tracks ){

View File

@ -12,7 +12,10 @@ const localstorageMiddleware = (function(){
// append our state to a global variable. This gives us access to debug the store at any point
window._store = store
console.log(action)
var actions_to_log = null
//actions_to_log = 'SPOTIFY'
//actions_to_log = 'MOPIDY'
if( action.type.startsWith(actions_to_log) ) console.log(action)
switch( action.type ){

View File

@ -210,6 +210,15 @@ const MopidyMiddleware = (function(){
})
break;
case 'MOPIDY_CREATE_PLAYLIST':
instruct( socket, store, 'playlists.create', { name: action.name, uri_scheme: action.scheme })
.then( response => {
// re-load our global playlists
store.dispatch({ type: 'MOPIDY_PLAYLISTS' });
});
break
case 'MOPIDY_PLAYLIST':
store.dispatch({ type: 'MOPIDY_PLAYLIST_LOADED', data: false });
instruct( socket, store, 'playlists.lookup', action.data )
@ -227,13 +236,13 @@ const MopidyMiddleware = (function(){
)
// tracks? get the full track objects
if( playlist.tracks.length > 0 ) store.dispatch({ type: 'MOPIDY_FETCH_PLAYLIST_TRACKS', tracks: playlist.tracks })
if( playlist.tracks.length > 0 ) store.dispatch({ type: 'MOPIDY_PLAYLIST_TRACKS', tracks: playlist.tracks })
store.dispatch({ type: 'MOPIDY_PLAYLIST_LOADED', data: playlist })
})
break;
case 'MOPIDY_FETCH_PLAYLIST_TRACKS':
case 'MOPIDY_PLAYLIST_TRACKS':
var tracks = Object.assign([], action.tracks)
var uris = [];
for( var i = 0; i < tracks.length; i++ ){
@ -315,15 +324,6 @@ const MopidyMiddleware = (function(){
});
break
case 'MOPIDY_CREATE_PLAYLIST':
instruct( socket, store, 'playlists.create', { name: action.name, uri_scheme: action.scheme })
.then( response => {
// re-load our global playlists
store.dispatch({ type: 'MOPIDY_PLAYLISTS' });
});
break
case 'MOPIDY_SAVE_PLAYLIST':
instruct( socket, store, 'playlists.lookup', { uri: action.uri })
.then( response => {
@ -376,7 +376,7 @@ const MopidyMiddleware = (function(){
.then( response => {
// and now re-render our full track references
store.dispatch({ type: 'MOPIDY_FETCH_PLAYLIST_TRACKS', tracks: playlist.tracks })
store.dispatch({ type: 'MOPIDY_PLAYLIST_TRACKS', tracks: playlist.tracks })
})
});
break

View File

@ -641,3 +641,20 @@ export function deleteTracksFromPlaylist( uri, snapshot_id, tracks_indexes ){
}
}
export function reorderPlaylistTracks( uri, indexes, to_index, snapshot_id ){
var range_start = indexes[0]
var range_length = indexes.length
return (dispatch, getState) => {
sendRequest( dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri) + '/playlists/'+ helpers.getFromUri('playlistid',uri) + '/tracks', 'PUT', { uri: uri, range_start: range_start, range_length: range_length, insert_before: to_index, snapshot_id: snapshot_id } )
.then( response => {
dispatch({
type: 'PLAYLIST_TRACKS_REORDERED',
range_start: range_start,
range_length: range_length,
to_index: to_index,
snapshot_id: response.snapshot_id
});
});
}
}

View File

@ -52,6 +52,16 @@ const SpotifyMiddleware = (function(){
break
case 'SPOTIFY_REORDER_PLAYLIST_TRACKS':
if( !store.getState().spotify.authorized ){
alert('Must be logged in to Spotify to do this')
return
}
store.dispatch( actions.reorderPlaylistTracks( action.uri, action.indexes, action.to_index ))
break
case 'SPOTIFY_SAVE_PLAYLIST':
if( !store.getState().spotify.authorized ){

View File

@ -59,15 +59,17 @@ export function dragEnd(){
return { type: 'DRAG_END' }
}
export function reorderPlaylistTracks( uri, indexes, to_index ){
export function reorderPlaylistTracks( uri, indexes, to_index, snapshot_id = false ){
switch( helpers.uriSource( uri ) ){
case 'spotify':
// TODO: handle bunched selected tracks (ie non-continuious indexes)
return {
type: 'SPOTIFY_REORDER_PLAYLIST_TRACKS',
uri: uri,
indexes: indexes,
to_index: to_index
to_index: to_index,
snapshot_id: snapshot_id
}
case 'm3u':

View File

@ -233,13 +233,13 @@ export default function reducer(ui = {}, action){
case 'PLAYLIST_TRACKS_LOADED':
var playlist = Object.assign({}, ui.playlist, { tracks: action.tracks })
return Object.assign({}, ui, { playlist: playlist });
/*
case 'PLAYLIST_TRACKS_REORDERED':
var snapshot_id = null
if( action.snapshot_id ) snapshot_id = action.snapshot_id
var playlist = Object.assign({}, ui.playlist, { tracks: action.tracks, snapshot_id: snapshot_id })
return Object.assign({}, ui, { playlist: playlist });
*/
/**
* Library Playlists

View File

@ -74,7 +74,7 @@ class Playlist extends React.Component{
}
reorderTracks( indexes, index ){
this.props.uiActions.reorderPlaylistTracks( this.props.playlist.uri, indexes, index )
this.props.uiActions.reorderPlaylistTracks( this.props.playlist.uri, indexes, index, this.props.playlist.snapshot_id )
}
removeTracks( tracks_indexes ){