mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-23 23:20:57 +03:00
feat: store state in localStorage
This commit is contained in:
parent
944f3695c4
commit
083a11a563
5
ui/package-lock.json
generated
5
ui/package-lock.json
generated
@ -10436,6 +10436,11 @@
|
||||
"lodash._reinterpolate": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"lodash.throttle": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
|
||||
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
|
||||
},
|
||||
"lodash.uniq": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
|
||||
|
@ -8,6 +8,7 @@
|
||||
"@testing-library/user-event": "^10.0.0",
|
||||
"deepmerge": "^4.2.2",
|
||||
"jwt-decode": "^2.2.0",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"md5-hex": "^3.0.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"ra-data-json-server": "^3.3.1",
|
||||
|
@ -1,4 +1,6 @@
|
||||
import React from 'react'
|
||||
import { Provider } from 'react-redux'
|
||||
import { createHashHistory } from 'history'
|
||||
import { Admin, resolveBrowserLocale, Resource } from 'react-admin'
|
||||
import dataProvider from './dataProvider'
|
||||
import authProvider from './authProvider'
|
||||
@ -15,12 +17,15 @@ import { Player, playQueueReducer } from './audioplayer'
|
||||
import { albumViewReducer } from './album/albumState'
|
||||
import customRoutes from './routes'
|
||||
import themeReducer from './configuration/themeReducer'
|
||||
import createAdminStore from './store/createAdminStore'
|
||||
|
||||
const i18nProvider = polyglotI18nProvider(
|
||||
(locale) => (messages[locale] ? messages[locale] : messages.en),
|
||||
resolveBrowserLocale()
|
||||
)
|
||||
|
||||
const history = createHashHistory()
|
||||
|
||||
const App = () => {
|
||||
try {
|
||||
const appConfig = JSON.parse(window.__APP_CONFIG__)
|
||||
@ -32,44 +37,57 @@ const App = () => {
|
||||
} catch (e) {}
|
||||
|
||||
return (
|
||||
<Admin
|
||||
customReducers={{
|
||||
queue: playQueueReducer,
|
||||
albumView: albumViewReducer,
|
||||
theme: themeReducer
|
||||
}}
|
||||
dataProvider={dataProvider}
|
||||
authProvider={authProvider}
|
||||
i18nProvider={i18nProvider}
|
||||
customRoutes={customRoutes}
|
||||
layout={Layout}
|
||||
loginPage={Login}
|
||||
<Provider
|
||||
store={createAdminStore({
|
||||
authProvider,
|
||||
dataProvider,
|
||||
history,
|
||||
customReducers: {
|
||||
queue: playQueueReducer,
|
||||
albumView: albumViewReducer,
|
||||
theme: themeReducer
|
||||
}
|
||||
})}
|
||||
>
|
||||
{(permissions) => [
|
||||
<Resource name="artist" {...artist} options={{ subMenu: 'library' }} />,
|
||||
<Resource name="album" {...album} options={{ subMenu: 'library' }} />,
|
||||
<Resource name="song" {...song} options={{ subMenu: 'library' }} />,
|
||||
<Resource name="albumSong" />,
|
||||
permissions === 'admin' ? (
|
||||
<Resource name="user" {...user} options={{ subMenu: 'settings' }} />
|
||||
) : null,
|
||||
<Resource
|
||||
name="player"
|
||||
{...player}
|
||||
options={{ subMenu: 'settings' }}
|
||||
/>,
|
||||
permissions === 'admin' ? (
|
||||
<Admin
|
||||
dataProvider={dataProvider}
|
||||
authProvider={authProvider}
|
||||
i18nProvider={i18nProvider}
|
||||
customRoutes={customRoutes}
|
||||
history={history}
|
||||
layout={Layout}
|
||||
loginPage={Login}
|
||||
>
|
||||
{(permissions) => [
|
||||
<Resource
|
||||
name="transcoding"
|
||||
{...transcoding}
|
||||
name="artist"
|
||||
{...artist}
|
||||
options={{ subMenu: 'library' }}
|
||||
/>,
|
||||
<Resource name="album" {...album} options={{ subMenu: 'library' }} />,
|
||||
<Resource name="song" {...song} options={{ subMenu: 'library' }} />,
|
||||
<Resource name="albumSong" />,
|
||||
permissions === 'admin' ? (
|
||||
<Resource name="user" {...user} options={{ subMenu: 'settings' }} />
|
||||
) : null,
|
||||
<Resource
|
||||
name="player"
|
||||
{...player}
|
||||
options={{ subMenu: 'settings' }}
|
||||
/>
|
||||
) : (
|
||||
<Resource name="transcoding" />
|
||||
),
|
||||
<Player />
|
||||
]}
|
||||
</Admin>
|
||||
/>,
|
||||
permissions === 'admin' ? (
|
||||
<Resource
|
||||
name="transcoding"
|
||||
{...transcoding}
|
||||
options={{ subMenu: 'settings' }}
|
||||
/>
|
||||
) : (
|
||||
<Resource name="transcoding" />
|
||||
),
|
||||
<Player />
|
||||
]}
|
||||
</Admin>
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -22,8 +22,8 @@ const selectAlbumList = (mode) => ({ type: mode })
|
||||
|
||||
const albumViewReducer = (
|
||||
previousState = {
|
||||
mode: localStorage.getItem('albumViewMode') || ALBUM_MODE_LIST,
|
||||
list: localStorage.getItem('albumListType') || ALBUM_LIST_ALL,
|
||||
mode: ALBUM_MODE_LIST,
|
||||
list: ALBUM_LIST_ALL,
|
||||
params: { sort: {}, filter: {} }
|
||||
},
|
||||
payload
|
||||
@ -32,14 +32,12 @@ const albumViewReducer = (
|
||||
switch (type) {
|
||||
case ALBUM_MODE_GRID:
|
||||
case ALBUM_MODE_LIST:
|
||||
localStorage.setItem('albumViewMode', type)
|
||||
return { ...previousState, mode: type }
|
||||
case ALBUM_LIST_ALL:
|
||||
case ALBUM_LIST_RANDOM:
|
||||
case ALBUM_LIST_NEWEST:
|
||||
case ALBUM_LIST_RECENT:
|
||||
case ALBUM_LIST_STARRED:
|
||||
localStorage.setItem('albumListType', type)
|
||||
return { ...previousState, list: type, params: albumListParams[type] }
|
||||
default:
|
||||
return previousState
|
||||
|
59
ui/src/store/createAdminStore.js
Normal file
59
ui/src/store/createAdminStore.js
Normal file
@ -0,0 +1,59 @@
|
||||
import { applyMiddleware, combineReducers, compose, createStore } from 'redux'
|
||||
import { routerMiddleware, connectRouter } from 'connected-react-router'
|
||||
import createSagaMiddleware from 'redux-saga'
|
||||
import { all, fork } from 'redux-saga/effects'
|
||||
import { adminReducer, adminSaga, USER_LOGOUT } from 'react-admin'
|
||||
import throttle from 'lodash.throttle'
|
||||
import { loadState, saveState } from './persistState'
|
||||
|
||||
export default ({
|
||||
authProvider,
|
||||
dataProvider,
|
||||
history,
|
||||
customReducers = {}
|
||||
}) => {
|
||||
const reducer = combineReducers({
|
||||
admin: adminReducer,
|
||||
router: connectRouter(history),
|
||||
...customReducers
|
||||
})
|
||||
const resettableAppReducer = (state, action) =>
|
||||
reducer(action.type !== USER_LOGOUT ? state : undefined, action)
|
||||
|
||||
const saga = function* rootSaga() {
|
||||
yield all([adminSaga(dataProvider, authProvider)].map(fork))
|
||||
}
|
||||
const sagaMiddleware = createSagaMiddleware()
|
||||
|
||||
const composeEnhancers =
|
||||
(process.env.NODE_ENV === 'development' &&
|
||||
typeof window !== 'undefined' &&
|
||||
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ &&
|
||||
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
|
||||
trace: true,
|
||||
traceLimit: 25
|
||||
})) ||
|
||||
compose
|
||||
|
||||
const persistedState = loadState()
|
||||
const store = createStore(
|
||||
resettableAppReducer,
|
||||
persistedState,
|
||||
composeEnhancers(applyMiddleware(sagaMiddleware, routerMiddleware(history)))
|
||||
)
|
||||
|
||||
store.subscribe(
|
||||
throttle(() => {
|
||||
const state = store.getState()
|
||||
saveState({
|
||||
theme: state.theme,
|
||||
// queue: state.queue, TODO: Need to make queue serializable (remove functions from it)
|
||||
albumView: state.albumView
|
||||
})
|
||||
}),
|
||||
1000
|
||||
)
|
||||
|
||||
sagaMiddleware.run(saga)
|
||||
return store
|
||||
}
|
20
ui/src/store/persistState.js
Normal file
20
ui/src/store/persistState.js
Normal file
@ -0,0 +1,20 @@
|
||||
export const loadState = () => {
|
||||
try {
|
||||
const serializedState = localStorage.getItem('state')
|
||||
if (serializedState === null) {
|
||||
return undefined
|
||||
}
|
||||
return JSON.parse(serializedState)
|
||||
} catch (err) {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
export const saveState = (state) => {
|
||||
try {
|
||||
const serializedState = JSON.stringify(state)
|
||||
localStorage.setItem('state', serializedState)
|
||||
} catch (err) {
|
||||
// Ignore write errors
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user