From af32551ddf893f00f88fda26e87f649fb8926d03 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Tue, 15 Nov 2016 17:08:21 +1300 Subject: [PATCH] Drag-and-drop within tracklists --- src/js/components/Dragger.js | 34 ++++++++++++++++------------ src/js/components/Dropzones.js | 4 ++-- src/js/components/Track.js | 11 ++++++---- src/js/components/TrackList.js | 16 +++++++++++--- src/js/services/ui/actions.js | 39 ++++++++++++++++++++++----------- src/js/services/ui/reducer.js | 28 ++++++----------------- src/js/views/App.js | 2 +- src/scss/components/_lists.scss | 5 +++++ 8 files changed, 81 insertions(+), 58 deletions(-) diff --git a/src/js/components/Dragger.js b/src/js/components/Dragger.js index 97a5fbfe..b4e79a4e 100755 --- a/src/js/components/Dragger.js +++ b/src/js/components/Dragger.js @@ -15,6 +15,7 @@ class Dragger extends React.Component{ this.handleMouseUp = this.handleMouseUp.bind(this) this.state = { + active: false, position_x: 0, position_y: 0 } @@ -30,28 +31,33 @@ class Dragger extends React.Component{ window.removeEventListener("mouseup", this.handleMouseUp, false); } - componentWillReceiveProps( nextProps ){ - if( this.props.dragger && this.props.dragger.dragging ){ - this.setState( nextProps.dragger ) + handleMouseMove(e){ + if( !this.props.dragger ) return null; + + var threshold = 10 + if( + e.clientX > this.props.dragger.start_x + threshold || + e.clientX < this.props.dragger.start_x - threshold || + e.clientY > this.props.dragger.start_y + threshold || + e.clientY < this.props.dragger.start_y - threshold ){ + + this.setState({ + position_x: e.clientX, + position_y: e.clientY + }) + + // if not already, activate + if( !this.props.dragger.active ) this.props.uiActions.dragActive() } } - handleMouseMove(e){ - if( !this.props.dragger || !this.props.dragger.dragging ) return null; - - this.setState({ - position_x: e.clientX, - position_y: e.clientY - }) - } - handleMouseUp(e){ - if( !this.props.dragger || !this.props.dragger.dragging ) return null; + if( !this.props.dragger ) return null; this.props.uiActions.dragEnd( e ) } render(){ - if( !this.props.dragger || !this.props.dragger.dragging ) return null; + if( !this.props.dragger || !this.props.dragger.active ) return null; var style = { left: this.state.position_x, diff --git a/src/js/components/Dropzones.js b/src/js/components/Dropzones.js index e2819048..58f76ffa 100755 --- a/src/js/components/Dropzones.js +++ b/src/js/components/Dropzones.js @@ -36,7 +36,7 @@ class Dropzones extends React.Component{ } handleMouseMove(e){ - if( !this.props.dragger || !this.props.dragger.dragging ) return null; + if( !this.props.dragger || !this.props.dragger.active ) return null; this.props.uiActions.dragMove( e ) } @@ -58,7 +58,7 @@ class Dropzones extends React.Component{ } render(){ - if( !this.props.dragger || !this.props.dragger.dragging ) return null + if( !this.props.dragger || !this.props.dragger.active ) return null return (
diff --git a/src/js/components/Track.js b/src/js/components/Track.js index 739e5cd4..5a033076 100755 --- a/src/js/components/Track.js +++ b/src/js/components/Track.js @@ -23,11 +23,14 @@ export default class Track extends React.Component{ return this.props.handleDoubleClick(e); } - handleDragStart(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) + } - this.props.handleDragStart(e) + handleMouseUp(e){ + this.props.handleMouseUp(e) } handleContextMenu(e){ @@ -51,8 +54,8 @@ export default class Track extends React.Component{ return (
this.handleDragStart(e) } + 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) }> diff --git a/src/js/components/TrackList.js b/src/js/components/TrackList.js index a1634de6..0281fd19 100755 --- a/src/js/components/TrackList.js +++ b/src/js/components/TrackList.js @@ -88,8 +88,16 @@ class TrackList extends React.Component{ this.playTracks() } - handleDragStart(e, index){ - this.props.uiActions.dragStart( e, this.props.context, this.selectedTracks() ) + 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 ){ + var indexes = this.props.dragger.victims_indexes + this.props.uiActions.reorderTracks(this.props.context, indexes, index) + } } handleContextMenu(e, index){ @@ -173,7 +181,8 @@ class TrackList extends React.Component{ track={track} handleDoubleClick={ e => self.handleDoubleClick(e, index)} handleClick={ e => self.handleClick(e, index)} - handleDragStart={ e => self.handleDragStart(e, index)} + handleMouseUp={ e => self.handleMouseUp(e, index)} + handleMouseDown={ e => self.handleMouseDown(e, index)} handleContextMenu={ e => self.handleContextMenu(e, index)} /> } ) @@ -192,6 +201,7 @@ class TrackList extends React.Component{ const mapStateToProps = (state, ownProps) => { return { + dragger: state.ui.dragger, current_track: state.ui.current_track, context_menu: state.ui.context_menu } diff --git a/src/js/services/ui/actions.js b/src/js/services/ui/actions.js index c6a7d418..ee0c64cd 100755 --- a/src/js/services/ui/actions.js +++ b/src/js/services/ui/actions.js @@ -40,32 +40,45 @@ export function lazyLoading( start ){ } } -export function dragStart( e, context, victims ){ +export function dragStart( e, context, victims, victims_indexes = false ){ return { type: 'DRAG_START', context: context, victims: victims, - position_x: e.clientX, - position_y: e.clientY + victims_indexes: victims_indexes, + start_x: e.clientX, + start_y: e.clientY } } -export function dragMove( e ){ - return { - type: 'DRAG_MOVE', - position_x: e.clientX, - position_y: e.clientY, - } -} - -export function dragCancel(){ - return { type: 'DRAG_CANCEL' } +export function dragActive(){ + return { type: 'DRAG_ACTIVE' } } export function dragEnd(){ return { type: 'DRAG_END' } } +export function reorderTracks( context, indexes, destination_index ){ + console.log('uiActions.reorderTracks', context, indexes, destination_index) + switch( context ){ + + case 'queue': + return { + type: 'MOPIDY_REORDER_TRACKLIST', + indexes: indexes, + destination_index: destination_index + } + + case 'editable-playlist': + return { + type: 'SPOTIFY_REORDER_TRACKLIST', + indexes: indexes, + destination_index: destination_index + } + } +} + export function savePlaylist( uri, name, is_public = false ){ switch( helpers.uriSource( uri ) ){ diff --git a/src/js/services/ui/reducer.js b/src/js/services/ui/reducer.js index a3b4b2a6..3d332e28 100755 --- a/src/js/services/ui/reducer.js +++ b/src/js/services/ui/reducer.js @@ -34,36 +34,22 @@ export default function reducer(ui = {}, action){ return Object.assign({}, ui, { dragger: { dragging: true, + active: false, context: action.context, victims: action.victims, - position_x: action.position_x, - position_y: action.position_y + victims_indexes: action.victims_indexes, + start_x: action.start_x, + start_y: action.start_y } }); - case 'DRAG_MOVE': - var dragger = Object.assign({}, ui.dragger, { - position_x: action.position_x, - position_y: action.position_y - }) + case 'DRAG_ACTIVE': + var dragger = Object.assign({}, ui.dragger, { active: true }) return Object.assign({}, ui, { dragger: dragger }); case 'DRAG_END': return Object.assign({}, ui, { - dragger: { - dragging: false, - context: false, - victims: false - } - }); - - case 'DRAG_CANCEL': - return Object.assign({}, ui, { - dragger: { - dragging: false, - context: false, - victims: false - } + dragger: false }); diff --git a/src/js/views/App.js b/src/js/views/App.js index 5c2b344e..33356ffa 100755 --- a/src/js/views/App.js +++ b/src/js/views/App.js @@ -106,7 +106,7 @@ class App extends React.Component{ render(){ var className = ''; - if( this.props.dragger && this.props.dragger.dragging ) className += ' dragging' + if( this.props.dragger && this.props.dragger.active ) className += ' dragging' return (
diff --git a/src/scss/components/_lists.scss b/src/scss/components/_lists.scss index 1c434be4..e8b2ce8e 100755 --- a/src/scss/components/_lists.scss +++ b/src/scss/components/_lists.scss @@ -60,6 +60,11 @@ &.playing { font-weight: 600; } + + :root .dragging &:hover { + border-top: 3px solid $blue; + margin-top: -3px; + } }