mirror of
https://github.com/austinried/subtracks.git
synced 2026-02-10 23:02:43 +01:00
serach debouncing, hiding result categories
This commit is contained in:
@@ -1,47 +1,92 @@
|
||||
import GradientScrollView from '@app/components/GradientScrollView'
|
||||
import Header from '@app/components/Header'
|
||||
import ListItem from '@app/components/ListItem'
|
||||
import { searchResultsAtom, useUpdateSearchResults } from '@app/state/music'
|
||||
import NothingHere from '@app/components/NothingHere'
|
||||
import { ListableItem, SearchResults } from '@app/models/music'
|
||||
import { searchResultsAtom, searchResultsUpdatingAtom, useUpdateSearchResults } from '@app/state/music'
|
||||
import colors from '@app/styles/colors'
|
||||
import font from '@app/styles/font'
|
||||
import { useAtomValue } from 'jotai/utils'
|
||||
import React, { useState } from 'react'
|
||||
import { StatusBar, StyleSheet, View, TextInput } from 'react-native'
|
||||
import debounce from 'lodash.debounce'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { ActivityIndicator, StatusBar, StyleSheet, TextInput, View } from 'react-native'
|
||||
|
||||
function getSubtitle(item: ListableItem) {
|
||||
switch (item.itemType) {
|
||||
case 'playlist':
|
||||
return item.comment
|
||||
case 'album':
|
||||
case 'song':
|
||||
return item.artist
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
const ResultsCategory = React.memo<{
|
||||
name: string
|
||||
items: ListableItem[]
|
||||
}>(({ name, items }) => {
|
||||
if (items.length === 0) {
|
||||
return <></>
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header>{name}</Header>
|
||||
{items.map(a => (
|
||||
<ListItem key={a.id} item={a} showArt={true} showStar={false} subtitle={getSubtitle(a)} />
|
||||
))}
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
const Results = React.memo<{
|
||||
results: SearchResults
|
||||
}>(({ results }) => {
|
||||
return (
|
||||
<>
|
||||
<ResultsCategory name="Artists" items={results.artists} />
|
||||
<ResultsCategory name="Albums" items={results.albums} />
|
||||
<ResultsCategory name="Songs" items={results.songs} />
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
const Search = () => {
|
||||
const [text, setText] = useState('')
|
||||
const updateSearch = useUpdateSearchResults()
|
||||
const updating = useAtomValue(searchResultsUpdatingAtom)
|
||||
const results = useAtomValue(searchResultsAtom)
|
||||
|
||||
const onSubmitEditing = () => {
|
||||
console.log(text)
|
||||
updateSearch(text)
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const debouncedonUpdateSearch = useMemo(() => debounce(updateSearch, 400), [])
|
||||
|
||||
const onChangeText = useCallback(
|
||||
(value: string) => {
|
||||
setText(value)
|
||||
debouncedonUpdateSearch(value)
|
||||
},
|
||||
[setText, debouncedonUpdateSearch],
|
||||
)
|
||||
|
||||
const resultsCount = results.albums.length + results.artists.length + results.songs.length
|
||||
|
||||
return (
|
||||
<GradientScrollView style={styles.scroll} contentContainerStyle={styles.scrollContentContainer}>
|
||||
<View style={styles.content}>
|
||||
<TextInput
|
||||
style={styles.textInput}
|
||||
placeholder="Search"
|
||||
placeholderTextColor="grey"
|
||||
selectionColor={colors.text.secondary}
|
||||
value={text}
|
||||
onChangeText={setText}
|
||||
onSubmitEditing={onSubmitEditing}
|
||||
/>
|
||||
<Header>Artists</Header>
|
||||
{results.artists.map(a => (
|
||||
<ListItem key={a.id} item={a} showArt={true} showStar={false} />
|
||||
))}
|
||||
<Header>Albums</Header>
|
||||
{results.albums.map(a => (
|
||||
<ListItem key={a.id} item={a} showArt={true} showStar={false} subtitle={a.artist} />
|
||||
))}
|
||||
<Header>Songs</Header>
|
||||
{results.songs.map(a => (
|
||||
<ListItem key={a.id} item={a} showArt={true} showStar={false} subtitle={a.artist} />
|
||||
))}
|
||||
<View style={styles.inputBar}>
|
||||
<TextInput
|
||||
style={styles.textInput}
|
||||
placeholder="Search"
|
||||
placeholderTextColor="grey"
|
||||
selectionColor={colors.text.secondary}
|
||||
value={text}
|
||||
onChangeText={onChangeText}
|
||||
/>
|
||||
<ActivityIndicator animating={updating} size="small" color={colors.text.secondary} style={styles.activity} />
|
||||
</View>
|
||||
{resultsCount > 0 ? <Results results={results} /> : <NothingHere style={styles.noResults} />}
|
||||
</View>
|
||||
</GradientScrollView>
|
||||
)
|
||||
@@ -56,14 +101,28 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
content: {
|
||||
paddingHorizontal: 20,
|
||||
alignItems: 'stretch',
|
||||
},
|
||||
inputBar: {
|
||||
justifyContent: 'center',
|
||||
},
|
||||
activity: {
|
||||
position: 'absolute',
|
||||
right: 16,
|
||||
bottom: 15,
|
||||
},
|
||||
textInput: {
|
||||
width: '100%',
|
||||
backgroundColor: '#515151',
|
||||
fontFamily: font.regular,
|
||||
fontSize: 18,
|
||||
color: colors.text.primary,
|
||||
marginTop: 20,
|
||||
paddingHorizontal: 12,
|
||||
paddingRight: 46,
|
||||
},
|
||||
noResults: {
|
||||
width: '100%',
|
||||
},
|
||||
itemText: {
|
||||
color: colors.text.primary,
|
||||
|
||||
Reference in New Issue
Block a user