Sorting part 2 - should be at storage level perhaps; Thumbnail not updating fixed

This commit is contained in:
James Barnsley
2016-12-10 23:30:03 +13:00
parent 26b069faa7
commit c1ea65666c
7 changed files with 117 additions and 53 deletions

View File

@ -56,7 +56,7 @@ export default class Parallax extends React.Component{
}
componentWillReceiveProps( nextProps ){
if( ( !this.props.url || nextProps.image != this.props.url ) && !this._loading ){
if( ( !this.state.url || nextProps.image != this.state.url ) && !this._loading ){
this._loading = true
this.setState({ url: nextProps.image, image: false, loading: true })
this.loadImage( nextProps.image )

View File

@ -6,41 +6,61 @@ export default class Thumbnail extends React.Component{
constructor(props) {
super(props);
}
this.state = {
url: require('../../assets/no-image.svg')
// TODO: ascertain whether this is improving or hindering performance
// The UI appears to work perfectly fine without this
shouldComponentUpdate(nextProps, nextState){
// no images at all, and we already know it
if( !this.props.image &&
!this.props.images &&
!nextProps.image &&
!nextProps.images ){
return false
}
}
componentDidMount(){
this.mapImageSizes();
}
// image changed
if( this.props.image && !nextProps.image ) return true
if( !this.props.image && nextProps.image ) return true
if( this.props.image != nextProps.image ) return true
componentWillReceiveProps( nextProps ){
this.mapImageSizes( nextProps );
// images array changed
if( this.props.images && !nextProps.images ) return true
if( !this.props.images && nextProps.images ) return true
if( this.props.images.length != nextProps.images.length ) return true
// image item changed
var size = 'medium'
var images = helpers.sizedImages( nextProps.images )
if( this.props.size ) size = this.props.size
if( this.props.images[size] != images[size] ) return true
return false
}
mapImageSizes( props = this.props ){
// no images
if( !this.props.image && !this.props.images ){
this.setState({ url: require('../../assets/no-image.svg') })
return require('../../assets/no-image.svg')
// single image
}else if( this.props.image ){
this.setState({ url: this.props.image })
return this.props.image
// multiple images
}else if( this.props.images && this.props.images.length > 0 ){
var images = helpers.sizedImages( this.props.images )
var size = 'medium'
if( this.props.size ) size = this.props.size
this.setState({ url: images[size] })
return images[size]
}
}
render(){
var style = { backgroundImage: 'url("'+this.state.url+'")' }
var image = this.mapImageSizes()
var style = { backgroundImage: 'url("'+image+'")' }
var className = 'thumbnail '+this.props.size;
if( this.props.circle ) className += ' circle';

View File

@ -20,6 +20,13 @@ export default class Track extends React.Component{
}
}
handleTouchEnd(e){
var target = $(e.target);
if( !target.is('a') && target.closest('a').length <= 0 ){
this.props.handleTouchEnd(e);
}
}
handleContextMenu(e){
e.preventDefault();
this.props.handleContextMenu(e);
@ -46,7 +53,7 @@ export default class Track extends React.Component{
<div
className={className}
onTouchStart={ e => this.props.handleTouchStart(e) }
onTouchEnd={ e => this.props.handleTouchEnd(e) }
onTouchEnd={ e => this.handleTouchEnd(e) }
onMouseDown={ e => this.handleMouseDown(e) }
onMouseUp={ e => this.props.handleMouseUp(e) }
onDoubleClick={ e => this.props.handleDoubleClick(e) }

View File

@ -257,24 +257,43 @@ export let createRange = function (indexes){
export let sortItems = function (array, property, reverse = false){
function compare(a,b) {
switch( typeof(a[property]) ){
var a_value = a
var a_property_split = property.split('.')
for( var i = 0; i < a_property_split.length; i++ ){
if( typeof(a_value[a_property_split[i]]) === 'undefined' ) return -1
a_value = a_value[a_property_split[i]]
}
case 'boolean':
return a[property]
break
var b_value = b
var b_property_split = property.split('.')
for( var i = 0; i < b_property_split.length; i++ ){
if( typeof(b_value[b_property_split[i]]) === 'undefined' ) return -1
b_value = b_value[b_property_split[i]]
}
default:
if( typeof(a_value) === 'boolean'){
return a_value
// both objects must have this property
if( typeof(a[property]) === 'undefined' || typeof(b[property]) === 'undefined' ) return 0
}else if( typeof(a_value) === 'string'){
if(a_value.toLowerCase() > b_value.toLowerCase()) return 1
return -1
if(a[property] > b[property]) return 1
if(a[property] < b[property]) return -1
return 0
}else{
if( parseInt(a_value) > parseInt(b_value) ) return 1
return -1
}
}
var sorted = array.sort(compare)
if( reverse ) sorted.reverse()
return sorted
}
/**
* Figure out if a value is a number
* @param data = mixed
* @return boolean
**/
export let isNumeric = function (data) {
return !isNaN(parseFloat(data)) && isFinite(data)
}

View File

@ -52,7 +52,7 @@ function getToken( dispatch, getState ){
// token is okay for now, so just resolve with the current token
if( new Date().getTime() < getState().spotify.token_expiry ){
resolve(getState().spotify.access_token);
resolve(getState().spotify.access_token)
return
}
@ -81,16 +81,17 @@ function refreshToken( dispatch, getState ){
})
.then(
response => {
response.token_expiry = new Date().getTime() + ( response.expires_in * 1000 );
response.source = 'spotify';
response.token_expiry = new Date().getTime() + ( response.expires_in * 1000 )
response.source = 'spotify'
dispatch({
type: 'SPOTIFY_TOKEN_REFRESHED',
provider: 'spotify-http-api',
data: response
});
resolve(response);
})
resolve(response)
},
error => {
dispatch({ type: 'SPOTIFY_DISCONNECTED' })
console.error('Could not refresh token', error)
reject(error)
}
@ -116,6 +117,7 @@ function refreshToken( dispatch, getState ){
resolve(response);
},
error => {
dispatch({ type: 'SPOTIFY_DISCONNECTED' })
console.error('Could not refresh token', error)
reject(error)
}

View File

@ -4,10 +4,13 @@ export default function reducer(spotify = {}, action){
case 'SPOTIFY_CONNECT':
case 'SPOTIFY_CONNECTING':
return Object.assign({}, spotify, { connected: false, connecting: true });
return Object.assign({}, spotify, { connected: false, connecting: true })
case 'SPOTIFY_CONNECTED':
return Object.assign({}, spotify, { connected: true, connecting: false });
return Object.assign({}, spotify, { connected: true, connecting: false })
case 'SPOTIFY_DISCONNECTED':
return Object.assign({}, spotify, { connected: false, connecting: false })
case 'PUSHER_SPOTIFY_TOKEN':
if( spotify.authorized ) return spotify;
@ -17,7 +20,7 @@ export default function reducer(spotify = {}, action){
authorization: false,
access_token: action.data.access_token,
token_expiry: action.data.token_expiry
});
})
case 'SPOTIFY_AUTHORIZATION_GRANTED':
return Object.assign({}, spotify, {
@ -27,7 +30,7 @@ export default function reducer(spotify = {}, action){
access_token: action.data.access_token,
refresh_token: action.data.refresh_token,
token_expiry: action.data.token_expiry
});
})
case 'SPOTIFY_AUTHORIZATION_REVOKED':
return Object.assign({}, spotify, {
@ -38,45 +41,46 @@ export default function reducer(spotify = {}, action){
refresh_token: false,
token_expiry: 0,
me: false
});
})
case 'SPOTIFY_TOKEN_REFRESHING':
return Object.assign({}, spotify, { refreshing_token: true });
return Object.assign({}, spotify, { refreshing_token: true })
case 'SPOTIFY_TOKEN_REFRESHED':
return Object.assign({}, spotify, {
connected: true,
refreshing_token: false,
authorization: action.data,
access_token: action.data.access_token,
token_expiry: action.data.token_expiry,
provider: action.provider
});
})
case 'SPOTIFY_DISCONNECTED':
return Object.assign({}, spotify, { connected: false, connecting: false });
return Object.assign({}, spotify, { connected: false, connecting: false })
case 'SPOTIFY_ME_LOADED':
return Object.assign({}, spotify, { me: action.data });
return Object.assign({}, spotify, { me: action.data })
case 'SPOTIFY_ARTISTS_LOADED':
if( !action.data ) return Object.assign({}, spotify)
return Object.assign({}, spotify, {
artists: action.data.artists.items,
artists_more: action.data.artists.next
});
})
case 'SPOTIFY_LIBRARY_ARTISTS_LOADED':
if( !action.data ) return Object.assign({}, spotify)
return Object.assign({}, spotify, {
library_artists: action.data.artists.items,
library_artists_more: action.data.artists.next
});
})
case 'SPOTIFY_LIBRARY_ARTISTS_LOADED_MORE':
return Object.assign({}, spotify, {
library_artists: [ ...spotify.library_artists, ...action.data.artists.items ],
library_artists_more: action.data.artists.next
});
})
case 'SPOTIFY_LIBRARY_ALBUMS_LOADED':
if( !action.data ) return Object.assign({}, spotify)
@ -93,7 +97,7 @@ export default function reducer(spotify = {}, action){
return Object.assign({}, spotify, {
library_albums: albums,
library_albums_more: action.data.next
});
})
case 'SPOTIFY_LIBRARY_ALBUMS_LOADED_MORE':
var albums = []
@ -109,7 +113,7 @@ export default function reducer(spotify = {}, action){
return Object.assign({}, spotify, {
library_albums: [...spotify.library_albums, ...albums ],
library_albums_more: action.data.next
});
})
case 'SPOTIFY_LIBRARY_TRACKS_LOADED':
if( !action.data ) return Object.assign({}, spotify)
@ -126,7 +130,7 @@ export default function reducer(spotify = {}, action){
return Object.assign({}, spotify, {
library_tracks: tracks,
library_tracks_more: action.data.next
});
})
case 'SPOTIFY_LIBRARY_TRACKS_LOADED_MORE':
var tracks = Object.assign([], action.data.items)
@ -142,19 +146,19 @@ export default function reducer(spotify = {}, action){
return Object.assign({}, spotify, {
library_tracks: [...spotify.library_tracks, ...tracks],
library_tracks_more: action.data.next
});
})
case 'SPOTIFY_FEATURED_PLAYLISTS_LOADED':
return Object.assign({}, spotify, { featured_playlists: action.data });
return Object.assign({}, spotify, { featured_playlists: action.data })
case 'SPOTIFY_CATEGORIES_LOADED':
return Object.assign({}, spotify, { categories: action.data });
return Object.assign({}, spotify, { categories: action.data })
case 'SPOTIFY_CATEGORY_LOADED':
return Object.assign({}, spotify, { category: action.data });
return Object.assign({}, spotify, { category: action.data })
case 'SPOTIFY_CATEGORY_PLAYLISTS_LOADED':
return Object.assign({}, spotify, { category_playlists: action.data });
return Object.assign({}, spotify, { category_playlists: action.data })
case 'SPOTIFY_CATEGORY_PLAYLISTS_LOADED_MORE':
return Object.assign({}, spotify, { category_playlists: {
@ -162,7 +166,7 @@ export default function reducer(spotify = {}, action){
next: action.data.next,
previous: action.data.previous,
items: [ ...spotify.category_playlists.items, ...action.data.items ]
}});
}})
case 'SPOTIFY_NEW_RELEASES_LOADED':
return Object.assign({}, spotify, { new_releases: action.data });
@ -173,7 +177,7 @@ export default function reducer(spotify = {}, action){
next: action.data.albums.next,
previous: action.data.albums.previous,
items: [ ...spotify.new_releases.items, ...action.data.albums.items ]
}});
}})
default:
return spotify

View File

@ -21,12 +21,23 @@ class LibraryPlaylists extends React.Component{
super(props);
}
setSort(value){
var reverse = false
if( this.props.sort == value ) reverse = !this.props.sort_reverse
var data = {
library_playlists_sort_reverse: reverse,
library_playlists_sort: value
}
this.props.uiActions.set(data)
}
renderView(){
if( !this.props.playlists ) return null
var playlists = this.props.playlists
if( this.props.sort ){
playlists = helpers.sortItems(playlists, this.props.sort)
playlists = helpers.sortItems(playlists, this.props.sort, this.props.sort_reverse)
}
if( this.props.view == 'list' ){
@ -96,7 +107,7 @@ class LibraryPlaylists extends React.Component{
var actions = (
<div>
<DropdownField icon="sort" name="Sort" value={ this.props.sort } options={ sort_options } handleChange={ value => this.props.uiActions.set({ library_playlists_sort: value }) } />
<DropdownField icon="sort" name="Sort" value={ this.props.sort } options={ sort_options } handleChange={ value => this.setSort(value) } />
<DropdownField icon="eye" name="View" value={ this.props.view } options={ view_options } handleChange={ value => this.props.uiActions.set({ library_playlists_view: value }) } />
<button onClick={ () => this.props.uiActions.openModal('create_playlist', {} ) }>
<FontAwesome name="plus" />&nbsp;
@ -125,6 +136,7 @@ const mapStateToProps = (state, ownProps) => {
return {
view: state.ui.library_playlists_view,
sort: state.ui.library_playlists_sort,
sort_reverse: state.ui.library_playlists_sort_reverse,
playlists: state.ui.playlists
}
}