diff --git a/src/js/components/ContextMenu.js b/src/js/components/ContextMenu.js
index add4fd75..ca270d58 100755
--- a/src/js/components/ContextMenu.js
+++ b/src/js/components/ContextMenu.js
@@ -17,8 +17,7 @@ class ContextMenu extends React.Component{
constructor(props) {
super(props)
this.state = {
- submenu_expanded: false,
- in_library: false
+ submenu_expanded: false
}
this.handleScroll = this.handleScroll.bind(this)
this.handleClick = this.handleClick.bind(this)
@@ -41,6 +40,17 @@ class ContextMenu extends React.Component{
this.setState({ submenu_expanded: false })
$('body').addClass('context-menu-open')
+ // if we're able to be in the library, run a check
+ if (this.props.spotify_authorized && this.contextType().source == 'spotify'){
+ switch (nextProps.menu.context){
+ case 'artist':
+ case 'album':
+ case 'playlist':
+ this.props.spotifyActions.following(nextProps.menu.items[0].uri)
+ break
+ }
+ }
+
// we DID have one prior, and now we don't
} else if (this.props.menu && !nextProps.menu){
$('body').removeClass('context-menu-open')
@@ -60,6 +70,35 @@ class ContextMenu extends React.Component{
}
}
+ contextType(){
+ var context = {
+ name: null,
+ label: 'Unknown'
+ }
+
+ if (this.props.menu && this.props.menu.context){
+ context.name = this.props.menu.context
+ context.label = this.props.menu.context
+
+ switch (this.props.menu.context){
+
+ case 'playlist':
+ case 'editable-playlist':
+ context.label = 'playlist'
+ break
+
+ case 'track':
+ case 'queue-track':
+ case 'playlist-track':
+ case 'editable-playlist-track':
+ context.label = 'track'
+ break
+ }
+ }
+
+ return context
+ }
+
inLibrary(){
if (!this.props.menu || !this.props.menu.context){
return false
@@ -82,6 +121,14 @@ class ContextMenu extends React.Component{
return false
}
+ canBeInLibrary(){
+ if (!this.props.spotify_authorized){
+ return false
+ }
+
+ return (helpers.uriSource(this.props.menu.items[0].uri) == 'spotify')
+ }
+
toggleInLibrary(in_library){
this.props.uiActions.hideContextMenu()
if (in_library){
@@ -117,10 +164,6 @@ class ContextMenu extends React.Component{
this.props.mopidyActions.enqueueURIsNext(this.props.menu.uris, this.props.menu.tracklist_uri)
}
- addToPlaylist(){
- this.setState({ submenu_expanded: !this.state.submenu_expanded })
- }
-
addToQueue(){
this.props.uiActions.hideContextMenu()
this.props.mopidyActions.enqueueURIs(this.props.menu.uris, this.props.menu.tracklist_uri)
@@ -208,79 +251,12 @@ class ContextMenu extends React.Component{
)
}
- getItems(){
- switch (this.props.menu.context) {
-
- case 'album':
- var items = [
- { handleClick: 'playURIs', label: 'Play' },
- { handleClick: 'playURIsNext', label: 'Play next' },
- { handleClick: 'addToQueue', label: 'Add to queue' },
- { handleClick: 'toggleInLibrary', label: 'Add to library' },
- { handleClick: 'goToArtist', label: 'Go to artist' },
- { handleClick: 'copyURIs', label: 'Copy URI' }
- ]
- break
-
- case 'artist':
- var items = [
- { handleClick: 'startRadio', label: 'Start radio' },
- { handleClick: 'toggleInLibrary', label: 'Add to library' },
- { handleClick: 'copyURIs', label: 'Copy URI' }
- ]
- break
-
- case 'playlist':
- var items = [
- { handleClick: 'playURIs', label: 'Play' },
- { handleClick: 'toggleInLibrary', label: 'Add to library' },
- { handleClick: 'goToUser', label: 'Go to user' },
- { handleClick: 'copyURIs', label: 'Copy URI' }
- ]
- break
-
- case 'queue':
- var items = [
- { handleClick: 'playQueueItem', label: 'Play' },
- { handleClick: 'addToPlaylist', label: 'Add to playlist' },
- { handleClick: 'copyURIs', label: 'Copy URIs' },
- { handleClick: 'removeFromQueue', label: 'Remove' }
- ]
- break
-
- case 'editable-playlist-track':
- var items = [
- { handleClick: 'playURIs', label: 'Play' },
- { handleClick: 'playURIsNext', label: 'Play next' },
- { handleClick: 'addToQueue', label: 'Add to queue' },
- { handleClick: 'addToPlaylist', label: 'Add to playlist' },
- { handleClick: 'startRadio', label: 'Start radio' },
- { handleClick: 'copyURIs', label: 'Copy URIs' },
- { handleClick: 'removeFromPlaylist', label: 'Remove' }
- ]
- break
-
- default:
- var items = [
- { handleClick: 'playURIs', label: 'Play' },
- { handleClick: 'playURIsNext', label: 'Play next' },
- { handleClick: 'addToQueue', label: 'Add to queue' },
- { handleClick: 'addToPlaylist', label: 'Add to playlist' },
- { handleClick: 'startRadio', label: 'Start radio' },
- { handleClick: 'copyURIs', label: 'Copy URIs' }
- ]
- break
- }
-
- return items
- }
-
renderTitle(){
if (!this.props.menu.items || this.props.menu.items.length <= 0){
return null
}
- switch (this.props.menu.context){
+ switch (this.contextType().name){
case 'artist':
case 'album':
@@ -299,7 +275,7 @@ class ContextMenu extends React.Component{
{helpers.uriSource(item.uri)}
- {this.props.menu.context}
+ {this.contextType().label}
{helpers.uriSource(this.props.menu.items[0].uri)}
- {this.props.menu.context}s
+ {this.contextType().label}s
{this.props.menu.items.length} items
@@ -325,51 +301,180 @@ class ContextMenu extends React.Component{
}
renderItems(){
- var items = this.getItems()
-
- return (
-
+ var play_uris = (
+
+ this.playURIs(e)}>
+ Play
+
+
)
+
+ var play_queue_item = (
+
+ this.playQueueItem(e)}>
+ Play
+
+
+ )
+
+ var play_uris_next = (
+
+ this.playURIsNext(e)}>
+ Play next
+
+
+ )
+
+ var add_to_queue = (
+
+ this.addToQueue(e)}>
+ Add to queue
+
+
+ )
+
+ var add_to_playlist = (
+
+ this.setState({ submenu_expanded: !this.state.submenu_expanded })}>
+ Add to playlist
+
+
+ {this.renderPlaylistSubmenu()}
+
+ )
+
+ var toggle_in_library = (
+
+ this.toggleInLibrary(this.inLibrary())}>
+
+ {this.inLibrary() ? 'Remove from library' : 'Add to library'}
+
+
+
+ )
+
+ var go_to_artist = (
+
+ this.goToArtist(e)}>
+ Go to artist
+
+
+ )
+
+ var go_to_user = (
+
+ this.goToUser(e)}>
+ Go to user
+
+
+ )
+
+ var start_radio = (
+
+ this.startRadio(e)}>
+ Start {this.contextType().label} radio
+
+
+ )
+
+ var remove_from_queue = (
+
+ this.removeFromQueue(e)}>
+ Remove
+
+
+ )
+
+ var remove_from_playlist = (
+
+ this.removeFromPlaylist(e)}>
+ Remove
+
+
+ )
+
+ var copy_uris = (
+
+ this.copyURIs(e)}>
+ Copy URIs
+
+
+ )
+
+ switch (this.contextType().name){
+
+ case 'album':
+ return (
+
+ {play_uris}
+ {play_uris_next}
+ {add_to_queue}
+ {this.canBeInLibrary() ? toggle_in_library : null}
+ {go_to_artist}
+ {copy_uris}
+
+ )
+ break
+
+ case 'artist':
+ return (
+
+ {start_radio}
+ {this.canBeInLibrary() ? toggle_in_library : null}
+ {copy_uris}
+
+ )
+ break
+
+ case 'playlist':
+ return (
+
+ {play_uris}
+ {this.canBeInLibrary() ? toggle_in_library : null}
+ {go_to_user}
+ {copy_uris}
+
+ )
+ break
+
+ case 'queue':
+ return (
+
+ {play_queue_item}
+ {add_to_playlist}
+ {copy_uris}
+ {remove_from_queue}
+
+ )
+ break
+
+ case 'editable-playlist-track':
+ return (
+
+ {play_uris}
+ {play_uris_next}
+ {add_to_queue}
+ {add_to_playlist}
+ {start_radio}
+ {copy_uris}
+ {remove_from_playlist}
+
+ )
+ break
+
+ default:
+ return (
+
+ {play_uris}
+ {play_uris_next}
+ {add_to_queue}
+ {add_to_playlist}
+ {start_radio}
+ {copy_uris}
+
+ )
+ break
+ }
}
render(){
@@ -379,11 +484,7 @@ class ContextMenu extends React.Component{
left: this.props.menu.position_x,
top: this.props.menu.position_y,
}
-
- var items = this.getItems()
- var height = 0
- if (items) height = items.length * 34 // this is an approximation of how tall each menu item is
-
+ var height = 0 // TODO: use jquery to detect height
var className = "context-menu "+this.props.menu.context
if (this.state.submenu_expanded) className += ' submenu-expanded'
if (this.props.menu.position_x > (window.innerWidth - 154)) className += ' right-align'
@@ -413,7 +514,8 @@ const mapStateToProps = (state, ownProps) => {
library_artists: state.ui.library_artists,
library_albums: state.ui.library_albums,
library_playlists: state.ui.library_playlists,
- playlists: state.ui.playlists
+ playlists: state.ui.playlists,
+ spotify_authorized: state.spotify.authorized
}
}
diff --git a/src/js/components/List.js b/src/js/components/List.js
index 69f4d3fa..12cad121 100755
--- a/src/js/components/List.js
+++ b/src/js/components/List.js
@@ -39,7 +39,8 @@ class List extends React.Component{
{
this.props.columns.map( (col, col_index) => {
- return
{ col.label ? col.label : col.name }
+ var className = 'col '+col.name.replace('.','_')
+ return
{ col.label ? col.label : col.name }
})
}
@@ -88,8 +89,9 @@ class List extends React.Component{
key={row_index}>
{
this.props.columns.map( (col, col_index) => {
+ var className = 'col '+col.name.replace('.','_')
return (
-
+
{ this.renderValue(row, col.name) }
)
diff --git a/src/js/services/ui/reducer.js b/src/js/services/ui/reducer.js
index 4bc8595d..6aafa70c 100755
--- a/src/js/services/ui/reducer.js
+++ b/src/js/services/ui/reducer.js
@@ -254,6 +254,7 @@ export default function reducer(ui = {}, action){
return Object.assign({}, ui, {
library_albums: [...library_albums, ...action.uris],
+ library_albums_started: true,
library_albums_more: action.more,
library_albums_total: action.total
});
@@ -347,19 +348,12 @@ export default function reducer(ui = {}, action){
return Object.assign({}, ui, { artists: artists });
case 'LIBRARY_ARTISTS_LOADED':
- if (!action.uris){
- return Object.assign({}, ui, {
- library_artists: null,
- library_artists_more: null,
- library_artists_total: null
- });
- }
-
var library_artists = []
if (ui.library_artists) library_artists = Object.assign([], ui.library_artists)
return Object.assign({}, ui, {
library_artists: [...library_artists, ...action.uris],
+ library_artists_started: true,
library_artists_more: action.more,
library_artists_total: action.total
});
@@ -551,7 +545,8 @@ export default function reducer(ui = {}, action){
library_playlists = helpers.removeDuplicates(library_playlists)
return Object.assign({}, ui, {
- library_playlists: library_playlists
+ library_playlists: library_playlists,
+ library_playlists_started: true
});
case 'PLAYLIST_LIBRARY_CHECK':
diff --git a/src/js/views/App.js b/src/js/views/App.js
index cc484b4f..8f62521d 100755
--- a/src/js/views/App.js
+++ b/src/js/views/App.js
@@ -44,8 +44,6 @@ class App extends React.Component{
if (this.props.spotify_authorized){
this.props.spotifyActions.getAllLibraryPlaylists();
- this.props.spotifyActions.getLibraryAlbums();
- this.props.spotifyActions.getLibraryArtists();
}
// when we navigate to a new route
diff --git a/src/js/views/library/LibraryAlbums.js b/src/js/views/library/LibraryAlbums.js
index a3c3cbe4..eba0d964 100755
--- a/src/js/views/library/LibraryAlbums.js
+++ b/src/js/views/library/LibraryAlbums.js
@@ -25,7 +25,9 @@ class LibraryAlbums extends React.Component{
}
componentDidMount(){
- if (!this.props.library_albums) this.props.spotifyActions.getLibraryAlbums();
+ if (!this.props.library_albums_started){
+ this.props.spotifyActions.getLibraryAlbums();
+ }
}
handleContextMenu(e,item){
@@ -33,7 +35,7 @@ class LibraryAlbums extends React.Component{
e: e,
context: 'album',
uris: [item.uri],
- item: item
+ items: [item]
}
this.props.uiActions.showContextMenu(data)
}
@@ -59,33 +61,28 @@ class LibraryAlbums extends React.Component{
if( this.props.view == 'list' ){
var columns = [
{
- width: 30,
label: 'Name',
name: 'name'
},
{
- width: 30,
label: 'Artists',
name: 'artists'
},
{
- width: 15,
label: 'Added',
name: 'added_at'
},
{
- width: 15,
label: 'Released',
name: 'release_date'
},
{
- width: 10,
label: 'Tracks',
name: 'tracks_total'
}
]
return (
-
+
this.handleContextMenu(e,item)}
rows={albums}
@@ -214,7 +211,8 @@ const mapStateToProps = (state, ownProps) => {
sort: state.ui.library_albums_sort,
sort_reverse: state.ui.library_albums_sort_reverse,
library_albums: state.ui.library_albums,
- library_albums_more: state.ui.library_albums_more,
+ library_albums_started: state.ui.library_albums_started,
+ library_albums_more: state.ui.library_albums_more
}
}
diff --git a/src/js/views/library/LibraryArtists.js b/src/js/views/library/LibraryArtists.js
index b4d2ad04..d6f22f01 100755
--- a/src/js/views/library/LibraryArtists.js
+++ b/src/js/views/library/LibraryArtists.js
@@ -26,13 +26,15 @@ class LibraryArtists extends React.Component{
e: e,
context: 'artist',
uris: [item.uri],
- item: item
+ items: [item]
}
this.props.uiActions.showContextMenu(data)
}
componentDidMount(){
- if (!this.props.library_artists) this.props.spotifyActions.getLibraryArtists();
+ if (!this.props.library_artists_started){
+ this.props.spotifyActions.getLibraryArtists();
+ }
}
loadMore(){
@@ -55,22 +57,19 @@ class LibraryArtists extends React.Component{
var columns = [
{
label: 'Name',
- width: 70,
name: 'name'
},
{
label: 'Followers',
- width: 15,
name: 'followers.total'
},
{
label: 'Popularity',
- width: 15,
name: 'popularity'
}
]
return (
-
+
this.handleContextMenu(e,item)}
rows={artists}
@@ -161,6 +160,7 @@ const mapStateToProps = (state, ownProps) => {
sort: state.ui.library_artists_sort,
sort_reverse: state.ui.library_artists_sort_reverse,
library_artists: state.ui.library_artists,
+ library_artists_started: state.ui.library_artists_started,
library_artists_more: state.ui.library_artists_more,
view: state.ui.library_artists_view
}
diff --git a/src/js/views/library/LibraryLocalArtists.js b/src/js/views/library/LibraryLocalArtists.js
index 1929e079..1ec6297f 100755
--- a/src/js/views/library/LibraryLocalArtists.js
+++ b/src/js/views/library/LibraryLocalArtists.js
@@ -32,7 +32,7 @@ class LibraryLocalArtists extends React.Component{
e: e,
context: 'artist',
uris: [item.uri],
- item: item
+ items: [item]
}
this.props.uiActions.showContextMenu(data)
}
diff --git a/src/js/views/library/LibraryPlaylists.js b/src/js/views/library/LibraryPlaylists.js
index bf7e37f5..07299631 100755
--- a/src/js/views/library/LibraryPlaylists.js
+++ b/src/js/views/library/LibraryPlaylists.js
@@ -26,7 +26,7 @@ class LibraryPlaylists extends React.Component{
e: e,
context: 'playlist',
uris: [item.uri],
- item: item
+ items: [item]
}
this.props.uiActions.showContextMenu(data)
}
@@ -60,33 +60,28 @@ class LibraryPlaylists extends React.Component{
if( this.props.view == 'list' ){
var columns = [
{
- width: 50,
label: 'Name',
name: 'name'
},
{
- width: 20,
label: 'Owner',
name: 'owner'
},
{
- width: 10,
label: 'Source',
name: 'source'
},
{
- width: 10,
label: 'Tracks',
name: 'tracks_total'
},
{
- width: 10,
label: 'Editable',
name: 'can_edit'
}
]
return (
-
+
this.handleContextMenu(e,item)}
rows={playlists}
diff --git a/src/scss/components/_lists.scss b/src/scss/components/_lists.scss
index 3c47bb5e..c18ce7f0 100755
--- a/src/scss/components/_lists.scss
+++ b/src/scss/components/_lists.scss
@@ -79,57 +79,105 @@
margin-top: -3px;
background: transparent;
}
-
- @include responsive( $bp_medium ){
- padding: 7px 10px 7px 20px;
-
- .col {
- &.name {
- width: 90%;
- padding-right: 10%;
- }
-
- &.duration {
- width: auto;
- position: absolute;
- right: 10px;
- text-align: right;
- }
-
- &.artists,
- &.album {
- width: auto;
- color: $mid_grey;
- display: inline-block;
- }
-
- &.album {
- @include bullet();
- }
- }
-
- &.header {
- display: none;
- }
-
- .select-state,
- .play-state {
- top: 11px;
- left: 5px;
- }
- }
}
-
- &.playlist {
+ @include responsive( $bp_medium ){
+ padding: 7px 10px 7px 20px;
.col {
&.name {
- width: 30%;
+ width: 90% !important;
+ padding-right: 10%;
}
- &.owner {
- width: 20%;
+
+ &.duration {
+ width: auto;
+ position: absolute;
+ right: 10px;
+ text-align: right;
}
+
+ &:not(.name){
+ color: $mid_grey;
+ display: inline-block;
+ width: auto !important;
+ }
+
+ &:not(.name):not(:nth-child(2)){
+ @include bullet();
+ }
+
+ &.followers_total:after {
+ content: ' followers';
+ }
+
+ &.tracks_total:after {
+ content: ' tracks';
+ }
+
+ &.popularity:after {
+ content: '% popularity';
+ }
+
+ &.can_edit,
+ &.release_date {
+ display: none;
+ }
+ }
+
+ &.header {
+ display: none;
+ }
+
+ .select-state,
+ .play-state {
+ top: 11px;
+ left: 5px;
+ }
+ }
+ }
+
+ &.playlist-list .list-item {
+ .col {
+ &.name {
+ width: 50%;
+ }
+ &.owner {
+ width: 20%
+ }
+ &.source,
+ &.can_edit,
+ &.tracks_total,
+ &.popularity {
+ width: 10%;
+ }
+ }
+ }
+
+ &.album-list .list-item {
+ .col {
+ &.name,
+ &.artists {
+ width: 30%;
+ }
+ &.added_at,
+ &.release_date {
+ width: 15%;
+ }
+ &.tracks_total {
+ width: 10%;
+ }
+ }
+ }
+
+ &.artist-list .list-item {
+ .col {
+ &.name {
+ width: 70%;
+ }
+ &.followers_total,
+ &.popularity {
+ width: 15%;
}
}
}