mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
Merge branch 'main' into candidate
This commit is contained in:
@ -1,2 +1,3 @@
|
|||||||
toooting愉快!此版本包括以下改进和修复:
|
toooting愉快!此版本包括以下改进和修复:
|
||||||
- 新增希腊语
|
- 新增希腊语
|
||||||
|
- 新增neodb专辑、播客及剧集卡片
|
@ -17,20 +17,17 @@ export const CardNeodb: React.FC<Props> = ({ card }) => {
|
|||||||
const { colors } = useTheme()
|
const { colors } = useTheme()
|
||||||
|
|
||||||
const segments = Linking.parse(card.url).path?.split('/')
|
const segments = Linking.parse(card.url).path?.split('/')
|
||||||
if (
|
if (!segments || !['movie', 'book', 'tv', 'game', 'album', 'podcast'].includes(segments[0]))
|
||||||
!segments ||
|
|
||||||
!(
|
|
||||||
segments[0] === 'movie' ||
|
|
||||||
segments[0] === 'book' ||
|
|
||||||
(segments[0] === 'tv' && segments[1] !== 'season') ||
|
|
||||||
segments[0] === 'game'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return null
|
return null
|
||||||
|
|
||||||
const [headingLines, setHeadingLines] = useState(3)
|
const [headingLines, setHeadingLines] = useState(3)
|
||||||
|
|
||||||
const { data } = useNeodbQuery({ path: `${segments[0]}/${segments[1]}` })
|
const { data } = useNeodbQuery({
|
||||||
|
path:
|
||||||
|
segments[0] === 'tv' && segments[1] === 'season'
|
||||||
|
? `${segments[0]}${segments[1]}/${segments[2]}`
|
||||||
|
: `${segments[0]}/${segments[1]}`
|
||||||
|
})
|
||||||
|
|
||||||
if (!data) return null
|
if (!data) return null
|
||||||
|
|
||||||
@ -110,6 +107,20 @@ export const CardNeodb: React.FC<Props> = ({ card }) => {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
case 'tv':
|
case 'tv':
|
||||||
|
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 (
|
return (
|
||||||
<Content
|
<Content
|
||||||
heading={[data.title, data.orig_title, data.year ? `(${data.year})` : null]}
|
heading={[data.title, data.orig_title, data.year ? `(${data.year})` : null]}
|
||||||
@ -121,6 +132,7 @@ export const CardNeodb: React.FC<Props> = ({ card }) => {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
}
|
||||||
case 'game':
|
case 'game':
|
||||||
return (
|
return (
|
||||||
<Content
|
<Content
|
||||||
@ -133,6 +145,23 @@ export const CardNeodb: React.FC<Props> = ({ card }) => {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
case 'album':
|
||||||
|
return (
|
||||||
|
<Content
|
||||||
|
heading={[data.title]}
|
||||||
|
details={[
|
||||||
|
data.artist.join(' '),
|
||||||
|
data.release_date,
|
||||||
|
data.duration,
|
||||||
|
data.genre.join(' '),
|
||||||
|
data.company.join(' ')
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
case 'podcast':
|
||||||
|
return (
|
||||||
|
<Content heading={[data.title]} details={[data.hosts.join(' '), data.genre.join(' ')]} />
|
||||||
|
)
|
||||||
default:
|
default:
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,8 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
|||||||
const ancestorsCache = useRef<(Mastodon.Status & { _level?: number })[]>()
|
const ancestorsCache = useRef<(Mastodon.Status & { _level?: number })[]>()
|
||||||
const loaded = useRef<boolean>(false)
|
const loaded = useRef<boolean>(false)
|
||||||
const prependContent = async () => {
|
const prependContent = async () => {
|
||||||
|
await new Promise<void>(promise => setTimeout(promise, 128))
|
||||||
|
|
||||||
loaded.current = true
|
loaded.current = true
|
||||||
|
|
||||||
if (ancestorsCache.current?.length) {
|
if (ancestorsCache.current?.length) {
|
||||||
@ -135,7 +137,9 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
|||||||
const remoteQueryEnabled =
|
const remoteQueryEnabled =
|
||||||
['public', 'unlisted'].includes(toot.visibility) &&
|
['public', 'unlisted'].includes(toot.visibility) &&
|
||||||
match?.domain !== getAccountStorage.string('auth.domain')
|
match?.domain !== getAccountStorage.string('auth.domain')
|
||||||
const query = useQuery<Mastodon.Status[]>(
|
const query = useQuery<{
|
||||||
|
pages: { body: (Mastodon.Status & { _level?: number })[] }[]
|
||||||
|
}>(
|
||||||
queryKey.local,
|
queryKey.local,
|
||||||
async () => {
|
async () => {
|
||||||
const context = await apiInstance<{
|
const context = await apiInstance<{
|
||||||
@ -149,7 +153,10 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
|||||||
ancestorsCache.current = [...context.ancestors]
|
ancestorsCache.current = [...context.ancestors]
|
||||||
const statuses = [{ ...toot }, ...context.descendants]
|
const statuses = [{ ...toot }, ...context.descendants]
|
||||||
|
|
||||||
return statuses.map((status, index) => {
|
return {
|
||||||
|
pages: [
|
||||||
|
{
|
||||||
|
body: statuses.map((status, index) => {
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
status._level = 0
|
status._level = 0
|
||||||
return status
|
return status
|
||||||
@ -160,19 +167,22 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
|||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
enabled: !toot._remote,
|
enabled: !toot._remote,
|
||||||
staleTime: 0,
|
staleTime: 0,
|
||||||
refetchOnMount: true,
|
refetchOnMount: true,
|
||||||
onSuccess: async data => {
|
onSuccess: data => {
|
||||||
if (data.length < 1) {
|
if (data.pages[0].body.length < 1) {
|
||||||
navigation.goBack()
|
navigation.goBack()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!remoteQueryEnabled) {
|
if (!remoteQueryEnabled) {
|
||||||
await prependContent()
|
prependContent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,42 +249,55 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
|||||||
refetchOnMount: true,
|
refetchOnMount: true,
|
||||||
retry: false,
|
retry: false,
|
||||||
onSuccess: async data => {
|
onSuccess: async data => {
|
||||||
if ((query.data?.length || 0) < 1 && data.length < 1) {
|
if ((query.data?.pages[0].body.length || 0) < 1 && data.length < 1) {
|
||||||
navigation.goBack()
|
navigation.goBack()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((query.data?.length || 0) < data.length) {
|
if ((query.data?.pages[0].body.length || 0) < data.length) {
|
||||||
setHasRemoteContent(true)
|
setHasRemoteContent(true)
|
||||||
|
|
||||||
queryClient.cancelQueries(queryKey.local)
|
queryClient.cancelQueries(queryKey.local)
|
||||||
queryClient.setQueryData<Mastodon.Status[]>(queryKey.local, old => {
|
queryClient.setQueryData<{ pages: { body: Mastodon.Status[] }[] }>(
|
||||||
return data.map(remote => {
|
queryKey.local,
|
||||||
const localMatch = old?.find(local => local.uri === remote.uri)
|
old => ({
|
||||||
|
pages: [
|
||||||
|
{
|
||||||
|
body: data.map(remote => {
|
||||||
|
const localMatch = old?.pages[0].body.find(local => local.uri === remote.uri)
|
||||||
if (localMatch) {
|
if (localMatch) {
|
||||||
return { ...localMatch, _level: remote._level, ...updateCounts(remote) }
|
return { ...localMatch, _level: remote._level, ...updateCounts(remote) }
|
||||||
} else {
|
} else {
|
||||||
return appendRemote.status(remote, match!.domain)
|
return appendRemote.status(remote, match!.domain)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
})
|
})
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
queryClient.cancelQueries(queryKey.local)
|
queryClient.cancelQueries(queryKey.local)
|
||||||
queryClient.setQueryData<Mastodon.Status[]>(queryKey.local, old => {
|
queryClient.setQueryData<{ pages: { body: Mastodon.Status[] }[] }>(
|
||||||
return old?.map(local => {
|
queryKey.local,
|
||||||
|
old => ({
|
||||||
|
pages: [
|
||||||
|
{
|
||||||
|
body:
|
||||||
|
old?.pages[0].body.map(local => {
|
||||||
const remoteMatch = data.find(remote => remote.uri === local.uri)
|
const remoteMatch = data.find(remote => remote.uri === local.uri)
|
||||||
if (remoteMatch) {
|
if (remoteMatch) {
|
||||||
return { ...local, ...updateCounts(remoteMatch) }
|
return { ...local, ...updateCounts(remoteMatch) }
|
||||||
} else {
|
} else {
|
||||||
return local
|
return local
|
||||||
}
|
}
|
||||||
|
}) || []
|
||||||
|
}
|
||||||
|
]
|
||||||
})
|
})
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSettled: async () => {
|
onSettled: () => prependContent()
|
||||||
await prependContent()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -285,12 +308,12 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
|||||||
return (
|
return (
|
||||||
<FlatList
|
<FlatList
|
||||||
ref={flRef}
|
ref={flRef}
|
||||||
data={query.data}
|
data={query.data?.pages?.[0].body}
|
||||||
keyExtractor={(item, index) => `${item.id}_${index}`}
|
keyExtractor={(item, index) => `${item.id}_${index}`}
|
||||||
renderItem={({ item, index }) => {
|
renderItem={({ item, index }) => {
|
||||||
const prev = query.data?.[index - 1]?._level || 0
|
const prev = query.data?.pages[0].body[index - 1]?._level || 0
|
||||||
const curr = item._level || 0
|
const curr = item._level || 0
|
||||||
const next = query.data?.[index + 1]?._level || 0
|
const next = query.data?.pages[0].body[index + 1]?._level || 0
|
||||||
|
|
||||||
const height = heights[index] || 300
|
const height = heights[index] || 300
|
||||||
let path = ''
|
let path = ''
|
||||||
|
Reference in New Issue
Block a user