Links for grid items, may need to add more context options

This commit is contained in:
James Barnsley
2019-01-16 16:46:40 +13:00
parent 1efe083002
commit d5c946456f
12 changed files with 2196 additions and 1885 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -98,7 +98,7 @@
// Release details
// These are automatically injected to built HTML
var build = "1547510940";
var build = "1547579515";
var version = "3.31.8";
// Construct the script tag

View File

@ -36,6 +36,7 @@ import LibraryAlbums from './views/library/LibraryAlbums';
import LibraryTracks from './views/library/LibraryTracks';
import LibraryPlaylists from './views/library/LibraryPlaylists';
import LibraryBrowse from './views/library/LibraryBrowse';
import LibraryBrowseDirectory from './views/library/LibraryBrowseDirectory';
import EditPlaylist from './views/modals/EditPlaylist';
import CreatePlaylist from './views/modals/CreatePlaylist';
@ -387,30 +388,31 @@ class App extends React.Component{
<Switch>
<Route exact path="/" component={Queue} />
<Route path="/queue" component={Queue} />
<Route path="/queue/history" component={QueueHistory} />
<Route path="/settings/debug" component={Debug} />
<Route path="/settings" component={Settings} />
<Route path="/settings/service/:sub_view?" component={Settings} />
<Route exact path="/queue" component={Queue} />
<Route exact path="/queue/history" component={QueueHistory} />
<Route exact path="/settings/debug" component={Debug} />
<Route exact path="/settings" component={Settings} />
<Route exact path="/settings/service/:sub_view?" component={Settings} />
<Route path="/search/:type/:term?" component={Search} />
<Route path="/album/:uri" component={Album} />
<Route path="/artist/:uri/:sub_view?" component={Artist} />
<Route path="/playlist/:uri" component={Playlist} />
<Route path="/user/:uri" component={User} />
<Route path="/track/:uri" component={Track} />
<Route exact path="/search/(:type/:term)?" component={Search} />
<Route exact path="/album/:uri" component={Album} />
<Route exact path="/artist/:uri/:sub_view?" component={Artist} />
<Route exact path="/playlist/:uri" component={Playlist} />
<Route exact path="/user/:uri" component={User} />
<Route exact path="/track/:uri" component={Track} />
<Route path="/discover/recommendations/:seeds?" component={DiscoverRecommendations} />
<Route path="/discover/featured" component={DiscoverFeatured} />
<Route path="/discover/categories" component={DiscoverCategories} />
<Route path="/discover/categories/:id" component={DiscoverCategory} />
<Route path="/discover/new-releases" component={DiscoverNewReleases} />
<Route exact path="/discover/recommendations/:seeds?" component={DiscoverRecommendations} />
<Route exact path="/discover/featured" component={DiscoverFeatured} />
<Route exact path="/discover/categories/:id" component={DiscoverCategory} />
<Route exact path="/discover/categories" component={DiscoverCategories} />
<Route exact path="/discover/new-releases" component={DiscoverNewReleases} />
<Route path="/library/artists" component={LibraryArtists} />
<Route path="/library/albums" component={LibraryAlbums} />
<Route path="/library/tracks" component={LibraryTracks} />
<Route path="/library/playlists" component={LibraryPlaylists} />
<Route path="/library/browse/:uri?" component={LibraryBrowse} />
<Route exact path="/library/artists" component={LibraryArtists} />
<Route exact path="/library/albums" component={LibraryAlbums} />
<Route exact path="/library/tracks" component={LibraryTracks} />
<Route exact path="/library/playlists" component={LibraryPlaylists} />
<Route exact path="/library/browse/:uri" component={LibraryBrowseDirectory} />
<Route exact path="/library/browse" component={LibraryBrowse} />
<Route>
<h1>I'm lost</h1>

View File

@ -26,7 +26,7 @@ export default class CategoryGrid extends React.Component{
key={category.id}
type="category"
item={category}
onClick={e => {this.props.history.push(global.baseURL+'discover/categories/'+encodeURIComponent(category.id))}}
link={global.baseURL+'discover/categories/'+encodeURIComponent(category.id)}
/>
)
})

View File

@ -107,8 +107,18 @@ export default class GridItem extends React.Component{
images = this.props.item.icons;
}
if (this.props.link){
var link = this.props.link;
} else {
var link = global.baseURL+this.props.type+'/'+encodeURIComponent(item.uri);
}
return (
<Link className={"grid__item grid__item--"+this.props.type} to={global.baseURL+this.props.type+'/'+encodeURIComponent(item.uri)} onClick={e => helpers.scrollTo()} onContextMenu={e => this.handleContextMenu(e)}>
<Link
className={"grid__item grid__item--"+this.props.type}
to={link}
onClick={e => helpers.scrollTo()}
onContextMenu={e => this.handleContextMenu(e)}>
<Thumbnail size="medium" className="grid__item__thumbnail" images={images} />
<div className="grid__item__name">
{item.name ? item.name : <span className="opaque-text">{item.uri}</span>}

View File

@ -1,7 +1,9 @@
import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Redirect } from 'react-router';
import { Route, Switch } from 'react-router-dom';
import Link from '../components/Link';
import LazyLoadListener from '../components/LazyLoadListener'
@ -105,18 +107,7 @@ class Artist extends React.Component{
this.props.uiActions.set({artist_albums_filter: value});
}
renderSubViewMenu(){
return (
<div className="sub-views" id="sub-views-menu">
<Link className="option" activeClassName="active" to={global.baseURL+'artist/'+this.props.uri} scrollTo="sub-views-menu"><h4>Overview</h4></Link>
{this.props.artist.related_artists_uris ? <Link className="option" activeClassName="active" to={global.baseURL+'artist/'+this.props.uri+'/related-artists'} scrollTo="sub-views-menu"><h4>Related artists</h4></Link> : null}
<Link className="option" activeClassName="active" to={global.baseURL+'artist/'+this.props.uri+'/about'} scrollTo="sub-views-menu"><h4>About</h4></Link>
</div>
)
}
renderBody(){
var scheme = helpers.uriSource(this.props.uri);
renderOverview(){
var artist = helpers.collate(
this.props.artist,
{
@ -134,52 +125,6 @@ class Artist extends React.Component{
artist.albums = helpers.applyFilter('type', this.props.filter, artist.albums);
}
switch (this.props.match.params.sub_view){
case 'related-artists':
return (
<div className="body related-artists">
<section className="grid-wrapper no-top-padding">
<ArtistGrid artists={artist.related_artists} />
</section>
</div>
)
case 'about':
var thumbnails = [];
if (artist.images && artist.images.length > 0){
for (var i = 0; i < artist.images.length; i++){
thumbnails.push(
<div className="tile thumbnail-wrapper" key={i}>
<Thumbnail size="huge" canZoom images={artist.images[i]} />
</div>
);
}
}
return (
<div className="body about">
<div className="col col--w40 tiles artist-stats">
{thumbnails}
{artist.followers ? <div className="tile"><span className="content"><Icon type="fontawesome" name="users" />{artist.followers.toLocaleString()} followers</span></div> : null}
{artist.popularity ? <div className="tile"><span className="content"><Icon type="fontawesome" name="fire" />{artist.popularity }% popularity</span></div> : null}
{artist.listeners ? <div className="tile"><span className="content"><Icon type="fontawesome" name="headphones" />{ artist.listeners.toLocaleString() } listeners</span></div> : null }
</div>
<div className="col col--w60 biography">
<section>
{ artist.biography ? <div className="biography-text"><p>{artist.biography}</p><br />
<div className="mid_grey-text">Published: { artist.biography_publish_date }</div>
<div className="mid_grey-text">Origin: <a href={ artist.biography_link } target="_blank">{ artist.biography_link }</a></div></div> : null }
</section>
</div>
</div>
)
default:
var sort_options = [
{
value: null,
@ -270,8 +215,64 @@ class Artist extends React.Component{
</section>
</div> : null}
</div>
);
}
renderRelatedArtists(){
var artist = helpers.collate(
this.props.artist,
{
artists: this.props.artists
}
);
return (
<div className="body related-artists">
<section className="grid-wrapper no-top-padding">
<ArtistGrid artists={artist.related_artists} />
</section>
</div>
)
}
renderAbout(){
var artist = helpers.collate(
this.props.artist,
{
artists: this.props.artists
}
);
var thumbnails = [];
if (artist.images && artist.images.length > 0){
for (var i = 0; i < artist.images.length; i++){
thumbnails.push(
<div className="tile thumbnail-wrapper" key={i}>
<Thumbnail size="huge" canZoom images={artist.images[i]} />
</div>
);
}
}
return (
<div className="body about">
<div className="col col--w40 tiles artist-stats">
{thumbnails}
{artist.followers ? <div className="tile"><span className="content"><Icon type="fontawesome" name="users" />{artist.followers.toLocaleString()} followers</span></div> : null}
{artist.popularity ? <div className="tile"><span className="content"><Icon type="fontawesome" name="fire" />{artist.popularity }% popularity</span></div> : null}
{artist.listeners ? <div className="tile"><span className="content"><Icon type="fontawesome" name="headphones" />{ artist.listeners.toLocaleString() } listeners</span></div> : null }
</div>
<div className="col col--w60 biography">
<section>
{ artist.biography ? <div className="biography-text"><p>{artist.biography}</p><br />
<div className="mid_grey-text">Published: { artist.biography_publish_date }</div>
<div className="mid_grey-text">Origin: <a href={ artist.biography_link } target="_blank">{ artist.biography_link }</a></div></div> : null }
</section>
</div>
</div>
);
}
render(){
@ -316,11 +317,49 @@ class Artist extends React.Component{
{is_spotify ? <FollowButton uri={this.props.uri} removeText="Remove from library" addText="Add to library" is_following={this.inLibrary()} /> : null}
<ContextMenuTrigger className="white" onTrigger={e => this.handleContextMenu(e)} />
</div>
{ this.renderSubViewMenu() }
<div className="sub-views" id="sub-views-menu">
<Link
nav
className="option"
activeClassName="active"
to={global.baseURL+'artist/'+this.props.uri+'/overview'}
scrollTo="sub-views-menu">
<h4>Overview</h4>
</Link>
{this.props.artist.related_artists_uris ? <Link
nav
className="option"
activeClassName="active"
to={global.baseURL+'artist/'+this.props.uri+'/related-artists'}
scrollTo="sub-views-menu">
<h4>Related artists</h4>
</Link> : null}
<Link
nav
className="option"
activeClassName="active"
to={global.baseURL+'artist/'+this.props.uri+'/about'}
scrollTo="sub-views-menu">
<h4>About</h4>
</Link>
</div>
</div>
</div>
<div className="content-wrapper">
{this.renderBody()}
<Switch>
<Route exact path="/artist/:id/related-artists">
{this.renderRelatedArtists()}
</Route>
<Route exact path="/artist/:id/about">
{this.renderAbout()}
</Route>
<Route exact path="/artist/:id/overview">
{this.renderOverview()}
</Route>
<Route>
{this.renderOverview()}
</Route>
</Switch>
</div>
</div>
);

View File

@ -230,7 +230,7 @@ class Playlist extends React.Component{
<TrackList
uri={playlist.uri}
className="playlist-track-list"
context={context}
track_context={context}
tracks={playlist.tracks}
removeTracks={tracks_indexes => this.removeTracks(tracks_indexes)}
reorderTracks={(indexes, index) => this.reorderTracks(indexes, index)}

View File

@ -52,7 +52,7 @@ class Search extends React.Component{
componentWillReceiveProps(nextProps){
// Query changed
if (nextProps.params.term !== this.props.params.term || nextProps.params.type !== this.props.params.type){
if (nextProps.term !== this.props.term || nextProps.type !== this.props.type){
this.digestUri(nextProps);
}
@ -69,13 +69,13 @@ class Search extends React.Component{
// Digest the URI query property
// Triggered when the URL changes
digestUri(props = this.props){
if (props.params && props.params.type && props.params.term){
if (props.params && props.type && props.term){
this.setState({
type: props.params.type,
term: props.params.term
type: props.type,
term: props.term
});
this.search(props.params.type, props.params.term);
this.search(props.type, props.term);
}
}
@ -429,6 +429,8 @@ class Search extends React.Component{
const mapStateToProps = (state, ownProps) => {
return {
type: ownProps.match.params.type,
term: ownProps.match.params.term,
mopidy_connected: state.mopidy.connected,
albums: (state.core.albums ? state.core.albums : []),
artists: (state.core.artists ? state.core.artists : []),

View File

@ -24,7 +24,7 @@ class DiscoverCategory extends React.Component{
}
componentWillReceiveProps(nextProps){
if (nextProps.params.id != this.props.params.id){
if (nextProps.match.params.id != this.props.match.params.id){
this.loadCategory();
}
@ -43,11 +43,11 @@ class DiscoverCategory extends React.Component{
loadCategory(){
if (!this.props.category){
this.props.spotifyActions.getCategory(this.props.params.id);
this.props.spotifyActions.getCategory(this.props.match.params.id);
}
if (!this.props.category.playlists_uris){
this.props.spotifyActions.getCategoryPlaylists(this.props.params.id);
this.props.spotifyActions.getCategoryPlaylists(this.props.match.params.id);
}
}
@ -57,7 +57,7 @@ class DiscoverCategory extends React.Component{
null,
{
type: 'SPOTIFY_CATEGORY_PLAYLISTS_LOADED_MORE',
uri: 'category:'+this.props.params.id
uri: 'category:'+this.props.match.params.id
}
);
}
@ -104,18 +104,11 @@ class DiscoverCategory extends React.Component{
}
}
/**
* Export our component
*
* We also integrate our global store, using connect()
**/
const mapStateToProps = (state, ownProps) => {
return {
load_queue: state.ui.load_queue,
playlists: state.core.playlists,
category: (state.spotify.categories && state.spotify.categories['category:'+ownProps.params.id] !== undefined ? state.spotify.categories['category:'+ownProps.params.id] : false )
category: (state.spotify.categories && state.spotify.categories['category:'+ownProps.match.params.id] !== undefined ? state.spotify.categories['category:'+ownProps.match.params.id] : false )
}
}

View File

@ -1,23 +1,23 @@
import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Route, Switch } from 'react-router-dom';
import Link from '../../components/Link';
import Header from '../../components/Header'
import List from '../../components/List'
import TrackList from '../../components/TrackList'
import GridItem from '../../components/GridItem'
import DropdownField from '../../components/Fields/DropdownField'
import Icon from '../../components/Icon'
import URILink from '../../components/URILink'
import ErrorBoundary from '../../components/ErrorBoundary'
import Header from '../../components/Header';
import List from '../../components/List';
import TrackList from '../../components/TrackList';
import GridItem from '../../components/GridItem';
import DropdownField from '../../components/Fields/DropdownField';
import Icon from '../../components/Icon';
import URILink from '../../components/URILink';
import ErrorBoundary from '../../components/ErrorBoundary';
import * as helpers from '../../helpers'
import * as uiActions from '../../services/ui/actions'
import * as mopidyActions from '../../services/mopidy/actions'
import * as spotifyActions from '../../services/spotify/actions'
import * as helpers from '../../helpers';
import * as uiActions from '../../services/ui/actions';
import * as mopidyActions from '../../services/mopidy/actions';
class LibraryBrowse extends React.Component{
@ -36,182 +36,19 @@ class LibraryBrowse extends React.Component{
if (!this.props.mopidy_connected && nextProps.mopidy_connected){
this.loadDirectory(nextProps);
}
// our uri changes
if (nextProps.match.params.uri != this.props.match.params.uri){
this.loadDirectory(nextProps);
}
}
loadDirectory(props = this.props){
if (props.mopidy_connected){
var uri = null
if (props.match.params.uri !== undefined){
uri = props.match.params.uri;
if (props.uri !== undefined){
uri = props.uri;
}
this.props.mopidyActions.getDirectory(uri);
}
}
playAll(e, tracks){
var tracks_uris = helpers.arrayOf('uri',tracks);
this.props.mopidyActions.playURIs(tracks_uris, "iris:browse:"+this.props.match.params.uri);
this.props.uiActions.hideContextMenu();
}
goBack(e){
window.history.back();
this.props.uiActions.hideContextMenu();
}
renderBreadcrumbs(){
if (this.props.match.params.uri){
var parent_uri = this.props.match.params.uri;
} else {
return null;
}
if (parent_uri.startsWith('file://')){
var uri = parent_uri.replace('file:///','');
var uri_elements = uri.split('/');
return (
<h4>
{uri_elements.map((uri_element, index) => {
// Reconstruct a URL to this element
var uri = "file://";
for (var i = 0; i <= index; i++){
uri += "/"+uri_elements[i];
}
return (
<span key={uri}>
{index > 0 ? <span>&nbsp; <Icon type="fontawesome" name="angle-right" /> &nbsp;&nbsp;</span> : null}
<URILink type="browse" uri={uri}>
{decodeURI(uri_element)}
</URILink>
</span>
);
})}
</h4>
);
}
return null;
}
renderSubdirectories(subdirectories){
if (this.props.view == 'list'){
return (
<List
nocontext
rows={subdirectories}
className="library-local-directory-list"
link_prefix={global.baseURL+'library/browse/'}
/>
);
} else {
return (
<div className="grid category-grid">
{
subdirectories.map(subdirectory => {
return (
<GridItem
key={subdirectory.uri}
type="category"
item={subdirectory}
onClick={e => {this.props.history.push(global.baseURL+'library/browse/'+encodeURIComponent(subdirectory.uri))}}
/>
);
})
}
</div>
);
}
}
renderDirectory(directory){
var title = 'Browse';
var uri_exploded = this.props.match.params.uri.split(':');
if (uri_exploded.length > 0){
title = uri_exploded[0];
title = title.charAt(0).toUpperCase() + title.slice(1);
}
if (!this.props.directory || helpers.isLoading(this.props.load_queue,['mopidy_browse'])){
return (
<div className="view library-local-view">
<Header icon="music" title={title} uiActions={this.props.uiActions} />
<div className="body-loader loading">
<div className="loader"></div>
</div>
</div>
)
}
var tracks = (this.props.directory.tracks && this.props.directory.tracks.length > 0 ? this.props.directory.tracks : null);
tracks = helpers.sortItems(tracks, 'name');
var subdirectories = (this.props.directory.subdirectories && this.props.directory.subdirectories.length > 0 ? this.props.directory.subdirectories : null);
subdirectories = helpers.sortItems(subdirectories, 'name');
var view_options = [
{
label: 'Thumbnails',
value: 'thumbnails'
},
{
label: 'List',
value: 'list'
}
];
var options = (
<span>
<DropdownField
icon="visibility"
name="View"
value={this.props.view}
options={view_options}
handleChange={value => {this.props.uiActions.set({ library_directory_view: value }); this.props.uiActions.hideContextMenu()}}
/>
{tracks ? <a className="button button--no-hover" onClick={e => {this.props.uiActions.hideContextMenu(); this.playAll(e, tracks)}}>
<Icon name="play_circle_filled" />Play all
</a> : null }
<a className="button button--no-hover" onClick={e => {this.props.uiActions.hideContextMenu(); this.goBack(e)}}>
<Icon name="keyboard_backspace" />Back
</a>
</span>
);
return (
<div className="view library-local-view">
<Header options={options} uiActions={this.props.uiActions}>
<Icon name="folder" type="material" />
{title}
</Header>
<section className="content-wrapper">
<ErrorBoundary>
{this.renderBreadcrumbs()}
{subdirectories ? this.renderSubdirectories(subdirectories) : null}
{tracks ? <TrackList
tracks={this.props.directory.tracks}
uri={"iris:browse:"+this.props.match.params.uri}
className="library-local-track-list"
/> : null }
</ErrorBoundary>
</section>
</div>
);
}
renderIndex(){
render(){
var grid_items = []
if (this.props.directory){
for (var subdirectory of this.props.directory.subdirectories){
@ -269,7 +106,7 @@ class LibraryBrowse extends React.Component{
return (
<div className="view library-local-view">
<Header uiActions={this.props.uiActions}>
<Header>
<Icon name="folder" type="material" />
Browse
</Header>
@ -284,7 +121,6 @@ class LibraryBrowse extends React.Component{
item={item}
key={index}
type="category"
onClick={e => this.props.history.push(item.link)}
/>
)
}
@ -296,14 +132,6 @@ class LibraryBrowse extends React.Component{
</div>
);
}
render(){
if (this.props.match.params.uri !== undefined && this.props.match.params.uri){
return this.renderDirectory();
} else {
return this.renderIndex();
}
}
}
const mapStateToProps = (state, ownProps) => {
@ -318,8 +146,7 @@ const mapStateToProps = (state, ownProps) => {
const mapDispatchToProps = (dispatch) => {
return {
uiActions: bindActionCreators(uiActions, dispatch),
mopidyActions: bindActionCreators(mopidyActions, dispatch),
spotifyActions: bindActionCreators(spotifyActions, dispatch)
mopidyActions: bindActionCreators(mopidyActions, dispatch)
}
}

View File

@ -0,0 +1,235 @@
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import Link from '../../components/Link';
import Header from '../../components/Header';
import List from '../../components/List';
import TrackList from '../../components/TrackList';
import GridItem from '../../components/GridItem';
import DropdownField from '../../components/Fields/DropdownField';
import Icon from '../../components/Icon';
import URILink from '../../components/URILink';
import ErrorBoundary from '../../components/ErrorBoundary';
import * as helpers from '../../helpers';
import * as uiActions from '../../services/ui/actions';
import * as mopidyActions from '../../services/mopidy/actions';
import * as spotifyActions from '../../services/spotify/actions';
class LibraryBrowseDirectory extends React.Component{
constructor(props){
super(props);
}
componentDidMount(){
this.props.uiActions.setWindowTitle("Browse");
this.loadDirectory();
}
componentWillReceiveProps(nextProps){
// mopidy goes online
if (!this.props.mopidy_connected && nextProps.mopidy_connected){
this.loadDirectory(nextProps);
}
// our uri changes
if (nextProps.uri && nextProps.uri !== this.props.uri){
console.log(nextProps.uri,this.props.uri);
//this.loadDirectory(nextProps);
}
}
loadDirectory(props = this.props){
if (props.mopidy_connected){
var uri = null
if (props.uri !== undefined){
uri = props.uri;
}
this.props.mopidyActions.getDirectory(uri);
}
}
playAll(e, tracks){
var tracks_uris = helpers.arrayOf('uri',tracks);
this.props.mopidyActions.playURIs(tracks_uris, "iris:browse:"+this.props.uri);
this.props.uiActions.hideContextMenu();
}
goBack(e){
window.history.back();
this.props.uiActions.hideContextMenu();
}
renderBreadcrumbs(){
if (this.props.uri){
var parent_uri = this.props.uri;
} else {
return null;
}
if (parent_uri.startsWith('file://')){
var uri = parent_uri.replace('file:///','');
var uri_elements = uri.split('/');
return (
<h4>
{uri_elements.map((uri_element, index) => {
// Reconstruct a URL to this element
var uri = "file://";
for (var i = 0; i <= index; i++){
uri += "/"+uri_elements[i];
}
return (
<span key={uri}>
{index > 0 ? <span>&nbsp; <Icon type="fontawesome" name="angle-right" /> &nbsp;&nbsp;</span> : null}
<URILink type="browse" uri={uri}>
{decodeURI(uri_element)}
</URILink>
</span>
);
})}
</h4>
);
}
return null;
}
renderSubdirectories(subdirectories){
if (this.props.view == 'list'){
return (
<List
nocontext
rows={subdirectories}
className="library-local-directory-list"
link_prefix={global.baseURL+'library/browse/'}
/>
);
} else {
return (
<div className="grid category-grid">
{
subdirectories.map(subdirectory => {
return (
<GridItem
key={subdirectory.uri}
type="directory"
item={subdirectory}
/>
);
})
}
</div>
);
}
}
render(){
var title = 'Directory';
var uri_exploded = this.props.uri.split(':');
if (uri_exploded.length > 0){
title = uri_exploded[0];
title = title.charAt(0).toUpperCase() + title.slice(1);
}
if (!this.props.directory || helpers.isLoading(this.props.load_queue,['mopidy_browse'])){
return (
<div className="view library-local-view">
<Header icon="music" title={title} uiActions={this.props.uiActions} />
<div className="body-loader loading">
<div className="loader"></div>
</div>
</div>
)
}
var tracks = (this.props.directory.tracks && this.props.directory.tracks.length > 0 ? this.props.directory.tracks : null);
tracks = helpers.sortItems(tracks, 'name');
var subdirectories = (this.props.directory.subdirectories && this.props.directory.subdirectories.length > 0 ? this.props.directory.subdirectories : null);
subdirectories = helpers.sortItems(subdirectories, 'name');
var view_options = [
{
label: 'Thumbnails',
value: 'thumbnails'
},
{
label: 'List',
value: 'list'
}
];
var options = (
<span>
<DropdownField
icon="visibility"
name="View"
value={this.props.view}
options={view_options}
handleChange={value => {this.props.uiActions.set({ library_directory_view: value }); this.props.uiActions.hideContextMenu()}}
/>
{tracks ? <a className="button button--no-hover" onClick={e => {this.props.uiActions.hideContextMenu(); this.playAll(e, tracks)}}>
<Icon name="play_circle_filled" />Play all
</a> : null }
<a className="button button--no-hover" onClick={e => {this.props.uiActions.hideContextMenu(); this.goBack(e)}}>
<Icon name="keyboard_backspace" />Back
</a>
</span>
);
return (
<div className="view library-local-view">
<Header options={options} uiActions={this.props.uiActions}>
<Icon name="folder" type="material" />
{title}
</Header>
<section className="content-wrapper">
<ErrorBoundary>
{this.renderBreadcrumbs()}
{subdirectories ? this.renderSubdirectories(subdirectories) : null}
{tracks ? <TrackList
tracks={this.props.directory.tracks}
uri={"iris:browse:"+this.props.uri}
className="library-local-track-list"
/> : null }
</ErrorBoundary>
</section>
</div>
);
}
}
const mapStateToProps = (state, ownProps) => {
var uri = decodeURIComponent(ownProps.match.params.uri);
return {
uri: uri,
load_queue: state.ui.load_queue,
mopidy_connected: state.mopidy.connected,
directory: state.mopidy.directory,
view: state.ui.library_directory_view
}
}
const mapDispatchToProps = (dispatch) => {
return {
uiActions: bindActionCreators(uiActions, dispatch),
mopidyActions: bindActionCreators(mopidyActions, dispatch),
spotifyActions: bindActionCreators(spotifyActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(LibraryBrowseDirectory)