Removing remaining artistLoaded, albumLoaded, etc in favor of itemLoaded for consistent pipeline; Looking at search
This commit is contained in:
@ -37,7 +37,7 @@ class DebugInfo extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
renderLoadQueue() {
|
||||
renderload_queue() {
|
||||
const { ui: { load_queue } } = this.props;
|
||||
if (!load_queue) return <div className="debug-info-item mid_grey-text">Nothing loading</div>;
|
||||
|
||||
@ -171,7 +171,7 @@ kb (~
|
||||
|
||||
<div className="debug-info-section">
|
||||
<h5>Load queue</h5>
|
||||
{this.renderLoadQueue()}
|
||||
{this.renderload_queue()}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@ -57,21 +57,20 @@ class AddSeedField extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
handleSelect(e, item) {
|
||||
handleSelect = (e, item) => {
|
||||
const {
|
||||
onSelect,
|
||||
spotifyActions: {
|
||||
clearAutocompleteResults,
|
||||
},
|
||||
coreActions: {
|
||||
itemLoaded,
|
||||
},
|
||||
} = this.props;
|
||||
this.setState({ value: '' });
|
||||
this.props.onSelect(e, item.uri);
|
||||
this.props.spotifyActions.clearAutocompleteResults(this.id);
|
||||
|
||||
// Add our selected item to our global index
|
||||
switch (uriType(item.uri)) {
|
||||
case 'artist':
|
||||
this.props.coreActions.artistsLoaded(item);
|
||||
break;
|
||||
|
||||
case 'track':
|
||||
this.props.coreActions.tracksLoaded(item);
|
||||
break;
|
||||
}
|
||||
onSelect(e, item.uri);
|
||||
clearAutocompleteResults(this.id);
|
||||
itemLoaded(item);
|
||||
}
|
||||
|
||||
results() {
|
||||
|
||||
@ -20,7 +20,7 @@ export default class ListItem extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { item, lastfmActions, discogsActions } = this.props;
|
||||
const { item, mopidyActions, discogsActions } = this.props;
|
||||
if (!item) return;
|
||||
|
||||
// If the item that has just been mounted doesn't have images,
|
||||
@ -29,13 +29,13 @@ export default class ListItem extends React.Component {
|
||||
switch (uriType(item.uri)) {
|
||||
case 'artist':
|
||||
if (discogsActions) {
|
||||
discogsActions.getArtistImages(item.uri, item);
|
||||
//discogsActions.getArtistImages(item.uri, item);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'album':
|
||||
if (lastfmActions && item.artists && item.artists.length > 0) {
|
||||
lastfmActions.getAlbum(item.uri, item.artists[0].name, item.name, (item.mbid ? item.mbid : null));
|
||||
if (mopidyActions) {
|
||||
mopidyActions.getImages([item.uri]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { titleCase, getIndexedRecords } from '../util/helpers';
|
||||
import { sortItems } from '../util/arrays';
|
||||
import { sortItems, indexToArray } from '../util/arrays';
|
||||
import URILink from './URILink';
|
||||
import Icon from './Icon';
|
||||
import AlbumGrid from './AlbumGrid';
|
||||
@ -17,7 +17,7 @@ const SearchResults = ({
|
||||
type,
|
||||
query,
|
||||
loadMore,
|
||||
index,
|
||||
items,
|
||||
mopidy_search_results,
|
||||
spotify_search_results,
|
||||
sort,
|
||||
@ -39,7 +39,7 @@ const SearchResults = ({
|
||||
...(
|
||||
type === 'tracks'
|
||||
? mopidy_search_results[type]
|
||||
: getIndexedRecords(index, mopidy_search_results[type])
|
||||
: indexToArray(items, mopidy_search_results[type])
|
||||
),
|
||||
];
|
||||
}
|
||||
@ -50,7 +50,7 @@ const SearchResults = ({
|
||||
...(
|
||||
type === 'tracks'
|
||||
? spotify_search_results[type]
|
||||
: getIndexedRecords(index, spotify_search_results[type])
|
||||
: indexToArray(items, spotify_search_results[type])
|
||||
),
|
||||
];
|
||||
}
|
||||
@ -120,8 +120,8 @@ const SearchResults = ({
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
index: state.core[ownProps.type] || [],
|
||||
const mapStateToProps = (state) => ({
|
||||
items: state.core.items,
|
||||
uri_schemes_priority: state.ui.uri_schemes_priority || [],
|
||||
mopidy_search_results: state.mopidy.search_results || {},
|
||||
spotify_search_results: state.spotify.search_results || {},
|
||||
|
||||
@ -315,7 +315,7 @@ const CoreMiddleware = (function () {
|
||||
* */
|
||||
case 'LOAD_ITEMS':
|
||||
action.uris.forEach((uri) => {
|
||||
store.dispatch(uiActions.startLoading(uri, `load_item_${uri}`));
|
||||
store.dispatch(uiActions.startLoading(uri));
|
||||
store.dispatch({
|
||||
type: `LOAD_${uriType(uri).toUpperCase()}`,
|
||||
uri,
|
||||
@ -350,7 +350,8 @@ const CoreMiddleware = (function () {
|
||||
store.getState().core.items[action.uri]
|
||||
&& store.getState().core.items[action.uri].images
|
||||
) {
|
||||
console.info(`Using "${action.uri}" from index`);
|
||||
console.info(`${action.uri}" already in index`);
|
||||
store.dispatch(uiActions.stopLoading(action.uri));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -397,7 +398,8 @@ const CoreMiddleware = (function () {
|
||||
store.getState().core.items[action.uri]
|
||||
&& (!action.options.full || store.getState().core.items[action.uri].tracks)
|
||||
) {
|
||||
console.info(`Using "${action.uri}" from index`);
|
||||
console.info(`${action.uri}" already in index`);
|
||||
store.dispatch(uiActions.stopLoading(action.uri));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -419,6 +421,7 @@ const CoreMiddleware = (function () {
|
||||
break;
|
||||
|
||||
case 'LOAD_ARTIST':
|
||||
console.log(action);
|
||||
const fetchArtist = () => {
|
||||
switch (uriSource(action.uri)) {
|
||||
case 'spotify':
|
||||
@ -451,7 +454,9 @@ const CoreMiddleware = (function () {
|
||||
)
|
||||
)
|
||||
) {
|
||||
console.info(`Using "${action.uri}" from index`);
|
||||
console.info(`${action.uri}" already in index`);
|
||||
store.dispatch(coreActions.loadItems(store.getState().core.items[action.uri].albums_uris));
|
||||
store.dispatch(uiActions.stopLoading(action.uri));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -507,7 +512,8 @@ const CoreMiddleware = (function () {
|
||||
|| store.getState().core.items[action.uri].tracks
|
||||
)
|
||||
) {
|
||||
console.info(`Using "${action.uri}" from index`);
|
||||
console.info(`${action.uri}" already in index`);
|
||||
store.dispatch(uiActions.stopLoading(action.uri));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -575,7 +581,7 @@ const CoreMiddleware = (function () {
|
||||
break;
|
||||
|
||||
case 'LOAD_LIBRARY':
|
||||
store.dispatch(uiActions.startLoading(action.uri, `load_library_${action.uri}`));
|
||||
store.dispatch(uiActions.startLoading(action.uri));
|
||||
const fetchLibrary = () => {
|
||||
switch (uriSource(action.uri)) {
|
||||
case 'spotify':
|
||||
@ -602,7 +608,8 @@ const CoreMiddleware = (function () {
|
||||
break;
|
||||
}
|
||||
if (store.getState().core.libraries[action.uri]) {
|
||||
console.info(`Using "${action.uri}" from index`);
|
||||
console.info(`${action.uri}" already in index`);
|
||||
store.dispatch(uiActions.stopLoading(action.uri));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -612,10 +619,12 @@ const CoreMiddleware = (function () {
|
||||
|
||||
const promises = library.items_uris.map((libraryItem) => localForage.getItem(libraryItem));
|
||||
Promise.all(promises).then(
|
||||
(libraryItems) => store.dispatch(coreActions.restoreItemsFromColdStore(compact(libraryItems))),
|
||||
(libraryItems) => {
|
||||
store.dispatch(coreActions.restoreItemsFromColdStore(compact(libraryItems)));
|
||||
store.dispatch(coreActions.restoreLibraryFromColdStore(library));
|
||||
},
|
||||
);
|
||||
|
||||
store.dispatch(coreActions.restoreLibraryFromColdStore(library));
|
||||
} else {
|
||||
fetchLibrary();
|
||||
}
|
||||
@ -720,10 +729,10 @@ const CoreMiddleware = (function () {
|
||||
action.albums = albums_loaded;
|
||||
|
||||
if (artists_loaded.length > 0) {
|
||||
store.dispatch(coreActions.artistsLoaded(artists_loaded));
|
||||
store.dispatch(coreActions.items(artists_loaded));
|
||||
}
|
||||
if (tracks_loaded.length > 0) {
|
||||
store.dispatch(coreActions.tracksLoaded(tracks_loaded));
|
||||
store.dispatch(coreActions.items(tracks_loaded));
|
||||
}
|
||||
|
||||
store.dispatch(coreActions.updateColdStore(albums_loaded));
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
|
||||
import { generateGuid } from '../../util/helpers';
|
||||
import { formatArtist } from '../../util/format';
|
||||
|
||||
const coreActions = require('../core/actions');
|
||||
const uiActions = require('../ui/actions');
|
||||
@ -58,11 +59,10 @@ export function getArtistImages(uri, artist) {
|
||||
(response) => {
|
||||
if (response) {
|
||||
if (response.results.length > 0 && response.results[0].cover_image !== undefined) {
|
||||
const updated_artist = {
|
||||
dispatch(coreActions.itemLoaded(formatArtist({
|
||||
uri,
|
||||
images: [response.results[0].cover_image],
|
||||
};
|
||||
dispatch(coreActions.artistLoaded(updated_artist));
|
||||
})));
|
||||
} else {
|
||||
console.log(`Discogs: No results for artist ${artist.name}`);
|
||||
}
|
||||
|
||||
@ -332,7 +332,9 @@ export function getImages(context, uri) {
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.album) {
|
||||
dispatch(coreActions.albumLoaded({ uri, images: response.album.image }));
|
||||
dispatch(
|
||||
coreActions.itemLoaded(formatAlbum({ uri, images: response.album.image })),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@ -12,6 +12,7 @@ import {
|
||||
import {
|
||||
digestMopidyImages,
|
||||
formatImages,
|
||||
formatAlbums,
|
||||
formatTrack,
|
||||
formatTracks,
|
||||
formatSimpleObject,
|
||||
@ -1094,7 +1095,7 @@ const MopidyMiddleware = (function () {
|
||||
let albums_uris = arrayOf('uri', albums);
|
||||
albums_uris = removeDuplicates(albums_uris);
|
||||
|
||||
store.dispatch(coreActions.albumsLoaded(albums));
|
||||
store.dispatch(coreActions.itemsLoaded(albums));
|
||||
|
||||
// and plug in their URIs
|
||||
store.dispatch({
|
||||
@ -1169,11 +1170,7 @@ const MopidyMiddleware = (function () {
|
||||
}
|
||||
|
||||
artists_uris = removeDuplicates(artists_uris);
|
||||
|
||||
// load each artist
|
||||
for (var i = 0; i < artists_uris.length; i++) {
|
||||
store.dispatch(mopidyActions.getArtist(artists_uris[i]));
|
||||
}
|
||||
store.dispatch(coreActions.loadItems(artists_uris));
|
||||
|
||||
// and plug in their URIs
|
||||
store.dispatch({
|
||||
@ -1380,7 +1377,7 @@ const MopidyMiddleware = (function () {
|
||||
let albums_uris = arrayOf('uri', albums);
|
||||
albums_uris = removeDuplicates(albums_uris);
|
||||
|
||||
store.dispatch(coreActions.albumsLoaded(albums));
|
||||
store.dispatch(coreActions.itemsLoaded(formatAlbums(albums)));
|
||||
|
||||
// and plug in their URIs
|
||||
store.dispatch({
|
||||
@ -1446,11 +1443,7 @@ const MopidyMiddleware = (function () {
|
||||
}
|
||||
|
||||
artists_uris = removeDuplicates(artists_uris);
|
||||
|
||||
// load each artist
|
||||
for (var i = 0; i < artists_uris.length; i++) {
|
||||
store.dispatch(mopidyActions.getArtist(artists_uris[i]));
|
||||
}
|
||||
store.dispatch(coreActions.loadItems(artists_uris));
|
||||
|
||||
// and plug in their URIs
|
||||
store.dispatch({
|
||||
@ -1676,7 +1669,7 @@ const MopidyMiddleware = (function () {
|
||||
store.dispatch(coreActions.addPinned(playlist));
|
||||
}
|
||||
|
||||
store.dispatch(coreActions.playlistLoaded(playlist));
|
||||
store.dispatch(coreActions.itemLoaded(playlist));
|
||||
store.dispatch(uiActions.createNotification({ content: 'Playlist saved' }));
|
||||
});
|
||||
});
|
||||
@ -1726,7 +1719,7 @@ const MopidyMiddleware = (function () {
|
||||
request(store, 'playlists.create', { name: action.name, uri_scheme: action.scheme })
|
||||
.then((response) => {
|
||||
store.dispatch(uiActions.createNotification({ content: 'Created playlist' }));
|
||||
store.dispatch(coreActions.playlistLoaded(response));
|
||||
store.dispatch(coreActions.itemLoaded(response));
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_LIBRARY_PLAYLIST_CREATED',
|
||||
key: response.uri,
|
||||
@ -1807,6 +1800,7 @@ const MopidyMiddleware = (function () {
|
||||
break;
|
||||
|
||||
case 'MOPIDY_GET_ARTIST':
|
||||
console.log(action);
|
||||
request(store, 'library.lookup', { uris: [action.uri] })
|
||||
.then((_response) => {
|
||||
if (!_response) return;
|
||||
@ -1876,7 +1870,7 @@ const MopidyMiddleware = (function () {
|
||||
provider: 'mopidy',
|
||||
}));
|
||||
|
||||
store.dispatch(coreActions.artistsLoaded(artists));
|
||||
store.dispatch(coreActions.itemsLoaded(artists));
|
||||
|
||||
// Re-run any consequential processes in 100ms. This allows a small window for other
|
||||
// server requests before our next batch. It's a little crude but it means the server isn't
|
||||
@ -2084,6 +2078,7 @@ const MopidyMiddleware = (function () {
|
||||
request(store, 'library.browse', { uri: action.uri })
|
||||
.then((response) => {
|
||||
const tracks_uris = [];
|
||||
const tracks = [];
|
||||
const subdirectories = [];
|
||||
|
||||
for (const item of response) {
|
||||
@ -2125,8 +2120,6 @@ const MopidyMiddleware = (function () {
|
||||
return;
|
||||
}
|
||||
|
||||
const tracks = [];
|
||||
|
||||
for (const uri in response) {
|
||||
if (response.hasOwnProperty(uri) && response[uri].length > 0) {
|
||||
tracks.push(formatTrack(response[uri][0]));
|
||||
|
||||
@ -678,19 +678,19 @@ export function getAutocompleteResults(field_id, query, types = ['album', 'artis
|
||||
}
|
||||
|
||||
if (response.artists && response.artists.items) {
|
||||
dispatch(coreActions.artistsLoaded(response.artists.items));
|
||||
dispatch(coreActions.itemsLoaded(response.artists.items));
|
||||
}
|
||||
|
||||
if (response.albums && response.albums.items) {
|
||||
dispatch(coreActions.albumsLoaded(response.albums.items));
|
||||
dispatch(coreActions.itemsLoaded(response.albums.items));
|
||||
}
|
||||
|
||||
if (response.playlists && response.playlists.items) {
|
||||
dispatch(coreActions.playlistsLoaded(response.playlists.items));
|
||||
dispatch(coreActions.itemsLoaded(response.playlists.items));
|
||||
}
|
||||
|
||||
if (response.tracks && response.tracks.items) {
|
||||
dispatch(coreActions.tracksLoaded(response.tracks.items));
|
||||
dispatch(coreActions.itemsLoaded(response.tracks.items));
|
||||
}
|
||||
|
||||
dispatch({
|
||||
|
||||
@ -121,6 +121,7 @@ const SpotifyMiddleware = (function () {
|
||||
next(action);
|
||||
break;
|
||||
|
||||
// TODO: This can go
|
||||
case 'SPOTIFY_ARTIST_ALBUMS_LOADED':
|
||||
store.dispatch(coreActions.albumsLoaded(action.data.items));
|
||||
store.dispatch({
|
||||
|
||||
@ -124,7 +124,7 @@ export default function reducer(ui = {}, action) {
|
||||
|
||||
case 'START_LOADING':
|
||||
var load_queue = { ...(ui.load_queue ? ui.load_queue : {}) };
|
||||
load_queue[action.key] = action.source;
|
||||
load_queue[action.key] = action.source || action.key;
|
||||
return { ...ui, load_queue };
|
||||
|
||||
case 'STOP_LOADING':
|
||||
|
||||
@ -209,6 +209,7 @@ const uiPersistConfig = {
|
||||
key: 'ui',
|
||||
storage: localForage,
|
||||
blacklist: [
|
||||
'debug_response',
|
||||
'load_queue',
|
||||
'notifications',
|
||||
'processes',
|
||||
|
||||
@ -369,20 +369,26 @@ let isObject = function (value) {
|
||||
* @param key = string (the string to lookup)
|
||||
* @return boolean
|
||||
* */
|
||||
const isLoading = function (load_queue = [], keys = []) {
|
||||
// Loop all of our load queue items
|
||||
for (const load_queue_key in load_queue) {
|
||||
// Make sure it's not a root object method
|
||||
if (load_queue.hasOwnProperty(load_queue_key)) {
|
||||
// Loop all the keys we're looking for
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
if (load_queue[load_queue_key].includes(keys[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const isLoading = function (load_queue = {}, keys = []) {
|
||||
if (!load_queue || !keys) return false;
|
||||
|
||||
const queue_keys = Object.keys(load_queue);
|
||||
const matches = keys.reduce((acc, key) => {
|
||||
let regex = '';
|
||||
try {
|
||||
regex = new RegExp(key);
|
||||
} catch {
|
||||
console.error('Invalid regular expression', keys);
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
return [
|
||||
...acc,
|
||||
...(queue_keys.filter((qk) => qk.match(regex))),
|
||||
];
|
||||
}, []);
|
||||
|
||||
return matches.length > 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -171,9 +171,7 @@ export class Album extends React.Component {
|
||||
|
||||
if (!album) {
|
||||
if (
|
||||
isLoading(load_queue, [
|
||||
`spotify_albums/${getFromUri('albumid', uri)}`,
|
||||
])
|
||||
isLoading(load_queue, [`(.*)${uri}`])
|
||||
) {
|
||||
return <Loader body loading />;
|
||||
}
|
||||
|
||||
@ -197,10 +197,6 @@ class Artist extends React.Component {
|
||||
value: 'single',
|
||||
label: i18n('artist.albums.filter.singles'),
|
||||
},
|
||||
{
|
||||
value: 'compilation',
|
||||
label: i18n('artist.albums.filter.compilations'),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
@ -402,10 +398,7 @@ class Artist extends React.Component {
|
||||
|
||||
if (!artist) {
|
||||
if (
|
||||
isLoading(
|
||||
load_queue,
|
||||
[`spotify_artists/${getFromUri('artistid', uri)}`, 'lastfm_method=artist.getInfo'],
|
||||
)
|
||||
isLoading(load_queue, [`(.*)${uri}(.*)`])
|
||||
) {
|
||||
return <Loader body loading />;
|
||||
}
|
||||
|
||||
@ -279,7 +279,7 @@ class Playlist extends React.Component {
|
||||
const playlist_id = getFromUri('playlistid', uri);
|
||||
|
||||
if (!playlist) {
|
||||
if (isLoading(load_queue, [`spotify_playlists/${playlist_id}?`])) {
|
||||
if (isLoading(load_queue, [`(.*)${playlist_id}`])) {
|
||||
return <Loader body loading />
|
||||
}
|
||||
return (
|
||||
@ -349,7 +349,7 @@ class Playlist extends React.Component {
|
||||
|
||||
{this.renderActions()}
|
||||
|
||||
{isLoading(load_queue, [`spotify_playlists/${playlist_id}/tracks`]) ? (
|
||||
{isLoading(load_queue, [`(.*)${playlist_id}/tracks`]) ? (
|
||||
<Loader body loading />
|
||||
) : (
|
||||
<section className="list-wrapper">
|
||||
|
||||
@ -377,10 +377,6 @@ const mapStateToProps = (state) => {
|
||||
spotify_enabled: state.spotify.enabled,
|
||||
radio: state.core.radio,
|
||||
radio_enabled: !!(state.core.radio && state.core.radio.enabled),
|
||||
artists: state.core.artists,
|
||||
albums: state.core.albums,
|
||||
playlists: state.core.playlists,
|
||||
tracks: state.core.tracks,
|
||||
items,
|
||||
queue_tracks,
|
||||
current_track_uri: state.core.current_track_uri,
|
||||
|
||||
@ -46,6 +46,7 @@ class Search extends React.Component {
|
||||
|
||||
// Auto-focus on the input field
|
||||
$(document).find('.search-form input').focus();
|
||||
this.digestUri();
|
||||
}
|
||||
|
||||
componentDidUpdate = ({
|
||||
@ -61,13 +62,7 @@ class Search extends React.Component {
|
||||
} = this.props;
|
||||
const { type, term } = this.state;
|
||||
|
||||
// Already connected, but search properties changed
|
||||
if (prev_mopidy_connected && mopidy_connected) {
|
||||
if (prevType !== typeProp || prevTerm !== termProp) {
|
||||
this.digestUri();
|
||||
}
|
||||
// Connected
|
||||
} else if (!prev_mopidy_connected && mopidy_connected && uri_schemes_search_enabled) {
|
||||
if (prevType !== typeProp || prevTerm !== termProp) {
|
||||
this.search(type, term);
|
||||
}
|
||||
}
|
||||
@ -148,7 +143,6 @@ class Search extends React.Component {
|
||||
uiActions: {
|
||||
setWindowTitle,
|
||||
},
|
||||
mopidy_connected,
|
||||
uri_schemes_search_enabled,
|
||||
mopidyActions,
|
||||
spotifyActions,
|
||||
@ -174,7 +168,7 @@ class Search extends React.Component {
|
||||
|
||||
setWindowTitle(i18n('search.title_window', { term: decodeURIComponent(term) }));
|
||||
|
||||
if (type && term && mopidy_connected && uri_schemes_search_enabled) {
|
||||
if (type && term) {
|
||||
if (mopidyTerm !== term || mopidyType !== type) {
|
||||
mopidyActions.clearSearchResults();
|
||||
mopidyActions.getSearchResults(type, term);
|
||||
@ -324,7 +318,6 @@ class Search extends React.Component {
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
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 : []),
|
||||
playlists: (state.core.playlists ? state.core.playlists : []),
|
||||
|
||||
@ -18,6 +18,8 @@ import { sortItems, applyFilter } from '../../util/arrays';
|
||||
import { collate } from '../../util/format';
|
||||
import Button from '../../components/Button';
|
||||
import { i18n, I18n } from '../../locale';
|
||||
import { isLoading } from '../../util/helpers';
|
||||
import Loader from '../../components/Loader';
|
||||
|
||||
class LibraryAlbums extends React.Component {
|
||||
constructor(props) {
|
||||
@ -175,12 +177,17 @@ class LibraryAlbums extends React.Component {
|
||||
sort,
|
||||
sort_reverse,
|
||||
view,
|
||||
load_queue,
|
||||
} = this.props;
|
||||
const {
|
||||
limit,
|
||||
filter,
|
||||
} = this.state;
|
||||
|
||||
if (isLoading(load_queue, ['(.*):library:albums'])) {
|
||||
return <Loader body loading />;
|
||||
}
|
||||
|
||||
let albums = [
|
||||
...(source === 'all' || source === 'spotify' ? collate(spotify_library, { items }).items : []),
|
||||
...(source === 'all' || source === 'google' ? collate(google_library, { items }).items : []),
|
||||
|
||||
@ -12,12 +12,13 @@ import Icon from '../../components/Icon';
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
import * as coreActions from '../../services/core/actions';
|
||||
import {
|
||||
uriSource,
|
||||
uriSource, isLoading,
|
||||
} from '../../util/helpers';
|
||||
import { sortItems, applyFilter } from '../../util/arrays';
|
||||
import { I18n, i18n } from '../../locale';
|
||||
import { collate, collateLibrary } from '../../util/format';
|
||||
import Button from '../../components/Button';
|
||||
import Loader from '../../components/Loader';
|
||||
|
||||
class LibraryArtists extends React.Component {
|
||||
constructor(props) {
|
||||
@ -155,12 +156,17 @@ class LibraryArtists extends React.Component {
|
||||
sort,
|
||||
sort_reverse,
|
||||
view,
|
||||
load_queue,
|
||||
} = this.props;
|
||||
const {
|
||||
limit,
|
||||
filter,
|
||||
} = this.state;
|
||||
|
||||
if (isLoading(load_queue, ['(.*):library:artists'])) {
|
||||
return <Loader body loading />;
|
||||
}
|
||||
|
||||
let artists = [
|
||||
...(source === 'all' || source === 'spotify' ? collate(spotify_library, { items }).items : []),
|
||||
...(source === 'all' || source === 'google' ? collate(google_library, { items }).items : []),
|
||||
@ -342,6 +348,7 @@ const mapStateToProps = (state) => ({
|
||||
sort: (state.ui.library_artists_sort ? state.ui.library_artists_sort : null),
|
||||
sort_reverse: (state.ui.library_artists_sort_reverse ? state.ui.library_artists_sort_reverse : false),
|
||||
view: state.ui.library_artists_view,
|
||||
load_queue: state.ui.load_queue,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
@ -86,23 +86,31 @@ class LibraryBrowseDirectory extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
playAll(e, tracks) {
|
||||
const tracks_uris = arrayOf('uri', tracks);
|
||||
this.props.mopidyActions.playURIs(tracks_uris, `iris:browse:${this.props.uri}`);
|
||||
this.props.uiActions.hideContextMenu();
|
||||
playAll = (tracks) => {
|
||||
const {
|
||||
uri,
|
||||
mopidyActions: {
|
||||
playURIs,
|
||||
},
|
||||
uiActions: {
|
||||
hideContextMenu,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
playURIs(arrayOf('uri', tracks), `iris:browse:${uri}`);
|
||||
hideContextMenu();
|
||||
}
|
||||
|
||||
goBack(e) {
|
||||
goBack = () => {
|
||||
const { uiActions: { hideContextMenu } } = this.props;
|
||||
|
||||
window.history.back();
|
||||
this.props.uiActions.hideContextMenu();
|
||||
hideContextMenu();
|
||||
}
|
||||
|
||||
renderBreadcrumbs() {
|
||||
if (this.props.uri) {
|
||||
var parent_uri = this.props.uri;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
renderBreadcrumbs = () => {
|
||||
const { uri } = this.props;
|
||||
let parent_uri = uri || null;
|
||||
|
||||
if (parent_uri.startsWith('file://')) {
|
||||
parent_uri = parent_uri.substring(0, parent_uri.lastIndexOf('/'));
|
||||
@ -120,11 +128,12 @@ class LibraryBrowseDirectory extends React.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
renderSubdirectories(subdirectories) {
|
||||
if (this.props.view === 'list') {
|
||||
renderSubdirectories = (subdirectories) => {
|
||||
const { view } = this.props;
|
||||
|
||||
if (view === 'list') {
|
||||
return (
|
||||
<List
|
||||
nocontext
|
||||
rows={subdirectories}
|
||||
className="library-local-directory-list"
|
||||
link_prefix="/library/browse/"
|
||||
@ -219,7 +228,7 @@ class LibraryBrowseDirectory extends React.Component {
|
||||
/>
|
||||
{tracks && (
|
||||
<Button
|
||||
onClick={(e) => { uiActions.hideContextMenu(); this.playAll(e, all_tracks); }}
|
||||
onClick={() => { uiActions.hideContextMenu(); this.playAll(all_tracks); }}
|
||||
noHover
|
||||
discrete
|
||||
tracking={{ category: 'Directory', action: 'Play' }}
|
||||
|
||||
@ -17,6 +17,8 @@ import * as spotifyActions from '../../services/spotify/actions';
|
||||
import { applyFilter, removeDuplicates, sortItems } from '../../util/arrays';
|
||||
import { I18n, i18n } from '../../locale';
|
||||
import { collate } from '../../util/format';
|
||||
import { isLoading } from '../../util/helpers';
|
||||
import Loader from '../../components/Loader';
|
||||
|
||||
class LibraryPlaylists extends React.Component {
|
||||
constructor(props) {
|
||||
@ -138,12 +140,17 @@ class LibraryPlaylists extends React.Component {
|
||||
sort_reverse,
|
||||
view,
|
||||
source,
|
||||
load_queue,
|
||||
} = this.props;
|
||||
const {
|
||||
filter,
|
||||
limit,
|
||||
} = this.state;
|
||||
|
||||
if (isLoading(load_queue, ['(.*):library:playlists'])) {
|
||||
return <Loader body loading />;
|
||||
}
|
||||
|
||||
let playlists = [
|
||||
...(source === 'all' || source === 'spotify' ? collate(spotify_library, { items }).items : []),
|
||||
...(source === 'all' || source === 'local' ? collate(mopidy_library, { items }).items : []),
|
||||
|
||||
@ -26,27 +26,29 @@ class EditPlaylist extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.uiActions.setWindowTitle(i18n('modal.edit_playlist.title'));
|
||||
const {
|
||||
uri,
|
||||
playlist,
|
||||
coreActions: {
|
||||
loadItem,
|
||||
},
|
||||
uiActions: {
|
||||
setWindowTitle,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
setWindowTitle(i18n('modal.edit_playlist.title'));
|
||||
|
||||
if (this.props.playlist) {
|
||||
if (playlist) {
|
||||
this.setState({
|
||||
loaded: true,
|
||||
name: this.props.playlist.name,
|
||||
description: this.props.playlist.description,
|
||||
public: (this.props.playlist.public == true),
|
||||
collaborative: (this.props.playlist.collaborative == true),
|
||||
name: playlist.name,
|
||||
description: playlist.description,
|
||||
public: (playlist.public === true),
|
||||
collaborative: (playlist.collaborative === true),
|
||||
});
|
||||
} else {
|
||||
switch (uriSource(this.props.uri)) {
|
||||
case 'spotify':
|
||||
this.props.spotifyActions.getPlaylist(this.props.uri);
|
||||
this.props.spotifyActions.following(this.props.uri);
|
||||
break;
|
||||
|
||||
default:
|
||||
this.props.mopidyActions.getPlaylist(this.props.uri);
|
||||
break;
|
||||
}
|
||||
loadItem(uri);
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,32 +81,13 @@ class EditPlaylist extends React.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
savePlaylist(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!this.state.name || this.state.name == '') {
|
||||
this.setState({ error: i18n('modal.edit_playlist.name_required') });
|
||||
return false;
|
||||
}
|
||||
this.props.coreActions.savePlaylist(
|
||||
this.props.uri,
|
||||
this.state.name,
|
||||
this.state.description,
|
||||
this.state.public,
|
||||
this.state.collaborative,
|
||||
this.state.image,
|
||||
);
|
||||
window.history.back();
|
||||
return false;
|
||||
}
|
||||
|
||||
setImage(e) {
|
||||
setImage = (e) => {
|
||||
const self = this;
|
||||
|
||||
// Create a file-reader to import the selected image as a base64 string
|
||||
const file_reader = new FileReader();
|
||||
|
||||
// Once the image is loaded, convert the result
|
||||
// Once the image is loaded, convert the result
|
||||
file_reader.addEventListener('load', (e) => {
|
||||
const image_base64 = e.target.result.replace('data:image/jpeg;base64,', '');
|
||||
self.setState({ image: image_base64 });
|
||||
@ -114,7 +97,51 @@ class EditPlaylist extends React.Component {
|
||||
file_reader.readAsDataURL(e.target.files[0]);
|
||||
}
|
||||
|
||||
renderFields() {
|
||||
savePlaylist = (e) => {
|
||||
const {
|
||||
name,
|
||||
description,
|
||||
public: isPublic,
|
||||
collaborative,
|
||||
image,
|
||||
} = this.state;
|
||||
const {
|
||||
uri,
|
||||
coreActions: {
|
||||
savePlaylist,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
if (!name || name == '') {
|
||||
this.setState({ error: i18n('modal.edit_playlist.name_required') });
|
||||
return false;
|
||||
}
|
||||
savePlaylist(
|
||||
uri,
|
||||
name,
|
||||
description,
|
||||
isPublic,
|
||||
collaborative,
|
||||
image,
|
||||
);
|
||||
window.history.back();
|
||||
return false;
|
||||
}
|
||||
|
||||
renderFields = () => {
|
||||
const {
|
||||
uri,
|
||||
} = this.props;
|
||||
const {
|
||||
name,
|
||||
description,
|
||||
public: isPublic,
|
||||
collaborative,
|
||||
image,
|
||||
} = this.state;
|
||||
|
||||
switch (uriSource(this.props.uri)) {
|
||||
case 'spotify':
|
||||
return (
|
||||
@ -127,7 +154,7 @@ class EditPlaylist extends React.Component {
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ name: e.target.value })}
|
||||
value={this.state.name}
|
||||
value={name}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -139,7 +166,7 @@ class EditPlaylist extends React.Component {
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ description: e.target.value })}
|
||||
value={this.state.description}
|
||||
value={description}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -167,8 +194,8 @@ class EditPlaylist extends React.Component {
|
||||
<input
|
||||
type="checkbox"
|
||||
name="playlist_private"
|
||||
checked={this.state.public}
|
||||
onChange={(e) => this.setState({ public: !this.state.public })}
|
||||
checked={isPublic}
|
||||
onChange={() => this.setState({ public: !isPublic })}
|
||||
/>
|
||||
<span className="label">
|
||||
<I18n path="modal.edit_playlist.options.public" />
|
||||
@ -178,8 +205,8 @@ class EditPlaylist extends React.Component {
|
||||
<input
|
||||
type="checkbox"
|
||||
name="collaborative"
|
||||
checked={this.state.collaborative}
|
||||
onChange={(e) => this.setState({ collaborative: !this.state.collaborative })}
|
||||
checked={collaborative}
|
||||
onChange={() => this.setState({ collaborative: !collaborative })}
|
||||
/>
|
||||
<span className="label">
|
||||
<I18n path="modal.edit_playlist.options.collaborative" />
|
||||
@ -189,7 +216,6 @@ class EditPlaylist extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (
|
||||
@ -202,7 +228,7 @@ class EditPlaylist extends React.Component {
|
||||
<input
|
||||
type="text"
|
||||
onChange={(e) => this.setState({ name: e.target.value })}
|
||||
value={this.state.name}
|
||||
value={name}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -211,13 +237,17 @@ class EditPlaylist extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
render = () => {
|
||||
const {
|
||||
error,
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
<Modal className="modal--edit-playlist">
|
||||
<h1>
|
||||
<I18n path="modal.edit_playlist.title" />
|
||||
</h1>
|
||||
{this.state.error ? <h3 className="red-text">{this.state.error}</h3> : null}
|
||||
{error ? <h3 className="red-text">{error}</h3> : null}
|
||||
<form onSubmit={(e) => this.savePlaylist(e)}>
|
||||
|
||||
{this.renderFields()}
|
||||
@ -252,8 +282,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
|
||||
return {
|
||||
uri,
|
||||
playlist: (state.core.playlists[uri] !== undefined ? state.core.playlists[uri] : null),
|
||||
playlists: state.core.playlists,
|
||||
playlist: (state.core.items[uri] !== undefined ? state.core.items[uri] : null),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user