From bc31da47fdcb4c1704c96b0083f8e5429475da4e Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 21 Dec 2023 22:56:45 +0000 Subject: [PATCH] Consolidate List props a bit (#2216) --- src/view/com/feeds/ProfileFeedgens.tsx | 23 ++----- src/view/com/lists/ListMembers.tsx | 17 +---- src/view/com/lists/MyLists.tsx | 70 +++++++++++++-------- src/view/com/lists/ProfileLists.tsx | 23 ++----- src/view/com/notifications/Feed.tsx | 14 +---- src/view/com/post-thread/PostLikedBy.tsx | 14 +---- src/view/com/post-thread/PostRepostedBy.tsx | 14 +---- src/view/com/post-thread/PostThread.tsx | 11 +--- src/view/com/posts/Feed.tsx | 17 +---- src/view/com/profile/ProfileFollowers.tsx | 14 +---- src/view/com/profile/ProfileFollows.tsx | 14 +---- src/view/com/util/List.tsx | 45 ++++++++++++- src/view/screens/Feeds.tsx | 12 +--- src/view/screens/Search/Search.tsx | 12 +--- 14 files changed, 123 insertions(+), 177 deletions(-) diff --git a/src/view/com/feeds/ProfileFeedgens.tsx b/src/view/com/feeds/ProfileFeedgens.tsx index ff650550..8665fbfa 100644 --- a/src/view/com/feeds/ProfileFeedgens.tsx +++ b/src/view/com/feeds/ProfileFeedgens.tsx @@ -1,12 +1,5 @@ import React from 'react' -import { - Dimensions, - RefreshControl, - StyleProp, - StyleSheet, - View, - ViewStyle, -} from 'react-native' +import {Dimensions, StyleProp, StyleSheet, View, ViewStyle} from 'react-native' import {useQueryClient} from '@tanstack/react-query' import {List, ListRef} from '../util/List' import {FeedSourceCardLoaded} from './FeedSourceCard' @@ -180,22 +173,14 @@ export const ProfileFeedgens = React.forwardRef< data={items} keyExtractor={(item: any) => item._reactKey || item.uri} renderItem={renderItemInner} - refreshControl={ - - } + refreshing={isPTRing} + onRefresh={onRefresh} + headerOffset={headerOffset} contentContainerStyle={{ minHeight: Dimensions.get('window').height * 1.5, }} - style={{paddingTop: headerOffset}} indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'} removeClippedSubviews={true} - contentOffset={{x: 0, y: headerOffset * -1}} // @ts-ignore our .web version only -prf desktopFixedHeight onEndReached={onEndReached} diff --git a/src/view/com/lists/ListMembers.tsx b/src/view/com/lists/ListMembers.tsx index a31ca479..2aef7d76 100644 --- a/src/view/com/lists/ListMembers.tsx +++ b/src/view/com/lists/ListMembers.tsx @@ -2,7 +2,6 @@ import React from 'react' import { ActivityIndicator, Dimensions, - RefreshControl, StyleProp, View, ViewStyle, @@ -15,7 +14,6 @@ import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {ProfileCard} from '../profile/ProfileCard' import {Button} from '../util/forms/Button' import {useAnalytics} from 'lib/analytics/analytics' -import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useListMembersQuery} from '#/state/queries/list-members' import {logger} from '#/logger' @@ -51,7 +49,6 @@ export function ListMembers({ headerOffset?: number desktopFixedHeightOffset?: number }) { - const pal = usePalette('default') const {track} = useAnalytics() const [isRefreshing, setIsRefreshing] = React.useState(false) const {isMobile} = useWebMediaQueries() @@ -215,24 +212,16 @@ export function ListMembers({ renderItem={renderItem} ListHeaderComponent={renderHeader} ListFooterComponent={Footer} - refreshControl={ - - } + refreshing={isRefreshing} + onRefresh={onRefresh} + headerOffset={headerOffset} contentContainerStyle={{ minHeight: Dimensions.get('window').height * 1.5, }} - style={{paddingTop: headerOffset}} onScrolledDownChange={onScrolledDownChange} onEndReached={onEndReached} onEndReachedThreshold={0.6} removeClippedSubviews={true} - contentOffset={{x: 0, y: headerOffset * -1}} // @ts-ignore our .web version only -prf desktopFixedHeight={desktopFixedHeightOffset || true} /> diff --git a/src/view/com/lists/MyLists.tsx b/src/view/com/lists/MyLists.tsx index 586ad234..a2a6b065 100644 --- a/src/view/com/lists/MyLists.tsx +++ b/src/view/com/lists/MyLists.tsx @@ -119,31 +119,51 @@ export function MyLists({ [error, onRefresh, renderItem, pal], ) - const FlatListCom = inline ? RNFlatList : List - return ( - - {items.length > 0 && ( - (item.uri ? item.uri : item._reactKey)} - renderItem={renderItemInner} - refreshControl={ - - } - contentContainerStyle={[s.contentContainer]} - removeClippedSubviews={true} - // @ts-ignore our .web version only -prf - desktopFixedHeight - /> - )} - - ) + if (inline) { + return ( + + {items.length > 0 && ( + (item.uri ? item.uri : item._reactKey)} + renderItem={renderItemInner} + refreshControl={ + + } + contentContainerStyle={[s.contentContainer]} + removeClippedSubviews={true} + // @ts-ignore our .web version only -prf + desktopFixedHeight + /> + )} + + ) + } else { + return ( + + {items.length > 0 && ( + (item.uri ? item.uri : item._reactKey)} + renderItem={renderItemInner} + refreshing={isPTRing} + onRefresh={onRefresh} + contentContainerStyle={[s.contentContainer]} + removeClippedSubviews={true} + // @ts-ignore our .web version only -prf + desktopFixedHeight + /> + )} + + ) + } } const styles = StyleSheet.create({ diff --git a/src/view/com/lists/ProfileLists.tsx b/src/view/com/lists/ProfileLists.tsx index e3d9bd0b..db981717 100644 --- a/src/view/com/lists/ProfileLists.tsx +++ b/src/view/com/lists/ProfileLists.tsx @@ -1,12 +1,5 @@ import React from 'react' -import { - Dimensions, - RefreshControl, - StyleProp, - StyleSheet, - View, - ViewStyle, -} from 'react-native' +import {Dimensions, StyleProp, StyleSheet, View, ViewStyle} from 'react-native' import {useQueryClient} from '@tanstack/react-query' import {List, ListRef} from '../util/List' import {ListCard} from './ListCard' @@ -182,22 +175,14 @@ export const ProfileLists = React.forwardRef( data={items} keyExtractor={(item: any) => item._reactKey} renderItem={renderItemInner} - refreshControl={ - - } + refreshing={isPTRing} + onRefresh={onRefresh} + headerOffset={headerOffset} contentContainerStyle={{ minHeight: Dimensions.get('window').height * 1.5, }} - style={{paddingTop: headerOffset}} indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'} removeClippedSubviews={true} - contentOffset={{x: 0, y: headerOffset * -1}} // @ts-ignore our .web version only -prf desktopFixedHeight onEndReached={onEndReached} diff --git a/src/view/com/notifications/Feed.tsx b/src/view/com/notifications/Feed.tsx index 52d534c4..a99fe2c1 100644 --- a/src/view/com/notifications/Feed.tsx +++ b/src/view/com/notifications/Feed.tsx @@ -1,13 +1,12 @@ import React from 'react' import {CenteredView} from '../util/Views' -import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' +import {ActivityIndicator, StyleSheet, View} from 'react-native' import {FeedItem} from './FeedItem' import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' import {ErrorMessage} from '../util/error/ErrorMessage' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {EmptyState} from '../util/EmptyState' import {s} from 'lib/styles' -import {usePalette} from 'lib/hooks/usePalette' import {useNotificationFeedQuery} from '#/state/queries/notifications/feed' import {useUnreadNotificationsApi} from '#/state/queries/notifications/unread' import {logger} from '#/logger' @@ -30,7 +29,6 @@ export function Feed({ onScrolledDownChange: (isScrolledDown: boolean) => void ListHeaderComponent?: () => JSX.Element }) { - const pal = usePalette('default') const [isPTRing, setIsPTRing] = React.useState(false) const moderationOpts = useModerationOpts() @@ -152,14 +150,8 @@ export function Feed({ renderItem={renderItem} ListHeaderComponent={ListHeaderComponent} ListFooterComponent={FeedFooter} - refreshControl={ - - } + refreshing={isPTRing} + onRefresh={onRefresh} onEndReached={onEndReached} onEndReachedThreshold={0.6} onScrolledDownChange={onScrolledDownChange} diff --git a/src/view/com/post-thread/PostLikedBy.tsx b/src/view/com/post-thread/PostLikedBy.tsx index 245ba59e..6e013f61 100644 --- a/src/view/com/post-thread/PostLikedBy.tsx +++ b/src/view/com/post-thread/PostLikedBy.tsx @@ -1,18 +1,16 @@ import React, {useCallback, useMemo, useState} from 'react' -import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' +import {ActivityIndicator, StyleSheet, View} from 'react-native' import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api' import {CenteredView} from '../util/Views' import {List} from '../util/List' import {ErrorMessage} from '../util/error/ErrorMessage' import {ProfileCardWithFollowBtn} from '../profile/ProfileCard' -import {usePalette} from 'lib/hooks/usePalette' import {logger} from '#/logger' import {useResolveUriQuery} from '#/state/queries/resolve-uri' import {usePostLikedByQuery} from '#/state/queries/post-liked-by' import {cleanError} from '#/lib/strings/errors' export function PostLikedBy({uri}: {uri: string}) { - const pal = usePalette('default') const [isPTRing, setIsPTRing] = useState(false) const { data: resolvedUri, @@ -88,14 +86,8 @@ export function PostLikedBy({uri}: {uri: string}) { item.actor.did} - refreshControl={ - - } + refreshing={isPTRing} + onRefresh={onRefresh} onEndReached={onEndReached} renderItem={renderItem} initialNumToRender={15} diff --git a/src/view/com/post-thread/PostRepostedBy.tsx b/src/view/com/post-thread/PostRepostedBy.tsx index 5cc00638..a2d3be55 100644 --- a/src/view/com/post-thread/PostRepostedBy.tsx +++ b/src/view/com/post-thread/PostRepostedBy.tsx @@ -1,18 +1,16 @@ import React, {useMemo, useCallback, useState} from 'react' -import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' +import {ActivityIndicator, StyleSheet, View} from 'react-native' import {AppBskyActorDefs as ActorDefs} from '@atproto/api' import {CenteredView} from '../util/Views' import {List} from '../util/List' import {ProfileCardWithFollowBtn} from '../profile/ProfileCard' import {ErrorMessage} from '../util/error/ErrorMessage' -import {usePalette} from 'lib/hooks/usePalette' import {logger} from '#/logger' import {useResolveUriQuery} from '#/state/queries/resolve-uri' import {usePostRepostedByQuery} from '#/state/queries/post-reposted-by' import {cleanError} from '#/lib/strings/errors' export function PostRepostedBy({uri}: {uri: string}) { - const pal = usePalette('default') const [isPTRing, setIsPTRing] = useState(false) const { data: resolvedUri, @@ -89,14 +87,8 @@ export function PostRepostedBy({uri}: {uri: string}) { item.did} - refreshControl={ - - } + refreshing={isPTRing} + onRefresh={onRefresh} onEndReached={onEndReached} renderItem={renderItem} initialNumToRender={15} diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx index 91755088..6cd1f355 100644 --- a/src/view/com/post-thread/PostThread.tsx +++ b/src/view/com/post-thread/PostThread.tsx @@ -2,7 +2,6 @@ import React, {useEffect, useRef} from 'react' import { ActivityIndicator, Pressable, - RefreshControl, StyleSheet, TouchableOpacity, View, @@ -349,14 +348,8 @@ function PostThreadLoaded({ } keyExtractor={item => item._reactKey} renderItem={renderItem} - refreshControl={ - - } + refreshing={isPTRing} + onRefresh={onPTR} onContentSizeChange={onContentSizeChange} style={s.hContentRegion} // @ts-ignore our .web version only -prf diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx index 8d5c11bd..3d38fbbc 100644 --- a/src/view/com/posts/Feed.tsx +++ b/src/view/com/posts/Feed.tsx @@ -3,7 +3,6 @@ import { ActivityIndicator, AppState, Dimensions, - RefreshControl, StyleProp, StyleSheet, View, @@ -16,7 +15,6 @@ import {FeedErrorMessage} from './FeedErrorMessage' import {FeedSlice} from './FeedSlice' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' import {useAnalytics} from 'lib/analytics/analytics' -import {usePalette} from 'lib/hooks/usePalette' import {useTheme} from 'lib/ThemeContext' import {logger} from '#/logger' import { @@ -74,7 +72,6 @@ let Feed = ({ ListHeaderComponent?: () => JSX.Element extraData?: any }): React.ReactNode => { - const pal = usePalette('default') const theme = useTheme() const {track} = useAnalytics() const queryClient = useQueryClient() @@ -294,25 +291,17 @@ let Feed = ({ renderItem={renderItem} ListFooterComponent={FeedFooter} ListHeaderComponent={ListHeaderComponent} - refreshControl={ - - } + refreshing={isPTRing} + onRefresh={onRefresh} + headerOffset={headerOffset} contentContainerStyle={{ minHeight: Dimensions.get('window').height * 1.5, }} - style={{paddingTop: headerOffset}} onScrolledDownChange={onScrolledDownChange} indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'} onEndReached={onEndReached} onEndReachedThreshold={2} // number of posts left to trigger load more removeClippedSubviews={true} - contentOffset={{x: 0, y: headerOffset * -1}} extraData={extraData} // @ts-ignore our .web version only -prf desktopFixedHeight={ diff --git a/src/view/com/profile/ProfileFollowers.tsx b/src/view/com/profile/ProfileFollowers.tsx index 077dabe5..fd8dee17 100644 --- a/src/view/com/profile/ProfileFollowers.tsx +++ b/src/view/com/profile/ProfileFollowers.tsx @@ -1,18 +1,16 @@ import React from 'react' -import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' +import {ActivityIndicator, StyleSheet, View} from 'react-native' import {AppBskyActorDefs as ActorDefs} from '@atproto/api' import {CenteredView} from '../util/Views' import {List} from '../util/List' import {ErrorMessage} from '../util/error/ErrorMessage' import {ProfileCardWithFollowBtn} from './ProfileCard' -import {usePalette} from 'lib/hooks/usePalette' import {useProfileFollowersQuery} from '#/state/queries/profile-followers' import {useResolveDidQuery} from '#/state/queries/resolve-uri' import {logger} from '#/logger' import {cleanError} from '#/lib/strings/errors' export function ProfileFollowers({name}: {name: string}) { - const pal = usePalette('default') const [isPTRing, setIsPTRing] = React.useState(false) const { data: resolvedDid, @@ -90,14 +88,8 @@ export function ProfileFollowers({name}: {name: string}) { item.did} - refreshControl={ - - } + refreshing={isPTRing} + onRefresh={onRefresh} onEndReached={onEndReached} renderItem={renderItem} initialNumToRender={15} diff --git a/src/view/com/profile/ProfileFollows.tsx b/src/view/com/profile/ProfileFollows.tsx index 5265ee07..091922dd 100644 --- a/src/view/com/profile/ProfileFollows.tsx +++ b/src/view/com/profile/ProfileFollows.tsx @@ -1,18 +1,16 @@ import React from 'react' -import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native' +import {ActivityIndicator, StyleSheet, View} from 'react-native' import {AppBskyActorDefs as ActorDefs} from '@atproto/api' import {CenteredView} from '../util/Views' import {List} from '../util/List' import {ErrorMessage} from '../util/error/ErrorMessage' import {ProfileCardWithFollowBtn} from './ProfileCard' -import {usePalette} from 'lib/hooks/usePalette' import {useProfileFollowsQuery} from '#/state/queries/profile-follows' import {useResolveDidQuery} from '#/state/queries/resolve-uri' import {logger} from '#/logger' import {cleanError} from '#/lib/strings/errors' export function ProfileFollows({name}: {name: string}) { - const pal = usePalette('default') const [isPTRing, setIsPTRing] = React.useState(false) const { data: resolvedDid, @@ -90,14 +88,8 @@ export function ProfileFollows({name}: {name: string}) { item.did} - refreshControl={ - - } + refreshing={isPTRing} + onRefresh={onRefresh} onEndReached={onEndReached} renderItem={renderItem} initialNumToRender={15} diff --git a/src/view/com/util/List.tsx b/src/view/com/util/List.tsx index 2acc3f4b..9abd7d35 100644 --- a/src/view/com/util/List.tsx +++ b/src/view/com/util/List.tsx @@ -1,27 +1,42 @@ import React, {memo, startTransition} from 'react' -import {FlatListProps} from 'react-native' +import {FlatListProps, RefreshControl} from 'react-native' import {FlatList_INTERNAL} from './Views' +import {addStyle} from 'lib/styles' import {useScrollHandlers} from '#/lib/ScrollContext' import {runOnJS, useSharedValue} from 'react-native-reanimated' import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED' +import {usePalette} from '#/lib/hooks/usePalette' export type ListMethods = FlatList_INTERNAL export type ListProps = Omit< FlatListProps, - 'onScroll' // Use ScrollContext instead. + | 'onScroll' // Use ScrollContext instead. + | 'refreshControl' // Pass refreshing and/or onRefresh instead. + | 'contentOffset' // Pass headerOffset instead. > & { onScrolledDownChange?: (isScrolledDown: boolean) => void + headerOffset?: number + refreshing?: boolean + onRefresh?: () => void } export type ListRef = React.MutableRefObject const SCROLLED_DOWN_LIMIT = 200 function ListImpl( - {onScrolledDownChange, ...props}: ListProps, + { + onScrolledDownChange, + refreshing, + onRefresh, + headerOffset, + style, + ...props + }: ListProps, ref: React.Ref, ) { const isScrolledDown = useSharedValue(false) const contextScrollHandlers = useScrollHandlers() + const pal = usePalette('default') function handleScrolledDownChange(didScrollDown: boolean) { startTransition(() => { @@ -49,12 +64,36 @@ function ListImpl( }, }) + let refreshControl + if (refreshing !== undefined || onRefresh !== undefined) { + refreshControl = ( + + ) + } + + let contentOffset + if (headerOffset != null) { + style = addStyle(style, { + paddingTop: headerOffset, + }) + contentOffset = {x: 0, y: headerOffset * -1} + } + return ( ) diff --git a/src/view/screens/Feeds.tsx b/src/view/screens/Feeds.tsx index 1c8bdf9f..20cdf815 100644 --- a/src/view/screens/Feeds.tsx +++ b/src/view/screens/Feeds.tsx @@ -1,5 +1,5 @@ import React from 'react' -import {ActivityIndicator, StyleSheet, View, RefreshControl} from 'react-native' +import {ActivityIndicator, StyleSheet, View} from 'react-native' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome' import {ViewHeader} from 'view/com/util/ViewHeader' @@ -487,14 +487,8 @@ export function FeedsScreen(_props: Props) { keyExtractor={item => item.key} contentContainerStyle={styles.contentContainer} renderItem={renderItem} - refreshControl={ - - } + refreshing={isPTR} + onRefresh={isUserSearching ? undefined : onPullToRefresh} initialNumToRender={10} onEndReached={onEndReached} // @ts-ignore our .web version only -prf diff --git a/src/view/screens/Search/Search.tsx b/src/view/screens/Search/Search.tsx index efd8507a..60fd2167 100644 --- a/src/view/screens/Search/Search.tsx +++ b/src/view/screens/Search/Search.tsx @@ -3,7 +3,6 @@ import { View, StyleSheet, ActivityIndicator, - RefreshControl, TextInput, Pressable, Platform, @@ -185,7 +184,6 @@ type SearchResultSlice = function SearchScreenPostResults({query}: {query: string}) { const {_} = useLingui() - const pal = usePalette('default') const [isPTR, setIsPTR] = React.useState(false) const { isFetched, @@ -254,14 +252,8 @@ function SearchScreenPostResults({query}: {query: string}) { } }} keyExtractor={item => item.key} - refreshControl={ - - } + refreshing={isPTR} + onRefresh={onPullToRefresh} onEndReached={onEndReached} // @ts-ignore web only -prf desktopFixedHeight