1
0
mirror of https://github.com/tooot-app/app synced 2025-03-12 09:30:11 +01:00

Added fetched notice

This commit is contained in:
xmflsct 2023-01-30 00:25:46 +01:00
parent aee206fc95
commit d1714fab26
3 changed files with 91 additions and 7 deletions

View File

@ -17,6 +17,7 @@ import Animated, {
Extrapolate, Extrapolate,
interpolate, interpolate,
runOnJS, runOnJS,
SharedValue,
useAnimatedReaction, useAnimatedReaction,
useAnimatedStyle, useAnimatedStyle,
useDerivedValue, useDerivedValue,
@ -28,6 +29,7 @@ export interface Props {
flRef: RefObject<FlatList<any>> flRef: RefObject<FlatList<any>>
queryKey: QueryKeyTimeline queryKey: QueryKeyTimeline
fetchingActive: React.MutableRefObject<boolean> fetchingActive: React.MutableRefObject<boolean>
setFetchedCount: React.Dispatch<React.SetStateAction<number | null>>
scrollY: Animated.SharedValue<number> scrollY: Animated.SharedValue<number>
fetchingType: Animated.SharedValue<0 | 1 | 2> fetchingType: Animated.SharedValue<0 | 1 | 2>
disableRefresh?: boolean disableRefresh?: boolean
@ -42,6 +44,7 @@ const TimelineRefresh: React.FC<Props> = ({
flRef, flRef,
queryKey, queryKey,
fetchingActive, fetchingActive,
setFetchedCount,
scrollY, scrollY,
fetchingType, fetchingType,
disableRefresh = false, disableRefresh = false,
@ -152,6 +155,8 @@ const TimelineRefresh: React.FC<Props> = ({
meta: {} meta: {}
}) })
.then(res => { .then(res => {
setFetchedCount(res.body.length)
if (!res.body.length) return if (!res.body.length) return
queryClient.setQueryData< queryClient.setQueryData<

View File

@ -1,4 +1,5 @@
import ComponentSeparator from '@components/Separator' import ComponentSeparator from '@components/Separator'
import CustomText from '@components/Text'
import TimelineDefault from '@components/Timeline/Default' import TimelineDefault from '@components/Timeline/Default'
import { useScrollToTop } from '@react-navigation/native' import { useScrollToTop } from '@react-navigation/native'
import { UseInfiniteQueryOptions } from '@tanstack/react-query' import { UseInfiniteQueryOptions } from '@tanstack/react-query'
@ -11,9 +12,20 @@ import {
} from '@utils/storage/actions' } from '@utils/storage/actions'
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, useRef } from 'react' import React, { RefObject, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { FlatList, FlatListProps, Platform, RefreshControl } from 'react-native' import { FlatList, FlatListProps, Platform, RefreshControl } from 'react-native'
import Animated, { useAnimatedScrollHandler, useSharedValue } from 'react-native-reanimated' import Animated, {
Easing,
runOnJS,
useAnimatedScrollHandler,
useAnimatedStyle,
useDerivedValue,
useSharedValue,
withDelay,
withSequence,
withTiming
} from 'react-native-reanimated'
import TimelineEmpty from './Empty' import TimelineEmpty from './Empty'
import TimelineFooter from './Footer' import TimelineFooter from './Footer'
import TimelineRefresh, { SEPARATION_Y_1, SEPARATION_Y_2 } from './Refresh' import TimelineRefresh, { SEPARATION_Y_1, SEPARATION_Y_2 } from './Refresh'
@ -42,9 +54,10 @@ const Timeline: React.FC<Props> = ({
readMarker = undefined, readMarker = undefined,
customProps customProps
}) => { }) => {
const { colors } = useTheme() const { colors, theme } = useTheme()
const { t } = useTranslation('componentTimeline')
const { data, refetch, isFetching, isLoading, fetchNextPage, isFetchingNextPage } = const { data, refetch, isFetching, isLoading, isRefetching, fetchNextPage, isFetchingNextPage } =
useTimelineQuery({ useTimelineQuery({
...queryKey[1], ...queryKey[1],
options: { options: {
@ -58,6 +71,28 @@ const Timeline: React.FC<Props> = ({
const flRef = useRef<FlatList>(null) const flRef = useRef<FlatList>(null)
const fetchingActive = useRef<boolean>(false) const fetchingActive = useRef<boolean>(false)
const [fetchedCount, setFetchedCount] = useState<number | null>(null)
const fetchedNoticeHeight = useSharedValue<number>(100)
const fetchedNoticeTop = useDerivedValue(() => {
if ((!isLoading && !isRefetching && isFetching) || fetchedCount !== null) {
return withSequence(
withTiming(fetchedNoticeHeight.value + 16 + 4),
withDelay(
2000,
withTiming(0, { easing: Easing.out(Easing.ease) }, finished => {
if (finished) {
runOnJS(setFetchedCount)(null)
}
})
)
)
} else {
return 0
}
}, [isLoading, isRefetching, isFetching, fetchedCount])
const fetchedNoticeAnimate = useAnimatedStyle(() => ({
transform: [{ translateY: fetchedNoticeTop.value }]
}))
const scrollY = useSharedValue(0) const scrollY = useSharedValue(0)
const fetchingType = useSharedValue<0 | 1 | 2>(0) const fetchingType = useSharedValue<0 | 1 | 2>(0)
@ -96,9 +131,9 @@ const Timeline: React.FC<Props> = ({
const firstItemId = viewableItems.filter(item => item.isViewable)[0]?.item.id const firstItemId = viewableItems.filter(item => item.isViewable)[0]?.item.id
if (!fetchingActive.current && firstItemId && firstItemId > (marker || '0')) { if (!fetchingActive.current && firstItemId && firstItemId > (marker || '0')) {
setAccountStorage([{ key: readMarker, value: firstItemId }]) // setAccountStorage([{ key: readMarker, value: firstItemId }])
} else { } else {
// setAccountStorage([{ key: readMarker, value: '109519141378761752' }]) setAccountStorage([{ key: readMarker, value: '109519141378761752' }])
} }
} }
} }
@ -136,6 +171,7 @@ const Timeline: React.FC<Props> = ({
flRef={flRef} flRef={flRef}
queryKey={queryKey} queryKey={queryKey}
fetchingActive={fetchingActive} fetchingActive={fetchingActive}
setFetchedCount={setFetchedCount}
scrollY={scrollY} scrollY={scrollY}
fetchingType={fetchingType} fetchingType={fetchingType}
disableRefresh={disableRefresh} disableRefresh={disableRefresh}
@ -176,6 +212,44 @@ const Timeline: React.FC<Props> = ({
{...androidRefreshControl} {...androidRefreshControl}
{...customProps} {...customProps}
/> />
{!disableRefresh ? (
<Animated.View
style={[
{
position: 'absolute',
alignSelf: 'center',
top: -fetchedNoticeHeight.value - 16,
paddingVertical: StyleConstants.Spacing.S,
paddingHorizontal: StyleConstants.Spacing.M,
backgroundColor: colors.backgroundDefault,
shadowColor: colors.primaryDefault,
shadowOffset: { width: 0, height: 0 },
shadowOpacity: theme === 'light' ? 0.16 : 0.24,
borderRadius: 99,
justifyContent: 'center',
alignItems: 'center'
},
fetchedNoticeAnimate
]}
onLayout={({
nativeEvent: {
layout: { height }
}
}) => (fetchedNoticeHeight.value = height)}
>
<CustomText
fontStyle='M'
style={{ color: colors.primaryDefault }}
children={
fetchedCount !== null
? fetchedCount > 0
? t('refresh.fetched.found', { count: fetchedCount })
: t('refresh.fetched.none')
: t('refresh.fetching')
}
/>
</Animated.View>
) : null}
</> </>
) )
} }

View File

@ -16,7 +16,12 @@
}, },
"refresh": { "refresh": {
"fetchPreviousPage": "Newer from here", "fetchPreviousPage": "Newer from here",
"refetch": "To latest" "refetch": "To latest",
"fetching": "Fetching newer toots ...",
"fetched": {
"none": "No newer toot",
"found": "Fetched {{count}} toots"
}
}, },
"shared": { "shared": {
"actioned": { "actioned": {