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