tooot/src/components/Timeline/Shared/Card/Neodb.tsx

169 lines
5.0 KiB
TypeScript
Raw Normal View History

2023-03-14 00:40:28 +01:00
import GracefullyImage from '@components/GracefullyImage'
import openLink from '@components/openLink'
import CustomText from '@components/Text'
import { useNeodbQuery } from '@utils/queryHooks/neodb'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import * as Linking from 'expo-linking'
2023-03-14 20:56:16 +01:00
import { useState } from 'react'
2023-03-14 00:40:28 +01:00
import { Pressable, View } from 'react-native'
2023-03-14 10:50:22 +01:00
import { Rating } from './Rating'
2023-03-14 00:40:28 +01:00
2023-03-14 10:50:22 +01:00
export type Props = {
card: Mastodon.Card
}
export const CardNeodb: React.FC<Props> = ({ card }) => {
2023-03-14 00:40:28 +01:00
const { colors } = useTheme()
const segments = Linking.parse(card.url).path?.split('/')
2023-04-18 22:53:50 +02:00
if (!segments || !['movie', 'book', 'tv', 'game', 'album', 'podcast'].includes(segments[0]))
2023-03-14 10:50:22 +01:00
return null
2023-03-14 00:40:28 +01:00
2023-03-14 23:48:35 +01:00
const [headingLines, setHeadingLines] = useState(3)
2023-04-18 22:53:50 +02:00
const { data } = useNeodbQuery({
path:
segments[0] === 'tv' && segments[1] === 'season'
? `${segments[0]}${segments[1]}/${segments[2]}`
: `${segments[0]}/${segments[1]}`
})
2023-03-14 00:40:28 +01:00
if (!data) return null
const Content = ({ heading, details }: { heading: string[]; details: string[] }) => (
<Pressable
style={{
marginTop: StyleConstants.Spacing.M,
backgroundColor: colors.shimmerDefault,
borderRadius: StyleConstants.BorderRadius,
padding: StyleConstants.Spacing.S,
flexDirection: 'row'
2023-03-14 10:50:22 +01:00
}}
onPress={() => openLink(card.url)}
>
{data.cover_image_url ? (
<GracefullyImage
sources={{ default: { uri: data.cover_image_url } }}
dimension={{
width: StyleConstants.Font.LineHeight.M * 4,
height: StyleConstants.Font.LineHeight.M * 5
}}
style={{ marginRight: StyleConstants.Spacing.S }}
imageStyle={{ borderRadius: StyleConstants.BorderRadius / 2 }}
dim
/>
) : null}
<View style={{ flex: 1, gap: StyleConstants.Spacing.S, justifyContent: 'space-between' }}>
<View style={{ gap: StyleConstants.Spacing.S }}>
<CustomText
fontStyle='S'
fontWeight='Bold'
style={{ color: colors.primaryDefault }}
numberOfLines={3}
onTextLayout={({ nativeEvent }) => setHeadingLines(nativeEvent.lines.length)}
children={heading.filter(d => d).join(' ')}
/>
<Rating rating={data.rating / 2} />
</View>
<CustomText
fontStyle='S'
style={{ color: colors.secondary }}
numberOfLines={4 - headingLines}
children={details.filter(d => d).join(' / ')}
/>
</View>
</Pressable>
2023-03-14 10:50:22 +01:00
)
2023-03-14 00:40:28 +01:00
switch (segments[0]) {
case 'movie':
return (
<Content
heading={[data.title, data.orig_title, data.year ? `(${data.year})` : null]}
details={[
data.duration
? parseInt(data.duration).toString() === data.duration
? `${data.duration}分钟`
: data.duration
: null,
data.area?.join(' '),
data.genre?.join(' '),
data.director?.join(' ')
]}
/>
2023-03-14 00:40:28 +01:00
)
case 'book':
return (
<Content
heading={[data.title]}
details={[
data.author?.join(' '),
data.pages ? `${data.pages}` : null,
data.language,
data.pub_house
]}
/>
2023-03-14 10:50:22 +01:00
)
case 'tv':
2023-04-18 22:53:50 +02:00
if (segments[1] === 'season') {
return (
<Content
heading={[data.title, data.orig_title, data.year ? `(${data.year})` : null]}
details={[
data.season_number ? `${data.season_number}` : null,
data.episode_count ? `${data.episode_count}` : null,
data.area?.join(' '),
data.genre?.join(' '),
data.director?.join(' ')
]}
/>
)
} else {
return (
<Content
heading={[data.title, data.orig_title, data.year ? `(${data.year})` : null]}
details={[
data.season_count ? `${data.season_count}` : null,
data.area?.join(' '),
data.genre?.join(' '),
data.director?.join(' ')
]}
/>
)
}
case 'game':
2023-03-14 10:50:22 +01:00
return (
<Content
2023-04-18 22:53:50 +02:00
heading={[data.title]}
details={[
data.genre?.join(' '),
2023-04-18 22:53:50 +02:00
data.developer?.join(' '),
data.platform?.join(' '),
data.release_date
]}
/>
)
2023-04-18 22:53:50 +02:00
case 'album':
return (
<Content
heading={[data.title]}
details={[
2023-04-18 22:53:50 +02:00
data.artist.join(' '),
data.release_date,
data.duration,
data.genre.join(' '),
data.company.join(' ')
]}
/>
2023-03-14 00:40:28 +01:00
)
2023-04-18 22:53:50 +02:00
case 'podcast':
return (
<Content heading={[data.title]} details={[data.hosts.join(' '), data.genre.join(' ')]} />
)
2023-03-14 00:40:28 +01:00
default:
return null
}
}