import React from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import ErrorMessage from '../components/ErrorMessage'; import TrackList from '../components/TrackList'; import Thumbnail from '../components/Thumbnail'; import LinksSentence from '../components/LinksSentence'; import Loader from '../components/Loader'; import FollowButton from '../components/Fields/FollowButton'; import { nice_number } from '../components/NiceNumber'; import { Dater } from '../components/Dater'; import ContextMenuTrigger from '../components/ContextMenuTrigger'; import Icon from '../components/Icon'; import DropdownField from '../components/Fields/DropdownField'; import FilterField from '../components/Fields/FilterField'; import { i18n, I18n } from '../locale'; import * as coreActions from '../services/core/actions'; import * as uiActions from '../services/ui/actions'; import * as mopidyActions from '../services/mopidy/actions'; import * as spotifyActions from '../services/spotify/actions'; import * as lastfmActions from '../services/lastfm/actions'; import { uriSource, sourceIcon, } from '../util/helpers'; import Button from '../components/Button'; import { makeLoadingSelector, makeItemSelector } from '../util/selectors'; import { applyFilter, sortItems } from '../util/arrays'; import { trackEvent } from '../components/Trackable'; import { encodeUri } from '../util/format'; class Album extends React.Component { constructor(props) { super(props); this.state = { filter: '', }; } componentDidMount = () => { const { uri, album, coreActions: { loadAlbum, }, lastfmActions: { getAlbum, }, } = this.props; this.setWindowTitle(); loadAlbum(uri, { full: true }); if (album) { if (album.artists && album.wiki === undefined) { getAlbum(album.uri, album.artists[0].name, album.name); } } } componentDidUpdate = ({ uri: prevUri, album: prevAlbum, }) => { const { uri, album, coreActions: { loadAlbum, }, lastfmActions: { getAlbum, }, } = this.props; if (uri !== prevUri) { loadAlbum(uri, { full: true }); } // We have just received our full album or our album artists if ((!prevAlbum && album)) { if (album.artists && album.wiki === undefined) { getAlbum(album.uri, album.artists[0].name, album.name); } } if (!prevAlbum && album) this.setWindowTitle(album); } setWindowTitle = (album = this.props.album) => { const { uiActions: { setWindowTitle }, artists } = this.props; if (album) { let artistNames = []; if (album.artists_uris && artists) { for (let i = 0; i < album.artists_uris.length; i++) { const uri = album.artists_uris[i]; if (artists.hasOwnProperty(uri)) { artistNames.push(artists[uri].name); } } } setWindowTitle(i18n('album.title_window', { name: album.name, artist: artistNames.join() })); } else { setWindowTitle(i18n('album.title')); } } handleContextMenu = (e) => { const { album, uri, uiActions: { showContextMenu } } = this.props; showContextMenu({ e, context: 'album', items: [album], uris: [uri], }); } loadMore = () => { const { spotifyActions: { getMore, }, album: { uri, name, tracks_more, } = {}, } = this.props; getMore( tracks_more, { parent_type: 'album', parent_key: uri, records_type: 'track', }, null, { album: { uri, name, }, }, ); } play = () => { const { uri, mopidyActions: { playURIs } } = this.props; playURIs([uri], uri); } onChangeSort = (value) => { const { sort, sort_reverse, uiActions: { set, hideContextMenu, }, } = this.props; let reverse = false; if (value !== null && sort === value) { reverse = !sort_reverse; } set({ album_tracks_sort_reverse: reverse, album_tracks_sort: value, }); hideContextMenu(); trackEvent({ category: 'Album', action: 'SortTracks', label: `${value} ${reverse ? 'DESC' : 'ASC'}` }); } inLibrary = () => { const { uri } = this.props; const library = `${uriSource(uri)}_library_albums`; return (this.props[library] && this.props[library].indexOf(this.props.uri) > -1); } render = () => { const { uri, album, loading, slim_mode, sort, sort_reverse, } = this.props; let { album: { tracks, } = {}, } = this.props; const { filter, } = this.state; if (loading) { return ; } if (!album) { return (

{i18n('errors.uri_not_found', { uri })}

); } if (sort && tracks) { tracks = sortItems(tracks, sort, sort_reverse); } if (filter && filter !== '') { tracks = applyFilter('name', filter, tracks); } const sort_options = [ { value: 'disc_track', label: i18n('album.tracks.sort.disc_track'), }, { value: 'name', label: i18n('album.tracks.sort.name'), }, ]; return (

{album.name}

    {!slim_mode ? (
  • ) : null} {album.artists && album.artists.length > 0 ? (
  • ) : null} {album.release_date ? (
  • ) : null} {album.tracks ? (
  • {i18n( 'specs.tracks', { count: album.tracks.length }, )}
  • ) : null} {!slim_mode && album.tracks ? (
  • ) : null} {!slim_mode && album.play_count ? (
  • {i18n( 'specs.plays', { count: nice_number(album.play_count) }, )}
  • ) : null} {!slim_mode && album.listeners ? (
  • {i18n( 'specs.listeners', { count: nice_number(album.listeners) }, )}
  • ) : null}
{uriSource(uri) === 'spotify' && ( )}

this.setState({ filter: value })} onSubmit={() => uiActions.hideContextMenu()} />

{album.wiki ? (

{i18n('album.wiki.title')}

{album.wiki}


) : null}
); } } const mapStateToProps = (state, ownProps) => { const uri = decodeURIComponent(ownProps.match.params.uri); const itemSelector = makeItemSelector(uri); const loadingSelector = makeLoadingSelector([`(.*)${uri}(.*)`, '^((?!contains).)*$', '^((?!me\/albums).)*$']); return { uri, slim_mode: state.ui.slim_mode, theme: state.ui.theme, album: itemSelector(state), loading: loadingSelector(state), spotify_library_albums: state.spotify.library_albums, local_library_albums: state.mopidy.library_albums, spotify_authorized: state.spotify.authorization, sort: (state.ui.album_tracks_sort ? state.ui.album_tracks_sort : 'disc_track'), sort_reverse: (!!state.ui.album_tracks_sort_reverse), }; }; const mapDispatchToProps = (dispatch) => ({ coreActions: bindActionCreators(coreActions, dispatch), uiActions: bindActionCreators(uiActions, dispatch), mopidyActions: bindActionCreators(mopidyActions, dispatch), spotifyActions: bindActionCreators(spotifyActions, dispatch), lastfmActions: bindActionCreators(lastfmActions, dispatch), }); export { Album, }; export default connect( mapStateToProps, mapDispatchToProps, )(Album);