diff --git a/src/js/bootstrap.js b/src/js/bootstrap.js
index 666350df..32bbb4c4 100755
--- a/src/js/bootstrap.js
+++ b/src/js/bootstrap.js
@@ -87,6 +87,12 @@ if( localStorage.getItem('spotify') ){
initialState.spotify = Object.assign(initialState.spotify, storedSpotify );
}
+// if we've got a stored version of spotify state, load and merge
+if( localStorage.getItem('ui') ){
+ var storedUi = JSON.parse( localStorage.getItem('ui') );
+ initialState.ui = Object.assign(initialState.ui, storedUi );
+}
+
console.log('Bootstrapping', initialState)
let store = createStore(
diff --git a/src/js/components/AlbumGrid.js b/src/js/components/AlbumGrid.js
index c4e608f7..ebb3bd7c 100755
--- a/src/js/components/AlbumGrid.js
+++ b/src/js/components/AlbumGrid.js
@@ -17,14 +17,6 @@ export default class AlbumGrid extends React.Component{
{
this.props.albums.map(
(album, index) => {
-
- // handle nested album objects (as in Album Library)
- if( album.album ){
- var flatAlbum = album.album;
- flatAlbum.added_at = album.added_at;
- album = flatAlbum;
- }
-
return
}
)
diff --git a/src/js/components/List.js b/src/js/components/List.js
index c666b6a5..ea60c297 100755
--- a/src/js/components/List.js
+++ b/src/js/components/List.js
@@ -1,9 +1,12 @@
import React, { PropTypes } from 'react'
import { Link } from 'react-router'
-
import FontAwesome from 'react-fontawesome'
+import ArtistSentence from './ArtistSentence'
+
+import * as helpers from '../helpers'
+
export default class List extends React.Component{
constructor(props) {
@@ -17,16 +20,28 @@ export default class List extends React.Component{
{
this.props.columns.map( (col, col_index) => {
- return
{ col.name }
+ return
{ col.label ? col.label : col.name }
})
}
)
}
- renderValue( value ){
- if( typeof(value) === 'undefined' ) return -
+ renderValue( row, key ){
+ var key = key.split('.')
+ var value = row
+
+ for( var i = 0; i < key.length; i++ ){
+ if( typeof(value[key[i]]) !== 'undefined' ){
+ value = value[key[i]]
+ }else{
+ return -
+ }
+ }
+
+ if( key[0] === 'artists' ) return
if( value === true ) return
+ if( typeof(value) === 'number' ) return {value.toLocaleString()}
return {value}
}
@@ -44,11 +59,12 @@ export default class List extends React.Component{
this.props.columns.map( (col, col_index) => {
return (
- { this.renderValue(row[col.name]) }
+ { this.renderValue(row, col.name) }
)
})
}
+ { this.props.show_source_icon ? : null }
)
})
diff --git a/src/js/components/SpotifyAuthenticationFrame.js b/src/js/components/SpotifyAuthenticationFrame.js
index 4a0600cb..1fd38684 100755
--- a/src/js/components/SpotifyAuthenticationFrame.js
+++ b/src/js/components/SpotifyAuthenticationFrame.js
@@ -68,7 +68,7 @@ class SpotifyAuthenticationFrame extends React.Component{
Logged in as {this.props.spotify.me.display_name ? this.props.spotify.me.display_name : null }
- ({ this.props.spotify.me.id })
+ ({ this.props.spotify.me.id })
diff --git a/src/js/services/localstorage/middleware.js b/src/js/services/localstorage/middleware.js
index 68da3581..87d5ca69 100755
--- a/src/js/services/localstorage/middleware.js
+++ b/src/js/services/localstorage/middleware.js
@@ -12,7 +12,7 @@ const localstorageMiddleware = (function(){
// append our state to a global variable. This gives us access to debug the store at any point
window._store = store
- console.log(action)
+ //console.log(action)
switch( action.type ){
@@ -114,6 +114,13 @@ const localstorageMiddleware = (function(){
);
localStorage.setItem('spotify', JSON.stringify(spotify));
break;
+
+ case 'SET_VIEW':
+ var ui = JSON.parse( localStorage.getItem('ui') );
+ if( !ui ) ui = {};
+ Object.assign( ui, action.view );
+ localStorage.setItem('ui', JSON.stringify(ui));
+ break;
}
}
diff --git a/src/js/services/spotify/reducer.js b/src/js/services/spotify/reducer.js
index b39d5c07..19bd84f9 100755
--- a/src/js/services/spotify/reducer.js
+++ b/src/js/services/spotify/reducer.js
@@ -79,14 +79,34 @@ export default function reducer(spotify = {}, action){
case 'SPOTIFY_LIBRARY_ALBUMS_LOADED':
if( !action.data ) return Object.assign({}, spotify)
+ var albums = []
+ for( var i = 0; i < action.data.items.length; i++ ){
+ albums.push( Object.assign(
+ {},
+ action.data.items[i].album,
+ {
+ added_at: action.data.items[i].added_at
+ }
+ ))
+ }
return Object.assign({}, spotify, {
- library_albums: action.data.items,
+ library_albums: albums,
library_albums_more: action.data.next
});
case 'SPOTIFY_LIBRARY_ALBUMS_LOADED_MORE':
+ var albums = []
+ for( var i = 0; i < action.data.items.length; i++ ){
+ albums.push( Object.assign(
+ {},
+ action.data.items[i].album,
+ {
+ added_at: action.data.items[i].added_at
+ }
+ ))
+ }
return Object.assign({}, spotify, {
- library_albums: [...spotify.library_albums, ...action.data.items ],
+ library_albums: [...spotify.library_albums, ...albums ],
library_albums_more: action.data.next
});
diff --git a/src/js/views/library/LibraryAlbums.js b/src/js/views/library/LibraryAlbums.js
index e19799a7..fd473493 100755
--- a/src/js/views/library/LibraryAlbums.js
+++ b/src/js/views/library/LibraryAlbums.js
@@ -5,9 +5,12 @@ import { bindActionCreators } from 'redux'
import { Link } from 'react-router'
import AlbumGrid from '../../components/AlbumGrid'
+import List from '../../components/List'
import Header from '../../components/Header'
+import DropdownField from '../../components/DropdownField'
import LazyLoadListener from '../../components/LazyLoadListener'
+import * as uiActions from '../../services/ui/actions'
import * as mopidyActions from '../../services/mopidy/actions'
import * as spotifyActions from '../../services/spotify/actions'
@@ -26,16 +29,77 @@ class LibraryAlbums extends React.Component{
this.props.spotifyActions.getURL( this.props.albums_more, 'SPOTIFY_LIBRARY_ALBUMS_LOADED_MORE' );
}
- render(){
- return (
-
-
+ renderView(){
+ if( !this.props.albums ) return null
+
+ if( this.props.view == 'list' ){
+ var columns = [
+ {
+ width: 35,
+ label: 'Name',
+ name: 'name'
+ },
+ {
+ width: 35,
+ label: 'Artists',
+ name: 'artists'
+ },
+ {
+ width: 15,
+ label: 'Added',
+ name: 'added_at'
+ },
+ {
+ width: 15,
+ label: 'Tracks',
+ name: 'tracks.total'
+ }
+ ]
+ return (
+
+ )
+ }else if( this.props.view == 'thumbnails' ){
+ return (
{ this.props.albums ? : null }
-
+
+ )
+ }else{
+ return (
+
+ { this.props.albums ? : null }
+
+ )
+ }
+ }
+
+ render(){
+
+ var view_options = [
+ {
+ value: 'detail',
+ label: 'Detail'
+ },
+ {
+ value: 'thumbnails',
+ label: 'Thumbnails'
+ },
+ {
+ value: 'list',
+ label: 'List'
+ }
+ ]
+
+ var actions = (
+
this.props.uiActions.setView({ library_albums_view: value }) } />
+ )
+
+ return (
+
+
+ { this.renderView() }
this.loadMore() }/>
);
@@ -51,6 +115,7 @@ class LibraryAlbums extends React.Component{
const mapStateToProps = (state, ownProps) => {
return {
+ view: state.ui.library_albums_view,
albums: state.spotify.library_albums,
albums_more: state.spotify.library_albums_more,
}
@@ -58,6 +123,7 @@ const mapStateToProps = (state, ownProps) => {
const mapDispatchToProps = (dispatch) => {
return {
+ uiActions: bindActionCreators(uiActions, dispatch),
mopidyActions: bindActionCreators(mopidyActions, dispatch),
spotifyActions: bindActionCreators(spotifyActions, dispatch)
}
diff --git a/src/js/views/library/LibraryArtists.js b/src/js/views/library/LibraryArtists.js
index 44581da0..d3fd13da 100755
--- a/src/js/views/library/LibraryArtists.js
+++ b/src/js/views/library/LibraryArtists.js
@@ -37,16 +37,18 @@ class LibraryArtists extends React.Component{
var columns = [
{
width: 30,
+ label: 'Name',
name: 'name'
},
{
width: 10,
+ label: 'Followers',
name: 'followers.total'
}
]
return (
)
}else{
diff --git a/src/js/views/library/LibraryPlaylists.js b/src/js/views/library/LibraryPlaylists.js
index eddb5c84..424aebdf 100755
--- a/src/js/views/library/LibraryPlaylists.js
+++ b/src/js/views/library/LibraryPlaylists.js
@@ -6,6 +6,8 @@ import { Link } from 'react-router'
import FontAwesome from 'react-fontawesome'
import PlaylistGrid from '../../components/PlaylistGrid'
+import List from '../../components/List'
+import DropdownField from '../../components/DropdownField'
import Header from '../../components/Header'
import * as uiActions from '../../services/ui/actions'
@@ -18,31 +20,73 @@ class LibraryPlaylists extends React.Component{
super(props);
}
- render(){
+ renderView(){
if( !this.props.playlists ) return null
- var columns = [
- { name: 'name', width: '30'},
- { name: 'tracks.total', width: '15'},
- { name: 'can_edit', width: '15'},
- { name: 'uri', width: '40'}
+
+ if( this.props.view == 'list' ){
+ var columns = [
+ {
+ width: 30,
+ label: 'Name',
+ name: 'name'
+ },
+ {
+ width: 30,
+ label: 'Owner',
+ name: 'owner.id'
+ },
+ {
+ width: 10,
+ label: 'Can edit',
+ name: 'can_edit'
+ },
+ {
+ width: 10,
+ label: 'Tracks',
+ name: 'tracks.total'
+ }
+ ]
+ return (
+
+ )
+ }else{
+ return (
+
+ )
+ }
+ }
+
+ render(){
+
+ var view_options = [
+ {
+ value: 'thumbnails',
+ label: 'Thumbnails'
+ },
+ {
+ value: 'list',
+ label: 'List'
+ }
]
var actions = (
-
+
+ this.props.uiActions.setView({ library_playlists_view: value }) } />
+
+
)
return (
-
-
-
-
+ { this.renderView() }
)
}
@@ -57,6 +101,7 @@ class LibraryPlaylists extends React.Component{
const mapStateToProps = (state, ownProps) => {
return {
+ view: state.ui.library_playlists_view,
playlists: state.ui.playlists
}
}
diff --git a/src/scss/components/_dropdown-field.scss b/src/scss/components/_dropdown-field.scss
index 8d02aa2b..618321d5 100755
--- a/src/scss/components/_dropdown-field.scss
+++ b/src/scss/components/_dropdown-field.scss
@@ -4,6 +4,7 @@
font-weight: 600;
text-transform: uppercase;
position: relative;
+ display: inline-block;
.label {
padding: 18px 10px;