remove unused + (slightly) rework search

This commit is contained in:
austinried
2022-03-19 12:20:45 +09:00
parent 71330e2925
commit 1803e9dc7c
5 changed files with 93 additions and 193 deletions

View File

@@ -21,12 +21,6 @@ export interface Album extends AlbumListItem {
year?: number year?: number
} }
export interface SearchResults {
artists: Artist[]
albums: AlbumListItem[]
songs: Song[]
}
export interface PlaylistListItem { export interface PlaylistListItem {
itemType: 'playlist' itemType: 'playlist'
id: string id: string

View File

@@ -5,9 +5,8 @@ import ListItem from '@app/components/ListItem'
import NothingHere from '@app/components/NothingHere' import NothingHere from '@app/components/NothingHere'
import TextInput from '@app/components/TextInput' import TextInput from '@app/components/TextInput'
import { useActiveServerRefresh } from '@app/hooks/server' import { useActiveServerRefresh } from '@app/hooks/server'
import { ListableItem, SearchResults, Song } from '@app/models/music' import { Album, Artist, mapById, SearchResults, Song } from '@app/state/library'
import { selectMusic } from '@app/state/music' import { useStore, useStoreDeep } from '@app/state/store'
import { useStore } 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'
@@ -42,8 +41,27 @@ const SongItem = React.memo<{ item: Song }>(({ item }) => {
const ResultsCategory = React.memo<{ const ResultsCategory = React.memo<{
name: string name: string
query: string query: string
items: ListableItem[] ids: string[]
}>(({ name, query, items }) => { type: 'artist' | 'album' | 'song'
}>(({ name, query, type, ids }) => {
const items: (Album | Artist | Song)[] = useStoreDeep(
useCallback(
store => {
switch (type) {
case 'album':
return mapById(store.entities.albums, ids)
case 'artist':
return mapById(store.entities.artists, ids)
case 'song':
return mapById(store.entities.songs, ids)
default:
return []
}
},
[ids, type],
),
)
const navigation = useNavigation() const navigation = useNavigation()
if (items.length === 0) { if (items.length === 0) {
@@ -54,8 +72,8 @@ const ResultsCategory = React.memo<{
<> <>
<Header>{name}</Header> <Header>{name}</Header>
{items.map(a => {items.map(a =>
a.itemType === 'song' ? ( type === 'song' ? (
<SongItem key={a.id} item={a} /> <SongItem key={a.id} item={a as Song} />
) : ( ) : (
<ListItem key={a.id} item={a} showArt={true} showStar={false} /> <ListItem key={a.id} item={a} showArt={true} showStar={false} />
), ),
@@ -78,15 +96,15 @@ const Results = React.memo<{
}>(({ results, query }) => { }>(({ results, query }) => {
return ( return (
<> <>
<ResultsCategory name="Artists" query={query} items={results.artists} /> <ResultsCategory name="Artists" query={query} type={'artist'} ids={results.artists} />
<ResultsCategory name="Albums" query={query} items={results.albums} /> <ResultsCategory name="Albums" query={query} type={'album'} ids={results.albums} />
<ResultsCategory name="Songs" query={query} items={results.songs} /> <ResultsCategory name="Songs" query={query} type={'song'} ids={results.songs} />
</> </>
) )
}) })
const Search = () => { const Search = () => {
const fetchSearchResults = useStore(selectMusic.fetchSearchResults) const fetchSearchResults = useStore(store => store.fetchLibrarySearchResults)
const [results, setResults] = useState<SearchResults>({ artists: [], albums: [], songs: [] }) const [results, setResults] = useState<SearchResults>({ artists: [], albums: [], songs: [] })
const [refreshing, setRefreshing] = useState(false) const [refreshing, setRefreshing] = useState(false)
const [text, setText] = useState('') const [text, setText] = useState('')
@@ -118,7 +136,7 @@ const Search = () => {
() => () =>
debounce(async (query: string) => { debounce(async (query: string) => {
setRefreshing(true) setRefreshing(true)
setResults(await fetchSearchResults(query)) setResults(await fetchSearchResults({ query, albumCount: 5, artistCount: 5, songCount: 5 }))
setRefreshing(false) setRefreshing(false)
}, 400), }, 400),
[fetchSearchResults], [fetchSearchResults],

View File

@@ -1,15 +1,15 @@
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 { useFetchPaginatedList } from '@app/hooks/list' import { useFetchPaginatedList } from '@app/hooks/list'
import { AlbumListItem, Artist, Song } from '@app/models/music' import { Album, Artist, Song, mapById } from '@app/state/library'
import { selectMusic } from '@app/state/music' import { useStore, useStoreDeep } from '@app/state/store'
import { useStore } from '@app/state/store'
import { selectTrackPlayer } from '@app/state/trackplayer' import { selectTrackPlayer } from '@app/state/trackplayer'
import { Search3Params } from '@app/subsonic/params'
import { useNavigation } from '@react-navigation/native' import { useNavigation } from '@react-navigation/native'
import React, { useCallback, useEffect } from 'react' import React, { useCallback, useEffect } from 'react'
import { StyleSheet } from 'react-native' import { StyleSheet } from 'react-native'
type SearchListItemType = AlbumListItem | Song | Artist type SearchListItemType = Album | Song | Artist
const ResultsListItem: React.FC<{ item: SearchListItemType }> = ({ item }) => { const ResultsListItem: React.FC<{ item: SearchListItemType }> = ({ item }) => {
const setQueue = useStore(selectTrackPlayer.setQueue) const setQueue = useStore(selectTrackPlayer.setQueue)
@@ -40,27 +40,62 @@ const SearchResultsView: React.FC<{
type: 'album' | 'artist' | 'song' type: 'album' | 'artist' | 'song'
}> = ({ query, type }) => { }> = ({ query, type }) => {
const navigation = useNavigation() const navigation = useNavigation()
const fetchSearchResults = useStore(selectMusic.fetchSearchResults) const fetchSearchResults = useStore(store => store.fetchLibrarySearchResults)
const { list, refreshing, refresh, fetchNextPage } = useFetchPaginatedList<SearchListItemType>( const { list, refreshing, refresh, fetchNextPage } = useFetchPaginatedList(
useCallback( useCallback(
(size, offset) => async (size, offset) => {
fetchSearchResults(query, type, size, offset).then(results => { const params: Search3Params = { query }
switch (type) { if (type === 'album') {
case 'album': params.albumCount = size
return results.albums params.albumOffset = offset
case 'artist': } else if (type === 'artist') {
return results.artists params.artistCount = size
case 'song': params.artistOffset = offset
return results.songs } else if (type === 'song') {
default: params.songCount = size
return [] params.songOffset = offset
} } else {
}), params.albumCount = 5
params.artistCount = 5
params.songCount = 5
}
const results = await fetchSearchResults(params)
switch (type) {
case 'album':
return results.albums
case 'artist':
return results.artists
case 'song':
return results.songs
default:
return []
}
},
[fetchSearchResults, query, type], [fetchSearchResults, query, type],
), ),
100, 100,
) )
const items: SearchListItemType[] = useStoreDeep(
useCallback(
store => {
switch (type) {
case 'album':
return mapById(store.entities.albums, list)
case 'artist':
return mapById(store.entities.artists, list)
case 'song':
return mapById(store.entities.songs, list)
default:
return []
}
},
[list, type],
),
)
useEffect(() => { useEffect(() => {
navigation.setOptions({ navigation.setOptions({
title: `Search: "${query}"`, title: `Search: "${query}"`,
@@ -70,7 +105,7 @@ const SearchResultsView: React.FC<{
return ( return (
<GradientFlatList <GradientFlatList
data={list} data={items}
renderItem={SearchResultsRenderItem} renderItem={SearchResultsRenderItem}
keyExtractor={(item, i) => i.toString()} keyExtractor={(item, i) => i.toString()}
onRefresh={refresh} onRefresh={refresh}

View File

@@ -1,23 +1,10 @@
import { AlbumListItem, Artist, PlaylistListItem, SearchResults, StarrableItemType } from '@app/models/music' import { StarrableItemType } from '@app/models/music'
import { Store } from '@app/state/store' import { Store } from '@app/state/store'
import { GetAlbumList2Params, Search3Params, StarParams } from '@app/subsonic/params' import { StarParams } from '@app/subsonic/params'
import produce from 'immer' import produce from 'immer'
import { GetState, SetState } from 'zustand' import { GetState, SetState } from 'zustand'
export type MusicSlice = { export type MusicSlice = {
//
// lists-style state
//
fetchArtists: (size?: number, offset?: number) => Promise<Artist[]>
fetchPlaylists: () => Promise<PlaylistListItem[]>
fetchAlbums: () => Promise<AlbumListItem[]>
fetchSearchResults: (
query: string,
type?: 'album' | 'song' | 'artist',
size?: number,
offset?: number,
) => Promise<SearchResults>
// //
// actions, etc. // actions, etc.
// //
@@ -33,11 +20,6 @@ export type MusicSlice = {
} }
export const selectMusic = { export const selectMusic = {
fetchArtists: (store: MusicSlice) => store.fetchArtists,
fetchPlaylists: (store: MusicSlice) => store.fetchPlaylists,
fetchAlbums: (store: MusicSlice) => store.fetchAlbums,
fetchSearchResults: (store: MusicSlice) => store.fetchSearchResults,
starItem: (store: MusicSlice) => store.starItem, starItem: (store: MusicSlice) => store.starItem,
} }
@@ -55,141 +37,6 @@ function reduceStarred(
} }
export const createMusicSlice = (set: SetState<Store>, get: GetState<Store>): MusicSlice => ({ export const createMusicSlice = (set: SetState<Store>, get: GetState<Store>): MusicSlice => ({
fetchArtists: async () => {
const client = get().client
if (!client) {
return []
}
try {
const response = await client.getArtists()
const artists = response.data.artists.map(get().mapArtistID3toArtist)
set(
produce<MusicSlice>(state => {
state.starredArtists = reduceStarred(state.starredArtists, artists)
}),
)
return artists
} catch {
return []
}
},
fetchPlaylists: async () => {
const client = get().client
if (!client) {
return []
}
try {
const response = await client.getPlaylists()
return response.data.playlists.map(get().mapPlaylistListItem)
} catch {
return []
}
},
fetchAlbums: async (size = 500, offset = 0) => {
const client = get().client
if (!client) {
return []
}
try {
const filter = get().settings.screens.library.albums
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
}
const response = await client.getAlbumList2(params)
const albums = response.data.albums.map(get().mapAlbumID3toAlbumListItem)
set(
produce<MusicSlice>(state => {
state.starredAlbums = reduceStarred(state.starredAlbums, albums)
}),
)
return albums
} catch {
return []
}
},
fetchSearchResults: async (query, type, size, offset) => {
if (query.length < 2) {
return { artists: [], albums: [], songs: [] }
}
const client = get().client
if (!client) {
return { artists: [], albums: [], songs: [] }
}
try {
const params: Search3Params = { query }
if (type === 'album') {
params.albumCount = size
params.albumOffset = offset
} else if (type === 'artist') {
params.artistCount = size
params.artistOffset = offset
} else if (type === 'song') {
params.songCount = size
params.songOffset = offset
} else {
params.albumCount = 5
params.artistCount = 5
params.songCount = 5
}
const response = await client.search3(params)
const artists = response.data.artists.map(get().mapArtistID3toArtist)
const albums = response.data.albums.map(get().mapAlbumID3toAlbumListItem)
const songs = await get().mapChildrenToSongs(response.data.songs)
set(
produce<MusicSlice>(state => {
state.starredSongs = reduceStarred(state.starredSongs, songs)
state.starredArtists = reduceStarred(state.starredArtists, artists)
state.starredAlbums = reduceStarred(state.starredAlbums, albums)
}),
)
return { artists, albums, songs }
} catch {
return { artists: [], albums: [], songs: [] }
}
},
starredSongs: {}, starredSongs: {},
starredAlbums: {}, starredAlbums: {},
starredArtists: {}, starredArtists: {},

View File

@@ -6,6 +6,12 @@ enableScreens()
import { LogBox } from 'react-native' import { LogBox } from 'react-native'
LogBox.ignoreLogs(["The action 'POP_TO_TOP'"]) LogBox.ignoreLogs(["The action 'POP_TO_TOP'"])
LogBox.ignoreLogs([
'`new NativeEventEmitter()` was called with a non-null argument without the required `addListener` method.',
])
LogBox.ignoreLogs([
'`new NativeEventEmitter()` was called with a non-null argument without the required `removeListeners` method.',
])
import { AppRegistry } from 'react-native' import { AppRegistry } from 'react-native'
import App from '@app/App' import App from '@app/App'