Option to disable grid glow (firefox performance issue); Using process for library loading (WIP)
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
10
mopidy_iris/static/app.min.js
vendored
10
mopidy_iris/static/app.min.js
vendored
File diff suppressed because one or more lines are too long
@ -106,7 +106,7 @@
|
||||
|
||||
// Release details
|
||||
// These are automatically injected to built HTML
|
||||
var build = "1602663216";
|
||||
var build = "1603129371";
|
||||
var version = "3.53.0";
|
||||
|
||||
// Construct the script tag
|
||||
|
||||
@ -394,24 +394,53 @@ export class App extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
language: state.ui.language,
|
||||
theme: state.ui.theme,
|
||||
wide_scrollbar_enabled: state.ui.wide_scrollbar_enabled,
|
||||
smooth_scrolling_enabled: state.ui.smooth_scrolling_enabled,
|
||||
hotkeys_enabled: state.ui.hotkeys_enabled,
|
||||
allow_reporting: state.ui.allow_reporting,
|
||||
touch_dragging: state.ui.touch_dragging,
|
||||
initial_setup_complete: state.ui.initial_setup_complete,
|
||||
slim_mode: state.ui.slim_mode,
|
||||
snapcast_enabled: state.snapcast.enabled,
|
||||
spotify_authorized: state.spotify.authorization,
|
||||
sidebar_open: state.ui.sidebar_open,
|
||||
dragging: state.ui.dragger && state.ui.dragger.active,
|
||||
context_menu: state.ui.context_menu,
|
||||
debug_info: state.ui.debug_info,
|
||||
test_mode: state.ui.test_mode,
|
||||
});
|
||||
const mapStateToProps = (state) => {
|
||||
const {
|
||||
ui: {
|
||||
language,
|
||||
theme,
|
||||
wide_scrollbar_enabled,
|
||||
smooth_scrolling_enabled,
|
||||
hotkeys_enabled,
|
||||
allow_reporting,
|
||||
touch_dragging,
|
||||
initial_setup_complete,
|
||||
slim_mode,
|
||||
sidebar_open,
|
||||
dragger: {
|
||||
active: dragging,
|
||||
} = {},
|
||||
context_menu,
|
||||
debug_info,
|
||||
test_mode,
|
||||
},
|
||||
snapcast: {
|
||||
enabled: snapcast_enabled,
|
||||
},
|
||||
spotify: {
|
||||
authorization: spotify_authorized,
|
||||
},
|
||||
} = state;
|
||||
|
||||
return {
|
||||
language,
|
||||
theme,
|
||||
wide_scrollbar_enabled,
|
||||
smooth_scrolling_enabled,
|
||||
hotkeys_enabled,
|
||||
allow_reporting,
|
||||
touch_dragging,
|
||||
initial_setup_complete,
|
||||
slim_mode,
|
||||
sidebar_open,
|
||||
dragging,
|
||||
context_menu,
|
||||
debug_info,
|
||||
test_mode,
|
||||
snapcast_enabled,
|
||||
spotify_authorized,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
|
||||
@ -38,7 +38,7 @@ class DebugInfo extends React.Component {
|
||||
}
|
||||
|
||||
renderLoadQueue = () => {
|
||||
const { ui: { load_queue } } = this.props;
|
||||
const { load_queue } = this.props;
|
||||
if (!load_queue) return <div className="debug-info-item mid_grey-text">Nothing loading</div>;
|
||||
|
||||
const queue = indexToArray(load_queue);
|
||||
@ -56,19 +56,13 @@ class DebugInfo extends React.Component {
|
||||
render = () => {
|
||||
const localStorageUsage = this.localStorageSize();
|
||||
const {
|
||||
core: {
|
||||
items = {},
|
||||
},
|
||||
ui: {
|
||||
notifications = {},
|
||||
processes = {},
|
||||
slim_mode,
|
||||
test_mode,
|
||||
selected_tracks = [],
|
||||
},
|
||||
mopidy: {
|
||||
enqueue_uris_batches = [],
|
||||
},
|
||||
items = {},
|
||||
notifications = {},
|
||||
processes = {},
|
||||
slim_mode,
|
||||
test_mode,
|
||||
selected_tracks = [],
|
||||
enqueue_uris_batches = [],
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -144,11 +138,35 @@ class DebugInfo extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
core: state.core,
|
||||
ui: state.ui,
|
||||
mopidy: state.mopidy,
|
||||
});
|
||||
const mapStateToProps = (state) => {
|
||||
const {
|
||||
core: {
|
||||
items,
|
||||
},
|
||||
ui: {
|
||||
notifications,
|
||||
processes,
|
||||
slim_mode,
|
||||
test_mode,
|
||||
selected_tracks,
|
||||
load_queue,
|
||||
},
|
||||
mopidy: {
|
||||
enqueue_uris_batches,
|
||||
},
|
||||
} = state;
|
||||
|
||||
return {
|
||||
items,
|
||||
notifications,
|
||||
processes,
|
||||
slim_mode,
|
||||
test_mode,
|
||||
selected_tracks,
|
||||
enqueue_uris_batches,
|
||||
load_queue,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
uriType,
|
||||
scrollTo,
|
||||
@ -11,7 +11,7 @@ import Thumbnail from './Thumbnail';
|
||||
import LinksSentence from './LinksSentence';
|
||||
import { I18n } from '../locale';
|
||||
|
||||
export default class GridItem extends React.Component {
|
||||
class GridItem extends React.Component {
|
||||
componentDidMount() {
|
||||
const {
|
||||
mopidyActions,
|
||||
@ -99,7 +99,9 @@ export default class GridItem extends React.Component {
|
||||
link: customLink,
|
||||
type,
|
||||
show_source_icon,
|
||||
grid_glow_enabled,
|
||||
} = this.props;
|
||||
|
||||
let { item } = this.props;
|
||||
|
||||
if (!item) return null;
|
||||
@ -115,7 +117,7 @@ export default class GridItem extends React.Component {
|
||||
onContextMenu={this.onContextMenu}
|
||||
>
|
||||
<Thumbnail
|
||||
glow
|
||||
glow={grid_glow_enabled}
|
||||
size="medium"
|
||||
className="grid__item__thumbnail"
|
||||
images={item.images || item.icons}
|
||||
@ -134,3 +136,17 @@ export default class GridItem extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
const {
|
||||
ui: {
|
||||
grid_glow_enabled,
|
||||
},
|
||||
} = state;
|
||||
|
||||
return {
|
||||
grid_glow_enabled,
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(GridItem);
|
||||
|
||||
@ -48,6 +48,7 @@ common:
|
||||
sort: Sort
|
||||
filter: Filter
|
||||
by: ' by '
|
||||
loading_library: 'Loading %{provider} %{type}'
|
||||
fields:
|
||||
start_typing: 'Start typing...'
|
||||
search: 'Search...'
|
||||
@ -335,6 +336,8 @@ settings:
|
||||
touch_events: Enable touch events on play controls
|
||||
touch_events_tooltip: Allows left- and right-swipe to change tracks
|
||||
wide_scrollbars: Use wide scrollbars
|
||||
grid_glow: Thumbnail glow effect
|
||||
grid_glow_tooltip: Disable effect for lower-power devices or older browsers
|
||||
sources_priority:
|
||||
label: Sources priority
|
||||
description: Drag-and-drop to prioritize search providers and results
|
||||
|
||||
@ -125,7 +125,10 @@ const CoreMiddleware = (function () {
|
||||
return (store) => (next) => (action = {}) => {
|
||||
const {
|
||||
core,
|
||||
ui,
|
||||
ui: {
|
||||
allow_reporting,
|
||||
log_actions,
|
||||
},
|
||||
mopidy,
|
||||
spotify,
|
||||
} = store.getState();
|
||||
@ -136,6 +139,16 @@ const CoreMiddleware = (function () {
|
||||
// store.getState()
|
||||
window._store = store;
|
||||
|
||||
if (log_actions) {
|
||||
const ignored_actions = [
|
||||
'START_LOADING',
|
||||
'STOP_LOADING',
|
||||
];
|
||||
if (!ignored_actions.includes(action.type)) {
|
||||
console.log(action);
|
||||
}
|
||||
}
|
||||
|
||||
switch (action.type) {
|
||||
case 'HANDLE_EXCEPTION':
|
||||
const state = store.getState();
|
||||
@ -185,7 +198,7 @@ const CoreMiddleware = (function () {
|
||||
};
|
||||
|
||||
// Log with Analytics
|
||||
if (ui.allow_reporting) {
|
||||
if (allow_reporting) {
|
||||
ReactGA.event({
|
||||
category: 'Error',
|
||||
action: message,
|
||||
@ -210,49 +223,49 @@ const CoreMiddleware = (function () {
|
||||
break;
|
||||
|
||||
case 'PLAY_PLAYLIST':
|
||||
if (ui.allow_reporting) {
|
||||
if (allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Play', label: action.uri });
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'SAVE_PLAYLIST':
|
||||
if (ui.allow_reporting) {
|
||||
if (allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Save', label: action.key });
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'CREATE_PLAYLIST':
|
||||
if (ui.allow_reporting) {
|
||||
if (allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Create', label: +action.name });
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'REORDER_PLAYLIST_TRACKS':
|
||||
if (ui.allow_reporting) {
|
||||
if (allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Reorder tracks', label: action.key });
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'ADD_PLAYLIST_TRACKS':
|
||||
if (ui.allow_reporting) {
|
||||
if (allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Add tracks', label: action.playlist_uri });
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'REMOVE_PLAYLIST_TRACKS':
|
||||
if (ui.allow_reporting) {
|
||||
if (allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Remove tracks', label: action.playlist_uri });
|
||||
}
|
||||
next(action);
|
||||
break;
|
||||
|
||||
case 'DELETE_PLAYLIST':
|
||||
if (ui.allow_reporting) {
|
||||
if (allow_reporting) {
|
||||
ReactGA.event({ category: 'Playlist', action: 'Delete', label: action.uri });
|
||||
}
|
||||
next(action);
|
||||
|
||||
@ -5,8 +5,10 @@ import {
|
||||
formatArtists,
|
||||
formatTracks,
|
||||
} from '../../util/format';
|
||||
import { i18n } from '../../locale';
|
||||
const coreActions = require('../core/actions');
|
||||
const mopidyActions = require('../mopidy/actions');
|
||||
const uiActions = require('../ui/actions');
|
||||
|
||||
const GoogleMiddleware = (function () {
|
||||
// A Google request is an alias of the Mopidy request
|
||||
@ -70,15 +72,61 @@ const GoogleMiddleware = (function () {
|
||||
}
|
||||
|
||||
case 'GOOGLE_GET_LIBRARY_ARTISTS': {
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'GOOGLE_GET_LIBRARY_ARTISTS',
|
||||
i18n(
|
||||
'common.loading_library',
|
||||
{
|
||||
provider: i18n('services.google.title'),
|
||||
type: i18n('artist.title'),
|
||||
},
|
||||
),
|
||||
));
|
||||
|
||||
request(
|
||||
store,
|
||||
'library.browse',
|
||||
{ uri: 'gmusic:artist' },
|
||||
(browseResponse) => {
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'GOOGLE_GET_LIBRARY_ARTISTS',
|
||||
i18n(
|
||||
'common.loading_library',
|
||||
{
|
||||
provider: i18n('services.google.title'),
|
||||
type: i18n('artist.title'),
|
||||
},
|
||||
),
|
||||
{
|
||||
remaining: browseResponse.length,
|
||||
total: browseResponse.length,
|
||||
},
|
||||
));
|
||||
|
||||
const allUris = arrayOf('uri', browseResponse);
|
||||
const run = () => {
|
||||
if (allUris.length) {
|
||||
const uris = allUris.splice(0, 5);
|
||||
const uris = allUris.splice(0, 5);
|
||||
const processor = store.getState().ui.processes.GOOGLE_GET_LIBRARY_ARTISTS;
|
||||
|
||||
if (processor && processor.status === 'cancelling') {
|
||||
store.dispatch(uiActions.processCancelled('GOOGLE_GET_LIBRARY_ARTISTS'));
|
||||
return;
|
||||
}
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'GOOGLE_GET_LIBRARY_ARTISTS',
|
||||
i18n(
|
||||
'common.loading_library',
|
||||
{
|
||||
provider: i18n('services.google.title'),
|
||||
type: i18n('artist.title'),
|
||||
},
|
||||
),
|
||||
{
|
||||
remaining: allUris.length,
|
||||
},
|
||||
));
|
||||
|
||||
if (uris.length) {
|
||||
request(
|
||||
store,
|
||||
'library.lookup',
|
||||
@ -102,6 +150,7 @@ const GoogleMiddleware = (function () {
|
||||
},
|
||||
);
|
||||
} else {
|
||||
store.dispatch(uiActions.processFinished('GOOGLE_GET_LIBRARY_ARTISTS'));
|
||||
store.dispatch(coreActions.libraryLoaded({
|
||||
uri: 'google:library:artists',
|
||||
items_uris: arrayOf('uri', allUris),
|
||||
|
||||
@ -61,6 +61,7 @@ let state = {
|
||||
notifications: {},
|
||||
processes: {},
|
||||
suppressed_broadcasts: [],
|
||||
grid_glow_enabled: true,
|
||||
},
|
||||
mopidy: {
|
||||
connected: false,
|
||||
|
||||
25
src/js/util/debug.js
Executable file
25
src/js/util/debug.js
Executable file
@ -0,0 +1,25 @@
|
||||
import { useRef, useEffect } from 'react';
|
||||
|
||||
const useTraceUpdate = (props) => {
|
||||
const prev = useRef(props);
|
||||
useEffect(() => {
|
||||
const changedProps = Object.entries(props).reduce((ps, [k, v]) => {
|
||||
if (prev.current[k] !== v) {
|
||||
ps[k] = [prev.current[k], v];
|
||||
}
|
||||
return ps;
|
||||
}, {});
|
||||
if (Object.keys(changedProps).length > 0) {
|
||||
console.debug('Props changed:', changedProps);
|
||||
}
|
||||
prev.current = props;
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
useTraceUpdate,
|
||||
};
|
||||
|
||||
export default {
|
||||
useTraceUpdate,
|
||||
};
|
||||
@ -3,8 +3,10 @@ import * as helpers from './helpers';
|
||||
import * as selectors from './selectors';
|
||||
import * as storage from './storage';
|
||||
import * as format from './format';
|
||||
import * as debug from './debug';
|
||||
|
||||
export {
|
||||
debug,
|
||||
arrays,
|
||||
helpers,
|
||||
selectors,
|
||||
@ -13,6 +15,7 @@ export {
|
||||
};
|
||||
|
||||
export default {
|
||||
debug,
|
||||
arrays,
|
||||
helpers,
|
||||
selectors,
|
||||
|
||||
@ -8,6 +8,7 @@ const getLoadQueue = (state) => state.ui.load_queue;
|
||||
const getLibrary = (state, uri) => state.core.libraries[uri];
|
||||
const getLibraries = (state) => state.core.libraries;
|
||||
const getSearchResults = (state) => state.core.search_results;
|
||||
const getGridGlowEnabled = (state) => state.ui.grid_glow_enabled;
|
||||
|
||||
const makeItemSelector = (uri) => createSelector(
|
||||
[getItems],
|
||||
@ -54,6 +55,7 @@ const makeSearchResultsSelector = (term, type) => createSelector(
|
||||
export {
|
||||
getItem,
|
||||
getLibrary,
|
||||
getGridGlowEnabled,
|
||||
makeItemSelector,
|
||||
makeLibrarySelector,
|
||||
makeLoadingSelector,
|
||||
|
||||
@ -372,6 +372,20 @@ class Settings extends React.Component {
|
||||
<I18n path="settings.interface.behavior.wide_scrollbars" />
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="grid_glow_enabled"
|
||||
checked={ui.grid_glow_enabled}
|
||||
onChange={() => uiActions.set({ grid_glow_enabled: !ui.grid_glow_enabled })}
|
||||
/>
|
||||
<span className="label tooltip">
|
||||
<I18n path="settings.interface.behavior.grid_glow" />
|
||||
<span className="tooltip__content">
|
||||
<I18n path="settings.interface.behavior.grid_glow_tooltip" />
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -11,10 +11,12 @@ import Loader from '../../components/Loader';
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
import * as mopidyActions from '../../services/mopidy/actions';
|
||||
import * as spotifyActions from '../../services/spotify/actions';
|
||||
import { isLoading } from '../../util/helpers';
|
||||
import { i18n, I18n } from '../../locale';
|
||||
import Button from '../../components/Button';
|
||||
import { indexToArray } from '../../util/arrays';
|
||||
import {
|
||||
makeItemSelector,
|
||||
makeLoadingSelector,
|
||||
} from '../../util/selectors';
|
||||
|
||||
class DiscoverNewReleases extends React.Component {
|
||||
componentDidMount() {
|
||||
@ -37,14 +39,14 @@ class DiscoverNewReleases extends React.Component {
|
||||
|
||||
loadMore = () => {
|
||||
const {
|
||||
new_releases_more,
|
||||
more,
|
||||
spotifyActions: {
|
||||
getMore,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
getMore(
|
||||
new_releases_more,
|
||||
more,
|
||||
null,
|
||||
{
|
||||
type: 'SPOTIFY_NEW_RELEASES_LOADED',
|
||||
@ -92,14 +94,13 @@ class DiscoverNewReleases extends React.Component {
|
||||
|
||||
render = () => {
|
||||
const {
|
||||
load_queue,
|
||||
items,
|
||||
new_releases,
|
||||
new_releases_more,
|
||||
loading,
|
||||
albums,
|
||||
more,
|
||||
uiActions,
|
||||
} = this.props;
|
||||
|
||||
if (isLoading(load_queue, ['(.*)new-releases(.*)offset=0(.*)'])) {
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="view discover-new-releases-view">
|
||||
<Header>
|
||||
@ -111,8 +112,6 @@ class DiscoverNewReleases extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
const albums = indexToArray(items, new_releases || []);
|
||||
|
||||
const options = (
|
||||
<Button
|
||||
noHover
|
||||
@ -134,8 +133,8 @@ class DiscoverNewReleases extends React.Component {
|
||||
<AlbumGrid albums={albums} />
|
||||
</section>
|
||||
<LazyLoadListener
|
||||
loadKey={new_releases_more}
|
||||
showLoader={new_releases_more}
|
||||
loadKey={more}
|
||||
showLoader={more}
|
||||
loadMore={this.loadMore}
|
||||
/>
|
||||
</div>
|
||||
@ -143,14 +142,29 @@ class DiscoverNewReleases extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
theme: state.ui.theme,
|
||||
load_queue: state.ui.load_queue,
|
||||
items: state.core.items,
|
||||
new_releases: (state.spotify.new_releases ? state.spotify.new_releases : null),
|
||||
new_releases_more: (state.spotify.new_releases_more ? state.spotify.new_releases_more : null),
|
||||
new_releases_total: (state.spotify.new_releases_total ? state.spotify.new_releases_total : null),
|
||||
});
|
||||
const mapStateToProps = (state) => {
|
||||
const {
|
||||
ui: {
|
||||
theme,
|
||||
},
|
||||
spotify: {
|
||||
new_releases: uris,
|
||||
new_releases_more: more,
|
||||
new_releases_total: total,
|
||||
},
|
||||
} = state;
|
||||
const loadingSelector = makeLoadingSelector(['(.*)new-releases(.*)offset=0(.*)']);
|
||||
const itemSelector = makeItemSelector(uris);
|
||||
|
||||
return {
|
||||
uris,
|
||||
loading: loadingSelector(state),
|
||||
albums: itemSelector(state),
|
||||
more,
|
||||
total,
|
||||
theme,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
|
||||
@ -11,12 +11,8 @@ import LazyLoadListener from '../../components/LazyLoadListener';
|
||||
import Icon from '../../components/Icon';
|
||||
import * as uiActions from '../../services/ui/actions';
|
||||
import * as coreActions from '../../services/core/actions';
|
||||
import {
|
||||
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';
|
||||
import {
|
||||
@ -53,7 +49,6 @@ class LibraryArtists extends React.Component {
|
||||
setWindowTitle(i18n('library.artists.title'));
|
||||
|
||||
this.getMopidyLibrary();
|
||||
this.getGoogleLibrary();
|
||||
this.getSpotifyLibrary();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user