Option to disable grid glow (firefox performance issue); Using process for library loading (WIP)

This commit is contained in:
James Barnsley
2020-10-20 09:07:42 +13:00
parent a2e2d37a4d
commit 870407c168
17 changed files with 514 additions and 214 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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

View File

@ -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),

View File

@ -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),

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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),

View File

@ -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
View 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,
};

View File

@ -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,

View File

@ -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,

View File

@ -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>

View File

@ -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),

View File

@ -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();
}