From 932c8169512fe0d3f05aa796ab36edeb5903cfb3 Mon Sep 17 00:00:00 2001 From: Zhiyuan Zheng Date: Thu, 12 May 2022 00:04:30 +0200 Subject: [PATCH 1/2] Remove custom refresh --- src/components/Timeline.tsx | 148 +++++------- src/components/Timeline/Lookback.tsx | 32 --- src/components/Timeline/Refresh.tsx | 328 --------------------------- 3 files changed, 53 insertions(+), 455 deletions(-) delete mode 100644 src/components/Timeline/Lookback.tsx delete mode 100644 src/components/Timeline/Refresh.tsx diff --git a/src/components/Timeline.tsx b/src/components/Timeline.tsx index 9d41b3fd..2dbde09f 100644 --- a/src/components/Timeline.tsx +++ b/src/components/Timeline.tsx @@ -1,11 +1,11 @@ import ComponentSeparator from '@components/Separator' import { useScrollToTop } from '@react-navigation/native' -import { useAppDispatch } from '@root/store' -import { QueryKeyTimeline, useTimelineQuery } from '@utils/queryHooks/timeline' import { - getInstanceActive, - updateInstanceTimelineLookback -} from '@utils/slices/instancesSlice' + QueryKeyTimeline, + TimelineData, + useTimelineQuery +} from '@utils/queryHooks/timeline' +import { getInstanceActive } from '@utils/slices/instancesSlice' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import React, { RefObject, useCallback, useRef } from 'react' @@ -14,22 +14,12 @@ import { FlatListProps, Platform, RefreshControl, - StyleSheet, - ViewabilityConfigCallbackPairs + StyleSheet } from 'react-native' -import Animated, { - useAnimatedScrollHandler, - useSharedValue -} from 'react-native-reanimated' +import { InfiniteData, useQueryClient } from 'react-query' import { useSelector } from 'react-redux' import TimelineEmpty from './Timeline/Empty' import TimelineFooter from './Timeline/Footer' -import TimelineRefresh, { - SEPARATION_Y_1, - SEPARATION_Y_2 -} from './Timeline/Refresh' - -const AnimatedFlatList = Animated.createAnimatedComponent(FlatList) export interface Props { flRef?: RefObject> @@ -46,17 +36,19 @@ const Timeline: React.FC = ({ queryKey, disableRefresh = false, disableInfinity = false, - lookback, customProps }) => { const { colors } = useTheme() + const queryClient = useQueryClient() const { data, refetch, isFetching, isLoading, + fetchPreviousPage, fetchNextPage, + isFetchingPreviousPage, isFetchingNextPage } = useTimelineQuery({ ...queryKey[1], @@ -65,6 +57,12 @@ const Timeline: React.FC = ({ ios: ['dataUpdatedAt', 'isFetching'], android: ['dataUpdatedAt', 'isFetching', 'isLoading'] }), + getPreviousPageParam: firstPage => + firstPage?.links?.prev && { + min_id: firstPage.links.prev, + // https://github.com/facebook/react-native/issues/25239 + limit: '10' + }, getNextPageParam: lastPage => lastPage?.links?.next && { max_id: lastPage.links.next @@ -93,26 +91,6 @@ const Timeline: React.FC = ({ ) const flRef = useRef(null) - const scrollY = useSharedValue(0) - const fetchingType = useSharedValue<0 | 1 | 2>(0) - - const onScroll = useAnimatedScrollHandler( - { - onScroll: ({ contentOffset: { y } }) => { - scrollY.value = y - }, - onEndDrag: ({ contentOffset: { y } }) => { - if (!disableRefresh && !isFetching) { - if (y <= SEPARATION_Y_2) { - fetchingType.value = 2 - } else if (y <= SEPARATION_Y_1) { - fetchingType.value = 1 - } - } - } - }, - [isFetching] - ) const androidRefreshControl = Platform.select({ android: { @@ -128,27 +106,6 @@ const Timeline: React.FC = ({ } }) - const dispatch = useAppDispatch() - const viewabilityPairs = useRef([ - { - viewabilityConfig: { - minimumViewTime: 10, - viewAreaCoveragePercentThreshold: 10 - }, - onViewableItemsChanged: ({ viewableItems }) => { - lookback && - dispatch( - updateInstanceTimelineLookback({ - [lookback]: { - queryKey, - ids: viewableItems.map(item => item.key).slice(0, 3) - } - }) - ) - } - } - ]) - useScrollToTop(flRef) useSelector(getInstanceActive, (prev, next) => { if (prev !== next) { @@ -158,43 +115,44 @@ const Timeline: React.FC = ({ }) return ( - <> - - + + } + ListEmptyComponent={} + ItemSeparatorComponent={ItemSeparatorComponent} + maintainVisibleContentPosition={{ minIndexForVisible: 0 }} + refreshing={isFetchingPreviousPage} + onRefresh={() => { + if (!disableRefresh && !isFetchingPreviousPage) { + queryClient.setQueryData | undefined>( + queryKey, + data => { + if (data?.pages[0] && data.pages[0].body.length === 0) { + return { + pages: data.pages.slice(1), + pageParams: data.pageParams.slice(1) + } + } else { + return data + } + } + ) + fetchPreviousPage() } - ListEmptyComponent={} - ItemSeparatorComponent={ItemSeparatorComponent} - maintainVisibleContentPosition={{ - minIndexForVisible: 0 - }} - {...(lookback && { - viewabilityConfigCallbackPairs: viewabilityPairs.current - })} - {...androidRefreshControl} - {...customProps} - /> - + }} + {...androidRefreshControl} + {...customProps} + /> ) } diff --git a/src/components/Timeline/Lookback.tsx b/src/components/Timeline/Lookback.tsx deleted file mode 100644 index aaa9ee2e..00000000 --- a/src/components/Timeline/Lookback.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import CustomText from '@components/Text' -import { StyleConstants } from '@utils/styles/constants' -import { useTheme } from '@utils/styles/ThemeManager' -import React from 'react' -import { useTranslation } from 'react-i18next' -import { View } from 'react-native' - -const TimelineLookback = React.memo( - () => { - const { t } = useTranslation('componentTimeline') - const { colors } = useTheme() - - return ( - - - {t('lookback.message')} - - - ) - }, - () => true -) - -export default TimelineLookback diff --git a/src/components/Timeline/Refresh.tsx b/src/components/Timeline/Refresh.tsx deleted file mode 100644 index 71b0d266..00000000 --- a/src/components/Timeline/Refresh.tsx +++ /dev/null @@ -1,328 +0,0 @@ -import haptics from '@components/haptics' -import Icon from '@components/Icon' -import CustomText from '@components/Text' -import { - QueryKeyTimeline, - TimelineData, - useTimelineQuery -} from '@utils/queryHooks/timeline' -import { StyleConstants } from '@utils/styles/constants' -import { useTheme } from '@utils/styles/ThemeManager' -import React, { RefObject, useCallback, useRef, useState } from 'react' -import { useTranslation } from 'react-i18next' -import { FlatList, Platform, View } from 'react-native' -import { Circle } from 'react-native-animated-spinkit' -import Animated, { - Extrapolate, - interpolate, - runOnJS, - useAnimatedReaction, - useAnimatedStyle, - useSharedValue, - withTiming -} from 'react-native-reanimated' -import { InfiniteData, useQueryClient } from 'react-query' - -export interface Props { - flRef: RefObject> - queryKey: QueryKeyTimeline - scrollY: Animated.SharedValue - fetchingType: Animated.SharedValue<0 | 1 | 2> - disableRefresh?: boolean -} - -const CONTAINER_HEIGHT = StyleConstants.Spacing.M * 2.5 -export const SEPARATION_Y_1 = -( - CONTAINER_HEIGHT / 2 + - StyleConstants.Font.Size.S / 2 -) -export const SEPARATION_Y_2 = -( - CONTAINER_HEIGHT * 1.5 + - StyleConstants.Font.Size.S / 2 -) - -const TimelineRefresh: React.FC = ({ - flRef, - queryKey, - scrollY, - fetchingType, - disableRefresh = false -}) => { - if (Platform.OS !== 'ios') { - return null - } - if (disableRefresh) { - return null - } - - const fetchingLatestIndex = useRef(0) - const refetchActive = useRef(false) - - const { - refetch, - isFetching, - isLoading, - fetchPreviousPage, - hasPreviousPage, - isFetchingNextPage - } = useTimelineQuery({ - ...queryKey[1], - options: { - getPreviousPageParam: firstPage => - firstPage?.links?.prev && { - min_id: firstPage.links.prev, - // https://github.com/facebook/react-native/issues/25239#issuecomment-731100372 - limit: '5' - }, - select: data => { - if (refetchActive.current) { - data.pageParams = [data.pageParams[0]] - data.pages = [data.pages[0]] - refetchActive.current = false - } - return data - }, - onSuccess: () => { - if (fetchingLatestIndex.current > 0) { - if (fetchingLatestIndex.current > 5) { - clearFirstPage() - fetchingLatestIndex.current = 0 - } else { - if (hasPreviousPage) { - fetchPreviousPage() - fetchingLatestIndex.current++ - } else { - clearFirstPage() - fetchingLatestIndex.current = 0 - } - } - } - } - } - }) - - const { t } = useTranslation('componentTimeline') - const { colors } = useTheme() - - const queryClient = useQueryClient() - const clearFirstPage = () => { - queryClient.setQueryData | undefined>( - queryKey, - data => { - if (data?.pages[0] && data.pages[0].body.length === 0) { - return { - pages: data.pages.slice(1), - pageParams: data.pageParams.slice(1) - } - } else { - return data - } - } - ) - } - const prepareRefetch = () => { - refetchActive.current = true - queryClient.setQueryData | 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 arrowY = useAnimatedStyle(() => ({ - transform: [ - { - translateY: interpolate( - scrollY.value, - [0, SEPARATION_Y_1], - [ - -CONTAINER_HEIGHT / 2 - StyleConstants.Font.Size.M / 2, - CONTAINER_HEIGHT / 2 - StyleConstants.Font.Size.S / 2 - ], - Extrapolate.CLAMP - ) - } - ] - })) - const arrowTop = useAnimatedStyle(() => ({ - marginTop: - scrollY.value < SEPARATION_Y_2 - ? withTiming(CONTAINER_HEIGHT) - : withTiming(0) - })) - - const arrowStage = useSharedValue(0) - const onLayout = useCallback( - ({ nativeEvent }) => { - if (nativeEvent.layout.x + nativeEvent.layout.width > textRight) { - setTextRight(nativeEvent.layout.x + nativeEvent.layout.width) - } - }, - [textRight] - ) - useAnimatedReaction( - () => { - if (isFetching) { - return false - } - switch (arrowStage.value) { - case 0: - if (scrollY.value < SEPARATION_Y_1) { - arrowStage.value = 1 - return true - } - return false - case 1: - if (scrollY.value < SEPARATION_Y_2) { - arrowStage.value = 2 - return true - } - if (scrollY.value > SEPARATION_Y_1) { - arrowStage.value = 0 - return false - } - return false - case 2: - if (scrollY.value > SEPARATION_Y_2) { - arrowStage.value = 1 - return false - } - return false - } - }, - data => { - if (data) { - runOnJS(haptics)('Light') - } - }, - [isFetching] - ) - const wrapperStartLatest = () => { - fetchingLatestIndex.current = 1 - } - - useAnimatedReaction( - () => { - return fetchingType.value - }, - data => { - fetchingType.value = 0 - switch (data) { - case 1: - runOnJS(wrapperStartLatest)() - runOnJS(clearFirstPage)() - runOnJS(fetchPreviousPage)() - break - case 2: - runOnJS(prepareRefetch)() - runOnJS(callRefetch)() - break - } - }, - [] - ) - - const headerPadding = useAnimatedStyle( - () => ({ - paddingTop: - fetchingLatestIndex.current !== 0 || - (isFetching && !isLoading && !isFetchingNextPage) - ? withTiming(StyleConstants.Spacing.M * 2.5) - : withTiming(0) - }), - [fetchingLatestIndex.current, isFetching, isFetchingNextPage, isLoading] - ) - - return ( - - - {isFetching ? ( - - - - ) : ( - <> - - - - } - /> - - - - - - )} - - - ) -} - -export default TimelineRefresh From 9c3e8f58b092c0af5864d03f1862802a504398f1 Mon Sep 17 00:00:00 2001 From: Zhiyuan Zheng Date: Thu, 12 May 2022 00:10:10 +0200 Subject: [PATCH 2/2] Bump up packages --- ios/Podfile.lock | 4 ++-- package.json | 6 +++--- yarn.lock | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index e7cfa6cf..4d3e9684 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -31,7 +31,7 @@ PODS: - EXJSONUtils - EXNotifications (0.15.2): - ExpoModulesCore - - Expo (45.0.2): + - Expo (45.0.3): - ExpoModulesCore - ExpoCrypto (10.2.0): - ExpoModulesCore @@ -849,7 +849,7 @@ SPEC CHECKSUMS: EXJSONUtils: 2a74b8f40f1523cc3f92af99c91aa78201737a77 EXManifests: 0c6134b7b6f3236a93a778c3f44ba1cfb3f9fa3d EXNotifications: ea9fc56d27d1fee229489c5d8f452c7f367c237e - Expo: 27c7466cea6c8be416d8e50a0c0faa48cf8b4d1a + Expo: 353cd6d2154838c0c8bb1072d3ac89eb535a2ef4 ExpoCrypto: d0d0f3e20875dc450b4ec88f0fb608da5c2c6c17 ExpoHaptics: ad58ec96a25e57579c14a47c7d71f0de0de8656a ExpoImageManipulator: b55580bbc7b10099c7707949903e7176a8542ee8 diff --git a/package.json b/package.json index 3e0f68fe..903d8483 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@sentry/react-native": "3.4.2", "@sharcoux/slider": "6.0.3", "axios": "0.27.2", - "expo": "45.0.2", + "expo": "45.0.3", "expo-auth-session": "3.6.0", "expo-av": "11.2.3", "expo-constants": "^13.1.1", @@ -68,7 +68,7 @@ "expo-updates": "0.13.1", "expo-video-thumbnails": "6.3.0", "expo-web-browser": "10.2.0", - "i18next": "21.8.0", + "i18next": "21.8.1", "li": "1.3.0", "lodash": "4.17.21", "react": "17.0.2", @@ -118,7 +118,7 @@ "babel-plugin-module-resolver": "4.1.0", "babel-plugin-transform-remove-console": "6.9.4", "chalk": "4.1.2", - "dotenv": "16.0.0", + "dotenv": "16.0.1", "patch-package": "6.4.7", "postinstall-postinstall": "2.1.0", "react-native-clean-project": "4.0.1", diff --git a/yarn.lock b/yarn.lock index 01bd1287..dc98f89d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3902,10 +3902,10 @@ domutils@^2.8.0: domelementtype "^2.2.0" domhandler "^4.2.0" -dotenv@16.0.0: - version "16.0.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.0.tgz#c619001253be89ebb638d027b609c75c26e47411" - integrity sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q== +dotenv@16.0.1: + version "16.0.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d" + integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== ee-first@1.1.1: version "1.1.1" @@ -4372,10 +4372,10 @@ expo-web-browser@10.2.0, expo-web-browser@~10.2.0: dependencies: compare-urls "^2.0.0" -expo@45.0.2: - version "45.0.2" - resolved "https://registry.yarnpkg.com/expo/-/expo-45.0.2.tgz#d773d1b6f427bcdbfcb3da26274b35b2749c632c" - integrity sha512-WRVNTEc2ZqstGwVIxCAfJUTsmhFVAWR4vNaF4kTDEQa2J5GHbFuSQbENYrTeLldLc5Q/60HX3xfxUu8pqqdjGA== +expo@45.0.3: + version "45.0.3" + resolved "https://registry.yarnpkg.com/expo/-/expo-45.0.3.tgz#7682b4dd29c6ec9de440bc151c3aa43ec392ec6e" + integrity sha512-xI22uW8ekA5152mcN1bgXLFOFO0a2eafHr0Kgq80BvV6MyYbkZS3M8trtjo9Cs6LVMMVgyc0MWI/2cd5sGjMgg== dependencies: "@babel/runtime" "^7.14.0" "@expo/cli" "0.1.4" @@ -5028,10 +5028,10 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -i18next@21.8.0: - version "21.8.0" - resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.8.0.tgz#2ad46a882fe1b793e499c47a934bb115b7c618b3" - integrity sha512-opNd7cQj0PDlUX15hPjtzReRxy5/Rn405YvHTBEm1nf1YJhsqYFFFhHMwuU4NEHZNlrepHk5uK+CJbFtB+KO3w== +i18next@21.8.1: + version "21.8.1" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.8.1.tgz#44e083ade3dfe08c8099882c560d3c7294cdf679" + integrity sha512-uulZBD5kLME7Ucz8pFwpC7jXDjq4BHkio3b6GBw1ykXNHA8rIAk1S2t6zb2Ripf9OMetMkysiDRlPlCVqjvQeg== dependencies: "@babel/runtime" "^7.17.2"