Searching

This commit is contained in:
James Barnsley
2017-01-16 18:31:06 +13:00
parent 8aba61edb0
commit cb41a24dbd
8 changed files with 182 additions and 52 deletions

8
src/js/bootstrap.js vendored
View File

@ -59,14 +59,6 @@ var initialState = {
},
current_tracklist: [],
current_tltrack: false,
search_results: {
artists: [],
albums: [],
playlists: [],
tracks: []
},
library_playlists: [],
playlists: [],
notifications: []
}
};

View File

@ -248,6 +248,25 @@ export let mergeDuplicates = function(list, key){
return clean_list;
}
/**
* Remove duplicate items in a simple array
*
* @param list Array the unclean array
**/
export let removeDuplicates = function(array){
var unique = [];
for( var i in array ){
if (unique.indexOf(array[i]) <= -1 ){
unique.push(array[i])
}
}
return unique;
}
/**
* Convert a list of indexes to a useable range
* We ignore stragglers, and only attend to the first 'bunch' of consecutive indexes

View File

@ -12,7 +12,9 @@ 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)
// if debug enabled
if (store.getState().ui.log_actions) console.log(action)
switch( action.type ){

View File

@ -211,11 +211,15 @@ export function getSearchResults(query, backends = null, fields = ['any']){
for( var i = 0; i < fields.length; i++ ){
queryObj[fields[i]] = [query];
}
return {
type: 'NOTHING'
}
/*
return {
type: 'MOPIDY_INSTRUCT',
call: 'library.search',
value: { query: queryObj, uris: backends }
}
*/
}

View File

@ -317,9 +317,9 @@ export function getCategory( id ){
).then( ( category_response, playlists_response ) => {
var playlists = []
for (var i = 0; i < playlists_response.playlists.items.length; i++){
var playlist = Object.assign(
playlists.push(Object.assign(
{},
playlists_response.playlists.items[i],
{
@ -327,14 +327,14 @@ export function getCategory( id ){
tracks_more: null,
tracks_total: playlists_response.playlists.items[i].tracks.total
}
)
dispatch({
type: 'PLAYLIST_LOADED',
playlist: playlist
});
))
}
dispatch({
type: 'PLAYLISTS_LOADED',
playlists: playlists
});
var category = Object.assign(
{},
category_response,
@ -382,7 +382,7 @@ export function getURL( url, action_name, uri = false ){
export function getSearchResults( query, type = 'album,artist,playlist,track', limit = 50, offset = 0 ){
return (dispatch, getState) => {
dispatch({ type: 'SPOTIFY_SEARCH_RESULTS_LOADED', data: false });
dispatch({ type: 'SEARCH_RESULTS_LOADED', reset: true });
var url = 'search?q='+query
url += '&type='+type
@ -392,9 +392,42 @@ export function getSearchResults( query, type = 'album,artist,playlist,track', l
sendRequest( dispatch, getState, url )
.then( response => {
dispatch({
type: 'SPOTIFY_SEARCH_RESULTS_LOADED',
data: response
type: 'ARTISTS_LOADED',
artists: response.artists.items
});
dispatch({
type: 'ALBUMS_LOADED',
albums: response.albums.items
});
var playlists = []
for (var i = 0; i < response.playlists.items.length; i++){
playlists.push(Object.assign(
{},
response.playlists.items[i],
{
can_edit: (getState().spotify.me && response.playlists.items[i].owner.id == getState().spotify.me.id),
tracks_total: response.playlists.items[i].tracks.total
}
))
}
dispatch({
type: 'PLAYLISTS_LOADED',
playlists: playlists
});
dispatch({
type: 'SEARCH_RESULTS_LOADED',
playlists_uris: helpers.asURIs(playlists),
playlists_more: response.playlists.next,
artists_uris: helpers.asURIs(response.artists.items),
artists_more: response.artists.next,
albums_uris: helpers.asURIs(response.albums.items),
albums_more: response.albums.next,
tracks: response.tracks
});
});
}

View File

@ -142,7 +142,6 @@ export default function reducer(ui = {}, action){
return Object.assign({}, ui, { albums: albums });
case 'ALBUMS_LOADED':
console.log(action)
var albums = Object.assign([], ui.albums)
for (var i = 0; i < action.albums.length; i++){
@ -202,7 +201,6 @@ export default function reducer(ui = {}, action){
**/
case 'ARTIST_LOADED':
console.log(action)
var artists = Object.assign([], ui.artists)
if (artists[action.uri]){
@ -391,11 +389,16 @@ export default function reducer(ui = {}, action){
return Object.assign({}, ui, { playlists: playlists });
case 'LIBRARY_PLAYLISTS_LOADED':
var library_playlists = []
if (ui.library_playlists) library_playlists = ui.library_playlists
if (ui.library_playlists){
var library_playlists = [...ui.library_playlists, ...action.uris]
}else{
var library_playlists = action.uris
}
library_playlists = helpers.removeDuplicates(library_playlists)
return Object.assign({}, ui, {
library_playlists: [...library_playlists, ...action.uris]
library_playlists: library_playlists
});
@ -420,26 +423,49 @@ export default function reducer(ui = {}, action){
})
return Object.assign({}, ui, { search_results: results })
case 'SPOTIFY_SEARCH_RESULTS_LOADED':
if( !action.data ) return ui
case 'SEARCH_RESULTS_LOADED':
if (action.reset) return ui
return Object.assign({}, ui, { search_results: {
artists: [ ...ui.search_results.artists, ...action.data.artists.items ],
albums: [ ...ui.search_results.albums, ...action.data.albums.items ],
playlists: [ ...ui.search_results.playlists, ...action.data.playlists.items ],
tracks: [ ...ui.search_results.tracks, ...action.data.tracks.items ],
artists_more: action.data.artists.next,
albums_more: action.data.albums.next,
playlists_more: action.data.playlists.next,
tracks_more: action.data.tracks.next
}});
if (ui.search_results.artists_uris){
var artists_uris = [...ui.search_results.artists_uris, ...action.artists_uris]
}else{
var artists_uris = action.artists_uris
}
if (ui.search_results.albums_uris){
var albums_uris = [...ui.search_results.albums_uris, ...action.albums_uris]
}else{
var albums_uris = action.albums_uris
}
if (ui.search_results.playlists_uris){
var playlists_uris = [...ui.search_results.playlists_uris, ...action.playlists_uris]
}else{
var playlists_uris = action.playlists_uris
}
return Object.assign({}, ui, {
search_results: {
artists_more: (action.artists_more ? action.artists_more : null),
artists_uris: artists_uris,
albums_more: (action.albums_more ? action.albums_more : null),
albums_uris: albums_uris,
playlists_more: (action.playlists_more ? action.playlists_more : null),
playlists_uris: playlists_uris,
tracks: [ ...ui.search_results.tracks, ...action.tracks.items ],
tracks_more: action.tracks.next
}
});
case 'SPOTIFY_SEARCH_RESULTS_LOADED_MORE_ARTISTS':
var artists = [...ui.search_results.artists, ...action.data.artists.items]
var results = Object.assign({}, ui.search_results, {
artists: artists,
artists_more: action.data.artists.next
})
var results = Object.assign(
{},
ui.search_results,
{
artists_uris: [...ui.search_results.artists_uris, ...action.data.artists_uris],
artists_more: action.data.artists.next
}
)
return Object.assign({}, ui, { search_results: results })
case 'SPOTIFY_SEARCH_RESULTS_LOADED_MORE_ALBUMS':

View File

@ -76,6 +76,19 @@ class Debug extends React.Component{
</label>
</div>
</div>
<div className="field checkbox">
<div className="name">Debug data</div>
<div className="input">
<label>
<input
type="checkbox"
name="emulate_touch"
checked={ this.props.log_actions }
onChange={ e => this.props.uiActions.set({ log_actions: !this.props.log_actions })} />
<span className="label">Log actions in developer console</span>
</label>
</div>
</div>
</form>
<h4 className="underline">Mopidy</h4>
@ -147,6 +160,7 @@ const mapStateToProps = (state, ownProps) => {
return {
connectionid: state.pusher.connectionid,
emulate_touch: state.ui.emulate_touch,
log_actions: state.ui.log_actions,
debug_response: state.ui.debug_response
}
}

View File

@ -59,13 +59,44 @@ class Search extends React.Component{
}
renderResults(){
var artists = []
if (this.props.artists_uris){
for (var i = 0; i < this.props.artists_uris.length; i++){
var uri = this.props.artists_uris[i]
if (this.props.artists.hasOwnProperty(uri)){
artists.push(this.props.artists[uri])
}
}
}
var albums = []
if (this.props.albums_uris){
for (var i = 0; i < this.props.albums_uris.length; i++){
var uri = this.props.albums_uris[i]
if (this.props.albums.hasOwnProperty(uri)){
albums.push(this.props.albums[uri])
}
}
}
var playlists = []
if (this.props.playlists_uris){
for (var i = 0; i < this.props.playlists_uris.length; i++){
var uri = this.props.playlists_uris[i]
if (this.props.playlists.hasOwnProperty(uri)){
playlists.push(this.props.playlists[uri])
}
}
}
switch( this.props.params.type ){
case 'artists':
return (
<div>
<section className="grid-wrapper">
<ArtistGrid artists={ this.props.search_results.artists } />
<ArtistGrid artists={artists} />
<LazyLoadListener loadMore={ () => this.loadMore('artists') }/>
</section>
</div>
@ -76,7 +107,7 @@ class Search extends React.Component{
return (
<div>
<section className="grid-wrapper">
<AlbumGrid albums={ this.props.search_results.albums } />
<AlbumGrid albums={albums} />
<LazyLoadListener loadMore={ () => this.loadMore('albums') }/>
</section>
</div>
@ -87,7 +118,7 @@ class Search extends React.Component{
return (
<div>
<section className="grid-wrapper">
<PlaylistGrid playlists={ this.props.search_results.playlists } />
<PlaylistGrid playlists={playlists} />
<LazyLoadListener loadMore={ () => this.loadMore('playlists') }/>
</section>
</div>
@ -98,7 +129,7 @@ class Search extends React.Component{
return (
<div>
<section className="list-wrapper">
<TrackList show_source_icon={true} tracks={ this.props.search_results.tracks } />
<TrackList show_source_icon={true} tracks={ this.props.tracks } />
<LazyLoadListener loadMore={ () => this.loadMore('tracks') }/>
</section>
</div>
@ -112,26 +143,26 @@ class Search extends React.Component{
<section>
<div className="inner">
<h4><Link to={global.baseURL+'search/'+this.props.params.query+'/artists'}>Artists</Link></h4>
<ArtistGrid className="mini" artists={ this.props.search_results.artists.slice(0,6) } />
<ArtistGrid className="mini" artists={artists.slice(0,6)} />
</div>
</section>
<section>
<div className="inner">
<h4><Link to={global.baseURL+'search/'+this.props.params.query+'/albums'}>Albums</Link></h4>
<AlbumGrid className="mini" albums={ this.props.search_results.albums.slice(0,6) } />
<AlbumGrid className="mini" albums={albums.slice(0,6)} />
</div>
</section>
<section>
<div className="inner">
<h4><Link to={global.baseURL+'search/'+this.props.params.query+'/playlists'}>Playlists</Link></h4>
<PlaylistGrid className="mini" playlists={ this.props.search_results.playlists.slice(0,6) } />
<PlaylistGrid className="mini" playlists={playlists.slice(0,6)} />
</div>
</section>
</div>
<section className="list-wrapper">
<h4 className="left-padding"><Link to={global.baseURL+'search/'+this.props.params.query+'/tracks'}>Tracks</Link></h4>
<TrackList show_source_icon={true} tracks={ this.props.search_results.tracks } />
<TrackList show_source_icon={true} tracks={ this.props.tracks } />
<LazyLoadListener loadMore={ () => this.loadMore('tracks') }/>
</section>
@ -154,7 +185,16 @@ const mapStateToProps = (state, ownProps) => {
return {
mopidy_connected: state.mopidy.connected,
uri_schemes: state.mopidy.uri_schemes,
search_results: state.ui.search_results
tracks: (state.ui.search_results ? state.ui.search_results.tracks : []),
artists: state.ui.artists,
artists_uris: (state.ui.search_results ? state.ui.search_results.artists_uris : []),
artists_more: (state.ui.search_results ? state.ui.search_results.artists_more : null),
albums: state.ui.albums,
albums_uris: (state.ui.search_results ? state.ui.search_results.albums_uris : []),
albums_more: (state.ui.search_results ? state.ui.search_results.albums_more : null),
playlists: state.ui.playlists,
playlists_uris: (state.ui.search_results ? state.ui.search_results.playlists_uris : []),
playlists_more: (state.ui.search_results ? state.ui.search_results.playlists_more : null)
}
}