From b99894901a2e9d082ccba9c4d8fa50e178b7fd04 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Wed, 25 Jan 2023 19:56:11 +1300 Subject: [PATCH] Upgrading BrowseDirectory to functional component --- src/js/views/Album.js | 22 +- src/js/views/Library/BrowseDirectory.js | 377 ++++++++++-------------- 2 files changed, 168 insertions(+), 231 deletions(-) diff --git a/src/js/views/Album.js b/src/js/views/Album.js index ec7fd666..88608dbd 100755 --- a/src/js/views/Album.js +++ b/src/js/views/Album.js @@ -15,10 +15,15 @@ import { SourceIcon } 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 lastfmActions from '../services/lastfm/actions'; +import { loadAlbum } from '../services/core/actions'; +import { playURIs } from '../services/mopidy/actions'; +import { getAlbum } from '../services/lastfm/actions'; +import { + setSort, + setWindowTitle, + showContextMenu, + hideContextMenu, +} from '../services/ui/actions'; import { uriSource } from '../util/helpers'; import Button from '../components/Button'; import { makeItemSelector, makeSortSelector } from '../util/selectors'; @@ -28,15 +33,6 @@ import { decodeUri, formatContext } from '../util/format'; const SORT_KEY = 'album_tracks'; const Album = () => { - const { loadAlbum } = coreActions; - const { getAlbum } = lastfmActions; - const { playURIs } = mopidyActions; - const { - setSort, - setWindowTitle, - showContextMenu, - hideContextMenu, - } = uiActions; const dispatch = useDispatch(); const { uri: encodedUri } = useParams(); const uri = decodeUri(encodedUri); diff --git a/src/js/views/Library/BrowseDirectory.js b/src/js/views/Library/BrowseDirectory.js index d18bcef2..e416a417 100755 --- a/src/js/views/Library/BrowseDirectory.js +++ b/src/js/views/Library/BrowseDirectory.js @@ -1,6 +1,6 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; +import React, { useEffect, useState } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { useParams } from 'react-router-dom'; import Loader from '../../components/Loader'; import Header from '../../components/Header'; import TrackList from '../../components/TrackList'; @@ -10,8 +10,15 @@ import DropdownField from '../../components/Fields/DropdownField'; import FilterField from '../../components/Fields/FilterField'; import Icon from '../../components/Icon'; import ErrorBoundary from '../../components/ErrorBoundary'; -import * as uiActions from '../../services/ui/actions'; -import * as mopidyActions from '../../services/mopidy/actions'; +import { + set, + setWindowTitle, + hideContextMenu, +} from '../../services/ui/actions'; +import { + getDirectory, + playURIs, +} from '../../services/mopidy/actions'; import * as spotifyActions from '../../services/spotify/actions'; import { arrayOf, sortItems, applyFilter } from '../../util/arrays'; import { i18n, I18n } from '../../locale'; @@ -19,7 +26,8 @@ import Button from '../../components/Button'; import { encodeUri, decodeUri } from '../../util/format'; import { makeLoadingSelector } from '../../util/selectors'; import ErrorMessage from '../../components/ErrorMessage'; -import { withRouter } from '../../util'; + +const loadingSelector = makeLoadingSelector(['mopidy_library.(browse|lookup)']); const Breadcrumbs = ({ uri }) => { let parent_uri = uri || null; @@ -64,221 +72,154 @@ const Subdirectories = ({ items, view }) => { ); }; -class BrowseDirectory extends React.Component { - constructor(props) { - super(props); +const BrowseDirectory = () => { + const dispatch = useDispatch(); + const [filter, setFilter] = useState(''); + const directoryInState = useSelector(({ mopidy }) => mopidy?.directory || {}); + const view = useSelector(({ ui }) => ui?.library_directory_view); + const loading = useSelector(loadingSelector); - this.state = { - filter: '', - }; - } - - componentDidMount() { - const { - uiActions: { - setWindowTitle, - }, - } = this.props; - - 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); - } - - playAll = () => { - const { - uri, - mopidyActions: { - playURIs, - }, - uiActions: { - hideContextMenu, - }, - directory: { - tracks, - } = {}, - } = this.props; - - if (!tracks || !tracks.length) return; - - playURIs({ - uris: arrayOf('uri', sortItems(tracks, 'name')), - from: { - name: 'Browse', - type: 'browse', - uri, - }, - }); - hideContextMenu(); - } - - goBack = () => { - const { uiActions: { hideContextMenu } } = this.props; - - window.history.back(); - hideContextMenu(); - } - - render = () => { - const { - uri, - directory, - uiActions, - loading, - view, - name, - } = this.props; - const { filter } = this.state; - - if (!directory || (!directory.subdirectories && !directory.tracks)) { - if (loading) { - return ; - } - return ( - -

- -

-
- ); - } - - let subdirectories = directory?.subdirectories; - let tracks = directory?.tracks; - subdirectories = sortItems(subdirectories, 'name'); - tracks = sortItems(tracks, 'name'); - if (filter && filter !== '') { - subdirectories = applyFilter('name', filter, subdirectories); - tracks = applyFilter('name', filter, tracks); - } - - const view_options = [ - { - value: 'thumbnails', - label: i18n('fields.filters.thumbnails'), - }, - { - value: 'list', - label: i18n('fields.filters.list'), - }, - ]; - - const options = ( - <> - this.setState({ filter: value })} - onSubmit={() => uiActions.hideContextMenu()} - /> - { uiActions.set({ library_directory_view: value }); uiActions.hideContextMenu(); }} - /> - {tracks && ( - - )} - - - ); - - return ( -
-
- -
- {name || i18n('library.browse_directory.title')} - -
-
-
- - - - - - - -
-
- ); - } -} - -const loadingSelector = makeLoadingSelector(['mopidy_library.(browse|lookup)']); -const mapStateToProps = (state, ownProps) => { - console.debug('browser directory', ownProps) - const { - mopidy: { - directory: _directory = {}, - }, - ui: { - library_directory_view: view, - }, - } = state; - const uri = decodeUri(ownProps.params.uri); + let { uri, name } = useParams(); + uri = decodeUri(uri); + name = decodeURIComponent(name); const uriMatcher = [uri, decodeURIComponent(uri)]; // Lenient matching due to encoding diffs - const directory = _directory && uriMatcher.includes(_directory.uri) - ? _directory + const directory = directoryInState && uriMatcher.includes(directoryInState.uri) + ? directoryInState : undefined; - return { - uri, - name: decodeURIComponent(ownProps.params.name), - loading: loadingSelector(state), - directory, - view, - }; -}; + useEffect(() => { + dispatch(setWindowTitle(i18n('library.browse_directory.title'))); + dispatch(getDirectory(uri)); + }, []); -const mapDispatchToProps = (dispatch) => ({ - uiActions: bindActionCreators(uiActions, dispatch), - mopidyActions: bindActionCreators(mopidyActions, dispatch), - spotifyActions: bindActionCreators(spotifyActions, dispatch), -}); + useEffect(() => { + dispatch(getDirectory(uri)); + }, [uri]); -export default withRouter(connect(mapStateToProps, mapDispatchToProps)(BrowseDirectory)); + const onViewChange = (value) => { + dispatch(set({ library_directory_view: value })); + dispatch(hideContextMenu()); + } + + const playAll = () => { + if (!tracks || !tracks.length) return; + + dispatch( + playURIs({ + uris: arrayOf('uri', sortItems(tracks, 'name')), + from: { + name: 'Browse', + type: 'browse', + uri, + }, + }) + ); + dispatch(hideContextMenu()); + } + + const goBack = () => { + dispatch(hideContextMenu()); + window.history.back(); + } + + if (!directory || (!directory.subdirectories && !directory.tracks)) { + if (loading) { + return ; + } + return ( + +

+ +

+
+ ); + } + + let subdirectories = directory?.subdirectories; + let tracks = directory?.tracks; + subdirectories = sortItems(subdirectories, 'name'); + tracks = sortItems(tracks, 'name'); + if (filter && filter !== '') { + subdirectories = applyFilter('name', filter, subdirectories); + tracks = applyFilter('name', filter, tracks); + } + + const view_options = [ + { + value: 'thumbnails', + label: i18n('fields.filters.thumbnails'), + }, + { + value: 'list', + label: i18n('fields.filters.list'), + }, + ]; + + const options = ( + <> + dispatch(hideContextMenu())} + /> + + {tracks && ( + + )} + + + ); + + return ( +
+
+ +
+ {name || i18n('library.browse_directory.title')} + +
+
+
+ + + + + + + +
+
+ ); +} + +export default BrowseDirectory;