Fixing context menu trigger silencing; Search form polish
This commit is contained in:
@ -1,25 +1,16 @@
|
||||
|
||||
import React from 'react';
|
||||
import React, { memo } from 'react';
|
||||
import ContextMenuTrigger from './ContextMenuTrigger';
|
||||
|
||||
export default class Header extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
expanded: false,
|
||||
};
|
||||
}
|
||||
|
||||
handleContextMenuTrigger = (e, options) => {
|
||||
const {
|
||||
title,
|
||||
handleContextMenuTrigger,
|
||||
uiActions: {
|
||||
showContextMenu,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
export default memo(({
|
||||
handleContextMenuTrigger,
|
||||
options,
|
||||
title,
|
||||
uiActions,
|
||||
className,
|
||||
children,
|
||||
}) => {
|
||||
const onTrigger = (e) => {
|
||||
if (handleContextMenuTrigger) return handleContextMenuTrigger(e);
|
||||
|
||||
e.preventDefault();
|
||||
@ -29,48 +20,25 @@ export default class Header extends React.Component {
|
||||
title,
|
||||
options,
|
||||
};
|
||||
showContextMenu(data);
|
||||
}
|
||||
uiActions.showContextMenu(data);
|
||||
return true;
|
||||
};
|
||||
|
||||
renderContextMenuTrigger = () => {
|
||||
const {
|
||||
handleContextMenuTrigger,
|
||||
options,
|
||||
} = this.props;
|
||||
|
||||
if (!handleContextMenuTrigger && !options) return null;
|
||||
|
||||
return <ContextMenuTrigger onTrigger={(e) => this.handleContextMenuTrigger(e, options)} />;
|
||||
}
|
||||
|
||||
renderOptions = () => {
|
||||
const {
|
||||
handleContextMenuTrigger,
|
||||
options,
|
||||
} = this.props;
|
||||
|
||||
if (!options && !handleContextMenuTrigger) return null;
|
||||
|
||||
return (
|
||||
<div className="header__options">
|
||||
{this.renderContextMenuTrigger()}
|
||||
<div className="header__options__wrapper">
|
||||
{options || null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const { className, children } = this.props;
|
||||
|
||||
return (
|
||||
<header className={className}>
|
||||
<h1>
|
||||
{children}
|
||||
</h1>
|
||||
{this.renderOptions()}
|
||||
</header>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<header className={className}>
|
||||
<h1>
|
||||
{children}
|
||||
</h1>
|
||||
{
|
||||
(options || handleContextMenuTrigger) && (
|
||||
<div className="header__options">
|
||||
<ContextMenuTrigger onTrigger={onTrigger} />
|
||||
<div className="header__options__wrapper">
|
||||
{options || null}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</header>
|
||||
);
|
||||
});
|
||||
|
||||
@ -24,9 +24,14 @@ const SearchResults = ({
|
||||
all,
|
||||
}) => {
|
||||
const encodedTerm = encodeURIComponent(query.term);
|
||||
|
||||
const resultsMatchQuery = (results) => {
|
||||
if (!results.query) return false;
|
||||
if (results.query.term !== query.term) return false;
|
||||
if (results.query.type !== query.type) return false;
|
||||
return true;
|
||||
};
|
||||
let results = [];
|
||||
if (mopidy_search_results.query === query.term && mopidy_search_results[type]) {
|
||||
if (resultsMatchQuery(mopidy_search_results) && mopidy_search_results[type]) {
|
||||
results = [
|
||||
...results,
|
||||
...(
|
||||
@ -37,7 +42,7 @@ const SearchResults = ({
|
||||
];
|
||||
}
|
||||
|
||||
if (spotify_search_results.query === query.term && spotify_search_results[type]) {
|
||||
if (resultsMatchQuery(spotify_search_results) && spotify_search_results[type]) {
|
||||
results = [
|
||||
...results,
|
||||
...(
|
||||
@ -116,7 +121,7 @@ const mapStateToProps = (state, ownProps) => ({
|
||||
uri_schemes_priority: state.ui.uri_schemes_priority || [],
|
||||
mopidy_search_results: state.mopidy.search_results || {},
|
||||
spotify_search_results: state.spotify.search_results || {},
|
||||
sort: state.ui.search_results_sort || 'followers.total',
|
||||
sort: state.ui.search_results_sort || 'followers',
|
||||
sort_reverse: !!state.ui.search_results_sort_reverse,
|
||||
});
|
||||
|
||||
|
||||
@ -69,8 +69,7 @@ const CoreMiddleware = (function () {
|
||||
delete exported_state.mopidy.library_artists;
|
||||
delete exported_state.mopidy.library_playlists;
|
||||
|
||||
var data = {
|
||||
|
||||
let data = {
|
||||
...action.data,
|
||||
message,
|
||||
description,
|
||||
@ -79,17 +78,17 @@ const CoreMiddleware = (function () {
|
||||
|
||||
// Log with Analytics
|
||||
if (store.getState().ui.allow_reporting) {
|
||||
ReactGA.event({
|
||||
category: 'Error',
|
||||
action: message,
|
||||
label: description,
|
||||
nonInteraction: true,
|
||||
});
|
||||
}
|
||||
ReactGA.event({
|
||||
category: 'Error',
|
||||
action: message,
|
||||
label: description,
|
||||
nonInteraction: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (action.show_notification) {
|
||||
store.dispatch(uiActions.createNotification({ content: message, level: 'error', description }));
|
||||
}
|
||||
if (action.show_notification) {
|
||||
store.dispatch(uiActions.createNotification({ content: message, level: 'error', description }));
|
||||
}
|
||||
|
||||
console.error(message, description, data);
|
||||
|
||||
@ -97,57 +96,57 @@ const CoreMiddleware = (function () {
|
||||
|
||||
case 'PLAY_PLAYLIST':
|
||||
if (store.getState().ui.allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Play', label: action.uri });
|
||||
}
|
||||
ReactGA.event({ category: 'Playlist', action: 'Play', label: action.uri });
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'SAVE_PLAYLIST':
|
||||
if (store.getState().ui.allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Save', label: action.key });
|
||||
}
|
||||
ReactGA.event({ category: 'Playlist', action: 'Save', label: action.key });
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'CREATE_PLAYLIST':
|
||||
if (store.getState().ui.allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Create', label: +action.name });
|
||||
}
|
||||
ReactGA.event({ category: 'Playlist', action: 'Create', label: +action.name });
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'REORDER_PLAYLIST_TRACKS':
|
||||
if (store.getState().ui.allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Reorder tracks', label: action.key });
|
||||
}
|
||||
ReactGA.event({ category: 'Playlist', action: 'Reorder tracks', label: action.key });
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'ADD_PLAYLIST_TRACKS':
|
||||
if (store.getState().ui.allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Add tracks', label: action.playlist_uri });
|
||||
}
|
||||
ReactGA.event({ category: 'Playlist', action: 'Add tracks', label: action.playlist_uri });
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'REMOVE_PLAYLIST_TRACKS':
|
||||
if (store.getState().ui.allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Remove tracks', label: action.playlist_uri });
|
||||
}
|
||||
ReactGA.event({ category: 'Playlist', action: 'Remove tracks', label: action.playlist_uri });
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'DELETE_PLAYLIST':
|
||||
if (store.getState().ui.allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Delete', label: action.uri });
|
||||
}
|
||||
ReactGA.event({ category: 'Playlist', action: 'Delete', label: action.uri });
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'SEARCH_STARTED':
|
||||
if (store.getState().ui.allow_reporting) {
|
||||
ReactGA.event({ category: 'Search', action: 'Started', label: `${action.type}: ${action.query}` });
|
||||
}
|
||||
ReactGA.event({ category: 'Search', action: 'Started', label: `${action.type}: ${action.query}` });
|
||||
}
|
||||
next(action);
|
||||
|
||||
var state = store.getState();
|
||||
@ -177,12 +176,14 @@ const CoreMiddleware = (function () {
|
||||
|
||||
// backend searching (mopidy)
|
||||
if (state.mopidy.connected) {
|
||||
store.dispatch(mopidyActions.getSearchResults(action.search_type, action.query, 100, full_uri_schemes));
|
||||
store.dispatch(
|
||||
mopidyActions.getSearchResults(action.search_type, action.query, 100, full_uri_schemes),
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Get assets from all of our providers
|
||||
// Get assets from all of our providers
|
||||
case 'GET_LIBRARY_PLAYLISTS':
|
||||
if (store.getState().spotify.connected) {
|
||||
store.dispatch(spotifyActions.getLibraryPlaylists());
|
||||
@ -193,7 +194,7 @@ const CoreMiddleware = (function () {
|
||||
next(action);
|
||||
break;
|
||||
|
||||
// Get assets from all of our providers
|
||||
// Get assets from all of our providers
|
||||
case 'GET_LIBRARY_ALBUMS':
|
||||
if (store.getState().spotify.connected) {
|
||||
store.dispatch(spotifyActions.getLibraryAlbums());
|
||||
@ -204,7 +205,7 @@ const CoreMiddleware = (function () {
|
||||
next(action);
|
||||
break;
|
||||
|
||||
// Get assets from all of our providers
|
||||
// Get assets from all of our providers
|
||||
case 'GET_LIBRARY_ARTISTS':
|
||||
if (store.getState().spotify.connected) {
|
||||
store.dispatch(spotifyActions.getLibraryArtists());
|
||||
@ -219,11 +220,9 @@ const CoreMiddleware = (function () {
|
||||
location.reload();
|
||||
break;
|
||||
|
||||
|
||||
/**
|
||||
* Playlist manipulation
|
||||
* */
|
||||
|
||||
/**
|
||||
* Playlist manipulation
|
||||
* */
|
||||
case 'PLAYLIST_TRACKS':
|
||||
var tracks = formatTracks(action.tracks);
|
||||
action.tracks_uris = arrayOf('uri', tracks);
|
||||
@ -245,10 +244,11 @@ const CoreMiddleware = (function () {
|
||||
case 'spotify':
|
||||
store.dispatch(spotifyActions.getPlaylist(action.key));
|
||||
break;
|
||||
|
||||
case 'm3u':
|
||||
if (store.getState().mopidy.connected) store.dispatch(mopidyActions.getPlaylist(action.key));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
@ -314,30 +314,29 @@ const CoreMiddleware = (function () {
|
||||
});
|
||||
break;
|
||||
|
||||
|
||||
/**
|
||||
* Asset Load commands
|
||||
*
|
||||
* These are called from views and other middleware to load
|
||||
* assets. This is where we can return already indexed records
|
||||
* where appropriate
|
||||
* */
|
||||
/**
|
||||
* Asset Load commands
|
||||
*
|
||||
* These are called from views and other middleware to load
|
||||
* assets. This is where we can return already indexed records
|
||||
* where appropriate
|
||||
* */
|
||||
|
||||
case 'LOAD_TRACK':
|
||||
if (
|
||||
!action.force_reload
|
||||
&& store.getState().core.tracks[action.uri]) {
|
||||
console.info(`Loading "${action.uri}" from index`);
|
||||
break;
|
||||
}
|
||||
if (
|
||||
!action.force_reload
|
||||
&& store.getState().core.tracks[action.uri]) {
|
||||
console.info(`Loading "${action.uri}" from index`);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (uriSource(action.uri)) {
|
||||
case 'spotify':
|
||||
store.dispatch(spotifyActions.getTrack(action.uri));
|
||||
|
||||
if (store.getState().spotify.me) {
|
||||
store.dispatch(spotifyActions.following(action.uri));
|
||||
}
|
||||
store.dispatch(spotifyActions.following(action.uri));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -351,21 +350,21 @@ const CoreMiddleware = (function () {
|
||||
break;
|
||||
|
||||
case 'LOAD_ALBUM':
|
||||
if (
|
||||
!action.force_reload
|
||||
&& store.getState().core.albums[action.uri]
|
||||
&& store.getState().core.albums[action.uri].tracks_uris) {
|
||||
console.info(`Loading "${action.uri}" from index`);
|
||||
break;
|
||||
}
|
||||
if (
|
||||
!action.force_reload
|
||||
&& store.getState().core.albums[action.uri]
|
||||
&& store.getState().core.albums[action.uri].tracks_uris) {
|
||||
console.info(`Loading "${action.uri}" from index`);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (uriSource(action.uri)) {
|
||||
case 'spotify':
|
||||
store.dispatch(spotifyActions.getAlbum(action.uri));
|
||||
|
||||
if (store.getState().spotify.me) {
|
||||
store.dispatch(spotifyActions.following(action.uri));
|
||||
}
|
||||
store.dispatch(spotifyActions.following(action.uri));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -379,22 +378,22 @@ const CoreMiddleware = (function () {
|
||||
break;
|
||||
|
||||
case 'LOAD_ARTIST':
|
||||
if (
|
||||
!action.force_reload
|
||||
&& store.getState().core.artists[action.uri]
|
||||
&& store.getState().core.artists[action.uri].albums_uris
|
||||
&& store.getState().core.artists[action.uri].tracks_uris) {
|
||||
console.info(`Loading "${action.uri}" from index`);
|
||||
break;
|
||||
}
|
||||
if (
|
||||
!action.force_reload
|
||||
&& store.getState().core.artists[action.uri]
|
||||
&& store.getState().core.artists[action.uri].albums_uris
|
||||
&& store.getState().core.artists[action.uri].tracks_uris) {
|
||||
console.info(`Loading "${action.uri}" from index`);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (uriSource(action.uri)) {
|
||||
case 'spotify':
|
||||
store.dispatch(spotifyActions.getArtist(action.uri, true));
|
||||
|
||||
if (store.getState().spotify.me) {
|
||||
store.dispatch(spotifyActions.following(action.uri));
|
||||
}
|
||||
store.dispatch(spotifyActions.following(action.uri));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -437,21 +436,21 @@ const CoreMiddleware = (function () {
|
||||
break;
|
||||
|
||||
case 'LOAD_USER':
|
||||
if (
|
||||
!action.force_reload
|
||||
&& store.getState().core.users[action.uri]
|
||||
&& store.getState().core.users[action.uri].playlists_uris) {
|
||||
console.info(`Loading "${action.uri}" from index`);
|
||||
break;
|
||||
}
|
||||
if (
|
||||
!action.force_reload
|
||||
&& store.getState().core.users[action.uri]
|
||||
&& store.getState().core.users[action.uri].playlists_uris) {
|
||||
console.info(`Loading "${action.uri}" from index`);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (uriSource(action.uri)) {
|
||||
case 'spotify':
|
||||
store.dispatch(spotifyActions.getUser(action.uri));
|
||||
|
||||
if (store.getState().spotify.me) {
|
||||
store.dispatch(spotifyActions.following(action.uri));
|
||||
}
|
||||
store.dispatch(spotifyActions.following(action.uri));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -465,8 +464,8 @@ const CoreMiddleware = (function () {
|
||||
case 'LOAD_USER_PLAYLISTS':
|
||||
if (
|
||||
!action.force_reload
|
||||
&& store.getState().core.users[action.uri]
|
||||
&& store.getState().core.users[action.uri].playlists_uris) {
|
||||
&& store.getState().core.users[action.uri]
|
||||
&& store.getState().core.users[action.uri].playlists_uris) {
|
||||
console.info(`Loading "${action.uri}" playlists from index`);
|
||||
break;
|
||||
}
|
||||
@ -485,10 +484,10 @@ const CoreMiddleware = (function () {
|
||||
break;
|
||||
|
||||
|
||||
/**
|
||||
* Index actions
|
||||
* These modify our asset indexes, which are used globally
|
||||
* */
|
||||
/**
|
||||
* Index actions
|
||||
* These modify our asset indexes, which are used globally
|
||||
* */
|
||||
|
||||
case 'CURRENT_TRACK_LOADED':
|
||||
store.dispatch(coreActions.trackLoaded(action.track));
|
||||
@ -604,31 +603,31 @@ const CoreMiddleware = (function () {
|
||||
var tracks_loaded = [];
|
||||
|
||||
for (const raw_artist of action.artists) {
|
||||
var artist = formatArtist(raw_artist);
|
||||
var artist = formatArtist(raw_artist);
|
||||
|
||||
// Already have an artist in the index
|
||||
// Already have an artist in the index
|
||||
if (artists_index[artist.uri]) {
|
||||
// And we've already got some images, make sure we merge the arrays,
|
||||
// rather than overwriting
|
||||
if (artists_index[artist.uri].images && artist.images) {
|
||||
const existing_images = artists_index[artist.uri].images;
|
||||
let are_new_images = true;
|
||||
// And we've already got some images, make sure we merge the arrays,
|
||||
// rather than overwriting
|
||||
if (artists_index[artist.uri].images && artist.images) {
|
||||
const existing_images = artists_index[artist.uri].images;
|
||||
let are_new_images = true;
|
||||
|
||||
// loop all extisting images to make sure we're not adding one that
|
||||
// we already have
|
||||
for (const existing_image of existing_images) {
|
||||
// We only need to check one size, the formatter should insist on consistency
|
||||
// Note that we depend on having a one-item array of images provided per action
|
||||
if (existing_image.huge == artist.images[0].huge) {
|
||||
are_new_images = false;
|
||||
}
|
||||
}
|
||||
// loop all extisting images to make sure we're not adding one that
|
||||
// we already have
|
||||
for (const existing_image of existing_images) {
|
||||
// We only need to check one size, the formatter should insist on consistency
|
||||
// Note that we depend on having a one-item array of images provided per action
|
||||
if (existing_image.huge == artist.images[0].huge) {
|
||||
are_new_images = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Only if they're new images should we merge them in
|
||||
if (are_new_images) {
|
||||
artist.images = Object.assign([], [...existing_images, ...artist.images]);
|
||||
}
|
||||
}
|
||||
// Only if they're new images should we merge them in
|
||||
if (are_new_images) {
|
||||
artist.images = Object.assign([], [...existing_images, ...artist.images]);
|
||||
}
|
||||
}
|
||||
|
||||
artist = { ...artists_index[artist.uri], ...artist };
|
||||
}
|
||||
@ -659,7 +658,7 @@ const CoreMiddleware = (function () {
|
||||
var tracks_loaded = [];
|
||||
|
||||
for (var playlist of action.playlists) {
|
||||
playlist = formatPlaylist(playlist);
|
||||
playlist = formatPlaylist(playlist);
|
||||
|
||||
// Detect editability
|
||||
switch (uriSource(playlist.uri)) {
|
||||
@ -725,15 +724,15 @@ const CoreMiddleware = (function () {
|
||||
break;
|
||||
|
||||
case 'USER_PLAYLISTS_LOADED':
|
||||
store.dispatch(coreActions.playlistsLoaded(action.playlists));
|
||||
store.dispatch(coreActions.playlistsLoaded(action.playlists));
|
||||
next(action);
|
||||
break;
|
||||
|
||||
/**
|
||||
* Loaded more linked assets
|
||||
* Often fired during lazy-loading or async asset grabbing.
|
||||
* We link the parent to these indexed records by {type}s_uris
|
||||
* */
|
||||
/**
|
||||
* Loaded more linked assets
|
||||
* Often fired during lazy-loading or async asset grabbing.
|
||||
* We link the parent to these indexed records by {type}s_uris
|
||||
* */
|
||||
|
||||
case 'LOADED_MORE':
|
||||
var parent_type_plural = `${action.parent_type}s`;
|
||||
@ -772,7 +771,7 @@ const CoreMiddleware = (function () {
|
||||
// If we're a list of playlists, we need to manually filter Spotify's new URI structure
|
||||
// Really poor form because they haven't updated it everywhere, yet
|
||||
if (action.records_type == 'playlist') {
|
||||
records_uris = upgradeSpotifyPlaylistUris(records_uris);
|
||||
records_uris = upgradeSpotifyPlaylistUris(records_uris);
|
||||
}
|
||||
|
||||
// Append our parent object's reference to these records
|
||||
@ -802,7 +801,7 @@ const CoreMiddleware = (function () {
|
||||
next(action);
|
||||
break;
|
||||
|
||||
// This action is irrelevant to us, pass it on to the next middleware
|
||||
// This action is irrelevant to us, pass it on to the next middleware
|
||||
default:
|
||||
return next(action);
|
||||
}
|
||||
|
||||
@ -541,11 +541,10 @@ export function clearSearchResults() {
|
||||
};
|
||||
}
|
||||
|
||||
export function getSearchResults(context, query, limit = 100) {
|
||||
export function getSearchResults(type, term, limit = 100) {
|
||||
return {
|
||||
type: 'MOPIDY_GET_SEARCH_RESULTS',
|
||||
context,
|
||||
query,
|
||||
query: { type, term },
|
||||
limit,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1043,7 +1043,6 @@ const MopidyMiddleware = (function () {
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
`Searching ${uri_schemes_total} Mopidy providers`,
|
||||
{
|
||||
context: action.context,
|
||||
query: action.query,
|
||||
limit: action.limit,
|
||||
total: uri_schemes_total,
|
||||
@ -1084,13 +1083,10 @@ const MopidyMiddleware = (function () {
|
||||
},
|
||||
));
|
||||
|
||||
switch (action.data.context) {
|
||||
// Albums
|
||||
switch (action.data.query.type) {
|
||||
case 'albums':
|
||||
|
||||
// Quick check to see if we should be cancelling
|
||||
var last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
if (last_run && last_run.status == 'cancelling') {
|
||||
if (last_run && last_run.status === 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
}
|
||||
@ -1104,7 +1100,6 @@ const MopidyMiddleware = (function () {
|
||||
store.dispatch(uiActions.runProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
{
|
||||
context: action.data.context,
|
||||
query: action.data.query,
|
||||
limit: action.data.limit,
|
||||
uri_scheme: next_uri_scheme,
|
||||
@ -1113,7 +1108,7 @@ const MopidyMiddleware = (function () {
|
||||
));
|
||||
};
|
||||
|
||||
request(socket, store, 'library.search', { query: { album: [action.data.query] }, uris: [action.data.uri_scheme] })
|
||||
request(socket, store, 'library.search', { query: { album: [action.data.query.term] }, uris: [action.data.uri_scheme] })
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0) {
|
||||
@ -1142,8 +1137,8 @@ const MopidyMiddleware = (function () {
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_SEARCH_RESULTS_LOADED',
|
||||
query: action.data.query,
|
||||
context: action.data.context,
|
||||
results: albums_uris,
|
||||
context: 'albums',
|
||||
});
|
||||
}
|
||||
|
||||
@ -1159,12 +1154,9 @@ const MopidyMiddleware = (function () {
|
||||
);
|
||||
break;
|
||||
|
||||
// Artists
|
||||
case 'artists':
|
||||
|
||||
// Quick check to see if we should be cancelling
|
||||
var last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
if (last_run && last_run.status == 'cancelling') {
|
||||
if (last_run && last_run.status === 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
}
|
||||
@ -1178,7 +1170,6 @@ const MopidyMiddleware = (function () {
|
||||
store.dispatch(uiActions.runProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
{
|
||||
context: action.data.context,
|
||||
query: action.data.query,
|
||||
limit: action.data.limit,
|
||||
uri_scheme: next_uri_scheme,
|
||||
@ -1187,7 +1178,7 @@ const MopidyMiddleware = (function () {
|
||||
));
|
||||
};
|
||||
|
||||
request(socket, store, 'library.search', { query: { artist: [action.data.query] }, uris: [action.data.uri_scheme] })
|
||||
request(socket, store, 'library.search', { query: { artist: [action.data.query.term] }, uris: [action.data.uri_scheme] })
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0) {
|
||||
@ -1225,7 +1216,7 @@ const MopidyMiddleware = (function () {
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_SEARCH_RESULTS_LOADED',
|
||||
query: action.data.query,
|
||||
context: action.data.context,
|
||||
context: 'artists',
|
||||
results: artists_uris,
|
||||
});
|
||||
}
|
||||
@ -1242,12 +1233,9 @@ const MopidyMiddleware = (function () {
|
||||
);
|
||||
break;
|
||||
|
||||
// Playlists
|
||||
case 'playlists':
|
||||
|
||||
// Quick check to see if we should be cancelling
|
||||
var last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
if (last_run && last_run.status == 'cancelling') {
|
||||
if (last_run && last_run.status === 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
}
|
||||
@ -1283,7 +1271,7 @@ const MopidyMiddleware = (function () {
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_SEARCH_RESULTS_LOADED',
|
||||
query: action.data.query,
|
||||
context: action.data.context,
|
||||
context: 'playlists',
|
||||
results: playlists_uris,
|
||||
});
|
||||
}
|
||||
@ -1299,12 +1287,9 @@ const MopidyMiddleware = (function () {
|
||||
);
|
||||
break;
|
||||
|
||||
// Tracks
|
||||
case 'tracks':
|
||||
|
||||
// Quick check to see if we should be cancelling
|
||||
var last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
if (last_run && last_run.status == 'cancelling') {
|
||||
if (last_run && last_run.status === 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
return;
|
||||
}
|
||||
@ -1318,7 +1303,6 @@ const MopidyMiddleware = (function () {
|
||||
store.dispatch(uiActions.runProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
{
|
||||
context: action.data.context,
|
||||
query: action.data.query,
|
||||
limit: action.data.limit,
|
||||
uri_scheme: next_uri_scheme,
|
||||
@ -1327,7 +1311,7 @@ const MopidyMiddleware = (function () {
|
||||
));
|
||||
};
|
||||
|
||||
request(socket, store, 'library.search', { query: { any: [action.data.query] }, uris: [action.data.uri_scheme] })
|
||||
request(socket, store, 'library.search', { query: { any: [action.data.query.term] }, uris: [action.data.uri_scheme] })
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0 && response[0].tracks !== undefined) {
|
||||
@ -1336,7 +1320,7 @@ const MopidyMiddleware = (function () {
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_SEARCH_RESULTS_LOADED',
|
||||
query: action.data.query,
|
||||
context: action.data.context,
|
||||
context: 'tracks',
|
||||
results: formatTracks(tracks),
|
||||
});
|
||||
}
|
||||
@ -1353,12 +1337,9 @@ const MopidyMiddleware = (function () {
|
||||
|
||||
break;
|
||||
|
||||
// Search for all types
|
||||
case 'all':
|
||||
default:
|
||||
|
||||
var process_tracks = () => {
|
||||
// Quick check to see if we should be cancelling
|
||||
const last_run = store.getState().ui.processes.MOPIDY_GET_SEARCH_RESULTS_PROCESSOR;
|
||||
if (last_run && last_run.status == 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_GET_SEARCH_RESULTS_PROCESSOR'));
|
||||
@ -1372,7 +1353,7 @@ const MopidyMiddleware = (function () {
|
||||
remaining: (action.data.uri_schemes.length) + 1,
|
||||
},
|
||||
));
|
||||
request(socket, store, 'library.search', { query: { any: [action.data.query] }, uris: [action.data.uri_scheme] })
|
||||
request(socket, store, 'library.search', { query: { any: [action.data.query.term] }, uris: [action.data.uri_scheme] })
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0 && response[0].tracks !== undefined) {
|
||||
@ -1413,7 +1394,7 @@ const MopidyMiddleware = (function () {
|
||||
remaining: (action.data.uri_schemes.length) + 0.75,
|
||||
},
|
||||
));
|
||||
request(socket, store, 'library.search', { query: { album: [action.data.query] }, uris: [action.data.uri_scheme] })
|
||||
request(socket, store, 'library.search', { query: { album: [action.data.query.term] }, uris: [action.data.uri_scheme] })
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0) {
|
||||
@ -1474,7 +1455,7 @@ const MopidyMiddleware = (function () {
|
||||
remaining: (action.data.uri_schemes.length) + 0.5,
|
||||
},
|
||||
));
|
||||
request(socket, store, 'library.search', { query: { artist: [action.data.query] }, uris: [action.data.uri_scheme] })
|
||||
request(socket, store, 'library.search', { query: { artist: [action.data.query.term] }, uris: [action.data.uri_scheme] })
|
||||
.then(
|
||||
(response) => {
|
||||
if (response.length > 0) {
|
||||
@ -1551,7 +1532,7 @@ const MopidyMiddleware = (function () {
|
||||
let playlists_uris = [];
|
||||
for (var i = 0; i < response.length; i++) {
|
||||
const playlist = response[i];
|
||||
if (playlist.name.includes(action.data.query) && action.data.uri_schemes.includes(`${uriSource(playlist.uri)}:`)) {
|
||||
if (playlist.name.includes(action.data.query.term) && action.data.uri_schemes.includes(`${uriSource(playlist.uri)}:`)) {
|
||||
playlists_uris.push(playlist.uri);
|
||||
}
|
||||
}
|
||||
@ -1593,7 +1574,6 @@ const MopidyMiddleware = (function () {
|
||||
store.dispatch(uiActions.runProcess(
|
||||
'MOPIDY_GET_SEARCH_RESULTS_PROCESSOR',
|
||||
{
|
||||
context: action.data.context,
|
||||
query: action.data.query,
|
||||
limit: action.data.limit,
|
||||
uri_scheme: next_uri_scheme,
|
||||
|
||||
@ -172,6 +172,7 @@ export default function reducer(mopidy = {}, action) {
|
||||
return { ...mopidy, search_results: {} };
|
||||
|
||||
case 'MOPIDY_SEARCH_RESULTS_LOADED':
|
||||
console.log(action);
|
||||
|
||||
// Fetch or create our container
|
||||
if (mopidy.search_results) {
|
||||
@ -180,7 +181,10 @@ export default function reducer(mopidy = {}, action) {
|
||||
var search_results = {};
|
||||
}
|
||||
|
||||
search_results.query = action.query;
|
||||
search_results = {
|
||||
...search_results,
|
||||
query: action.query,
|
||||
};
|
||||
|
||||
if (search_results[action.context]) {
|
||||
search_results[action.context] = [...search_results[action.context], ...action.results];
|
||||
|
||||
@ -274,7 +274,7 @@ const PusherMiddleware = (function () {
|
||||
};
|
||||
|
||||
socket.onerror = (e) => {
|
||||
if (socket.readyState == 1) {
|
||||
if (socket.readyState === 1) {
|
||||
store.dispatch(coreActions.handleException(
|
||||
'Pusher websocket error',
|
||||
e,
|
||||
|
||||
@ -561,17 +561,17 @@ export function clearSearchResults() {
|
||||
};
|
||||
}
|
||||
|
||||
export function getSearchResults(type, query, limit = 50, offset = 0) {
|
||||
export function getSearchResults(type, term, limit = 50, offset = 0) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(uiActions.startProcess('SPOTIFY_GET_SEARCH_RESULTS_PROCESSOR', 'Searching Spotify'));
|
||||
|
||||
type = type.replace(/s+$/, '');
|
||||
if (type == 'all') {
|
||||
type = 'album,artist,playlist,track';
|
||||
let typeString = type.replace(/s+$/, '');
|
||||
if (typeString === 'all') {
|
||||
typeString = 'album,artist,playlist,track';
|
||||
}
|
||||
|
||||
let url = `search?q=${query}`;
|
||||
url += `&type=${type}`;
|
||||
let url = `search?q=${term}`;
|
||||
url += `&type=${typeString}`;
|
||||
url += `&country=${getState().spotify.country}`;
|
||||
url += `&limit=${limit}`;
|
||||
url += `&offset=${offset}`;
|
||||
@ -583,7 +583,7 @@ export function getSearchResults(type, query, limit = 50, offset = 0) {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_SEARCH_RESULTS_LOADED',
|
||||
context: 'tracks',
|
||||
query,
|
||||
query: { type, term },
|
||||
results: formatTracks(response.tracks.items),
|
||||
more: response.tracks.next,
|
||||
});
|
||||
@ -597,7 +597,7 @@ export function getSearchResults(type, query, limit = 50, offset = 0) {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_SEARCH_RESULTS_LOADED',
|
||||
context: 'artists',
|
||||
query,
|
||||
query: { type, term },
|
||||
results: arrayOf('uri', response.artists.items),
|
||||
more: response.artists.next,
|
||||
});
|
||||
@ -611,22 +611,18 @@ export function getSearchResults(type, query, limit = 50, offset = 0) {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_SEARCH_RESULTS_LOADED',
|
||||
context: 'albums',
|
||||
query,
|
||||
query: { type, term },
|
||||
results: arrayOf('uri', response.albums.items),
|
||||
more: response.albums.next,
|
||||
});
|
||||
}
|
||||
|
||||
if (response.playlists !== undefined) {
|
||||
const playlists = [];
|
||||
for (const playlist of response.playlists.items) {
|
||||
playlists.push({
|
||||
|
||||
...formatPlaylist(playlist),
|
||||
can_edit: (getState().spotify.me && playlist.owner.id == getState().spotify.me.id),
|
||||
tracks_total: playlist.tracks.total,
|
||||
});
|
||||
}
|
||||
const playlists = response.playlists.items.map((item) => ({
|
||||
...formatPlaylist(item),
|
||||
can_edit: (getState().spotify.me && item.owner.id === getState().spotify.me.id),
|
||||
tracks_total: item.tracks.total,
|
||||
}));
|
||||
dispatch({
|
||||
type: 'PLAYLISTS_LOADED',
|
||||
playlists,
|
||||
@ -635,7 +631,7 @@ export function getSearchResults(type, query, limit = 50, offset = 0) {
|
||||
dispatch({
|
||||
type: 'SPOTIFY_SEARCH_RESULTS_LOADED',
|
||||
context: 'playlists',
|
||||
query,
|
||||
query: { type, term },
|
||||
results: arrayOf('uri', playlists),
|
||||
more: response.playlists.next,
|
||||
});
|
||||
|
||||
@ -325,7 +325,10 @@ export default function reducer(spotify = {}, action) {
|
||||
var search_results = {};
|
||||
}
|
||||
|
||||
search_results.query = action.query;
|
||||
search_results = {
|
||||
...search_results,
|
||||
query: action.query,
|
||||
};
|
||||
|
||||
if (search_results.results) {
|
||||
search_results[action.context] = [...search_results[action.context], ...action.results];
|
||||
|
||||
@ -22,7 +22,6 @@ export default function reducer(ui = {}, action) {
|
||||
}
|
||||
return ui;
|
||||
|
||||
|
||||
case 'TOGGLE_SIDEBAR':
|
||||
var new_state = !ui.sidebar_open;
|
||||
if (typeof (action.new_state) !== 'undefined') new_state = action.new_state;
|
||||
@ -42,20 +41,14 @@ export default function reducer(ui = {}, action) {
|
||||
case 'INSTALL_PROMPT':
|
||||
return { ...ui, install_prompt: action.event };
|
||||
|
||||
|
||||
/**
|
||||
* Context menu
|
||||
* */
|
||||
|
||||
case 'SHOW_CONTEXT_MENU':
|
||||
return { ...ui, context_menu: action.data };
|
||||
|
||||
case 'HIDE_CONTEXT_MENU':
|
||||
return {
|
||||
|
||||
...ui,
|
||||
context_menu: { ...ui.context_menu, closing: true },
|
||||
};
|
||||
return { ...ui, context_menu: { ...ui.context_menu, closing: true } };
|
||||
|
||||
case 'REMOVE_CONTEXT_MENU':
|
||||
return { ...ui, context_menu: null };
|
||||
@ -64,20 +57,14 @@ export default function reducer(ui = {}, action) {
|
||||
return { ...ui, touch_context_menu: action.data };
|
||||
|
||||
case 'HIDE_TOUCH_CONTEXT_MENU':
|
||||
return {
|
||||
|
||||
...ui,
|
||||
touch_context_menu: { ...ui.touch_context_menu, closing: true },
|
||||
};
|
||||
return { ...ui, touch_context_menu: { ...ui.touch_context_menu, closing: true } };
|
||||
|
||||
case 'REMOVE_TOUCH_CONTEXT_MENU':
|
||||
return { ...ui, touch_context_menu: null };
|
||||
|
||||
|
||||
/**
|
||||
* Dragging
|
||||
* */
|
||||
|
||||
case 'DRAG_START':
|
||||
return {
|
||||
...ui,
|
||||
@ -100,11 +87,9 @@ export default function reducer(ui = {}, action) {
|
||||
case 'DRAG_END':
|
||||
return { ...ui, dragger: false };
|
||||
|
||||
|
||||
/**
|
||||
* Modals
|
||||
* */
|
||||
|
||||
case 'OPEN_MODAL':
|
||||
return { ...ui, modal: action.modal };
|
||||
|
||||
@ -115,7 +100,6 @@ export default function reducer(ui = {}, action) {
|
||||
/**
|
||||
* Notifications
|
||||
* */
|
||||
|
||||
case 'CREATE_NOTIFICATION':
|
||||
var notifications = { ...ui.notifications };
|
||||
notifications[action.notification.key] = action.notification;
|
||||
|
||||
@ -34,18 +34,17 @@ class Search extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.uiActions.setWindowTitle('Search');
|
||||
componentDidMount = () => {
|
||||
const {
|
||||
uiActions: {
|
||||
setWindowTitle,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
setWindowTitle('Search');
|
||||
|
||||
// Auto-focus on the input field
|
||||
$(document).find('.search-form input').focus();
|
||||
|
||||
// Listen for a query baked-in to the URL
|
||||
// This would be the case when we've clicked from a link elsewhere
|
||||
this.digestUri({
|
||||
...this.props,
|
||||
term: decodeURIComponent(this.props.term),
|
||||
});
|
||||
}
|
||||
|
||||
componentDidUpdate = ({
|
||||
@ -61,97 +60,154 @@ class Search extends React.Component {
|
||||
} = this.props;
|
||||
const { type, term } = this.state;
|
||||
|
||||
if (prevType !== typeProp || prevTerm !== termProp) {
|
||||
this.digestUri({ type: typeProp, term: termProp });
|
||||
}
|
||||
|
||||
// Services came online
|
||||
if (!prev_mopidy_connected && mopidy_connected && uri_schemes_search_enabled) {
|
||||
this.search(type, term, 'mopidy');
|
||||
|
||||
if (uri_schemes_search_enabled.includes('spotify:')) {
|
||||
this.search(type, term, 'spotify');
|
||||
// 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) {
|
||||
this.search(type, term);
|
||||
}
|
||||
}
|
||||
|
||||
handleSubmit = (term) => {
|
||||
onSubmit = (term) => {
|
||||
const { type } = this.state;
|
||||
const { history, term: propTerm } = this.props;
|
||||
const { history } = this.props;
|
||||
const encodedTerm = encodeURIComponent(term);
|
||||
|
||||
this.setState(
|
||||
{ term }, () => {
|
||||
// Unchanged term, so this is a forced re-search
|
||||
// Often the other search parameters have changed instead, but we can't
|
||||
// push a URL change when the term hasn't changed
|
||||
if (propTerm === term) {
|
||||
this.search();
|
||||
} else {
|
||||
history.push(`/search/${type}/${encodedTerm}`);
|
||||
}
|
||||
{ term },
|
||||
() => {
|
||||
history.push(`/search/${type}/${encodedTerm}`);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
onReset = () => {
|
||||
const { history } = this.props;
|
||||
this.setState({ term: '', type: 'all' });
|
||||
history.push('/search');
|
||||
}
|
||||
|
||||
// Digest the URI query property
|
||||
// Triggered when the URL changes
|
||||
digestUri = ({ type, term } = this.props) => {
|
||||
if (type && term) {
|
||||
this.setState({ type, term });
|
||||
onSortChange = (value) => {
|
||||
const { uiActions: { hideContextMenu } } = this.props;
|
||||
this.setSort(value);
|
||||
hideContextMenu();
|
||||
}
|
||||
|
||||
this.search(type, term);
|
||||
onSourceChange = (value) => {
|
||||
const {
|
||||
uiActions: {
|
||||
set,
|
||||
hideContextMenu,
|
||||
},
|
||||
} = this.props;
|
||||
set({ uri_schemes_search_enabled: value });
|
||||
hideContextMenu();
|
||||
}
|
||||
|
||||
onSourceClose = () => {
|
||||
spotifyActions.clearSearchResults();
|
||||
mopidyActions.clearSearchResults();
|
||||
this.search();
|
||||
};
|
||||
|
||||
digestUri = () => {
|
||||
const {
|
||||
type,
|
||||
term,
|
||||
} = this.props;
|
||||
|
||||
if (type && term) {
|
||||
this.setState({ type, term }, () => {
|
||||
this.search();
|
||||
});
|
||||
} else if (!term || term === '') {
|
||||
this.props.spotifyActions.clearSearchResults();
|
||||
this.props.mopidyActions.clearSearchResults();
|
||||
this.clearSearch();
|
||||
}
|
||||
}
|
||||
|
||||
search = (type = this.state.type, term = this.state.term, provider) => {
|
||||
this.props.uiActions.setWindowTitle(`Search: ${decodeURIComponent(term)}`);
|
||||
clearSearch = () => {
|
||||
const {
|
||||
spotifyActions,
|
||||
mopidyActions,
|
||||
uiActions: {
|
||||
setWindowTitle,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
if (type && term) {
|
||||
if (provider == 'mopidy' || (this.props.mopidy_connected && this.props.uri_schemes_search_enabled)) {
|
||||
if (this.props.mopidy_search_results.query === undefined || this.props.mopidy_search_results.query != term) {
|
||||
this.props.mopidyActions.clearSearchResults();
|
||||
this.props.mopidyActions.getSearchResults(type, term);
|
||||
}
|
||||
spotifyActions.clearSearchResults();
|
||||
mopidyActions.clearSearchResults();
|
||||
setWindowTitle('Search');
|
||||
this.setState({ term: '' });
|
||||
}
|
||||
|
||||
search = () => {
|
||||
const {
|
||||
uiActions: {
|
||||
setWindowTitle,
|
||||
},
|
||||
mopidy_connected,
|
||||
uri_schemes_search_enabled,
|
||||
mopidyActions,
|
||||
spotifyActions,
|
||||
mopidy_search_results: {
|
||||
query: {
|
||||
term: mopidyTerm,
|
||||
type: mopidyType,
|
||||
} = {},
|
||||
},
|
||||
spotify_search_results: {
|
||||
query: {
|
||||
term: spotifyTerm,
|
||||
type: spotifyType,
|
||||
} = {},
|
||||
},
|
||||
} = this.props;
|
||||
const {
|
||||
type,
|
||||
term,
|
||||
} = this.state;
|
||||
|
||||
console.info(`Searching for ${type} matching "${term}"`);
|
||||
|
||||
setWindowTitle(`Search: ${decodeURIComponent(term)}`);
|
||||
|
||||
if (type && term && mopidy_connected && uri_schemes_search_enabled) {
|
||||
if (mopidyTerm !== term || mopidyType !== type) {
|
||||
mopidyActions.clearSearchResults();
|
||||
mopidyActions.getSearchResults(type, term);
|
||||
}
|
||||
|
||||
if (provider == 'spotify' || (this.props.mopidy_connected && this.props.uri_schemes_search_enabled && this.props.uri_schemes_search_enabled.includes('spotify:'))) {
|
||||
if (this.props.spotify_search_results.query === undefined || this.props.spotify_search_results.query != term) {
|
||||
this.props.spotifyActions.clearSearchResults();
|
||||
this.props.spotifyActions.getSearchResults(type, term);
|
||||
}
|
||||
if ((spotifyTerm !== term || spotifyType !== type) && uri_schemes_search_enabled.includes('spotify:')) {
|
||||
spotifyActions.clearSearchResults();
|
||||
spotifyActions.getSearchResults(type, term);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadMore(type) {
|
||||
loadMore = (type) => {
|
||||
alert(`load more: ${type}`);
|
||||
// this.props.spotifyActions.getURL(this.props['spotify_'+type+'_more'], 'SPOTIFY_SEARCH_RESULTS_LOADED_MORE_'+type.toUpperCase());
|
||||
}
|
||||
|
||||
setSort(value) {
|
||||
setSort = (value) => {
|
||||
const {
|
||||
sort,
|
||||
sort_reverse,
|
||||
uiActions: {
|
||||
set,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
let reverse = false;
|
||||
if (this.props.sort == value) reverse = !this.props.sort_reverse;
|
||||
if (sort === value) reverse = !sort_reverse;
|
||||
|
||||
const data = {
|
||||
search_results_sort_reverse: reverse,
|
||||
search_results_sort: value,
|
||||
};
|
||||
this.props.uiActions.set(data);
|
||||
}
|
||||
|
||||
handleSourceChange(value) {
|
||||
this.props.uiActions.set({ uri_schemes_search_enabled: value });
|
||||
this.props.uiActions.hideContextMenu();
|
||||
set(data);
|
||||
}
|
||||
|
||||
render = () => {
|
||||
@ -160,39 +216,20 @@ class Search extends React.Component {
|
||||
type,
|
||||
} = this.state;
|
||||
const {
|
||||
search_settings,
|
||||
uri_schemes,
|
||||
sort,
|
||||
sort_reverse,
|
||||
history,
|
||||
uri_schemes_priority,
|
||||
uri_schemes_search_enabled,
|
||||
mopidy_search_results,
|
||||
spotify_search_results,
|
||||
spotifyActions,
|
||||
mopidyActions,
|
||||
uiActions,
|
||||
} = this.props;
|
||||
|
||||
const sort_options = [
|
||||
{
|
||||
value: 'followers',
|
||||
label: 'Popularity',
|
||||
},
|
||||
{
|
||||
value: 'name',
|
||||
label: 'Name',
|
||||
},
|
||||
{
|
||||
value: 'artists.name',
|
||||
label: 'Artist',
|
||||
},
|
||||
{
|
||||
value: 'duration',
|
||||
label: 'Duration',
|
||||
},
|
||||
{
|
||||
value: 'uri',
|
||||
label: 'Source',
|
||||
},
|
||||
{ value: 'followers', label: 'Popularity' },
|
||||
{ value: 'name', label: 'Name' },
|
||||
{ value: 'artists.name', label: 'Artist' },
|
||||
{ value: 'duration', label: 'Duration' },
|
||||
{ value: 'uri', label: 'Source' },
|
||||
];
|
||||
|
||||
const provider_options = [];
|
||||
@ -212,19 +249,15 @@ class Search extends React.Component {
|
||||
valueAsLabel
|
||||
options={sort_options}
|
||||
selected_icon={sort_reverse ? 'keyboard_arrow_up' : 'keyboard_arrow_down'}
|
||||
handleChange={(value) => { this.setSort(value); uiActions.hideContextMenu(); }}
|
||||
handleChange={this.onSortChange}
|
||||
/>
|
||||
<DropdownField
|
||||
icon="cloud"
|
||||
name="Sources"
|
||||
value={uri_schemes_search_enabled}
|
||||
options={provider_options}
|
||||
handleChange={(value) => this.handleSourceChange(value)}
|
||||
onClose={() => {
|
||||
spotifyActions.clearSearchResults();
|
||||
mopidyActions.clearSearchResults();
|
||||
this.search();
|
||||
}}
|
||||
handleChange={this.onSourceChange}
|
||||
onClose={this.onSourceClose}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
@ -239,7 +272,7 @@ class Search extends React.Component {
|
||||
key={`search_form_${type}_${term}`}
|
||||
history={history}
|
||||
term={term}
|
||||
onSubmit={(term) => this.handleSubmit(term)}
|
||||
onSubmit={this.onSubmit}
|
||||
onReset={this.onReset}
|
||||
/>
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@ import { bindActionCreators } from 'redux';
|
||||
import PlaylistGrid from '../../components/PlaylistGrid';
|
||||
import Header from '../../components/Header';
|
||||
import Icon from '../../components/Icon';
|
||||
import Parallax from '../../components/Parallax';
|
||||
import Loader from '../../components/Loader';
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
import * as mopidyActions from '../../services/mopidy/actions';
|
||||
@ -14,17 +13,40 @@ import { isLoading } from '../../util/helpers';
|
||||
|
||||
class DiscoverFeatured extends React.Component {
|
||||
componentDidMount() {
|
||||
this.props.uiActions.setWindowTitle('Featured playlists');
|
||||
if (!this.props.featured_playlists) {
|
||||
this.props.spotifyActions.getFeaturedPlaylists();
|
||||
}
|
||||
const {
|
||||
featured_playlists,
|
||||
uiActions: {
|
||||
setWindowTitle,
|
||||
},
|
||||
spotifyActions: {
|
||||
getFeaturedPlaylists,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
setWindowTitle('Featured playlists');
|
||||
if (!featured_playlists) getFeaturedPlaylists();
|
||||
}
|
||||
|
||||
playPlaylist(e, playlist) {
|
||||
this.props.mopidyActions.playPlaylist(playlist.uri);
|
||||
onRefresh = () => {
|
||||
const {
|
||||
uiActions: {
|
||||
hideContextMenu,
|
||||
},
|
||||
spotifyActions: {
|
||||
getFeaturedPlaylists,
|
||||
},
|
||||
} = this.props;
|
||||
hideContextMenu();
|
||||
getFeaturedPlaylists();
|
||||
}
|
||||
|
||||
handleContextMenu(e, item) {
|
||||
const {
|
||||
uiActions: {
|
||||
showContextMenu,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
e.preventDefault();
|
||||
const data = {
|
||||
e,
|
||||
@ -32,14 +54,21 @@ class DiscoverFeatured extends React.Component {
|
||||
uris: [item.uri],
|
||||
items: [item],
|
||||
};
|
||||
this.props.uiActions.showContextMenu(data);
|
||||
showContextMenu(data);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (isLoading(this.props.load_queue, ['spotify_browse/featured-playlists'])) {
|
||||
render = () => {
|
||||
const {
|
||||
load_queue,
|
||||
uiActions,
|
||||
featured_playlists,
|
||||
playlists,
|
||||
} = this.props;
|
||||
|
||||
if (isLoading(load_queue, ['spotify_browse/featured-playlists'])) {
|
||||
return (
|
||||
<div className="view discover-featured-view preserve-3d">
|
||||
<Header className="overlay" uiActions={this.props.uiActions}>
|
||||
<Header className="overlay" uiActions={uiActions}>
|
||||
<Icon name="star" type="material" />
|
||||
Featured playlists
|
||||
</Header>
|
||||
@ -48,38 +77,38 @@ class DiscoverFeatured extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
const playlists = [];
|
||||
if (this.props.featured_playlists) {
|
||||
for (let i = 0; i < this.props.featured_playlists.playlists.length; i++) {
|
||||
const uri = this.props.featured_playlists.playlists[i];
|
||||
if (this.props.playlists.hasOwnProperty(uri)) {
|
||||
playlists.push(this.props.playlists[uri]);
|
||||
const items = [];
|
||||
if (featured_playlists) {
|
||||
for (let i = 0; i < featured_playlists.playlists.length; i++) {
|
||||
const uri = featured_playlists.playlists[i];
|
||||
if (playlists.hasOwnProperty(uri)) {
|
||||
items.push(playlists[uri]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = (
|
||||
<a className="button button--no-hover" onClick={(e) => { this.props.uiActions.hideContextMenu(); this.props.spotifyActions.getFeaturedPlaylists(); }}>
|
||||
<a className="button button--no-hover" onClick={this.onRefresh}>
|
||||
<Icon name="refresh" />
|
||||
Refresh
|
||||
Refresh
|
||||
</a>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="view discover-featured-view preserve-3d">
|
||||
<Header options={options}>
|
||||
<Header uiActions={uiActions} options={options}>
|
||||
<Icon name="star" type="material" />
|
||||
Featured playlists
|
||||
Featured playlists
|
||||
</Header>
|
||||
<section className="content-wrapper grid-wrapper">
|
||||
{playlists ? <PlaylistGrid playlists={playlists} /> : null }
|
||||
{items && <PlaylistGrid playlists={items} />}
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
const mapStateToProps = (state) => ({
|
||||
theme: state.ui.theme,
|
||||
load_queue: state.ui.load_queue,
|
||||
featured_playlists: state.spotify.featured_playlists,
|
||||
|
||||
@ -656,6 +656,7 @@ footer {
|
||||
font-size: 2rem;
|
||||
line-height: 2rem;
|
||||
display: block;
|
||||
letter-spacing: 0.08rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
|
||||
@ -84,6 +84,10 @@
|
||||
input {
|
||||
font-size: 1.8rem;
|
||||
height: 2.5rem;
|
||||
letter-spacing: 0.08rem;
|
||||
}
|
||||
&__reset {
|
||||
padding: 0.25rem 0 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user