Files
Iris/src/js/components/TrackList.js

199 lines
4.7 KiB
JavaScript
Raw Normal View History

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'
import * as mopidyActions from '../services/mopidy/actions'
2016-10-27 10:02:12 +13:00
import * as uiActions from '../services/ui/actions'
2016-10-14 18:15:34 +13:00
2016-10-03 21:21:14 +13:00
import Track from './Track'
2016-10-03 14:44:27 +13:00
2016-10-14 18:15:34 +13:00
class TrackList extends React.Component{
2016-10-03 14:44:27 +13:00
constructor(props) {
super(props);
2016-10-06 16:38:06 +13:00
this.state = {
tracks: this.props.tracks,
lastSelectedTrack: false
2016-10-06 16:38:06 +13:00
}
2016-10-27 13:02:10 +13:00
this.handleKeyUp = this.handleKeyUp.bind(this)
}
componentWillMount(){
window.addEventListener("keyup", this.handleKeyUp, false);
}
componentWillUnmount(){
window.removeEventListener("keyup", this.handleKeyUp, false);
}
handleKeyUp(e){
if( this.selectedTracks().length <= 0 ) return;
2016-10-27 13:02:10 +13:00
switch(e.keyCode){
case 13: // enter
this.playTracks();
2016-10-27 13:02:10 +13:00
break;
case 46: // delete
this.removeTracks();
2016-10-27 13:02:10 +13:00
break;
}
2016-10-03 14:44:27 +13:00
}
componentWillReceiveProps( nextProps ){
this.setState({ tracks: nextProps.tracks });
}
handleClick( e, index ){
2016-10-27 10:02:12 +13:00
if( this.props.ui.context_menu.show ) this.props.uiActions.hideContextMenu();
2016-10-06 16:38:06 +13:00
var tracks = this.state.tracks;
if( e.ctrlKey ){
tracks[index].selected = !tracks[index].selected;
}else if( e.shiftKey ){
if( this.state.lastSelectedTrack < index ){
var start = this.state.lastSelectedTrack;
var end = index;
}else{
var start = index;
var end = this.state.lastSelectedTrack;
}
for( var i = start; i <= end; i++ ){
tracks[i].selected = true;
}
}else{
for( var i = 0; i < tracks.length; i++ ){
tracks[i].selected = false;
}
tracks[index].selected = !tracks[index].selected;
}
this.setState({ tracks: tracks, lastSelectedTrack: index });
}
handleDoubleClick( e, index ){
2016-10-27 10:02:12 +13:00
if( this.props.ui.context_menu.show ) this.props.uiActions.hideContextMenu();
this.playTracks()
}
2016-10-27 10:02:12 +13:00
handleContextMenu( e, index ){
var data = {
selected_tracks: this.selectedTracks()
}
this.props.uiActions.showContextMenu( e, this.props.context, data )
}
2016-10-19 14:09:34 +13:00
selectedTracks(){
function isSelected( track ){
return ( typeof(track.selected) !== 'undefined' && track.selected );
}
2016-10-19 14:09:34 +13:00
return this.state.tracks.filter(isSelected)
}
playTracks(){
var tracks = this.selectedTracks();
// if we've got a specific action, run it
if( typeof(this.props.playTracks) !== 'undefined' ){
return this.props.playTracks( tracks );
}
// default to playing a bunch of uris
var uris = [];
for( var i = 0; i < tracks.length; i++ ){
uris.push( tracks[i].uri )
}
return this.props.mopidyActions.playTracks( uris )
2016-10-19 14:09:34 +13:00
}
removeTracks(){
2016-10-03 14:44:27 +13:00
var tracks = this.selectedTracks();
// if we've got a specific action, run it
if( typeof(this.props.removeTracks) !== 'undefined' ){
return this.props.removeTracks( tracks );
}
// by default, do nothing
2016-10-06 16:38:06 +13:00
}
render(){
let self = this;
if( this.state.tracks ){
2016-10-03 14:44:27 +13:00
return (
2016-10-27 10:02:12 +13:00
<ul>
<li className="list-item header track">
<span className="col name">Name</span>
<span className="col artists">Artists</span>
<span className="col album">Album</span>
<span className="col duration">Duration</span>
</li>
{
this.state.tracks.map(
(track, index) => {
// flatten nested track objects (as in the case of TlTracks)
if( typeof(track.track) !== 'undefined' ){
// see if we're the current tlTrack
// TODO: figure out why this isn't fired when the tracklist changes
2016-10-27 13:02:10 +13:00
if( self.props.mopidy.current_tltrack && self.props.mopidy.current_tltrack.tlid == track.tlid ){
2016-10-27 10:02:12 +13:00
track.playing = true;
}else{
track.playing = false;
}
2016-10-22 19:13:06 +13:00
2016-10-27 10:02:12 +13:00
for( var property in track.track ){
if( track.track.hasOwnProperty(property) ){
track[property] = track.track[property]
2016-10-06 16:38:06 +13:00
}
}
2016-10-03 21:21:14 +13:00
}
2016-10-27 10:02:12 +13:00
return <Track
2016-11-06 18:29:49 +13:00
show_source_icon={ this.props.show_source_icon }
2016-10-27 10:02:12 +13:00
key={index+'_'+track.uri}
track={track}
handleDoubleClick={(e) => self.handleDoubleClick(e, index)}
handleClick={(e) => self.handleClick(e, index)}
handleContextMenu={(e) => self.handleContextMenu(e, index)} />
}
)
}
</ul>
2016-10-03 14:44:27 +13:00
);
}
return null;
}
2016-10-14 18:15:34 +13:00
}
/**
* Export our component
*
* We also integrate our global store, using connect()
**/
const mapStateToProps = (state, ownProps) => {
return state;
}
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)