mirror of
https://github.com/tooot-app/app
synced 2025-04-24 07:07:24 +02:00
parent
c2aa78fef8
commit
70d57ed830
@ -4,9 +4,9 @@ import { InfiniteData, useQueryClient } from '@tanstack/react-query'
|
|||||||
import { QueryKeyTimeline, TimelineData, useTimelineQuery } from '@utils/queryHooks/timeline'
|
import { QueryKeyTimeline, TimelineData, useTimelineQuery } from '@utils/queryHooks/timeline'
|
||||||
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, { RefObject, useCallback, useRef, useState } from 'react'
|
import React, { RefObject, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FlatList, LayoutChangeEvent, Platform, StyleSheet, Text, View } from 'react-native'
|
import { FlatList, Platform, Text, View } from 'react-native'
|
||||||
import { Circle } from 'react-native-animated-spinkit'
|
import { Circle } from 'react-native-animated-spinkit'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
Extrapolate,
|
Extrapolate,
|
||||||
@ -45,10 +45,10 @@ const TimelineRefresh: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fetchingLatestIndex = useRef(0)
|
const fetchingLatestIndex = useRef(0)
|
||||||
|
const FETCHING_LATEST_MAX = 5
|
||||||
const refetchActive = useRef(false)
|
const refetchActive = useRef(false)
|
||||||
|
|
||||||
const { refetch, isFetching, isLoading, fetchPreviousPage, hasPreviousPage, isFetchingNextPage } =
|
const { refetch, isFetching, fetchPreviousPage, hasPreviousPage } = useTimelineQuery({
|
||||||
useTimelineQuery({
|
|
||||||
...queryKey[1],
|
...queryKey[1],
|
||||||
options: {
|
options: {
|
||||||
getPreviousPageParam: firstPage =>
|
getPreviousPageParam: firstPage =>
|
||||||
@ -67,13 +67,14 @@ const TimelineRefresh: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: async () => {
|
||||||
if (fetchingLatestIndex.current > 0) {
|
if (fetchingLatestIndex.current > 0) {
|
||||||
if (fetchingLatestIndex.current > 5) {
|
if (fetchingLatestIndex.current > FETCHING_LATEST_MAX) {
|
||||||
clearFirstPage()
|
clearFirstPage()
|
||||||
fetchingLatestIndex.current = 0
|
fetchingLatestIndex.current = 0
|
||||||
} else {
|
} else {
|
||||||
if (hasPreviousPage) {
|
if (hasPreviousPage) {
|
||||||
|
await new Promise(res => setTimeout(res, 100))
|
||||||
fetchPreviousPage()
|
fetchPreviousPage()
|
||||||
fetchingLatestIndex.current++
|
fetchingLatestIndex.current++
|
||||||
} else {
|
} else {
|
||||||
@ -102,27 +103,6 @@ const TimelineRefresh: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const prepareRefetch = () => {
|
|
||||||
refetchActive.current = true
|
|
||||||
queryClient.setQueryData<InfiniteData<TimelineData> | undefined>(queryKey, data => {
|
|
||||||
if (data) {
|
|
||||||
data.pageParams = [undefined]
|
|
||||||
const newFirstPage: TimelineData = { body: [] }
|
|
||||||
for (let page of data.pages) {
|
|
||||||
// @ts-ignore
|
|
||||||
newFirstPage.body.push(...page.body)
|
|
||||||
if (newFirstPage.body.length > 10) break
|
|
||||||
}
|
|
||||||
data.pages = [newFirstPage]
|
|
||||||
}
|
|
||||||
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const callRefetch = async () => {
|
|
||||||
await refetch()
|
|
||||||
setTimeout(() => flRef.current?.scrollToOffset({ offset: 1 }), 50)
|
|
||||||
}
|
|
||||||
|
|
||||||
const [textRight, setTextRight] = useState(0)
|
const [textRight, setTextRight] = useState(0)
|
||||||
const arrowY = useAnimatedStyle(() => ({
|
const arrowY = useAnimatedStyle(() => ({
|
||||||
@ -145,14 +125,6 @@ const TimelineRefresh: React.FC<Props> = ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const arrowStage = useSharedValue(0)
|
const arrowStage = useSharedValue(0)
|
||||||
const onLayout = useCallback(
|
|
||||||
({ nativeEvent }: LayoutChangeEvent) => {
|
|
||||||
if (nativeEvent.layout.x + nativeEvent.layout.width > textRight) {
|
|
||||||
setTextRight(nativeEvent.layout.x + nativeEvent.layout.width)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[textRight]
|
|
||||||
)
|
|
||||||
useAnimatedReaction(
|
useAnimatedReaction(
|
||||||
() => {
|
() => {
|
||||||
if (isFetching) {
|
if (isFetching) {
|
||||||
@ -190,8 +162,32 @@ const TimelineRefresh: React.FC<Props> = ({
|
|||||||
},
|
},
|
||||||
[isFetching]
|
[isFetching]
|
||||||
)
|
)
|
||||||
const wrapperStartLatest = () => {
|
|
||||||
|
const runFetchPrevious = () => {
|
||||||
fetchingLatestIndex.current = 1
|
fetchingLatestIndex.current = 1
|
||||||
|
fetchPreviousPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
const prepareRefetch = () => {
|
||||||
|
refetchActive.current = true
|
||||||
|
queryClient.setQueryData<InfiniteData<TimelineData> | undefined>(queryKey, data => {
|
||||||
|
if (data) {
|
||||||
|
data.pageParams = [undefined]
|
||||||
|
const newFirstPage: TimelineData = { body: [] }
|
||||||
|
for (let page of data.pages) {
|
||||||
|
// @ts-ignore
|
||||||
|
newFirstPage.body.push(...page.body)
|
||||||
|
if (newFirstPage.body.length > 10) break
|
||||||
|
}
|
||||||
|
data.pages = [newFirstPage]
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const callRefetch = async () => {
|
||||||
|
await refetch()
|
||||||
|
setTimeout(() => flRef.current?.scrollToOffset({ offset: 0 }), 50)
|
||||||
}
|
}
|
||||||
|
|
||||||
useAnimatedReaction(
|
useAnimatedReaction(
|
||||||
@ -202,42 +198,46 @@ const TimelineRefresh: React.FC<Props> = ({
|
|||||||
fetchingType.value = 0
|
fetchingType.value = 0
|
||||||
switch (data) {
|
switch (data) {
|
||||||
case 1:
|
case 1:
|
||||||
runOnJS(wrapperStartLatest)()
|
runOnJS(runFetchPrevious)()
|
||||||
runOnJS(clearFirstPage)()
|
return
|
||||||
runOnJS(fetchPreviousPage)()
|
|
||||||
break
|
|
||||||
case 2:
|
case 2:
|
||||||
runOnJS(prepareRefetch)()
|
runOnJS(prepareRefetch)()
|
||||||
runOnJS(callRefetch)()
|
runOnJS(callRefetch)()
|
||||||
break
|
return
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
const headerPadding = useAnimatedStyle(
|
|
||||||
() => ({
|
|
||||||
paddingTop:
|
|
||||||
fetchingLatestIndex.current !== 0 || (isFetching && !isLoading && !isFetchingNextPage)
|
|
||||||
? withTiming(StyleConstants.Spacing.M * 2.5)
|
|
||||||
: withTiming(0)
|
|
||||||
}),
|
|
||||||
[fetchingLatestIndex.current, isFetching, isFetchingNextPage, isLoading]
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Animated.View style={headerPadding}>
|
<Animated.View
|
||||||
<View style={styles.base}>
|
style={{
|
||||||
{isFetching ? (
|
position: 'absolute',
|
||||||
<View style={styles.container2}>
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
height: CONTAINER_HEIGHT * 2,
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{(fetchingLatestIndex.current || 99) <= FETCHING_LATEST_MAX || refetchActive.current ? (
|
||||||
|
<View style={{ height: CONTAINER_HEIGHT, justifyContent: 'center' }}>
|
||||||
<Circle size={StyleConstants.Font.Size.L} color={colors.secondary} />
|
<Circle size={StyleConstants.Font.Size.L} color={colors.secondary} />
|
||||||
</View>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<View style={styles.container1}>
|
<View style={{ flex: 1, flexDirection: 'row', height: CONTAINER_HEIGHT }}>
|
||||||
<Text
|
<Text
|
||||||
style={[styles.explanation, { color: colors.primaryDefault }]}
|
style={{
|
||||||
onLayout={onLayout}
|
fontSize: StyleConstants.Font.Size.S,
|
||||||
|
lineHeight: CONTAINER_HEIGHT,
|
||||||
|
color: colors.primaryDefault
|
||||||
|
}}
|
||||||
|
onLayout={({ nativeEvent }) => {
|
||||||
|
if (nativeEvent.layout.x + nativeEvent.layout.width > textRight) {
|
||||||
|
setTextRight(nativeEvent.layout.x + nativeEvent.layout.width)
|
||||||
|
}
|
||||||
|
}}
|
||||||
children={t('refresh.fetchPreviousPage')}
|
children={t('refresh.fetchPreviousPage')}
|
||||||
/>
|
/>
|
||||||
<Animated.View
|
<Animated.View
|
||||||
@ -258,39 +258,25 @@ const TimelineRefresh: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.container2}>
|
<View style={{ height: CONTAINER_HEIGHT, justifyContent: 'center' }}>
|
||||||
<Text
|
<Text
|
||||||
style={[styles.explanation, { color: colors.primaryDefault }]}
|
style={{
|
||||||
onLayout={onLayout}
|
fontSize: StyleConstants.Font.Size.S,
|
||||||
|
lineHeight: CONTAINER_HEIGHT,
|
||||||
|
color: colors.primaryDefault
|
||||||
|
}}
|
||||||
|
onLayout={({ nativeEvent }) => {
|
||||||
|
if (nativeEvent.layout.x + nativeEvent.layout.width > textRight) {
|
||||||
|
setTextRight(nativeEvent.layout.x + nativeEvent.layout.width)
|
||||||
|
}
|
||||||
|
}}
|
||||||
children={t('refresh.refetch')}
|
children={t('refresh.refetch')}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</View>
|
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
base: {
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
height: CONTAINER_HEIGHT * 2,
|
|
||||||
alignItems: 'center'
|
|
||||||
},
|
|
||||||
container1: {
|
|
||||||
flex: 1,
|
|
||||||
flexDirection: 'row',
|
|
||||||
height: CONTAINER_HEIGHT
|
|
||||||
},
|
|
||||||
container2: { height: CONTAINER_HEIGHT, justifyContent: 'center' },
|
|
||||||
explanation: {
|
|
||||||
fontSize: StyleConstants.Font.Size.S,
|
|
||||||
lineHeight: CONTAINER_HEIGHT
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export default TimelineRefresh
|
export default TimelineRefresh
|
||||||
|
@ -129,13 +129,11 @@ const Timeline: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
maintainVisibleContentPosition={
|
{...(!isLoading && {
|
||||||
isFetching
|
maintainVisibleContentPosition: {
|
||||||
? {
|
|
||||||
minIndexForVisible: 0
|
minIndexForVisible: 0
|
||||||
}
|
}
|
||||||
: undefined
|
})}
|
||||||
}
|
|
||||||
{...androidRefreshControl}
|
{...androidRefreshControl}
|
||||||
{...customProps}
|
{...customProps}
|
||||||
/>
|
/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user