React slider
This commit is contained in:
@ -108,7 +108,7 @@ class ContextMenu extends React.Component{
|
||||
case 'playlist':
|
||||
case 'editable-playlist':
|
||||
context.nice_name = 'playlist';
|
||||
break
|
||||
break;
|
||||
|
||||
case 'track':
|
||||
case 'queue-track':
|
||||
@ -116,7 +116,7 @@ class ContextMenu extends React.Component{
|
||||
case 'editable-playlist-track':
|
||||
context.nice_name = 'track';
|
||||
context.is_track = true;
|
||||
break
|
||||
break;
|
||||
}
|
||||
|
||||
// Consider the object(s) themselves
|
||||
@ -138,21 +138,21 @@ class ContextMenu extends React.Component{
|
||||
|
||||
inLibrary(item = null){
|
||||
if (!item){
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (helpers.uriType(item.uri)){
|
||||
case 'artist':
|
||||
return (this.props.spotify_library_artists && this.props.spotify_library_artists.indexOf(item.uri) > -1)
|
||||
break
|
||||
return (this.props.spotify_library_artists && this.props.spotify_library_artists.indexOf(item.uri) > -1);
|
||||
break;
|
||||
case 'album':
|
||||
return (this.props.spotify_library_albums && this.props.spotify_library_albums.indexOf(item.uri) > -1)
|
||||
break
|
||||
return (this.props.spotify_library_albums && this.props.spotify_library_albums.indexOf(item.uri) > -1);
|
||||
break;
|
||||
case 'playlist':
|
||||
return (this.props.spotify_library_playlists && this.props.spotify_library_playlists.indexOf(item.uri) > -1)
|
||||
break
|
||||
return (this.props.spotify_library_playlists && this.props.spotify_library_playlists.indexOf(item.uri) > -1);
|
||||
break;
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,7 +191,7 @@ class ContextMenu extends React.Component{
|
||||
playQueueItem(e){
|
||||
this.props.uiActions.hideContextMenu()
|
||||
var tracks = this.props.menu.items;
|
||||
this.props.mopidyActions.changeTrack(tracks[0].tlid )
|
||||
this.props.mopidyActions.changeTrack(tracks[0].tlid);
|
||||
}
|
||||
|
||||
removeFromQueue(e){
|
||||
@ -201,102 +201,102 @@ class ContextMenu extends React.Component{
|
||||
for(var i = 0; i < tracks.length; i++){
|
||||
tracks_tlids.push(tracks[i].tlid );
|
||||
}
|
||||
this.props.mopidyActions.removeTracks(tracks_tlids )
|
||||
this.props.mopidyActions.removeTracks(tracks_tlids);
|
||||
}
|
||||
|
||||
playURIs(e){
|
||||
this.props.uiActions.hideContextMenu()
|
||||
this.props.mopidyActions.playURIs(this.props.menu.uris, this.props.menu.tracklist_uri)
|
||||
this.props.uiActions.hideContextMenu();
|
||||
this.props.mopidyActions.playURIs(this.props.menu.uris, this.props.menu.tracklist_uri);
|
||||
}
|
||||
|
||||
playPlaylist(e){
|
||||
this.props.uiActions.hideContextMenu()
|
||||
this.props.mopidyActions.playPlaylist(this.props.menu.uris[0])
|
||||
this.props.uiActions.hideContextMenu();
|
||||
this.props.mopidyActions.playPlaylist(this.props.menu.uris[0]);
|
||||
}
|
||||
|
||||
playArtistTopTracks(e){
|
||||
this.props.uiActions.hideContextMenu()
|
||||
this.props.spotifyActions.playArtistTopTracks(this.props.menu.uris[0])
|
||||
this.props.uiActions.hideContextMenu();
|
||||
this.props.spotifyActions.playArtistTopTracks(this.props.menu.uris[0]);
|
||||
}
|
||||
|
||||
addToQueue(e, next = false){
|
||||
this.props.uiActions.hideContextMenu()
|
||||
this.props.mopidyActions.enqueueURIs(this.props.menu.uris, this.props.menu.tracklist_uri, next)
|
||||
this.props.uiActions.hideContextMenu();
|
||||
this.props.mopidyActions.enqueueURIs(this.props.menu.uris, this.props.menu.tracklist_uri, next);
|
||||
}
|
||||
|
||||
addTracksToPlaylist(e, playlist_uri){
|
||||
this.props.uiActions.hideContextMenu()
|
||||
this.props.coreActions.addTracksToPlaylist(playlist_uri, this.props.menu.uris)
|
||||
this.props.uiActions.hideContextMenu();
|
||||
this.props.coreActions.addTracksToPlaylist(playlist_uri, this.props.menu.uris);
|
||||
}
|
||||
|
||||
toggleLoved(e, is_loved){
|
||||
this.props.uiActions.hideContextMenu()
|
||||
this.props.uiActions.hideContextMenu();
|
||||
if (is_loved){
|
||||
this.props.lastfmActions.unloveTrack(this.props.menu.items[0].uri)
|
||||
this.props.lastfmActions.unloveTrack(this.props.menu.items[0].uri);
|
||||
} else {
|
||||
this.props.lastfmActions.loveTrack(this.props.menu.items[0].uri)
|
||||
this.props.lastfmActions.loveTrack(this.props.menu.items[0].uri);
|
||||
}
|
||||
}
|
||||
|
||||
unloveTrack(e){
|
||||
this.props.uiActions.hideContextMenu()
|
||||
this.props.lastfmActions.unloveTrack(this.props.menu.items[0])
|
||||
this.props.uiActions.hideContextMenu();
|
||||
this.props.lastfmActions.unloveTrack(this.props.menu.items[0]);
|
||||
}
|
||||
|
||||
removeFromPlaylist(e){
|
||||
this.props.uiActions.hideContextMenu()
|
||||
this.props.coreActions.removeTracksFromPlaylist(this.props.menu.tracklist_uri, this.props.menu.indexes)
|
||||
this.props.uiActions.hideContextMenu();
|
||||
this.props.coreActions.removeTracksFromPlaylist(this.props.menu.tracklist_uri, this.props.menu.indexes);
|
||||
}
|
||||
|
||||
deletePlaylist(e){
|
||||
this.props.uiActions.hideContextMenu()
|
||||
this.props.coreActions.deletePlaylist(this.props.menu.uris[0])
|
||||
this.props.uiActions.hideContextMenu();
|
||||
this.props.coreActions.deletePlaylist(this.props.menu.uris[0]);
|
||||
}
|
||||
|
||||
startRadio(e){
|
||||
this.props.uiActions.hideContextMenu()
|
||||
this.props.pusherActions.startRadio(this.props.menu.uris)
|
||||
this.props.uiActions.hideContextMenu();
|
||||
this.props.pusherActions.startRadio(this.props.menu.uris);
|
||||
}
|
||||
|
||||
goToRecommendations(e){
|
||||
this.props.uiActions.hideContextMenu()
|
||||
var uris_string = helpers.arrayOf('uri',this.props.menu.items).join(',')
|
||||
hashHistory.push(global.baseURL +'discover/recommendations/'+ uris_string )
|
||||
this.props.uiActions.hideContextMenu();
|
||||
var uris_string = helpers.arrayOf('uri',this.props.menu.items).join(',');
|
||||
hashHistory.push(global.baseURL +'discover/recommendations/'+ uris_string );
|
||||
}
|
||||
|
||||
goToArtist(e){
|
||||
if (!this.props.menu.items || this.props.menu.items.length <= 0 || !this.props.menu.items[0].artists || this.props.menu.items[0].artists.length <= 0){
|
||||
return null
|
||||
return null;
|
||||
} else {
|
||||
this.props.uiActions.hideContextMenu()
|
||||
hashHistory.push(global.baseURL +'artist/'+ this.props.menu.items[0].artists[0].uri )
|
||||
this.props.uiActions.hideContextMenu();
|
||||
hashHistory.push(global.baseURL +'artist/'+ this.props.menu.items[0].artists[0].uri);
|
||||
}
|
||||
}
|
||||
|
||||
goToAlbum(e){
|
||||
if (!this.props.menu.items || this.props.menu.items.length <= 0 || !this.props.menu.items[0].album){
|
||||
return null
|
||||
return null;
|
||||
} else {
|
||||
this.props.uiActions.hideContextMenu()
|
||||
hashHistory.push(global.baseURL +'album/'+ this.props.menu.items[0].album.uri )
|
||||
this.props.uiActions.hideContextMenu();
|
||||
hashHistory.push(global.baseURL +'album/'+ this.props.menu.items[0].album.uri);
|
||||
}
|
||||
}
|
||||
|
||||
goToUser(e){
|
||||
if (!this.props.menu.items || this.props.menu.items.length <= 0){
|
||||
return null
|
||||
return null;
|
||||
} else {
|
||||
this.props.uiActions.hideContextMenu()
|
||||
hashHistory.push(global.baseURL +'user/'+ this.props.menu.items[0].owner.uri )
|
||||
this.props.uiActions.hideContextMenu();
|
||||
hashHistory.push(global.baseURL +'user/'+ this.props.menu.items[0].owner.uri);
|
||||
}
|
||||
}
|
||||
|
||||
goToTrack(e){
|
||||
if (!this.props.menu.items || this.props.menu.items.length <= 0){
|
||||
return null
|
||||
return null;
|
||||
} else {
|
||||
this.props.uiActions.hideContextMenu()
|
||||
hashHistory.push(global.baseURL +'track/'+ encodeURIComponent(this.props.menu.items[0].uri))
|
||||
this.props.uiActions.hideContextMenu();
|
||||
hashHistory.push(global.baseURL +'track/'+ encodeURIComponent(this.props.menu.items[0].uri));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -923,7 +923,7 @@ export function getRecommendations(uris = [], limit = 20){
|
||||
// anyway so we can proceed in the meantime
|
||||
var artists_uris = []
|
||||
if (tracks.length > artists_ids.length && tracks.length > 10){
|
||||
while (artists_uris.length < 5){
|
||||
while (artists_uris.length < 6){
|
||||
var random_index = Math.round(Math.random() * (tracks.length - 1))
|
||||
var artist = tracks[random_index].artists[0]
|
||||
|
||||
@ -940,7 +940,7 @@ export function getRecommendations(uris = [], limit = 20){
|
||||
var albums = []
|
||||
var albums_uris = []
|
||||
if (tracks.length > 10){
|
||||
while (albums.length < 5){
|
||||
while (albums.length < 6){
|
||||
var random_index = Math.round(Math.random() * (tracks.length - 1))
|
||||
var album = tracks[random_index].album
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import FontAwesome from 'react-fontawesome'
|
||||
import InputRange from 'react-input-range';
|
||||
|
||||
import Header from '../../components/Header'
|
||||
import ArtistSentence from '../../components/ArtistSentence'
|
||||
@ -12,8 +13,12 @@ import TrackList from '../../components/TrackList'
|
||||
import Parallax from '../../components/Parallax'
|
||||
import AddSeedField from '../../components/AddSeedField'
|
||||
import URILink from '../../components/URILink'
|
||||
import ContextMenuTrigger from '../../components/ContextMenuTrigger'
|
||||
import RelatedArtists from '../../components/RelatedArtists'
|
||||
|
||||
import * as helpers from '../../helpers'
|
||||
import * as uiActions from '../../services/ui/actions'
|
||||
import * as mopidyActions from '../../services/mopidy/actions'
|
||||
import * as spotifyActions from '../../services/spotify/actions'
|
||||
|
||||
class Discover extends React.Component{
|
||||
@ -24,11 +29,15 @@ class Discover extends React.Component{
|
||||
this._autocomplete_timer = false
|
||||
|
||||
this.state = {
|
||||
seeds: [
|
||||
'spotify:genre:chill'
|
||||
],
|
||||
add_seed: '',
|
||||
adding_seed: false
|
||||
adding_seed: false,
|
||||
seeds: [],
|
||||
tunabilities: {
|
||||
loudness: {
|
||||
min: 0,
|
||||
max: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,12 +45,8 @@ class Discover extends React.Component{
|
||||
|
||||
// We have seeds provided in the URL
|
||||
if (this.props.params.seeds){
|
||||
this.handleURLSeeds(this.props.params.seeds)
|
||||
|
||||
// BAU
|
||||
} else {
|
||||
this.props.spotifyActions.getFavorites()
|
||||
}
|
||||
this.handleURLSeeds(this.props.params.seeds);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(newProps, newState){
|
||||
@ -50,17 +55,38 @@ class Discover extends React.Component{
|
||||
if (newProps.params.seeds != this.props.params.seeds){
|
||||
this.handleURLSeeds(newProps.params.seeds)
|
||||
}
|
||||
}
|
||||
|
||||
// When we've loaded favorite_artists.
|
||||
// This indirectly listens for when the action has
|
||||
// loaded new data.
|
||||
if (this.props.favorite_artists.length <= 0 && newProps.favorite_artists.length > 0){
|
||||
var initial_seeds = newProps.favorite_artists.sort(() => .5 - Math.random())
|
||||
initial_seeds = initial_seeds.slice(0,2)
|
||||
handleContextMenu(e){
|
||||
|
||||
this.setState({seeds: initial_seeds})
|
||||
this.getRecommendations(initial_seeds)
|
||||
var uri = 'iris:discover';
|
||||
if (this.state.seeds){
|
||||
uri += ':';
|
||||
for (var i = 0; i < this.state.seeds.length; i++){
|
||||
if (i > 0){
|
||||
uri += ',';
|
||||
}
|
||||
uri += this.state.seeds[i].split(':').join('_');
|
||||
}
|
||||
}
|
||||
|
||||
var tracks = [];
|
||||
if (this.props.recommendations.tracks_uris && this.props.tracks){
|
||||
for (var i = 0; i < this.props.recommendations.tracks_uris.length; i++){
|
||||
var uri = this.props.recommendations.tracks_uris[i];
|
||||
if (this.props.tracks.hasOwnProperty(uri)){
|
||||
tracks.push(this.props.tracks[uri]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var data = {
|
||||
e: e,
|
||||
context: 'track',
|
||||
items: tracks,
|
||||
uris: [uri]
|
||||
}
|
||||
this.props.uiActions.showContextMenu(data);
|
||||
}
|
||||
|
||||
handleURLSeeds(seeds_string = this.props.params.seeds){
|
||||
@ -87,12 +113,16 @@ class Discover extends React.Component{
|
||||
this.getRecommendations(seeds)
|
||||
}
|
||||
|
||||
getRecommendations(seeds = this.state.seeds){
|
||||
getRecommendations(seeds = this.state.seeds, tunabilities = this.state.tunabilities){
|
||||
if (seeds.length > 0){
|
||||
this.props.spotifyActions.getRecommendations(seeds, 50)
|
||||
this.props.spotifyActions.getRecommendations(seeds, 50, tunabilities)
|
||||
}
|
||||
}
|
||||
|
||||
playTracks(){
|
||||
this.props.mopidyActions.playURIs(this.props.recommendations.tracks_uris);
|
||||
}
|
||||
|
||||
removeSeed(index){
|
||||
var seeds = this.state.seeds
|
||||
seeds.splice(index,1)
|
||||
@ -168,6 +198,49 @@ class Discover extends React.Component{
|
||||
)
|
||||
}
|
||||
|
||||
setTunability(name, value){
|
||||
var tunabilities = this.state.tunabilities;
|
||||
tunabilities[name] = value;
|
||||
console.log(tunabilities);
|
||||
this.setState({ tunabilities: tunabilities });
|
||||
}
|
||||
|
||||
renderTunabilities(){
|
||||
|
||||
var tunabilities = [];
|
||||
for (var key in this.state.tunabilities){
|
||||
if (this.state.tunabilities.hasOwnProperty(key)){
|
||||
var tunability = {
|
||||
name: key,
|
||||
value: this.state.tunabilities[key]
|
||||
};
|
||||
tunabilities.push(tunability);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="tunabilities">
|
||||
{
|
||||
tunabilities.map(tunability => {
|
||||
return (
|
||||
<div className="field tunability range" key={tunability.name}>
|
||||
<label>
|
||||
{tunability.name}
|
||||
</label>
|
||||
<InputRange
|
||||
maxValue={100}
|
||||
minValue={0}
|
||||
value={tunability.value}
|
||||
onChange={value => this.setTunability(tunability.name, value)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderResults(){
|
||||
if (helpers.isLoading(this.props.load_queue,['spotify_recommendations'])){
|
||||
return (
|
||||
@ -177,16 +250,16 @@ class Discover extends React.Component{
|
||||
)
|
||||
}
|
||||
|
||||
if (!this.props.recommendations || typeof(this.props.recommendations.albums_uris) === 'undefined' || typeof(this.props.recommendations.artists_uris) === 'undefined'){
|
||||
if (!this.props.recommendations || this.props.recommendations.albums_uris === undefined || this.props.recommendations.artists_uris === undefined){
|
||||
return null;
|
||||
}
|
||||
|
||||
var albums = [];
|
||||
if (this.props.recommendations.albums_uris && this.props.albums){
|
||||
for (var i = 0; i < this.props.recommendations.albums_uris.length; i++){
|
||||
var uri = this.props.recommendations.albums_uris[i];
|
||||
if (this.props.albums.hasOwnProperty(uri)){
|
||||
albums.push(this.props.albums[uri]);
|
||||
var tracks = [];
|
||||
if (this.props.recommendations.tracks_uris && this.props.tracks){
|
||||
for (var i = 0; i < this.props.recommendations.tracks_uris.length; i++){
|
||||
var uri = this.props.recommendations.tracks_uris[i];
|
||||
if (this.props.tracks.hasOwnProperty(uri)){
|
||||
tracks.push(this.props.tracks[uri]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -201,35 +274,54 @@ class Discover extends React.Component{
|
||||
}
|
||||
}
|
||||
|
||||
var tracks = [];
|
||||
if (this.props.recommendations.tracks_uris && this.props.tracks){
|
||||
for (var i = 0; i < this.props.recommendations.tracks_uris.length; i++){
|
||||
var uri = this.props.recommendations.tracks_uris[i];
|
||||
if (this.props.tracks.hasOwnProperty(uri)){
|
||||
tracks.push(this.props.tracks[uri]);
|
||||
var albums = [];
|
||||
if (this.props.recommendations.albums_uris && this.props.albums){
|
||||
for (var i = 0; i < this.props.recommendations.albums_uris.length; i++){
|
||||
var uri = this.props.recommendations.albums_uris[i];
|
||||
if (this.props.albums.hasOwnProperty(uri)){
|
||||
albums.push(this.props.albums[uri]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var uri = 'iris:discover';
|
||||
if (this.props.params.seeds){
|
||||
uri += ':'+this.props.params.seeds.split(':').join('_');
|
||||
if (this.state.seeds){
|
||||
uri += ':';
|
||||
for (var i = 0; i < this.state.seeds.length; i++){
|
||||
if (i > 0){
|
||||
uri += ',';
|
||||
}
|
||||
uri += this.state.seeds[i].split(':').join('_');
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="content-wrapper recommendations-results">
|
||||
<section>
|
||||
<h4>Artists</h4>
|
||||
<ArtistGrid single_row artists={artists} />
|
||||
</section>
|
||||
<section>
|
||||
<h4>Albums</h4>
|
||||
<AlbumGrid single_row albums={albums} />
|
||||
</section>
|
||||
<section>
|
||||
<h4>Tracks</h4>
|
||||
<div className="content-wrapper recommendations-results cf">
|
||||
|
||||
<section className="col w70">
|
||||
<h4>
|
||||
Tracks
|
||||
<ContextMenuTrigger onTrigger={e => this.handleContextMenu(e)} />
|
||||
<button className="primary pull-right" onClick={e => this.playTracks(e)}>Play all</button>
|
||||
</h4>
|
||||
<TrackList className="discover-track-list" uri={uri} tracks={tracks} />
|
||||
</section>
|
||||
|
||||
<div className="col w5"></div>
|
||||
|
||||
<div className="col w25">
|
||||
<section>
|
||||
<h4>Artists</h4>
|
||||
<RelatedArtists artists={artists} />
|
||||
</section>
|
||||
<br />
|
||||
<br />
|
||||
<section>
|
||||
<h4>Albums</h4>
|
||||
<AlbumGrid className="mini" albums={albums} />
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -244,10 +336,10 @@ class Discover extends React.Component{
|
||||
<div className="liner">
|
||||
<h1>Explore new music</h1>
|
||||
<h2 className="grey-text">
|
||||
Add seeds below to build your sound
|
||||
{!this.props.params.seeds ? ". Let's start with two of your favorite artists." : null}
|
||||
Add seeds and musical properties below to build your sound
|
||||
</h2>
|
||||
{this.renderSeeds()}
|
||||
{this.renderTunabilities()}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -283,6 +375,8 @@ const mapStateToProps = (state, ownProps) => {
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,3 +38,4 @@
|
||||
@import 'views/discover';
|
||||
@import 'views/settings';
|
||||
|
||||
@import "../../node_modules/react-input-range/lib/css/index.css";
|
||||
@ -291,6 +291,11 @@
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
|
||||
h4 &,
|
||||
h4 &:active {
|
||||
margin: -8px 0 0 10px;
|
||||
}
|
||||
|
||||
.dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
|
||||
@ -75,7 +75,7 @@
|
||||
@include responsive(null, 1900px){
|
||||
&.mini {
|
||||
.grid-item {
|
||||
@include grid_item(3 )
|
||||
@include grid_item(3)
|
||||
}
|
||||
&.single-row {
|
||||
.grid-item:nth-child(1n+4){
|
||||
|
||||
@ -99,6 +99,15 @@ input[type="submit"] {
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
|
||||
&.small {
|
||||
padding: 6px 18px 4px;
|
||||
}
|
||||
|
||||
&.pull-right {
|
||||
margin-right: 0;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
&.primary {
|
||||
background: $turquoise;
|
||||
color: $white;
|
||||
@ -284,6 +293,13 @@ input[type="submit"] {
|
||||
}
|
||||
}
|
||||
|
||||
&.range {
|
||||
.input-range__track,
|
||||
.input-range__slider-container {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
display: inline-block;
|
||||
padding: 10px 14px;
|
||||
|
||||
Reference in New Issue
Block a user