mirror of
https://github.com/austinried/subtracks.git
synced 2026-02-10 23:02:43 +01:00
fixed perf issue related to too many rerenders
rerenders were caused by strict equality check on object/array picks switched artistInfo to new store updated zustand and fixed deprecation warnings
This commit is contained in:
@@ -1,9 +1,7 @@
|
|||||||
import { CacheImageSize, CacheItemTypeKey } from '@app/models/cache'
|
import { CacheImageSize, CacheItemTypeKey } from '@app/models/cache'
|
||||||
import { ArtistInfo } from '@app/models/music'
|
|
||||||
import { selectCache } from '@app/state/cache'
|
import { selectCache } from '@app/state/cache'
|
||||||
import { selectMusic } from '@app/state/music'
|
|
||||||
import { selectSettings } from '@app/state/settings'
|
import { selectSettings } from '@app/state/settings'
|
||||||
import { useStore, Store } from '@app/state/store'
|
import { Store, useStore, useStoreDeep } from '@app/state/store'
|
||||||
import { useCallback, useEffect } from 'react'
|
import { useCallback, useEffect } from 'react'
|
||||||
|
|
||||||
const useFileRequest = (key: CacheItemTypeKey, id: string) => {
|
const useFileRequest = (key: CacheItemTypeKey, id: string) => {
|
||||||
@@ -61,28 +59,25 @@ export const useCoverArtFile = (coverArt = '-1', size: CacheImageSize = 'thumbna
|
|||||||
|
|
||||||
export const useArtistArtFile = (artistId: string, size: CacheImageSize = 'thumbnail') => {
|
export const useArtistArtFile = (artistId: string, size: CacheImageSize = 'thumbnail') => {
|
||||||
const type: CacheItemTypeKey = size === 'original' ? 'artistArt' : 'artistArtThumb'
|
const type: CacheItemTypeKey = size === 'original' ? 'artistArt' : 'artistArtThumb'
|
||||||
const fetchArtistInfo = useStore(selectMusic.fetchArtistInfo)
|
const fetchArtistInfo = useStore(store => store.fetchLibraryArtistInfo)
|
||||||
|
const artistInfo = useStoreDeep(store => store.entities.artistInfo[artistId])
|
||||||
const { file, request } = useFileRequest(type, artistId)
|
const { file, request } = useFileRequest(type, artistId)
|
||||||
const cacheItem = useStore(selectCache.cacheItem)
|
const cacheItem = useStore(selectCache.cacheItem)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!file) {
|
if (!artistInfo) {
|
||||||
cacheItem(type, artistId, async () => {
|
fetchArtistInfo(artistId)
|
||||||
let artistInfo: ArtistInfo | undefined
|
return
|
||||||
const cachedArtistInfo = useStore.getState().artistInfo[artistId]
|
|
||||||
|
|
||||||
if (cachedArtistInfo) {
|
|
||||||
artistInfo = cachedArtistInfo
|
|
||||||
} else {
|
|
||||||
artistInfo = await fetchArtistInfo(artistId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
cacheItem(type, artistId, async () => {
|
||||||
return type === 'artistArtThumb' ? artistInfo?.smallImageUrl : artistInfo?.largeImageUrl
|
return type === 'artistArtThumb' ? artistInfo?.smallImageUrl : artistInfo?.largeImageUrl
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// intentionally leaving file out so it doesn't re-render if the request fails
|
// intentionally leaving file out so it doesn't re-render if the request fails
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [artistId, cacheItem, fetchArtistInfo, type])
|
}, [artistId, cacheItem, fetchArtistInfo, type, artistInfo])
|
||||||
|
|
||||||
return { file, request }
|
return { file, request }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { selectMusic } from '@app/state/music'
|
import { selectMusic } from '@app/state/music'
|
||||||
import { Store, useStore } from '@app/state/store'
|
import { Store, useStore, useStoreDeep } from '@app/state/store'
|
||||||
import { useCallback, useEffect } from 'react'
|
import { useCallback, useEffect } from 'react'
|
||||||
|
|
||||||
export const useArtistInfo = (id: string) => {
|
export const useArtistInfo = (id: string) => {
|
||||||
const artistInfo = useStore(useCallback((state: Store) => state.artistInfo[id], [id]))
|
const artistInfo = useStoreDeep(useCallback(store => store.entities.artistInfo[id], [id]))
|
||||||
const fetchArtistInfo = useStore(selectMusic.fetchArtistInfo)
|
const fetchArtistInfo = useStore(store => store.fetchLibraryArtistInfo)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!artistInfo) {
|
if (!artistInfo) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { getCurrentTrack, getPlayerState, TrackExt, trackPlayerCommands } from '@app/state/trackplayer'
|
import { getCurrentTrack, getPlayerState, trackPlayerCommands } from '@app/state/trackplayer'
|
||||||
import TrackPlayer, { Event, State } from 'react-native-track-player'
|
import TrackPlayer, { Event, State } from 'react-native-track-player'
|
||||||
import { useStore } from './state/store'
|
import { useStore } from './state/store'
|
||||||
import { unstable_batchedUpdates } from 'react-native'
|
import { unstable_batchedUpdates } from 'react-native'
|
||||||
@@ -44,13 +44,12 @@ let serviceCreated = false
|
|||||||
|
|
||||||
const createService = async () => {
|
const createService = async () => {
|
||||||
useStore.subscribe(
|
useStore.subscribe(
|
||||||
(currentTrack?: TrackExt) => {
|
state => state.currentTrack?.id,
|
||||||
if (currentTrack) {
|
(currentTrackId?: string) => {
|
||||||
useStore.getState().scrobbleTrack(currentTrack.id)
|
if (currentTrackId) {
|
||||||
|
useStore.getState().scrobbleTrack(currentTrackId)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
state => state.currentTrack,
|
|
||||||
(prev, next) => prev?.id === next?.id,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
NetInfo.fetch().then(state => {
|
NetInfo.fetch().then(state => {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import Header from '@app/components/Header'
|
|||||||
import HeaderBar from '@app/components/HeaderBar'
|
import HeaderBar from '@app/components/HeaderBar'
|
||||||
import ListItem from '@app/components/ListItem'
|
import ListItem from '@app/components/ListItem'
|
||||||
import { Album, Song } from '@app/models/music'
|
import { Album, Song } from '@app/models/music'
|
||||||
import { useStore } from '@app/state/store'
|
import { useStore, useStoreDeep } from '@app/state/store'
|
||||||
import { selectTrackPlayer } from '@app/state/trackplayer'
|
import { selectTrackPlayer } from '@app/state/trackplayer'
|
||||||
import colors from '@app/styles/colors'
|
import colors from '@app/styles/colors'
|
||||||
import dimensions from '@app/styles/dimensions'
|
import dimensions from '@app/styles/dimensions'
|
||||||
@@ -70,7 +70,7 @@ const TopSongs = React.memo<{
|
|||||||
const ArtistAlbums = React.memo<{
|
const ArtistAlbums = React.memo<{
|
||||||
id: string
|
id: string
|
||||||
}>(({ id }) => {
|
}>(({ id }) => {
|
||||||
const albums = useStore(
|
const albums = useStoreDeep(
|
||||||
useCallback(
|
useCallback(
|
||||||
store => {
|
store => {
|
||||||
const ids = store.entities.artistAlbums[id]
|
const ids = store.entities.artistAlbums[id]
|
||||||
@@ -114,8 +114,8 @@ const ArtistViewFallback = React.memo(() => (
|
|||||||
))
|
))
|
||||||
|
|
||||||
const ArtistView = React.memo<{ id: string; title: string }>(({ id, title }) => {
|
const ArtistView = React.memo<{ id: string; title: string }>(({ id, title }) => {
|
||||||
const artist = useStore(useCallback(store => store.entities.artists[id], [id]))
|
const artist = useStoreDeep(useCallback(store => store.entities.artists[id], [id]))
|
||||||
const artistInfo = useStore(useCallback(store => store.entities.artistInfo[id], [id]))
|
const artistInfo = useStoreDeep(useCallback(store => store.entities.artistInfo[id], [id]))
|
||||||
|
|
||||||
const fetchArtist = useStore(store => store.fetchLibraryArtist)
|
const fetchArtist = useStore(store => store.fetchLibraryArtist)
|
||||||
const fetchArtistInfo = useStore(store => store.fetchLibraryArtistInfo)
|
const fetchArtistInfo = useStore(store => store.fetchLibraryArtistInfo)
|
||||||
|
|||||||
@@ -3,21 +3,20 @@ import CoverArt from '@app/components/CoverArt'
|
|||||||
import GradientScrollView from '@app/components/GradientScrollView'
|
import GradientScrollView from '@app/components/GradientScrollView'
|
||||||
import Header from '@app/components/Header'
|
import Header from '@app/components/Header'
|
||||||
import NothingHere from '@app/components/NothingHere'
|
import NothingHere from '@app/components/NothingHere'
|
||||||
import { useFetchPaginatedList } from '@app/hooks/list'
|
|
||||||
import { useActiveServerRefresh } from '@app/hooks/server'
|
import { useActiveServerRefresh } from '@app/hooks/server'
|
||||||
import { AlbumListItem } from '@app/models/music'
|
import { AlbumListItem } from '@app/models/music'
|
||||||
import { Album, mapById } from '@app/state/library'
|
import { mapById } from '@app/state/library'
|
||||||
import { selectMusic } from '@app/state/music'
|
|
||||||
import { selectSettings } from '@app/state/settings'
|
import { selectSettings } from '@app/state/settings'
|
||||||
import { Store, useStore } from '@app/state/store'
|
import { useStore, useStoreDeep } from '@app/state/store'
|
||||||
import colors from '@app/styles/colors'
|
import colors from '@app/styles/colors'
|
||||||
import font from '@app/styles/font'
|
import font from '@app/styles/font'
|
||||||
import { GetAlbumList2Params, GetAlbumList2TypeBase, GetAlbumListType } from '@app/subsonic/params'
|
import { GetAlbumList2TypeBase, GetAlbumListType } from '@app/subsonic/params'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
|
import equal from 'fast-deep-equal/es6/react'
|
||||||
import produce from 'immer'
|
import produce from 'immer'
|
||||||
import React, { createContext, useCallback, useContext, useEffect, useState } from 'react'
|
import React, { useCallback, useState } from 'react'
|
||||||
import { RefreshControl, ScrollView, StatusBar, StyleSheet, Text, View } from 'react-native'
|
import { RefreshControl, ScrollView, StatusBar, StyleSheet, Text, View } from 'react-native'
|
||||||
import create from 'zustand'
|
import create, { StateSelector } from 'zustand'
|
||||||
|
|
||||||
const titles: { [key in GetAlbumListType]?: string } = {
|
const titles: { [key in GetAlbumListType]?: string } = {
|
||||||
recent: 'Recently Played',
|
recent: 'Recently Played',
|
||||||
@@ -55,8 +54,8 @@ const AlbumItem = React.memo<{
|
|||||||
const Category = React.memo<{
|
const Category = React.memo<{
|
||||||
type: string
|
type: string
|
||||||
}>(({ type }) => {
|
}>(({ type }) => {
|
||||||
const list = useHomeStore(useCallback(store => store.lists[type] || [], [type]))
|
const list = useHomeStoreDeep(useCallback(store => store.lists[type] || [], [type]))
|
||||||
const albums = useStore(useCallback(store => mapById(store.entities.albums, list), [list]))
|
const albums = useStoreDeep(useCallback(store => mapById(store.entities.albums, list), [list]))
|
||||||
|
|
||||||
const Albums = () => (
|
const Albums = () => (
|
||||||
<ScrollView
|
<ScrollView
|
||||||
@@ -90,7 +89,7 @@ interface HomeState {
|
|||||||
setList: (type: string, list: string[]) => void
|
setList: (type: string, list: string[]) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const useHomeStore = create<HomeState>((set, get) => ({
|
const useHomeStore = create<HomeState>(set => ({
|
||||||
lists: {},
|
lists: {},
|
||||||
|
|
||||||
setList: (type, list) => {
|
setList: (type, list) => {
|
||||||
@@ -102,6 +101,10 @@ const useHomeStore = create<HomeState>((set, get) => ({
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
function useHomeStoreDeep<U>(stateSelector: StateSelector<HomeState, U>) {
|
||||||
|
return useHomeStore(stateSelector, equal)
|
||||||
|
}
|
||||||
|
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
const [refreshing, setRefreshing] = useState(false)
|
const [refreshing, setRefreshing] = useState(false)
|
||||||
const types = useStore(selectSettings.homeLists)
|
const types = useStore(selectSettings.homeLists)
|
||||||
@@ -113,9 +116,7 @@ const Home = () => {
|
|||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
types.map(async type => {
|
types.map(async type => {
|
||||||
console.log('fetch', type)
|
|
||||||
const ids = await fetchAlbumList({ type: type as GetAlbumList2TypeBase, size: 20, offset: 0 })
|
const ids = await fetchAlbumList({ type: type as GetAlbumList2TypeBase, size: 20, offset: 0 })
|
||||||
console.log('set', type)
|
|
||||||
setList(type, ids)
|
setList(type, ids)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,13 +6,12 @@ import { useFetchPaginatedList } from '@app/hooks/list'
|
|||||||
import { Album, AlbumListItem } from '@app/models/music'
|
import { Album, AlbumListItem } from '@app/models/music'
|
||||||
import { mapById } from '@app/state/library'
|
import { mapById } from '@app/state/library'
|
||||||
import { selectSettings } from '@app/state/settings'
|
import { selectSettings } from '@app/state/settings'
|
||||||
import { Store, useStore } from '@app/state/store'
|
import { useStore, useStoreDeep } from '@app/state/store'
|
||||||
import colors from '@app/styles/colors'
|
import colors from '@app/styles/colors'
|
||||||
import font from '@app/styles/font'
|
import font from '@app/styles/font'
|
||||||
import { GetAlbumList2Params, GetAlbumList2Type } from '@app/subsonic/params'
|
import { GetAlbumList2Params, GetAlbumList2Type } from '@app/subsonic/params'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
import pick from 'lodash.pick'
|
import React, { useCallback } from 'react'
|
||||||
import React, { useCallback, useEffect } from 'react'
|
|
||||||
import { StyleSheet, Text, useWindowDimensions, View } from 'react-native'
|
import { StyleSheet, Text, useWindowDimensions, View } from 'react-native'
|
||||||
|
|
||||||
const AlbumItem = React.memo<{
|
const AlbumItem = React.memo<{
|
||||||
@@ -97,7 +96,7 @@ const AlbumsList = () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const { list, refreshing, refresh, fetchNextPage } = useFetchPaginatedList(fetchPage, 300)
|
const { list, refreshing, refresh, fetchNextPage } = useFetchPaginatedList(fetchPage, 300)
|
||||||
const albums = useStore(useCallback(store => mapById(store.entities.albums, list), [list]))
|
const albums = useStoreDeep(useCallback(store => mapById(store.entities.albums, list), [list]))
|
||||||
|
|
||||||
const layout = useWindowDimensions()
|
const layout = useWindowDimensions()
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useFetchList2 } from '@app/hooks/list'
|
|||||||
import { Artist } from '@app/models/music'
|
import { Artist } from '@app/models/music'
|
||||||
import { ArtistFilterType } from '@app/models/settings'
|
import { ArtistFilterType } from '@app/models/settings'
|
||||||
import { selectSettings } from '@app/state/settings'
|
import { selectSettings } from '@app/state/settings'
|
||||||
import { Store, useStore } from '@app/state/store'
|
import { useStore, useStoreDeep } from '@app/state/store'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { StyleSheet, View } from 'react-native'
|
import { StyleSheet, View } from 'react-native'
|
||||||
|
|
||||||
@@ -19,12 +19,10 @@ const filterOptions: OptionData[] = [
|
|||||||
{ text: 'Random', value: 'random' },
|
{ text: 'Random', value: 'random' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const selectArtists = (store: Store) => store.entities.artists
|
|
||||||
|
|
||||||
const ArtistsList = () => {
|
const ArtistsList = () => {
|
||||||
const fetchArtists = useStore(store => store.fetchLibraryArtists)
|
const fetchArtists = useStore(store => store.fetchLibraryArtists)
|
||||||
const { refreshing, refresh } = useFetchList2(fetchArtists)
|
const { refreshing, refresh } = useFetchList2(fetchArtists)
|
||||||
const artists = useStore(selectArtists)
|
const artists = useStoreDeep(store => store.entities.artists)
|
||||||
|
|
||||||
const filter = useStore(selectSettings.libraryArtistFilter)
|
const filter = useStore(selectSettings.libraryArtistFilter)
|
||||||
const setFilter = useStore(selectSettings.setLibraryArtistFiler)
|
const setFilter = useStore(selectSettings.setLibraryArtistFiler)
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import GradientFlatList from '@app/components/GradientFlatList'
|
import GradientFlatList from '@app/components/GradientFlatList'
|
||||||
import ListItem from '@app/components/ListItem'
|
import ListItem from '@app/components/ListItem'
|
||||||
import { useFetchList, useFetchList2 } from '@app/hooks/list'
|
import { useFetchList2 } from '@app/hooks/list'
|
||||||
import { PlaylistListItem } from '@app/models/music'
|
import { PlaylistListItem } from '@app/models/music'
|
||||||
import { selectMusic } from '@app/state/music'
|
import { useStore, useStoreDeep } from '@app/state/store'
|
||||||
import { useStore } from '@app/state/store'
|
import React from 'react'
|
||||||
import React, { useCallback, useState } from 'react'
|
|
||||||
import { StyleSheet } from 'react-native'
|
import { StyleSheet } from 'react-native'
|
||||||
|
|
||||||
const PlaylistRenderItem: React.FC<{ item: PlaylistListItem }> = ({ item }) => (
|
const PlaylistRenderItem: React.FC<{ item: PlaylistListItem }> = ({ item }) => (
|
||||||
@@ -14,7 +13,7 @@ const PlaylistRenderItem: React.FC<{ item: PlaylistListItem }> = ({ item }) => (
|
|||||||
const PlaylistsList = () => {
|
const PlaylistsList = () => {
|
||||||
const fetchPlaylists = useStore(store => store.fetchLibraryPlaylists)
|
const fetchPlaylists = useStore(store => store.fetchLibraryPlaylists)
|
||||||
const { refreshing, refresh } = useFetchList2(fetchPlaylists)
|
const { refreshing, refresh } = useFetchList2(fetchPlaylists)
|
||||||
const playlists = useStore(store => store.entities.playlists)
|
const playlists = useStoreDeep(store => store.entities.playlists)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GradientFlatList
|
<GradientFlatList
|
||||||
|
|||||||
@@ -5,13 +5,12 @@ import ImageGradientFlatList from '@app/components/ImageGradientFlatList'
|
|||||||
import ListItem from '@app/components/ListItem'
|
import ListItem from '@app/components/ListItem'
|
||||||
import ListPlayerControls from '@app/components/ListPlayerControls'
|
import ListPlayerControls from '@app/components/ListPlayerControls'
|
||||||
import { useCoverArtFile } from '@app/hooks/cache'
|
import { useCoverArtFile } from '@app/hooks/cache'
|
||||||
import { useAlbumWithSongs, usePlaylistWithSongs } from '@app/hooks/music'
|
import { usePlaylistWithSongs } from '@app/hooks/music'
|
||||||
import { Album, AlbumWithSongs, PlaylistListItem, PlaylistWithSongs, Song } from '@app/models/music'
|
import { Album, PlaylistListItem, Song } from '@app/models/music'
|
||||||
import { useStore } from '@app/state/store'
|
import { useStore, useStoreDeep } from '@app/state/store'
|
||||||
import { selectTrackPlayer } from '@app/state/trackplayer'
|
import { selectTrackPlayer } from '@app/state/trackplayer'
|
||||||
import colors from '@app/styles/colors'
|
import colors from '@app/styles/colors'
|
||||||
import font from '@app/styles/font'
|
import font from '@app/styles/font'
|
||||||
import pick from 'lodash.pick'
|
|
||||||
import React, { useCallback, useEffect, useState } from 'react'
|
import React, { useCallback, useEffect, useState } from 'react'
|
||||||
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native'
|
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native'
|
||||||
|
|
||||||
@@ -139,8 +138,8 @@ const AlbumView = React.memo<{
|
|||||||
}>(({ id, title }) => {
|
}>(({ id, title }) => {
|
||||||
// const album = useAlbumWithSongs(id)
|
// const album = useAlbumWithSongs(id)
|
||||||
|
|
||||||
const album = useStore(useCallback(store => store.entities.albums[id], [id]))
|
const album = useStoreDeep(useCallback(store => store.entities.albums[id], [id]))
|
||||||
const songs = useStore(
|
const songs = useStoreDeep(
|
||||||
useCallback(
|
useCallback(
|
||||||
store => {
|
store => {
|
||||||
const ids = store.entities.albumSongs[id]
|
const ids = store.entities.albumSongs[id]
|
||||||
|
|||||||
@@ -20,16 +20,6 @@ export type CacheDirsByServer = Record<string, Record<CacheItemTypeKey, string>>
|
|||||||
export type CacheFilesByServer = Record<string, Record<CacheItemTypeKey, Record<string, CacheFile>>>
|
export type CacheFilesByServer = Record<string, Record<CacheItemTypeKey, Record<string, CacheFile>>>
|
||||||
export type CacheRequestsByServer = Record<string, Record<CacheItemTypeKey, Record<string, CacheRequest>>>
|
export type CacheRequestsByServer = Record<string, Record<CacheItemTypeKey, Record<string, CacheRequest>>>
|
||||||
|
|
||||||
// export type DownloadedItemsByServer = Record<
|
|
||||||
// string,
|
|
||||||
// {
|
|
||||||
// songs: { [songId: string]: DownloadedSong }
|
|
||||||
// albums: { [albumId: string]: DownloadedAlbum }
|
|
||||||
// artists: { [songId: string]: DownloadedArtist }
|
|
||||||
// playlists: { [playlistId: string]: DownloadedPlaylist }
|
|
||||||
// }
|
|
||||||
// >
|
|
||||||
|
|
||||||
export type CacheSlice = {
|
export type CacheSlice = {
|
||||||
cacheItem: (
|
cacheItem: (
|
||||||
key: CacheItemTypeKey,
|
key: CacheItemTypeKey,
|
||||||
|
|||||||
@@ -166,10 +166,6 @@ export type LibrarySlice = {
|
|||||||
albums: ById<Album>
|
albums: ById<Album>
|
||||||
albumSongs: OneToMany
|
albumSongs: OneToMany
|
||||||
|
|
||||||
// todo: remove these and store in component state
|
|
||||||
albumsList: PaginatedList
|
|
||||||
albumsListSize: number
|
|
||||||
|
|
||||||
playlists: ById<Playlist>
|
playlists: ById<Playlist>
|
||||||
playlistSongs: OneToMany
|
playlistSongs: OneToMany
|
||||||
|
|
||||||
@@ -216,8 +212,6 @@ const defaultEntities = () => ({
|
|||||||
artistNameTopSongs: {},
|
artistNameTopSongs: {},
|
||||||
|
|
||||||
albums: {},
|
albums: {},
|
||||||
albumsList: {},
|
|
||||||
albumsListSize: 300,
|
|
||||||
albumSongs: {},
|
albumSongs: {},
|
||||||
|
|
||||||
playlists: {},
|
playlists: {},
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { createMusicSlice, MusicSlice } from '@app/state/music'
|
import { createMusicSlice, MusicSlice } from '@app/state/music'
|
||||||
import { createSettingsSlice, SettingsSlice } from '@app/state/settings'
|
import { createSettingsSlice, SettingsSlice } from '@app/state/settings'
|
||||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||||
import create from 'zustand'
|
import equal from 'fast-deep-equal/es6/react'
|
||||||
import { persist, StateStorage } from 'zustand/middleware'
|
import create, { GetState, Mutate, SetState, StateSelector, StoreApi } from 'zustand'
|
||||||
|
import { persist, subscribeWithSelector } from 'zustand/middleware'
|
||||||
import { CacheSlice, createCacheSlice } from './cache'
|
import { CacheSlice, createCacheSlice } from './cache'
|
||||||
import migrations from './migrations'
|
|
||||||
import { createLibrarySlice, LibrarySlice } from './library'
|
import { createLibrarySlice, LibrarySlice } from './library'
|
||||||
|
import migrations from './migrations'
|
||||||
import { createMusicMapSlice, MusicMapSlice } from './musicmap'
|
import { createMusicMapSlice, MusicMapSlice } from './musicmap'
|
||||||
import { createTrackPlayerSlice, TrackPlayerSlice } from './trackplayer'
|
import { createTrackPlayerSlice, TrackPlayerSlice } from './trackplayer'
|
||||||
import { createTrackPlayerMapSlice, TrackPlayerMapSlice } from './trackplayermap'
|
import { createTrackPlayerMapSlice, TrackPlayerMapSlice } from './trackplayermap'
|
||||||
@@ -23,25 +24,13 @@ export type Store = SettingsSlice &
|
|||||||
setHydrated: (hydrated: boolean) => void
|
setHydrated: (hydrated: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const storage: StateStorage = {
|
export const useStore = create<
|
||||||
getItem: async name => {
|
Store,
|
||||||
try {
|
SetState<Store>,
|
||||||
return await AsyncStorage.getItem(name)
|
GetState<Store>,
|
||||||
} catch (err) {
|
Mutate<StoreApi<Store>, [['zustand/subscribeWithSelector', never], ['zustand/persist', Partial<Store>]]>
|
||||||
console.error(`getItem error (key: ${name})`, err)
|
>(
|
||||||
return null
|
subscribeWithSelector(
|
||||||
}
|
|
||||||
},
|
|
||||||
setItem: async (name, item) => {
|
|
||||||
try {
|
|
||||||
await AsyncStorage.setItem(name, item)
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`setItem error (key: ${name})`, err)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useStore = create<Store>(
|
|
||||||
persist(
|
persist(
|
||||||
(set, get) => ({
|
(set, get) => ({
|
||||||
...createSettingsSlice(set, get),
|
...createSettingsSlice(set, get),
|
||||||
@@ -58,8 +47,9 @@ export const useStore = create<Store>(
|
|||||||
{
|
{
|
||||||
name: '@appStore',
|
name: '@appStore',
|
||||||
version: DB_VERSION,
|
version: DB_VERSION,
|
||||||
getStorage: () => storage,
|
getStorage: () => AsyncStorage,
|
||||||
whitelist: ['settings', 'cacheFiles'],
|
// whitelist: ['settings', 'cacheFiles'],
|
||||||
|
partialize: state => ({ settings: state.settings, cacheFiles: state.cacheFiles }),
|
||||||
onRehydrateStorage: _preState => {
|
onRehydrateStorage: _preState => {
|
||||||
return async (postState, _error) => {
|
return async (postState, _error) => {
|
||||||
await postState?.setActiveServer(postState.settings.activeServer, true)
|
await postState?.setActiveServer(postState.settings.activeServer, true)
|
||||||
@@ -79,4 +69,7 @@ export const useStore = create<Store>(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const useStoreDeep = <U>(stateSelector: StateSelector<Store, U>) => useStore(stateSelector, equal)
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ export const selectTrackPlayerMap = {
|
|||||||
export const createTrackPlayerMapSlice = (set: SetState<Store>, get: GetState<Store>): TrackPlayerMapSlice => ({
|
export const createTrackPlayerMapSlice = (set: SetState<Store>, get: GetState<Store>): TrackPlayerMapSlice => ({
|
||||||
mapSongtoTrackExt: async song => {
|
mapSongtoTrackExt: async song => {
|
||||||
let artwork = require('@res/fallback.png')
|
let artwork = require('@res/fallback.png')
|
||||||
// if (song.coverArt) {
|
if (song.coverArt) {
|
||||||
// const filePath = await get().fetchCoverArtFilePath(song.coverArt)
|
const filePath = await get().fetchCoverArtFilePath(song.coverArt)
|
||||||
// if (filePath) {
|
if (filePath) {
|
||||||
// artwork = filePath
|
artwork = filePath
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
console.log('mapping', song.title)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: song.id,
|
id: song.id,
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"@react-navigation/native": "^5.9.4",
|
"@react-navigation/native": "^5.9.4",
|
||||||
"@types/react": "^17",
|
"@types/react": "^17",
|
||||||
"@xmldom/xmldom": "^0.7.0",
|
"@xmldom/xmldom": "^0.7.0",
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
"immer": "^9.0.6",
|
"immer": "^9.0.6",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"lodash.merge": "^4.6.2",
|
"lodash.merge": "^4.6.2",
|
||||||
@@ -50,7 +51,7 @@
|
|||||||
"react-native-vector-icons": "^8.1.0",
|
"react-native-vector-icons": "^8.1.0",
|
||||||
"react-native-webview": "^11.13.0",
|
"react-native-webview": "^11.13.0",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"zustand": "^3.5.7"
|
"zustand": "^3.7.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.12.9",
|
"@babel/core": "^7.12.9",
|
||||||
|
|||||||
@@ -7629,7 +7629,7 @@ yargs@^16.1.1:
|
|||||||
y18n "^5.0.5"
|
y18n "^5.0.5"
|
||||||
yargs-parser "^20.2.2"
|
yargs-parser "^20.2.2"
|
||||||
|
|
||||||
zustand@^3.5.7:
|
zustand@^3.7.1:
|
||||||
version "3.6.9"
|
version "3.7.1"
|
||||||
resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.6.9.tgz#f61a756ddea9f95c7ee7cfd3af2f88c10078afbc"
|
resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.7.1.tgz#7388f0a7175a6c2fd9a2880b383a4bf6cdf6b7c6"
|
||||||
integrity sha512-OvDNu/jEWpRnEC7k8xh8GKjqYog7td6FZrLMuHs/IeI8WhrCwV+FngVuwMIFhp5kysZXr6emaeReMqjLGaldAQ==
|
integrity sha512-wHBCZlKj+bg03/hP+Tzv24YhnqqP8MCeN9ECPDXoF01062SIbnfl3j9O0znkDw1lNTY0a8WN3F///a0UhhaEqg==
|
||||||
|
|||||||
Reference in New Issue
Block a user