mirror of
https://github.com/austinried/subtracks.git
synced 2026-02-10 06:52:43 +01:00
full reworked images to download (cache) first
This commit is contained in:
@@ -1,146 +1,92 @@
|
||||
import { useArtistInfo, useCoverArtUri } from '@app/hooks/music'
|
||||
import { useArtistCoverArtFile, useCoverArtFile } from '@app/hooks/music'
|
||||
import { DownloadFile } from '@app/state/music'
|
||||
import colors from '@app/styles/colors'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import { ActivityIndicator, StyleSheet, View, ViewStyle } from 'react-native'
|
||||
import FastImage, { ImageStyle } from 'react-native-fast-image'
|
||||
|
||||
type BaseProps = {
|
||||
imageSize?: 'thumbnail' | 'original'
|
||||
style?: ViewStyle
|
||||
imageStyle?: ImageStyle
|
||||
resizeMode?: keyof typeof FastImage.resizeMode
|
||||
round?: boolean
|
||||
}
|
||||
|
||||
type BaseImageProps = BaseProps & {
|
||||
enableLoading: () => void
|
||||
disableLoading: () => void
|
||||
fallbackError: () => void
|
||||
}
|
||||
|
||||
type ArtistIdProp = {
|
||||
type ArtistCoverArtProps = BaseProps & {
|
||||
type: 'artist'
|
||||
artistId: string
|
||||
}
|
||||
|
||||
type CoverArtProp = {
|
||||
type CoverArtProps = BaseProps & {
|
||||
type: 'cover'
|
||||
coverArt?: string
|
||||
}
|
||||
|
||||
type ArtistIdImageProps = BaseImageProps & ArtistIdProp
|
||||
type CoverArtImageProps = BaseImageProps & CoverArtProp
|
||||
const Image: React.FC<{ file?: DownloadFile } & BaseProps> = ({ file, style, imageStyle, resizeMode }) => {
|
||||
const [source, setSource] = useState<number | { uri: string }>(
|
||||
file && file.progress === 1 ? { uri: `file://${file.path}` } : require('@res/fallback.png'),
|
||||
)
|
||||
|
||||
type CoverArtProps = BaseProps & CoverArtProp & Partial<ArtistIdProp>
|
||||
|
||||
const ArtistImageFallback: React.FC<{
|
||||
enableLoading: () => void
|
||||
}> = ({ enableLoading }) => {
|
||||
useEffect(() => {
|
||||
enableLoading()
|
||||
}, [enableLoading])
|
||||
return <></>
|
||||
if (file && file.progress === 1) {
|
||||
setSource({ uri: `file://${file.path}` })
|
||||
}
|
||||
}, [file])
|
||||
|
||||
return (
|
||||
<>
|
||||
<FastImage
|
||||
source={source}
|
||||
resizeMode={resizeMode || FastImage.resizeMode.contain}
|
||||
style={[{ height: style?.height, width: style?.width }, imageStyle]}
|
||||
onError={() => {
|
||||
setSource(require('@res/fallback.png'))
|
||||
}}
|
||||
/>
|
||||
<ActivityIndicator
|
||||
animating={file && file.progress < 1}
|
||||
size="large"
|
||||
color={colors.accent}
|
||||
style={styles.indicator}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const ArtistImage = React.memo<ArtistIdImageProps>(
|
||||
({ artistId, imageSize, style, imageStyle, resizeMode, enableLoading, disableLoading, fallbackError }) => {
|
||||
const artistInfo = useArtistInfo(artistId)
|
||||
const ArtistImage = React.memo<ArtistCoverArtProps>(props => {
|
||||
const file = useArtistCoverArtFile(props.artistId)
|
||||
|
||||
if (!artistInfo) {
|
||||
return <ArtistImageFallback enableLoading={enableLoading} />
|
||||
}
|
||||
return <Image file={file} {...props} />
|
||||
})
|
||||
|
||||
const uri = imageSize === 'thumbnail' ? artistInfo?.smallImageUrl : artistInfo?.largeImageUrl
|
||||
const CoverArtImage = React.memo<CoverArtProps>(props => {
|
||||
const file = useCoverArtFile(props.coverArt)
|
||||
|
||||
return (
|
||||
<FastImage
|
||||
source={{ uri }}
|
||||
style={[{ height: style?.height, width: style?.width }, imageStyle]}
|
||||
resizeMode={resizeMode || FastImage.resizeMode.contain}
|
||||
onProgress={enableLoading}
|
||||
onLoadEnd={disableLoading}
|
||||
onError={fallbackError}
|
||||
/>
|
||||
)
|
||||
},
|
||||
)
|
||||
return <Image file={file} {...props} />
|
||||
})
|
||||
|
||||
const CoverArtImage = React.memo<CoverArtImageProps>(
|
||||
({ coverArt, imageSize, style, imageStyle, resizeMode, enableLoading, disableLoading, fallbackError }) => {
|
||||
const coverArtUri = useCoverArtUri()
|
||||
|
||||
return (
|
||||
<FastImage
|
||||
source={{ uri: coverArtUri(coverArt, imageSize) }}
|
||||
style={[{ height: style?.height, width: style?.width }, imageStyle]}
|
||||
resizeMode={resizeMode || FastImage.resizeMode.contain}
|
||||
onProgress={enableLoading}
|
||||
onLoadEnd={disableLoading}
|
||||
onError={fallbackError}
|
||||
/>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
const CoverArt: React.FC<CoverArtProps> = ({ coverArt, artistId, resizeMode, imageSize, style, imageStyle, round }) => {
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [fallback, setFallback] = useState(false)
|
||||
|
||||
const enableLoading = React.useCallback(() => setLoading(true), [])
|
||||
const disableLoading = React.useCallback(() => setLoading(false), [])
|
||||
const fallbackError = React.useCallback(() => {
|
||||
setFallback(true)
|
||||
setLoading(false)
|
||||
}, [])
|
||||
|
||||
imageSize = imageSize === undefined ? 'thumbnail' : 'original'
|
||||
round = round === undefined ? artistId !== undefined : round
|
||||
|
||||
const viewStyles = [style]
|
||||
if (round) {
|
||||
const CoverArt: React.FC<CoverArtProps | ArtistCoverArtProps> = props => {
|
||||
const viewStyles = [props.style]
|
||||
if (props.round) {
|
||||
viewStyles.push(styles.round)
|
||||
}
|
||||
|
||||
let ImageComponent
|
||||
if (artistId) {
|
||||
ImageComponent = (
|
||||
<ArtistImage
|
||||
artistId={artistId}
|
||||
imageSize={imageSize}
|
||||
style={style}
|
||||
imageStyle={imageStyle}
|
||||
resizeMode={resizeMode}
|
||||
enableLoading={enableLoading}
|
||||
disableLoading={disableLoading}
|
||||
fallbackError={fallbackError}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
ImageComponent = (
|
||||
<CoverArtImage
|
||||
coverArt={coverArt}
|
||||
imageSize={imageSize}
|
||||
style={style}
|
||||
imageStyle={imageStyle}
|
||||
resizeMode={resizeMode}
|
||||
enableLoading={enableLoading}
|
||||
disableLoading={disableLoading}
|
||||
fallbackError={fallbackError}
|
||||
/>
|
||||
)
|
||||
}
|
||||
const coverArtImage = useCallback(() => <CoverArtImage {...(props as CoverArtProps)} />, [props])
|
||||
const artistImage = useCallback(() => <ArtistImage {...(props as ArtistCoverArtProps)} />, [props])
|
||||
|
||||
if (fallback) {
|
||||
ImageComponent = (
|
||||
<FastImage
|
||||
source={require('@res/fallback.png')}
|
||||
style={[{ height: style?.height, width: style?.width }, imageStyle]}
|
||||
/>
|
||||
)
|
||||
let ImageComponent
|
||||
switch (props.type) {
|
||||
case 'artist':
|
||||
ImageComponent = artistImage
|
||||
break
|
||||
default:
|
||||
ImageComponent = coverArtImage
|
||||
break
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={viewStyles}>
|
||||
{ImageComponent}
|
||||
<ActivityIndicator animating={loading} size="large" color={colors.accent} style={styles.indicator} />
|
||||
<ImageComponent />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user