2016-10-03 14:44:27 +13:00
|
|
|
|
|
|
|
|
import React, { PropTypes } from 'react'
|
2016-10-14 18:15:34 +13:00
|
|
|
import { connect } from 'react-redux'
|
|
|
|
|
import { bindActionCreators } from 'redux'
|
|
|
|
|
|
2016-10-03 21:21:14 +13:00
|
|
|
import Track from './Track'
|
2017-03-02 07:55:28 +13:00
|
|
|
import ContextMenuTrigger from './ContextMenuTrigger'
|
2016-10-03 14:44:27 +13:00
|
|
|
|
2017-01-27 09:55:19 +13:00
|
|
|
import * as helpers from '../helpers'
|
2016-11-10 16:17:10 +13:00
|
|
|
import * as mopidyActions from '../services/mopidy/actions'
|
|
|
|
|
import * as uiActions from '../services/ui/actions'
|
|
|
|
|
|
2016-10-14 18:15:34 +13:00
|
|
|
class TrackList extends React.Component{
|
2016-10-03 14:44:27 +13:00
|
|
|
|
2017-10-10 13:05:28 +13:00
|
|
|
constructor(props){
|
2017-05-17 09:07:09 +12:00
|
|
|
super(props)
|
2016-12-06 16:54:48 +13:00
|
|
|
|
2017-07-22 06:36:47 +12:00
|
|
|
this.touch_dragging_tracks_keys = false
|
|
|
|
|
|
2017-08-23 08:05:00 +12:00
|
|
|
this.handleKeyDown = this.handleKeyDown.bind(this)
|
2017-07-17 09:13:12 +12:00
|
|
|
this.handleTouchMove = this.handleTouchMove.bind(this)
|
2017-07-22 06:36:47 +12:00
|
|
|
this.handleTouchEnd = this.handleTouchEnd.bind(this)
|
2016-10-27 13:02:10 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentWillMount(){
|
2017-08-23 08:05:00 +12:00
|
|
|
window.addEventListener("keydown", this.handleKeyDown, false)
|
2017-07-17 09:13:12 +12:00
|
|
|
window.addEventListener("touchmove", this.handleTouchMove, false)
|
2017-07-22 06:36:47 +12:00
|
|
|
window.addEventListener("touchend", this.handleTouchEnd, false)
|
2016-10-27 13:02:10 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentWillUnmount(){
|
2017-08-23 08:05:00 +12:00
|
|
|
window.removeEventListener("keydown", this.handleKeyDown, false)
|
2017-07-17 09:13:12 +12:00
|
|
|
window.removeEventListener("touchmove", this.handleTouchMove, false)
|
2017-07-22 06:36:47 +12:00
|
|
|
window.removeEventListener("touchend", this.handleTouchEnd, false)
|
2016-10-27 13:02:10 +13:00
|
|
|
}
|
|
|
|
|
|
2017-08-23 08:05:00 +12:00
|
|
|
handleKeyDown(e){
|
2016-10-27 13:34:22 +13:00
|
|
|
|
2017-08-11 08:14:52 +12:00
|
|
|
// When we're focussed on certian elements (like form input fields), don't fire any shortcuts
|
|
|
|
|
var ignoreNodes = ['INPUT', 'TEXTAREA']
|
|
|
|
|
if (ignoreNodes.indexOf(e.target.nodeName) > -1){
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-23 08:05:00 +12:00
|
|
|
var tracks_keys = this.digestTracksKeys()
|
2017-08-11 08:14:52 +12:00
|
|
|
|
|
|
|
|
switch(e.keyCode){
|
2016-10-27 13:02:10 +13:00
|
|
|
case 13: // enter
|
2017-08-23 08:05:00 +12:00
|
|
|
if (tracks_keys && tracks_keys.length > 0){
|
|
|
|
|
this.playTracks();
|
|
|
|
|
}
|
2016-10-27 13:02:10 +13:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 46: // delete
|
2017-08-23 08:05:00 +12:00
|
|
|
if (tracks_keys && tracks_keys.length > 0){
|
|
|
|
|
this.removeTracks();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 65: // a
|
2017-10-31 08:43:29 +13:00
|
|
|
if ((e.ctrlKey || e.metaKey)){
|
2017-08-23 08:05:00 +12:00
|
|
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
|
|
// Select all our tracks
|
|
|
|
|
var all_tracks = []
|
|
|
|
|
for (var i = 0; i < this.props.tracks.length; i++){
|
|
|
|
|
all_tracks.push(this.buildTrackKey(this.props.tracks[i], i))
|
|
|
|
|
}
|
|
|
|
|
this.props.uiActions.setSelectedTracks(all_tracks)
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
2016-10-27 13:02:10 +13:00
|
|
|
break;
|
|
|
|
|
}
|
2016-10-03 14:44:27 +13:00
|
|
|
}
|
|
|
|
|
|
2017-07-22 06:36:47 +12:00
|
|
|
handleDrag(e,track_key){
|
|
|
|
|
|
|
|
|
|
let selected_tracks = []
|
|
|
|
|
|
|
|
|
|
// Dragging a non-selected track. We need to deselect everything
|
|
|
|
|
// else and select only this track
|
|
|
|
|
if (!this.props.selected_tracks.includes(track_key)){
|
|
|
|
|
this.props.uiActions.setSelectedTracks([track_key])
|
|
|
|
|
selected_tracks = this.digestTracksKeys([track_key])
|
|
|
|
|
} else {
|
|
|
|
|
selected_tracks = this.digestTracksKeys()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let selected_tracks_indexes = helpers.arrayOf('index',selected_tracks)
|
|
|
|
|
|
|
|
|
|
this.props.uiActions.dragStart(
|
|
|
|
|
e,
|
|
|
|
|
this.props.context,
|
|
|
|
|
this.props.uri,
|
|
|
|
|
selected_tracks,
|
|
|
|
|
selected_tracks_indexes
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleDrop(e,track_key){
|
|
|
|
|
if (this.props.dragger && this.props.dragger.active){
|
|
|
|
|
|
|
|
|
|
// if this tracklist handles sorting, handle it
|
|
|
|
|
if (this.props.reorderTracks !== undefined){
|
|
|
|
|
let indexes = this.props.dragger.victims_indexes
|
|
|
|
|
let tracks = this.digestTracksKeys([track_key])
|
|
|
|
|
return this.props.reorderTracks(indexes, tracks[0].index)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this.touch_dragging_tracks_keys = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleTouchDrag(e,track_key){
|
|
|
|
|
let selected_tracks = []
|
|
|
|
|
|
|
|
|
|
// Drag initiated on a selected track
|
|
|
|
|
if (this.props.selected_tracks.includes(track_key)){
|
|
|
|
|
|
|
|
|
|
// They're all dragging
|
|
|
|
|
this.touch_dragging_tracks_keys = this.props.selected_tracks
|
|
|
|
|
|
|
|
|
|
// Not already selected
|
|
|
|
|
} else {
|
|
|
|
|
this.touch_dragging_tracks_keys = [track_key]
|
|
|
|
|
this.props.uiActions.setSelectedTracks([track_key])
|
2017-07-17 09:13:12 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleTouchMove(e){
|
2017-07-22 06:36:47 +12:00
|
|
|
if (this.touch_dragging_tracks_keys){
|
|
|
|
|
|
2017-12-18 08:48:36 +13:00
|
|
|
let touch = e.touches[0];
|
|
|
|
|
let over = $(document.elementFromPoint(touch.clientX, touch.clientY));
|
2017-07-18 08:26:50 +12:00
|
|
|
if (!over.is('.track')){
|
2017-12-18 08:48:36 +13:00
|
|
|
over = over.closest('.track');
|
2017-07-18 08:26:50 +12:00
|
|
|
}
|
2017-12-18 08:48:36 +13:00
|
|
|
$(document).find('.touch-drag-hover').removeClass('touch-drag-hover');
|
2017-07-18 08:26:50 +12:00
|
|
|
if (over.length > 0){
|
2017-12-18 08:48:36 +13:00
|
|
|
over.addClass('touch-drag-hover');
|
2017-07-18 08:26:50 +12:00
|
|
|
}
|
2017-07-22 06:36:47 +12:00
|
|
|
|
2017-12-18 08:48:36 +13:00
|
|
|
e.returnValue = false;
|
|
|
|
|
e.cancelBubble = true;
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
return false;
|
2017-07-17 09:13:12 +12:00
|
|
|
}
|
2016-12-06 16:54:48 +13:00
|
|
|
}
|
|
|
|
|
|
2017-07-22 06:36:47 +12:00
|
|
|
handleTouchEnd(e){
|
|
|
|
|
if (this.touch_dragging_tracks_keys){
|
2017-12-18 08:48:36 +13:00
|
|
|
let touch = e.changedTouches[0];
|
|
|
|
|
let over = $(document.elementFromPoint(touch.clientX, touch.clientY));
|
2017-07-18 08:26:50 +12:00
|
|
|
if (!over.is('.track')){
|
2017-12-18 08:48:36 +13:00
|
|
|
over = over.closest('.track');
|
2017-07-18 08:26:50 +12:00
|
|
|
}
|
|
|
|
|
if (over.length > 0){
|
2017-12-07 16:54:28 +13:00
|
|
|
let siblings = over.parent().children('.track');
|
|
|
|
|
let dropped_at = siblings.index(over) - 1;
|
2017-07-23 08:50:15 +12:00
|
|
|
|
2017-07-22 06:36:47 +12:00
|
|
|
if (this.props.reorderTracks !== undefined){
|
2017-12-07 16:54:28 +13:00
|
|
|
this.props.reorderTracks(helpers.arrayOf('index',this.digestTracksKeys()),dropped_at);
|
|
|
|
|
this.props.uiActions.setSelectedTracks([]);
|
2017-07-18 08:26:50 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-18 08:48:36 +13:00
|
|
|
$(document).find('.touch-drag-hover').removeClass('touch-drag-hover');
|
|
|
|
|
$('body').removeClass('touch-dragging');
|
2017-07-17 09:13:12 +12:00
|
|
|
}
|
2017-07-22 06:36:47 +12:00
|
|
|
|
2017-12-18 08:48:36 +13:00
|
|
|
this.touch_dragging_tracks_keys = false;
|
2016-12-06 16:54:48 +13:00
|
|
|
}
|
|
|
|
|
|
2017-12-20 16:33:38 +13:00
|
|
|
handleTap(e, track_key){
|
|
|
|
|
this.updateSelection(e, track_key, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleDoubleTap(e,track_key){
|
|
|
|
|
this.playTracks([track_key]);
|
|
|
|
|
this.updateSelection(e, track_key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleClick(e, track_key){
|
|
|
|
|
this.updateSelection(e, track_key);
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-21 22:56:28 +12:00
|
|
|
handleDoubleClick(e,track_key){
|
2017-12-06 17:02:11 +13:00
|
|
|
if (this.props.context_menu){
|
|
|
|
|
this.props.uiActions.hideContextMenu();
|
|
|
|
|
}
|
2017-12-20 16:33:38 +13:00
|
|
|
this.playTracks([track_key]);
|
|
|
|
|
this.updateSelection(e, track_key);
|
2016-11-16 14:58:08 +13:00
|
|
|
}
|
|
|
|
|
|
2017-12-18 08:48:36 +13:00
|
|
|
handleContextMenu(e, track_key = null){
|
2017-12-20 16:33:38 +13:00
|
|
|
|
|
|
|
|
// Do our best to stop any flow-on events
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
e.cancelBubble = true;
|
|
|
|
|
|
2017-12-18 08:48:36 +13:00
|
|
|
let selected_tracks = this.props.selected_tracks;
|
|
|
|
|
|
2017-07-25 09:22:15 +12:00
|
|
|
// Not already selected, so select it prior to triggering menu
|
2017-07-26 15:24:18 +12:00
|
|
|
if (track_key && !selected_tracks.includes(track_key)){
|
2017-12-18 08:48:36 +13:00
|
|
|
selected_tracks = [track_key];
|
|
|
|
|
this.props.uiActions.setSelectedTracks(selected_tracks);
|
2017-07-25 09:22:15 +12:00
|
|
|
}
|
|
|
|
|
|
2017-12-18 08:48:36 +13:00
|
|
|
let selected_tracks_digested = this.digestTracksKeys(selected_tracks);
|
|
|
|
|
let selected_tracks_uris = helpers.arrayOf('uri',selected_tracks_digested);
|
|
|
|
|
let selected_tracks_indexes = helpers.arrayOf('index',selected_tracks_digested);
|
2017-05-18 09:17:55 +12:00
|
|
|
|
2017-07-22 06:36:47 +12:00
|
|
|
let data = {
|
2017-01-29 16:25:05 +13:00
|
|
|
e: e,
|
2017-03-13 21:19:09 +13:00
|
|
|
context: (this.props.context ? this.props.context+'-track' : 'track'),
|
2017-02-14 12:13:07 +13:00
|
|
|
tracklist_uri: (this.props.uri ? this.props.uri : null),
|
2017-07-25 09:22:15 +12:00
|
|
|
items: selected_tracks_digested,
|
2017-07-22 06:36:47 +12:00
|
|
|
uris: selected_tracks_uris,
|
|
|
|
|
indexes: selected_tracks_indexes
|
2016-11-16 14:58:08 +13:00
|
|
|
}
|
2017-12-07 16:54:28 +13:00
|
|
|
|
2017-11-08 08:44:56 +13:00
|
|
|
this.props.uiActions.showContextMenu(data);
|
2017-01-29 16:25:05 +13:00
|
|
|
}
|
|
|
|
|
|
2017-12-20 16:33:38 +13:00
|
|
|
updateSelection(e, track_key, touched = false){
|
2017-12-18 08:48:36 +13:00
|
|
|
let selected_tracks = this.props.selected_tracks;
|
2017-07-21 22:56:28 +12:00
|
|
|
|
2017-12-07 16:54:28 +13:00
|
|
|
if ((e.ctrlKey || e.metaKey) || touched){
|
2016-10-17 22:00:29 +13:00
|
|
|
|
2017-07-21 22:56:28 +12:00
|
|
|
// Already selected, so unselect it
|
|
|
|
|
if (selected_tracks.includes(track_key)){
|
2017-12-18 08:48:36 +13:00
|
|
|
var index = selected_tracks.indexOf(track_key);
|
|
|
|
|
selected_tracks.splice(index, 1);
|
2016-10-17 22:00:29 +13:00
|
|
|
|
2017-07-21 22:56:28 +12:00
|
|
|
// Not selected, so add it
|
2017-02-02 09:06:15 +13:00
|
|
|
} else {
|
2017-12-18 08:48:36 +13:00
|
|
|
selected_tracks.push(track_key);
|
2017-02-02 09:06:15 +13:00
|
|
|
}
|
2016-10-17 22:00:29 +13:00
|
|
|
|
2017-07-21 22:56:28 +12:00
|
|
|
} else if (e.shiftKey){
|
2016-10-17 22:00:29 +13:00
|
|
|
|
2017-12-18 08:48:36 +13:00
|
|
|
let last_selected_track = this.digestTracksKeys(selected_tracks[selected_tracks.length-1]);
|
|
|
|
|
let last_selected_track_index = last_selected_track.index;
|
|
|
|
|
let newly_selected_track = this.digestTracksKeys(track_key);
|
|
|
|
|
let newly_selected_track_index = newly_selected_track.index;
|
2016-10-17 22:00:29 +13:00
|
|
|
|
2017-07-21 22:56:28 +12:00
|
|
|
// We've selected a track further down the list,
|
|
|
|
|
// so proceed normally
|
|
|
|
|
if (last_selected_track_index < newly_selected_track_index){
|
2017-12-18 08:48:36 +13:00
|
|
|
var start = last_selected_track_index + 1;
|
|
|
|
|
var end = newly_selected_track_index;
|
2016-10-17 22:00:29 +13:00
|
|
|
|
2017-07-21 22:56:28 +12:00
|
|
|
// Selected a track up the list, so
|
|
|
|
|
// our last selected is the END of our range
|
|
|
|
|
} else {
|
2017-12-18 08:48:36 +13:00
|
|
|
var start = newly_selected_track_index;
|
|
|
|
|
var end = last_selected_track_index - 1;
|
2017-07-21 22:56:28 +12:00
|
|
|
}
|
2016-10-17 22:00:29 +13:00
|
|
|
|
2017-07-21 22:56:28 +12:00
|
|
|
if (start !== false && start >= 0 && end !== false && end >= 0){
|
|
|
|
|
for (let i = start; i <= end; i++){
|
2017-12-18 08:48:36 +13:00
|
|
|
selected_tracks.push(this.buildTrackKey(this.props.tracks[i], i));
|
2017-07-21 22:56:28 +12:00
|
|
|
}
|
2016-10-17 22:00:29 +13:00
|
|
|
}
|
2016-11-15 13:34:55 +13:00
|
|
|
|
2017-07-21 22:56:28 +12:00
|
|
|
// Regular, unmodified left click
|
|
|
|
|
} else {
|
2017-12-18 08:48:36 +13:00
|
|
|
selected_tracks = [track_key];
|
2016-10-17 22:00:29 +13:00
|
|
|
}
|
|
|
|
|
|
2017-12-07 16:54:28 +13:00
|
|
|
this.props.uiActions.setSelectedTracks(selected_tracks);
|
2017-04-10 21:00:05 +12:00
|
|
|
}
|
|
|
|
|
|
2016-11-16 14:58:08 +13:00
|
|
|
isRightClick(e){
|
2017-12-18 08:48:36 +13:00
|
|
|
if ('which' in e ){
|
2016-11-16 14:58:08 +13:00
|
|
|
return e.which == 3
|
2017-12-18 08:48:36 +13:00
|
|
|
} else if ('button' in e){
|
|
|
|
|
return e.button == 2;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2016-10-27 10:02:12 +13:00
|
|
|
}
|
|
|
|
|
|
2017-12-20 16:33:38 +13:00
|
|
|
playTracks(tracks_keys = null){
|
|
|
|
|
if (tracks_keys !== null){
|
|
|
|
|
var selected_tracks = this.digestTracksKeys(tracks_keys);
|
|
|
|
|
} else {
|
|
|
|
|
var selected_tracks = this.digestTracksKeys();
|
|
|
|
|
}
|
|
|
|
|
var selected_tracks_indexes = helpers.arrayOf('index', selected_tracks);
|
2017-12-06 17:02:11 +13:00
|
|
|
|
|
|
|
|
if (selected_tracks.length <= 0){
|
2018-02-23 09:35:38 +13:00
|
|
|
return this.props.uiActions.createNotification({content: 'No tracks selected', type: 'bad'});
|
2017-12-06 17:02:11 +13:00
|
|
|
}
|
2017-07-26 09:04:47 +12:00
|
|
|
|
|
|
|
|
// Our parent handles playing
|
|
|
|
|
if (this.props.playTracks !== undefined){
|
2017-12-06 17:02:11 +13:00
|
|
|
return this.props.playTracks(selected_tracks);
|
2017-07-26 09:04:47 +12:00
|
|
|
|
|
|
|
|
// Default to playing the URIs
|
|
|
|
|
} else {
|
2017-12-06 17:02:11 +13:00
|
|
|
let selected_tracks_uris = helpers.arrayOf('uri',selected_tracks);
|
|
|
|
|
return this.props.mopidyActions.playURIs(selected_tracks_uris, this.props.uri);
|
2017-07-26 09:04:47 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
removeTracks(){
|
|
|
|
|
|
|
|
|
|
// Our parent handles removal
|
|
|
|
|
if (this.props.removeTracks !== undefined){
|
|
|
|
|
let selected_tracks = this.digestTracksKeys()
|
|
|
|
|
let selected_tracks_indexes = helpers.arrayOf('index',selected_tracks)
|
|
|
|
|
return this.props.removeTracks(selected_tracks_indexes)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// By default, do nothing
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Build the track key
|
|
|
|
|
* This is our unique reference to a track in a particular tracklist
|
|
|
|
|
*
|
|
|
|
|
* @param track = Track obj
|
|
|
|
|
* @param index = int (position of track in tracklist)
|
|
|
|
|
* @return string
|
|
|
|
|
**/
|
|
|
|
|
buildTrackKey(track, index){
|
|
|
|
|
let key = index
|
2017-08-29 08:35:26 +12:00
|
|
|
key += '@@'+(track.tlid ? track.tlid : 'none')
|
|
|
|
|
key += '@@'+track.uri
|
|
|
|
|
key += '@@'+(this.props.uri ? this.props.uri : 'none')
|
|
|
|
|
key += '@@'+(this.props.context ? this.props.context : 'none')
|
2017-07-26 09:04:47 +12:00
|
|
|
return key
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-15 13:34:55 +13:00
|
|
|
|
2017-07-22 06:36:47 +12:00
|
|
|
/**
|
|
|
|
|
* Digest our selected tracks
|
|
|
|
|
*
|
2017-07-26 09:04:47 +12:00
|
|
|
* @param tracks = mixed (defaults to stored value)
|
2017-07-22 06:36:47 +12:00
|
|
|
* @param indexex_only = boolean (do we just want an array of indexes)
|
|
|
|
|
* @return mixed
|
|
|
|
|
**/
|
|
|
|
|
digestTracksKeys(keys = this.props.selected_tracks, indexes_only = false){
|
2017-07-26 09:04:47 +12:00
|
|
|
if (!keys){
|
2017-07-21 22:56:28 +12:00
|
|
|
return false
|
2016-10-16 12:37:37 +13:00
|
|
|
}
|
|
|
|
|
|
2017-07-26 09:04:47 +12:00
|
|
|
// Accommodate a single key
|
|
|
|
|
let singleton = false
|
|
|
|
|
if (!(keys instanceof Array)){
|
|
|
|
|
singleton = true
|
|
|
|
|
keys = [keys]
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-21 22:56:28 +12:00
|
|
|
// Construct a basic track object, based on our unique track key
|
|
|
|
|
// This is enough to perform interactions (dragging, selecting, etc)
|
2017-07-22 06:36:47 +12:00
|
|
|
let array = []
|
|
|
|
|
for (let i = 0; i < keys.length; i++){
|
2017-08-29 08:35:26 +12:00
|
|
|
let key = keys[i].split('@@')
|
2017-07-21 22:56:28 +12:00
|
|
|
|
|
|
|
|
if (indexes_only){
|
2017-07-22 06:36:47 +12:00
|
|
|
array.push(key[0])
|
2017-07-21 22:56:28 +12:00
|
|
|
|
|
|
|
|
} else {
|
2017-07-22 06:36:47 +12:00
|
|
|
array.push({
|
|
|
|
|
index: parseInt(key[0]),
|
2017-07-26 09:04:47 +12:00
|
|
|
tlid: parseInt(key[1]),
|
|
|
|
|
uri: key[2],
|
|
|
|
|
context: key[3],
|
|
|
|
|
context_uri: key[4]
|
2017-07-21 22:56:28 +12:00
|
|
|
})
|
|
|
|
|
}
|
2016-11-11 12:12:50 +13:00
|
|
|
}
|
2017-07-21 22:56:28 +12:00
|
|
|
|
2017-07-26 09:04:47 +12:00
|
|
|
if (singleton && array.length > 0){
|
|
|
|
|
return array[0]
|
2017-07-22 06:36:47 +12:00
|
|
|
} else {
|
2017-07-26 09:04:47 +12:00
|
|
|
return array
|
2017-07-22 06:36:47 +12:00
|
|
|
}
|
2016-10-19 14:09:34 +13:00
|
|
|
}
|
|
|
|
|
|
2016-12-16 08:32:21 +13:00
|
|
|
|
2016-10-06 16:38:06 +13:00
|
|
|
render(){
|
2018-11-07 17:01:18 +13:00
|
|
|
if (!this.props.tracks || Object.prototype.toString.call(this.props.tracks) !== '[object Array]' ){
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2016-11-08 13:36:13 +13:00
|
|
|
|
2017-03-13 13:17:11 +13:00
|
|
|
var className = 'list track-list '+this.props.context
|
|
|
|
|
if (this.props.className){
|
|
|
|
|
className += ' '+this.props.className
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 13:36:13 +13:00
|
|
|
return (
|
2017-03-13 13:17:11 +13:00
|
|
|
<div className={className}>
|
2016-11-08 13:36:13 +13:00
|
|
|
{
|
2017-07-21 22:56:28 +12:00
|
|
|
this.props.tracks.map(
|
2016-11-08 13:36:13 +13:00
|
|
|
(track, index) => {
|
2017-11-17 20:25:43 +13:00
|
|
|
let track_key = this.buildTrackKey(track, index);
|
|
|
|
|
track.key = track_key;
|
2017-07-17 09:13:12 +12:00
|
|
|
return (
|
|
|
|
|
<Track
|
2017-03-23 11:51:04 +13:00
|
|
|
show_source_icon={this.props.show_source_icon}
|
2017-07-21 22:56:28 +12:00
|
|
|
key={track_key}
|
2017-12-18 08:48:36 +13:00
|
|
|
mini_zones={this.props.slim_mode || helpers.isTouchDevice()}
|
2016-11-08 13:36:13 +13:00
|
|
|
track={track}
|
2017-02-14 20:24:35 +13:00
|
|
|
context={this.props.context}
|
2017-07-22 06:36:47 +12:00
|
|
|
can_sort={this.props.context == 'queue' || this.props.context == 'editable-playlist'}
|
2017-07-21 22:56:28 +12:00
|
|
|
selected={this.props.selected_tracks.includes(track_key)}
|
2017-07-22 06:36:47 +12:00
|
|
|
dragger={this.props.dragger}
|
2017-12-20 16:33:38 +13:00
|
|
|
handleClick={(e) => this.handleClick(e, track_key)}
|
2017-07-21 22:56:28 +12:00
|
|
|
handleDoubleClick={e => this.handleDoubleClick(e, track_key)}
|
2017-07-25 09:22:15 +12:00
|
|
|
handleContextMenu={e => this.handleContextMenu(e, track_key)}
|
2017-07-22 06:36:47 +12:00
|
|
|
handleDrag={e => this.handleDrag(e, track_key)}
|
|
|
|
|
handleDrop={e => this.handleDrop(e, track_key)}
|
2017-12-20 16:33:38 +13:00
|
|
|
handleTap={e => this.handleTap(e, track_key)}
|
|
|
|
|
handleDoubleTap={e => this.handleDoubleTap(e, track_key)}
|
2017-07-22 06:36:47 +12:00
|
|
|
handleTouchDrag={e => this.handleTouchDrag(e, track_key)}
|
2017-07-17 09:13:12 +12:00
|
|
|
/>
|
|
|
|
|
)
|
2016-11-08 13:36:13 +13:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}
|
2016-11-25 22:49:34 +13:00
|
|
|
</div>
|
2016-11-08 13:36:13 +13:00
|
|
|
);
|
2016-10-03 14:44:27 +13:00
|
|
|
}
|
2016-10-14 18:15:34 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Export our component
|
|
|
|
|
*
|
|
|
|
|
* We also integrate our global store, using connect()
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
const mapStateToProps = (state, ownProps) => {
|
2016-11-09 13:18:03 +13:00
|
|
|
return {
|
2017-08-23 07:39:33 +12:00
|
|
|
slim_mode: state.ui.slim_mode,
|
2017-07-21 22:56:28 +12:00
|
|
|
selected_tracks: state.ui.selected_tracks,
|
2016-11-15 17:08:21 +13:00
|
|
|
dragger: state.ui.dragger,
|
2017-08-02 10:53:30 +12:00
|
|
|
current_track: state.core.current_track,
|
2016-11-09 13:18:03 +13:00
|
|
|
context_menu: state.ui.context_menu
|
|
|
|
|
}
|
2016-10-14 18:15:34 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const mapDispatchToProps = (dispatch) => {
|
|
|
|
|
return {
|
2016-10-27 10:02:12 +13:00
|
|
|
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
|
|
|
|
uiActions: bindActionCreators(uiActions, dispatch)
|
2016-10-14 18:15:34 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(TrackList)
|