diff --git a/README.md b/README.md index 6a92cd7..d564ac8 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,8 @@ These are the contents of the script: $ mkdir ~/Spotify ; cd ~/Spotify $ rm -rf rama $ rm -rf rama-spotify -$ wget https://github.com/carsy/rama-spotify/releases/download/v0.6/rama_v0.6.tar.gz -$ tar -xvf rama_v0.6.tar.gz +$ wget https://github.com/carsy/rama-spotify/releases/download/v0.8/rama_v0.8.tar.gz +$ tar -xvf rama_v0.8.tar.gz $ open spotify:app:rama ``` You should now be in the app and seeing a graph thingy. @@ -61,6 +61,11 @@ With no official release for the Spotify Desktop Client, there's nothing I can d [Releases] ---- +[v0.8] - UX update + - Look and feel of nodes and buttons updated + - [bugfix] on double click node does not refresh graph + - new map button added to artist menu + [v0.6] - Artist menu - Artist menu added - Click on an artist node to view its info on the menu @@ -107,6 +112,7 @@ José Bateira [here]:https://github.com/carsy/rama-spotify/releases/latest [Releases]:https://github.com/carsy/rama-spotify/releases/latest [issues]:https://github.com/carsy/rama-spotify/issues +[v0.8]:https://github.com/carsy/rama-spotify/releases/tag/v0.8 [v0.6]:https://github.com/carsy/rama-spotify/releases/tag/v0.6 [v0.5]:https://github.com/carsy/rama-spotify/releases/tag/v0.5 [v0.3]:https://github.com/carsy/rama-spotify/releases/tag/v0.3 diff --git a/css/main.css b/css/main.css index 4b164db..e12adfb 100644 --- a/css/main.css +++ b/css/main.css @@ -295,7 +295,7 @@ a { } /* line 16, ../sass/_header.scss */ #header .header-text a { - color: #bbb; + color: #dfe0e6; } /* line 21, ../sass/_header.scss */ #header .header-title { @@ -342,8 +342,9 @@ a { z-index: 2; top: 65px; right: 10px; + color: #dfe0e6; } -/* line 9, ../sass/_settings.scss */ +/* line 11, ../sass/_settings.scss */ #settings .settings-btn { float: right; width: 20px; @@ -353,19 +354,19 @@ a { background: url(../img/settings.png) no-repeat; background-size: cover; } -/* line 20, ../sass/_settings.scss */ +/* line 22, ../sass/_settings.scss */ #settings .settings-btn:hover { cursor: pointer; } -/* line 24, ../sass/_settings.scss */ +/* line 26, ../sass/_settings.scss */ #settings .settings-btn.opened { opacity: 1; } -/* line 28, ../sass/_settings.scss */ +/* line 30, ../sass/_settings.scss */ #settings .settings-btn:active { -webkit-transform: scale(0.9, 0.9); } -/* line 33, ../sass/_settings.scss */ +/* line 35, ../sass/_settings.scss */ #settings .settings-form { display: none; position: relative; @@ -378,7 +379,7 @@ a { border-color: #3e3e40; border-style: solid; } -/* line 47, ../sass/_settings.scss */ +/* line 49, ../sass/_settings.scss */ #settings .settings-form .tri { position: absolute; top: -5px; @@ -392,20 +393,20 @@ a { border-style: solid; -webkit-transform: rotate(45deg); } -/* line 64, ../sass/_settings.scss */ +/* line 66, ../sass/_settings.scss */ #settings .settings-form .option { overflow: auto; } -/* line 67, ../sass/_settings.scss */ +/* line 69, ../sass/_settings.scss */ #settings .settings-form .option:not(.first-child) { margin-top: 5px; } -/* line 71, ../sass/_settings.scss */ +/* line 73, ../sass/_settings.scss */ #settings .settings-form .option label { float: left; margin-right: 5px; } -/* line 75, ../sass/_settings.scss */ +/* line 77, ../sass/_settings.scss */ #settings .settings-form .option input { padding: 2px; width: 30px; @@ -414,7 +415,7 @@ a { border-width: 1px; border-color: #3e3e40; } -/* line 83, ../sass/_settings.scss */ +/* line 85, ../sass/_settings.scss */ #settings .settings-form .option input[name=treemode] { margin-top: 5px; margin-left: 5px; @@ -508,6 +509,11 @@ meter { opacity: 0.95; } /* line 54, ../sass/_tracklist.scss */ +#tracklist .list-track:active { + border-color: #7fb701; + -webkit-transform: scale(0.98, 0.98); +} +/* line 59, ../sass/_tracklist.scss */ #tracklist .list-track a { color: #dfe0e6; } @@ -517,7 +523,7 @@ meter { position: absolute; left: 0; top: 20%; - width: 151px; + width: 126px; opacity: 0.9; background-color: #222326; border-color: #3e3e40; @@ -526,32 +532,30 @@ meter { border-left: 0; color: #dfe0e6; } -/* line 20, ../sass/_artistmenu.scss */ +/* line 19, ../sass/_artistmenu.scss */ #artistmenu .artist-info-field { margin: 5px; } -/* line 24, ../sass/_artistmenu.scss */ +/* line 23, ../sass/_artistmenu.scss */ #artistmenu #artist_albums { width: 120px; margin: 5px auto; } -/* line 28, ../sass/_artistmenu.scss */ +/* line 27, ../sass/_artistmenu.scss */ #artistmenu #artist_albums .artist-album { display: inline-block; margin: 5px; } -/* line 35, ../sass/_artistmenu.scss */ +/* line 33, ../sass/_artistmenu.scss */ #artistmenu #artist_controls { display: none; - position: absolute; - bottom: 0; width: 100%; } -/* line 41, ../sass/_artistmenu.scss */ +/* line 37, ../sass/_artistmenu.scss */ #artistmenu #artist_controls .control:first-child { margin-top: 10px; } -/* line 44, ../sass/_artistmenu.scss */ +/* line 40, ../sass/_artistmenu.scss */ #artistmenu #artist_controls .control { background-color: #2e2f33; max-width: 80%; @@ -564,7 +568,16 @@ meter { cursor: pointer; text-align: center; } +/* line 53, ../sass/_artistmenu.scss */ +#artistmenu #artist_controls .control#control_expand, #artistmenu #artist_controls .control#control_delete { + display: none; +} /* line 57, ../sass/_artistmenu.scss */ #artistmenu #artist_controls .control:hover { opacity: 0.95; } +/* line 61, ../sass/_artistmenu.scss */ +#artistmenu #artist_controls .control:active { + border-color: #7fb701; + -webkit-transform: scale(0.98, 0.98); +} diff --git a/install.sh b/install.sh index 344c3c6..fc7c3b1 100644 --- a/install.sh +++ b/install.sh @@ -1,6 +1,6 @@ #!/bin/sh -version="v0.6" +version="v0.8" mkdir ~/Spotify ; cd ~/Spotify rm -rf rama-spotify diff --git a/js/controllers/artistmenu.js b/js/controllers/artistmenu.js index 41310bb..c3842ac 100644 --- a/js/controllers/artistmenu.js +++ b/js/controllers/artistmenu.js @@ -26,7 +26,6 @@ require([ this.artist = models.Artist.fromURI( models.player.track.artists[0].uri); - this.updateView(this.artist); this.bindEvents(); @@ -35,15 +34,29 @@ require([ bindEvents: function() { this.graphcontroller.addGraphEvent('click', this.onClickNode.bind(this)); + + var controls = { + expand: 'onBtnExpandClick', + new: 'onBtnNewClick', + delete: 'onBtnDeleteClick', + }; + + for (var control in controls) { + document.getElementById('control_' + control) + .onclick = this[controls[control]].bind(this); + } }, updateView: function(artist) { - if (!artist) + if (!artist || this.artist === artist.uri) return; + this.artist = artist; + + if (!this.image) { this.image = Image.forArtist(artist, { - width: 150, - height: 100, + width: 125, + height: 80, style: 'plain', overlay: [artist.name], player: true, @@ -58,6 +71,7 @@ require([ this.image.setOverlay(artist.name); this.jelement.find(this.selectors.albums).html(''); + this.jelement.find(this.selectors.albumsTitle).html(''); artist.load(['popularity', 'years', 'albums']) .done(this, function(artist) { @@ -78,69 +92,120 @@ require([ this.jelement.find(this.selectors.years).html(''); var jalbums = this.jelement.find(this.selectors.albums); - artist.albums.snapshot(0, 7).done(this, function(snapshot) { - - var albumLoaded = function(album) { - var albumImage = Image.forAlbum(album, { - width: 50, - height: 50, - style: 'plain', - player: true, - placeholder: 'album', - link: 'auto', - title: album.name - }); - var albumElement = document.createElement('span'); - albumElement.className = 'artist-album'; - - albumImage.node.className += ' artist-album-cover'; - - $(albumElement).append(albumImage.node); - - jalbums.append(albumElement); - }; - - for (var i = 0; i <= 7; ++i) { - if (snapshot.get(i)) { - var album = snapshot.get(i).albums[0]; - - if (album && album.playable) { - album.load(['uri', 'name', 'popularity']).done(this, albumLoaded); + artist.albums.snapshot(0, 8).done(this, + function(snapshot) { + for (var i = 0; i <= 8; ++i) { + if (snapshot.get(i) && snapshot.get(i).albums[0] && + snapshot.get(i).albums[0].playable) { + var album = snapshot.get(i).albums[0]; + + if (!jalbums.find("a[href='" + album.uri + "']")[0]) { + var albumImage = Image.forAlbum(album, { + width: 50, + height: 50, + style: 'plain', + player: true, + placeholder: 'album', + link: 'auto', + title: album.name + }); + + var albumElement = document.createElement('span'); + albumElement.className = 'artist-album'; + albumImage.node.className += ' artist-album-cover'; + $(albumElement).append(albumImage.node); + jalbums.append(albumElement); + } } + if (i === 8 && jalbums.html() !== '') { + this.jelement + .find(this.selectors.albumsTitle).html('Albums:
'); + } } - } - - }); + }); }); }, + onPlayerChange: function() { + models.player.load('track').done(this, function(player) { + + if (player.track.advertisement) + return; + + var artist = models.Artist.fromURI(player.track.artists[0].uri); + + if ((this.artist && this.artist.uri === artist.uri) || + player.track.advertisement) { + return; + } + + + this.updateView(this.artist); + + this.jelement.find(this.selectors.control_new).show(); + }); + }, onClickNode: function(data) { var node = _.findWhere( this.graphcontroller.artistGraph.data.nodes, { id: parseInt(data.nodes[0]) }); - if (!node) + if (!node || node.artist.uri === this.artist.uri) return; + if (node.id === 1) { + this.jelement.find(this.selectors.controls).hide(); + } else { + $(this.selectors.control_new).show(); + this.jelement.find(this.selectors.controls).show(); + } + + // if (node.isLeaf) { + // // this.jelement.find(this.selectors.control_expand).show(); + // this.jelement.find(this.selectors.control_delete).show(); + // } else { + // // this.jelement.find(this.selectors.control_expand).hide(); + // this.jelement.find(this.selectors.control_delete).hide(); + // } + this.updateView(node.artist); }, - onPlayerChange: function() { - models.player.load('track').done(this, function(player) { - var artist = models.Artist.fromURI( - models.Artist.fromURI(player.track.artists[0].uri) - ); - - if ((this.artist && this.artist.uri === artist.uri) || - player.track.advertisement) { - return; - } + onBtnExpandClick: function(event) { + // TODO expand node (depth one) + // try to save nodes positions + // then add nodes and edges + // create new graph with updated nodes and edges + // setPosition(savedPositions) + }, + onBtnNewClick: function(event) { + this.graphcontroller.updateArtist(this.artist); + this.jelement.find(this.selectors.control_new).hide(); + this.jelement.find(this.selectors.control_delete).hide(); + }, + onBtnDeleteClick: function(event) { + // TODO delete node from graph + // save nodes' positions + // delete node from graph + // create new graph from updated data + // + var node = _.findWhere( + this.graphcontroller.artistGraph.data.nodes, { + id: this.artist.nodeid + }); - this.artist = artist; - this.updateView(this.artist); + var edges = _.where(this.graphcontroller.artistGraph.data.edges, { + to: this.artist.nodeid }); + + var index = this.graphcontroller.artistGraph.data.nodes.indexOf(node); + this.graphcontroller.artistGraph.graph.setData(this.graphcontroller.artistGraph.data); + // this.graphcontroller.updateGraph(); + console.log(this.artist); + console.log(this.artist.nodeid); } + }); exports.artistmenu = ArtistMenu; diff --git a/js/controllers/graphcontroller.js b/js/controllers/graphcontroller.js index c505125..9be10c8 100644 --- a/js/controllers/graphcontroller.js +++ b/js/controllers/graphcontroller.js @@ -21,7 +21,10 @@ require([ afterLoad: function(settings) { models.player.load('track') - .done(this, this.setArtistGraph); + .done(this, function(player) { + this.nowplayingArtist = player.track.artists[0]; + this.setArtistGraph(player); + }); var controller = this; _.each(settings.inputs, function(input) { @@ -61,6 +64,8 @@ require([ config.treemode = this.artistGraph.treemode; } + this.artist = player.track.artists[0]; + this.artistGraph = new ArtistGraph( this.element, player.track.artists[0], @@ -72,6 +77,47 @@ require([ this.bindAllEvents(); }, + updateArtist: function(artist) { + var config = { + options: this.options + }; + + config.branching = this.artistGraph.branching; + config.depth = this.artistGraph.depth; + config.treemode = this.artistGraph.treemode; + + this.artist = artist; + this.artistGraph = new ArtistGraph( + this.element, + artist, + config + ); + + this.showThrobber(); + this.artistGraph.buildGraph(); + + this.bindAllEvents(); + }, + updateGraph: function() { + var config = { + options: this.options + }; + + config.branching = this.artistGraph.branching; + config.depth = this.artistGraph.depth; + config.treemode = this.artistGraph.treemode; + + this.artistGraph = new ArtistGraph( + this.element, + this.artist, + config + ); + + this.showThrobber(); + this.artistGraph.buildGraph(); + + this.bindAllEvents(); + }, showThrobber: function() { if (this.artistGraph.throbber) this.artistGraph.throbber.hide(); @@ -97,25 +143,19 @@ require([ }); }, onPlayerChange: function(player) { - // TODO refactor same artist verification - if (!this.artistGraph) - this.setArtistGraph(player); if (player.track.advertisement) return; - var oldArtistURI = this.artistGraph.artist.uri; - - if (player.track.artists[0].uri !== oldArtistURI) { - this.setArtistGraph(player); - } + this.nowplayingArtist = player.track.artists[0]; }, onNodeDoubleClick: function(data) { var node = _.findWhere(this.artistGraph.data.nodes, { id: parseInt(data.nodes[0]) }); - if (!node || node.id === 1) + if (!node || node.id === 1 || + this.nowplayingArtist.uri === node.artist.uri) return; node.artist.load('compilations').done(function(artist) { diff --git a/js/controllers/tracklist.js b/js/controllers/tracklist.js index ff58b50..533cc8b 100644 --- a/js/controllers/tracklist.js +++ b/js/controllers/tracklist.js @@ -54,7 +54,7 @@ $(this.selector).find(this.selectors.cover); $(wrapper).append(this.image.node); - $(this.selectors.title).html('More popular tracks from ' + artist.name); + $(this.selectors.title).html('More popular tracks by ' + artist.name); var compilations = models.Playlist.fromURI(artist.uri); diff --git a/js/main.js b/js/main.js index ec72748..1395a57 100644 --- a/js/main.js +++ b/js/main.js @@ -30,29 +30,33 @@ spotify.require([ options: { nodes: { color: { - background: '#474747', - border: '#555' + background: '#2e2f33', + border: '#3e3e40', + highlight: { + border: '#7fb701', + background: '#313336' + } }, - fontColor: '#ddd', + fontColor: '#dfe0e6', fontFace: '', shape: 'box', radius: 1 }, edges: { color: { - color: '#8f9096', - highlight: '#8f9096' + color: '#3e3e40', + highlight: '#dfe0e6' } }, stabilize: true //, clustering: true }, }, - // eqbar: { - // loadtemplate: false, - // controller: controllers.EQBar, - // numRows: 128 - // }, + eqbar: { + loadtemplate: false, + controller: controllers.EQBar, + numRows: 128 + }, tracklist: { loadtemplate: true, controller: controllers.TrackList, @@ -70,8 +74,12 @@ spotify.require([ cover: '#artist_cover', popularity: '#artist_pop', years: '#artist_years', + albumsTitle: '#artist_albums_title', albums: '#artist_albums', controls: '#artist_controls', + control_expand: '#control_expand', + control_new: '#control_new', + control_delete: '#control_delete' }, hasDependencies: true } diff --git a/js/models/artistgraph.js b/js/models/artistgraph.js index 64d4035..188cf4f 100644 --- a/js/models/artistgraph.js +++ b/js/models/artistgraph.js @@ -31,8 +31,9 @@ var ArtistGraph = function(element, artist, config) { var graph = this.graph; this.graph.on('stabilized', function(iterations) { // Y U NO WORK - graph.zoomExtent(); + // graph.zoomExtent(); console.log(iterations); + // this.storePosition(); }); }; @@ -51,9 +52,13 @@ ArtistGraph.prototype = { id: this.index, label: this.artist.name, artist: this.artist, + isLeaf: false, fontColor: '#313336', color: { - background: '#afb0b6' + background: '#dfe0e6', + highlight: { + border: '#7fb701' + } } }], edges: [] @@ -94,7 +99,6 @@ ArtistGraph.prototype = { var extraEdge = { from: rootArtist.nodeid, to: duplicated.id, - color: '#aaa' }; this.extraEdges.push(extraEdge); @@ -108,7 +112,8 @@ ArtistGraph.prototype = { this.data.nodes.push({ id: nodeid, label: artist.name, - artist: artist + artist: artist, + isLeaf: depth <= 0 }); this.data.edges.push({ @@ -150,6 +155,7 @@ ArtistGraph.prototype = { }); this.graph.start(); + this.graph.storePosition(); this.bindAllEvents(); diff --git a/manifest.json b/manifest.json index a648295..575f766 100644 --- a/manifest.json +++ b/manifest.json @@ -11,7 +11,7 @@ "track" ], "BundleType": "Application", - "BundleVersion": "0.2", + "BundleVersion": "0.8", "Dependencies": { "api": "1.0.0", "views": "1.0.0", diff --git a/sass/_artistmenu.scss b/sass/_artistmenu.scss index d413e50..26aed59 100644 --- a/sass/_artistmenu.scss +++ b/sass/_artistmenu.scss @@ -1,12 +1,11 @@ #artistmenu { - // display: none; position: absolute; left: 0; top: 20%; // $header-height + 20px; // height: 60%; - width: 151px; + width: 126px; opacity: 0.9; background-color: $new-bg; @@ -31,11 +30,8 @@ } } - #artist_controls { display: none; - position: absolute; - bottom: 0; width: 100%; .control:first-child { @@ -54,9 +50,18 @@ cursor: pointer; text-align: center; + &#control_expand, &#control_delete { + display: none; + } + &:hover { opacity: 0.95; } + + &:active { + border-color: $green1; + -webkit-transform: scale(0.98, 0.98); + } } } } \ No newline at end of file diff --git a/sass/_header.scss b/sass/_header.scss index 5b7177a..bfff219 100644 --- a/sass/_header.scss +++ b/sass/_header.scss @@ -14,7 +14,7 @@ .header-text { a { - color: #bbb; + color: $new-white; } } diff --git a/sass/_settings.scss b/sass/_settings.scss index 4101df9..5a65b97 100644 --- a/sass/_settings.scss +++ b/sass/_settings.scss @@ -6,6 +6,8 @@ top: $header-height + 5px; right: 10px; + color: $new-white; + .settings-btn { float: right; diff --git a/sass/_tracklist.scss b/sass/_tracklist.scss index 20a0758..7974b3c 100644 --- a/sass/_tracklist.scss +++ b/sass/_tracklist.scss @@ -51,6 +51,11 @@ $width: $height; // omg its a square opacity: 0.95; } + &:active { + border-color: $green1; + -webkit-transform: scale(0.98, 0.98); + } + a { color: $new-white; } diff --git a/views/artistmenu.html b/views/artistmenu.html index 124181f..b0d4dd7 100644 --- a/views/artistmenu.html +++ b/views/artistmenu.html @@ -2,11 +2,11 @@
-
Albums:
+
+
expand
new map
delete
-
\ No newline at end of file