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}
{item.name}
@@ -312,7 +288,7 @@ class ContextMenu extends React.Component{
{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 ( -
- { - items.map((item, index) => { - switch (item.handleClick){ - - case 'addToPlaylist': - return ( - - this[item.handleClick](e)}> - { item.label } - - - {this.renderPlaylistSubmenu()} - - ) - break - - case 'toggleInLibrary': - return ( - - this[item.handleClick](this.inLibrary())}> - - {this.inLibrary() ? 'Remove from library' : 'Add to library'} - - - - ) - break - - default: - return ( - - this[item.handleClick](e)}> - { item.label } - - - ) - } - }) - } -
+ 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%; } } }