mirror of
https://github.com/austinried/subtracks.git
synced 2025-12-29 01:19:28 +01:00
clean up artist art/placeholders
This commit is contained in:
parent
d1598d53f8
commit
e7f9b1db86
@ -1,11 +1,12 @@
|
|||||||
import { useAtomValue } from 'jotai/utils'
|
import { useAtomValue } from 'jotai/utils'
|
||||||
import React from 'react'
|
import React, { useState } from 'react'
|
||||||
import { ActivityIndicator, View } from 'react-native'
|
import { ActivityIndicator, LayoutChangeEvent, StyleSheet, View } from 'react-native'
|
||||||
import FastImage from 'react-native-fast-image'
|
import FastImage from 'react-native-fast-image'
|
||||||
import LinearGradient from 'react-native-linear-gradient'
|
import LinearGradient from 'react-native-linear-gradient'
|
||||||
import { artistArtAtomFamily } from '@app/state/music'
|
import { artistArtAtomFamily } from '@app/state/music'
|
||||||
import colors from '@app/styles/colors'
|
import colors from '@app/styles/colors'
|
||||||
import CoverArt from '@app/components/CoverArt'
|
import CoverArt from '@app/components/CoverArt'
|
||||||
|
import IconFA5 from 'react-native-vector-icons/FontAwesome5'
|
||||||
|
|
||||||
interface ArtistArtSizeProps {
|
interface ArtistArtSizeProps {
|
||||||
height: number
|
height: number
|
||||||
@ -20,26 +21,31 @@ interface ArtistArtProps extends ArtistArtSizeProps {
|
|||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const PlaceholderContainer: React.FC<ArtistArtSizeProps> = ({ height, width, children }) => (
|
const PlaceholderContainer: React.FC<ArtistArtSizeProps> = ({ height, width, children }) => {
|
||||||
<LinearGradient
|
const [layout, setLayout] = useState({ x: 0, y: 0, width: 0, height: 0 })
|
||||||
colors={[colors.accent, colors.accentLow]}
|
|
||||||
style={{
|
|
||||||
height,
|
|
||||||
width,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
}}>
|
|
||||||
{children}
|
|
||||||
</LinearGradient>
|
|
||||||
)
|
|
||||||
|
|
||||||
const FourUp: React.FC<ArtistArtXUpProps> = ({ height, width, coverArtUris }) => {
|
const onLayout = (event: LayoutChangeEvent) => {
|
||||||
|
setLayout(event.nativeEvent.layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LinearGradient
|
||||||
|
onLayout={onLayout}
|
||||||
|
colors={[colors.accent, colors.accentLow]}
|
||||||
|
style={[styles.placeholderContainer, { height, width }]}>
|
||||||
|
<IconFA5 name="microphone" color="black" size={layout.width / 1.8} style={styles.placeholderIcon} />
|
||||||
|
{children}
|
||||||
|
</LinearGradient>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const FourUp = React.memo<ArtistArtXUpProps>(({ height, width, coverArtUris }) => {
|
||||||
const halfHeight = height / 2
|
const halfHeight = height / 2
|
||||||
const halfWidth = width / 2
|
const halfWidth = width / 2
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PlaceholderContainer height={height} width={width}>
|
<PlaceholderContainer height={height} width={width}>
|
||||||
<View style={{ width, height: halfHeight, flexDirection: 'row' }}>
|
<View style={[styles.artRow, { width, height: halfHeight }]}>
|
||||||
<FastImage
|
<FastImage
|
||||||
source={{ uri: coverArtUris[0] }}
|
source={{ uri: coverArtUris[0] }}
|
||||||
style={{ height: halfHeight, width: halfWidth }}
|
style={{ height: halfHeight, width: halfWidth }}
|
||||||
@ -51,7 +57,7 @@ const FourUp: React.FC<ArtistArtXUpProps> = ({ height, width, coverArtUris }) =>
|
|||||||
resizeMode={FastImage.resizeMode.cover}
|
resizeMode={FastImage.resizeMode.cover}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={{ width, height: halfHeight, flexDirection: 'row' }}>
|
<View style={[styles.artRow, { width, height: halfHeight }]}>
|
||||||
<FastImage
|
<FastImage
|
||||||
source={{ uri: coverArtUris[2] }}
|
source={{ uri: coverArtUris[2] }}
|
||||||
style={{ height: halfHeight, width: halfWidth }}
|
style={{ height: halfHeight, width: halfWidth }}
|
||||||
@ -65,22 +71,22 @@ const FourUp: React.FC<ArtistArtXUpProps> = ({ height, width, coverArtUris }) =>
|
|||||||
</View>
|
</View>
|
||||||
</PlaceholderContainer>
|
</PlaceholderContainer>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
const ThreeUp: React.FC<ArtistArtXUpProps> = ({ height, width, coverArtUris }) => {
|
const ThreeUp = React.memo<ArtistArtXUpProps>(({ height, width, coverArtUris }) => {
|
||||||
const halfHeight = height / 2
|
const halfHeight = height / 2
|
||||||
const halfWidth = width / 2
|
const halfWidth = width / 2
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PlaceholderContainer height={height} width={width}>
|
<PlaceholderContainer height={height} width={width}>
|
||||||
<View style={{ width, height: halfHeight, flexDirection: 'row' }}>
|
<View style={[styles.artRow, { width, height: halfHeight }]}>
|
||||||
<FastImage
|
<FastImage
|
||||||
source={{ uri: coverArtUris[0] }}
|
source={{ uri: coverArtUris[0] }}
|
||||||
style={{ height: halfHeight, width }}
|
style={{ height: halfHeight, width }}
|
||||||
resizeMode={FastImage.resizeMode.cover}
|
resizeMode={FastImage.resizeMode.cover}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={{ width, height: halfHeight, flexDirection: 'row' }}>
|
<View style={[styles.artRow, { width, height: halfHeight }]}>
|
||||||
<FastImage
|
<FastImage
|
||||||
source={{ uri: coverArtUris[1] }}
|
source={{ uri: coverArtUris[1] }}
|
||||||
style={{ height: halfHeight, width: halfWidth }}
|
style={{ height: halfHeight, width: halfWidth }}
|
||||||
@ -94,21 +100,21 @@ const ThreeUp: React.FC<ArtistArtXUpProps> = ({ height, width, coverArtUris }) =
|
|||||||
</View>
|
</View>
|
||||||
</PlaceholderContainer>
|
</PlaceholderContainer>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
const TwoUp: React.FC<ArtistArtXUpProps> = ({ height, width, coverArtUris }) => {
|
const TwoUp = React.memo<ArtistArtXUpProps>(({ height, width, coverArtUris }) => {
|
||||||
const halfHeight = height / 2
|
const halfHeight = height / 2
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PlaceholderContainer height={height} width={width}>
|
<PlaceholderContainer height={height} width={width}>
|
||||||
<View style={{ width, height: halfHeight, flexDirection: 'row' }}>
|
<View style={[styles.artRow, { width, height: halfHeight }]}>
|
||||||
<FastImage
|
<FastImage
|
||||||
source={{ uri: coverArtUris[0] }}
|
source={{ uri: coverArtUris[0] }}
|
||||||
style={{ height: halfHeight, width }}
|
style={{ height: halfHeight, width }}
|
||||||
resizeMode={FastImage.resizeMode.cover}
|
resizeMode={FastImage.resizeMode.cover}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={{ width, height: halfHeight, flexDirection: 'row' }}>
|
<View style={[styles.artRow, { width, height: halfHeight }]}>
|
||||||
<FastImage
|
<FastImage
|
||||||
source={{ uri: coverArtUris[1] }}
|
source={{ uri: coverArtUris[1] }}
|
||||||
style={{ height: halfHeight, width }}
|
style={{ height: halfHeight, width }}
|
||||||
@ -117,32 +123,19 @@ const TwoUp: React.FC<ArtistArtXUpProps> = ({ height, width, coverArtUris }) =>
|
|||||||
</View>
|
</View>
|
||||||
</PlaceholderContainer>
|
</PlaceholderContainer>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
const OneUp: React.FC<ArtistArtXUpProps> = ({ height, width, coverArtUris }) => {
|
const OneUp = React.memo<ArtistArtXUpProps>(({ height, width, coverArtUris }) => (
|
||||||
return (
|
<PlaceholderContainer height={height} width={width}>
|
||||||
<PlaceholderContainer height={height} width={width}>
|
<FastImage source={{ uri: coverArtUris[0] }} style={{ height, width }} resizeMode={FastImage.resizeMode.cover} />
|
||||||
<FastImage source={{ uri: coverArtUris[0] }} style={{ height, width }} resizeMode={FastImage.resizeMode.cover} />
|
</PlaceholderContainer>
|
||||||
</PlaceholderContainer>
|
))
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const NoneUp: React.FC<ArtistArtSizeProps> = ({ height, width }) => {
|
const NoneUp = React.memo<ArtistArtSizeProps>(({ height, width }) => (
|
||||||
return (
|
<PlaceholderContainer height={height} width={width} />
|
||||||
<PlaceholderContainer height={height} width={width}>
|
))
|
||||||
<FastImage
|
|
||||||
source={require('@res/icons/mic_on-fill.png')}
|
|
||||||
style={{
|
|
||||||
height: height - height / 4,
|
|
||||||
width: width - width / 4,
|
|
||||||
}}
|
|
||||||
resizeMode={FastImage.resizeMode.cover}
|
|
||||||
/>
|
|
||||||
</PlaceholderContainer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const ArtistArt: React.FC<ArtistArtProps> = ({ id, height, width }) => {
|
const ArtistArt = React.memo<ArtistArtProps>(({ id, height, width }) => {
|
||||||
const artistArt = useAtomValue(artistArtAtomFamily(id))
|
const artistArt = useAtomValue(artistArtAtomFamily(id))
|
||||||
|
|
||||||
const Placeholder = () => {
|
const Placeholder = () => {
|
||||||
@ -170,27 +163,17 @@ const ArtistArt: React.FC<ArtistArtProps> = ({ id, height, width }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View style={[styles.container, { borderRadius: height / 2 }]}>
|
||||||
style={{
|
|
||||||
borderRadius: height / 2,
|
|
||||||
overflow: 'hidden',
|
|
||||||
}}>
|
|
||||||
<CoverArt PlaceholderComponent={Placeholder} height={height} width={width} coverArtUri={artistArt?.uri} />
|
<CoverArt PlaceholderComponent={Placeholder} height={height} width={width} coverArtUri={artistArt?.uri} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
const ArtistArtFallback: React.FC<ArtistArtProps> = ({ height, width }) => (
|
const ArtistArtFallback = React.memo<ArtistArtProps>(({ height, width }) => (
|
||||||
<View
|
<View style={[styles.fallback, { height, width }]}>
|
||||||
style={{
|
<ActivityIndicator size="large" color={colors.accent} />
|
||||||
height,
|
|
||||||
width,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
}}>
|
|
||||||
<ActivityIndicator size="small" color={colors.accent} />
|
|
||||||
</View>
|
</View>
|
||||||
)
|
))
|
||||||
|
|
||||||
const ArtistArtLoader: React.FC<ArtistArtProps> = props => (
|
const ArtistArtLoader: React.FC<ArtistArtProps> = props => (
|
||||||
<React.Suspense fallback={<ArtistArtFallback {...props} />}>
|
<React.Suspense fallback={<ArtistArtFallback {...props} />}>
|
||||||
@ -198,4 +181,24 @@ const ArtistArtLoader: React.FC<ArtistArtProps> = props => (
|
|||||||
</React.Suspense>
|
</React.Suspense>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
placeholderContainer: {
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
placeholderIcon: {
|
||||||
|
position: 'absolute',
|
||||||
|
},
|
||||||
|
artRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
fallback: {
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
export default React.memo(ArtistArtLoader)
|
export default React.memo(ArtistArtLoader)
|
||||||
|
|||||||
@ -1,16 +1,20 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { ActivityIndicator, StyleSheet, View } from 'react-native'
|
import { ActivityIndicator, LayoutChangeEvent, StyleSheet, View } from 'react-native'
|
||||||
import FastImage from 'react-native-fast-image'
|
import FastImage from 'react-native-fast-image'
|
||||||
import colors from '@app/styles/colors'
|
import colors from '@app/styles/colors'
|
||||||
|
import IconFA5 from 'react-native-vector-icons/FontAwesome5'
|
||||||
|
import LinearGradient from 'react-native-linear-gradient'
|
||||||
|
|
||||||
const CoverArt: React.FC<{
|
const CoverArt: React.FC<{
|
||||||
PlaceholderComponent?: () => JSX.Element
|
PlaceholderComponent?: () => JSX.Element
|
||||||
|
placeholderIcon?: string
|
||||||
height?: string | number
|
height?: string | number
|
||||||
width?: string | number
|
width?: string | number
|
||||||
coverArtUri?: string
|
coverArtUri?: string
|
||||||
}> = ({ PlaceholderComponent, height, width, coverArtUri }) => {
|
}> = ({ PlaceholderComponent, placeholderIcon, height, width, coverArtUri }) => {
|
||||||
const [placeholderVisible, setPlaceholderVisible] = useState(false)
|
const [placeholderVisible, setPlaceholderVisible] = useState(false)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
|
const [layout, setLayout] = useState({ x: 0, y: 0, width: 0, height: 0 })
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!coverArtUri) {
|
if (!coverArtUri) {
|
||||||
@ -25,18 +29,27 @@ const CoverArt: React.FC<{
|
|||||||
resizeMode={FastImage.resizeMode.contain}
|
resizeMode={FastImage.resizeMode.contain}
|
||||||
onError={() => {
|
onError={() => {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
console.log('asdfdsaf')
|
|
||||||
setPlaceholderVisible(true)
|
setPlaceholderVisible(true)
|
||||||
}}
|
}}
|
||||||
onLoadEnd={() => setLoading(false)}
|
onLoadEnd={() => setLoading(false)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const Placeholder = () => (
|
||||||
|
<LinearGradient colors={[colors.accent, colors.accentLow]} style={styles.placeholder}>
|
||||||
|
<IconFA5 name={placeholderIcon || 'record-vinyl'} color="black" size={layout.width / 1.5} />
|
||||||
|
</LinearGradient>
|
||||||
|
)
|
||||||
|
|
||||||
|
const onLayout = (event: LayoutChangeEvent) => {
|
||||||
|
setLayout(event.nativeEvent.layout)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{ ...styles.container, height, width }}>
|
<View style={{ ...styles.container, height, width }} onLayout={onLayout}>
|
||||||
{coverArtUri ? <Image /> : <></>}
|
{coverArtUri ? <Image /> : <></>}
|
||||||
<View style={{ ...styles.placeholderContainer, opacity: placeholderVisible ? 1 : 0 }}>
|
<View style={{ ...styles.placeholderContainer, opacity: placeholderVisible ? 1 : 0 }}>
|
||||||
{PlaceholderComponent ? <PlaceholderComponent /> : <></>}
|
{PlaceholderComponent ? <PlaceholderComponent /> : <Placeholder />}
|
||||||
</View>
|
</View>
|
||||||
<ActivityIndicator style={styles.indicator} animating={loading} size={'large'} color={colors.accent} />
|
<ActivityIndicator style={styles.indicator} animating={loading} size={'large'} color={colors.accent} />
|
||||||
</View>
|
</View>
|
||||||
@ -54,6 +67,12 @@ const styles = StyleSheet.create({
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
},
|
},
|
||||||
|
placeholder: {
|
||||||
|
height: '100%',
|
||||||
|
width: '100%',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
indicator: {
|
indicator: {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
|||||||
@ -21,12 +21,7 @@ const AlbumItem = React.memo<{
|
|||||||
onPress={() => navigation.navigate('AlbumView', { id: album.id, title: album.name })}
|
onPress={() => navigation.navigate('AlbumView', { id: album.id, title: album.name })}
|
||||||
key={album.id}
|
key={album.id}
|
||||||
style={styles.item}>
|
style={styles.item}>
|
||||||
<CoverArt
|
<CoverArt coverArtUri={album.coverArtThumbUri} height={styles.item.width} width={styles.item.width} />
|
||||||
PlaceholderComponent={() => <></>}
|
|
||||||
coverArtUri={album.coverArtThumbUri}
|
|
||||||
height={styles.item.width}
|
|
||||||
width={styles.item.width}
|
|
||||||
/>
|
|
||||||
<Text style={styles.title} numberOfLines={1}>
|
<Text style={styles.title} numberOfLines={1}>
|
||||||
{album.name}
|
{album.name}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user