mirror of
				https://github.com/tooot-app/app
				synced 2025-06-05 22:19:13 +02:00 
			
		
		
		
	Retry refresh
This commit is contained in:
		| @@ -50,14 +50,12 @@ const Timeline: React.FC<Props> = ({ | |||||||
|     status, |     status, | ||||||
|     data, |     data, | ||||||
|     refetch, |     refetch, | ||||||
|     isFetching, |  | ||||||
|     isSuccess, |     isSuccess, | ||||||
|     hasPreviousPage, |     hasPreviousPage, | ||||||
|     fetchPreviousPage, |     fetchPreviousPage, | ||||||
|     isFetchingPreviousPage, |     isFetchingPreviousPage, | ||||||
|     hasNextPage, |     hasNextPage, | ||||||
|     fetchNextPage, |     fetchNextPage | ||||||
|     isFetchingNextPage |  | ||||||
|   } = useInfiniteQuery(queryKey, timelineFetch, { |   } = useInfiniteQuery(queryKey, timelineFetch, { | ||||||
|     getPreviousPageParam: firstPage => { |     getPreviousPageParam: firstPage => { | ||||||
|       return firstPage.toots.length |       return firstPage.toots.length | ||||||
| @@ -67,7 +65,7 @@ const Timeline: React.FC<Props> = ({ | |||||||
|           } |           } | ||||||
|         : undefined |         : undefined | ||||||
|     }, |     }, | ||||||
|     getNextPageParam: (lastPage, all) => { |     getNextPageParam: lastPage => { | ||||||
|       return lastPage.toots.length |       return lastPage.toots.length | ||||||
|         ? { |         ? { | ||||||
|             direction: 'next', |             direction: 'next', | ||||||
| @@ -96,8 +94,8 @@ const Timeline: React.FC<Props> = ({ | |||||||
|     } |     } | ||||||
|   }, [isSuccess]) |   }, [isSuccess]) | ||||||
|  |  | ||||||
|   const flKeyExtrator = useCallback(({ id }) => id, []) |   const keyExtractor = useCallback(({ id }) => id, []) | ||||||
|   const flRenderItem = useCallback( |   const renderItem = useCallback( | ||||||
|     ({ item, index }) => { |     ({ item, index }) => { | ||||||
|       switch (page) { |       switch (page) { | ||||||
|         case 'Conversations': |         case 'Conversations': | ||||||
| @@ -123,7 +121,7 @@ const Timeline: React.FC<Props> = ({ | |||||||
|     }, |     }, | ||||||
|     [flattenPinnedLength[0]] |     [flattenPinnedLength[0]] | ||||||
|   ) |   ) | ||||||
|   const flItemSeparatorComponent = useCallback( |   const ItemSeparatorComponent = useCallback( | ||||||
|     ({ leadingItem }) => ( |     ({ leadingItem }) => ( | ||||||
|       <TimelineSeparator |       <TimelineSeparator | ||||||
|         {...(toot && toot.id === leadingItem.id && { highlighted: true })} |         {...(toot && toot.id === leadingItem.id && { highlighted: true })} | ||||||
| @@ -135,27 +133,19 @@ const Timeline: React.FC<Props> = ({ | |||||||
|     () => <TimelineEmpty status={status} refetch={refetch} />, |     () => <TimelineEmpty status={status} refetch={refetch} />, | ||||||
|     [status] |     [status] | ||||||
|   ) |   ) | ||||||
|   const flOnRefresh = useCallback(() => { |   const onEndReached = useCallback(() => fetchNextPage(), []) | ||||||
|     !disableRefresh && |   const ListFooterComponent = useCallback( | ||||||
|       (hasPreviousPage |     () => <TimelineEnd hasNextPage={hasNextPage} />, | ||||||
|         ? fetchPreviousPage() |  | ||||||
|         : !isFetching |  | ||||||
|         ? refetch() |  | ||||||
|         : undefined) |  | ||||||
|   }, [hasPreviousPage, isFetching]) |  | ||||||
|   const flOnEndReach = useCallback(() => !disableRefresh && fetchNextPage(), []) |  | ||||||
|   const flFooter = useCallback( |  | ||||||
|     () => (!disableRefresh ? <TimelineEnd hasNextPage={hasNextPage} /> : null), |  | ||||||
|     [hasNextPage] |     [hasNextPage] | ||||||
|   ) |   ) | ||||||
|   const flRefreshControl = useMemo( |   const refreshControl = useMemo( | ||||||
|     () => ( |     () => ( | ||||||
|       <RefreshControl |       <RefreshControl | ||||||
|         refreshing={isFetchingPreviousPage || isFetching} |         refreshing={isFetchingPreviousPage} | ||||||
|         onRefresh={flOnRefresh} |         onRefresh={() => fetchPreviousPage()} | ||||||
|       /> |       /> | ||||||
|     ), |     ), | ||||||
|     [isFetchingPreviousPage, isFetching] |     [isFetchingPreviousPage] | ||||||
|   ) |   ) | ||||||
|   const onScrollToIndexFailed = useCallback(error => { |   const onScrollToIndexFailed = useCallback(error => { | ||||||
|     const offset = error.averageItemLength * error.index |     const offset = error.averageItemLength * error.index | ||||||
| @@ -177,14 +167,14 @@ const Timeline: React.FC<Props> = ({ | |||||||
|       initialNumToRender={5} |       initialNumToRender={5} | ||||||
|       maxToRenderPerBatch={5} |       maxToRenderPerBatch={5} | ||||||
|       style={styles.flatList} |       style={styles.flatList} | ||||||
|       renderItem={flRenderItem} |       renderItem={renderItem} | ||||||
|       onEndReached={flOnEndReach} |       onEndReached={onEndReached} | ||||||
|       keyExtractor={flKeyExtrator} |       keyExtractor={keyExtractor} | ||||||
|       ListFooterComponent={flFooter} |       onEndReachedThreshold={0.75} | ||||||
|       refreshControl={flRefreshControl} |       ListFooterComponent={ListFooterComponent} | ||||||
|       ListEmptyComponent={flItemEmptyComponent} |       ListEmptyComponent={flItemEmptyComponent} | ||||||
|       ItemSeparatorComponent={flItemSeparatorComponent} |       {...(!disableRefresh && { refreshControl })} | ||||||
|       onEndReachedThreshold={!disableRefresh ? 0.75 : null} |       ItemSeparatorComponent={ItemSeparatorComponent} | ||||||
|       {...(toot && isSuccess && { onScrollToIndexFailed })} |       {...(toot && isSuccess && { onScrollToIndexFailed })} | ||||||
|     /> |     /> | ||||||
|   ) |   ) | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ const TimelineAvatar: React.FC<Props> = ({ queryKey, account }) => { | |||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <Pressable style={styles.avatar} onPress={onPress}> |     <Pressable style={styles.avatar} onPress={onPress}> | ||||||
|       <Image source={{ uri: account.avatar }} style={styles.image} /> |       <Image source={{ uri: account.avatar_static }} style={styles.image} /> | ||||||
|     </Pressable> |     </Pressable> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| import React, { useRef, useState } from 'react' | import React, { useRef, useState } from 'react' | ||||||
| import { Animated, ScrollView } from 'react-native' | import { Animated, LayoutAnimation, ScrollView } from 'react-native' | ||||||
| import { useSelector } from 'react-redux' | import { useSelector } from 'react-redux' | ||||||
|  |  | ||||||
| import { getLocalUrl } from '@utils/slices/instancesSlice' | import { getLocalUrl } from '@utils/slices/instancesSlice' | ||||||
| @@ -14,6 +14,7 @@ import { AccountState } from '../Shared/Account' | |||||||
| import AccountNav from '../Shared/Account/Nav' | import AccountNav from '../Shared/Account/Nav' | ||||||
|  |  | ||||||
| const ScreenMeRoot: React.FC = () => { | const ScreenMeRoot: React.FC = () => { | ||||||
|  |   LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) | ||||||
|   const localRegistered = useSelector(getLocalUrl) |   const localRegistered = useSelector(getLocalUrl) | ||||||
|  |  | ||||||
|   const scrollRef = useRef<ScrollView>(null) |   const scrollRef = useRef<ScrollView>(null) | ||||||
|   | |||||||
| @@ -28,7 +28,7 @@ const MyInfo: React.FC<Props> = ({ setData }) => { | |||||||
|         account={data} |         account={data} | ||||||
|         limitHeight |         limitHeight | ||||||
|       /> |       /> | ||||||
|       <AccountInformation account={data} /> |       <AccountInformation account={data} disableActions /> | ||||||
|     </> |     </> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| import React, { useEffect, useReducer, useRef, useState } from 'react' | import React, { useEffect, useReducer, useRef, useState } from 'react' | ||||||
| import { Animated, ScrollView } from 'react-native' | import { Animated, LayoutAnimation, ScrollView } from 'react-native' | ||||||
|  |  | ||||||
| import { useQuery } from 'react-query' | import { useQuery } from 'react-query' | ||||||
| import { accountFetch } from '@utils/fetches/accountFetch' | import { accountFetch } from '@utils/fetches/accountFetch' | ||||||
| @@ -73,10 +73,10 @@ const ScreenSharedAccount: React.FC<Props> = ({ | |||||||
|   }, |   }, | ||||||
|   navigation |   navigation | ||||||
| }) => { | }) => { | ||||||
|  |   LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) | ||||||
|   const localAccountId = useSelector(getLocalAccountId) |   const localAccountId = useSelector(getLocalAccountId) | ||||||
|   const { data } = useQuery(['Account', { id: account.id }], accountFetch) |   const { data } = useQuery(['Account', { id: account.id }], accountFetch) | ||||||
|  |  | ||||||
|   // const stateRelationships = useSelector(relationshipsState) |  | ||||||
|   const scrollY = useRef(new Animated.Value(0)).current |   const scrollY = useRef(new Animated.Value(0)).current | ||||||
|   const [accountState, accountDispatch] = useReducer( |   const [accountState, accountDispatch] = useReducer( | ||||||
|     accountReducer, |     accountReducer, | ||||||
| @@ -104,11 +104,14 @@ const ScreenSharedAccount: React.FC<Props> = ({ | |||||||
|         scrollY={scrollY} |         scrollY={scrollY} | ||||||
|         account={data} |         account={data} | ||||||
|       /> |       /> | ||||||
|  |       {accountState.informationLayout?.height && | ||||||
|  |       accountState.informationLayout.y ? ( | ||||||
|         <AccountSegmentedControl |         <AccountSegmentedControl | ||||||
|           accountState={accountState} |           accountState={accountState} | ||||||
|           accountDispatch={accountDispatch} |           accountDispatch={accountDispatch} | ||||||
|           scrollY={scrollY} |           scrollY={scrollY} | ||||||
|         /> |         /> | ||||||
|  |       ) : null} | ||||||
|       <ScrollView |       <ScrollView | ||||||
|         bounces={false} |         bounces={false} | ||||||
|         onScroll={Animated.event( |         onScroll={Animated.event( | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| import React, { Dispatch, useEffect, useRef, useState } from 'react' | import React, { Dispatch, useEffect, useState } from 'react' | ||||||
| import { Animated, Dimensions, Image, StyleSheet } from 'react-native' | import { Dimensions, Image, StyleSheet, View } from 'react-native' | ||||||
| import { AccountAction, AccountState } from '../Account' | import { AccountAction, AccountState } from '../Account' | ||||||
|  |  | ||||||
| export interface Props { | export interface Props { | ||||||
| @@ -15,19 +15,14 @@ const AccountHeader: React.FC<Props> = ({ | |||||||
|   account, |   account, | ||||||
|   limitHeight = false |   limitHeight = false | ||||||
| }) => { | }) => { | ||||||
|   const [imageShown, setImageShown] = useState(true) |   const [ratio, setRatio] = useState(accountState.headerRatio) | ||||||
|  |  | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     if (account?.header) { |     if ( | ||||||
|       if (account.header.includes('/headers/original/missing.png')) { |       account?.header && | ||||||
|         animateNewSize(accountState.headerRatio) |       !account.header.includes('/headers/original/missing.png') | ||||||
|       } else { |     ) { | ||||||
|         if (account.header !== account.header_static) { |       Image.getSize(account.header, (width, height) => { | ||||||
|           setImageShown(false) |  | ||||||
|         } |  | ||||||
|         Image.getSize( |  | ||||||
|           account.header, |  | ||||||
|           (width, height) => { |  | ||||||
|         if (!limitHeight) { |         if (!limitHeight) { | ||||||
|           accountDispatch && |           accountDispatch && | ||||||
|             accountDispatch({ |             accountDispatch({ | ||||||
| @@ -35,42 +30,17 @@ const AccountHeader: React.FC<Props> = ({ | |||||||
|               payload: height / width |               payload: height / width | ||||||
|             }) |             }) | ||||||
|         } |         } | ||||||
|             animateNewSize( |         setRatio(limitHeight ? accountState.headerRatio : height / width) | ||||||
|               limitHeight ? accountState.headerRatio : height / width |       }) | ||||||
|             ) |  | ||||||
|           }, |  | ||||||
|           () => { |  | ||||||
|             animateNewSize(accountState.headerRatio) |  | ||||||
|           } |  | ||||||
|         ) |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|   }, [account]) |   }, [account]) | ||||||
|  |  | ||||||
|   const theImage = imageShown ? ( |  | ||||||
|     <Image source={{ uri: account?.header }} style={styles.image} /> |  | ||||||
|   ) : null |  | ||||||
|  |  | ||||||
|   const windowWidth = Dimensions.get('window').width |   const windowWidth = Dimensions.get('window').width | ||||||
|   const imageHeight = useRef( |  | ||||||
|     new Animated.Value(windowWidth * accountState.headerRatio) |  | ||||||
|   ).current |  | ||||||
|   const animateNewSize = (ratio: number) => { |  | ||||||
|     Animated.timing(imageHeight, { |  | ||||||
|       toValue: windowWidth * ratio, |  | ||||||
|       duration: 350, |  | ||||||
|       useNativeDriver: false |  | ||||||
|     }).start(({ finished }) => { |  | ||||||
|       if (finished) { |  | ||||||
|         setImageShown(true) |  | ||||||
|       } |  | ||||||
|     }) |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <Animated.View style={[styles.imageContainer, { height: imageHeight }]}> |     <View style={[styles.imageContainer, { height: windowWidth * ratio }]}> | ||||||
|       {theImage} |       <Image source={{ uri: account?.header }} style={styles.image} /> | ||||||
|     </Animated.View> |     </View> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -49,9 +49,14 @@ const fireMutation = async ({ | |||||||
| export interface Props { | export interface Props { | ||||||
|   accountDispatch?: Dispatch<AccountAction> |   accountDispatch?: Dispatch<AccountAction> | ||||||
|   account: Mastodon.Account | undefined |   account: Mastodon.Account | undefined | ||||||
|  |   disableActions?: boolean | ||||||
| } | } | ||||||
|  |  | ||||||
| const AccountInformation: React.FC<Props> = ({ accountDispatch, account }) => { | const AccountInformation: React.FC<Props> = ({ | ||||||
|  |   accountDispatch, | ||||||
|  |   account, | ||||||
|  |   disableActions = false | ||||||
|  | }) => { | ||||||
|   const navigation = useNavigation() |   const navigation = useNavigation() | ||||||
|   const { t } = useTranslation('sharedAccount') |   const { t } = useTranslation('sharedAccount') | ||||||
|   const { theme } = useTheme() |   const { theme } = useTheme() | ||||||
| @@ -165,6 +170,7 @@ const AccountInformation: React.FC<Props> = ({ accountDispatch, account }) => { | |||||||
|             onLoadEnd={() => setAvatarLoaded(true)} |             onLoadEnd={() => setAvatarLoaded(true)} | ||||||
|           /> |           /> | ||||||
|         </ShimmerPlaceholder> |         </ShimmerPlaceholder> | ||||||
|  |         {!disableActions && ( | ||||||
|           <View style={styles.actions}> |           <View style={styles.actions}> | ||||||
|             <ButtonRow |             <ButtonRow | ||||||
|               icon='mail' |               icon='mail' | ||||||
| @@ -181,6 +187,7 @@ const AccountInformation: React.FC<Props> = ({ accountDispatch, account }) => { | |||||||
|             /> |             /> | ||||||
|             {followingButton} |             {followingButton} | ||||||
|           </View> |           </View> | ||||||
|  |         )} | ||||||
|       </View> |       </View> | ||||||
|  |  | ||||||
|       <ShimmerPlaceholder |       <ShimmerPlaceholder | ||||||
|   | |||||||
| @@ -35,7 +35,8 @@ const AccountSegmentedControl: React.FC<Props> = ({ | |||||||
|         (accountState.informationLayout?.height || 0) + |         (accountState.informationLayout?.height || 0) + | ||||||
|         headerHeight |         headerHeight | ||||||
|     ], |     ], | ||||||
|     extrapolate: 'clamp' |     extrapolate: 'clamp', | ||||||
|  |     easing: undefined | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ import { | |||||||
|   Alert, |   Alert, | ||||||
|   Keyboard, |   Keyboard, | ||||||
|   KeyboardAvoidingView, |   KeyboardAvoidingView, | ||||||
|  |   LayoutAnimation, | ||||||
|   StyleSheet, |   StyleSheet, | ||||||
|   Text, |   Text, | ||||||
|   TextInput |   TextInput | ||||||
| @@ -330,6 +331,7 @@ export interface Props { | |||||||
| } | } | ||||||
|  |  | ||||||
| const Compose: React.FC<Props> = ({ route: { params }, navigation }) => { | const Compose: React.FC<Props> = ({ route: { params }, navigation }) => { | ||||||
|  |   LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) | ||||||
|   const { theme } = useTheme() |   const { theme } = useTheme() | ||||||
|   const queryClient = useQueryClient() |   const queryClient = useQueryClient() | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user