import React from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import Loader from '../../components/Loader'; 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 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'; import { isLoading, } from '../../util/helpers'; import { arrayOf, sortItems } from '../../util/arrays'; import { i18n, I18n } from '../../locale'; import Button from '../../components/Button'; class LibraryBrowseDirectory extends React.Component { constructor(props) { super(props); this.state = { filter: '', limit: 50, per_page: 50, }; } componentDidMount() { // Restore any limit defined in our location state const state = (this.props.location.state ? this.props.location.state : {}); if (state.limit) { this.setState({ limit: state.limit, }); } this.props.uiActions.setWindowTitle(i18n('library.browse_directory.title')); this.loadDirectory(); } componentDidUpdate = ({ uri: prevUri }) => { const { uri } = this.props; if (uri && uri !== prevUri) { this.loadDirectory(); } } loadDirectory = () => { const { uri, mopidyActions: { getDirectory, }, } = this.props; getDirectory(uri); } loadMore = () => { const { limit: prevLimit, per_page, } = this.state; const { history, location: { state: prevState = {}, }, } = this.props; const limit = prevLimit + per_page; this.setState({ limit }); history.replace({ ...prevState, limit, }); } playAll = (tracks) => { const { uri, mopidyActions: { playURIs, }, uiActions: { hideContextMenu, }, } = this.props; playURIs(arrayOf('uri', tracks), `iris:browse:${uri}`); hideContextMenu(); } goBack = () => { const { uiActions: { hideContextMenu } } = this.props; window.history.back(); hideContextMenu(); } renderBreadcrumbs = () => { const { uri } = this.props; let parent_uri = uri || null; if (parent_uri.startsWith('file://')) { parent_uri = parent_uri.substring(0, parent_uri.lastIndexOf('/')); return (

{decodeURI(parent_uri)}

); } return null; } renderSubdirectories = (subdirectories) => { const { view } = this.props; if (view === 'list') { return ( ); } return (
{ subdirectories.map((subdirectory) => ( )) }
); } render = () => { const { uri, directory, load_queue, uiActions, view, } = this.props; const { limit, } = this.state; let title = i18n('library.browse_directory.title'); if (!directory || isLoading(load_queue, ['mopidy_browse'])) { return (
); } if (directory.name) { title = directory.name; } else { const uri_exploded = uri.split(':'); if (uri_exploded.length > 0) { title = uri_exploded[0]; title = title.charAt(0).toUpperCase() + title.slice(1); } }; let subdirectories = (directory.subdirectories && directory.subdirectories.length > 0 ? directory.subdirectories : null); subdirectories = sortItems(subdirectories, 'name'); const total_items = (directory.tracks ? directory.tracks.length : 0) + (subdirectories ? subdirectories.length : 0); subdirectories = subdirectories.slice(0, limit); let all_tracks = null; let tracks = null; const limit_remaining = limit - subdirectories.length; if (limit_remaining > 0) { all_tracks = (directory.tracks && directory.tracks.length > 0 ? directory.tracks : null); all_tracks = sortItems(all_tracks, 'name'); tracks = all_tracks.slice(0, limit_remaining); } const view_options = [ { value: 'thumbnails', label: i18n('fields.filters.thumbnails'), }, { value: 'list', label: i18n('fields.filters.list'), }, ]; const options = ( <> { uiActions.set({ library_directory_view: value }); uiActions.hideContextMenu(); }} /> {tracks && ( )} ); return (
{title}
{this.renderBreadcrumbs()} {subdirectories ? this.renderSubdirectories(subdirectories) : null} {tracks && ( )} limit ? limit : total_items} showLoader={limit < total_items} loadMore={this.loadMore} />
); } } const mapStateToProps = (state, ownProps) => { // Decode the URI, and then re-encode selected characters // This is needed as Mopidy encodes *some* characters in URIs (but not other characters) // We need to retain ":" because this a reserved URI separator let uri = decodeURIComponent(ownProps.match.params.uri); uri = uri.replace(/\s/g, '%20'); // space uri = uri.replace(/&/g, '%26'); // & uri = uri.replace(/\[/g, '%5B'); // [ uri = uri.replace(/\]/g, '%5D'); // ] uri = uri.replace(/\(/g, '%28'); // ( uri = uri.replace(/\)/g, '%29'); // ) uri = uri.replace(/\#/g, '%23'); // # return { uri, load_queue: state.ui.load_queue, directory: state.mopidy.directory, view: state.ui.library_directory_view, }; }; const mapDispatchToProps = (dispatch) => ({ uiActions: bindActionCreators(uiActions, dispatch), mopidyActions: bindActionCreators(mopidyActions, dispatch), spotifyActions: bindActionCreators(spotifyActions, dispatch), }); export default connect(mapStateToProps, mapDispatchToProps)(LibraryBrowseDirectory);