mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 07:29:14 +01:00
Library store refactor (#76)
* start of music store refactor moving stuff into a state cache better separate it from view logic * added paginated list/album list * reworked fetchAlbumList to remove ui state refactored home screen to use new method i broke playing songs somehow, JS thread goes into a loop * don't reset parts manually, do it all at once * 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 * update typescript and use workspace tsc version for vscode * remove old artistInfo * switched to new playlist w/songs removed more unused stuff * remove unused + (slightly) rework search * refactor star * use only original/large imges for covers/artist fix view artist from context menu add loading indicators to song list and artist views (show info we have right away) * set starred/unstar assuming it works and correct state on error * reorg, remove old music slice files * added back fix for song cover art * sort artists by localCompare name * update licenses * fix now playing background grey bar * update react-native-gesture-handler for node-fetch security alert * fix another gradient height grey bar issue * update licenses again * remove thumbnail cache * rename to remove "Library" from methods * Revert "remove thumbnail cache" This reverts commite0db4931f1. * use ids for lists, pull state later * Revert "use only original/large imges for covers/artist" This reverts commitc9aea9065c. * deep equal ListItem props for now this needs a bigger refactor * use immer as middleware * refactor api client to use string method hoping to use this for requestKey/deduping next * use thumbnails in list items * Revert "refactor api client to use string method" This reverts commit234326135b. * rename/cleanup * store servers by id * get rid of settings selectors * renames for clarity remove unused estimateContentLength setting * remove trackplayer selectors * fix migration for library filter settings * fixed shuffle order reporting wrong track/queue * removed the other selectors * don't actually need es6/react for our state * fix slow artist sort on star localeCompare is too slow for large lists
This commit is contained in:
+66
-27
@@ -3,17 +3,17 @@ import CoverArt from '@app/components/CoverArt'
|
||||
import GradientScrollView from '@app/components/GradientScrollView'
|
||||
import Header from '@app/components/Header'
|
||||
import NothingHere from '@app/components/NothingHere'
|
||||
import { useActiveServerRefresh } from '@app/hooks/server'
|
||||
import { AlbumListItem } from '@app/models/music'
|
||||
import { selectMusic } from '@app/state/music'
|
||||
import { selectSettings } from '@app/state/settings'
|
||||
import { useStore } from '@app/state/store'
|
||||
import { useActiveServerRefresh } from '@app/hooks/settings'
|
||||
import { useStore, useStoreDeep } from '@app/state/store'
|
||||
import colors from '@app/styles/colors'
|
||||
import font from '@app/styles/font'
|
||||
import { GetAlbumListType } from '@app/subsonic/params'
|
||||
import { GetAlbumList2TypeBase, GetAlbumListType } from '@app/subsonic/params'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import React, { useCallback } from 'react'
|
||||
import equal from 'fast-deep-equal/es6/react'
|
||||
import produce from 'immer'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { RefreshControl, ScrollView, StatusBar, StyleSheet, Text, View } from 'react-native'
|
||||
import create, { StateSelector } from 'zustand'
|
||||
|
||||
const titles: { [key in GetAlbumListType]?: string } = {
|
||||
recent: 'Recently Played',
|
||||
@@ -23,9 +23,14 @@ const titles: { [key in GetAlbumListType]?: string } = {
|
||||
}
|
||||
|
||||
const AlbumItem = React.memo<{
|
||||
album: AlbumListItem
|
||||
}>(({ album }) => {
|
||||
id: string
|
||||
}>(({ id }) => {
|
||||
const navigation = useNavigation()
|
||||
const album = useStoreDeep(useCallback(store => store.library.albums[id], [id]))
|
||||
|
||||
if (!album) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
return (
|
||||
<AlbumContextPressable
|
||||
@@ -49,9 +54,10 @@ const AlbumItem = React.memo<{
|
||||
})
|
||||
|
||||
const Category = React.memo<{
|
||||
name?: string
|
||||
data: AlbumListItem[]
|
||||
}>(({ name, data }) => {
|
||||
type: string
|
||||
}>(({ type }) => {
|
||||
const list = useHomeStoreDeep(useCallback(store => store.lists[type] || [], [type]))
|
||||
|
||||
const Albums = () => (
|
||||
<ScrollView
|
||||
horizontal={true}
|
||||
@@ -59,8 +65,8 @@ const Category = React.memo<{
|
||||
overScrollMode={'never'}
|
||||
style={styles.artScroll}
|
||||
contentContainerStyle={styles.artScrollContent}>
|
||||
{data.map(album => (
|
||||
<AlbumItem key={album.id} album={album} />
|
||||
{list.map(id => (
|
||||
<AlbumItem key={id} id={id} />
|
||||
))}
|
||||
</ScrollView>
|
||||
)
|
||||
@@ -73,24 +79,57 @@ const Category = React.memo<{
|
||||
|
||||
return (
|
||||
<View style={styles.category}>
|
||||
<Header style={styles.header}>{name}</Header>
|
||||
{data.length > 0 ? <Albums /> : <Nothing />}
|
||||
<Header style={styles.header}>{titles[type as GetAlbumListType] || ''}</Header>
|
||||
{list.length > 0 ? <Albums /> : <Nothing />}
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
interface HomeState {
|
||||
lists: { [type: string]: string[] }
|
||||
setList: (type: string, list: string[]) => void
|
||||
}
|
||||
|
||||
const useHomeStore = create<HomeState>(set => ({
|
||||
lists: {},
|
||||
|
||||
setList: (type, list) => {
|
||||
set(
|
||||
produce<HomeState>(state => {
|
||||
state.lists[type] = list
|
||||
}),
|
||||
)
|
||||
},
|
||||
}))
|
||||
|
||||
function useHomeStoreDeep<U>(stateSelector: StateSelector<HomeState, U>) {
|
||||
return useHomeStore(stateSelector, equal)
|
||||
}
|
||||
|
||||
const Home = () => {
|
||||
const types = useStore(selectSettings.homeLists)
|
||||
const lists = useStore(selectMusic.homeLists)
|
||||
const updating = useStore(selectMusic.homeListsUpdating)
|
||||
const update = useStore(selectMusic.fetchHomeLists)
|
||||
const clear = useStore(selectMusic.clearHomeLists)
|
||||
const [refreshing, setRefreshing] = useState(false)
|
||||
const types = useStoreDeep(store => store.settings.screens.home.listTypes)
|
||||
const fetchAlbumList = useStore(store => store.fetchAlbumList)
|
||||
const setList = useHomeStore(store => store.setList)
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
setRefreshing(true)
|
||||
|
||||
await Promise.all(
|
||||
types.map(async type => {
|
||||
const ids = await fetchAlbumList({ type: type as GetAlbumList2TypeBase, size: 20, offset: 0 })
|
||||
setList(type, ids)
|
||||
}),
|
||||
)
|
||||
|
||||
setRefreshing(false)
|
||||
}, [fetchAlbumList, setList, types])
|
||||
|
||||
useActiveServerRefresh(
|
||||
useCallback(() => {
|
||||
clear()
|
||||
update()
|
||||
}, [clear, update]),
|
||||
types.forEach(type => setList(type, []))
|
||||
refresh()
|
||||
}, [refresh, setList, types]),
|
||||
)
|
||||
|
||||
return (
|
||||
@@ -99,15 +138,15 @@ const Home = () => {
|
||||
contentContainerStyle={styles.scrollContentContainer}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={updating}
|
||||
onRefresh={update}
|
||||
refreshing={refreshing}
|
||||
onRefresh={refresh}
|
||||
colors={[colors.accent, colors.accentLow]}
|
||||
progressViewOffset={StatusBar.currentHeight}
|
||||
/>
|
||||
}>
|
||||
<View style={styles.content}>
|
||||
{types.map(type => (
|
||||
<Category key={type} name={titles[type as GetAlbumListType]} data={type in lists ? lists[type] : []} />
|
||||
<Category key={type} type={type} />
|
||||
))}
|
||||
</View>
|
||||
</GradientScrollView>
|
||||
|
||||
Reference in New Issue
Block a user