added nothing here message for empty lists

This commit is contained in:
austinried 2021-07-19 22:23:33 +09:00
parent 9d835f04aa
commit a1b6aa6732
6 changed files with 113 additions and 46 deletions

View File

@ -0,0 +1,33 @@
import font from '@app/styles/font'
import React from 'react'
import { Text, View, StyleSheet } from 'react-native'
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
const NothingHere = React.memo<{
height?: number
width?: number
}>(({ height, width }) => {
height = height || 200
width = width || 200
return (
<View style={[styles.container, { height, width }]}>
<Icon name="music-note-outline" color={styles.text.color} size={width / 2} />
<Text style={[styles.text, { fontSize: width / 8 }]}>Nothing here...</Text>
</View>
)
})
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
opacity: 0.25,
},
text: {
fontFamily: font.lightItalic,
color: 'white',
},
})
export default NothingHere

View File

@ -6,7 +6,6 @@ import { useAtomValue } from 'jotai/utils'
import React from 'react'
import { GestureResponderEvent, StyleSheet, Text, View } from 'react-native'
import IconFA from 'react-native-vector-icons/FontAwesome'
import IconMat from 'react-native-vector-icons/MaterialIcons'
import CoverArt from './CoverArt'
import PressableOpacity from './PressableOpacity'
@ -33,10 +32,7 @@ const SongItem: React.FC<{
</PressableOpacity>
<View style={styles.controls}>
<PressableOpacity onPress={undefined}>
<IconFA name="star-o" size={26} color={colors.text.primary} />
</PressableOpacity>
<PressableOpacity onPress={undefined} style={styles.more}>
<IconMat name="more-vert" size={32} color="white" />
<IconFA name="star-o" size={26} color={colors.text.secondary} />
</PressableOpacity>
</View>
</View>
@ -76,7 +72,7 @@ const styles = StyleSheet.create({
controls: {
flexDirection: 'row',
alignItems: 'center',
marginLeft: 10,
marginLeft: 16,
},
more: {
marginLeft: 8,

View File

@ -2,6 +2,7 @@ import Button from '@app/components/Button'
import CoverArt from '@app/components/CoverArt'
import GradientBackground from '@app/components/GradientBackground'
import ImageGradientScrollView from '@app/components/ImageGradientScrollView'
import NothingHere from '@app/components/NothingHere'
import SongItem from '@app/components/SongItem'
import { albumAtomFamily } from '@app/state/music'
import { useSetQueue } from '@app/state/trackplayer'
@ -22,6 +23,27 @@ const AlbumDetails: React.FC<{
return <></>
}
const Songs = () => (
<>
<View style={styles.controls}>
<Button title="Play Album" onPress={() => setQueue(album.songs, album.name, album.songs[0].id)} />
</View>
<View style={styles.songs}>
{album.songs
.sort((a, b) => {
if (b.track && a.track) {
return a.track - b.track
} else {
return a.title.localeCompare(b.title)
}
})
.map(s => (
<SongItem key={s.id} song={s} onPress={() => setQueue(album.songs, album.name, s.id)} />
))}
</View>
</>
)
return (
<ImageGradientScrollView
imageUri={album.coverArtThumbUri}
@ -34,22 +56,7 @@ const AlbumDetails: React.FC<{
{album.artist}
{album.year ? `${album.year}` : ''}
</Text>
<View style={styles.controls}>
<Button title="Play Album" onPress={() => setQueue(album.songs, album.name, album.songs[0].id)} />
</View>
<View style={styles.songs}>
{album.songs
.sort((a, b) => {
if (b.track && a.track) {
return a.track - b.track
} else {
return a.title.localeCompare(b.title)
}
})
.map(s => (
<SongItem key={s.id} song={s} onPress={() => setQueue(album.songs, album.name, s.id)} />
))}
</View>
{album.songs.length > 0 ? <Songs /> : <NothingHere height={300} width={250} />}
</View>
</ImageGradientScrollView>
)

View File

@ -1,5 +1,6 @@
import CoverArt from '@app/components/CoverArt'
import GradientScrollView from '@app/components/GradientScrollView'
import NothingHere from '@app/components/NothingHere'
import PressableOpacity from '@app/components/PressableOpacity'
import { AlbumListItem } from '@app/models/music'
import { homeListsAtom, homeListsUpdatingAtom, useUpdateHomeLists } from '@app/state/music'
@ -44,19 +45,29 @@ const Category = React.memo<{
name?: string
data: AlbumListItem[]
}>(({ name, data }) => {
const Albums = () => (
<ScrollView
horizontal={true}
showsHorizontalScrollIndicator={false}
overScrollMode={'never'}
style={styles.artScroll}
contentContainerStyle={styles.artScrollContent}>
{data.map(album => (
<AlbumItem key={album.id} album={album} />
))}
</ScrollView>
)
const Nothing = () => (
<View style={styles.nothingHereContent}>
<NothingHere height={styles.nothingHereContent.height} />
</View>
)
return (
<View style={styles.category}>
<Text style={styles.categoryHeader}>{name}</Text>
<ScrollView
horizontal={true}
showsHorizontalScrollIndicator={false}
overScrollMode={'never'}
style={styles.artScroll}
contentContainerStyle={styles.artScrollContent}>
{data.map(album => (
<AlbumItem key={album.id} album={album} />
))}
</ScrollView>
{data.length > 0 ? <Albums /> : <Nothing />}
</View>
)
})
@ -110,6 +121,12 @@ const styles = StyleSheet.create({
paddingHorizontal: 20,
marginTop: 4,
},
nothingHereContent: {
width: '100%',
height: 190,
justifyContent: 'center',
alignItems: 'center',
},
artScroll: {
marginTop: 10,
height: 190,

View File

@ -2,6 +2,7 @@ import Button from '@app/components/Button'
import CoverArt from '@app/components/CoverArt'
import GradientBackground from '@app/components/GradientBackground'
import ImageGradientScrollView from '@app/components/ImageGradientScrollView'
import NothingHere from '@app/components/NothingHere'
import SongItem from '@app/components/SongItem'
import { playlistAtomFamily } from '@app/state/music'
import { useSetQueue } from '@app/state/trackplayer'
@ -22,6 +23,19 @@ const PlaylistDetails: React.FC<{
return <></>
}
const Songs = () => (
<>
<View style={styles.controls}>
<Button title="Play Playlist" onPress={() => setQueue(playlist.songs, playlist.name, playlist.songs[0].id)} />
</View>
<View style={styles.songs}>
{playlist.songs.map((s, index) => (
<SongItem key={index} song={s} showArt={true} onPress={() => setQueue(playlist.songs, playlist.name, s.id)} />
))}
</View>
</>
)
return (
<ImageGradientScrollView
imageUri={playlist.coverArtThumbUri}
@ -31,19 +45,7 @@ const PlaylistDetails: React.FC<{
<CoverArt coverArtUri={playlist.coverArtUri} style={styles.cover} />
<Text style={styles.title}>{playlist.name}</Text>
{playlist.comment ? <Text style={styles.subtitle}>{playlist.comment}</Text> : <></>}
<View style={styles.controls}>
<Button title="Play Playlist" onPress={() => setQueue(playlist.songs, playlist.name, playlist.songs[0].id)} />
</View>
<View style={styles.songs}>
{playlist.songs.map((s, index) => (
<SongItem
key={index}
song={s}
showArt={true}
onPress={() => setQueue(playlist.songs, playlist.name, s.id)}
/>
))}
</View>
{playlist.songs.length > 0 ? <Songs /> : <NothingHere height={350} width={250} />}
</View>
</ImageGradientScrollView>
)
@ -99,9 +101,14 @@ const styles = StyleSheet.create({
height: 160,
width: 160,
},
controls: {
songsContainer: {
width: '100%',
marginTop: 18,
alignItems: 'center',
},
controls: {
flexDirection: 'row',
marginTop: 20,
},
songs: {
marginTop: 26,
@ -112,6 +119,12 @@ const styles = StyleSheet.create({
alignItems: 'center',
paddingTop: 100,
},
nothingContainer: {
height: 400,
backgroundColor: 'green',
justifyContent: 'center',
alignItems: 'center',
},
})
export default React.memo(PlaylistView)

View File

@ -2,6 +2,7 @@ enum font {
regular = 'Metropolis-Regular',
semiBold = 'Metropolis-SemiBold',
bold = 'Metropolis-Bold',
lightItalic = 'Metropolis-SemiBoldItalic',
}
export default font