diff --git a/src/js/views/Artist.js b/src/js/views/Artist.js index f3fb62c3..231a5cb7 100755 --- a/src/js/views/Artist.js +++ b/src/js/views/Artist.js @@ -51,9 +51,7 @@ const Artist = ({ useEffect( () => { - if (uri) { - loadArtist(uri, { full: true }); - } + if (uri) loadArtist(uri, { full: true }); }, [uri], ); @@ -81,15 +79,13 @@ const Artist = ({ playURIs(arrayOf('uri', tracks) || albums_uris, uri); } - const handleContextMenu = (e) => { - showContextMenu({ - e, - context: 'artist', - items: [artist], - uris: [uri], - tracklist_uri: uri, - }); - } + const handleContextMenu = (e) => showContextMenu({ + e, + context: 'artist', + items: [artist], + uris: [uri], + tracklist_uri: uri, + }); if (loading) { return ; diff --git a/src/js/views/Playlist.js b/src/js/views/Playlist.js index 88b64d19..bc1d7d23 100755 --- a/src/js/views/Playlist.js +++ b/src/js/views/Playlist.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import ErrorMessage from '../components/ErrorMessage'; @@ -20,7 +20,6 @@ import * as uiActions from '../services/ui/actions'; import * as mopidyActions from '../services/mopidy/actions'; import * as spotifyActions from '../services/spotify/actions'; import { uriSource } from '../util/helpers'; -import { trackEvent } from '../components/Trackable'; import { i18n, I18n } from '../locale'; import { makeItemSelector, makeLoadingSelector, getSortSelector } from '../util/selectors'; import { sortItems, applyFilter } from '../util/arrays'; @@ -28,126 +27,158 @@ import { decodeUri, encodeUri } from '../util/format'; const SORT_KEY = 'playlist_tracks'; -class Playlist extends React.Component { - constructor(props) { - super(props); +const Actions = ({ + encodedUri, + playlist: { + uri, + can_edit, + name, + in_library, + }, + onPlay, + handleContextMenu, +}) => { + switch (uriSource(uri)) { + case 'm3u': + return ( +
+ + + + +
+ ); - let { uri } = props; + case 'spotify': + if (can_edit) { + return ( +
+ + + + +
+ ); + } + return ( +
+ + + + +
+ ); - this.state = { - filter: '', - }; + default: + return ( +
+ + + +
+ ); + } +} - // Spotify upgraded their playlists URI to remove user component (Sept 2018) - // We accept the old format, and redirect to the new one - if (uri.includes('spotify:user:')) { - uri = uri.replace(/spotify:user:([^:]*?):/i, 'spotify:'); - props.history.push(`/playlist/${encodeUri(uri)}`); +const Playlist = ({ + loading, + loading_tracks, + slim_mode, + history, + uri, + encodedUri, + name, + playlist: playlistProp, + sortField, + sortReverse, + coreActions: { + loadPlaylist, + reorderPlaylistTracks, + removeTracksFromPlaylist, + addPinned, + removePinned, + }, + uiActions: { + setSort, + setWindowTitle, + showContextMenu, + hideContextMenu, + createNotification, + }, + mopidyActions: { + playPlaylist, + }, +}) => { + const [playlist, setPlaylist] = useState({}); + const [filter, setFilter] = useState(''); + + useEffect( + () => { + if (uri) loadPlaylist(uri, { full: true, name }); + }, + [uri], + ); + + useEffect(() => { + if (playlistProp && playlist && playlistProp.moved_to !== playlist.moved_to) { + history.push(`/playlist/${encodeUri(playlistProp.moved_to)}`); } - } + }, [playlistProp]) - componentDidMount() { - const { - coreActions: { - loadPlaylist, - }, - uri, - name, - } = this.props; - this.setWindowTitle(); - setTimeout(() => loadPlaylist(uri, { full: true, name }), 1); - } - - componentDidUpdate = ({ - uri: prevUri, - playlist: prevPlaylist, - }) => { - const { - uri, - name, - playlist, - coreActions: { - loadPlaylist, - }, - history: { - push, - }, - } = this.props; - - if (prevPlaylist && playlist && prevPlaylist.moved_to !== playlist.moved_to) { - push(`/playlist/${encodeUri(playlist.moved_to)}`); + useEffect(() => { + if (playlistProp) { + setWindowTitle(i18n('playlist.title_window', { name: playlistProp.name })); + } else { + setWindowTitle(i18n('playlist.title')); } + setPlaylist(playlistProp); + }, [playlistProp]); - if (uri !== prevUri) { - loadPlaylist(uri, { full: true, name }); - } - - if (!prevPlaylist && playlist) this.setWindowTitle(playlist); - if (prevUri !== uri && playlist) this.setWindowTitle(playlist); - } - - setWindowTitle = (playlist = this.props.playlist) => { - const { uiActions: { setWindowTitle } } = this.props; - setWindowTitle( - playlist ? i18n('playlist.title_window', { name: playlist.name }) : i18n('playlist.title'), - ); - } - - handleContextMenu = (e) => { - const { - uiActions: { - showContextMenu, - }, - playlist, - uri, - name, - } = this.props; - - showContextMenu({ - e, - context: 'playlist', - items: [{ name, ...playlist }], - uris: [uri], - }); - } - - play = () => { - const { - mopidyActions: { - playPlaylist, - }, - playlist: { - uri, - }, - } = this.props; - - playPlaylist(uri); - } - - // TODO: Once deletion occurs, remove playlist from global playlists list - delete = () => { - const { - mopidyActions: { - deletePlaylist, - }, - playlist: { - uri, - }, - } = this.props; - - deletePlaylist(uri); - } - - onChangeSort = (field) => { - const { - sortField, - sortReverse, - uiActions: { - setSort, - hideContextMenu, - }, - } = this.props; + const handleContextMenu = (e) => showContextMenu({ + e, + context: 'playlist', + items: [{ name, ...playlist }], + uris: [uri], + }); + const onChangeSort = (field) => { let reverse = false; if (field !== null && sortField === field) { reverse = !sortReverse; @@ -155,25 +186,12 @@ class Playlist extends React.Component { setSort(SORT_KEY, field, reverse); hideContextMenu(); - } + }; - reorderTracks = (indexes, index) => { - const { - coreActions: { - reorderPlaylistTracks, - }, - uiActions: { - createNotification, - }, - playlist: { - uri, - snapshot_id, - tracks, - }, - sortField, - sortReverse, - } = this.props; - const { filter } = this.state; + const onPlay = () => playPlaylist(uri); + + const reorderTracks = (indexes, index) => { + const { snapshot_id, tracks } = playlist; if (sortField !== 'sort_id' || filter !== '') { createNotification({ @@ -193,286 +211,140 @@ class Playlist extends React.Component { reorderPlaylistTracks(uri, indexes, index, snapshot_id); } - removeTracks = (tracks_indexes) => { - const { - coreActions: { - removeTracksFromPlaylist, - }, - playlist: { - uri, - }, - } = this.props; - + const removeTracks = (tracks_indexes) => { removeTracksFromPlaylist(uri, tracks_indexes); } - inLibrary = () => { - const { uri } = this.props; - const libraryName = `${uriSource(uri)}_library_playlists`; - const { [libraryName]: library } = this.props; - - if (!library) return false; - - return library.indexOf(uri) > -1; + if (loading) { + return ; } - - togglePinned = () => { - const { - uri, - coreActions: { - addPinned, - removePinned, - }, - } = this.props; - - if (this.isPinned()) { - removePinned(uri); - } else { - addPinned(uri); - } - } - - renderActions = () => { - const { - uri, - encodedUri, - playlist: { - can_edit, - name, - in_library, - }, - } = this.props; - - switch (uriSource(uri)) { - case 'm3u': - return ( -
- - - - -
- ); - - case 'spotify': - if (can_edit) { - return ( -
- - - - -
- ); - } - return ( -
- - - - -
- ); - - default: - return ( -
- - - -
- ); - } - } - - render = () => { - const { - uri, - playlist, - loading, - loading_tracks, - slim_mode, - sortField, - sortReverse, - } = this.props; - const { - filter, - } = this.state; - - if (loading) { - return ; - } - if (!playlist) { - return ( - -

- -

-
- ); - } - - let context = 'playlist'; - if (playlist.can_edit) { - context = 'editable-playlist'; - } - let { - playlist: { - tracks, - }, - } = this.props; - - if (sortField && tracks) { - tracks = sortItems(tracks, sortField, sortReverse); - } - - if (filter && filter !== '') { - tracks = applyFilter('name', filter, tracks); - } - - const sort_options = [ - { - value: 'sort_id', - label: i18n('playlist.tracks.sort.sort_id'), - }, - { - value: 'name', - label: i18n('playlist.tracks.sort.name'), - }, - { - value: 'artist', - label: i18n('playlist.tracks.sort.artist'), - }, - { - value: 'album', - label: i18n('playlist.tracks.sort.album'), - }, - ]; - + if (!playlist) { return ( -
- -
- -
- -
-

{playlist.name}

- {playlist.description && ( -

- )} - -
    - {!slim_mode && ( -
  • - -
  • - )} - {playlist.user && ( -
  • - - {playlist.user.name} - -
  • - )} -
  • - -
  • - {!slim_mode && playlist.tracks && playlist.tracks_total > 0 && ( -
  • - )} - {!slim_mode && playlist.followers !== undefined && ( -
  • - -
  • - )} - {!slim_mode && playlist.last_modified_date && ( -
  • - -
  • - )} -
-

- - {this.renderActions()} - -

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

- -
- -
-
+ +

+ +

+
); } + + let context = 'playlist'; + if (playlist.can_edit) context = 'editable-playlist'; + + let tracks = playlist?.tracks || []; + if (sortField && tracks) tracks = sortItems(tracks, sortField, sortReverse); + if (filter && filter !== '') tracks = applyFilter('name', filter, tracks); + + const sort_options = [ + { + value: 'sort_id', + label: i18n('playlist.tracks.sort.sort_id'), + }, + { + value: 'name', + label: i18n('playlist.tracks.sort.name'), + }, + { + value: 'artist', + label: i18n('playlist.tracks.sort.artist'), + }, + { + value: 'album', + label: i18n('playlist.tracks.sort.album'), + }, + ]; + + return ( +
+ +
+ +
+ +
+

{playlist.name}

+ {playlist.description && ( +

+ )} + +
    + {!slim_mode && ( +
  • + +
  • + )} + {playlist.user && ( +
  • + + {playlist.user.name} + +
  • + )} +
  • + +
  • + {!slim_mode && playlist.tracks && playlist.tracks_total > 0 && ( +
  • + )} + {!slim_mode && playlist.followers !== undefined && ( +
  • + +
  • + )} + {!slim_mode && playlist.last_modified_date && ( +
  • + +
  • + )} +
+

+ + + +

+ + {loading_tracks && } +
+ + +
+

+ +
+ +
+
+ ); } const mapStateToProps = (state, ownProps) => {