React Query refactor (#91)

* initial react-query experiments

* use queries for item screens

send the data we do have over routing to prepopulate (album/playlist)
use number for starred because sending Date freaks out react-navigation

* add in equiv. song cover art fix

* reorg, switch artistview over

start mapping song cover art when any are available

* refactor useStar to queries

fix caching for starred items and album cover art

* add hook to reset queries on server change

* refactor search to use query

* fix song cover art setting

* use query for artistInfo

* remove last bits of library state

* cleanup

* use query key factory

already fixed one wrong key...

* require coverart size

* let's try no promise queues on these for now

* image cache uses query

* perf fix for playlist parsing

also use placeholder data so we don't have to deal with staleness

* drill that disabled

also list controls doesn't need its own songs hook/copy

* switch to react-native-blob-util for downloads

slightly slower but allows us to use DownloadManager, which backgrounds downloads so they are no longer corrupted when the app suspends

* add a fake "top songs" based on artist search

then sorted by play count/ratings
artistview should load now even if topSongs fails

* try not to swap between topSongs/search on refetch

set queueContext by song list so the index isn't off if the list changes

* add content type validation for file fetching

also try to speed up existing file return by limiting fs ops

* if the HEAD fails, don't queue the download

* clean up params

* reimpl clear image cache

* precompute contextId

prevents wrong "is playing" when any mismatch between queue and list

* clear images from all servers

use external files dir instead of cache

* fix pressable disabled flicker

don't retry topsongs on failure
try to optimize setqueue and fixcoverart a bit

* wait for queries during clear

* break out fetchExistingFile from fetchFile

allows to tell if file is coming from disk or not
only show placeholder/loading spinner if actually fetching image

* forgot these wouldn't do anything with objects

* remove query cache when switching servers

* add content-disposition extension gathering

add support for progress hook (needs native support still)

* added custom RNBU pkg with progress changes

* fully unmount tabs when server changes

prevents unwanted requests, gives fresh start on switch
fix fixCoverArt not re-rendering in certain cases on search

* use serverId from fetch deps

* fix lint

* update licenses

* just use the whole lodash package

* make using cache buster optional
This commit is contained in:
austinried
2022-04-11 09:40:51 +09:00
committed by GitHub
parent ccc7f44957
commit 335f30b0d2
48 changed files with 2205 additions and 1800 deletions
+24 -52
View File
@@ -2,21 +2,22 @@ import { AlbumContextPressable } from '@app/components/ContextMenu'
import CoverArt from '@app/components/CoverArt'
import FilterButton, { OptionData } from '@app/components/FilterButton'
import GradientFlatList from '@app/components/GradientFlatList'
import { useFetchPaginatedList } from '@app/hooks/list'
import { useQueryAlbumList } from '@app/hooks/query'
import { Album } from '@app/models/library'
import { useStore, useStoreDeep } from '@app/state/store'
import colors from '@app/styles/colors'
import font from '@app/styles/font'
import { GetAlbumList2Params, GetAlbumList2Type } from '@app/subsonic/params'
import { GetAlbumList2Type, GetAlbumList2TypeBase } from '@app/subsonic/params'
import { useNavigation } from '@react-navigation/native'
import React, { useCallback } from 'react'
import equal from 'fast-deep-equal/es6/react'
import React from 'react'
import { StyleSheet, Text, useWindowDimensions, View } from 'react-native'
const AlbumItem = React.memo<{
id: string
album: Album
size: number
height: number
}>(({ id, size, height }) => {
const album = useStoreDeep(useCallback(store => store.library.albums[id], [id]))
}>(({ album, size, height }) => {
const navigation = useNavigation()
if (!album) {
@@ -28,8 +29,14 @@ const AlbumItem = React.memo<{
album={album}
menuStyle={[styles.itemMenu, { width: size }]}
triggerWrapperStyle={[styles.itemWrapper, { height }]}
onPress={() => navigation.navigate('album', { id: album.id, title: album.name })}>
<CoverArt type="cover" coverArt={album.coverArt} style={{ height: size, width: size }} resizeMode={'cover'} />
onPress={() => navigation.navigate('album', { id: album.id, title: album.name, album })}>
<CoverArt
type="cover"
coverArt={album.coverArt}
style={{ height: size, width: size }}
resizeMode="cover"
size="thumbnail"
/>
<View style={styles.itemDetails}>
<Text style={styles.title} numberOfLines={1}>
{album.name}
@@ -40,11 +47,11 @@ const AlbumItem = React.memo<{
</View>
</AlbumContextPressable>
)
})
}, equal)
const AlbumListRenderItem: React.FC<{
item: { id: string; size: number; height: number }
}> = ({ item }) => <AlbumItem id={item.id} size={item.size} height={item.height} />
item: { album: Album; size: number; height: number }
}> = ({ item }) => <AlbumItem album={item.album} size={item.size} height={item.height} />
const filterOptions: OptionData[] = [
{ text: 'By Name', value: 'alphabeticalByName' },
@@ -62,42 +69,7 @@ const AlbumsList = () => {
const filter = useStoreDeep(store => store.settings.screens.library.albumsFilter)
const setFilter = useStore(store => store.setLibraryAlbumFilter)
const fetchAlbumList = useStore(store => store.fetchAlbumList)
const fetchPage = useCallback(
(size: number, offset: number) => {
let params: GetAlbumList2Params
switch (filter.type) {
case 'byYear':
params = {
size,
offset,
type: filter.type,
fromYear: filter.fromYear,
toYear: filter.toYear,
}
break
case 'byGenre':
params = {
size,
offset,
type: filter.type,
genre: filter.genre,
}
break
default:
params = {
size,
offset,
type: filter.type,
}
break
}
return fetchAlbumList(params)
},
[fetchAlbumList, filter.fromYear, filter.genre, filter.toYear, filter.type],
)
const { list, refreshing, refresh, fetchNextPage } = useFetchPaginatedList(fetchPage, 300)
const { isLoading, data, fetchNextPage, refetch } = useQueryAlbumList(filter.type as GetAlbumList2TypeBase, 300)
const layout = useWindowDimensions()
@@ -107,15 +79,15 @@ const AlbumsList = () => {
return (
<View style={styles.container}>
<GradientFlatList
data={list.map(id => ({ id, size, height }))}
data={data ? data.pages.flatMap(albums => albums.map(album => ({ album, size, height }))) : []}
renderItem={AlbumListRenderItem}
keyExtractor={item => item.id}
keyExtractor={item => item.album.id}
numColumns={3}
removeClippedSubviews={true}
refreshing={refreshing}
onRefresh={refresh}
refreshing={isLoading}
onRefresh={refetch}
overScrollMode="never"
onEndReached={fetchNextPage}
onEndReached={() => fetchNextPage()}
onEndReachedThreshold={6}
windowSize={5}
/>