mirror of https://github.com/tooot-app/app
Test #722
This commit is contained in:
parent
f8a3b56b11
commit
4e620f8987
|
@ -0,0 +1,125 @@
|
||||||
|
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'
|
||||||
|
import { Pressable, View } from 'react-native'
|
||||||
|
|
||||||
|
export const CardNeodb = ({ card }: { card: Mastodon.Card }) => {
|
||||||
|
const { colors } = useTheme()
|
||||||
|
|
||||||
|
const segments = Linking.parse(card.url).path?.split('/')
|
||||||
|
if (!segments || !(segments[0] === 'movie' || segments[0] === 'book')) return null
|
||||||
|
|
||||||
|
const { data } = useNeodbQuery({ path: `${segments[0]}/${segments[1]}` })
|
||||||
|
|
||||||
|
if (!data) return null
|
||||||
|
|
||||||
|
switch (segments[0]) {
|
||||||
|
case 'movie':
|
||||||
|
return (
|
||||||
|
<Pressable
|
||||||
|
style={{
|
||||||
|
marginTop: StyleConstants.Spacing.S,
|
||||||
|
backgroundColor: colors.shimmerDefault,
|
||||||
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
|
padding: StyleConstants.Spacing.S,
|
||||||
|
flexDirection: 'row'
|
||||||
|
}}
|
||||||
|
onPress={() => openLink(card.url)}
|
||||||
|
>
|
||||||
|
<GracefullyImage
|
||||||
|
sources={{ default: { uri: `https://neodb.social${data.image}` } }}
|
||||||
|
dimension={{
|
||||||
|
width: StyleConstants.Font.LineHeight.M * 4,
|
||||||
|
height: StyleConstants.Font.LineHeight.M * 5
|
||||||
|
}}
|
||||||
|
style={{ marginRight: StyleConstants.Spacing.S }}
|
||||||
|
imageStyle={{ borderRadius: StyleConstants.BorderRadius / 2 }}
|
||||||
|
dim
|
||||||
|
/>
|
||||||
|
<View style={{ flex: 1, gap: StyleConstants.Spacing.S }}>
|
||||||
|
<CustomText
|
||||||
|
fontStyle='S'
|
||||||
|
fontWeight='Bold'
|
||||||
|
style={{ color: colors.primaryDefault }}
|
||||||
|
numberOfLines={3}
|
||||||
|
>
|
||||||
|
{[
|
||||||
|
data.data.title,
|
||||||
|
data.data.orig_title,
|
||||||
|
data.data.year ? `(${data.data.year})` : null
|
||||||
|
]
|
||||||
|
.filter(d => d)
|
||||||
|
.join(' ')}
|
||||||
|
</CustomText>
|
||||||
|
<CustomText fontStyle='S' style={{ color: colors.secondary }} numberOfLines={2}>
|
||||||
|
{[
|
||||||
|
data.data.duration ? `${data.data.duration}分钟` : null,
|
||||||
|
data.data.area?.join(' '),
|
||||||
|
data.data.genre?.join(' '),
|
||||||
|
data.data.director?.join(' ')
|
||||||
|
]
|
||||||
|
.filter(d => d)
|
||||||
|
.join(' / ')}
|
||||||
|
</CustomText>
|
||||||
|
</View>
|
||||||
|
</Pressable>
|
||||||
|
)
|
||||||
|
case 'book':
|
||||||
|
return (
|
||||||
|
<Pressable
|
||||||
|
style={{
|
||||||
|
marginTop: StyleConstants.Spacing.S,
|
||||||
|
backgroundColor: colors.shimmerDefault,
|
||||||
|
borderRadius: StyleConstants.BorderRadius,
|
||||||
|
padding: StyleConstants.Spacing.S,
|
||||||
|
flexDirection: 'row'
|
||||||
|
}}
|
||||||
|
onPress={() => openLink(card.url)}
|
||||||
|
>
|
||||||
|
<GracefullyImage
|
||||||
|
sources={{ default: { uri: `https://neodb.social${data.image}` } }}
|
||||||
|
dimension={{
|
||||||
|
width: StyleConstants.Font.LineHeight.M * 4,
|
||||||
|
height: StyleConstants.Font.LineHeight.M * 5
|
||||||
|
}}
|
||||||
|
style={{ marginRight: StyleConstants.Spacing.S }}
|
||||||
|
imageStyle={{ borderRadius: StyleConstants.BorderRadius / 2 }}
|
||||||
|
dim
|
||||||
|
/>
|
||||||
|
<View style={{ flex: 1, gap: StyleConstants.Spacing.S }}>
|
||||||
|
<CustomText
|
||||||
|
fontStyle='S'
|
||||||
|
fontWeight='Bold'
|
||||||
|
style={{ color: colors.primaryDefault }}
|
||||||
|
numberOfLines={3}
|
||||||
|
>
|
||||||
|
{[
|
||||||
|
data.data.title,
|
||||||
|
data.data.pub_year && data.data.pub_month
|
||||||
|
? `(${data.data.pub_year}年${data.data.pub_month}月)`
|
||||||
|
: null
|
||||||
|
]
|
||||||
|
.filter(d => d)
|
||||||
|
.join(' ')}
|
||||||
|
</CustomText>
|
||||||
|
<CustomText fontStyle='S' style={{ color: colors.secondary }} numberOfLines={2}>
|
||||||
|
{[
|
||||||
|
data.data.author?.join(' '),
|
||||||
|
data.data.language,
|
||||||
|
data.data.pages ? `${data.data.pages}页` : null,
|
||||||
|
data.data.pub_house
|
||||||
|
]
|
||||||
|
.filter(d => d)
|
||||||
|
.join(' / ')}
|
||||||
|
</CustomText>
|
||||||
|
</View>
|
||||||
|
</Pressable>
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,14 +11,21 @@ import { useStatusQuery } from '@utils/queryHooks/status'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { useContext, useEffect, useState } from 'react'
|
import React, { useContext, useEffect, useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Pressable, View } from 'react-native'
|
import { Pressable, View } from 'react-native'
|
||||||
import TimelineDefault from '../Default'
|
import TimelineDefault from '../../Default'
|
||||||
import StatusContext from './Context'
|
import StatusContext from '../Context'
|
||||||
|
import { CardNeodb } from './Neodb'
|
||||||
|
|
||||||
const TimelineCard: React.FC = () => {
|
const TimelineCard: React.FC = () => {
|
||||||
const { status, spoilerHidden, disableDetails, inThread } = useContext(StatusContext)
|
const { status, spoilerHidden, disableDetails, inThread } = useContext(StatusContext)
|
||||||
if (!status || !status.card) return null
|
if (!status || !status.card) return null
|
||||||
|
|
||||||
|
const { i18n } = useTranslation()
|
||||||
|
if (status.card.url.includes('://neodb.social/') && i18n.language === 'zh-hans') {
|
||||||
|
return <CardNeodb card={status.card} />
|
||||||
|
}
|
||||||
|
|
||||||
const { colors } = useTheme()
|
const { colors } = useTheme()
|
||||||
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
|
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { QueryFunctionContext, useQuery, UseQueryOptions } from '@tanstack/react-query'
|
||||||
|
import apiGeneral from '@utils/api/general'
|
||||||
|
import { AxiosError } from 'axios'
|
||||||
|
|
||||||
|
export type QueryKeyNeodb = ['Neodb', { path: string }]
|
||||||
|
|
||||||
|
const queryFunction = async ({ queryKey }: QueryFunctionContext<QueryKeyNeodb>) => {
|
||||||
|
const data: any = {}
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
apiGeneral({
|
||||||
|
method: 'get',
|
||||||
|
domain: 'neodb.social',
|
||||||
|
url: `/${queryKey[1].path}`
|
||||||
|
}).then(res => {
|
||||||
|
const matches = (res.body as string).match(/"(\/media\/.+autocrop.+?)"/)
|
||||||
|
data.image = matches?.[1]
|
||||||
|
}),
|
||||||
|
apiGeneral({
|
||||||
|
method: 'get',
|
||||||
|
domain: 'neodb.social',
|
||||||
|
url: `/api/${queryKey[1].path}`
|
||||||
|
}).then(res => (data.data = res.body))
|
||||||
|
])
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useNeodbQuery = (
|
||||||
|
params: QueryKeyNeodb[1] & {
|
||||||
|
options?: UseQueryOptions<any, AxiosError>
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
const queryKey: QueryKeyNeodb = ['Neodb', { path: params.path }]
|
||||||
|
return useQuery(queryKey, queryFunction, {
|
||||||
|
...params?.options,
|
||||||
|
staleTime: Infinity,
|
||||||
|
cacheTime: Infinity
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue